一、关于编译器

小明一个XXX程序员,今天他想对c语言的编译过程进行一个系统的学习,而大神小度则是他今天的导师。

小度首先问了小明一个问题:C语言常用的编译器有哪些呢?

还好小明上课前还是做了一定的功课,不假思索的回答: > 1. GNU Compiler Collection 或称 GCC,它可以编译很多种编程语言(括C、C++、Objective-C、Fortran、Java等等) > 2. Microsoft C 或称 MS C > 3. Borland Turbo C 或称 Turbo C

小度:很好,除了以上三种还有LCC、TCC、PCC、Clang、Pelles C等等,不过目前GCC应用最为广泛,今天我们的课题就以GCC为我们的编译器。

二、关于GCC

  • 在小度导师的指定下,小明首先写一个简单c程序,程序包含两个c源文件,于是他很快就想到了用gcc命令编译它。

    gcc -o hellWorld hello.c world.c
    
    1. gcc在执行编译工作的时候,总共需要4步:
      a. 预处理,生成 .i 的文件[预处理器cpp]
      b. 将预处理后的文件不转换成汇编语言, 生成文件 .s [编译器egcs]
      c. 由汇编变为目标代码(机器代码)生成 .o 的文件[汇编器as]
      d. 连接目标代码, 生成可执行程序 [链接器ld]
    2. 常用命令:
      a. -x 指定编译的语言
      b. -c 执行(1、2、3),不执行4,生成 .o 的 obj 文件,gcc默认执行(1、2、3、4)生成可执行文件
      c. -o 批量输出文件
      d. -g 创建符号表,符号表包含了程序中使用的变量名称的列表,同时关闭所有的优化机制,以便程序执行过程中严格按照原来的C代码进行。主要用于gdb调试。
  • 写完第一个程序后,小明想来点有挑战的,他一口气写了一个包含20个c源文件的程序,小明想到20个c文件编译的场景:

    gcc -o main file1.c file2.c file3.c ... file20.c
    ```  
    感觉是不是有点过长,如果还要考虑文件的依赖关系,整个程序的编译过程将更加困难,有没有什么好的方法解决这个问题呢?
    ### 三、关于make工具
    小明不得不求助导师小度,小度乐道,你可以用make工具呀。那么小度说的make工具是什么呢?
    > 1. make工具可以看成是一个智能的批处理工具,它本身并没有编译和链接的功能,  
    而是用类似于批处理的方式,通过调用 Makefile 文件中用户指定的命令来进行编译和链接的。  
    (Make 工具各类比较多,例如 GNU Make ,QT 的 qmake ,微软的 MS nmake,BSD Make(pmake),Makepp,等等)
    > 2. make 根据 Makefile 中的内容通常可以按以下顺序执行:  
    > a. make 根据 Makefile 中的文件进行gcc编译,并生成相关的可执行文件。  
    > b. make test 执行完make时,可执行文件并没有安装到系统中,通过make test可以检测是否可以正常的安装到系统中。  
    > c. make install 将可执行文件安装到系统中  
    > d. make clear 清除编译过程生成的临时文件  
    > e. make remove 将可执行文件从系统中移除  
    ### 四、关于 Makefile
    1. Makefile 是什么?
    Make可以从一个名为 Makefile 的文件中获得如何构建你所写程序的依赖关系,Makefile中列出了每个目标文件以及如何由其他文件来生成它。
    当你编写一个程序时,你可以为它编写一个 Makefile 文件,这样你就可以使用Make来编译和安装这个程序。
    > Makefile 就像是一个设计图,那编写 Makefile 的人就是设计师,他需要设计gcc应该如何进行编译链接。
    2. Makefile 编写格式
    

target...: prerequisites ...(预备知识,先决条件) command(指令)

> target 也就是一个目标文件,可以是Object File,也可以是执行文件。  
> prerequisites 就是,要生成那个target所需要的文件或是目标。  
> command 也就是make需要执行的命令。(command前端必须带一个tab键,且不能是空格组成的tab)  

3. 一个简单 Makefile 的例子
  * hello.c  
    ```c
    #include <stdio.h>
    #include "world.h"

    int main() {
        say();
        return 0;
    }
    ```
  * world.h
    ```c
    #include <stdio.h>

    int say();
    ```
  * world.c
    ```c
    #include "world.h"

    int say() {
        printf("Hello, World!\n");
        return 0;
    }
    ```
  * Makefile
    ```
    hello: hello.o world.o
    	gcc -o hello hello.o world.o
    hello.o: hello.c
    	gcc -c hello.c
    world.o: world.c world.h
    	gcc -c world.c
    clean:
    	rm hello.exe hello.o world.o
    ```
4. 更好的选择?
小明在小度老师的指定终于完成了程序的 Makefile 编写,并且测试运行正常。
但整整20个文件,还是让小明感觉这活并不太轻松。
小度老师实在看不下去,即对小明说:那我们再来了解下一个神器 CMake 吧!

### 五、关于CMake
1. CMake概述
首先,CMake是一个项目构建工具,类似的工具还有 autotools,它们的目的正是为了产生可移植的makefile,
并简化自己动手写makefile时的巨大工作量。如果你自己动手写过makefile,你会发现,makefile通常依赖于你当前的编译平台,而且编写makefile的工作量比较大,解决依赖关系时也容易出错。因此,对于大多数项目,应当考虑使用更自动化一些的 cmake或者autotools来生成makefile,而不是上来就动手编写。  
详细文档地址: https://www.hahack.com/codes/cmake/

2. 安装与升级
  > cmake升级

cmake --version wget https://github.com/Kitware/CMake/releases/download/v3.15.2/cmake-3.15.2.tar.gz tar -xvf cmake-3.15.2.tar.gz cd cmake-3.15.2 ./configure

 > windows上有类似的版本:https://cmake.org/download/

### 六、关于CMakeLists.txt
安装好了 CMake 后,小明又向小度导师了解到,CMake 在生成 Makefile 文件时,需要一个 CMakeLists.txt 文件。

“抛开 Makefile,我们又要重新去写一个 CMakeLists.txt, 是不是又绕回来了呢?”小明不解的问道。  

“不急,我们先来看看CMakeLists.txt的书写规范”

cmake最低版本需求,不加入此行会受到警告信息

CMAKE_MINIMUM_REQUIRED(VERSION 2.6)

也可以自己指定编译器的路径[可选]

set(CMAKE_C_COMPILER "/usr/bin/gcc")

set(CMAKE_CXX_COMPILER "/usr/bin/g++")

项目名称

PROJECT(HELLO)

把当前目录(.)下所有源代码文件和头文件加入变量SRC_LIST

AUX_SOURCE_DIRECTORY(. SRC_LIST)

如果当前目录下有二级目录需要添加进来[可选]

add_subdirectory(math)

生成应用程序 hello (在windows下会自动生成hello.exe)

ADD_EXECUTABLE(hello ${SRC_LIST})

如果项目需要添加链接库[可选]

target_link_libraries(Demo MathFunctions)

如果只把把项目源文件编译为静态链接库[可选]

add_library (MathFunctions ${DIR_LIB_SRCS})

设置GDB调试支持

set(CMAKE_BUILD_TYPE "Debug") set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb") set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")

指定程序的库的安装路径

install (TARGETS Hello DESTINATION bin) install (FILES world.h DESTINATION include)

> CMakeLists.txt 的书写语法特别简单。与人工书写 Makefile 文件相比,节约了不省时间。

小明按照上面的书写规范,编写了第一个 CMakeLists.txt

$ ls CMakeLists.txt main.c $ mkdir build $ cd build/ $ cmake .. $ make

编译正常通过,程序正常运行,但是在输入一个不规范的参数时,程序错误了,小明不知道具体哪个地方出错了。  
他希望能够有一种类似于其它开发语言的断点调试工作。于是他想到之前学习过的GDB。

### 七、关于GDB
1. 概述  
  一般来说,GDB主要帮助你完成下面四个方面的功能:
  >  a.启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。  
  >  b.可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)  
  >  c.当程序被停住时,可以检查此时你的程序中所发生的事。  
  >  d.你可以改变你的程序,将一个BUG产生的影响修正从而测试其他BUG。  

2. 启用GDB
  启用GDB的方式很简单,在安装好GDB的前提下,使用gcc编译时加入-g则可以生成用于GDB调试的文件。

$ gcc -g -o hello hello.c $ gdb hello ``` 3. gdb具体用法请移步:GDB调试

引用

  1. GNU
    该系统的基本组成包括GNU编译器套装(GCC)、GNU的C库(glibc)、以及GNU核心工具组(coreutils),另外也是GNU除错器(GDB)、GNU二进制实用程序(binutils)的GNU Cashshell中和GNOME桌面环境。

  2. GCC 和 cmake的关系? https://www.zhihu.com/question/36609459

Cmake与make还可以用来编译go语言,更多详情可参考:https://blog.icorer.com/index.php/archives/382/