c语言编译运行出现Makefile.win已经改变,怎么改?

编写Makefile是一个苦乐交织的事情,快乐是因为从一堆需要手工逐个处理的编译过程,进步到一条命令完成,看着代码顺畅的在屏幕上滚动,编译为最终的产品,那个过程无比愉悦;而痛苦则是,写代码已经很累了,写完代码还要编写Makefile,这多出来的一点工作,很有点最后一根稻草的感觉。
最近整理手头的几个项目,把C语言类的Makefile抽象、合并了一下,形成了一个比较通用的编译脚本,这里分享一下:

#自己特定的编译参数,这里仅为示例,这个参数是消除mac编译openssl类程序用的 #定义输出文件夹,outs默认等于是./outs #定义.o中间文件的路径,这个路径编译完成可以清除 #扫描所有的c源码,这里默认src中所有文件都是相当于库文件,最终编译为.o #搜索出来的文件包含了src路径,这里也去掉,便于后面编译到临时目录 #编译所有的库文件由.c至.o #因为VPATH的存在,源文件会自动检索src目录 #利用所有的库文件编译主程序

这个编译脚本的主要特点是自动扫描所有的源文件,然后逐个编译,对于大多c类的项目,基本只需要定义一下主程序就可以完成编译了,其实根据同样的原理连主程序都一起扫描、编译也是可以的,只是似乎自由度太差了。
脚本简单修改可以适应各种环境,比如下面再贴一个ios使用的,ios如果非越狱的话,直接编译成可执行文件是没有意义的,这里我们假设编译成.a库文件,供xcode来调用:

#iphone6以后都是arm64了,所以这里不再考虑armv7,另外也不考虑模拟器运行了 #如果有需要可以根据自己的需求修改 #编译所有的库文件由.c至.o

在主要的编译环节,还有下面这种常用的办法,只是自己运算得到了源文件名而没有用Make系统的自动搜索功能而已:

对于更复杂的编译模式,建议把每个编译环节定义成子程序来执行,可以具备更多的灵活性。另外当前这个脚本有一个bug就是每次编译实际上所有的.o文件都会完整重新编译一遍,而没有判断源文件是否更新并忽略没有更新的源文件,所以不适合大的系统。

无论是在Linux还是在Unix环境中,make都是一个非常重要的编译命令。不管是自己进行项目开发还是安装应用软件,我们都经常要用到make或make install。利用make工具,我们可以将大型的开发项目分解成为多个更易于管理的模块,对于一个包括几百个源文件的应用程序,使用make和 makefile工具就可以简洁明快地理顺各个源文件之间纷繁复杂的相互关系。而且如此多的源文件,如果每次都要键入gcc命令进行编译的话,那对程序员来说简直就是一场灾难。而make工具则可自动完成编译工作,并且可以只对程序员在上次编译后修改过的部分进行编译。因此,有效的利用make和 makefile工具可以大大提高项目开发的效率。同时掌握make和makefile之后,您也不会再面对着Linux下的应用软件手足无措了。
  但令人遗憾的是,在许多讲述Linux应用的书籍上都没有详细介绍这个功能强大但又非常复杂的编译工具。在这里我就向大家详细介绍一下make及其描述文件makefile。
  Make工具最主要也是最基本的功能就是通过makefile文件来描述源程序之间的相互关系并自动维护编译工作。而makefile 文件需要按照某种语法进行编写,文件中需要说明如何编译各个源文件并连接生成可执行文件,并要求定义源文件之间的依赖关系。makefile 文件是许多编译器--包括 Windows NT 下的编译器--维护编译信息的常用方法,只是在集成开发环境中,用户通过友好的界面修改 makefile 文件而已。
