在netbeans里开发,有一个重要文件makefile,是用来编译所有的文件。
项目的目录结构如下,扁平的目录结构,如何实现自动化编译,写makefile呢?
第一版 基础版:CC = g++
CFLAGS = -O3 -DNDEBUG
SOURCE =AdaBoost.cpp aodeselect.cpp sample.cpp vfan.cpp kdbext2.cpp tan_gen.cpp
petal: ${SOURCE}
$(CC) -o $@ ${SOURCE} $(CFLAGS)
.PHONY:clean
clean:
rm -f petal.exe
简简单单,petal依赖所有的cpp,如果cpp有所修改那么就会全部重新编译,生成新的petal
十分耗时,大致需要
CFLAGS 就是传给编译器的编译参数,定义成了一个变量
第二版 雏形版 :CC = g++
CFLAGS = -O3 -DNDEBUG Debug版会使用参数-g;Release版使用-O3 –DNDEBUG
SOURCE =AdaBoost.cpp aodeselect.cpp sample.cpp变量的用法
default: petal 目标是生成default,要生成default,就要生成 petal ,规则没写,就是生成petal
echo "default"
depend: .depend 没什么用
echo "depend"
.depend: $(SOURCE) 依赖的是所有的.cpp 只要一个cpp文件有所修改 就要执行如下命令
echo ".depend"
rm -f ./.depend 删除当前目录下的.depend
$(CC) $(CFLAGS) -MM $^ >> ./.depend; -MM 自动找寻源文件中包含的非标准库头文件,并生成一个依赖关系 > 是定向输出到文件,如果文件不存在,就创建文件;如果文件存在,就将其清空; >> 这个是将输出内容追加到目标文件中。如果文件不存在,就创建文件;如果文件存在,则将新的内容追加到那个文件的末尾,该文件中的原有内容不受影响
$^--所有的依赖文件
.depend里的示例内容如下:
naomiaode.o: naomi/naomiaode.cpp naomi/naomiaode.h \
naomi/../incrementalLearner.h naomi/../learner.h \
naomi/../instanceStream.h naomi/../instance.h naomi/../capabilities.h \
naomi/../xxxxyDist.h naomi/../xxxyDist.h naomi/../xxyDist.h \
naomi/../xyDist.h naomi/../smoothing.h naomi/../utils.h \
naomi/../mtrand.h naomi/../FILEtype.h naomi/../crosstab.h
其实就是找出source所有的cpp文件依赖的头文件,并放到.depend里
include .depend 要把.depend加进来
petal: ${SOURCE}
$(CC) -o $@ ${SOURCE} $(CFLAGS) g++ -o 目标可执行文件 源文件 参数
petal64: ${SOURCE} 没有写要生成它,毫无作用
$(CC) -o $@ ${SOURCE} $(CFLAGS) –DSIXTYFOURBITCOUNTS
输出:
.depend文档:
流程:
首先我遇到了include 就要先生成.depend文档,生成完文档后,把文档中的.o与.c的依赖关系代替include指令,包括到makefile里面来。所以要生成.depend对象,如果源代码.cpp有所修改的话,就要删除原来的.depend文档,把依赖关系重新写入文档中。
Include阶段结束
然后,最终目标是default,要生成default,就要生成依赖petal,要生成petal,看一看发现.cpp有所修改,重新全部编译,删去.o中间文件(直接 – a.cpp不会出现.o中间文件)
生成了petal,生成完petal后,就返回去生成deafault,所谓的生成default不是说我一定要真的-o deafault才好,我要有default.exe,不是这样的,执行规则,就是生成对象,可惜default的规则,就是一条echo.那么打印完字符串,default也就生成了
这一版本因为有要输出所有头文件依赖,耗时惊人 2m57s
而且白把依赖关系include进来了,可惜petal依赖的还是cpp文件,生成依赖关系毫无作用
第三版 自动化编译 依赖.o 依赖于目标代码:我们把petal不依赖于cpp,不然每次都要全部重新编译,不如依赖.o ,哪个cpp改了,就生成那个的.o,其它cpp的.o都不用动,编译迅速
在旧版本的make中,使用编译器此项功能通常的做法是:在Makefile中书写一个伪目标"depend"的规则来定义自动产生依赖关系文件的命令。输入"make depend"将生成一个称为"depend"的文件,其中包含了所有源文件的依赖规则描述。Makefile使用"include"指示符包含这个文件。
这就是第二版的做法的初衷,depend对象也就是这么来的,这样petal依赖.o 再把.o依赖那些cpp和头文件都包含进来,哪个cpp改了,从而要改哪个.o对象,也就明白了,那么别的.o都不用重新编译,连接起来是非常快的,而且可以利用隐含规则,不必写如何通过.cpp和.h生成.o,十分爽
--------------------------------------分割线 --------------------------------------
Makefile之Linux内核模块的Makefile写法分析
Makefile之大型工程项目子目录Makefile的一种通用写法
--------------------------------------分割线 --------------------------------------
CC = g++
CFLAGS = -O3 -DNDEBUG
SOURCE = naomi/naomiaode.cpp naomi/naominbaode.cpp sampler.cpp trainTest.cpp ALGLIB_ap.cpp
OBJ= naomi/naomiaode.o naomi/naominbaode.o sampler.o trainTest.o ALGLIB_ap.o
default:petal 要注意的是要把目标放在第一个 一旦include进来之后,include进来的第一条目标naomi/naomiaode.o: naomi/naomiaode.cpp naomi/naomiaode.h \就是总目标了,所以就不以petal作为目标了
echo "default"
depend: .depend 可以使用make depend手动产生.depend依赖文件
echo "depend"
.depend: $(SOURCE)
echo ".depend"
rm -f ./.depend
$(CC) $(CFLAGS) -MM $^ >> ./.depend;
include .depend
petal: ${OBJ}
$(CC) -o $@ ${OBJ} $(CFLAGS)
.PHONY:clean
clean:
rm -f ${OBJ} petal.exe
现在makefile文件其实是这样的:
.depend: $(SOURCE)
echo ".depend"
rm -f ./.depend
$(CC) $(CFLAGS) -MM $^ >> ./.depend;
Petal: naomi/naomiaode.o naomi/naominbaode.o sampler.o trainTest.o ALGLIB_ap.o
$(CC) -o $@ ${OBJ} $(CFLAGS)
现在petal依赖于.o,而.o 依赖于cpp 与 h,当修改一个cpp的时候,会重新生成.depend文件,包括进.o最新的依赖,然后检查petal是否需要重新生成,petal依赖的naomi/naomiaode.o需要重新生成吗?由于cpp的修改时间比.o的早,要重新生成.o petal依赖的sampler.o需要重新生成吗?一个个检查下去
比如我修改了
以下四个文件,而petal的依赖关系为:
petal:AdaBoost.o aodeselect.o sample.o vfan.o
所以会按序重新生成:
速度很快,但是这个版本还是有他自己的问题:
修改.h的时候,没有重新生成.depend会出错
修改一个.cpp,没有必要重新产生所有cpp的依赖,依赖关系其实也像目标文件一样,修改 了cpp或h的文件重新产生它的依赖关系,没有修改的依赖关系不动。所以才有了.d文件版
当修改一个cpp的时候,比如naomi/naomiaode.cpp
就要重新写.depend文件,耗时较大
可以很明显地看到,只重新编译了naomiaode.cpp,耗时只有40s!!!! 从3分钟降到40s秒,划时代的进步,真正发挥了make的作用。