搜档网
当前位置:搜档网 › 万能makefile写法详解

万能makefile写法详解

万能makefile写法详解
万能makefile写法详解

“万能makefile”写法详解,一步一步写一个实用的makefile,详解sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \

目的:编写一个实用的makefile,能自动编译当前目录下所有.c/.cpp源文件,支持二者混合编译。并且当某个.c/.cpp、.h或依赖的源文件被修改后,仅重编涉及到的源文件,未涉及的不编译。

要达到这个目的,用到的技术有:

1-使用wildcard函数来获得当前目录下所有.c/.cpp文件的列表。

2-make的多目标规则。

3-make的模式规则。

4-用gcc -MM命令得到一个.c/.cpp文件include了哪些文件。

5-用sed命令对gcc -MM命令的结果作修改。

6-用include命令包含依赖描述文件.d。

三准备知识

(一)多目标

对makefile里下面2行,可看出多目标特征,执行make bigoutput或make littleoutput可看到结果:

[html]view plaincopy

1.bigoutput littleoutput: defs.h pub.h

2.@echo $@ $(subst output,OUTPUT,$@) $^ # $@指这个规则里所有目标的集合,$^指这个

规则里所有依赖的集合。该行是把目标(bigoutput或littleoutput)里所有子串output替换成大写的OUTPUT

(二)隐含规则

对makefile里下面4行,可看出make的隐含规则,执行foo可看到结果:

第3、4行表示由.c得到.o,第1、2行表示由.o得到可执行文件。

如果把第3、4行注释的话,效果一样。

即不写.o来自.c的规则,它会自动执行gcc -c -o foo.o foo.c这条命令,由.c编译出.o(其中-c表示只编译不链接),然后自动执行gcc -o foo foo.o链接为可执行文件。

[html]view plaincopy

1.foo:foo.o

2.gcc -o foo foo.o; ./foo

3.foo.o:foo.c #注释该行看效果

4.gcc -c foo.c -o foo.o #注释该行看效果

(三)定义模式规则

下面定义了一个模式规则,即如何由.c文件生成.d文件的规则。

[html]view plaincopy

1.foobar: foo.d bar.d

2.@echo complete generate foo.d and bar.d

3.%.d: %.c #make会对当前目录下每个.c文件,依次做一次里面的命令,从而由每个.c文

件生成对应.d文件。

4.@echo from $< to $@

5.g++ -MM $< > $@

假定当前目录下有2个.c文件:foo.c和bar.c(文件内容随意)。

验证方法有2种,都可:

1-运行make foo.d(或make bar.d),表示想要生成foo.d这个目标。

根据规则%.d: %.c,这时%匹配foo,这样%.c等于foo.c,即foo.d这个目标依赖于foo.c。

此时会自动执行该规则里的命令gcc -MM foo.c > foo.d,来生成foo.d这个目标。

2-运行make foobar,因为foobar依赖于foo.d和bar.d这2个文件,即会一次性生成这2个文件。

下面详述如何自动生成依赖性,从而实现本例的makefile。

(一)

本例使用了makefile的模式规则,目的是对当前目录下每个.c文件,生成其对应的.d文件,例如由main.c生成的.d文件内容为:

[html]view plaincopy

1.main.o : main.c command.h

这里指示了main.o目标依赖于哪几个源文件,我们只要把这一行的内容,通过make的include 指令包含到makefile文件里,即可在其任意一个依赖文件被修改后,重新编译目标main.o。下面详解如何生成这个.d文件。

(二)

gcc/g++编译器有一个-MM选项,可以对某个.c/.cpp文件,分析其依赖的源文件,例如假定main.c的内容为:

[cpp]view plaincopy

1.#include //标准头文件(以<>方式包含的),被-MM选项忽略,被-M选项收集

2.#include "stdlib.h"//标准头文件(以""方式包含的),被-MM选项忽略,被-M选项收集

3.#include "command.h"

4.int main()

5.{

6.printf("##### Hello Makefile #####\n");

7.return 0;

8.}

则执行gcc -MM main.c后,屏幕输出:

[html]view plaincopy

1.main.o: main.c command.h

执行gcc -M main.c后,屏幕输出:

[html]view plaincopy

1.main.o: main.c /usr/include/stdio.h /usr/include/features.h \

2./usr/include/bits/predefs.h /usr/include/sys/cdefs.h \

3./usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \

4./usr/include/gnu/stubs-64.h \

5./usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h \

6./usr/include/bits/types.h /usr/include/bits/typesizes.h \

7./usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \

8./usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h \

9./usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \

10./usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h \

11./usr/include/endian.h /usr/include/bits/endian.h \

12./usr/include/bits/byteswap.h /usr/include/sys/select.h \

13./usr/include/bits/select.h /usr/include/bits/sigset.h \

14./usr/include/bits/time.h /usr/include/sys/sysmacros.h \

15./usr/include/bits/pthreadtypes.h /usr/include/alloca.h command.h

(三)

可见,只要把这些行挪到makefile里,就能自动定义main.c的依赖是哪些文件了,做法是把命令的输出重定向到.d文件里:gcc -MM main.c > main.d,再把这个.d文件include到makefile 里。

如何include当前目录每个.c生成的.d文件:

[html]view plaincopy

1.sources:=$(wildcard *.c) #使用$(wildcard *.cpp)来获取工作目录下的所有.c文件的列表。

2.dependence=$(sources:.c=.d) #这里,dependence是所有.d文件的列表.即把串sources串里

的.c换成.d。

3.include $(dependence) #include 后面可以跟若干个文件名,用空格分开,支持通配符,例如

include foo.make *.mk。这里是把所有.d文件一次性全部include 进来。注意该句要放在终极目标all的规则之后,否则.d文件里的规则会被误当作终极规则了。

(四)

现在main.c command.h这几个文件,任何一个改了都会重编main.o。但是这里还有一个问题,如果修改了command.h,在command.h中加入#include "pub.h",这时:

1-再make,由于command.h改了,这时会重编main.o,并且会使用新加的pub.h,看起来是正常的。

2-这时打开main.d查看,发现main.d中未加入pub.h,因为根据模式规则%.d: %.c中的定义,只有依赖的.c文件变了,才会重新生成.d,而刚才改的是command.h,不会重新生成main.d、及在main.d中加入对pub.h的依赖关系,这会导致问题。

3-修改新加的pub.h的内容,再make,果然问题出现了,make报告up to date,没有像期望那样重编译main.o。

现在问题在于,main.d里的某个.h文件改了,没有重新生成main.d。进一步说,main.d里给出的每个依赖文件,任何一个改了,都要重新生成这个main.d。

所以main.d也要作为一个目标来生成,它的依赖应该是main.d里的每个依赖文件,也就是说make里要有这样的定义:

[html]view plaincopy

1.main.d: main.c command.h

这时我们发现,main.d与main.o的依赖是完全相同的,可以利用make的多目标规则,把main.d与main.o这两个目标的定义合并为一句:

[html]view plaincopy

1.main.o main.d: main.c command.h

现在,main.o: main.c command.h这一句我们已经有了,如何进一步得到main.o main.d: main.c command.h呢?

(五)

解决方法是行内字符串替换,对main.o,取出其中的子串main,加上.d后缀得到main.d,再插入到main.o后面。能实现这种替换功能的命令是sed。