每当命令运行完后,make会检测每个命令的返回码,如果命令返回成功,那么make会执行
下一条命令,当规则中所有的命令成功返回后,这个规则就算是成功完成了。如果一个规
则中的某个命令出错了(命令退出码非零),那么make就会终止执行当前规则,这将有可
能终止所有规则的执行。
有些时候,命令的出错并不表示就是错误的。例如mkdir命令,我们一定需要建立一个目录
,如果目录不存在,那么mkdir就成功执行,万事大吉,如果目录存在,那么就出错了。我
们之所以使用mkdir的意思就是一定要有这样的一个目录,于是我们就不希望mkdir出错而
为了做到这一点,忽略命令的出错,我们可以在Makefile的命令行前加一个减号“-”(在
Tab键之后),标记为不管命令出不出错都认为是成功的。如:
ile中所有命令都会忽略错误。而如果一个规则是以“.IGNORE”作为目标的,那么这个规
则中的所有命令将会忽略错误。这些是不同级别的防止命令出错的方法,你可以根据你的
还有一个要提一下的make的参数的是“-k”或是“--keep-going”,这个参数的意思是,
如果某规则中的命令出错了,那么就终目该规则的执行,但继续执行其它规则。
在一些大的工程中,我们会把我们不同模块或是不同功能的源文件放在不同的目录中,我
们可以在每个目录中都书写一个该目录的Makefile,这有利于让我们的Makefile变得更加
地简洁,而不至于把所有的东西全部写在一个Makefile中,这样会很难维护我们的Makefi
le,这个技术对于我们模块编译和分段编译有着非常大的好处。
例如,我们有一个子目录叫subdir,这个目录下有个Makefile文件,来指明了这个目录下
文件的编译规则。那么我们总控的Makefile可以这样书写:
定义$(MAKE)宏变量的意思是,也许我们的make需要一些参数,所以定义成一个变量比较利
于维护。这两个例子的意思都是先进入“subdir”目录,然后执行make命令。
file中(如果你显示的声明),但是不会覆盖下层的Makefile中所定义的变量,除非指定
如果你要传递变量到下级Makefile中,那么你可以使用这样的声明:
如果你不想让某些变量传递到下级Makefile中,那么你可以这样声明:


三、隐含规则使用的变量
在隐含规则中的命令中,基本上都是使用了一些预先设置的变量。你可以在你的makefile
中改变这些变量的值,或是在make的命令行中传入这些值,或是在你的环境变量中设置这
些值,无论怎么样,只要设置了这些特定的变量,那么其就会对隐含规则起作用。当然,
例如,第一条隐含规则——编译C程序的隐含规则的命令是“$(CC) –c $(CFLAGS) $(CPP
FLAGS)”。Make默认的编译命令是“cc”,如果你把变量“$(CC)”重定义成“gcc”,把
变量“$(CFLAGS)”重定义成“-g”,那么,隐含规则中的命令全部会以“gcc –c -g $(
我们可以把隐含规则中使用的变量分成两种:一种是命令相关的,如“CC”;一种是参数
相的关,如“CFLAGS”。下面是所有隐含规则中会用到的变量:
函数库打包程序。默认命令是“ar”。
汇编语言编译程序。默认命令是“as”。
C语言编译程序。默认命令是“cc”。
C++语言编译程序。默认命令是“g++”。
从 RCS文件中扩展文件程序。默认命令是“co”。
C程序的预处理器(输出是标准输出设备)。默认命令是“$(CC) –E”。
Fortran 和 Ratfor 的编译器和预处理程序。默认命令是“f77”。
从SCCS文件中扩展文件的程序。默认命令是“get”。
Lex方法分析器程序(针对于C或Ratfor)。默认命令是“lex”。
Pascal语言编译程序。默认命令是“pc”。
Yacc文法分析器(针对于C程序)。默认命令是“yacc”。
Yacc文法分析器(针对于Ratfor程序)。默认命令是“yacc –r”。
从TeX源文件创建TeX DVI文件的程序。默认命令是“tex”。
转换Web到TeX的程序。默认命令是“weave”。
转换Web到Pascal语言的程序。默认命令是“tangle”。
删除文件命令。默认命令是“rm –f”。
2、关于命令参数的变量
下面的这些变量都是相关上面的命令的参数。如果没有指明其默认值,那么其默认值都是
函数库打包程序AR命令的参数。默认值是“rv”。
汇编语言编译器参数。(当明显地调用“.s”或“.S”文件时)。
C++语言编译器参数。
C预处理器参数。( C 和 Fortran 编译器也会用到)。
Fortran语言编译器参数。
链接器参数。(如:“ld”)
Lex文法分析器参数。
Pascal语言编译器参数。
Yacc文法分析器参数。

有些时候,一个目标可能被一系列的隐含规则所作用。例如,一个[.o]的文件生成,可能
会是先被Yacc的[.y]文件先成[.c],然后再被C的编译器生成。我们把这一系列的隐含规则
在上面的例子中,如果文件[.c]存在,那么就直接调用C的编译器的隐含规则,如果没有[
.c]文件,但有一个[.y]文件,那么Yacc的隐含规则会被调用,生成[.c]文件,然后,再调
用C编译的隐含规则最终由[.c]生成[.o]文件,达到目标。
我们把这种[.c]的文件(或是目标),叫做中间目标。不管怎么样,make会努力自动推导
生成目标的一切方法,不管中间目标有多少,其都会执着地把所有的隐含规则和你书写的
规则全部合起来分析,努力达到目标,所以,有些时候,可能会让你觉得奇怪,怎么我的
目标会这样生成?怎么我的makefile发疯了?
在默认情况下,对于中间目标,它和一般的目标有两个地方所不同:第一个不同是除非中
间的目标不存在,才会引发中间规则。第二个不同的是,只要目标成功产生,那么,产生
最终目标过程中,所产生的中间目标文件会被以“rm -f”删除。
通常,一个被makefile指定成目标或是依赖目标的文件不能被当作中介。然而,你可以明
显地说明一个文件或是目标是中介目标,你可以使用伪目标“.INTERMEDIATE”来强制声明
你也可以阻止make自动删除中间目标,要做到这一点,你可以使用伪目标“.SECONDARY”
来强制声明(如:.SECONDARY : sec)。你还可以把你的目标,以模式的方式来指定(如
:%.o)成伪目标“.PRECIOUS”的依赖目标,以保存被隐含规则所生成的中间文件。
在“隐含规则链”中,禁止同一个目标出现两次或两次以上,这样一来,就可防止在make
自动推导时出现无限递归的情况。
Make会优化一些特殊的隐含规则,而不生成中间文件。如,从文件“foo.c”生成目标程序
“foo”,按道理,make会编译生成中间文件“foo.o”,然后链接成“foo”,但在实际情
况下,这一动作可以被一条“cc”的命令完成(cc –o foo foo.c),于是优化过的规则

你可以使用模式规则来定义一个隐含规则。一个模式规则就好像一个一般的规则,只是在
规则中,目标的定义需要有"%"字符。"%"的意思是表示一个或多个任意字符。在依赖目标
中同样可以使用"%",只是依赖目标中的"%"的取值,取决于其目标。
有一点需要注意的是,"%"的展开发生在变量和函数的展开之后,变量和函数的展开发生在
make载入Makefile时,而模式规则中的"%"则发生在运行时。

模式规则中,至少在规则的目标定义中要包含"%",否则,就是一般的规则。目标中的"%"
定义表示对文件名的匹配,"%"表示长度任意的非空字符串。例如:"%.c"表示以".c"结尾
的文件名(文件名的长度至少为3),而"s.%.c"则表示以"s."开头,".c"结尾的文件名(
文件名的长度至少为5)。
如果"%"定义在目标中,那么,目标中的"%"的值决定了依赖目标中的"%"的值,也就是说,
目标中的模式的"%"决定了依赖目标中"%"的样子。例如有一个模式规则如下:
其含义是,指出了怎么从所有的[.c]文件生成相应的[.o]文件的规则。如果要生成的目标
一旦依赖目标中的"%"模式被确定,那么,make会被要求去匹配当前目录下所有的文件名,
一旦找到,make就会规则下的命令,所以,在模式规则中,目标可能会是多个的,如果有
模式匹配出多个目标,make就会产生所有的模式目标,此时,make关心的是依赖的文件名
和生成目标的命令这两件事。

在上述的模式规则中,目标和依赖文件都是一系例的文件,那么我们如何书写一个命令来
完成从不同的依赖文件生成相应的目标?因为在每一次的对模式规则的解析时,都会是不
自动化变量就是完成这个功能的。在前面,我们已经对自动化变量有所提涉,相信你看到
这里已对它有一个感性认识了。所谓自动化变量,就是这种变量会把模式中所定义的一系
列的文件自动地挨个取出,直至所有的符合模式的文件都取完了。这种自动化变量只应出
下面是所有的自动化变量及其说明:
表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标
仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a(bar
[.a],下是[.lib]),那么,其值为空。
依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将是符
合模式的一系列的文件集。注意,其是一个一个取出来的。
所有比目标新的依赖目标的集合。以空格分隔。
所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会
去除重复的依赖目标,只保留一份。
这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。
这个变量表示目标模式中"%"及其之前的部分。如果目标是"dir/a.foo.b",并且目标的模
式是"a.%.b",那么,"$*"的值就是"dir/a.foo"。这个变量对于构造有关联的文件名是比
较有较。如果目标中没有模式的定义,那么"$*"也就不能被推导出,但是,如果目标文件
的后缀是make所识别的,那么"$*"就是除了后缀的那一部分。例如:如果目标是"foo.c",
因为".c"是make所能识别的后缀名,所以,"$*"的值就是"foo"。这个特性是GNU make的,
很有可能不兼容于其它版本的make,所以,你应该尽量避免使用"$*",除非是在隐含规则
或是静态模式中。如果目标中的后缀是make所不能识别的,那么"$*"就是空值。
当你希望只对更新过的依赖文件进行操作时,"$?"在显式规则中很有用,例如,假设有一
个函数库文件叫"lib",其由其它几个object文件更新。那么把object文件打包的比较有效
在上述所列出来的自动量变量中。四个变量($@、$<、$%、$*)在扩展时只会有一个文件
,而另三个的值是一个文件列表。这七个自动化变量还可以取得文件的目录名或是在当前
目录下的符合模式的文件名,只需要搭配上"D"或"F"字样。这是GNU make中老版本的特性
,在新版本中,我们使用函数"dir"或"notdir"就可以做到了。"D"的含义就是Directory,
就是目录,"F"的含义就是File,就是文件。
下面是对于上面的七个变量分别加上"D"或是"F"的含义:
是"dir",而如果"$@"中没有包含斜杠的话,其值就是"."(当前目录)。
和上面所述的同理,也是取文件的目录部分和文件部分。对于上面的那个例子,"$(*D)"返
分别表示了函数包文件成员的目录部分和文件部分。这对于形同"archive(member)"形式的
目标中的"member"中包含了不同的目录很有用。
分别表示依赖文件的目录部分和文件部分。
分别表示所有依赖文件的目录部分和文件部分。(无相同的)
分别表示所有依赖文件的目录部分和文件部分。(可以有相同的)
分别表示被更新的依赖文件的目录部分和文件部分。
最后想提醒一下的是,对于"$<",为了避免产生不必要的麻烦,我们最好给$后面的那个特
定字符都加上圆括号,比如,"$(<)"就要比"$<"要好一些。
还得要注意的是,这些变量只使用在规则的命令中,而且一般都是"显式规则"和"静态模式
规则"(参见前面"书写规则"一章)。其在隐含规则中并没有意义。
一般来说,一个目标的模式有一个有前缀或是后缀的"%",或是没有前后缀,直接就是一个
"%"。因为"%"代表一个或多个字符,所以在定义好了的模式中,我们把"%"所匹配的内容叫
做"茎",例如"%.c"所匹配的文件"test.c"中"test"就是"茎"。因为在目标和依赖目标中同
时有"%"时,依赖目标的"茎"会传给目标,当做目标中的"茎"。
当一个模式匹配包含有斜杠(实际也不经常包含)的文件时,那么在进行模式匹配时,目
录部分会首先被移开,然后进行匹配,成功后,再把目录加回去。在进行"茎"的传递时,
我们需要知道这个步骤。例如有一个模式"e%t",文件"src/eat"匹配于该模式,于是"src
/a"就是其"茎",如果这个模式定义在依赖目标中,而被依赖于这个模式的目标中又有个模

你可以重载内建的隐含规则(或是定义一个全新的),例如你可以重新构造和内建隐含规
你可以取消内建的隐含规则,只要不在后面写命令就行。如:
同样,你也可以重新定义一个全新的隐含规则,其在隐含规则中的位置取决于你在哪里写
下这个规则。朝前的位置就靠前。

六、老式风格的"后缀规则"
后缀规则是一个比较老式的定义隐含规则的方法。后缀规则会被模式规则逐步地取代。因
为模式规则更强更清晰。为了和老版本的Makefile兼容,GNU make同样兼容于这些东西。
后缀规则有两种方式:"双后缀"和"单后缀"。
双后缀规则定义了一对后缀:目标文件的后缀和依赖目标(源文件)的后缀。如".c.o"相
当于"%o : %c"。单后缀规则只定义一个后缀,也就是源文件的后缀。如".c"相当于"% :
后缀规则中所定义的后缀应该是make所认识的,如果一个后缀是make所认识的,那么这个
规则就是单后缀规则,而如果两个连在一起的后缀都被make所认识,那就是双后缀规则。
例如:".c"和".o"都是make所知道。因而,如果你定义了一个规则是".c.o"那么其就是双
后缀规则,意义就是".c"是源文件的后缀,".o"是目标文件的后缀。如下示例:
后缀规则不允许任何的依赖文件,如果有依赖文件的话,那就不是后缀规则,那些后缀统
统被认为是文件名,如:
这个例子,就是说,文件".c.o"依赖于文件"foo.h",而不是我们想要的这样:
后缀规则中,如果没有命令,那是毫无意义的。因为他也不会移去内建的隐含规则。
而要让make知道一些特定的后缀,我们可以使用伪目标".SUFFIXES"来定义或是删除,如:

比如我们有一个目标叫 T。下面是搜索目标T的规则的算法。请注意,在下面,我们没有提
到后缀规则,原因是,所有的后缀规则在Makefile被载入内存时,会被转换成模式规则。
如果目标是"archive(member)"的函数库文件模式,那么这个算法会被运行两次,第一次是
找目标T,如果没有找到的话,那么进入第二次,第二次会把"member"当作T来搜索。
1、把T的目录部分分离出来。叫D,而剩余部分叫N。(如:如果T是"src/foo.o",那么,
2、创建所有匹配于T或是N的模式规则列表。
3、如果在模式规则列表中有匹配所有文件的模式,如"%",那么从列表中移除其它的模式
4、移除列表中没有命令的规则。
5、对于第一个在列表中的模式规则:
1)推导其"茎"S,S应该是T或是N匹配于模式中"%"非空的部分。
2)计算依赖文件。把依赖文件中的"%"都替换成"茎"S。如果目标模式中没有包含斜框字符
,而把D加在第一个依赖文件的开头。
3)测试是否所有的依赖文件都存在或是理当存在。(如果有一个文件被定义成另外一个规
则的目标文件,或者是一个显式规则的依赖文件,那么这个文件就叫"理当存在")
4)如果所有的依赖文件存在或是理当存在,或是就没有依赖文件。那么这条规则将被采用
6、如果经过第5步,没有模式规则被找到,那么就做更进一步的搜索。对于存在于列表中
1)如果规则是终止规则,那就忽略它,继续下一条模式规则。
2)计算依赖文件。(同第5步)
3)测试所有的依赖文件是否存在或是理当存在。
4)对于不存在的依赖文件,递归调用这个算法查找他是否可以被隐含规则找到。
5)如果所有的依赖文件存在或是理当存在,或是就根本没有依赖文件。那么这条规则被采
7、如果没有隐含规则可以使用,查看".DEFAULT"规则,如果有,采用,把".DEFAULT"的命
一旦规则被找到,就会执行其相当的命令,而此时,我们的自动化变量的值才会生成。
使用make更新函数库文件
———————————
函数库文件也就是对Object文件(程序编译的中间文件)的打包文件。在Unix下,一般是
由命令"ar"来完成打包工作。
一个函数库文件由多个文件组成。你可以以如下格式指定函数库文件及其组成:
这个不是一个命令,而一个目标和依赖的定义。一般来说,这种用法基本上就是为了"ar"
如果要指定多个member,那就以空格分开,如:
你还可以使用Shell的文件通配符来定义,如:

二、函数库成员的隐含规则
当make搜索一个目标的隐含规则时,一个特殊的特性是,如果这个目标是"a(m)"形式的,
其会把目标变成"(m)"。于是,如果我们的成员是"%.o"的模式定义,并且如果我们使用"m
义bar.o的规则,那么内建隐含规则生效,make会去找bar.c文件来生成bar.o,如果找得到
的话,make执行的命令大致如下:
还有一个变量要注意的是"$%",这是专属函数库文件的自动化变量,有关其说明请参见"自

在进行函数库打包文件生成时,请小心使用make的并行机制("-j"参数)。如果多个ar命
令在同一时间运行在同一个函数库打包文件上,就很有可以损坏这个函数库文件。所以,
在make未来的版本中,应该提供一种机制来避免并行操作发生在函数打包文件上。
但就目前而言,你还是应该不要尽量不要使用"-j"参数。
终于到写结束语的时候了,以上基本上就是GNU make的Makefile的所有细节了。其它的产
商的make基本上也就是这样的,无论什么样的make,都是以文件的依赖性为基础的,其基
本是都是遵循一个标准的。这篇文档中80%的技术细节都适用于任何的make,我猜测"函数
"那一章的内容可能不是其它make所支持的,而隐含规则方面,我想不同的make会有不同的
什么样的差别,一是时间精力不够,二是因为我基本上都是在Unix下使用make,以前在SC
s下更多一点。不过,我可以肯定的是,在Unix下的make,无论是哪种平台,几乎都使用了
有的UNIX机器上都被装上了GNU的东西,所以,使用GNU的程序也就多了一些)。GNU的东西
还是很不错的,特别是使用得深了以后,越来越觉得GNU的软件的强大,也越来越觉得GNU
的在操作系统中(主要是Unix,甚至)"杀伤力"。
对于上述所有的make的细节,我们不但可以利用make这个工具来编译我们的程序,还可以
利用make来完成其它的工作,因为规则中的命令可以是任何Shell之下的命令,所以,在U
nix下,你不一定只是使用程序语言的编译器,你还可以在Makefile中书写其它的命令,如
完成诸如"程序打包"、"程序备份"、"制作程序安装包"、"提交代码"、"使用程序模板"、
"合并文件"等等五花八门的功能,文件操作,文件管理,编程开发设计,或是其它一些异
想天开的东西。比如,以前在书写银行交易程序时,由于银行的交易程序基本一样,就见
到有人书写了一些交易的通用程序模板,在该模板中把一些通讯、数据库操作的、业
务操作共性的东西写在一个文件中,在这些文件中用些诸如"@@@N、###N"奇怪字串标注一
些位置,然后书写交易时,只需按照一种特定的规则书写特定的处理,最后在make时,使
用awk和sed,把模板中的"@@@N、###N"等字串替代成特定的程序,形成C文件,然后再编译
。这个动作很像数据库的"扩展C"语言(即在C语言中用"EXEC SQL"的样子执行SQL语句,
在用cc/gcc编译之前,需要使用"扩展C"的翻译程序,如cpre,把其翻译成标准C)。如果
你在使用make时有一些更为绝妙的方法,请记得告诉我啊。
回头看看整篇文档,不觉记起几年前刚刚开始在Unix下做开发的时候,有人问我会不会写
Makefile时,我两眼发直,根本不知道在说什么。一开始看到别人在vi中写完程序后输入
"!make"时,还以为是vi的功能,后来才知道有一个Makefile在作怪,于是上网查啊查,那
时又不愿意看英文,发现就根本没有中文的文档介绍Makefile,只得看别人写的Makefile
,自己瞎碰瞎搞才积累了一点知识,但在很多地方完全是知其然不知所以然。后来开始从
事UNIX下产品软件的开发,看到一个400人年,近200万行代码的大工程,发现要编译这样
一个庞然大物,如果没有Makefile,那会是多么恐怖的一样事啊。于是横下心来,狠命地
读了一堆英文文档,才觉得对其掌握了。但发现目前网上对Makefile介绍的文章还是少得
那么的可怜,所以想写这样一篇文章,共享给大家,希望能对各位有所帮助。
现在我终于写完了,看了看文件的创建时间,这篇技术文档也写了两个多月了。发现,自
己知道是一回事,要写下来,跟别人讲述又是另外一回事,而且,现在越来越没有时间专
研技术细节,所以在写作时,发现在阐述一些细节问题时很难做到严谨和精练,而且对先
讲什么后讲什么不是很清楚,所以,还是参考了一些国外站点上的资料和题纲,以及一些
技术书籍的语言风格,才得以完成。整篇文档的提纲是基于GNU的Makefile技术手册的提纲
来书写的,并结合了自己的工作经验,以及自己的学习历程。因为从来没有写过这么长,
这么细的文档,所以一定会有很多地方存在表达问题,语言歧义或是错误。因些,我迫切
地得等待各位给我指证和建议,以及任何的反馈。
最后,还是利用这个后序,介绍一下自己。我目前从事于所有Unix平台下的软件研发,主
要是做分布式计算/网格计算方面的系统产品软件,并且我对于下一代的计算机革命——网
格计算非常地感兴趣,对于分布式计算、P2P、Web Service、J2EE技术方向也很感兴趣,
同时,对于项目实施、团队管理、项目管理也小有心得,希望同样和我战斗在“技术和管
理并重”的阵线上的年轻一代,能够和我多多地交流。我的MSN是:(
常用),QQ是:753640(不常用)。(注:请勿给我MSN的邮箱发信,由于hotmail的垃圾
邮件导致我拒收这个邮箱的所有来信)
我欢迎任何形式的交流,无论是讨论技术还是管理,或是其它海阔天空的东西。除了政治
和娱乐新闻我不关心,其它只要积极向上的东西我都欢迎!
最最后,我还想介绍一下make程序的设计开发者。
开源软件的领袖和先驱,从来没有领过一天工资,从来没有使用过操作系统。对于
他的事迹和他的软件以及他的思想,我无需说过多的话,相信大家对这个人并不比我陌生
,这是他的主页: 。上面贴上一张他的近照

