一、关于编译器
小明一个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
- gcc在执行编译工作的时候,总共需要4步:
a. 预处理,生成 .i 的文件[预处理器cpp]
b. 将预处理后的文件不转换成汇编语言, 生成文件 .s [编译器egcs]
c. 由汇编变为目标代码(机器代码)生成 .o 的文件[汇编器as]
d. 连接目标代码, 生成可执行程序 [链接器ld]
- 常用命令:
a. -x 指定编译的语言
b. -c 执行(1、2、3),不执行4,生成 .o 的 obj 文件,gcc默认执行(1、2、3、4)生成可执行文件
c. -o 批量输出文件
d. -g 创建符号表,符号表包含了程序中使用的变量名称的列表,同时关闭所有的优化机制,以便程序执行过程中严格按照原来的C代码进行。主要用于gdb调试。
- gcc在执行编译工作的时候,总共需要4步:
写完第一个程序后,小明想来点有挑战的,他一口气写了一个包含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调试
引用
GNU
该系统的基本组成包括GNU编译器套装(GCC)、GNU的C库(glibc)、以及GNU核心工具组(coreutils),另外也是GNU除错器(GDB)、GNU二进制实用程序(binutils)的GNU Cashshell中和GNOME桌面环境。GCC 和 cmake的关系? https://www.zhihu.com/question/36609459
Cmake与make还可以用来编译go语言,更多详情可参考:https://blog.icorer.com/index.php/archives/382/