实现的时候,先用gcc -MM命令生成临时文件main.d.temp,再用sed命令从该临时文件中读出内容(用<重定向输入)。做替换后,再用>输出到最终文件main.d。

命令可以这么写:

[html]view plaincopy

1.g++ -MM main.c > main.d.temp

2.sed 's,\(main\)\.o[ :]*,\1.o main.d : ,g' < main.d.temp > main.d

其中:

sed 's,\(main\)\.o[ :]*,\1.o main.d : ,g',是sed命令。

< main.d.temp,指示sed命令从临时文件main.d.temp读取输入,作为命令的来源字符串。

> main.d,把行内替换结果输出到最终文件main.d。

(六)

这条sed命令的结构是s/match/replace/g。有时为了清晰,可以把每个/写成逗号,即这里的格式s,match,replace,g。

该命令表示把源串内的match都替换成replace,s指示match可以是正则表达式。

g表示把每行内所有match都替换,如果去掉g,则只有每行的第1处match被替换(实际上不需要g,因为一个.d文件中,只会在开头有一个main.o:)。

这里match是正则式\(main\)\.o[ :]*,它分成3段:

第1段是\(main\),在sed命令里把main用\(和\)括起来,使接下来的replace中可以用\1引用main。

第2段是\.o,表示匹配main.o,(这里\不知何意,去掉也是可以的)。

第3段是正则式[ :]*,表示若干个空格或冒号,(其实一个.d里只会有一个冒号,如果这里写成[ ]*:,即匹配若干个空格后跟一个冒号,也是可以的)。

总体来说match用来匹配'main.o :'这样的串。

这里的replace是\1.o main.d :,其中\1会被替换为前面第1个\(和\)括起的内容,即main,这样replace值为main.o main.d :

这样该sed命令就实现了把main.o :替换为main.o main.d :的目的。

这两行实现了把临时文件main.d.temp的内容main.o : main.c command.h改为main.o main.d : main.c command.h,并存入main.d文件的功能。

(七)

进一步修改,采用自动化变量。使得当前目录下有多个.c文件时,make会依次对每个.c文件执行这段规则,生成对应的.d:

[html]view plaincopy

1.gcc -MM $< > $@.temp;

2.sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.temp > $@;

(八)

现在来看上面2行的执行流程:

第一次make,假定这时从来没有make过,所有.d文件不存在,这时键入make:

1-include所有.d文件的命令无效果。

2-首次编译所有.c文件。每个.c文件中若#include了其它头文件,会由编译器自动读取。由于这次是完整编译,不存在什么依赖文件改了不会重编的问题。

3-对每个.c文件,会根据依赖规则%.d: %.c,生成其对应的.d文件,例如main.c生成的main.d 文件为:

[html]view plaincopy

1.main.o main.d: main.c command.h

第二次make,假定改了command.h、在command.h中加入#include "pub.h",这时再make:

1-include所有.d文件,例如include了main.d后,得到依赖规则:

[html]view plaincopy

1.main.o main.d: main.c command.h

注意所有include命令是首先执行的,make会先把所有include进来,再生成依赖规则关系。

2-此时,根据依赖规则,由于command.h的文件戳改了,要重新生成main.o和main.d文件。3-先调用gcc -c main.c -o main.o生成main.o,

再调用gcc -MM main.c > main.d重新生成main.d。

此时main.d的依赖文件里增加了pub.h:

[html]view plaincopy

1.main.o main.d: main.c command.h pub.h

4-对其它依赖文件没改的.c(由其.d文件得到),不会重新编译.o和生成其.d。

5-最后会执行gcc $(objects) -o main生成最终可执行文件。

第三次make,假定改了pub.h,再make。由于第二遍中,已把pub.h加入了main.d的依赖,此时会重编main.c,重新生成main.o和main.d。

这样便实现了当前目录下任一源文件改了,自动编译涉及它的.c。

(九)

进一步修改,得到目前大家普遍使用的版本:

[html]view plaincopy

1.set -e; rm -f $@; \

2.$(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \

3.sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \

4.rm -f $@.$$$$

第一行,set -e表示,如果某个命令的返回参数非0,那么整个程序立刻退出。

rm -f用来删除上一次make时生成的.d文件,因为现在要重新生成这个.d,老的可以删除了(不删也可以)。

第二行:前面临时文件是用固定的.d.temp作为后缀,为了防止重名覆盖掉有用的文件,这里把temp换成一个随机数,该数可用$$得到,$$的值是当前进程号。

由于$是makefile特殊符号,一个$要用$$来转义,所以2个$要写成$$$$(你可以在makefile里用echo $$$$来显示进程号的值)。

第三行:sed命令的输入也改成该临时文件.$$。

每个shell命令的进程号通常是不同的,为了每次调用$$时得到的进程号相同,必须把这4行放在一条命令中,这里用分号把它们连接成一条命令(在书写时为了易读,用\拆成了多行),这样每次.$$便是同一个文件了。

你可以在makefile里用下面命令来比较:

[html]view plaincopy

1.echo $$$$

2.echo $$$$; echo $$$$

第四行:当make完后,每个临时文件.d.$$,已经不需要了,删除之。

但每个.d文件要在下一次make时被include进来,要保留。

(十)

综合前面的分析,得到我们的makefile文件:

[html]view plaincopy

1.#使用$(wildcard *.c)来获取工作目录下的所有.c文件的列表

2.sources:=$(wildcard *.c)

3.objects:=$(sources:.c=.o)

4.#这里,dependence是所有.d文件的列表.即把串sources串里的.c换成.d

5.dependence:=$(sources:.c=.d)

6.

7.#所用的编译工具

https://www.sodocs.net/doc/ce6492058.html,=gcc

9.

10.#当$(objects)列表里所有文件都生成后,便可调用这里的$(CC) $^ -o $@ 命令生

成最终目标all了

11.#把all定义成第1个规则,使得可以把make all命令简写成make

12.all: $(objects)

13.$(CC) $^ -o $@

14.

15.#这段是make的模式规则,指示如何由.c文件生成.o,即对每个.c文件,调用gcc

-c XX.c -o XX.o命令生成对应的.o文件。

16.#如果不写这段也可以,因为make的隐含规则可以起到同样的效果

17.%.o: %.c

18.$(CC) -c $< -o $@

19.

20.include $(dependence) #注意该句要放在终极目标all的规则之后,否则.d文件里的

规则会被误当作终极规则了

21.%.d: %.c

22.set -e; rm -f $@; \

23.$(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \

24.sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \

25.rm -f $@.$$$$

26.

27..PHONY: clean #之所以把clean定义成伪目标,是因为这个目标并不对应实际的文

28.clean:

29.rm -f all $(objects) $(dependence) #清除所有临时文件:所有.o和.d。.$$已在每次

使用后立即删除。-f参数表示被删文件不存在时不报错

(十一)

上面这个makefile已经能正常工作了(编译C程序),但如果要用它编译C++,变量CC值要改成g++,每个.c都要改成.cpp,有点繁琐。

现在我们继续完善它,使其同时支持C和C++,并支持二者的混合编译。

[html]view plaincopy

1.#一个实用的makefile,能自动编译当前目录下所有.c/.cpp源文件,支持二者混合编译

2.#并且当某个.c/.cpp、.h或依赖的源文件被修改后,仅重编涉及到的源文件,未涉及的不

编译

3.#详解文档:https://www.sodocs.net/doc/ce6492058.html,/huyansoft/article/details/8924624

4.#author:胡彦2013-5-21

5.

6.#----------------------------------------------------------

7.#编译工具用g++,以同时支持C和C++程序,以及二者的混合编译

https://www.sodocs.net/doc/ce6492058.html,=g++

9.

10.#使用$(winldcard *.c)来获取工作目录下的所有.c文件的列表

11.#sources:=main.cpp command.c

12.

13.#变量sources得到当前目录下待编译的.c/.cpp文件的列表,两次调用winldcard、

结果连在一起即可

14.sources:=$(wildcard *.c) $(wildcard *.cpp)

15.

16.#变量objects得到待生成的.o文件的列表,把sources中每个文件的扩展名换成.o

即可。这里两次调用patsubst函数,第1次把sources中所有.cpp换成.o,第2次把第1次结果里所有.c换成.o

17.objects:=$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(sources)))

