1. 什么是开放源码、编译程序与可执行文件
我们使用特定编程语言(如C或Java等),编写的纯文本文件即为源码文件。在完成源码文件的编写之后,再通过编译程序将源码文件编译成操作系统看得懂的二进制可执行文件。
在Linux上最标准的程序语言为C,所以我们使用C语法写完源码(以*.c扩展名形式存在)后,以Linux上标准C语言的编译程序gcc这个程序来编译,就可以制作一个可执行的二进制程序。
事实上,在编译过程中还会生成目标文件(以*.o扩展名形式存在)。此外,有时候,我们会在程序当中调用其他的外部子程序,或者是利用其他软件提供的函数功能,这个时候,我们就必须在编译的过程当中将该函数库加进去。如此一来,编译程序就可以将所有的程序代码与函数库做一个链接以生成正确的可执行文件。
2. 使用传统程序语言进行编译
- 单源码文件制作可执行文件:
// 比如我们用C编写一个hello.c的源代码,期望输出Hello World!
vim hello.c
// 我们可以用gcc编译,可执行文件的文件名默认是a
gcc hello.c
// 执行
./a.out
- 多源码文件利用目标文件制作可执行文件:
由于源码文件有时候并非只有一个,所以我们无法直接进行编译。这个时候就需要先生成目标文件,然后再以链接制作成为二进制可执行文件。
// 通过-c参数编译目标文件。-O参数为生成优化
gcc [-O] -c thanks_1.c thanks_2.c
// 此时目录里多了thanks_1.o和thanks_2.o两个目标文件
// 进行链接成为可执行文件,通过-o参数指定生成的可执行文件名。-Wall参数可产生更多的编译过程信息
gcc [-Wall] -o thanks thanks_1.o thanks_2.o
// 然后就可以执行了
./thanks
-
加入外部函数库
// 若上面的代码使用到了三角函数sin,那么在生成可执行文件时,要链入函数库
gcc [-Wall] -o thanks thanks_1.o thanks_2.o -lm [-L/lib -L/usr/lib -I/usr/include]
// -l:是加入某个函数库的意思
// m:则是libm.so这个函数库,其中,lib与扩展名(.a或.so)不需要写
// 所以-lm表示使用libm.so(或libm.a)函数库的意思。
// -L:后面接的路径是函数库搜索目录。上面是Linux默认函数库目录,可以不写
// -I:后面接的路径是源码内的include文件的所在目录。上面是Linux默认include目录,可以不写
### 3. 用make进行宏编译
* 为什么要用make
假设有4个源码文件,分别是main.c、haha.c、sin_value.c和cos_value.c。按照上面的方式,我们得这么做:
// 1. 先进行编译目标文件,最终会有4个.o的文件出现
gcc -c main.c
gcc -c haha.c
gcc -c sin_value.c
gcc -c cos_value.c
// 2. 再链接成为可执行文件,并加入libm数学函数,以生成main可执行文件
gcc -o main main.o haha.o sin_value.o cos_value.o -lm -L/usr/liba -L/lib
// 3. 运行文件
./main
> 一套软件通常有一堆程序代码文件,使用gcc来编译的过程并不简单。可以使用make进行编译过程的简化。
执行make时,会在当前目录下搜索Makefile文件,Makefile文件记录了源码如何编译的详细信息。通常软件开发商会在软件包里提供configure(或config)文件,用以检测用户的操作系统环境是否满足条件。
所以,你要进行的任务只有两个,先执行./configure生成Makefile,再执行make编译。
* 尝试使用make
vi makefile
// 1. 先编辑makefile规则文件,内容只要制作出main这个可执行文件
main: main.o haha.o sin_value.o cos_value.o
gcc -o main main.o haha.o sin_value.o cos_value.o -lm
// 注意第二行的gcc之前是<tab>键生成的空格
// 2. 使用makefile规则文件进行编译
rm -f main *.o <==现将之前的目标文件移除
make
* makefile的基本语法与变量
目标: 目标文件1 目标文件2...
<tab> gcc -o 预新建的可执行文件 目标文件1 目标文件2
以刚才上一个范例进一步说明,我们也可以有两个以上的操作:
vi makefile
main: main.o haha.o sin_value.o cos_value.o
gcc -o main main.o haha.o sin_value.o cos_value.o -lm
clean:
rm -f main main.o hah.o sin_value.o cos_value.o
如此一来,makefile就具有两个目标,如果想要清除,输入make clean,如果想要建立main,输入make main。如果想要先清除再生成main,则输入make clean main
* 用变量简化makefile
vi makefile
LIBS = -lm
OBJS = main.o haha.o sin_value.o cos_value.o
main: ${OBJS}
gcc -o main ${OBJS} ${LIBS}
clean:
rm -f main ${OBJS}
* Tarball软件安装的步骤
1. ./configure --prefix=/usr/local/apache
这个步骤就是建立makefile文件。这个步骤的相关信息应该要参考一下同目录下的README或INSTALL文件。configure比较重要的参数是--prefix,表示软件最终安装的目录,如果没有指定,默认为/usr/local。可以只用./configure --help查看有哪些参数。
2. make clean
清理目标文件。因为谁也不知道源码里是否包含上次编译过的目标文件(*.o)存在。
3. make
make会依据makefile当中的默认工作进行编译的行为。主要是进行gcc来将源码编译成可执行文件,通常还需要一些函数库的链接。可执行文件放置在当前目录下。
4. make install
最后的安装步骤,依据makefile里关于install的选项,将数据安装到默认的目录中,就完成了。
* Tarball软件安装建议
通常建议把软件安装在/usr/local/software下,源码则放在/usr/local/src下。
例如,我们将apache安装在/usr/local/apache当中,那么你的目录会变成:
/usr/local/apache/etc
/usr/local/apache/bin
/usr/local/apache/lib
/usr/local/apache/man
为避免每次使用绝对路径执行的麻烦,可以将/usr/local/apache/bin加入PATH里。
另外/usr/local/apache/man也需要加入man page搜索路径中去。
/etc/man.config内的40~50行左右写入如下一行:
MANPATH/usr/local/apache/man
### 4. 增加函数库的读取性能
> 函数库分为静态和动态函数库,静态函数库在编译的时候直接整合到执行程序中,所以最终文件会比较大些,若函数库升级,整个可执行文件必须重新编译才能整合新版函数库。
动态函数库,没有别整合到可执行文件里,当可执行文件使用到函数库时,程序才会去读取函数库使用。Linux大多是将函数库做成动态函数库。
* 增加函数库读取性能
比如mysql的函数库在/usr/lib/mysql位置,我可以这么做:
vi /etc/ld.so.conf
include ld.so.conf.d/*.conf
/usr/lib/mysql <==这一行新增的
// 将/etc/ld.so.conf的数据读入缓存当中,同时也将数据记录一份在/etc/ld.so.cache文件中
idconfig
// 列出目前所有函数库数据内容(/etc/ld.so.cache内的数据)
ldconfig -p
* 解析程序依赖的动态函数库
// -v选项,增加显示其他版本信息
ldd [-v] /usr/bin/passwd
### 5. 校验软件正确性
软件下载站,一般提供了软件的md5或sha1指纹码,可以用以下方式校验是否被修改过:
* 对比指纹
// 将结果与网站的指纹码比对,一致则未被他人修改
md5sum CentOS-5.3-i386-netinstall.iso sha1sum CentOS-5.3-i386-netinstall.iso
我们可以利用这个机制,为Linux系统上一些重要的文件创建指纹数据库,比如下面这些文件:
/etc/passwd
/etc/shadow(假如你不让用户改密码了)
/etc/group
/usr/bin/passwd
/sbin/portmap
/bin/login(这个也很容易被黑客利用)
/bin/ls
/bin/ps
/usr/bin/top
使用md5sum检查一次,将指纹记录下来,然后经常以shell script方式由程序自行检查指纹是否一致。