All we did must depend on compiler, and then What we did can run on machine.

What does compiler do behind our programm?

  • Reference to :http://gcc.gnu.org/
  • http://www.cnblogs.com/lingqing/archive/2012/08/04/2623241.html
  •  : -c GCC 把给它的文件编译成目标文件,用源文件的文件名命名
    e.g
    gcc -c Zhanglong.c longzhang.c
    生成如下:
    Zhanglong.o longzhang.o :如果给的是一列目标文件,则会连接成可执行文件
    e.g
    gcc zhanglong.o longzhang.o
    生成如下:
    a.out
    e.g.
    gcc -o zhanglong_execfile *.o
    生成如下:
    zhanglong_execfile :如果改变了一个HEADR文档,需要重新编译所有文档
    e.g.
    gcc -c zhanglong1.c zhanglong2.c zhanglong3.c *.c
    生成如下:
    zhanglong1.o zhanglong2.o zhanglong3.o *.o
    继续:
    gcc -o ZhangLong *.o
    生成如下:
    ZhangLong :makefile 主要包含一系列规则
    :.............
    (tab)<command>
    (tab)<command>
    .
    .
    .
    e.g.
    ZLProg:long.o zhang.o
    gcc long.o zhang.o ZLProg long.o: long.c long.h zhang.h
    gcc -c long.c -o long.o zhang.o:zhang.c zhang.h
    gcc -c zhang.c -o zhang.o
    注释:
    ZLProg 是主要目标,一个它需要保 证其总是最新的最终目标; 给出的规则说明只要文件‘myprog’
    比文件‘foo.o’或‘bar.o’中的任何一个旧,下一行的命令将 会被执行。
    但是,在检查文件 foo.o 和 bar.o 的时间戳之前,它会往下查 找那些把 foo.o 或
    bar.o 做为目标文件的规则。它找到的关于 foo.o 的规则,该文件的依靠文件是 foo.c,
    foo.h 和 bar.h 。
    它从下面再找不到生成这些依靠文件的规则,它就开始检查磁碟
    上这些依靠文件的时间戳。如果这些文件中任何一个的时间戳比 foo.o 的新,命令 'gcc
    -o foo.o foo.c' 将会执行,从而更新 文件 foo.o 。
    接下来对文件 bar.o 做类似的检查,依靠文件在这里是文件 bar.c 和 bar.h 。
    现在, make 回到‘myprog’的规则。如果刚才两个规则中的任 一个被执行,myprog
    就需要重建(因为其中一个 .o 档就会比 ‘myprog’新),因此连接命令将被执行。
    :编写 make 规则 (Rules) 最明显的(也是最简单的)编写规则的方法是一个一个的查
    看源码文件,把它们的目标文件做为目的,而C源码文件和被它 #include 的 header
    档做为依靠文件。但是你也要把其它被这些 header 档 #include 的 header
    档也列为依靠文件,还有那些被
    包括的文件所包括的文件……然后你会发现要对越来越多的文件进行管理。 使用 gcc 的时候,用 -M
    开关,它会为每一个你给它的C文件输出一个规则,把目标文件
    做为目的,而这个C文件和所有应该被 #include 的 header 文
    件将做为依靠文件。注意这个规则会加入所有 header 文件,包 括被角括号(`<',
    `>')和双引号(`"')所包围的文件。其实我们可以 相当肯定系统 header 档(比如
    stdio.h, stdlib.h 等等)不会 被我们更改,如果你用 -MM 来代替 -M 传递给
    gcc,那些用角括 号包围的 header 档将不会被包括。(这会节省一些编译时间)由 gcc
    输出的规则不会含有命令部分;你可以自己写入你的命令 或者什么也不写,而让 make
    使用它的隐含的规则
    e.g.
    file: Main.c
    #include <stdlib.h>
    #include "zhang.h"
    #include "long.h" int main()
    {
    printf("Hello wold!\n");
    }
    编译:
    gcc -M Main.c
    生成如下:
    Main.c:stdlib.h zhang.h long.h :Makefile 变量
    i) 贮存一个文件名列表。在上面的例子里,生成可执行文件的
    规则包含一些目标文件名做为依靠。在这个规则的命令行 里同样的那些文件被输送给 gcc
    做为命令参数。如果在这 里使用一个变数来贮存所有的目标文件名,加入新的目标
    文件会变的简单而且较不易出错。 ii) 贮存可执行文件名。如果你的项目被用在一个非 gcc 的系
    统里,或者如果你想使用一个不同的编译器,你必须将所
    有使用编译器的地方改成用新的编译器名。但是如果使用一
    个变量来代替编译器名,那么你只需要改变一个地方,其
    它所有地方的命令名就都改变了。 iii) 贮存编译器旗标。假设你想给你所有的编译命令传递一组 相同的选项(例如 -Wall
    -O -g);如果你把这组选项存 入一个变量,那么你可以把这个变量放在所有呼叫编译器
    的地方。而当你要改变选项的时候,你只需在一个地方改
    变这个变量的内容。要设定一个变量,你只要在一行的开始写下这个变量的名字,后
    面跟一个 = 号,后面跟你要设定的这个变量的值。以后你要引用 这个变量,写一个 $
    符号,后面是围在括号里的变量名。比如在 下面,我们把前面的 makefile
    利用变量重写一遍: === makefile 开始 ===
    OBJS = foo.o bar.o
    CC = gcc
    CFLAGS = -Wall -O -g myprog : $(OBJS)
    $(CC) $(OBJS) -o myprog foo.o : foo.c foo.h bar.h
    $(CC) $(CFLAGS) -c foo.c -o foo.o bar.o : bar.c bar.h
    $(CC) $(CFLAGS) -c bar.c -o bar.o
    === makefile 结束 === 还有一些设定好的内部变量,它们根据每一个规则内容定义。三个 比较有用的变量是
    $@,$< 和 $^ (这些变量不需要括号括住)。
    $@ 扩展成当前规则的目的文件名,
    $< 扩展成依靠列表中的第 一个依靠文件,
    而 $^ 扩展成整个依靠的列表 === makefile 开始 ===
    OBJS = foo.o bar.o
    CC = gcc
    CFLAGS = -Wall -O -g
    myprog:$(OBJS)
    $(CC) $^ -o $@ foo.o:foo.c foo.h bar.h
    $(CC) $(CFLAGS) -c $< -o $@ bar.o:bar.c bar.h
    $(CC) $(CFLAGS) -c $< -o $@
    === makefile 结束====== :
    如果你把生成 foo.o 和 bar.o 的命令从它们的规则中删除, make
    将会查找它的隐含规则,然后会找到一个适当的命令。它的命令会
    使用一些变量,因此你可以按照你的想法来设定它:它使用变量 CC
    做为编译器(象我们在前面的例子),并且传递变量 CFLAGS (给 C 编译器,C++
    编译器用 CXXFLAGS ),CPPFLAGS ( C 预 处理器旗标), TARGET_ARCH
    (现在不用考虑这个),然后它加 入旗标 '-c' ,后面跟变量 $<
    (第一个依靠名),然后是旗 标 '-o' 跟变量 $@
    (目的文件名)。一个C编译的具体命令将 会是: $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ :
    在 GNU Make 里有一个叫 'wildcard' 的函
    数,它有一个参数,功能是展开成一列所有符合由其参数描述的文
    件名,文件间以空格间隔。你可以像下面所示使用这个命令: SOURCES = $(wildcard *.c) 这行会产生一个所有以 '.c' 结尾的文件的列表,然后存入变量 SOURCES
    里。当然你不需要一定要把结果存入一个变量。 :
    另一个有用的函数是 patsubst ( patten substitude, 匹配替
    换的缩写)函数。它需要3个参数——第一个是一个需要匹配的
    式样,第二个表示用什么来替换它,第三个是一个需要被处理的
    由空格分隔的字列。例如,处理那个经过上面定义后的变量,
    OBJS = $(patsubst %.c,%.o,$(SOURCES))
    这行将处理所有在 SOURCES 字列中的字(一列文件名),如果它的 结尾是 '.c'
    ,就用 '.o' 把 '.c' 取代。注意这里的 % 符号将匹
    配一个或多个字符,而它每次所匹配的字串叫做一个‘柄’(stem) 。 在第二个参数里, %
    被解读成用第一参数所匹配的那个柄。
    : === makefile 开始 === ######################################
    #
    # Generic makefile
    #
    # by George Foot
    # email: george.foot@merton.ox.ac.uk
    #
    # Copyright (c) George Foot
    # All rights reserved.
    # 保留所有版权
    #
    # No warranty, no liability;
    # you use this at your own risk.
    # 没保险,不负责
    # 你要用这个,你自己担风险
    #
    # You are free to modify and
    # distribute this without giving
    # credit to the original author.
    # 你可以随便更改和散发这个文件
    # 而不需要给原作者什么荣誉。
    # (你好意思?)
    #
    ###################################### ### Customising
    # 用户设定
    #
    # Adjust the following if necessary; EXECUTABLE is the target
    # executable's filename, and LIBS is a list of libraries to link in
    # (e.g. alleg, stdcx, iostr, etc). You can override these on make's
    # command line of course, if you prefer to do it that way.
    #
    # 如果需要,调整下面的东西。 EXECUTABLE 是目标的可执行文件名, LIBS
    # 是一个需要连接的程序包列表(例如 alleg, stdcx, iostr 等等)。当然你
    # 可以在 make 的命令行覆盖它们,你愿意就没问题。
    # EXECUTABLE := mushroom.exe
    LIBS := alleg # Now alter any implicit rules' variables if you like, e.g.:
    #
    # 现在来改变任何你想改动的隐含规则中的变量,例如 CFLAGS := -g -Wall -O3 -m486
    CXXFLAGS := $(CFLAGS) # The next bit checks to see whether rm is in your djgpp bin
    # directory; if not it uses del instead, but this can cause (harmless)
    # `File not found' error messages. If you are not using DOS at all,
    # set the variable to something which will unquestioningly remove
    # files.
    #
    # 下面先检查你的 djgpp 命令目录下有没有 rm 命令,如果没有,我们使用
    # del 命令来代替,但有可能给我们 'File not found' 这个错误信息,这没
    # 什么大碍。如果你不是用 DOS ,把它设定成一个删文件而不废话的命令。
    # (其实这一步在 UNIX 类的系统上是多余的,只是方便 DOS 用户。 UNIX
    # 用户可以删除这5行命令。) ifneq ($(wildcard $(DJDIR)/bin/rm.exe),)
    RM-F := rm -f
    else
    RM-F := del
    endif # You shouldn't need to change anything below this point.
    #
    # 从这里开始,你应该不需要改动任何东西。(我是不太相信,太NB了!) SOURCE := $(wildcard *.c) $(wildcard *.cc)
    OBJS := $(patsubst %.c,%.o,$(patsubst %.cc,%.o,$(SOURCE)))
    DEPS := $(patsubst %.o,%.d,$(OBJS))
    MISSING_DEPS := $(filter-out $(wildcard $(DEPS)),$(DEPS))
    MISSING_DEPS_SOURCES := $(wildcard $(patsubst %.d,%.c,$(MISSING_DEPS)) \
    $(patsubst %.d,%.cc,$(MISSING_DEPS)))
    CPPFLAGS += -MD .PHONY : everything deps objs clean veryclean rebuild everything : $(EXECUTABLE) deps : $(DEPS) objs : $(OBJS) clean :
    @$(RM-F) *.o
    @$(RM-F) *.d veryclean: clean
    @$(RM-F) $(EXECUTABLE) rebuild: veryclean everything ifneq ($(MISSING_DEPS),)
    $(MISSING_DEPS) :
    @$(RM-F) $(patsubst %.d,%.o,$@)
    endif -include $(DEPS) $(EXECUTABLE) : $(OBJS)
    gcc -o $(EXECUTABLE) $(OBJS) $(addprefix -l,$(LIBS)) === makefile 结束 === 有几个地方值得解释一下的。首先,我在定义大部分变量的时候使 用的是 := 而不是 =
    符号。它的作用是立即把定义中参考到的函 数和变量都展开了。如果使用 =
    的话,函数和变量参考会留在那
    儿,就是说改变一个变量的值会导致其它变量的值也被改变。例 如: A = foo
    B = $(A)
    # 现在 B 是 $(A) ,而 $(A) 是 'foo' 。
    A = bar
    # 现在 B 仍然是 $(A) ,但它的值已随着变成 'bar' 了。
    B := $(A)
    # 现在 B 的值是 'bar' 。
    A = foo
    # B 的值仍然是 'bar' 。 make 会忽略在 # 符号后面直到那一行结束的所有文字。 ifneg...else...endif 系统是 makefile 里让某一部分码有条件的 失效/有效的工具。
    ifeq 使用两个参数,如果它们相同,它把直 到 else (或者 endif ,如果没有 else
    的话)的一段码加进 makefile 里;如果不同,把 else 到 endif 间的一段码加入
    makefile (如果有 else )。 ifneq 的用法刚好相反。 'filter-out' 函数使用两个用空格分开的列表,它把第二列表中所
    有的存在于第一列表中的项目删除。我用它来处理 DEPS 列表,把所
    有已经存在的项目都删除,而只保留缺少的那些。 我前面说过, CPPFLAGS 存有用于隐含规则中传给预处理器的一些 旗标。而 -MD 开关类似
    -M 开关,但是从源码文件 .c 或 .cc 中 形成的文件名是使用后缀 .d
    的(这就解释了我形成 DEPS 变量的 步骤)。DEPS 里提到的文件后来用 '-include'
    加进了 makefile 里,它隐藏了所有因文件不存在而产生的错误信息。 如果任何依靠文件不存在, makefile 会把相应的 .o 文件从磁碟 上删除,从而使得 make
    重建它。因为 CPPFLAGS 指定了 -MD , 它的 .d 文件也被重新产生。 最后, 'addprefix' 函数把第二个参数列表的每一项前缀上第一 个参数值。 这个 makefile 的那些目的是(这些目的可以传给 make 的命令行 来直接选用): everything:(预设) 更新主要的可执行程序,并且为每一个 源码文件生成或更新一个
    '.d' 文件和一个 '.o' 文件。 deps: 只是为每一个源码程序产生或更新一个 '.d' 文件。 objs: 为每一个源码程序生成或更新 '.d' 文件和目标文件。 clean: 删除所有中介/依靠文件( *.d 和 *.o )。 veryclean: 做 `clean' 和删除可执行文件。 rebuild: 先做 `veryclean' 然后 `everything' ;既完全重建。 除了预设的 everything 以外,这里头只有 clean , veryclean , 和 rebuild
    对用户是有意义的。 我还没有发现当给出一个源码文件的目录,这个 makefile 会失败的
    情况,除非依靠文件被弄乱。如果这种弄乱的情况发生了,只要输入 `make clean'
    ,所有的目标文件和依靠文件会被删除,问题就应该
    被解决了。当然,最好不要把它们弄乱。如果你发现在某种情况下这 个 makefile
    文件不能完成它的工作,请告诉我,我会把它整好的。 总结
    ~~~~~~~~~~~~~~~ 我希望这篇文章足够详细的解释了多文件项目是怎么运作的,也说明了
    怎样安全而合理的使用它。到此,你应该可以轻松的利用 GNU Make 工
    具来管理小型的项目,如果你完全理解了后面几个部分的话,这些对于
    你来说应该没什么困难。 GNU Make 是一件强大的工具,虽然它主要是用来建立程序,它还有很多
    别的用处。如果想要知道更多有关这个工具的知识,它的句法,函数,
    和许多别的特点,你应该参看它的参考文件 (info pages, 别的 GNU
    工具也一样,看它们的 info pages. )。

最新文章

  1. 前端开发--评论区抓bug
  2. AC日记——约瑟夫问题 codevs 1282
  3. js当中的声明和初始化的顺序
  4. Android Studio in OSX 提高工作效率的快捷键
  5. 通过组策略实现Firefox自动以当前域账号登录MOSS站点---(原创)
  6. json跨域
  7. java 动态代码生成。
  8. jquery ajax的async属性的理解
  9. iOS开发——实用篇&amp;KVO与KVC详解
  10. linux 如何禁用账号和解除禁用账号
  11. C语言的本质(12)——指针与函数
  12. Ling to entity实现分页
  13. 第三章 CUDA设备相关
  14. 【转】简单了介绍js中的一些概念(词法结构) 和 数据类型(部分)。
  15. 用AtomicStampedReference解决ABA问题
  16. Java监听器Listener使用详解
  17. python换行语法错误
  18. SOA总结(脑图图片)
  19. python之tkinter使用-复选框操作
  20. 2015.7.10js-07(简单时间)

热门文章

  1. linux 内核的 switch_to原理
  2. light oj 1047 - Neighbor House(贪心)
  3. 简单的Web日志分析脚本
  4. 报错:The valid characters are defined in RFC 7230 and RFC 3986
  5. Yiic执行php脚本
  6. sklearn——回归评估指标
  7. pageX,clientX,offsetX,screenX,offsetLeft,style.left,offsetWidth,scrollWidth的区别以及使用详解
  8. spark常用算子总结
  9. [转]Loading, Editing, and Saving a Text File in HTML5 Using Javascript
  10. 利用Intent.ACTION_SEND进行分享