18.

19.#变量dependence得到待生成的.d文件的列表,把objects中每个扩展名.o换成.d

即可。也可写成$(patsubst %.o,%.d,$(objects))

20.dependence:=$(objects:.o=.d)

21.

22.#----------------------------------------------------------

23.#当$(objects)列表里所有文件都生成后,便可调用这里的$(CC) $^ -o $@ 命令生

成最终目标all了

24.#把all定义成第1个规则,使得可以把make all命令简写成make

25.all: $(objects)

26.$(CC) $(CPPFLAGS) $^ -o $@

27.@./$@ #编译后立即执行

28.

29.#这段使用make的模式规则,指示如何由.c文件生成.o,即对每个.c文件,调用

gcc -c XX.c -o XX.o命令生成对应的.o文件

30.#如果不写这段也可以,因为make的隐含规则可以起到同样的效果

31.%.o: %.c

32.$(CC) $(CPPFLAGS) -c $< -o $@

33.

34.#同上,指示如何由.cpp生成.o,可省略

35.%.o: %.cpp

36.$(CC) $(CPPFLAGS) -c $< -o $@

37.

38.#----------------------------------------------------------

39.include $(dependence) #注意该句要放在终极目标all的规则之后,否则.d文件里

的规则会被误当作终极规则了

40.

41.#因为这4行命令要多次凋用,定义成命令包以简化书写

42.define gen_dep

43.set -e; rm -f $@; \

