了解:如何将开放源码的程序设计、加入函数库的原理、通过编译而成为可执行的二进制程序,最后该文件可被我们所使用的一连串过程。
这一章介绍最原始的软件管理方式,使用Tarball来安装与升级管理我们的软件。
Windows中无法修改该软件的源代码,如果想增加或者减少软件的某些功能时,只能求助于发行该软件的厂商。
如果能提前修补软件中的漏洞,就不用等到软件开发商提供修补程序包。提早补洞是很重要的一件事。
Linux上的软件几乎都是经过GPL授权,所以每个软件几乎均提供源代码,可以自行修改程序代码,定制自己的软件。
Linux系统上的可执行文件,是指:首先针对该文件具有可执行的权限,另外它应该是二进制文件。
[root@study ~]$ file /bin/bash 如果是二进制文件,那么就会显示ELF 64-bit LSB executable
/bin/bash: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=7e644dee920bc3ba797c38e05383286563712b49, stripped
[root@study ~]$ file /etc/init.d/network 如果不是二进制文件,而是脚本,就会显示ASCII text executable
/etc/init.d/network: Bourne-Again shell script, ASCII text executable
Linux上面最标准的程序语言为C,所以使用C的语法进行源代码编写,写完后,以Linux上标准的C语言编译器gcc这个程序来编译,可以制作一个可以执行的二进制程序。
编译过程会产生目标文件(.o),C语言的源代码一般是(.c)文件。有时候我们会在程序中引用、调用 其他的外部子程序,或是利用其他软件提供的函数功能,这时候,就必须在编译过程中,将该函数库加进去,这样,编译器就可以将所有的程序代码与函数库作一个链接以产生正确的执行文件。
Linux内核提供很多函数库给开发者们调用。
函数库分为动态函数库和静态函数库。
函数库就是类似子程序的角色,可以被调用来执行一段功能函数。
每个主程序与子程序都需要写上一条编译过程的命令,除此之外,还要写上最终的链接程序。程序代码短还好,如果非常大,编译命令会非常非常多,这时候可以利用make
这个命令的相关功能来进行编译过程的简化。
使用make时,make会在当前的目录下查找Makefile(或makefile)这个文本文件,而Makefile里面记录了源代码如何编译的详细信息。make会自动判别源代码是否经过变动了,而自动更新执行文件,是有力工具!
一般软件开发商会写一个检测程序来检测用户的操作环境,以及该操作环境是否具有软件开发商需要的其他功能。该检测软件检测完毕后,会主动地建立这个Makefile的规则文件,通常这个检测程序的文件名为configure或是config。
一般检测的内容包括:
我们要做的只有两件事:
将源代码这种纯文本文件压缩后,得到的就是Tarball的软件。
这样能够利用打包与压缩技术,将文件的数量和容量减小,既方便用户下载,也能节省软件开发商的网站带宽。
Tarball文件一般是将所有的源代码文件,先以tar打包,再以压缩技术来压缩,通常最常见的是以gzip来压缩。利用了tar和gzip的功能,Tarball文件的一半扩展名就是.tar.gz
或.tgz
。近期bzip2和xz的压缩率较优,Tarball也会以bzip2和xz的压缩技术来替换gzip,因此文件名也会变成.tar.bz2
、.tar.xz
之类的。
解压缩后Tarball里包括:
参考INSTALL或README进行软件安装,很简单。
gcc
进行源代码的编译(会产生目标文件object files)gcc
进行函数库、主、子程序的链接,以形成主要的二进制文件3和4两步可以通过make命令的功能简化它。
要求你的Linux系统里至少要安装有gcc
和make
两个软件。
[root@study ~]$ vim hello.c 首先,编写hello.c源代码
[root@study ~]$ cat hello.c
#include
int main(){
printf("Hello World\n");
}
[root@study ~]$ gcc hello.c 直接编译,产生一个a.out文件
[root@study ~]$ ll hello.c a.out
-rwxr-xr-x. 1 root root 8360 Jun 18 14:28 a.out
-rw-r--r--. 1 root root 58 Jun 18 14:28 hello.c
[root@study ~]$ ./a.out 这个a.out文件是可执行文件
Hello World
如果希望一步一步生成,同时能指定可执行文件的名称:
[root@study ~]$ gcc -c hello.c 首先产生目标文件.o文件
[root@study ~]$ ll hello*
-rw-r--r--. 1 root root 58 Jun 18 14:28 hello.c
-rw-r--r--. 1 root root 1496 Jun 18 14:29 hello.o <======这里可以看到,已经产生了
[root@study ~]$ gcc -o hello hello.o 根据目标文件生成可执行文件,起名hello
[root@study ~]$ ll hello*
-rwxr-xr-x. 1 root root 8360 Jun 18 14:30 hello <======这里可以看到,已经产生了
-rw-r--r--. 1 root root 58 Jun 18 14:28 hello.c
-rw-r--r--. 1 root root 1496 Jun 18 14:29 hello.o
[root@study ~]$ ./hello
Hello World
[root@study ~]$ vim thanks.c 主程序
[root@study ~]$ cat thanks.c
#include
int main(){
printf("Hello World\n" );
thanks_2();
}
[root@study ~]$ vim thanks_2.c 子程序
[root@study ~]$ cat thanks_2.c
#include
void thanks_2(){
printf("Thank you!\n");
}
[root@study ~]$ gcc -c thanks.c thanks_2.c 指定需要针对哪几个源代码生成目标文件
[root@study ~]$ ll thanks*
-rw-r--r--. 1 root root 62 Jun 18 14:39 thanks_2.c
-rw-r--r--. 1 root root 1504 Jun 18 14:39 thanks_2.o<======这里可以看到,已经产生了
-rw-r--r--. 1 root root 72 Jun 18 14:39 thanks.c
-rw-r--r--. 1 root root 1560 Jun 18 14:39 thanks.o<======这里可以看到,已经产生了
[root@study ~]$ gcc -o thanks thanks.o thanks_2.o 将两个目标文件一起链接到一个可执行文件中
[root@study ~]$ ll thanks*
-rwxr-xr-x. 1 root root 8424 Jun 18 14:40 thanks<======这里可以看到,已经产生了
-rw-r--r--. 1 root root 62 Jun 18 14:39 thanks_2.c
-rw-r--r--. 1 root root 1504 Jun 18 14:39 thanks_2.o
-rw-r--r--. 1 root root 72 Jun 18 14:39 thanks.c
-rw-r--r--. 1 root root 1560 Jun 18 14:39 thanks.o
[root@study ~]$ ./thanks 执行这个可执行文件
Hello World
Thank you!
如果哪天你更新了thanks_2.c
的内容,只需要重新编译thanks_2.c
这个文件内容产生thanks_2.o
,再拿着生成的目标文件去重新链接出一个新的可执行文件即可。
一般编译过程很耗时,这样的机制就可以节省大量的时间。
[root@study ~]$ gcc -O -c thanks.c thanks_2.c 加上-O能产生最佳化的参数
[root@study ~]$ gcc -Wall -c thanks.c thanks_2.c 加上-Wall能产生跟详细的编译过程信息
thanks.c: In function ‘main’:
thanks.c:4:2: warning: implicit declaration of function ‘thanks_2’ [-Wimplicit-function-declaration]
thanks_2();
^
thanks.c:5:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
[root@study ~]$ vim sin.c 编写源代码
[root@study ~]$ cat sin.c
#include
#include 其中要用到某个库
int main(){
float value;
value=sin(3.14/2);
printf("%f\n",value);
}
[root@study ~]$ gcc sin.c 直接编译,可以的!
[root@study ~]$ gcc sin.c -lm -L/lib -L/lib64 将库链接过来编译,也可以的!
[root@study ~]$ gcc sin.c -lm -I/usr/include 指定include文件的放置位置
-l
:加入某个函数库library的意思。
m
:是指libm.so
或libm.a
这个函数库。其中lib与扩展名不需要写。
Linux默认将函数库放置在/lib
和/lib64
中,所以就算没写-L/lib -L/lib64
也没关系。如果哪天你用的函数库不是放在这两个目录下,那么-L/path
就很重要了,否则找不到函数库。
Linux的include文件放置位置一般是/usr/include/
中。
-I/path
:后面接的路径就是设置要去查找相关的include文件的目录。
gcc是Linux上最标准的编译器,是由GNU计划所维护的。
gcc -c hello.c 仅将源代码编译成目标文件
gcc -O hello.c -c 会自动产生hello.o这个文件,但是并不会产生二进制执行文件;-O根据操作环境给予最佳化执行速度
gcc sin.c -lm -L/lib -I/usr/include 在尽心二进制文件制作时,将链接的函数库与相关的路径加入
gcc -o hello hello.c 将编译的结果输出成某个特定文件名
gcc -o hello hello.c -Wall 加入-Wall后,程序编译会变得更为严谨,警告信息也会显示出来
vim makefile 文件内容如下:
main:main.o haha.o sin_value.o cos_value.o 指出这个main需要4个目标文件
gcc -o main main.o haha.o sin_value.o cos_value.o -lm 执行链接操作
make的优点:
目标(target):目标文件1 目标文件2 ...
<tab> gcc -o 欲建立的执行文件 目标文件1 目标文件2 ...
clean:
rm -f 目标 目标文件1 目标文件2 ...
:
隔开makefile
中具有至少两个目标,分别是main
和clean
。执行make clean
,通过make
以clean
为目标;想要建立main
,输入make main
;如果想先清除再建立,输入make clean main
使用变量进一步简化makefile:
vi makefile
LIBS = -lm
OBJS = main.o haha.o sin.o cos.o
CFLAGS = -Wall
main:${OBJS}
gcc -o main ${OBJS} ${LIBS}
clean:
rm -f main ${OBJS}
变量的基本语法:
${变量}
或$(变量)
使用环境变量既可以定义在文件内,也可以在命令行当场定义,到底以哪个为主?牵扯到环境变量的使用规则:
$@
代表目前的目标(target)上述代码可以把main换成$@:
vi makefile
LIBS = -lm
OBJS = main.o haha.o sin.o cos.o
CFLAGS = -Wall
main:${OBJS}
gcc -o $@ ${OBJS} ${LIBS} 这里可以把main换成$@
clean:
rm -f $@ ${OBJS} 这里可以把main换成$@
如何使用具有源代码的Tarball来建立一个属于自己的软件?
Tarball的安装是可以跨平台的,因为C语言的程序代码在各个平台上是可以通用的,只是需要的编译器可能不同。
GNU的gcc是Linux上首选的自由软件编译器。
为了简化编译流程,配合make命令根据文件的依赖性进行编译。但是make需要makefile的文件规则,不同系统里的基础软件环境可能不相同,所以需要检测用户的操作环境,好自行建立一个makefile文件。这个自行检测的小程序也必须要借由autoconfig
这个相关软件来辅助才行。
需要内核提供的Library
以及相关的include
文件。很多软件直接使用操作系统内核提供的函数库和include文件,这样才可以与这个操作系统兼容。尤其是驱动程序方面的模块。在RedHat系统中,内核的相关功能通常被包含在kernel-source
或kernel-header
软件中。
安装CentOS
或者RedHat
过程中应选择Development tools
和kernel source development
等相关的软件包,这样才能默认安装gcc
和make
等软件。
安装系统过程中如果没有选择上述选项,可以通过其他方式安装gcc和make。
如果么有网络,可以通过RPM安装;
如果有网络,可以用YUM安装:
yum groupinstall "Development Tools"
yum groupinstall "X Software Development"
yum groupinstall "Legacy Software Development"
先将Tarball解压缩,然后到源代码所在的目录下进行makefile的建立,再以make来进行编译与安装:
/usr/local/src
目录下解压缩;INSTALL
和README
等相关文件内容(很重要!!!);INSTALL/README
的内容查看并安装好一些依赖的软件(非必要);makefile
:以自动检测程序(config
或configure
)检测操作环境,并建立Makefile这个文件;make
这个工具,并使用该目录下的Makefile
作为他的参数配置文件,来进行make
的操作;make
这个程序,并以Makefile
这个参数配置文件,根据install
这个目标(target
)的指定来安装到正确的路径。大部分的Tarball软件安装的命令执行方式:
./configure
make clean
make
make install
以上步骤只要有一个失败,后续的都会失败。如果安装成功,需要手动将软件的man page写入/etc/man_db.conf
中。
Tarball要在/usr/local/src
里面解压缩,因为
/usr
里面/usr/local
里面/usr/local/man
里面与info和man的功能有关,默认情况下,man会去查找/usr/local/man
里的说明文件。
将Apache安装好后,应该安装在以下文件夹中:
/usr/local/apache/etc
/usr/local/apache/bin
/usr/local/apache/lib
/usr/local/apache/man
这样,删除该目录/usr/local/apache
就可视为删除了Apache软件。具体为rm -f /usr/local/apache
。
安装完成后,需要将路径加入该加入的位置:
/usr/local/apache/bin
加入PATH里面/usr/local/apache/man
加入man page查找的路径中安装Tarball时:
/usr/local/src
中/usr/local
这个默认路径下/usr/local
下面/etc/man_db.conf
内的40-50行左右写下如下一行:MANPATH_MAP /usr/local/software/bin /usr/local/software/man
从实用角度来说,一般不太会用到Tarball安装,除非要安装的软件是专属软件(要钱的)或者是比较冷门的软件,否则在RMP的补充计划EPEL中,一般常用软件都已经被打包好了。
cd /usr/local/src
tar -zxvf /root/ntp-4.2.8p3.tar.gz
cd ntp-4.2.8p3
vi INSTALL
./configure --help | more
./configure --prefix=/usr/local/ntp --enable-all-clocks --enable-parse-clocks 开始建立Makefile
make clean;make
make check
make install
tar -zxvf main-0.1.tar
cd main-0.1
make clean main
./main
patch -p 数字 < patch_file 此处应格外注意 -p 数字,表示拿掉几个斜线/的意思
patch -p1 < ../main_0.1_to_0.2.patch 目前所在目录实在main-0.1下面,注意与patch文件的相对路径
make clean main
./main
make install 将它安装至/usr/local/bin
main 直接输入命令执行此程序
make uninstall 删除此软件
只需要下载patch文件就能将你现有的软件源代码更新了,但是更新源代码后不代表软件已经完成更新,所以还要将该软件编译后,采食最终正确的软件,因为patch的功能主要只是更新源代码文件而已,切记。
如果patch过程出错,想要还原:
patch -R < ../main_0.1_to_0.2.patch
函数库很重要,用于身份验证的函数库PAM、用于网络连接加密机制的函数库SSL等。
函数库依照是否被编译到程序内部分为动态、静态函数库。
静态函数库特点:
libxxx.a
动态库特点:
/lib64
和/lib
目录中。很多函数库内核就提供了。内核的函数库是放在/lib/modules
中的。不同版本的内核提供的函数库差异性挺大的,所以kernel2.4.xx版本的系统不要想将内核换成2.6.xx版本,很容易由于函数库的不同而导致很多原本可以执行的软件无法顺利运行。如何增强函数库的读取性能?
因为内存的访问速度是硬盘的好多倍,如果将常用的动态函数库加载到内存当中(缓存,cache),如此一来,当软件要使用动态函数库时,就不需要从头由硬盘里读出,这样就能提高动态函数库的读取速度了。
如何将函数库加载到内存?
/etc/ld.so.conf
里写入想要读入高速缓存当中的动态函数库所在的目录,是目录,不是文件;ldconfig
这个执行文件将/etc/ld.so.conf
的数据读入缓存中;/etc/ld.so.cache
这个文件中。ldconfig [-f conf] [-C cache]
ldconfig [-p]
-f conf 那个conf指的是某个文件名称,也就是说使用conf作为libarary函数库的获取路径,而不以/etc/ld.so.cache为默认值
-C cache 那个cache指的是某个文件名称,也就是说使用cache作为高速缓存的函数库数据,而不以/etc/ld.so.cache为默认值
-p 列出目前所有函数库数据内容(在/etc/ld.so.cache内的数据)
MariaDB数据库函数库在/usr/lib64/mysql
中,如何读入cache:
vim /etc/ld.so.conf.d/vbird.conf
新增:/usr/lib64/mysql
ldconfig
ldconfig -p
这样就完成了将MariaDB的相关函数库读入缓存当中,这样可以提高函数库读取的效率。
某些时候,你可能会自行加入某些Tarball
安装的动态函数库,若想要让这些动态函数库的相关链接可以被读入到缓存当中,这时候你可以将动态函数库所在的目录名称写入/etc/ld.so.conf.d/yourfile.conf
当中,然后执行/ldconfig
就可以。
如何判断某个可执行的二进制文件含有什么动态函数库?
ldd [-vdr] [filename]
-v 列出所有内容信息
-d 重新将数据有遗失的链接点显示出来
-r 将ELF有关的错误内容显示出来
找出/usr/bin/passwd这个文件的函数库信息:
ldd /usr/bin/passwd
ldd -v /lib64/libc.so.6 找出这个函数的相关函数库
md5sum
sha1sum
sha256sum
md5sum ntp-4.2.8p3.tar.gz 检验刚刚下载的这个文件,看看校验值
可以对重要文件创建校验值,每天比对,防止被木马入侵:
1 建立重要文件的文件名列表important.file
ls /etc/{passwd,shadow,group} > important.file
find /usr/bin /usr/bin -perm /6000 >> important.file
2 通过这个文件名列表,以名为md5.checkfile.sh的文件名去建立校验值,并将校验值文件finger1.file设置为不可修改的属性:
vim md5.checkfile.sh
文件内容:
#!/bin/bash
for filename in $(cat important.file)
do
md5sum $filename >> finger1.file
done
运行文件:
sh md5.checkfile.sh
设置不可修改:
chattr +i finger1.file
3 通过相同的机制建立后续的分析数据为finger_new.file,并将两者对比,若有问题,发送email给root
vim md5.checkfile.sh
文件内容:
#!/bin/bash
if [ "$1" == "new" ];then
for filename in $(cat important.file)
do
md5sum $filename >> finger1.file
done
echo "New file finger1.file is created."
exit 0;
fi
if [ ! -f finger1.file ];then
echo "file: finger1.file NOT exist."
exit 1
fi
[ -f finger new.file ] && rm finger_new.file
for filename in $(cat important.file)
do
md5sum $filename >> finger_new.file
done
testing=$(diff finger1.file finger_new.file)
if [ "$testing" != "" ];then
diff finger1.file finger_new.file | mail -s 'finger trouble..' root
fi
让这个文件定期执行(每天执行一次):
vim /etc/crontab
30 2 * * * root cd /root; sh md5.checkfile.sh
如果是正常的系统升级,升级后应该删掉原来的finger1.file,重新建立一个finger1.file,否则总会收到邮件。