文章目录
Linux思维导图
手动编译对比rpm安装
- 手动编译功能是可选,比如我们业务需要整个功能,但是整个软件没有,我们可以修改源代码
- 用rpm因为已经编译好了,所以功能是不可选的。
- 源码编译安装还可以指定目录
源码编译过程图解
以C语言为例,一个.c的源文件,经过预处理器和编译器处理生成目标代码后,再通过编译器把代码编译成二进制代码,但是一个大型的文件里面,可能不止一个.c文件,这些.c文件之间一般是有关联的,或者说要调用其他代码的库函数,所以要经过一个步骤叫做链接,一般是要经过链接的哈,链接又分为静态和动态。但是静态链接呢,可能会导致我们的文件变大,所以一些经常要使用的函数,我们把它做成库文件。
编译的三个步骤详解
./configue完成的步骤:
编译过程分析
1. 源码
例如:
#include <stdio.h>
int main(void)
{
printf("Hello, world!\n");
return 0;
}
2. 按照编译工具
yum install gcc make
简单的代码可以不通过./configue,make,make install,直接用gcc就行,但是一些比较大型的项目代码,他可能调用很多外部的库等等,那么如果手动的去编译,要自己去做链接,你知道怎么去做链接吗,不知道对不对,所以Linux为我们提供了一套自动编译的工具make,它工作前需要先运行一下./configue生成Makefile这个文件,是在./configue的是时候完成的
3. 配置
编译器在开始工作之前,需要知道当前的系统环境,比如标准库在哪里、软件的安装位置在哪里、需要安装哪些组件等等。这是因为不同计算机的系统环境不一样,通过指定编译参数,编译器就可以灵活适应环境,编译出各种环境都能运行的机器码。这个确定编译参数的步骤,就叫做"配置"(configure)。
如:
./configure --prefix=/usr/local/nginx --with-http_ssl_module
–with参数是启用这个功能,–without参数时不启用这个功能。
4. 确定标准库和头文件的位置
源码肯定会用到标准库函数(standard library)和头文件(header)。它们可以存放在系统的任意目录中,比如我们经常用的<stdio.h>,编译器实际上没办法自动检测它们的位置,只有通过配置文件才能知道。
5. 确定依赖关系
对于大型项目来说,源码文件之间往往存在依赖关系,编译器需要确定编译的先后顺序。假定A文件依赖于B文件,编译器应该保证做到下面两点。
- 只有在B文件编译完成后,才开始编译A文件。
- 当B文件发生变化时,A文件会被重新编译。
6.头文件的预编译
不同的源码文件,可能引用同一个头文件(比如stdio.h)。编译的时候,头文件也必须一起编译。为了节省时间,编译器会在编译源码之前,先编译头文件。这保证了头文件只需编译一次,不必每次用到的时候,都重新编译了。
7.编译(Compilation)
预处理之后,编译器就开始生成机器码。对于某些编译器来说,还存在一个中间步骤,会先把源码转为汇编码(assembly),这种文件称为对象文件object file(对象文件),然后再把汇编码转为机器码。
例子(汇编语言)
.file "test.c"
.section .rodata
.LC0:
.string "Hello, world!\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq stdout(%rip), %rax
movq %rax, %rcx
movl $14, %edx
movl $1, %esi
movl $.LC0, %edi
call fwrite
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Debian 4.9.1-19) 4.9.1"
.section .note.GNU-stack,"",@progbits
8.链接
- 对象文件还不能运行,必须进一步转成可执行文件。如果你仔细看上一步的转码结果,会发现其中引用了stdout函数和fwrite函数。也就是说,程序要正常运行,除了上面的代码以外,还必须有stdout和fwrite这两个函数的代码,它们是由C语言的标准库提供的。这个标准库一般情况下时默认安装的。
- 编译器的下一步工作,就是把外部函数的代码(通常是后缀名为.lib和.a的文件),添加到可执行文件中。这就叫做连接(linking)。这种通过拷贝,将外部函数库添加到可执行文件的方式,叫做静态连接(static linking),还有动态连接(dynamic linking)。
- 动态链接:前面已经说过,静态连接就是把外部函数库,直接拷贝到可执行文件中。这样做的好处是,适用范围比较广,不用担心用户机器缺少某个库文件;缺点是安装包会比较大,而且多个应用程序之间,无法共享库文件。动态连接的做法正好相反,外部函数库不进入安装包,只在运行时动态引用。好处是安装包会比较小,多个应用程序可以共享库文件;缺点是用户必须事先安装好库文件,而且版本和安装位置都必须符合要求,否则就不能正常运行。
9.安装
上一步的链接是在内存中进行的,即编译器在内存中生成了可执行文件。下一步,必须将可执行文件保存到用户事先指定的安装目录。
10.(动态连接)
- 正常情况下,到这一步,程序已经可以运行了。至于运行期间(runtime)发生的事情,与编译器一概无关。但是,开发者可以在编译阶段选择可执行文件连接外部函数库的方式,到底是静态连接(编译时连接),还是动态连接(运行时连接)。
- 前面已经说过,静态连接就是把外部函数库,直接拷贝到可执行文件中。这样做的好处是,适用范围比较广,不用担心用户机器缺少某个库文件;缺点是安装包会比较大,而且多个应用程序之间,无法共享库文件。动态连接的做法正好相反,外部函数库不进入安装包,只在运行时动态引用。好处是安装包会比较小,多个应用程序可以共享库文件;缺点是用户必须事先安装好库文件,而且版本和安装位置都必须符合要求,否则就不能正常运行。
源码编译安装过程经常会遇到的问题
- 源码编译安装最常出现的问题是报错说缺乏了一些库,缺乏的库我们可以根据他的提示,知道缺的软件包是什么,少什么就装什么喽,但是我们要注意的是在装的时候,在软件包后面加上-devel(也就是development的缩写)
- 使用yum安装的时候,有时也会遇到,我们想装什么包,它就是装不了,就是装不上,那么这一般是gcc编译器版本的问题,卸到原先的gcc编译器,按照它的要求重新下一个
鸟哥Linux私房菜的笔记
什么是函数库
- 函数库:就是类似于子程序的角色,说可以用来执行特定功能的一段功能函数
- 举个例子:就像是pam认证模块,这个pam提供的功能可以让程序在执行的时候,验证用户的信息,那么如此一来,我就不用去编写一个验证用户信息的功能,直接调用就行
什么说make与configure
- make:当执行make的时候,make会在当前目录下面搜索Makefile这个文件,而makefile里面记录了源代码如何编译的详细信息,make会自动判断源代码是否经过变动,而自动更新执行文件
- ./configure:那makefile说是怎么来的呢,通常,软件发行厂商会写一个检测程序,这个检测程序的文件名就叫configure,大概会检测的内容有:是否有合适的编译器,是否有软件所依赖的函数库,操作平台是否适合本软件,内核的头文件是否存在等。
更多具体内容:参考《鸟哥的Linux私房菜》