个人主页是: ,下面是他的一些事迹:
4) 合作编写并维护着部分的GNU Emacs。
在此,向这两位开源项目的斗士致以最真切的敬意。

一个空文件,文件名为makefile或者Makefile,这个文件名是必须的因为make默认查找该文件

1行:生成test可执行文件,它的依赖于main.o func.o,也就是说生成test你得先生成它们,

2行:gcc前边必须是tab也就是7个空格,表示编译生成test

后边是依赖项的生成规则

然后运行compile.bat就可以生成test.exe文件了,同时会附加生成func.o和main,o两个中间代码的文件,类似于VC中的obj文件

同VC,TC等编译器不同,GCC其实是可以很方便的在提示符下编译程序的。GCC在提示符下编译程序,并没有如同VC那样的冗长而晦涩的编译参数。相反,却有着比VC更灵活且简短的参数。

不得不承认,不懂GCC编译参数的人,确实会损失一些GCC的强大功能。所以,我下面简单介绍一下GCC的一些基本编译参数。这里,我以C编译器为例。

通过这条指令,GCC将会把yours.c源代码编译成名为yours的可执行程序。当然,您也可以将yours.c改成我们刚才介绍的yours.o文件。这样,gcc将使用编译刚才编译好的二进制文档来链接程序。这里,格式的特点是,-o后面是一串文件列表,第一个参数是所编译程序的文件名,从第二个开始,就是您编译和连接该可执行程序所需要的二进制文档或者源代码。

