8.1.1 编译、安装、打印HelloWorld程序

本节将带领大家完成从源代码编写到源码编译,再到程序安装的过程,希望通过该过程的学习,能让大家了解源码编译安装的原理。由于几乎所有的开源程序使用的都是C语言,所以这里也使用C语言来演示如何编写、编译、安装一个打印“Hello,world!”程序。

首先,根据软件需求写出源代码(本例中只要求能打印出HelloWorld)。可使用vi编译器编写HelloWorld.c文件,方式如下(常见编辑器包括vi编辑器的用法下一章中将具体讲):


  1. [root@localhost ~]# vi HelloWorld.c #
  2. 回车
  3. #
  4. 这里将进入vi
  5. 命令模式,按i
  6. 键进入编辑模式,输入如下内容
  7. #
  8. 输入完成后,按Esc
  9. 键,然后输入冒号,再按x
  10. 键并按回车键
  11. #include <stdio.h>
  12. int main(void) {
  13. printf("Hello,world!\n");
  14. return 0;
  15. }

有了HelloWorld.c这个源码文件,下面就需要使用gcc工具将该源代码编译成一个可执行的二进制程序了。如果你目前使用的Linux完全是按照第1章演示的安装过程安装的,那么很有可能系统中并没有gcc命令,要想安装gcc请参考下一节中的“使用rpm包安装gcc”;如果确认系统中存在该命令,则可以使用如下命令将源代码编译为可执行的二进制文件:


  1. [root@localhost ~]# gcc HelloWorld.c -o HelloWorld
  2. #
  3. 如果没有gcc
  4. 命令,将会出现如下报错信息,否则将生成文件HelloWorld
  5. #-bash: gcc: command not found
  6. [root@localhost ~]# ls HelloWorld #
  7. 得到了HelloWorld
  8. 二进制文件
  9. HelloWorld

编译完成后,我们得到了二进制可执行文件HelloWorld。那么接下来是否可以直接运行这个命令呢?答案是否定的,尝试运行该命令的时候,系统给出了command not found的报错信息,如下所示:


  1. [root@localhost ~]# HelloWorld
  2. -bash: HelloWorld: command not found

系统中确实已经有了HelloWorld这个程序,可为什么还是说不存在这个命令呢?这就不得不说到系统变量PATH了,它被称作为Linux系统的“环境变量”,可使用如下命令查看当前PATH变量定义的内容:


  1. [root@localhost ~]# echo $PATH
  2. usrkerberos/sbin:usrkerberos/bin:usrlocal/sbin:usrlocal/
  3. bin:/sbin:/bin:usrsbin:usrbin:rootbin

可以看到,PATH变量中是一些由冒号隔开的路径,当输入一个命令时,系统会到PATH所定义的路径中去寻找该命令,找到后就会执行该命令。也就是说,本例中在输入命令HelloWorld并按回车键时,系统先从目录usrkerberos/sbin中寻找是否有这个文件,如果找不到就继续从目录usrkerberos/bin中寻找,再找不到就到目录usrlocal/sbin中找,以此类推。如果在PATH定义的所有目录中都找不到该文件,这时系统就会提示command not found。

想象一下,如果不使用这种机制,那么运行任何命令都需要键入某个命令的全路径,将非常麻烦。还记得在第3章中学习过的which命令吗?它的工作原理也是到环境变量PATH中寻找某个命令,事实上如果使用which找不到某个命令,则说明该命令由于找不到而无法被执行:


  1. [root@localhost ~]# which HelloWorld
  2. usrbin/which: no HelloWorld in (usrkerberos/sbin:usrkerberos/
  3. bin:usrlocal/sbin:usrlocal/bin:/sbin:/bin:usrsbin:usrbin:rootbin)