44.$(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \

45.sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \

46.rm -f $@.$$$$

47.endef

48.

49.#指示如何由.c生成其依赖规则文件.d

50.#这段使用make的模式规则,指示对每个.c文件,如何生成其依赖规则文件.d,

调用上面的命令包即可

51.%.d: %.c

52.$(gen_dep)

53.

54.#同上,指示对每个.cpp,如何生成其依赖规则文件.d

55.%.d: %.cpp

56.$(gen_dep)

57.

58.#----------------------------------------------------------

59.#清除所有临时文件(所有.o和.d)。之所以把clean定义成伪目标,是因为这个

目标并不对应实际的文件

60..PHONY: clean

61.clean: #.$$已在每次使用后立即删除。-f参数表示被删文件不存在时不报错

62.rm -f all $(objects) $(dependence)

63.

64.echo: #调试时显示一些变量的值

65.@echo sources=$(sources)

66.@echo objects=$(objects)

67.@echo dependence=$(dependence)

68.@echo CPPFLAGS=$(CPPFLAGS)

69.

70.#提醒:当混合编译.c/.cpp时,为了能够在C++程序里调用C函数,必须把每一个

要调用的C函数,其声明都包括在extern "C"{}块里面,这样C++链接时才能成功链接它们。

makefile学习体会:

刚学过C语言的读者,可能会觉得makefile有点难,因为makefile不像C语言那样,一招一式都那么清晰明了。

在makefile里到处是“潜规则”,都是一些隐晦的东西,要弄明白只有搞清楚这些“潜规则”。

基本的规则无非是“一个依赖改了,去更新哪些目标”。

正因为隐晦动作较多,写成一个makefile才不需要那么多篇幅,毕竟项目代码才是主体。只要知道makefile的框架,往它的套路里填就行了。

较好的学习资料是《跟我一起写Makefile.pdf》这篇文档(下载包里已经附带了),比较详细,适合初学者。

我们学习的目的是,能够编写一个像本文这样的makefile,以满足简单项目的基本需求,这要求理解前面makefile几个关键点:

1-多目标

2-隐含规则

3-定义模式规则

4-自动生成依赖性

可惜的是,这篇文档虽然比较全面,却没有以一个完整的例子为引导,对几处要点没有突出指明,尤其是“定义模式规则”在最后不显眼的位置(第十一部分第五点),导致看了“自动生成依赖性”一节后还比较模糊。

所以,看了《跟我一起写Makefile.pdf》后,再结合本文针对性的讲解,会有更实际的收获。另一个学习资料是《GNU make v3.80中文手册v1.5.pdf》,这个手册更详细,但较枯燥,不适合完整学习,通常是遇到问题再去查阅。

其它文章和代码请留意我的blog: https://www.sodocs.net/doc/ce6492058.html,/huyansoft

LAMMPS手册-中文版讲解之欧阳家百创编

LAMMPS手册-中文解析 一、 欧阳家百(2021.03.07) 二、简介 本部分大至介绍了LAMMPS的一些功能和缺陷。 1.什么是LAMMPS? LAMMPS是一个经典的分子动力学代码,他可以模拟液体中的粒子,固体和汽体的系综。他可以采用不同的力场和边界条件来模拟全原子,聚合物,生物,金属,粒状和粗料化体系。LAMMPS可以计算的体系小至几个粒子,大到上百万甚至是上亿个粒子。 LAMMPS可以在单个处理器的台式机和笔记本本上运行且有较高的计算效率,但是它是专门为并行计算机设计的。他可以在任何一个按装了C++编译器和MPI的平台上运算,这其中当然包括分布式和共享式并行机和Beowulf型的集群机。 LAMMPS是一可以修改和扩展的计算程序,比如,可以加上一些新的力场,原子模型,边界条件和诊断功能等。 通常意义上来讲,LAMMPS是根据不同的边界条件和初始条件对通过短程和长程力相互作用的分子,原子和宏观粒子集合对它们的牛顿运动方程进行积分。高效率计算的LAMMPS通过采用相邻清单来跟踪他们邻近的粒子。这些清单是根据粒子间的短程互拆力的大小进行优化过的,目的是防止局部粒子密度过高。在

并行机上,LAMMPS采用的是空间分解技术来分配模拟的区域,把整个模拟空间分成较小的三维小空间,其中每一个小空间可以分配在一个处理器上。各个处理器之间相互通信并且存储每一个小空间边界上的”ghost”原子的信息。LAMMPS(并行情况)在模拟3维矩行盒子并且具有近均一密度的体系时效率最高。 2.LAMMPS的功能 总体功能: 可以串行和并行计算 分布式MPI策略 模拟空间的分解并行机制 开源 高移植性C++语言编写 MPI和单处理器串行FFT的可选性(自定义) 可以方便的为之扩展上新特征和功能 只需一个输入脚本就可运行 有定义和使用变量和方程完备语法规则 在运行过程中循环的控制都有严格的规则 只要一个输入脚本试就可以同时实现一个或多个模拟任务 粒子和模拟的类型: (atom style命令) 原子 粗粒化粒子 全原子聚合物,有机分子,蛋白质,DNA

linux驱动的Makefile分析

第6行,判断KERNELRELEASE是否为空,该变量是描述内核版本的字符串。只有执行make命令的当前目录为内核源代码目录时,该变量才不为空字符。 第7、8行定义了KERNELDIR和PWD变量。KERNELDIR是内核路径变量,PWD是由执行pwd命令得到的当前模块路径。 第11行make的语法是”Make –C 内核路径M=模块路径modules”,该语法会执行内核模块的编译 第13行是将模块安装到对应的路径中,当在命令执行make modules_install时,执行该命令,其他时候不执行 第24行,意思是将hello.o编译成hello.ko模块。如果要编译其他模块时,只要将hello.o中的hello改成模块的文件名就可以了 Makefile的执行过程: 执行make命令后,将进入Makefile文件。此时KERNELRELEASE变量为空,此时是第一次进入Makefile文件。当执行完变量赋值代码后,会根据make参数执行不同的逻辑。 如下: make modules_install 命令,将执行13、15行将模块安装到操作系统中。 make clean命令,会删除目录中的所有临时文件。 make命令,会执行10、11行编译模块。首先$(MAKE) -C $(KERNELDIR) M=$(PWD) modules 中的-C $(KERNELDIR)选项,会使编译器进入内核源码目录/home/zzc/linux-2.6.31,读取Makefile文件,从中得到一些信息,例如变量KERNELRELEASE将在这里赋值。当内核源码目录中的Makefile文件读取完成后,编译器会根据选项M=$(PWD)第二次进入模块所在的目录,并再一次执行Makefie文件。当第二次执行Makefile文件时,变量KERNELRELEASE

手动建立makefile简单实例解析

手动建立makefile简单实例解析 假设我们有一个程序由5个文件组成,源代码如下:/*main.c*/ #include "mytool1.h" #include "mytool2.h" int main() { mytool1_print("hello mytool1!"); mytool2_print("hello mytool2!"); return 0; } /*mytool1.c*/ #include "mytool1.h" #include void mytool1_print(char *print_str) { printf("This is mytool1 print : %s ",print_str); } /*mytool1.h*/ #ifndef _MYTOOL_1_H #define _MYTOOL_1_H void mytool1_print(char *print_str); #endif /*mytool2.c*/ #include "mytool2.h" #include void mytool2_print(char *print_str) { printf("This is mytool2 print : %s ",print_str); }

/*mytool2.h*/ #ifndef _MYTOOL_2_H #define _MYTOOL_2_H void mytool2_print(char *print_str); #endif 首先了解一下make和Makefile。GNU make是一个工程管理器,它可以管理较多的文件。我所使用的RedHat 9.0的make版本为GNU Make version 3.79.1。使用make的最大好处就是实现了“自动化编译”。如果有一个上百个文件的代码构成的项目,其中一个或者几个文件进行了修改,make就能够自动识别更新了的文件代码,不需要输入冗长的命令行就可以完成最后的编译工作。make执行时,自动寻找Makefile(makefile)文件,然后执行编译工作。所以我们需要编写Makefile文件,这样可以提高实际项目的工作效率。 在一个Makefile中通常包含下面内容: 1、需要由make工具创建的目标体(target),通常是目标文件或可执行文件。 2、要创建的目标体所依赖的文件(dependency_file)。 3、创建每个目标体时需要运行的命令(command)。 格式如下: target:dependency_files command target:规则的目标。通常是程序中间或者最后需要生成的文件名,可以是.o文件、也可以是最后的可执行程序的文件名。另外,目标也可以是一个make执行的动作的名称,如目标“clean”,这样的目标称为“伪目标”。 dependency_files:规则的依赖。生成规则目标所需要的文件名列表。通常一个目标依赖于一个或者多个文件。 command:规则的命令行。是make程序所有执行的动作(任意的shell命令或者可在shell下执行的程序)。一个规则可以有多个命令行,每一条命令占一行。注意:每一个命令行必须以[Tab]字符开始,[Tab]字符告诉make此行是一个命令行。make按照命令完成相应的动作。这也是书写Makefile中容易产生,而且比较隐蔽的错误。命令就是在任何一个目标的依赖文件发生变化后重建目标的动作描述。一个目标可以没有依赖而只有动作(指定的命令)。比如Makefile中的目标“clean”,此目标没有依赖,只有命令。它所指定的命令用来删除make过程产生的中间文件(清理工作)。 在Makefile中“规则”就是描述在什么情况下、如何重建规则的目标文件,通常规则

windows下的makefile教程

windows下的makefile教程 https://www.sodocs.net/doc/ce6492058.html,/mirror_hc/archive/2008/03/26/2221117.aspx joeliu 制作4/19/2011 22:10:29 1. 先说几句废话 以前看书时经常遇到makefile,nmake这几个名词,然后随之而来的就是一大段莫名其妙的代码,把我看得云里雾里的。在图书馆和google上搜了半天,也只能找到一些零零星星的资料,把我一直郁闷得不行。最近因缘巧合,被我搞到了一份传说中的MASM6手册,终于揭开了NMAKE的庐山真面目。想到那些可能正遭受着同样苦难的同志以及那些看到E文就头晕的兄弟,所以就写了这篇文章。假如大家觉得有帮助的话,记得回复一下,当作鼓励!如果觉得很白痴,也请扔几个鸡蛋.本文是总结加翻译,对于一些关键词以及一些不是很确定的句子,保留了英文原版,然后再在括号里给出自己的理解以作参考。由于水平有限,加上使用NMAKE的经验尚浅,有不对的地方大家记得要指正唷。MASM6手册在AOGO(好像是)可以download,在我的BLOG上有到那的链接。 2. 关于NMAKE Microsoft Program Maintenance Utility,外号NMAKE,顾名思义,是用来管理程序的工具。其实说白了,就是一个解释程序。它处理一种叫做makefile的文件(以mak为后缀),解释里面的语句并执行相应的指令。我们编写makefile文件,按照规定的语法描述文件之间的依赖关系,以及与该依赖关系相关联的一系列操作。然后在调用NMAKE时,它会检查所有相关的文件,如果目标文件(target file,下文简称target,即依赖于其它文件的文件)的time stamp(就是文件最后一次被修改的时间,一个32位数,表示距离1980年以来经过的时间,以2秒为单位)小于依赖文件(dependent file,下文简称dependent,即被依赖的文件)的time stamp,NMAKE就执行与该依赖关系相关联的操作。请看下面这个例子:foo.exe : first.obj second.obj link first.obj,second.obj 第一行定义了依赖关系,称为dependency line;第二行给出了与该依赖关系相关联的操作,称为command line。因为foo.exe由first.obj和second.obj连接而成,所以说foo.exe依赖于first.ogj和second.obj,即foo.exe为target,first.obj和second.obj为dependent。如果first.obj和second.obj中的任何一个被修改了(其time stamp更大),则调用link.exe,重新连接生成foo.exe。这就是NMAKE的执行逻辑。 综上,NMAKE的核心就是这3个家伙——依赖关系,操作和判定逻辑(target.timestamp < dependent.timestamp,如果为true,就执行相应操作)。 3. MAKEFILE的语法 现在详细讨论一下makefile的语法。makefile就像一个玩具型的程序语言,麻雀虽小,但五脏具全。makefile的组成部分包括:描述语句(description block),推导规则(inference rules),宏和指令(directive)。 描述语句就是dependent lines和command lines的组合;推导规则就是预先定义好的或用户自己定义的依赖关系和关联命令;宏就不用说了吧;指令就是内定的一些可以被NMAKE识别的控制命令,提供了很多有用的功能。 3.1 特殊符号

Makefile下编写Helloworld的例子

什么是makefile?或许很多Windows的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得 要作一个好的和professional的程序员,makefile还是要懂。这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专 业人士,你还是要了解HTML的标识的含义。特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile, 从一个侧面说明了一个人是否具备完成大型工程的能力。 因为,makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中, makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复 杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。 makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make 命令,整个工程完全自动编译,极大的提高了软件 开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如: Delphi的make,VisualC++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。 更新版本 hello.c程序 #include int main(){printf("Hello,World!\n");

return 0;}=== makefile开始=== Helloworld: hello.o gcc hello.o–o Helloworld Hello.o: hello.c hello.h gcc–MM hello.c gcc–c hello.c–o hello.o .PHONY: clean Clean: rm–rf*.o hellworld === makefile结束===

