Makefile

189 阅读3分钟

一、相关概念

Makefile是什么?

        一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,也可以执行操作系统的命令。

Make与Makefile的关系

        make是一个命令工具,用来解释Makefile中的指令。

        在Makefile文件中描述了整个工程所有文件的编译顺序、编译规则

Makefile命名规则:Makefile或makefile

CMake是什么?

        CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。能够输出各种各样的makefile或者project文件,能测试编译器所支持的C特性,类似UNIX下的automake。只是 CMake 的组态档取名为 CMakeLists.txt。Cmake 并不直接建构出最终的软件,而是产生标准的建构档(如 Unix 的 Makefile 或 Windows Visual C 的 projects/workspaces),然后再依一般的建构方式使用。

cmake与CMakeLists的关系

        cmake是一个命令工具,可以用来生成makefile。需要根据CMakeLists.txt中的内容生成,CMakeList.txt就是写给cmake的规则。

总结:

        make是一个命令工具,Makefile是一个文件,make执行的时候,去读取Makefile文件中的规则,需要自己实现makefile

        cmake是一个命令工具,CMakeList.txt是一个文件,cmke执行的时候,去读取CMakeList.txt文件中的规则,需要自己实现CMakeList.txt

二、Makefile 基本语法

目标:依赖
	命令
例:
a:
	echo "hello world"
	ls ./
clean:
	echo "hello clean"

        目标:一般指要编译的目标,也可以是一个动作

        依赖:指执行当前目标所要依赖的条件,如:其他目标、某个文件、某个库等。一个目标可以存在多个依赖。

        命令:该目标下需要执行的具体命令,可以没有,也可以存在多条;当存在多条时,每条命令一行。

make常用选项

        make[-f file][options][target]

        Make默认在当前目录中寻找GNUmakefile、makefile、Makefile的文件作为make的输入文件。

        -f 可以指定除上述文件名之外的文件作为输入文件

        -v 显示版本号

        -n 只输出命令,但不执行,一般用来测试

        -s 只执行命令,但不显示具体命令,此处可在命令中使用@符抑制命令输出

        -w 显示执行前执行后的路径

        -C dir 指定makefile所在的目录

        没有指定目标时,默认使用第一个目标;如果指定,则执行对应的命令

三、Makefile中的变量

系统变量

        $*   不包括拓展名的目标文件名称

        $+   所有的依赖文件,以空格分隔

        $<   表示规则中的第一个条件

        $?   所有时间戳比目标文件晚的依赖文件,以空格分离

        $@  目标文件的完整名称

        $^    所有不重复的依赖文件,以空格分隔

        $%   如果目标是归档成员,则该变了表示目标的归档成员名称

系统常量(可用 make -p查看)

        AS      汇编程序的名称 默认为as

        CC     C编译器名称 默认为cc

        CPP   C预编译器名称 默认为cc -E

        CXX   C++编译器名称 默认为g++

        RM    文件删除程序别明 默认 rm -f

自动变量

        @指代当前目标,就是Make命令当前构建的那个目标。比如,maketest@ ****指代当前目标,就是Make命令当前构建的那个目标。比如,make test的 @ 就指代test。

a.txt b.txt: 
    touch $@

#等同于下面的写法

a.txt:
    touch a.txt
b.txt:
    touch b.txt 

        <  指代第一个前置条件。比如,规则为t:p1p2,那么<   指代第一个前置条件。比如,规则为 t: p1 p2,那么< 就指代p1。

a.txt: b.txt c.txt
    cp $< $@ 

#等同于下面的写法
a.txt: b.txt c.txt
    cp b.txt a.txt 

        ?  指代比目标更新的所有前置条件,之间以空格分隔。比如,规则为t:p1p2,其中p2的时间戳比t新,?   指代比目标更新的所有前置条件,之间以空格分隔。比如,规则为 t: p1 p2,其中 p2 的时间戳比 t 新,?就指代p2。

          指代所有前置条件,之间以空格分隔。比如,规则为t:p1p2,那么^   指代所有前置条件,之间以空格分隔。比如,规则为 t: p1 p2,那么 ^ 就指代 p1 p2 。

          指代匹配符*   指代匹配符 % 匹配的部分, 比如% 匹配 f1.txt 中的f1 ,* 就表示 f1。

        (@D)(@D) 和 (@F) 分别指向 @的目录名和文件名。比如,@ 的目录名和文件名。比如,@是 src/input.c,那么(@D)的值为src(@D) 的值为 src ,(@F) 的值为 input.c。

        (<D)(<D) 和 (<F) 分别指向 $< 的目录名和文件名。

