zoukankan      html  css  js  c++  java
  • 读一下skynet的Makefile

    一直对Makefile感到很模糊。今天找到一份很好的资料,耗子叔的《陈皓_Makefile》。大致读了一遍,为了实践,我们来读一份Makefile。

    skynet是云风团队的开源服务器框架。skynet的地址

    https://github.com/cloudwu/skynet.git

    简单看下skynet的目录结构

    首先我想应该对Makefile有个总的认识。

    什么是Makefile。

    简单的讲,它是make命令的规则说明文件。当我们在一个路径下,敲make命令的时候,它会去找Makefile文件,按照Makefile里的规则,来编译链接生成目标文件。这通常是unix/linux系统的操作,windows我们有vs。

    vim Makefile来看一下。第一句就是

    include platform.mk

    作用是引用platform.mk(另一份Makefile)。所以先来看paltform.mk这份Makefile。比较短,有40行。

    PLAT ?= none
    PLATS = linux freebsd macosx
    
    CC ?= gcc
    
    .PHONY : none $(PLATS) clean all cleanall
    
    #ifneq ($(PLAT), none)
    
    .PHONY : default
    
    default :
            $(MAKE) $(PLAT)
    
    #endif
    
    none :
            @echo "Please do 'make PLATFORM' where PLATFORM is one of these:"
            @echo "   $(PLATS)"
    
    SKYNET_LIBS := -lpthread -lm
    SHARED := -fPIC --shared
    EXPORT := -Wl,-E
    
    linux : PLAT = linux
    macosx : PLAT = macosx
    freebsd : PLAT = freebsd
    
    macosx : SHARED := -fPIC -dynamiclib -Wl,-undefined,dynamic_lookup
    macosx : EXPORT :=
    macosx linux : SKYNET_LIBS += -ldl
    linux freebsd : SKYNET_LIBS += -lrt
    
    # Turn off jemalloc and malloc hook on macosx
    
    macosx : MALLOC_STATICLIB :=
    macosx : SKYNET_DEFINES :=-DNOUSE_JEMALLOC
    
    linux macosx freebsd :
            $(MAKE) all PLAT=$@ SKYNET_LIBS="$(SKYNET_LIBS)" SHARED="$(SHARED)" EXPORT="$(EXPORT)" MALLOC_STATICLIB="$(MALLOC_STATICLIB)" SKYNET_DEFINES="$(SKYNET_DEFINES)"

    先看前几行:

    PLAT ?= none
    PLATS = linux freebsd macosx
    
    CC ?= gcc

    ?=的意思是如果变量没有,则定义,如果有则用原来的。=自然就是变量定义。PLATS变量就是linux freebsd macosx,可见skynet可以在这三个平台编译。

    编译器用的是gcc。

    接下来:

    .PHONY : none $(PLATS) clean all cleanall

    .PHONY是一个固定用法。:后面的代表的是伪目标(标签)。伪目标是相对于目标而言的。$()则是引用变量。

    Makefile的规则。

    Makefile的规则简单来讲就是很多依赖关系,依赖关系包括目标文件,和依赖于目标文件的文件(前提)。再加上依赖关系上的命令。

    target ... : prerequisites ...

    [tab] command : ... 

    比如一个Makefile

    main : main.o
        cc -o main.o
    
    main.o : main.c
        cc -c main.c

    main是最后的目标文件,它依赖于main.o。通过命令cc -o main.o生成main。main.o的依赖同理。

    Makefile里有目标,同时有一种伪目标。它是通常是作为make后面的参数,比如官方文档里编译skynet的命令是make linux。

    那么Makefile里就应该有类似这样的代码

    linux :

      command

    更典型的是clean,make clean是常用的标签。

    clean :
        rm -rf cur/src

    但是这clean有可能是一个目标文件,这样就可以在伪目标前面加一个.PHONY来显式说明伪目标。

    所以这份Makefile里有多个伪目标(标签)none,linux,freebsd,macosx,clean,all,cleanall。

    接下来:

    #ifneq ($(PLAT), none)
    
    .PHONY : default
    
    default :
            $(MAKE) $(PLAT)
    
    #endif

    条件判断。#ifneq是如果不等于的意思。结合前面一起看,如果$(PLAT)不等于none,意思就是其他地方定义了PLAT,则定义伪目标default,来执行命令$(MAKE) $(PLAT)。$(MAKE)应该就是make。

    接下来是如果输入命令make none的话,会打印提示:

    none :
            @echo "Please do 'make PLATFORM' where PLATFORM is one of these:"
            @echo "   $(PLATS)"

     接下来:

    SKYNET_LIBS := -lpthread -lm
    SHARED := -fPIC --shared
    EXPORT := -Wl,-E

    :=是变量赋值,=也是赋值。两者的区别是,使用=变量的推导可以在后面,这样可能会出现无限推导,造成报错。使用:=使得前面的变量不能使用后面的变量。

    linux : PLAT = linux
    macosx : PLAT = macosx
    freebsd : PLAT = freebsd
    
    macosx : SHARED := -fPIC -dynamiclib -Wl,-undefined,dynamic_lookup
    macosx : EXPORT :=
    macosx linux : SKYNET_LIBS += -ldl
    linux freebsd : SKYNET_LIBS += -lrt

    其中+=是变量赋值追加的意思。这段另有个疑问。标签后面的变量赋值语句可以有多个?我写一段Makefile验证:

    test : a = first
    test : b = second
    
    test :
            echo $(a); echo $(b)

    make test试下:

    可见a,b变量都赋值了。也就是同一个标签后的赋值语句可以有多句。

    接下去最后的命令:

    linux macosx freebsd :
            $(MAKE) all PLAT=$@ SKYNET_LIBS="$(SKYNET_LIBS)" SHARED="$(SHARED)" EXPORT="$(EXPORT)" MALLOC_STATICLIB="$(MALLOC_STATICLIB)" SKYNET_DEFINES="$(SKYNET_DEFINES)"

    $@比较特殊,是一个自动化变量,代表所有目标集。这里应该是对应相应的plat,linux就是linux,macosx就是macosx。

    好了看完了platform.mk。再来看Makefile。

    首先一段是关于编译lua

    LUA_CLIB_PATH ?= luaclib
    CSERVICE_PATH ?= cservice
    
    SKYNET_BUILD_PATH ?= .
    
    CFLAGS = -g -O2 -Wall -I$(LUA_INC) $(MYCFLAGS)
    # CFLAGS += -DUSE_PTHREAD_LOCK
    
    # lua
    
    LUA_STATICLIB := 3rd/lua/liblua.a
    LUA_LIB ?= $(LUA_STATICLIB)
    LUA_INC ?= 3rd/lua
    
    $(LUA_STATICLIB) :
            cd 3rd/lua && $(MAKE) CC='$(CC) -std=gnu99' $(PLAT)

    skynet应该是自带了一份lua,放在3rd/lua下面,可以看到目标文件是生成liblua.a。

    其中有个$(MYCFLAGS)这个是什么,我好像读了上下文没有发现……??

    接下来关于jemalloc的:

    # jemalloc 
    
    JEMALLOC_STATICLIB := 3rd/jemalloc/lib/libjemalloc_pic.a
    JEMALLOC_INC := 3rd/jemalloc/include/jemalloc
    
    all : jemalloc
            
    .PHONY : jemalloc update3rd
    
    MALLOC_STATICLIB := $(JEMALLOC_STATICLIB)
    
    $(JEMALLOC_STATICLIB) : 3rd/jemalloc/Makefile
            cd 3rd/jemalloc && $(MAKE) CC=$(CC) 
    
    3rd/jemalloc/autogen.sh :
            git submodule update --init
    
    3rd/jemalloc/Makefile : | 3rd/jemalloc/autogen.sh
            cd 3rd/jemalloc && ./autogen.sh --with-jemalloc-prefix=je_ --disable-valgrind
    
    jemalloc : $(MALLOC_STATICLIB)
    
    update3rd :
            rm -rf 3rd/jemalloc && git submodule update --init

    jemalloc是一种内存分配算法,比c语言的malloc效率高。其实这段我有点凌乱……

    jemalloc是其他开源库的代码了,所以会执行git submodule update --init。

    其实目标文件是3rd/jemalloc/lib/libjemalloc_pic.a,在3rd/jemalloc下面也有一份Makefile,这里应该会根据这份Makefile来make。

    有一段3rd/jemalloc/Makefile : | 3rd/jemalloc/autogen.sh,其中:|是什么意思??

    总体来说,这段意思是先git submodule update得到autogen.sh,然后执行这个脚本,产生Makefile,接着make。

    看一下autogen.sh:

    #!/bin/sh
    
    for i in autoconf; do
        echo "$i"
        $i
        if [ $? -ne 0 ]; then
            echo "Error $? in $i"
            exit 1
        fi
    done
    
    echo "./configure --enable-autogen $@"
    ./configure --enable-autogen $@
    if [ $? -ne 0 ]; then
        echo "Error $? in ./configure"
        exit 1
    fi

    可能是autoconf工具产生Makefile的操作了。略过不想。

    再来:

    all : 
      $(SKYNET_BUILD_PATH)/skynet 
      $(foreach v, $(CSERVICE), $(CSERVICE_PATH)/$(v).so) 
      $(foreach v, $(LUA_CLIB), $(LUA_CLIB_PATH)/$(v).so)

    $(SKYNET_BUILD_PATH)/skynet就是./skynet。

    foreach的语法是这样$(foreach <var>,<list>,<text>), 它会从list中挨个取出var,作用于text。比如

    names := a b c d  
    files := $(foreach n,$(names),$(n).o)

    $(file)的值是a.o b.o c.o d.o。

    所以all后面其实一大推的目标.so文件。

    $(SKYNET_BUILD_PATH)/skynet : $(foreach v, $(SKYNET_SRC), skynet-src/$(v)) $(LUA_LIB) $(MALLOC_STATICLIB)
            $(CC) $(CFLAGS) -o $@ $^ -Iskynet-src -I$(JEMALLOC_INC) $(LDFLAGS) $(EXPORT) $(SKYNET_LIBS) $(SKYNET_DEFINES)

    核心目标skynet。依赖于一堆的src文件。下面的$@,$^两个叫做自动化变量。$@上面讲了,$^是所有的依赖集。

    define CSERVICE_TEMP
      $$(CSERVICE_PATH)/$(1).so : service-src/service_$(1).c | $$(CSERVICE_PATH)
            $$(CC) $$(CFLAGS) $$(SHARED) $$< -o $$@ -Iskynet-src
    endef

    define是定义命令包,endif结尾,CSERVICE_TEMP是命令包的名字。$(1)的意思是第一个参数,这里指的是?可能是调用命令的时候传进来的参数。另外$$的用法是,$$代表真实的$,而不是调用变量。

    $(foreach v, $(CSERVICE), $(eval $(call CSERVICE_TEMP,$(v))))
    
    $(LUA_CLIB_PATH)/skynet.so : $(addprefix lualib-src/,$(LUA_CLIB_SKYNET)) | $(LUA_CLIB_PATH)
            $(CC) $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src -Iservice-src -Ilualib-src

    用到了几个函数,eval,call和addprefix。call能够创建参数,$(call<exp, param1, param2...>),例如:

    reverse = $(1) $(2)  
    foo = $(call reverse,a,b) #foo = a b
    
    reverse = $(2) $(1)  
    foo = $(call reverse,a,b) #foo = b a

    addprefix增加前缀。eval是将后面的参数作为makefile的一部分解析执行。define,$$,eval经常在一起使用

    cleanall: clean
    ifneq (,$(wildcard 3rd/jemalloc/Makefile))
            cd 3rd/jemalloc && $(MAKE) clean && rm Makefile
    endif
            cd 3rd/lua && $(MAKE) clean
            rm -f $(LUA_STATICLIB)

    最后再看一下cleanall里面有个wildcard函数。在变量的值里面使用的通配符:

    objects = *.o  #object = *.o
    
    objects := $(wildcard *.o) #object = 所有.o文件

    好了,先读到这里了。

    引用:

    1.《陈皓_Makefile》

  • 相关阅读:
    Pixar 故事公式
    你想住在中国哪里
    tar.gz方式安装nacos设置使用systemct进行service方式的管理并设置开机自启动
    记一个nginx server_name配置多个时的坑
    linux软链接的创建、修改和删除
    阿里云SLB的健康检查配置
    (转载)bullet安装之——windows下的安装与VS开发
    [译] 找到ndarray中的重复行
    [译] 对dataframe数据按照某列值进行分组,分组后连接字符串
    [译] 如何将列表嵌套列表的情况转化成一维列表
  • 原文地址:https://www.cnblogs.com/yao2yaoblog/p/7826729.html
Copyright © 2011-2022 走看看