这条指令将会让GCC在连接时除了在默认Lib存放目录中搜索指定的静态库以外,还会在Your_Lib_Files_Document_Path中搜索。

这条指令将会让GCC在连接时把libyour_lib.a中您所用到的函数连接到可执行程序中。此处注意,GCC所使用的静态连接库是lib*.a格式的。在连接时,只且仅需要提供*的内容就可以了。

使用优化方式编译程序,其中除了-O2以外,还有-O3 -O1等等。他们代表不同的优化等级。最常用的,是-O2优化。当然,还有针对特殊CPU的优化,这里就不介绍了。

GCC在默认情况下,将对一些如变量申请未使用这样的问题或者申请了没有给予初始值的问题忽略。但是,如果使用了-Wall参数,编辑器将列出所有的警告信息。这样,您就可以知道您的代码中有多少可能会在其他操作系统下出错的地方了。(用这个指令看看你的代码有多少地方写的不怎么合适。)

正如同VC有debug编译模式一样,GCC也有debug模式。添加了-g参数编译的可执行程序比普通程序略为大一些,其中添加了一些调试代码。这些代码将被gdb所支持。

这个参数,似乎我没有在Unix环境下看到过。也不知道具体什么作用。因为有人说Visual-MinGW生成的代码小,于是研究了一下她的编译参数,发现release模式的编译参数就加了这一项。貌似编译后的代码的确缩小了很多。

这条指令从意思上就能看出,获得gcc的帮助信息。如果您有什么特殊需要,也许这个指令能帮上点小忙。

我要回帖

更多关于 c语言编译器 的文章

 

随机推荐