通用Makefile的编写和在项目工程中使用Makefile

通用Makefile的编写和在项目工程中使用Makefile

Makefile一般的格式是:

target:components

      rule

二、$@、$^、$<

这三个分别表示:

$@          --代表目标文件(target)

$^            --代表所有的依赖文件(components)

$<           --代表第一个依赖文件(components中最左边的那个)。

$?           --代表示比目标还要新的依赖文件列表。以空格分隔。

$%           --仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a(bar.o)",那么,"$%"就是"bar.o","$@"就是"foo.a"。如果目标不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。

通用Makefile的编写和在项目工程中使用Makefile(包括动态库、静态库的链接、整个工程联合编译)

(1)      什么是通用Makefile?

这里的通用Makefile指的是它既能编译可执行文件、也能编译动态连接库、又能编译静态库,只需要更改很少的内容即可。

(2)      写一个通用Makefile

#-------------------------配置区域----------------------- 

#DIR指的是.o文件和.c文件所在的目录 

DIR= 

#BIN指的是最终生成的目标对象名(包括路径),它可以是可执行程序、动态链接库或静态链接库 

BIN=$(DIR)/ 

#SHARE特指链接生成动态链接库对象时的编译选项 

SHARE=--share 

#CFLAG即compile flag,表示在编译时所加入的选项参数 

#参数包括   

#-Wall  : 编译后显示所有警告信息 

#-g     : 编译时加入调试信息,以便之后可以用gdb调试 

#-fPIC  : 编译动态链接库时加入的选项 

#-I./inc: -I选项指定从哪个目录寻找头文件,在这指定之后,在源文件中包含头文件就可以使用<>,这里./inc即为指定的目录 

CFLAG= 

#LFLAG即library flag,表示链接生成可执行程序时所要链接的所有库的选项参数 

#-L./lib : -L指示动态/静态链接库所在的目录,这里./lib即所在的目录 

#-l      : -l指示动态/静态链接库的名字,注意: 这里的库名字并不包括前缀(lib)和后缀(.a或.so) 

#$(SHARE) : 取SHARE变量对应的动态链接库链接选项--share 

LFLAG= 

#CC即编译链接命令gcc -o 用于编译或者链接动态库以及可执行程序 

CC=gcc -o 

#AR即ar -cr ,ar -cr是专门链接生成静态库的命令 

#-c : 即create,创建静态库 

#-r : 即replace,当静态库改变时,替代原有静态库 

AR=ar -cr 

#最终用的是哪个链接命令 

#链接生成动态库和可执行程序用CC 

#链接生成静态库用AR 

CO=$(CC) 

#-------------------------以下为通用不变区域----------------------- 

 

#SRC指的是指定目录下的所有.c文件名,OBJ指的是指定目录下的所有.o文件名 

