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. )。

GCC & Maker的更多相关文章

  1. gcc,make,cmake

    1.gcc是GNU Compiler Collection(就是GNU编译器套件),也可以简单认为是编译器,它可以编译很多种编程语言(括C.C++.Objective-C.Fortran.Java等等 ...

  2. 关于gcc、make和CMake的区别

    CMake是一种跨平台编译工具,比make更为高级,使用起来要方便得多.CMake主要是编写CMakeLists.txt文件,然后用cmake命令将CMakeLists.txt文件转化为make所需要 ...

  3. VSCode调试go语言出现:exec: "gcc": executable file not found in %PATH%

    1.问题描述 由于安装VS15 Preview 5,搞的系统由重新安装一次:在用vscdoe编译go语言时,出现以下问题: # odbcexec: "gcc": executabl ...

  4. GCC学习(1)之MinGW使用

    GCC学习(1)之MinGW使用 因为后续打算分享一些有关GCC的使用心得的文章,就把此篇当作一个小预热,依此来了解下使用GNU工具链(gcc.gdb.make等)在脱离IDE的情况下如何开发以及涉及 ...

  5. 使用 GCC 和 GNU Binutils 编写能在 x86 实模式运行的 16 位代码

    不可否认,这次的标题有点长.之所以把标题写得这么详细,主要是为了搜索引擎能够准确地把确实需要了解 GCC 生成 16 位实模式代码方法的朋友带到我的博客.先说一下背景,编写能在 x86 实模式下运行的 ...

  6. [异常解决] How to build a gcc toolchain for nRF51 on linux (very detailed!!!)

    1.Install gcc-arm-none-eabi https://devzone.nordicsemi.com/tutorials/7/This link shows that developm ...

  7. CentOS 6.6 升级GCC G++ (当前最新版本为v6.1.0) (完整)

    ---恢复内容开始--- CentOS 6.6 升级GCC G++ (当前最新GCC/G++版本为v6.1.0) 没有便捷方式, yum update....   yum install 或者 添加y ...

  8. GCC 预处理、编译、汇编、链接..

    1简介 GCC 的意思也只是 GNU C Compiler 而已.经过了这么多年的发展,GCC 已经不仅仅能支持 C 语言:它现在还支持 Ada 语言.C++ 语言.Java 语言.Objective ...

  9. 用gcc进行程序的编译

    在Linux系统上,一个档案能不能被执行看的是有没有可执行的那个权限(x),不过,Linux系统上真正认识的可执行文件其实是二进制文件(binary program),例如/usr/bin/passw ...

随机推荐

  1. html之表单和简单CSS

    一.==表单== 1. form表单本身 <form name="myform" action="#" method="get"> ...

  2. 使用RestTemplate时报错java.lang.IllegalStateException: No instances available for 127.0.0.1

    我在RestTemplate的配置类里使用了 @LoadBalanced@Componentpublic class RestTemplateConfig { @Bean @LoadBalanced ...

  3. js 遍历tree的一个例子

    小例子蕴含着到力量,我希望自己有改变自己生活的能力,自己有主宰自己命运的能力... 备注:这个例子有问题. <!DOCTYPE html> <html lang="en&q ...

  4. Til the Cows Come Home (dijkstra算法)

    Bessie is out in the field and wants to get back to the barn to get as much sleep as possible before ...

  5. wireshark开发环境搭建

    自己完成了wireshark开发环境的搭建,主要参考资料是wireshark的官方developer-guide.pdf,网址:https://www.wireshark.org/docs/. 现把搭 ...

  6. docker(5)常用命令

    1.docker docker安装国内源 $ sudo yum-config-manager \ --add-repo \ https://mirrors.ustc.edu.cn/docker-ce/ ...

  7. Linux关于用户信息的一些命令

    1.用户增加删除[root@VM_0_13_centos ~]# useradd better407 #添加 better407 用户 [root@VM_0_13_centos ~]# passwd ...

  8. 2 Sum

    Problem Given an array of integers, find two numbers such that they add up to aspecific target numbe ...

  9. 虚拟机 ---- 最小化安装无法使用tab补全键

    解决方法: 安装 yum -y install bash-completion 然后重启 注意:挂载时使用绝对路径的cdrom挂载,  ls -l /dev/cdromvim /etc/fstab — ...

  10. 关系型数据库---MySQL---对中文字段排序

    1.对中文进行排序时会发生错误,原因是使用的字符集不是中文的字符集: 解决:CONVERT函数 SELECT a.id,a.`name`,a.ch_name FROM `user` a ORDER B ...