makefile使cpp文件依赖头文件

读代码时发现目前工程中的makefile文件中有一个问题或bug,.即cpp文件没有和该.cpp文件include的头文件建立依赖性。这个危害是,当头文件被修改后,受影响的.cpp文件对应的.o文件不会被重新创建。 而目前的代码中大量使用C++模板,模板的实现全部写在.h文件中. 我做了个实验,修改了单件模板的实现文件 SingletonHolder.h。虽然这个修改影响了大量include了SingletonHolder.h的.cpp文件,但它们对应的.o全被没有被重新编译。 解决方法是用g++编译器提供的 -MM 选项。这个选项会让g++在把.cpp依赖的头文件(除系统头文件)全部列出来。具体的使用方法可以查阅手册。思路是,把cpp文件和头文件的依赖性写入到.d文件,在主makefile文件中include所有的.d文件。 以tcpd工程为列,修改后的makefile如下(亦见附件),该makefile可以检查到.cpp依赖的头文件被修改,使得重新生成目标文件。 include ./makefile.def SRCS = $(wildcard *.cpp) OBJS = $(patsubst %.cpp,%.o,$(SRCS)) # 每个.cpp都对应一个.d文件,.d文件由g++ -MM生成,列出了.cpp依赖的头文件. DEPENDENCIES = $(subst .cpp,.d,$(SRCS)) TARGET = tcpd OK = [\e[1m\e32m OK [\em FAILURE = [\e[1m\e31m FAILURE [\em all:$(TARGET) # 使包含.d文件,.d文件指定了.o文件依赖哪些头文件。 # 如果不是make clean 就include所有的.d文件。 ifneq “$(MAKECMDGOALS)” “clean” -include $(DEPENDENCIES) endif # 此函数生成.d文件,参考g++的 -MM -MF -MT选项 #$(call make-depend,source-file,object-file,depend-file) define make-depend g++ -MM -MF $3 -MT $2 $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) $1 ...

August 7, 2013 · 1 min · kamus

Linux内核Makefiles教程(二)

接第一篇 **3.3.**可加载模块目标 obj-m (Loadable module goals – obj-m) obj-m指定将被构建为可加载内核模块的对象文件(object file)。 一个模块可以从一个源文件构建或者从多个源文件构建。如果模块仅仅从一个源文件构建,kbuild makefile仅仅把对象文件加到obj-m。如下: #drivers/isdn/i4l/Makefile obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o _在这个例子中,__$(CONFIG_ISDN_PPP_BSDCOMP)_被求值为__m. If a kernel module is built from several source files, you specify that you want to build a module in the same way as above. 如果一个内核模块需要从多个源文件构建,你也是按照刚才提到的那一行指定。不过,除此之外,还要额外地指定,你的内核模块需要哪些对象文件。所以还需要设置<模块名>-objs变量。如下: #drivers/isdn/i4l/Makefile obj-$(CONFIG_ISDN) += isdn.o isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o 在这个例子中,模块名是 isdn 。Kbuild将编译isdn-objs列出的所有对象文件,然后运行$(LD) –r把这些对象文件链接成一个文件isdn.o。 Kbuild用-objs后缀或者-y后缀识别构成复合对象文件(composite objects)的对象文件。这样,Makefile就可以使用CONFIG_* 符号来确定一个对象文件是不是一个复合对象文件的一部分。如下: #fs/ext2/Makefile obj-$(CONFIG_EXT2_FS) += ext2.o ext2-y := balloc.o bitmap.o ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o ...

July 7, 2012 · 1 min · kamus