LINUX编程 Makefile中的变量详解应用

第六章:Makefile中的变量 -------------------------------------------------------------------------------- 在Makefile中,变量就是一个名字(像是C语言中的宏),代表一个文本字符串(变量的值)。在Makefile的目标、依赖、命令中引用一个变量的地方,变量会被它的值所取代(与C语言中宏引用的方式相同,因此其他版本的make也把变量称之为“宏”)。在Makefile中变量的特征有以下几点: 1. Makefile中变量和函数的展开(除规则的命令行以外),是在make读取makefile文件时进行的,这里的变量包括了使用“=”定义和使用指示符“define”定义的。 2. 变量可以用来代表一个文件名列表、编译选项列表、程序运行的选项参数列表、搜索源文件的目录列表、编译输出的目录列表和所有我们能够想到的事物。 3. 变量名是不包括“:”、“#”、“=”、前置空白和尾空白的任何字符串。需要注意的是,尽管在GNU make中没有对变量的命名有其它的限制,但定义一个包含除字母、数字和下划线以外的变量的做法也是不可取的,因为除字母、数字和下划线以外的其它字符可能会在以后的make版本中被赋予特殊含义,并且这样命名的变量对于一些shell来说不能作为环境变量使用。 4. 变量名是大小写敏感的。变量“foo”、“Foo”和“FOO”指的是三个不同的变量。Makefile 传统做法是变量名是全采用大写的方式。推荐的做法是在对于内部定义定义的一般变量(例如:目标文件列表objects)使用小写方式,而对于一些参数列表(例如:编译选项CFLAGS)采用大写方式,这并不是要求的。但需要强调一点:对于一个工程,所有Makefile中的变量命名应保持一种风格,否则会显得你是一个蹩脚的程序员(就像代码的变量命名风格一样)。 5. 另外有一些变量名只包含了一个或者很少的几个特殊的字符(符号)。称它们为自动化变量。像“$<”、“$@”、“$?”、“$*”等。 6.1 变量的引用 当我们定义了一个变量之后,就可以在Makefile的很多地方使用这个变量。变量的引用方式是:使用“$(VARIABLE_NAME)”或者“${ VARIABLE_NAME }”来引用一个变量的定义。例如:“$(foo) ”或者“${foo}”就是取变量“foo”的值。美元符号“$”在Makefile中有特殊的含义,所有在命令或者文件名中使用“$”时需要用两个美元符号“$$”来表示。对一个变量的引用可以在Makefile的任何上下文中,目标、依赖、命令、绝大多数指示符和新变量的赋值中。这里有一个例子,其中变量保存了所有.o文件的列表: objects = program.o foo.o utils.o program : $(objects) cc -o program $(objects)

MakeFile