SRC=$(wildcard $(DIR)/*.c) 

OBJ=$(patsubst %.c, %.o, $(SRC)) 

 

#链接命令 

all:$(BIN) 

$(BIN):$(OBJ) 

$(CO) $@ $^ $(LFLAG) 

#编译命令 

$(DIR)/%.o:$(DIR)/%.c 

$(CC) $@ -c $< $(CFLAG) 

#清除无用文件 

.PHONY:clean 

clean: 

rm $(OBJ) $(BIN) 

上面就是一个通用的Makefile模板,我们可以通过它可以写出对可执行程序编译Makefile,也可以写出对动态链接库编译的Makefile,当然也可以用它写出对静态库编译Makefile

   下面,我们通过一个工程实例,用通用Makefile模板来编写一下不同功能的Makefile

二、整个项目工程都包括什么?

之前讲过Makefile的编写规则,我们知道了简单的Makefile如何编写,那在编写软件项目时,一个Makefile往往不够用了。

         举个项目工程实例:

         一个工程目录下一般有7个目录一个联合编译Makefile文件:

         <1>、bin目录:一般存放可执行程序

         <2>、etc目录:存放配置文件

         <3>、lib目录 :存放所有的库文件,包括动态库和静态库

         <4>、inc目录:存放所有的公共头文件,一般是动态库和静态库对应的头文件

         <5>、src目录:存放项目源码文件和编译它的Makefile文件

         <6>、static目录:存放静态库源文件和编译它的Makefile文件

         <7>、dynamic目录:存放动态库源文件和编译它的Makefile文件

 

三、用(一)中的Makefile模板为src、static、dynamic目录下的源文件编写不同的Makefile文件

(1)、static目录,即静态链接库源代码目录。在此目录下要生成静态链接库文件libstatic_test.a

Makefile文件:

#------------------------------配置区域---------------------------- 

DIR=./static 

#静态库名以lib为前缀,.a为后缀 

BIN=$(DIR)/libstatic_test.a 

 

SHARE=--share 

 

CFLAG= 

  

LFLAG= 

 

CC=gcc -o 

 

AR=ar -cr 

 

#编译静态库用ar -cr命令 

CO=$(AR) 

#-------------------------以下为通用不变区域----------------------- 

SRC=$(wildcard $(DIR)/*.c)  [A1]  /*获取./static 目录下的所有.c文件,其返回值包含文件路径的文件列表*/

OBJ=$(patsubst %.c, %.o, $(SRC))[A2]  /*将上面获得的.c替换成.c文件列表*/

all:$(BIN) 

$(BIN):$(OBJ) 

    $(CO) $@ $^ $(LFLAG) 

 

$(DIR)/%.o:$(DIR)/%.c 

    $(CC) $@ -c $< $(CFLAG) 

 

.PHONY:clean 

clean: 

rm $(OBJ) $(BIN)

 

  

 

(2)、为dynamic目录,即动态链接库源代码目录,在此目录下生成动态链接库 libdynamic_test.so

 

Makefile文件:

#------------------------------配置区域---------------------------- 

 

DIR=./dynamic 

 

#动态库名以lib为前缀,以.so为后缀 

BIN=$(DIR)/libdynamic_test.so 

 

SHARE=--share 

 

#动态链接库编译时需要-fPIC选项 

CFLAG=-fPIC 

 

#链接动态库需要--share选项 

LFLAG=$(SHARE) 

 

CC=gcc -o 

 

AR=ar -cr 

 

#编译动态链接库用gcc -o命令 

CO=$(CC) 

#-------------------------以下为通用不变区域----------------------- 

/*

$^ 代表所有的依赖对象

$< 代表第一个依赖对象

$@ 代表目标

*/

SRC=$(wildcard   $(DIR)/*.c) 

OBJ=$(patsubst  %.c, %.o, $(SRC)) 

all:$(BIN) 

$(BIN):$(OBJ)  

    $(CO) $@ $^ $(LFLAG)  [A1] 

 

$(DIR)/%.o:$(DIR)/%.c 

    $(CC) $@ -c $< $(CFLAG) 

 

.PHONY:clean 

clean: 

rm $(OBJ) $(BIN)

3)、为src目录,即工程源代码目录。在此目录下要通过链接动态链接库libdynamic_test.so和静态库libstatic_test.a 来生成可执行文件main

Makefile文件:

#-------------------------配置区域----------------------- 

 

#源码所在的目录 

DIR=./src

 

#在源码所在目录下生成可执行文件main 

BIN=$(DIR)/main 

 

SHARE=--share  

 

#显示所有编译警告,并指示公共头文件(静态库和动态库的头文件)所在目录

CFLAG= -Wall -I../inc [个人用户1] /*[个人用户1]这个地方头文件路径需要注意!*/

#在../lib目录中链接两个外部库文件 

LFLAG=-L../lib -ldynamic_test -lstatic_test 

 

CC=gcc -o 

 

AR=ar -cr 

 

#使用gcc -o 链接命令 

CO=$(CC) 

 

 

#-------------------------以下为通用不变区域----------------------- 

 

#SRC指的是指定目录下的所有.c文件名,OBJ指的是指定目录下的所有.o文件名 

SRC=$(wildcard $(DIR)/*.c) 

OBJ=$(patsubst %.c, %.o, $(SRC)) 

 

#链接命令 

all:$(BIN) 

$(BIN):$(OBJ) 

    $(CO) $@ $^ $(LFLAG) 

 

#编译命令 

$(DIR)/%.o:$(DIR)/%.c 

    $(CC) $@ -c $< $(CFLAG) 

 

 

#清除无用文件 

.PHONY:clean 

clean: 

    rm $(OBJ) $(BIN)

 

以上三步完成后,整个工程的目录树是这样的:

 

四、编写联合编译Makefile文件

按照以前的思路,我们需要去每个目录下分别执行每个Makefile,最后生成可执行文件。

这个方法太麻烦了,现在有一个更好的方法:编写联合编译Makefile文件,它和src、bin等在一个目录下。在上面的图中有一个单独的Makefile文件未被标识,它就是联合编译Makefile文件。

 

联合编译Makefile文件

test: 

    make -C ./dynamic 

    #make -C:进入指定的目录下执行make命令 

    make -C ./static 

    #将静态、动态库文件拷贝到lib目录下 

    cp ./static/libstatic_test.a  ./lib 

    cp ./dynamic/libdynamic_test.so  ./lib 

     

    make -C ./src 

 

install: 

    #为lib目录下的动态链接库文件在/usr/lib目录下创建软连接,这里使用的必须是绝对路径  

    sudo ln -s /home/sunxiwang/03AgainStudyLinux/workspace/04makefile/03makefile/lib/libdynamic_test.so  /usr/lib/libdynamic_test.so  

    #将最后生成的可执行文件main拷贝到./bin目录下 

    mv ./src/main ./bin 

 

clean: 

    make clean -C ./dynamic 

    #make clean -C: 进入指定目录下执行make clean命令 

    make clean -C ./static 

    make clean -C ./src 

因为联合编译Makefile文件在工程目录下,所以在工程目录下执行make命令:

 

执行安装命令,将可执行文件main安装到bin目录

 

执行可执行程序

 

好,这样整个工程就编译完成了,生成的可执行文件在bin目录下!

最后,我们再来看一下当前的工程目录树结构:

 

 

转自:https://blog.csdn.net/SunXiWang/article/details/78701130

posted @ 2020-09-10 15:15  陈木  阅读(1221)  评论(0编辑  收藏  举报