由于程序HelloWorld当前所在的路径是rootHelloWorld,它并不存在于当前PATH中,所以这里的报错是正常的。解决这里出现的command not found错误有三种方法,第一种方法是在/root目录中使用./HelloWorld执行该命令,或者引用该命令的全路径来执行;第二种方法是将HelloWorld复制到任意一个当前PATH变量包含的目录中;第三种方法是将/root目录追加到PATH变量中。以上方法任意选择使用一种即可,如下所示:


  1. #
  2. 第一种方法
  3. #
  4. 使用./
  5. 执行或使用全路径执行
  6. [root@localhost ]# pwd
  7. /root
  8. [root@localhost ]# ./HelloWorld
  9. Hello, world!
  10. [root@localhost ]# rootHelloWorld
  11. Hello, world!
  12. #
  13. 第二种方法
  14. #
  15. HelloWorld
  16. 复制到任一PATH
  17. 变量包含的目录中,这里使用/bin
  18. 目录
  19. [root@localhost ]# cp HelloWorld bin
  20. [root@localhost ]# which HelloWorld
  21. binHelloWorld
  22. [root@localhost ]# HelloWorld
  23. Hello, world!
  24. #
  25. 第三种方法
  26. #
  27. 将/root
  28. 目录追加到PATH
  29. 变量中,注意看追加目录的方法
  30. #
  31. 在尝试使用该方法之前,如果已经使用了第二种方法,则先删除之前复制的文件
  32. #[root@localhost ]# rm binHelloWorld
  33. #rm: remove regular file `binHelloWorld'? y
  34. [root@localhost ]# export PATH=$PATH:/root
  35. [root@localhost ]# which HelloWorld
  36. rootHelloWorld
  37. [root@localhost ]# HelloWorld
  38. Hello, world!

此处需要注意的是,虽然第三种方法和第二种方法的原理是一致的,但是第三种方法一般在重启主机或重新登录之后就失效了,原因是这种方法并没有将所定义的环境变量保存到任何配置文件中。在这种方法下,可以使用以下命令保存变量PATH的值:


  1. echo "export PATH=$PATH:/root" >> etcrc.local

以上就是源码编译安装软件的原理,简单总结一下就是编写源代码→编译源码生成二进制可执行性文件(也就是程序)→复制该文件到任一PATH变量包含的目录中。

本例中用于演示的软件功能十分简单,只要能打印“Hello,world!”就可以了,所以只需要一个单独的源码文件就可以搞定,而且代码也非常简单。在实际工作中,软件的需求往往比较复杂,而且大多是基于模块化开发的思想来实现的,所以一个软件往往需要多个源码文件和各类配置文件,在编译的时候也需要严格按照一定的过程进行编译,比如说需要先编译出某些模块文件之后,才能最终编译并生成主程序。而这个过程也只有软件开发者自己才清楚,这意味着只有在软件开发者提供了详细的编译步骤文档的前提下,拿到该源码包的人才能按照其规定的编译顺序来编译生成程序。在这种情况下,为了方便软件安装,可以使用Makefile简化整个过程,由于本书并不涉及C语言开发以及Makefile的语法,所以这里并不打算深入讲解Makefile,只做一些演示。在/root目录中编辑Makefile,内容如下所示:


  1. [root@localhost ~]# cat Makefile
  2. HelloWorld:HelloWorld.o
  3. gcc -o HelloWorld HelloWorld.c #
  4. 前面不是空格,而是一个Tab
  5. install:
  6. cp HelloWorld bin #
  7. 此处前面的也是一个Tab

有了Makefile之后,编译安装HelloWorld程序就变得更简单了,只需要以下两条命令即可:


  1. #
  2. 第一步,输入make
  3. 命令,这会自动完成编译的过程
  4. [root@localhost ~]# make
  5. gcc -o HelloWorld HelloWorld.c #
  6. 这里是make
  7. 命令执行后的输出
  8. #
  9. 第二步,输入make install
  10. 命令,这会自动完成软件的复制
  11. [root@localhost ]# make install
  12. cp HelloWorld bin #
  13. 注意这里是make install
  14. 的输出,不需要人工复制
  15. #
  16. 然后就可以直接执行命令了
  17. [root@localhost ]# HelloWorld
  18. Hello, world!

事实上,有很多开源软件自身是不包含Makefile的,特别是在模块化程度较高的软件中,都不包含Makefile,而需要用户根据具体的需求使用软件包目录中的configure工具,生成适合用户特定需求的Makefile,所以典型的源码编译安装软件的过程包括以下3步:

第一步,运行configure命令,并结合必要的参数以生成Makefile;

第二步,运行make命令生成各类模块和主程序;

第三步,运行make install命令将必要的文件复制到安装目录中。

以上3步都需要在对应软件包目录的根目录下运行。