Linux内核Makefiles教程(一)

 Linux内核Makefiles 本教程描述了了Linux内核的Makefile是如何工作的。 1. 概述 Linux内核的Makefile包括五个部分。 Makefile <td style="width:373px;"> <p> 最上层Makefile </p> </td> .config <td style="width:373px;"> <p> 内核配置文件。 </p> </td> arch/$(ARCH)/Makefile <td style="width:373px;"> <p> CPU架构相关Makefile </p> </td> scripts/Makefile.* <td style="width:373px;"> <p> 对于所有Kbuild&nbsp;Makefile的公共方法。. </p> </td> kbuild Makefiles <td style="width:373px;"> <p> 有将近500个kbuild&nbsp;Makefiles。 </p> </td> 最上层Makefile读取.config文件。.config文件是由内核配置过程生成的。 最上级的Makefile负责生成linux的内核映象文件vmlinux和其它所有的模块。最上级Makefile递归地进入内核代码树的各级子目录分别执行子目录下的Makefile。究竟要进入哪些子目录是由内核配置阶段决定的,即配置在.cncfig文件中。最上级Makefile提定了一个路径为arch/$(ARCH)/Makefile的子目录Makefile。这个Makefile中定义了与处理器架构紧密相关的信息。 每一个子目录下面都有一个kbuild Makefile,这里都定义了一些makefile命令和变量可以被更下级的Makefile继承。Kbuild Makefile使用来自.config配置的信息生成各种文件列表用来构建内建的或者模块化的目标文件。Scripts/Makefile.*包括了很多被其它Makefile使用定义和规则。 2. 谁使用内核Makefile 内核Makefile的使用者可以大致分为四种。 用户(Userse) 这类使用者仅仅敲入一些命令,如“make menuconfig”或者“make”。他们很少会阅读甚修改内核Makefile和源代码文件。 一般开发者(Normal Developers) 一般开发者一般编写一些设备驱动程序,文件系统,网络协议。他们需要维护他们编写的代码涉及的子系统的kbuild Makefiles。为了工作地更有效率,他们甚至还需要对整个内核的Makefile有全局的把握,包括对kbuild的公共接口的详尽了解。 处理器架构开发者(Arch Developers) 这部分开发者关心与某个处理器架构紧密相关的代码部分,比如PC上最广泛使用的x86,以及IA64,还有ARM,Sparc,PowerPC,Alpha,s390,MIPS。Linux支持几百种处理器架构。从内核2.6.24开始,i386和x86_64合并为x86。 KBuild的开发者(KBuild Developers) KBuild的开发者就是维护内核构建系统的开发者,他们需要知道内核Makefile的各个方面。 —— 本篇教程主要面向第二类开发者和第三类开发者。即一般开发者和处理器体系架构开发者。 3. kbuild文件 大多数内核Makefile文件是kbuild Makefile文件,它们使用不同于一般make文件的kbuild语法。下面会介绍kbuild makefile的语法。Kbuild文件一般被命名为Mafile,但是也可以使用Kbuild名字。如果已经存在一个Makefile文件了,那么就只好用Kbuild名字了。 ...

July 6, 2012 · 1 min · kamus

linux的soname,链接库的问题.

第一次看到soname是读<程序员的自我修养.第一册:链接库>看来的。顺便说一下,这本书确实是本好书吖,国内出的难得技术好书。后来在公司的项目中把它从windows平台下移植到linux下,写makefile时用到过。 再后来又忘记了。今天再次看到soname的时候就有点记不起来了。又只好搜索了一些资料看。趁热打铁把学会的东西记下来。 linux为尝试解决动态链接库版本冲突的问题(windows平台下称之为DLL HELL),引入了soname进制。linux的动态链接库的扩展名约定为.so 即shared object的缩写。下面的makefile语句来自于哥今年上半年写的makefile文件: VERSION_NUM := 1.0.0 soname = lib$(dirname).so.$(firstword $(subst ., ,$(VERSION_NUM))) LINKFLAGS := -shared -Wl,-soname,$(soname) -L. -lpthread -lrt -lpentagon -lcross_platform 其中的变量$(soname)会被替换为eibcomm.so.1。再看看LINKFLAGS变量指定的几个选项. -shared 表示要生成一个shared object,即动态共享库. -pthread -lrt -lpentagon -lcross_platform 是要链接其它几个库,thread和linux的posix线程库,rt是一个和实时系统相关的库它提供了高精度的时间函数。 比较奇怪的是 -Wl,-soname,$(soname) 它们之前用逗号分开,而不是用空格分开。实际上这几个东东会被gcc传给ld(linux下的链接器)作为链接器的参数。gcc规定的写法就是这样的。指定的soname会被链接器写入到最终生成的elf文件中(linux下的可执行文件格式)。要查看elf文件的段布局什么的,可以用readelf工具。 最终生成的文件将命名为 libname.so.x.y.z 的形式。soname是libname.so.x的格式(也不尽然,这只是一个convetion,并非在语法或机制上强行要求)。接着把生成的so文件拷贝到/usr/lib 或者 /lib,这两个文件夹是系统用来放置动态链接库的地方。debian下没有把/usr/local/lib作为默认的动态链接库文件夹.可以通过改/etc/ld.so.conf 文件把更多的路径加入。再运行 ldconfig,更新cache中的库文件信息。为什么要用cache呢,有人就问了!因为library实在太多了咯,cache就被引用了。cache是个好东西啊!!! 这个时候依赖 libname.so.x 的文件就可以找到这个library并加载起来了。但是编译程序时还是找不到呢.编译程序时通常会写 -lname 这个时候会先找 libname.so 再找 libname.a 文件,结果找不到。link就会抱怨没有找到这个库文件。为了让编译通过,于是你就用 ln -sf libname.so libname.so.x.y.z (这个是realname,版本号部分可能只有x.y两个部分) 建一个软链接!搞定! copyright ykyi.net

December 8, 2011 · 1 min · kamus