编译程序

前言

  1. 本章将介绍如何通过源代码生成可执行程序。开放源代码是 Linux 自由开源的必要因素,整个 Linux 系统的开发依赖于开发人员之间的自由交流。
  2. 需要编译软件的原因:
  • 可用性:尽管有些发行版已经包含了版本库中一些预编译程序,但并不会包含用户所有可能需要的应用程序。这种情况下,用户获取所需要软件的唯一方式就是编译源代码。
  • 及时性:虽然有些发行版本专注于一些前沿的程序版本,但是多数并不会。这就意味着想要获取最新版本的程序,编译必不可少的。
  1. 编译软件源代码是一项非常复杂并且有技术性的任务,这远远超出了多数用户的能力范围。
  2. 本章将会介绍一个新的命令:
  • make: 维护程序的工具

什么是编译

  1. 编译就是一个将源代码 (由程序员编写的人类可读的程序描述) 编译成计算机处理器能识别的语言的过程。

是不是所有的程序都需要编译

  1. Shell 脚本可以直接运行而不需要编译,这些文件都是用脚本或解释型语言编写的。
  2. 这些语言越来越受欢迎,其中就有 Perl、Python、PHP、Ruby 以及其他多种语言等。
  3. 脚本语言由一个称为解释器的特殊程序来执行,解释器负责输入程序文件并执行其所包含的所有指令。
  4. 通常来讲,解释型程序要比编译后的程序执行起来慢。这是因为在解释型程序中,每条源代码指令在执行时,都要重新翻译一次该源代码指令。
  5. 然而,在编译后的程序中,每条源代码指令只翻译一次,并且该翻译结果将永久地记录到最后的可执行文件中。
  6. 其实对于许多日常的编程工作,解释型程序的执行速度也是足够的,而其真正的优点在于开发解释型程序比要开发编译程序简单而迅速得多。

编译一个 C 程序

基本介绍

  1. 在执行编译操作之前,需要一些工具,诸如编译器、链接器以及 make 等。
  2. gcc (GNU C 编译器) 是 Linux 环境中通用的 C 编译器,最初由 Richard Stallman 编写的。
  3. 多数 Linux 发行版本并不会默认安装 gcc ,我么可以用下面的命令行查看系统是否安装了该编译器。
    1
    2
    [me@linuxbox ~]$ which gcc
    /usr/bin/gcc

获取源码

  1. 从一个叫做 diction 的 GNU 项目中选择一个程序进行编译练习,这个方便短小的程序一般用于检查文本文件的质量和写作风格,它非常小并且容易生成。
  2. 依据惯例,我们首先创建一个 src 目录用于存放源代码,然后使用 ftp 下载源代码至该目录。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    [me@linuxbox ~]$ mkdir src && cd src
    [me@linuxbox src]$ ftp ftp.gnu.org
    Connected to ftp.gnu.org.
    220 GNU FTP server ready.
    Name (ftp.gnu.org:me): anonymous
    230-NOTICE (Updated October 13 2017):
    230-
    230-Because of security concerns with plaintext protocols, we still
    230-intend to disable the FTP protocol for downloads on this server
    230-(downloads would still be available over HTTP and HTTPS), but we
    230-will not be doing it on November 1, 2017, as previously announced
    230-here. We will be sharing our reasons and offering a chance to
    230-comment on this issue soon; watch this space for details.
    230-
    230-If you maintain scripts used to access ftp.gnu.org over FTP,
    230-we strongly encourage you to change them to use HTTPS instead.
    230-
    230----
    230-
    230-Due to U.S. Export Regulations, all cryptographic software on this
    230-site is subject to the following legal notice:
    230-
    230- This site includes publicly available encryption source code
    230- which, together with object code resulting from the compiling of
    230- publicly available source code, may be exported from the United
    230- States under License Exception "TSU" pursuant to 15 C.F.R. Section
    230- 740.13(e).
    230-
    230-This legal notice applies to cryptographic software only. Please see
    230-the Bureau of Industry and Security (www.bxa.doc.gov) for more
    230-information about current U.S. regulations.
    230 Login successful.
    ftp> cd gnu/diction
    250 Directory successfully changed.
    ftp> ls
    200 PORT command successful. Consider using PASV.
    150 Here comes the directory listing.
    -rw-r--r-- 1 3003 65534 68940 Aug 28 1998 diction-0.7.tar.gz
    -rw-r--r-- 1 3003 65534 90957 Mar 04 2002 diction-1.02.tar.gz
    -rw-r--r-- 1 3003 65534 141062 Sep 17 2007 diction-1.11.tar.gz
    -rw-r--r-- 1 3003 65534 189 Sep 17 2007 diction-1.11.tar.gz.sig
    226 Directory send OK.
    ftp> get diction-1.11.tar.gz
    200 PORT command successful. Consider using PASV.
    150 Opening BINARY mode data connection for diction-1.11.tar.gz (141062 bytes).
    WARNING! 554 bare linefeeds received in ASCII mode
    File may not have transferred correctly.
    226 Transfer complete.
    141062 bytes received in 1.3 seconds (106 kbytes/s)
    ftp> bye
    221 Goodbye.
    [me@linuxbox src]$ ls
    diction-1.11.tar.gz
  3. 我们可以看到,源代码通常以一个压缩的 tar 文件的形式存在,有时被称为 tarball,该文件包含了源代码数树,即构成该源代码的目录及文件的组织框架。
  4. 连接 FTP 站点后,我们便可以查看可用的 tar 文件列表并挑选其中最新的版本进行下载。
  5. 在 ftp 中使用 get 命令,即可将文件从 FTP 服务器复制到本地主机。
  6. 下载了该 tar 文件后,就必须对其进行解压缩,这是通过 tar 程序来完成的。
    1
    2
    3
    [me@linuxbox src]$ tar xzf diction-1.11.tar.gz
    [me@linuxbox src]$ ls
    diction-1.11 diction-1.11.tar.gz

