makefile 依赖怎么依赖系统库

6185人阅读
Linux学习笔记(21)
0.前言& & 从学习C语言开始就慢慢开始接触makefile,查阅了很多的makefile的资料但总感觉没有真正掌握makefile,如果自己动手写一个makefile总觉得非常吃力。所以特意借助博客总结makefile的相关知识,通过例子说明makefile的具体用法。& & 例说makefile分为以下几个部分,更多内容请参考【】& & 1.只有单个C文件& && & 2.含有多个C文件& &&& & 3.需要包括头文件路径& & 4.增加宏定义& & 5.增加系统共享库& & 6.增加自定义共享库& & 7.一个实际的例子& & 【代码仓库】——& & 代码仓库位于bitbucket,可借助TortoiseHg(GUI工具)克隆代码或者在网页中直接下载zip包。& & 【本例说明】& & 本例分为两个过程,先制作一个共享库,然后在使用这个共享库。共享库采用动态链接方式,后缀为.so。& &&1.gcc复习& & 【1】gcc指令中使用共享库使用前缀-l,共享库查找目录使用-L。& & 【2】一般情况下DLIBS中加入共享库,而LDFLAGS中加入共享库查找目录。2.共享库源文件& & 和生成共享库有关的文件位于libtest目录中,在makefile最后把共享库复制到同级的lib目录中。具体内容请参考代码仓库并复制zip包。& & 【libtest.h】& & 指定接口,给出相应声明#ifndef __LIBTEST_H
#define __LIBTEST_H
int sub(int a, int b);
int add(int a, int b);
#endif& & 【test-add.c】int add(int a, int b)
return a+b;
}& & 【test-sub.c】int sub(int a, int b)
return a-b;
}3.共享库的makefile& & 请替换其中的[tab],并以代码仓库中的makefile文件为主。# 指令编译器和选项
CFLAGS = -Wall -std=gnu99
# 目标文件
TARGET = libtest.so
SRCS = test-add.c test-sub.c
# 目标文件
OBJS = $(SRCS:.c=.o)
# 链接为可执行文件
$(TARGET):$(OBJS)
[tab]$(CC) -shared -o $@ $^
[tab]mv $(TARGET) ../lib
[tab]rm -rf $(TARGET) $(OBJS)
# 编译规则 $@代表目标文件 $& 代表第一个依赖文件
[tab]$(CC) $(CFLAGS) -o $@ -fPIC -c $&& & 【说明】& & 【1】目标为libtest.so,请务必以lib开头 .so结尾,在使用该共享库时系统会自动的去除lib和.so,使用时写成-ltest。& & 【2】多数内容和学习笔记中的多个文件相同。& & 【3】在链接过程中加入-shared参数,意为共享形式的目标文件。& & 【4】在编译过程中加入-fPIC参数,意为生成和地址无关的目标文件。& & 【5】在链接完成之后,通过mv指令把libtest.so移动到同级的lib目录中。& & 【6】如果有必要,可以把libtest.so复制到/usr/lib目录中,这样使用起来会更加方便。& & 【验证】&&& ldd test&&& linux-vdso.so.1 =&& (0x00007fffde960000)&& &libm.so.6 =& /lib/x86_64-linux-gnu/libm.so.6 (0x00007ffe55b18000)&& &libc.so.6 =& /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffe)&& &/lib64/ld-linux-x86-64.so.2 (0x00007ffe55e38000)& & 【编译和执行】& & make clean && make&& & 【控制台输出】rm -rf libtest.so test-add.o test-sub.ogcc -Wall -std=gnu99 -o test-add.o&-fPIC&-c test-add.cgcc -Wall -std=gnu99 -o test-sub.o&-fPIC&-c test-sub.cgcc&-shared&-o libtest.so test-add.o test-sub.omv libtest.so ../lib& & 【1】编译过程中加入了-fPIC选项。& & 【2】链接过程中加入-shared选项。& & 【3】共享库为libtest.so。& & 【4】最后,共享库被移动到上一级的lib目录中。& &4.源文件& & 调用共享库指定的接口,add和sub函数。#include &stdio.h&
#include &libtest.h&
int main(void)
int a = 3;
int b = 2;
printf(&a=%d\n&, a);
printf(&b=%d\n&, b);
printf(&a+b=%d\n&, add(a, b));
printf(&a-b=%d\n&, sub(a, b));
}& &&5.makefile& & 请替换其中的[tab],并以代码仓库中的makefile文件为主。 & &# 指令编译器和选项
CFLAGS = -Wall -std=gnu99
# 目标文件
TARGET = test
SRCS = test.c
# 头文件查找路径
# 库文件和库查找路径
DLIBS = -ltest
LDFLAGS = -L./lib
# 指定运行时的库文件路径
RPATH = -Wl,-rpath=./lib
# 目标文件
OBJS = $(SRCS:.c=.o)
# 链接为可执行文件
$(TARGET):$(OBJS)
[tab]$(CC) -o $@ $^ $(LDFLAGS) $(DLIBS) $(RPATH)
[tab]rm -rf $(TARGET) $(OBJS)
# 连续动作,请清除再编译链接,最后执行
exec:clean $(TARGET)
[tab]@echo 开始执行
[tab]./$(TARGET)
[tab]@echo 执行结束
# 编译规则 $@代表目标文件 $& 代表第一个依赖文件
[tab]$(CC) $(CFLAGS) $(INC) -o $@ -c $&6.具体说明& & 【1】DLIBS =&-ltest&指定共享库,请注意共享库的名称为libtest.so,而-l参数只取test部分,去掉前缀lib和后缀.so。& & 【2】LDFLAGS = -L./lib 指定共享库路径,请注意上一步中已经把共享库复制到lib目录中。& & 【3】INC = -I./lib &指定libtest.h目录,也可把libtest.h复制到test.c所在的目录。& & 【4】$(CC) -o $@ $^ $(LDFLAGS) $(DLIBS) 链接过程指定共享库查找路径,指定共享库名称。& & 【5】第【1】和第【2】点只在链接过程有效,在执行过程中需要通过-Wl,-rpath=&path&指定共享库路径。& &&& & 【编译和链接】& & make clean && make& & 【控制台输出】rm -rf test test.ogcc -Wall -std=gnu99 -I./lib -o test.o -c test.c&gcc -o test test.o&-L./lib -ltest -Wl,-rpath=./lib& & 【执行】& & 在执行之前还可以通过ldd test查看libtest是否链接成功。./testa=3b=2a+b=5a-b=1& & 从控制台的输出结果可以看出,共享库运行正常。7.总结& & 【1】-l指定共享库名称,-L指定共享库路径。8.参考资料& & 【1】& & 【2】& &&
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:2434286次
积分:18905
积分:18905
排名:第364名
原创:190篇
评论:1391条
所在地: 江苏无锡
(1)(1)(1)(1)(2)(1)(1)(3)(1)(3)(2)(1)(7)(16)(17)(14)(5)(13)(9)(4)(15)(11)(13)(12)(1)(3)(2)(21)(1)(4)(2)(1)(5)(2)(1)给 C工程添加库依赖的几种方法 - Linux Job - ITeye技术网站
博客分类:
#include &libxml/parser.h&
#include &stdio.h&
int main()
doc = xmlParseFile ("testfile.xml");
if (doc == NULL) {
printf ("Document not parsed successfully. \n");
return -1;
printf ("Document parsed successfully.\n");
xmlFreeDoc(doc);
在实例代码中存在libxml库的依赖,
对于一般的C工程来说我们可以通过下面三种方式来添加libxml库的依赖:
1.使用pkg-config
configure.ac (或者
configure.in
)中添加如下宏:
PKG_CHECK_MODULES(XML, libxml-2.0 &= 2.4)
./configure 时会去确认
libxml-2.0的版本号,大于或者等于2.4。
libxml-2.0 是依赖库的库名,可以通过命令
pkg-config --list-all 查看当前所有的
pkg-config支持库。
b. 在 Makefile.am 中添加如下宏:
tut_prog_CPPFLAGS = $(XML_CFLAGS)
tut_prog_LDFLAGS= $(XML_LIBS)
其中tut_prog是程序名,$(XML_CFLAGS) 和 $(XML_LIBS)就是对应的依赖库。
2.使用Autoconf工具提供的宏
在/usr/share/aclocal 中有很多用M4写好的宏,我们可以找到libxml对应的
/usr/share/aclocal/libxml.m4。
configure.ac (或者
configure.in
)中添加如下宏:
AM_PATH_XML2(2.4.0)
b. 在 Makefile.am 中添加如下宏:
tut_prog_CPPFLAGS = $(XML_CPPFLAGS)
tut_prog_LDFLAGS= $(XML_LIBS)
注意:这里的$(XML_CPPFLAGS)和第一点不同,是在libxml.m4中有定义的宏。
如果在/usr/share/aclocal/中找不到对应的M4宏,你可以去
看看,也许已经有人写好了一些常用的M4宏。
3.手动指定依赖库的路径
在 Makefile.am 中添加如下代码:
tut_prog_CPPFLAGS = -I /usr/include/libxml2
tut_prog_LDFLAGS= -lxml2
浏览: 560265 次
来自: 上海
mkdir ../logs
蜗牛笔 写道这是改为thunar,如何改为konqueror呢 ...
这是改为thunar,如何改为konqueror呢?
编译命令写错了,应该是:gcc -g -o mainloop0 ...
你好,我安照你上面的代码,为什么编译的时候出现找不到函数的定义 ...linux/c/c++/杂项(92)
Makefile中,可能需要书写一些规则来描述一个.o目标文件和头文件的依赖关系.
例如,如果在main.c中使用&#include defs.h&,那么我们可能需要如下那样的一个规则来描述当头文件&defs.h&被修改以后执行make,目标&main.o&应该被重建.
main.o: defs.h
这样,在一个比较大型的工程中.就需要在Makefile中书写很多条类似于这样的规则.并且,当在源文件中加入或删除头文件后,也需要小心地去修改Makefile.
这是一件很费力、也很费时并且容易出错误的工作.为了避免这个令人讨厌的问题,现代的c编译器提供了通过查找源文件中的&#include&来自动产生这种依赖的功能.&GCC&支持一个&-M&的选项来实现此功能.&GCC&将自动找寻源文件中包含的头文件,并生成一个依赖关系.
例如,如果&main.c&只包含了头文件&defs.h&,那么在Linxu下执行下面的命令:
gcc -M main.c
main.o : main.c defs.h
既然编译器已经提供了自动产生依赖关系的功能,那么我们就不需要去动手写这些规则的依赖关系了.
但是需要明确的是:在&main.c&中包含了其他的标准库的头文件,其输出的依赖关系中也包含了标准库的头文件.
当不需要依赖关系中不考虑标准库头文件时,需要使用&-MM&参数.
需要注意的是,在使用&GCC&自动产生依赖关系时,所产生的规则中明确的指明了目标是&main.o&文件.
通过.c文件直接产生可执行文件时,作为过程文件的&main.o&的中间过程文件在使用完之后将不会被删除.
在旧版本的make中,使用编译器此项功能通常的做法是:在Makefile中书写一个伪目标&depend&的规则来定义自动产生依赖关系文件的命令.
输入&make depend&将生成一个称为&depend&的文件,其中包含了所有源文件的依赖规则描述.Makefile使用&include&指示符包含这个文件.
在新版本的make中,推荐的方式是为每一个源文件产生一个描述其依赖关系的makefile文件.对于一个源文件&NAME.c&,
对应的这个makefile文件为&NAME.d&.&NAME.d&中描述了文件&NAME.o&所要依赖的所有头文件.采用这种方式,
只有源文件在修改之后才会重新使用命令生成新的依赖关系描述文件&NAME.o&.我们可以使用如下的模式规则来自动生成每一个.c文件对应的.d文件:&
$(CC) -M $(CPPFLAGS) $& & $@. /
sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' & $@.tmp & $@; /
rm -f $@.tmp
此规则的含义是:所有的.d文件依赖于同名的.c文件.
第一行;使用c编译器自自动生成依赖文件($&)的头文件依赖关系,并输出成为一个临时文件.
如果$(CC)为GNU的C编译工具,产生的依赖关系的规则中,依赖头文件包括了所有的使用的系统头文件和用户定义的头文件.
如果需要生成的依赖描述文件不包含系统头文件,可使用&-MM&代替&-M&.
第二行;使用sed处理第二行已产生的那个临时文件并生成此规则的目标文件.这里sed完成了如下的转换过程.
例如对已一个.c源文件.将编译器产生的依赖关系:
main.o : main.c defs.h
main.o main.d : main.c defs.h
这样就将.d加入到了规则的目标中,其和对应的.o文件文件一样依赖于对应的.c源文件和源文件所包含的头文件.
当.c源文件或者头文件被改变之后规则将会被执行,相应的.d文件同样会被更新.
使用上例的规则就可以建立一个描述目标文件依赖关系的.d文件.我们可以在Makefile中使用include指示符将描述将这个文件包含进来.
在执行make时,Makefile所包含的所有.d文件就会被自动创建或者更新.Makefile中对当前目录下.d文件处理可以参考如下:&
sources = foo.c bar.c
sinclude $(sources:.c=.d)
例子中,变量&sources&定义了当前目录下的需要编译的源文件.
变量引用变换&$(sources:.c=.d)&的功能是根据需要.c文件自动产生对应的.d文件,并在当前Makefile文件中包含这些.d文件.
.d文件和其它的makefile文件一样,make在执行时读取并试图重建他们.其实这些.d文件也是一些可被make解析的makefile文件.
需要注意的是include指示符的书写顺序,因为在这些.d文件中已经存在规则.当一个Makefile使用指示符include这些.d文件时,
应该注意它应该出现在终极目标之后,以免.d文件中的规则被是Makefile的终极规则.关于这个前面我们已经有了比较详细的讨论.
一个简单的makefile示例如下:
SOURCES = $(wildcard *.c)
OBJS = $(patsubst %.c,%.o, $(SOURCES))
DEPS = $(patsubst %.c,%.d, $(SOURCES))
TARGET = main
$(TARGET):$(OBJS)
$(CC) -o $@ $^
$(CC) -MM $(CPPFLAGS) $& & $@. \
sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' & $@.tmp & $@; \
rm -f $@.tmp
sinclude $(DEPS)
rm -f $(OBJS) $(DEPS) $(TARGET)
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:61979次
积分:1125
积分:1125
排名:千里之外
原创:37篇
转载:135篇
(22)(3)(18)(1)(2)(6)(2)(3)(4)(8)(2)(1)(1)(1)(1)(1)(1)(3)(3)(4)(1)(3)(1)(1)(7)(6)(11)(2)(2)(1)(3)(3)(3)(1)(21)(8)(1)(1)(2)(4)linux 编译 库文件(1)
我的工作最近需要用到linux下构建多目录下Makefile产生a静态库样例的知识,我将最新的学习心得,做一个记录分享,以便以后需要使用时可以做参考。
#linux gcc Makefile 多文件目录静态链接库lib*.a
1.&&&&&&首先,理解概念:
1)&&&&&&静态库(staticlibraray)(libxxx.a):将函数库的链接是放在编译时期(compiletime)完成。所有相关的对象文件(object
file*.o)与牵涉到的函数库(library)被链接合成一个可执行文件(executable file).程序在运行时,与函数库不先关,因为所有需要的函数已经在产出可执行文件过程加入到可执行文件中。
2)动态库(dynamic link library)(libxxx.so):
将库函数的链接载入时间推迟到程序执行文件的时间加入,就是动态链接库。
2.&&&&&&具体的Makefile内容,具体的内容如下:
#申明变量MAKEROOT,同时获取当前的系统路径。
exportMAKEROOT := $(shell pwd)
#申明变量,常用的变量做定义
OBJ =main.o print_main.o
SRC_MAIN= $(MAKEROOT)/src/main.c $(MAKEROOT)/include/print_main.h
SRC_PRINT_MAIN= $(MAKEROOT)/src/print_main.c $(MAKEROOT)/include/print_main.h
OUT_OBJ_PATH= $(MAKEROOT)/obj
#指定当前的所有*.h的文件到include目录下去找寻。
vpath %.csrc
vpath %.hinclude
#-I指定多个目录为搜索文件的路径。
INCLUDE_DIR:= -I$(MAKEROOT)/include \
-I$(MAKEROOT)/src\
-I$(MAKEROOT)/obj\
-I$(MAKEROOT)/bin\
-I$(MAKEROOT)/lib
#定义变量保存当前的路径。
CFLAGS :=$(INCLUDE_DIR)
#a库的源文件。
SRC_LIB_FILE+= $(MAKEROOT)/src/print_main.c
#a库参数。
SO_LIB_CFLAGS+= -rsv
#输出的a库文件名称。
OUT_A_Lib:= $(MAKEROOT)/lib/libprint_main.a
#-L afterpath libso.
#-lprint_mainthe file is cancle the lib and *.a.
#-L紧紧跟当前库的目录,当前目录直接-L.
#-lprint_main去掉了libxxx.a部分。
RUN_CFLAGS+= -L$(MAKEROOT)/lib/ -lprint_main
#可执行文件的输出名称。
OUT_RUN:= -o run
#主程序依赖的文件。
SRC_MAIN= $(MAKEROOT)/src/main.c $(MAKEROOT)/include/print_main.h
#库程序依赖的文件。
SRC_PRINT_MAIN=$(MAKEROOT)/src/print_main.c$(MAKEROOT)/include/print_main.h
#库a输出的路径。
OUT_OBJ_PATH= $(MAKEROOT)/obj
#依赖关系:可执行文件main,依赖于本身的主程序和库.a文件。
#命令部分:编译C语言+文件路径参数+源文件位置+a+输出可执行
main :main.o libprint_main.a
$(CC) $(CFLAGS) $(MAKEROOT)/src/main.c$(RUN_CFLAGS) -o main
main.o :$(SRC_MAIN)
$(CC) $(CFLAGS) -c $(MAKEROOT)/src/main.c -o$(OUT_OBJ_PATH)/$@
libprint_main.a: print_main.o
$(CC_A) $(SO_LIB_CFLAGS) $(OUT_A_Lib)$(MAKEROOT)/obj/print_main.o
print_main.o: $(SRC_PRINT_MAIN)
$(CC) $(CFLAGS) -c $(MAKEROOT)/src/print_main.c-o $(OUT_OBJ_PATH)/$@
.PHONY :clean
rm -rf main
rm -rf $(MAKEROOT)/obj/*.*
rm -rf $(MAKEROOT)/lib/*.*
执行前的目录内容:
make执行后的输出内容:
Make执行后的目录输出文件:
运行文件的效果:
注意以下的内容:
linux下man ar一下就可以得到参数,这里说明几个常用的
d:从库中删除成员文件。
r:在库中加入成员文件,若存在,则替换。
c:创建一个库。
s:无论ar命令是否修改了库内容,都强制重新生成库符号表。
其他的命令用时再man。
附上源码(位置:空间中下载即可):
直接将其copy到linux目录下直接运行即可。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:7281次
排名:千里之外
转载:10篇
(1)(1)(4)(9)(1)博客访问: 55613
博文数量: 16
博客积分: 817
博客等级: 准尉
技术积分: 205
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: 项目管理
&&& 虽然以前对Makefile有个基本概念,但是真正到自己去写一个哪怕是简单的Makefile时也会遇到不少的麻烦。&&& 现在我有如下文件 dList.h dList.c memory.c debug.c debug.h test.c aaron.h 其中包含关系如下:&&& aaron.h-->dList.h debug.h&&& dList.c-->aaron.h&&& debug.c-->aaron.h&&& test.c-->aaron.h&&& memory.c-->aaron.h&&& 第一次写Makefile如下:&&& OBJS := test.o debug.o memory.o dList.o&&& MACRO = DEBUGALL&&& CFLAGS+= -g& -D$(MACRO)&&& CC = gcc&&& main: $(OBJS)&&&&&&&&&& $(CC) $(OBJS)& -D$(MACRO) $(CFLAGS) -o main& &&& clean:&&& &&& rm -f $(OBJS)&&&&&&& rm -f main&&& 第一次看看似乎没什么问题啊。真正运行发现这个Makefile没有反应出.c文件对.h文件的依赖性,所以当.h文件发生变化时Makefile执行并不会发生变化。于是有了第二版:&&& OBJS := test.o debug.o memory.o dList.o&&& MACRO = DEBUGALL&&& CFLAGS+= -g& -D$(MACRO)&&& CC = gcc&&& main: $(OBJS)&&&&&&&&&& $(CC) $(OBJS)& -D$(MACRO) $(CFLAGS) -o main& &&& %o: aaron.h&&& clean:&&& &&& rm -f $(OBJS)&&&&&&& rm -f main&&& 这样当aaron.h发生变化时,所有.o都会被更新,从而main也会被更新。但是问题还是有,aaron是依赖于dList.h, debug.h的,如果这两个头文件发生变化在这个Makefile里仍然不能使main重新编译。继续改造:&&& OBJS := test.o debug.o memory.o dList.o&&& MACRO = DEBUGALL&&& CFLAGS+= -g& -D$(MACRO)&&& CC = gcc&&& main: $(OBJS)&&&&&&&&&& $(CC) $(OBJS)& -D$(MACRO) $(CFLAGS) -o main& &&& %o: aaron.h dList.h debug.h&&& clean:&&& &&& rm -f $(OBJS)&&&&&&& rm -f main&&& 这下看上去能满足我的要求。但是仔细一想就会发现如果我这个工程很大,靠手工去找到每个.c文件对应的所有头文件然后来完成这个Makefile似乎是不太可能而且也很难维护。于是想着Makefile应该有机制能自动生成依赖关系吧。&&& 于是找出宝典《GNU make中文手册》搜索了下果然有自动生成依赖相关内容。主要是利用gcc 的编译选项-M和-MM。不过让我看了半天也没有看明白其中的玄机。最后又重新翻看了改宝典众多章节总算理解了。先把代码贴出来:&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&& MACRO = DEBUGALL&&& CFLAGS+= -g -w -D$(MACRO)&&& SOURCES = $(wildcard *.c)&&& OBJS := $(patsubst %.c, %.o,$(SOURCES))&&& &&& CC = gcc&&& main: $(OBJS)&&&&&&&&&& @echo "source files:" $(SOURCES)&&&&&&&&&& @echo "object files:" $(OBJS)&&&&&&&&&& $(CC) $(OBJS)& -D$(MACRO) $(CFLAGS) -o main& &&& sinclude $(SOURCES:.c=.d)&&& %d: %c&&&&&&&&& @echo "create depend"&&&&&&&&& $(CC) -MM $(CFLAGS) $ $@.$$$$; \&&&&&&&&& sed 's,\($*\)\.o[ :]*,\1.o $@ ,g'
$@; \&&&&&&&&& $(RM) $@.$$$$&&&&&&&&& & clean:&&&&&&&&& rm -rf $(OBJS)&&&&&&&&& rm -f main&&& 下面一行一行来分析下这个Makefile.&&& 前面两行很简单就是定义编译变量和编译选项。&&& SOURCES = $(wildcard *.c) 这句话意思是定义一个变量SOURCES,它的值包含当前目录下所有.c文件。 在我的例子里我把这个值打印出来了就是dList.c memory.c test.c debug.c&&& $(wildcard PATTEN) 是Makefile内建的一个函数:&&& 函数名称:获取匹配模式文件名函数—wildcard&&& 函数功能:列出当前目录下所有符合模式“PATTERN”格式的文件名。&&& 返回值:空格分割的、存在当前目录下的所有符合模式“PATTERN”的文件名。&&& 函数说明:“PATTERN”使用shell可识别的通配符,包括“?”(单字符)、“*”(多字符)等&&& &&& &&& OBJS := $(patsubst %.c, %.o,$(SOURCES)) 这一行是定义了一个变量OBJS,它的值是将变量SOURCES里的内容以空格分开,将所有.c文件替换成.o. 在我的例子里打印出来就是dList.o memory.o test.o debug.o。&&& $(patsubst PATTEN, REPLACEMENT, TEXT)也是内建函数&&& 函数名称:模式替换函数—patsubst。&&& 函数功能:搜索“TEXT”中以空格分开的单词,将否符合模式“TATTERN”替换为“REPLACEMENT”&&& &&& &&& sinclude $(SOURCES:.c=.d) 这一行是非常关键的,它在当前Makefile里去include另外的Makefile. 这里“另外”的Makefile是将SOURCES变量里所有.c替换成.d。 在我的例子里就是dList.d memory.d test.d debug.d. 意思就是执行到这里&&& 的时候先去依次执行dList.d memory.d test.d debug.d. 这里的.d文件就是包含了每个.c文件自动生成的对头文件的依赖关系。这个依赖关系将由下面的%d:%c来完成。&&& &&& %d: %c&&& 此规则的含义是:所有的.d文件依赖于同名的.c文件。第一行;使用c编译器自自动生成依赖文件($<)的头文件的依赖关系,并输出成为一个临时文件,“$$$$”表示当前进程号。如果$(CC)为GNU的c编译工具,产生的依赖关系的规则中,依赖头文件包括了所有的使用的系统头文件和用户定义的头文件。如果需要生成的依赖描述文件不包含系统头文件,可使用“-MM”代替“-M”。第二行;使用sed处理第二行已产生的那个临时文件并生成此规则的目标文件。经过这一行后test.d里内容如下:test.o: test.c aaron.h dList.h debug.h 其他.d里以此类推。第三行;删除临时文件。&&& 到这里基本的意义弄明白了,但是让我不解的是%d: %c这个依赖的规则怎么能被执行到的?按照我的理解Makefile在执行时首先检查终极目标main是否存在,如果不存在则建立(根据main的依赖规则),如果存在在需要查看&&& main的依赖文件是否存在并且是最新的,这我的例子里就是要看test.o dList.o memory.o debug.o是否存在且最新。这样追下去是否没有%d: %c什么事啊, .d文件也应该不存在或者说是空的。尽管我们include了.d文件,但是没有依赖规则去执行它啊。后来仔细阅读了&&& Makefile文件的重建才明白了。&&& Makefile如果由其它文件重建(这里我的Makefile include了所有.d文件,.d也可以看成是一个Makefile),Makefile在读入所有其他makefile文件(.d)之后,首先将所读取的每个makefile(.d)作为一个目标,寻找更新它们的规则。同样&&& 如果此目标不存在则根据依赖规则重新创建。在例子里其实.d文件开始并不存在,所以当Makefile在include这些.d文件时首先看.d存在不,不存在就要去寻找.d的依赖文件和规则。这里就找到了%d: %c从而创建出真正的.d文件。其实这里的关键点就是对于&&& include了理解,它是把include的文件首先当成一个目标,然后要去寻找其依赖文件和规则的,而不是我事先想象的简单的把其他文件的内容包含过来。&&& 到此,问题解决,基本达到预期。
阅读(9374) | 评论(0) | 转发(2) |
下一篇:没有了
相关热门文章
给主人留下些什么吧!~~
请登录后评论。

我要回帖

更多关于 makefile 依赖库 的文章

 

随机推荐