MAKE 的使用 当编译单个文件时,使用GCC已经绰绰有余,但对于有几十个甚至上百个源文件的大工程来讲,单纯用GCC命令进行编译肯定就不行了,那样编译一次太麻烦,这就要求有一种自动化的方法,于是在Linux系统中Make工具就诞生了。 1、什么是Make makefile shell 什么是Make,可以将Make理解为一种脚本,这种脚本主要是用于多文件编译,在传统的命令行式编译方式中,如果修改了工程中的某一个头文件,有时候不需要重新编译整个工程,而只需要编译与这个头文件相关联的源文件即可,但如何以手动的方式从一个大工程里将这些文件找出,并手动编译,是件很麻烦的事情。 为了解决这一问题,设计了Make,make程序可以维护具有相互依赖性的源文件,当某些文件发生改变时,它能自动识别出,并只对相应文件进行自动编译。 虽然make工具有很多智能识别机制,但它无法自动了解他所面对的工程源文件的组成以及依赖规则,这些都需要开发人员编写makefile脚本,告诉make工具。MakeFile编写好以后,就可以在每次修改源文件之后,执行make命令就好了。Makefile make 什么又是makefile了,很多windows的程序开发人员都不知道这个东西,因为那些Windows的IDE都为你做了这些工作,但我觉得要作为一个好的和专业的程序员,makefile还是要懂得,这就好像在有这么多的HTML的编辑器,但如果你想成为一个专业人士,就必须了解HTML的标识的含义。特别在Linux下的软件编译,你就必须自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成某个大型大工程的能力。 2、makefile的组成 一个完整的makefile文件通常由五个部分组成: ◆显示规则 显示规则是指主动编写描述规则,用于指示在何种状态下更新哪些目标文件,即编写makefile时需要明确指出各目标文件所依赖的源文件的集合,以及编 译本目标文件所需的命令。 ◆隐含规则 指用make中默认的编译方式进行编译,即make工具可以根据目标文件的类型自动推导出的规则(由于我们的make有自动推导的功能,所以隐晦的规则可以 让我们比较粗糙地简略书写Makefile ,这是由make所支持的) abc.o abc.c cc -o abc.o -c abc.c ◆变量定义 为提升语句的灵活性,在make脚本中可以使用变量,来代表一个字符串,一组编译命令或一组文件名。(在makefile 中我们要定义一系列的变量,变量一般都是字符串,这个有点类似于C语言中的宏,当makefile 被执行时,其中的变量都会被扩展到相应的引用位置上) ◆makefile指示符 指示符告诉make工具,当程序在读取makefile文件时要执行的动作。 (文件指示包括三部分,一个是在一个makefile中引用另外一个makefile,就像C语言中的include一样,另一个是指根据某些情况制定MakeFile中的有效部分,就像C 语言中的预编译#if一样,还有就是定义一个多行的命令,)

3-Makefile书写规则

3 Makefile书写规则 规则包含两个部分,一个是依赖关系,一个是生成目标的方法。 在Makefile中,规则的顺序是很重要的,因为,Makefile中只应该有一个最终目标,其它的目标都是被这个目标所连带出来的,所以一定要让make知道你的最终目标是什么。一般来说,定义在Makefile中的目标可能会有很多,但是第一条规则中的目标将被确立为最终的目标。如果第一条规则中的目标有很多个,那么,第一个目标会成为最终的目标。make所完成的也就是这个目标。 好了,还是让我们来看一看如何书写规则。 3.1 规则举例 foo.o : foo.c defs.h # foo模块 cc -c -g foo.c 看到这个例子,各位应该不是很陌生了,前面也已说过,foo.o是我们的目标,foo.c和defs.h是目标所依赖的源文件,而只有一个命令“cc -c - g foo.c”(以Tab键开头)。这个规则告诉我们两件事: 1. 文件的依赖关系,foo.o依赖于foo.c和defs.h的文件,如果foo.c 和defs.h的文件日期要比foo.o文件日期要新,或是foo.o不存 在,那么依赖关系发生。 2. 如果生成(或更新)foo.o文件。也就是那个cc命令,其说明 了,如何生成foo.o这个文件。(当然foo.c文件include了defs.h 文件) 3.2 规则的语法 targets : prerequisites command

... 或是这样: targets : prerequisites ; command command ... targets是文件名,以空格分开,可以使用通配符。一般来说,我们的目标基本上是一个文件,但也有可能是多个文件。 command是命令行,如果其不与“target:prerequisites”在一行,那么,必须以[Tab键]开头,如果和prerequisites在一行,那么可以用分号做为分隔。(见上) prerequisites也就是目标所依赖的文件(或依赖目标)。如果其中的某个文件要比目标文件要新,那么,目标就被认为是“过时的”,被认为是需要重生成的。这个在前面已经讲过了。 如果命令太长,你可以使用反斜框(‘\’)作为换行符。make对一行上有多少个字符没有限制。规则告诉make两件事,文件的依赖关系和如何成成目标文件。 一般来说,make会以UNIX的标准Shell,也就是/bin/sh来执行命令。3.3 在规则中使用通配符 如果我们想定义一系列比较类似的文件,我们很自然地就想起使用通配符。make支持三各通配符:“*”,“?”和“[...]”。这是和Unix的B-Shell是相同的。 波浪号(“~”)字符在文件名中也有比较特殊的用途。如果是“~/test”,这就表示当前用户的$HOME目录下的test目录。而“~hchen/test”则表示用户hchen的宿主目录下的test目录。(这些都是Unix下的小知识了,make也支持)而在Windows或是MS-DOS下,用户没有宿主目录,那么波浪号所指的目录则根据环境变量“HOME”而定。

make_Makefile 结构分析

Makefile结构分析 -----uClinux (2.6.x内核)系统映像过程 刘江欧阳昭暐吕熙隆 1、源代码文件及目录构成 解压缩uClinux-dist-20070130.tar.gz压缩文件,在uClinux-dist原始子目录下主要有:config、Bin、linux-2.4.x、linux-2.6.x 、lib、tools、Include、user和vendors,以及文件Makefile。另外,在编译后生成子目录images和romfs,以及文件autoconfig.h、config.in和两个隐含文件:.config和.depend。 config子目录包含文件及下一级子目录,如 config.in、configure.help、Fixconfig、Makefile、 Mkconfig、Setconfig所有这些文件及子目录 Scripts均与系统配置有关; linux-2.6.x子目录是嵌入式操作系统 uClinux-2.6.x的核心目录,包括下一级子目录 arch、include、init、drivers、fs、ipc、kernel、 lib、Mm、scripts和关键文件Makefile、 rules.make,编译后还要生成新文件romfs.o、linux 和system.map;lib子目录为嵌入式操作系统提供 压缩和改进了的函数库支持;tools子目录包含 romfs-inst.sh文件,通过调用此文件,可以把目录 或文件加入到romfs子目录中;user子目录包含各 种驱动程序文件目录,根据用户的配置情况,不同的 驱动程序会被编译进最后形成的操作系统中; vendors子目录包括与特定硬件平台相关的分类目录 组。目录结构如图1所示。 Makefile的详细介绍情况在 uClinux-dist\linux-2.6.x\Documentation\kbuil d中,如图2所示。图1、目录结构即Linux 内核中的 Makefile 以及与 Makefile 直接相关的文件有:

如何学好并精通C语言

程序员之路——如何学习C语言并精通C语言 程序员之路——如何学习C语言 学习C语言不是一朝一夕的事情,但也不需要花费十年时间才能精通。如何以最小的代价学习并精通C 语言是本文的主题。请注意,即使是“最小的代价”,也绝不是什么捷径,而是以最短的时间取得最多的收获,同时也意味着你需要经历艰苦的过程。 一、要读就读好书,否则不如不读 所有初学者面临的第一个问题便是:如何选择教材。好的开始是成功的一半,选择一本优秀的教材是事半功倍的关键因素。不幸的是,学校通常会帮你指定一本很差劲的C语言课本;而幸运的是,你还可以再次选择。 大名鼎鼎的谭浩强教授出了一本《C语言程序设计》,据说发行量有超过400万,据我所知,很多学校都会推荐这本书作为C语言课本。虽然本人的名字(谭浩宇)跟教授仅仅一字之差,但我是无比坚定地黑他这本书的。这本书不是写给计算机专业的学生的,而是给那些需要考计算机等级考试的其它专业学生看的。这本书的主要缺点是:例子程序非常不专业,不能教给你程序设计应该掌握的思考方式;程序风格相当地不好,会让你养成乱写代码的恶习;错误太多,曾经有人指出过这本书的上百个错误,其中不乏关键的概念性错误。好了,这本书我也不想说太多了,有兴趣大家可以百度一下:) Kernighan和Ritchie的《The C Programming Language》(中译名《C程序设计语言》)堪称经典中的经典,不过旧版的很多内容都已过时,和现在的标准C语言相去甚远,大家一定要看最新的版本,否则不如不看。另外,即使是最经典最权威的书,也没有办法面面俱到,所以手边常备一本《C语言参考手册》是十分必要的。《C语言参考手册》就是《C Reference Manual》,是C语言标准的详细描述,包括绝大多数C标准库函数的细节,算得上是最好的标准C语言的工具书。顺便提一句,最新的《C程序设计语言》是根据C89标准修订的,而《C语言参考手册》描述的是C99标准,二者可能会有些出入,建议按照C99标准学习。还有一本《C和指针》,写得也是相当地不错,英文名是《Pointers on C》,特别地强调指针的重要性,算是本书的一个特点吧。不过这本书并不十分适合初学者,如果你曾经学过C语言,有那么一些C语言的基础但又不是很扎实,那么你可以尝试一下这本书。我相信,只要你理解了指针,C语言便不再神秘。 如果你已经啃完了一本C语言教材,想要更进一步,那么有两本书你一定要看。首先是《C Traps and Pitfalls》(中译名《C陷井与缺陷》),很薄的一本小册子,内容非常非常地有趣。要注意一点,这本书是二十多年前写成的,里面提到的很多C语言的缺陷都已被改进,不过能够了解一些历史也不是什么坏事。然后你可以挑战一下《Expert C Programming》(中译名《C专家编程》),书如其名,这本书颇具难度,一旦你仔细读完并能透彻理解,你便可以放心大胆地在简历上写“精通C语言”了。 切记一个原则,不要读自己目前还看不懂的书,那是浪费生命。如果你看不懂,那你一定是缺失了某些必需基础知识。此时,你要仔细分析自己需要补充哪些内容,然后再去书店寻找讲述的这些内容的书籍。把基础知识补充完毕再回头来学习,才会真正的事半功倍。 二、Unix/Linux还是Windows,这是个很大的问题 不同的编程环境会造就出不同思维的程序员。Windows的程序员大多依赖集成开发环境,比如Visual Studio,而Unix程序员更加钟爱Makefile与控制台。显而易见,集成开发环境更容易上手,在Windows上学习C语言,只需要会按几个基本的Visutal C++工具栏按钮就可以开始写Hello, World!了,而在Unix下,你需要一些控制台操作的基本知识。有人也许认为Unix的环境更简洁,但习惯的力量是很大的,大家都很熟悉Windows的基本操作,而为了学习C语言去专门装一个Unix系统,似乎有点不划算。 对于一个只懂得Windows基本操作、连DOS是什么都不知道的新手而言,尽快做一些有趣而有意义的事情才是最重要的。用C语言写一个小程序远比学习ls、cat等命令有趣,况且我们要专注于C语言本身,就不得不暂时忽略一些东西,比如编译链接的过程、Makefile的写法等等等等。 所以我建议初学者应该以Visual C++ 6.0(不是VisualC++ .NET)或者Dev C++作为主要的学习环境,而且千万不要在IDE的使用技巧上过多纠缠,因为今后你一定要转向Unix环境的。Visual C++ 6.0使用很方便,调试也很直观,但其默认的编译器对C标准的支持并不好,而Dev C++使用gcc编译器,对C99的标准都支持良好。使用顺带提一下,很多大学的C语言课程还在使用Turbo C 2.0作为实验环境,这是相当不可取的,原因其一是TC 2.0对C标准几乎没有支持,其二是TC 2.0编译得到的程序是16位的,这对今后理解32位的程序会造成极大的困扰(当然,用djgpp之类的东西可以使TC

通用Makefile模板及实例

1 通用Makefile——1 实现的功能: ?make——编译和连接程序 ?make objs——编译程序,生成目标文件 ?make clean——清除编译产生的目标文件(*.o)和依赖文件(*.d) ?make cleanall——清除目标文件(*.o)、依赖文件(*.d)和可执行文件(*.exe)?make rebuild——重新编译连接程序,相当于make clean && make Usage: Makefile源代码 # Gneric C/C++ Makefile #################################################### PROGRAM := SRCDIRS := SRCEXTS := CPPFLAGS := CFLAGS := CFLAGS += CXXFLAGS := CXXFLAGS += LDFLAGS := LDFLAGS += SHELL = /bin/sh SOURCES = $(foreach d,$(SRCDIRS),$(wildcard $(addprefix $(d)/*,$(SRCEXTS)))) OBJS = $(foreach x,$(SRCEXTS),\ $(patsubst %$(x),%.o,$(filter %$(x),$(SOURCES)))) DEPS = $(patsubst %.o,%.d,$(OBJS)) .PHONY: all objs clean cleanall rebuild all : $(PROGRAM) %.d : %.c @$(CC) -MM -MD $(CFLAGS) {1}lt; %.d : %.C @$(CC) -MM -MD $(CXXFLAGS) {1}lt; objs : $(OBJS) %.o : %.c $(CC) -c $(CPPFLAGS) $(CFLAGS) {1}lt; %.o : %.cpp $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) {1}lt; $(PROGRAM) : $(OBJS) ifeq ($(strip $(SRCEXTS)),.c) $(CC) -o $(PROGRAM) $(OBJS) $(LDFLAGS)

c 程序的书写格式

c 程序的书写格式 c++程序的书写格式2010-05-18 17:03文件结构文件头注释所有C++的源文件均必须包含一个规范的文件头,文件头包含了该文件的名称、功能概述、作者、版权和版本历史信息等内容。标准文件头的格式为:/*!@file*PRE模块名:文件所属的模块名称文件名:文件名相关文件:与此文件相关的其它文件文件实现功能:描述该文件实现的主要功能作者:作者部门和姓名版本:当前版本号--备注:其它说明--修改记录:日期版本修改人修改内容YYYY/MM/DD X.Y作者或修改者名修改内容/PRE*/如果该文件有其它需要说明的地方,还可以专门为此扩展一节:/*!@file*PRE模块名:文件所属的模块名称文件名:文件名相关文件:与此文件相关的其它文件文件实现功能:描述该文件实现的主要功能作者:作者部门和姓名版本:当前版本号--备注:其它说明--修改记录:日期版本修改人修改内容YYYY/MM/DD X.Y作者或修改者名修改内容/PRE**项目1-项目1.1-项目1.2==*项目2-项目2.1-项目2.2.*/每行注释的长度都不应该超过80个半角字符。还要注意缩进和对其,以利阅读。关于文件头的完整例子,请参见:文件头例子关于文件头的模板,请参见:文件头注释模板头文件头文件通常由以下几部分组成:文件头注释每个头文件,无论是内部的还是外部的,都应该由一个规范的文件头注释作为开始。预处理块为了防止头文件被重复引用,应当用ifndef/define/endif结构产生预处理块。函数和类/结构的声明等声明模块的接口需要包含的内联函数定义文件(如果有的话)如果类中的内联函数较多,或者一个头文件中包含多个类的定义(不推荐),可以将所有内联函数定义放入一个单独的内联函数定义文件中,并在类声明之后用 "#include"指令把它包含进来。头文件的编码规则:引用文件的格式用 #include filename.h格式来引用标准库和系统库的头文件(编译器将从标准库目录开始搜索)。用#include"filename.h"格式来引用当前工程中的头文件(编译器将从该文件所在目录开始搜索)。分割多组接口(如果有的话)如果在一个头件中定义了多个类或者多组接口(不推荐),为了便于浏览,应该在每个类/每组接口间使用分割带把它们相互分开。关于头文件的完整例子,请参见:头文件例子内联函数定义文件如上所述,在内联函数较多的情况下,为了避免头文件过长、版面混乱,可以将所有的内联函数定义移到一个单独的文件中去,然后再用#include指令将它包含到类声明的后面。这样的文件称为一个内联函数定

跟我一起写Makefile(可以注释版)

跟我一起写 Makefile 作者:陈皓 整理:祝冬华

第一部分、概述 (6) 第二部分、关于程序的编译和链接 (6) 第三部分、Makefile 介绍 (7) 一、Makefile的规则 (7) 二、一个示例 (8) 三、make是如何工作的 (9) 四、makefile中使用变量 (10) 五、让make自动推导 (11) 六、另类风格的makefile (12) 七、清空目标文件的规则 (13) 第四部分、Makefile 总述 (13) 一、Makefile里有什么? (13) 1、显式规则。 (14) 2、隐晦规则。 (14) 3、变量的定义。 (14) 4、文件指示。 (14) 5、注释。 (14) 二、Makefile的文件名 (15) 三、引用其它的Makefile (15) 四、环境变量 MAKEFILES (16) 五、make的工作方式 (16) 第五部分、书写规则 (17) 一、规则举例 (17) 二、规则的语法 (17) 三、在规则中使用通配符 (18) 四、文件搜寻 (19) 五、伪目标 (20) 六、多目标 (22) 七、静态模式 (22) 八、自动生成依赖性 (24) 第六部分书写命令 (25) 一、显示命令 (26) 二、命令执行 (26) 三、命令出错 (27) 四、嵌套执行make (28) 五、定义命令包 (30) 第七部分使用变量 (30) 一、变量的基础 (31) 二、变量中的变量 (32) 三、变量高级用法 (34) 四、追加变量值 (37) 五、override 指示符 (37) 六、多行变量 (38)

八、目标变量 (39) 九、模式变量 (40) 第八部分使用条件判断 (40) 一、示例 (40) 二、语法 (42) 第九部分使用函数 (43) 一、函数的调用语法 (44) 二、字符串处理函数 (44) 1、subst (44) 2、patsubst (45) 3、strip (45) 4、findstring (46) 5、filter (46) 6、filter-out (46) 7、sort (47) 8、word (47) 9、wordlist (47) 10、words (47) 11、firstword (48) 12、字符串函数实例 (48) 三、文件名操作函数 (48) 1、dir (48) 2、notdir (48) 3、suffix (49) 4、basename (49) 5、addsuffix (49) 6、addprefix (49) 7、join (50) 四、foreach 函数 (50) 五、if 函数 (50) 六、call函数 (51) 七、origin函数 (51) “undefined” (52) “default” (52) “file” (52) “command line” (52) “override” (52) “automatic” (52) 八、shell函数 (53) 九、控制make的函数 (53) 1、error (53) 2、warning (54) 第十部分 make 的运行 (54)

Makefile 语法分析

Makefile 语法分析第一部分 VERSION = 2 # 给变量VERSION赋值 PATCHLEVEL = 6 # 给变量PATCHLEVEL赋值 SUBLEVEL = 22 # 给变量SUBLEVEL赋值 EXTRAVERSION = .6 # 给变量EXTRAVERSION赋值 NAME = Holy Dancing Manatees, Batman! # 给变量NAME赋值 # *DOCUMENTATION* # To see a list of typical targets execute "make help" # More info can be located in ./README # Comments in this file are targeted only to the developer, do not # expect to learn how to build the kernel reading this file. # Do not: # o use make's built-in rules and variables # (this increases performance and avoid hard-to-debug behavour); # o print "Entering directory ..."; MAKEFLAGS += -rR --no-print-directory # 操作符“+=”的作用是给变量(“+=”前面的MAKEFLAGS)追加值。 # 如果变量(“+=”前面的MAKEFLAGS)之前没有定义过,那么,“+=”会自动变成“=”; # 如果前面有变量(“+=”前面的MAKEFLAGS)定义,那么“+=”会继承于前次操作的赋值符;# 如果前一次的是“:=”,那么“+=”会以“:=”作为其赋值符 # 在执行make时的命令行选项参数被通过变量“MAKEFLAGS”传递给子目录下的make程序。# 对于这个变量除非使用指示符“unexport”对它们进行声明,它们在整个make的执行过程中始终被自动的传递给所有的子make。 # 还有个特殊变量SHELL与MAKEFLAGS一样,默认情况(没有用“unexport”声明)下在整个make的执行过程中被自动的传递给所有的子make。 # # -rR --no-print-directory # -r disable the built-in impilict rules. # -R disable the built-in variable setttings. # --no-print-directory。 # We are using a recursive build, so we need to do a little thinking # to get the ordering right. # # Most importantly: sub-Makefiles should only ever modify files in # their own directory. If in some directory we have a dependency on # a file in another dir (which doesn't happen often, but it's often # unavoidable when linking the built-in.o targets which finally # turn into vmlinux), we will call a sub make in that other dir, and

实例—使用make及Makefile文件

2.3 实例—使用make及Makefile文件 一个工程有3个头文件(head1.h、head2.h、exam2.h)和8个C文件(main.c、exam1.c、exam2.c、exam3.c、exam4.c、exam5.c、exam6.c、exam7.c),建立一个Makefile文件(文件名为makefile),内容如下。注意,上述12个文件位于同一个目录中。 example : main.o exam1.o exam2.o exam3.o exam4.o exam5.o exam6.o exam7.o gcc -o example main.o exam1.o exam2.o exam3.o exam4.o exam5.o exam6.o exam7.o main.o : main.c head1.h gcc -c main.c exam1.o : exam1.c head1.h exam2.h gcc -c exam1.c exam2.o : exam2.c head1.h exam2.h gcc -c exam2.c exam3.o : exam3.c head1.h head2.h gcc -c exam3.c exam4.o : exam4.c head1.h head2.h gcc -c exam4.c exam5.o : exam5.c head1.h head2.h gcc -c exam5.c exam6.o : exam6.c head1.h head2.h exam2.h gcc -c exam6.c exam7.o : exam7.c head1.h gcc -c exam7.c clean : rm example main.o exam1.o exam2.o exam3.o exam4.o exam5.o exam6.o exam7.o makefile文件告诉make命令如何编译和链接这几个文件。在当前路径下执行make命令,就可以生成可执行文件example。如果要删除可执行文件和所有的中间目标文件,只需执行make clean命令即可。 Makefile文件的操作规则是: ①如果该工程没有编译过,所有C文件都要编译并被链接。 ②如果该工程的某几个C文件被修改,只需编译被修改的C文件,并链接目标程序。 ③如果该工程的头文件被改变,需要编译包含这些头文件的C文件,并链接目标程序。 在这个Makefile文件中,目标文件(target)有:执行文件example和中间目标文件(*.o);依赖文件(prerequisites)有:冒号后面的.c文件和.h文件。 每一个.o文件都有一组依赖文件,而这些.o文件又是执行文件example的依赖文件。依赖关系是指目标文件由哪些文件生成。在定义好依赖关系后,规则命令定义了如何生成目标文件,其一定要以一个Tab键打头。 make会比较targets文件和prerequisites文件的时间戳,如果prerequisites文件的日期比targets文件的日期要新,或者target不存在,make就会执行相应的规则命令。 默认方式下,执行make命令时,make会在当前目录下找Makefile,如果找到,make 会找文件中的第一个目标文件(target),上面的例子是example文件,并把这个文件作为最终的目标文件。如果example文件不存在,或example所依赖的.o文件的修改时间比example 文件新,make就会执行相应的规则命令生成example文件。如果example所依赖的.o文件不存在,make会在当前目录中找目标为.o文件的依赖文件(C文件和H文件),如果找到,则根据规则生成.o文件,然后再用.o文件生成make的最终结果,也就是可执行文件example。 有上可知,make会一层一层地去找文件的依赖关系,直到最终编译出第一个目标文件。在寻找的过程中,如果出现错误(比如被依赖的文件找不到)make就会直接退出,并报错。 clean不是一个文件,只是一个动作名字,类似于C语言中的lable,冒号后什么也没有,这样make就不会自动去找文件的依赖性,也就不会自动执行其后所定义的规则命令。要执行其后的命令,就要在make命令后显式的指出这个lable的名字,例如执行make clean命令。

相关主题