自定义变量

        定义:变量名=变量值

        使用:(变量名)/(变量名)/{变量名}

四、Makefile中的函数

        伪目标:.PHONY:clean

                声明目标为伪目标之后,makefile将不会判断目标是否存在或该目标是否需要更新

        %.o:%.c

                .o 依赖于对应的.c

        wildcard

                $(wildcard ./*.c) 获取当前目录下所有的.c文件

        patsubst

                $(patsubst %.c, %.o, ./*.c) 将对应的c文件名替换成.o文件名

        替换后缀名

                替换后缀名的函数写法是:变量名 + 冒号 + 后缀名替换规则

	min: $(OUTPUT:.js=.min.js)

        执行shell命令

FILE=test

A:=$(shell ls ../)
B:=$(shell pwd)
C :=$(shell if [ ! -f $(FILE) ];then touch $(FILE);fi;)

a:
	echo $(A)
	echo $(B)
	echo $(C)

clean:
	$(RM) $(FILE)

五、Makefile中编译动/静态链接库 .dll/.lib .so/.a 库文件

        动态链接库:不会把代码编译到二进制文件中,而是在运行时才去家在,所以只需要维护一个地址

        静态链接库:会把库中的代码编译到二进制文件中,当程序编译完成后,库文件可删除

                -fPIC 产生位置无关的代码

                -shared 共享

                -l(小L) 指定动态库

                -I(大i) 指定头文件目录,默认当前目录

                -L 手动指定库文件搜索目录,默认只链接共享目录

	#动态库
	SoTest.c		lisSoTest.so
	gcc -shared -fPIC SoTest.c -o libSoTest.so
	gcc -lSotest -L./ test.c -o test
	gcc -lSotest -L./usr main.c -o main	
	#静态库
	aTest.c			libaTest.a
	gcc -c aTest.c -o aTest.o
	ar -r libaTest.a aTest.o

六、Makefile中赋值

        Makefile中,都是先展开所有变量,再调用指令

        Makefile一共提供了四个赋值运算符 (=、:=、?=、+=)

VARIABLE = value
# 在执行时扩展,允许递归扩展。

VARIABLE := value
# 在定义时扩展。

VARIABLE ?= value
# 只有在该变量为空时才设置值。

VARIABLE += value
# 将值追加到变量的尾端。

        命令行传参 make -f Makefile FLAG=123 如果有Makefile ,则可写成 make FLAG=123

七、Makefile中的条件判断和循环

        ifeq 判断是否相等,相等返回true,不相等返回false

        ifneq 判断是否不相等,相等返回true,不相等返回false

        ifdef 判断变量是否存在,存在返回true,不存在返回false

        Ifndef 判断变量是否不存在,不存在返回true,存在返回false

Ifeq ($(A),123)

else

endif


Ifdef A

else

endif
#ifeq,ifneq 与条件之间要有空格,不然会报错
#可以只有if,没有else,
#但是没有 elseif的用法,如果要实现 elseif,就要写嵌套

        makefile 中只有一个循环 foreach,只支持 GNU Make ,其它平台的make ,可以用shell 中的循环来实现

TARGET:=a b c d
FILE:=$(foreach v, $(TARGET),$v.txt)

all:
	#foreach
	echo $(FILE)
	#for in
	for v in $(TARGET);\
		do touch $$v.txt;\
	done;\
	#用shell
	$(shell for v in $(TARGET); do touch $$v-txt;done)

八、make install

        make 1

        make install 2 3 4

        make clean 5

                1:将源文件编译成二进制可执行文件(包括各种库文件)

                2:创建目录,将可执行文件拷贝到指定目录(安装目录)

                3:加全局可执行的路径

                4:加全局的启停脚本

                5:重置编辑环境,删除无关文件

    make install 也就是把生成的文件类似于放入:/usr/local/bin/

     反汇编指令:objdump -DC main>main.txt