编译问题讨论--make与cmake已经静态动态链接库
前言
很早之前就接触过makefile的语法,但是没有深入的学习下去。本来以为自己了解这方面的知识了,谁知道最近做项目时,各种形式接连丢过来,我竟是懵了。这才发现自己其实根本没有形成系统的理解,稍微变形就使得我不知所云。想来想去还是写一篇博客吧,把自己的理解梳理一遍,以后如果有更深入、更清晰的理解,我会对这篇博客进行补充,尽量使得自己的知识见解有条理,系统化。
编译过程
首先,拿c语言为例,我们先写出了代码。通过编译器可以利用这些c代码(源文件)生成可执行文件。整个的编译流程可以分成四步:
- 预处理阶段:进行预处理器处理(用实际值替代#define、读入#include指令包含的头文件等);
- 编译阶段:将
.c
文件转换成.s
文件,即将c语言代码转换成汇编语言代码; - 汇编阶段:将
.s
文件转换成.o
文件,即将汇编语言代码转换成机器语言指令; - 链接阶段:最后将各个目标文件由链接器捆绑起来形成单一完整的可执行文件,链接器同时也会引入标准c函数库中任何被该程序用到的函数。
我在网上看到一张图,对于整个编译流程归纳的特别详细:
假设生成可执行文件excute
在当前目录下,我们可以通过如下shell命令将excute
载入内存执行。
./excute
一般情况下,当输入一条命令,shell会检测第一个单词是不是一个内置的shell命令,如果不是就会把它当成一个可执行文件的名字,并加载运行这个可执行文件。
gcc编译方式(bash)
编译main.c
、1.c
、1.h
,生成可执行文件excute
gcc -o excute main.c 1.c 1.h
注1:如果不-o
指定生成excute
,将默认生成a.out
。
注2:如果源文件不止一个,第二步产生的.o
文件将会保留,以待重新编译只编译改动过的代码。
make与cmake
由上,我们知道了整个编译过程,但是如果一个项目很大,使用上述方式输入命令,似乎就很不灵活了。于是产生了make工具,它是一个自动化编译工具,规定好编译规则(Makefile),一条命令make
,便能将整个工程编译完毕。
对于一个合格的程序员来说,编写Makefile是必备技能。
但是对于一个很大的项目,自己编写Makefile无疑是一件及其吃力的事情。于是又出现了cmake,它可以读入所有源文件后,自动生成Makefile文件。当然,cmake也有自己的规则文件(CmakeLists.txt)。不过比较而言,编写CmakeLists.txt
却是简单多了。
一般只需要输入cmake
,整个项目会自动编译完成。cmake时大体流程如下:
`cmake(CmakeLists.txt) --> Makefile`
`make(Makefile) --> 编译完成`
注:make一般在windows下效果不好,camke跨平台比较常见
make选项
我们也会经常看到make install
、make distribute
等形式,这些都是什么意思呢?
make install
:有些程序需要源码安装,make
install在编译完程序源码后,会接着往系统写入一些配置,完成程序安装。
make distribute
:感觉应该是使当前项目可以被外部项目依赖?
大工程 make 编译流程
./configure
make
make install
一般会是如上的顺序进行大工程的编译(c与c++)。
configure脚本:这个脚本的作用有获取编译参数(当前的系统环境,比如标准库在哪里、软件的安装位置在哪里、需要安装哪些组件);确定标准库与头文件的位置;确定依赖关系,生成makefile;
make:编译;
make install:将编译器在内存中生成的可执行文件保存到用户事先指定的安装目录(创建目录、保存文件、设置权限等,并告知操作系统,即在操作系统中,登记这个程序的元数据:文件名、文件描述、关联后缀名等等。Linux系统中,这些信息通常保存在/usr/share/applications目录下的.desktop文件中。)
动态连接与静态连接
开发者可以在编译阶段选择可执行文件连接外部函数库的方式,到底是静态连接(编译时连接),还是动态连接(运行时连接)。所以,最后还要提一下,什么叫做动态连接。
静态连接就是把外部函数库,拷贝到可执行文件中。所以在编译链接完成后,就不需要静态库文件了。 - 好处是,适用范围比较广,不用担心用户机器后来删掉某个库文件; - 缺点是安装包会比较大,而且多个应用程序之间,无法共享库文件;并且在链接时如果静态链接库之间存在依赖关系,需要考虑链接顺序问题。
动态连接的做法正好相反,外部函数库不进入安装包,只在运行时动态引用。在运行可执行文件时,动态库文件必须存在于指定的位置,否则出错。 - 好处是安装包会比较小,多个应用程序可以共享库文件; - 缺点是用户必须事先安装好库文件,而且版本和安装位置都必须符合要求,否则就不能正常运行。
现实中,大部分软件采用动态连接,共享库文件。这种动态共享的库文件,Linux平台是后缀名为.so的文件,Windows平台是.dll文件,Mac平台是.dylib文件。