检查源代码树

  1. 解压 tar 文件会产生一个新的目录:diction-1.11 。
  2. 该目录包含了源文件树,具体内容如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [me@linuxbox src]$ cd diction-1.11
    [me@linuxbox diction-1.11]$ ls
    config.guess diction.c getopt.c nl
    config.h.in diction.pot getopt.h nl.po
    config.sub diction.spec getopt_int.h README
    configure diction.spec.in INSTALL sentence.c
    configure.in diction.texi.in install-sh sentence.h
    COPYING en Makefile.in style.1.in
    de en_GB misc.c style.c de.po en_GB.po misc.h test
    diction.1.in getopt1.c NEWS
  3. 此目录下的其他有趣文件便是这些以 .c 和 .h 结尾的文件,
    1
    2
    3
    4
    [me@linuxbox diction-1.11]$ ls *.c
    diction.c getopt1.c getopt.c misc.c sentence.c style.c
    [me@linuxbox diction-1.11]$ ls *.h
    getopt.h getopt_int.h misc.h sentence.h
  4. 软件包提供的两个 C 程序 (style 和 diction) 便是以 .c 结尾,并且他们都被分成了多个模块。
  5. 这些源代码文件都是普通的文本文件,可以用 less 查看。
    1
    [me@linuxbox diction-1.11]$ less diction.c
  6. .h 文件是大家熟知的头文件。这些文件,同样也是普通的文本文件。
  7. 头文件中包含了对源代码文件或库中的例程的描述。编译器在链接这些例程模块时,必须给它提供一个其所用的所有模块的描述。
  8. 因此,在 diction.c 的开头,可一看到如下文本行:
    1
    # include "getopt.h"
  9. 该文本行会指示编译器在读取 diction.c 中的源代码内容时,先读取文件 getopt.c 中内容。
  10. getopt.c 文件包含的是由 style 和 diction 程序所共享的例程模块。
  11. 在 getopt.h 的 include 语句上面,还可以看到一些其他 include 语句,如下所示:
    1
    2
    3
    4
    5
    # include <regex.h>
    # include <stdio.h>
    # include <stdlib.h>
    # include <string.h>
    # include <unisted.h>
  12. 这些都是用来引用头文件,但是它们引用的是那些不存在当前源目录的头文件。它们由系统提供,为每个程序的编译提供支持。如果查看/usr/include 目录。便会看到如下内容。

生成程序

  1. 大多数程序都是使用一个简单的两行命令来生成的。
    1
    2
    ./configure
    make
  2. configure 程序其实是源代码树下的一个 Shell 脚本,它的任务就是分析生成环境。
  3. 多数源码都设计成可移植的。也就是说,源代码可以在多种类型的 UNIX 系统上生成,只是源代码在生成时可能需要经过细微的调整以适应各系统之间的不同。
  4. configure 同样会检查系统是否已经安装了必要的外部工具和组件。
  5. 由于 configure 并不是存放于 shell 通常期望程序所在的目录下,所以必须显式告知 shell 有关 configure 的位置,我们可以在命令前添加 ./ 目录符来实现目的。
  6. 该符号表示 configure 程序位于在当前的工作目录下
    1
    [me@linuxbox diction-1.11]$ ./configure
  7. configure 会在检查以及配置 build 程序的同时输出很多相关信息。
  8. 需要注意的是,如果没有错误信息表示成功,如果有,该 configure 操作将以失败告终,并且不会生成可执行程序,直到所有的错误都被纠正过来。
  9. configure 在源目录中创建了几个新文件,其中最重要的就是 Makefile 。
  10. Makefiles 是指导 make 命令如何生成可执行程序的配置文件,如果没有该文件, make 便无法运行。
  11. Makefile 也是一个普通的文本文件,所以我们可以用 less 查看其内容。
    1
    [me@linuxbox diction-1.11]$ less Makefile
  12. make 程序的作用其实就是输入 makefile (通常叫做 Makefile) ,该文件描述了生成最后可执行程序时各部件之间的练习及依赖关系。
  13. makefile 的第一部分内容定义了一些变量,这些变量在 makefile 的后面部分将会被替换掉。
  14. make 程序运行时,会使用 Makefile 文件中的内容指导其操作,其间会产生许多信息。
    1
    [me@linuxbox diction-1.11]$ make
  15. make 能够智能地仅生成需要指定 building 操作的目标文件。

安装程序

  1. 打包好的源代码一般包含一个特殊的 make 目标程序,他便是 install。
  2. 该目标程序将会在系统目录下安装最后生成的可执行程序。通常,会安装在目录 /usr/local/bin 下,该目录是本地主机上生成软件的常用安装目录。
  3. 然而,对于普通用户,该目录通常不可写的,所以必须转换成超级用户才可以运行安装。
    1
    [me@linuxbox diction-1.11]$ sudo make install
  4. 安装结束后,就可以查看该程序是否可以运行。
    1
    2
    3
    [me@linuxbox diction-1.11]$ which diction
    /usr/local/bin/diction
    [me@linuxbox diction-1.11]$ man diction

参考文章

  • 转载:Linux 命令行大全