Makefile这玩意在上学时就应该学,可是一直沉浸于IDE的诱惑,所谓“死于安乐”,直到现在一把年纪才开始接触这种基础东西。
创建C程序
先写个c程序,保存在main.c里:
- //////////////////
- //file:main.c
- //////////////////
- #include<stdio.h>
- intmain()
- {
- intc=0;
- printf("Tommy:%d\n",c+5);
- return0;
- }
看看我这时的目录结构
- ~/code/makefile$ls
- main.c
这时敲个“make”命令试试?
- ~/code/makefile$make
- make:***没有指明目标并且找不到makefile。停止。
创建makefile文件
显然,我们要建个名为“makefile”的文件。先建一个空的名为makefile的文件:
- ~/code/makefile$touchmakefile
- tommy@tommy-zheng-ThinkPad-T61:~/code/makefile$ls
- main.cmakefile
这时再试试“make”命令:
- ~/code/makefile$make
- make:***无目标。停止。
加入target
错误“无目标”告诉我们需要在makefile里添加一些东西:
- #注释file:makefile
- target:
再执行“make”命令:
- ~/code/makefile$make
- make:没有什么可以做的为`target'。
可以看到前面“无目标”的错误已经解决了。
加入命令
继续往makefile里添加东西:
- #注释file:makefile
- target:
- gcc-otommymain.c#注意,最前面是tab,不是空格!
好了,执行make命令:
- ~/code/makefile$make
- gcc-otommymain.c
- ~/code/makefile$ls
- main.cmakefiletommy
main.c被编译了,一个可执行文件“tommy”产生了。我们执行一下试试:
- ~/code/makefile$./tommy
- Tommy:5
我们的makefile写完了!!!
好吧,之前的makefile实在是太简单,以至于没什么实际的用途。现在再深入研究下。
Target
在前面的makefile里,有一个叫"target"的东西。其实它可以是任何名字,而且一个makefile里可以有多个target。比如下面的makefile:
- #注释file:makefile
- tommy:
- gcc-otommymain.c#注意,最前面是tab,不是空格!
- dosomething:
- echojustforfun.
给make命令一个参数:
- ~/code/makefile$makedosomething
- echojustforfun.
- justforfun.
可以看到,make可以用来执行任何一个target底下的命令,而这种命令并不局限于gcc这种编译的命令。每个target用冒号隔开。如果make命令没有指定哪个target,那第一个target下的命令会被执行。
Dependencies
make命令一次只能处理一个target,但如果我想一次处理多个target怎么办?这时可以为一个target在冒号后面指定它所依赖的target。修改下makefile:
- #注释file:makefile
- tommy:
- gcc-otommymain.c#注意,最前面是tab,不是空格!
- dosomething:dofirstdosecond#先执行另两个target的命令
- echojustforfun.
- dofirst:
- echofirst.
- dosecond:
- echosecond.
- donothing:
- echonothing.
make一下看看:
- ~/code/makefile$makedosomething
- echofirst.
- first.
- echosecond.
- second.
- echojustforfun.
- justforfun.
可以看到,dofirst和dosecond在dosomething之前都被make了,但tommy和donothing都没有执行。
编译多个C文件
现在增加两个文件f.h和f.c,同时改一下main.c:
- ////////////////
- //file:f.h
- ////////////////
- intadd(int,int);
- ////////////////
- //file:f.c
- ////////////////
- intadd(inta,intb)
- {
- returna+b;
- }
- //////////////////
- //file:main.c
- //////////////////
- #include<stdio.h>
- #include"f.h"
- intmain()
- {
- printf("Tommy-add:%d\n",add(2,4));
- return0;
- }
看看我的目录结构:
- ~/code/makefile$ls
- f.cf.hmain.cmakefile
基于前面的“Dependencies”得到的结论,我们可以改写makefile,来让main函数调用f函数:
- #file:makefile
- tommy:main.of.o
- gcc-otommymain.of.o
- main.o:
- gcc-cmain.c-omain.o
- f.o:
- gcc-cf.c-of.o
看下生成的结果:
- ~/code/makefile$make
- gcc-cmain.c-omain.o
- gcc-cf.c-of.o
- gcc-otommymain.of.o
- ~/code/makefile$ls
- f.cf.hf.omain.cmain.omakefiletommy
- ~/code/makefile$./tommy
- Tommy-add:6
可以看到我们的生成了我们想要的东西。
clean与install
经常可以看到“make clean”和“make install”的命令。我们也可以提供它们:
- #file:makefile
- tommy:main.of.o
- gcc-otommymain.of.o
- main.o:
- gcc-cmain.c-omain.o
- f.o:
- gcc-cf.c-of.o
- clean:
- rm*.o
- install:
- mvtommy/usr/local
宏
最后再研究下makefile里的宏。其实就是定义一个变量,之后再使用它:
- #file:makefile
- INSTALL_PATH=/usr/local
- TEMP_FILES=*.o
- tommy:main.of.o
- gcc-otommy\
- main.of.o#这里演示反斜杠用于换行,注意反斜杠后没有空格,行首是tab而非空格
- main.o:
- gcc-cmain.c-omain.o
- f.o:
- gcc-cf.c-of.o
- clean:
- rm$(TEMP_FILES)
- install:
- mvtommy$(INSTALL_PATH)