Linux基础知识(11)- GCC 简单使用(一)| GCC 安装配置和 Makefile 的基本用法


GCC 的全拼为 GNU C Compiler,即 GUN 计划诞生的 C 语言编译器,显然最初 GCC 的定位确实只用于编译 C 语言。但经过这些年不断的迭代,GCC 的功能得到了很大的扩展,它不仅可以用来编译 C 语言程序,还可以处理 C++、Go、Objective -C 等多种编译语言编写的程序。与此同时,由于之前的 GNU C Compiler 已经无法完美诠释 GCC 的含义,所以其英文全称被重新定义为  GNU Compiler Collection,即 GNU 编译器套件。

所谓编译器,可以简单地将其理解为 “翻译器”。要知道,计算机只认识二进制指令(仅有 0 和 1 组成的指令),我们日常编写的 C 语言代码、C++ 代码、Go 代码等,计算机根本无法识别,只有将程序中的每条语句翻译成对应的二进制指令,计算机才能执行。

GCC 编译器从而停止过改进。截止 2020 年 5 月,GCC 已经从最初的 1.0 版本发展到了 10.1 版本,期间历经了上百个版本的迭代。作为一款最受欢迎的编译器,GCC 被移植到数以千计的硬件/软件平台上,几乎所有的 Linux 发行版也都默认安装有 GCC 编译器。GCC 支持的硬件平台(部分):

 

硬件 操作系统
Alpha Red Hat Linux
HPPA HPUX
Intel x86 Debian Linux、Red Hat Linux 和 FreeBSD
MIPS IRIX
PowerPC AIX
Sparc Solaris

 

1. GCC 安装配置

    Linux 操作系统的自由、开源,在其基础上衍生出了很多不同的 Linux 操作系统,如 CentOS、Ubuntu、Debian 等。这些 Linux 发行版中,大多数都默认装有 GCC 编译器(版本通常都较低)。

    1) CentOS 7.9 下安装

        查看当前 GCC 版本:

            $ gcc --version

                -bash: gcc: command not found

                注:表明当前系统没有安装 GCC 编译器。

        (1) 基于 yum 安装

            $ sudo yum -y install gcc gcc-c++

                ...

                Installed:
                  gcc.x86_64 0:4.8.5-44.el7                                gcc-c++.x86_64 0:4.8.5-44.el7

                Dependency Installed:
                  cpp.x86_64 0:4.8.5-44.el7                               glibc-devel.x86_64 0:2.17-326.el7_9
                  glibc-headers.x86_64 0:2.17-326.el7_9                   kernel-headers.x86_64 0:3.10.0-1160.80.1.el7
                  libmpc.x86_64 0:1.0.1-3.el7                             libstdc++-devel.x86_64 0:4.8.5-44.el7
                  mpfr.x86_64 0:3.1.1-4.el7

                Complete!


            $ gcc --version

                gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
                Copyright (C) 2015 Free Software Foundation, Inc.
                This is free software; see the source for copying conditions.  There is NO
                warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 


            注:基于 yum 默认安装的 GCC 版本由 CentOS 的版本决定,由于 CentOS 7.9 下默认安装的 GCC 4.8.5 版本太低(低版本 GCC 默认的 C89 的标准不支持某些 C 语法,需要编译时指定 -std=语法标准),所以我们这里再手动安装更高版本的 GCC 。
     
        (2) 手动安装

            下载高版本源码安装包,安装前需要 CentOS 7.9 上已经安装低版本的 GCC,因为以源码的方式安装 GCC 编译器,即手动编译 GCC 编译器的源码,需要当前系统中存在一个可用的编译器。

            GCC 下载地址:https://mirrors.aliyun.com/gnu/gcc/,这里下载 gcc-9.4.0.tar.gz 并复制到 ~/ 目录,具体安装过程如下:

                $ cd ~/

                # 解压至 /usr/local 目录下
                $ sudo tar -vzxf gcc-9.4.0.tar.gz -C /usr/local     
                $ cd /usr/local/gcc-9.4.0

                # 下载安装 GCC 所需要的依赖包(如 gmp、mpfr、mpc 等),
                # 要确保这些依赖包被成功下载后,才能继续执行下面的安装步骤
                $ sudo ./contrib/download_prerequisites

                    ...

                    gmp-6.1.0.tar.bz2: OK
                    mpfr-3.1.4.tar.bz2: OK
                    mpc-1.0.3.tar.gz: OK
                    isl-0.18.tar.bz2: OK
                    All prerequisites downloaded successfully.


                # 手动创建一个目录,用于存放编译 GCC 源码包生成的文件
                $ sudo mkdir build-9.4.0
                $ cd build-9.4.0

                # GCC 编译器支持多种编程语言的编译,配置 GCC 支持编译 C 和 C++ 语言 (其它语言:java、objc、obj-c++、go 等)
                $ sudo ../configure --enable-checking=release --enable-languages=c,c++ --disable-multilib

                # 使用 make 命令来编译和安装
                $ sudo make & make install

                $ gcc --version

                    gcc (GCC) 9.4.0
                    Copyright (C) 2019 Free Software Foundation, Inc.
                    This is free software; see the source for copying conditions.  There is NO
                    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    2) Ubuntu 20.04 下安装

        查看当前 GCC 版本:

            $ gcc --version

                Command 'gcc' not found, but can be installed with:

                sudo apt install gcc

                注:表明当前系统没有安装 GCC 编译器。

        基于 apt-get 安装:

            $ sudo apt install gcc g++ make

                ...

                Setting up gcc-9 (9.4.0-1ubuntu1~20.04.1) ...
                Setting up gcc (4:9.3.0-1ubuntu2) ...
                Setting up g++-9 (9.4.0-1ubuntu1~20.04.1) ...
                Setting up g++ (4:9.3.0-1ubuntu2) ...
                Setting up make (4.2.1-1.2) ...
                update-alternatives: using /usr/bin/g++ to provide /usr/bin/c++ (c++) in auto mode
                Processing triggers for man-db (2.9.1-1) ...
                Processing triggers for libc-bin (2.31-0ubuntu9.9) ...


            $ gcc -version

                gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
                Copyright (C) 2019 Free Software Foundation, Inc.
                This is free software; see the source for copying conditions.  There is NO
                warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 

            注:Ubuntu 20.04 版本默认安装了 GCC 9.4.0,这里不需要手动安装更高版本的 GCC。


2. Hello World

    使用 vim 编辑器,编写 C 和 C++ 程序,其功能是输出 "Hello World!"。如果 vim 编辑器没有安装,可以运行如下命令安装 vim:      

        $ sudo apt-get install vim     # CentOS 下运行 sudo yum -y install vim

    1) C 程序

        $ cd ~/
        $ vim hello.c

            #include <stdio.h>
            
            int main() {
                puts("Hello World!- C");
                return 0;
            }


        # gcc 编译
        $ gcc hello.c -o hello

        $ ./hello

            Hello World! - C

    2) C++ 程序

        $ vim hello2.cpp

            #include <iostream>
            using namespace std;
            
            int main() {
                cout << "Hello World! - C++" << endl;
                return 0;
            }


        # g++ 编译
        $ g++ hello2.cpp -o hello2

        $ ./hello2

            Hello World! - C++

     3) GCC/G++ 常用的指令选项

指令选项 描述
-E(大写) 预处理指定的源文件,不进行编译。
-S(大写) 编译指定的源文件,但是不进行汇编。
-c 编译、汇编指定的源文件,但是不进行链接。
-o 指定生成文件的文件名。
-llibrary(-I library)    其中 library 表示要搜索的库文件的名称。该选项用于手动指定链接环节中程序可以调用的库文件。建议 -l 和库文件名之间不使用空格,比如 -lstdc++。
-ansi 对于 C 语言程序来说,其等价于 -std=c90;对于 C++ 程序来说,其等价于 -std=c++98。
-std= 手动指令编程语言所遵循的标准,例如 c89、c90、c++98、c++11 等。

        注:以上仅列出的一些常用指令选项,GCC 编译器提供有大量的指令选项,更多的指令选项,可以查看 GCC 手册


3. Makefile 的基本用法

    上文我们使用 “gcc hello.c -o hello” 命令把 hello.c 源文件编译成了 hello 可执行程序(类似 Windows 下的 *.exe 文件)。

    编译一个 *.c 文件(这里没有用到 *.h 头文件),可以用单命令行的方式很简单的实现,如果项目中有很多个 *.c 文件和 *.h 头文件,用单命令行方式编译,视乎是一件不可思议的事情。

    要解决这个问题,最好的方式就是把项目的编译规则写下来,让编译器自动加载该规则进行编译,也就是使用 make 命令和 Makefile 文件。关于 make 命令和 Makefile 文件,具体描述如下:

        make 命令:它可以帮助我们找出项目里面修改变更过的文件,并根据依赖关系,找出受修改影响的其他相关文件,然后对这些文件按照规则进行单独的编译,避免重新编译项目的所有的文件;

        Makefile 文件:上面提到的规则、依赖关系就定义在这个 Makefile 文件中,定义文件的依赖关系之后,make 命令就能精准地进行编译工作;

        注:GNU 官方的 make 说明文档:https://www.gnu.org/software/make/manual

    1) Makefile 示例

        创建 Makefile 文件,内容如下:

            # target_a 是第一个目标,是最终目标,即 make 的默认目标
            # 执行 ls 命令列出当前目录下的内容,target_a 依赖于 target_b 和 target_c
            target_a: target_b target_c
                ls

            # 执行 touch 命令创建 test.txt 文件,target_b 无依赖
            target_b:
                touch test.txt

            # 执行 pwd 命令显示当前路径,target_c 无依赖
            target_c:
                pwd

            # 执行 rm 命令删除 test.txt 文件,target_d 无依赖
            target_d:
                rm -f test.txt


            注:命令行之前是 tab 键,不能是空格。vim 的默认 tab 是 8 个空格,建议创建或修改 vim 的配置文件 ~/.vimrc,添加:

                set tabstop=4   // 设置 tab 键是 4 个空格
                set noexpandtab  // 不把 tab 键用空格代替

        运行:

            $ ls

                hello  hello2  hello2.cpp  hello.c  Makefile

            $ make

                touch test.txt
                pwd
                /home/xxx
                ls
                hello  hello2  hello2.cpp  hello.c  Makefile  test.txt

            $ make target_d

                rm -f test.txt

            $ make target_b

                touch test.txt

            $ make target_c

                pwd
                /home/xxx


            注:target_d 不是默认目标,且不被其它任何目标依赖,所以直接 make 时 target_d并没有被执行,可以使用 “make 目标名” 的语法执行指定的目标。

                make 命令和 Makefile 文件一起配合使用,从原理上讲有点类似于 Windows 的批处理程序 (*.bat)。


    2) 使用 Makefile 编译程序

        (1) 创建多个文件

            创建 hello_main.c 文件,内容如下:

                #include "hello_func.h"

                int main() {
                    hello_func();
                    return 0;
                }


            创建 hello_func.c 文件,内容如下:

                #include <stdio.h>
                #include "hello_func.h"

                void hello_func(void) {

                    printf("Hello world - Makefile!\n");
                    for (int i=0; i<3; i++ ) {
                        printf("output i=%d\n",i);
                    }
                }


            创建 hello_func.h 文件,内容如下:

                void hello_func(void);

        (2) 命令行编译

            # 注意最后的 "-I ." 包含名点 "."
            $ gcc -o hello_main hello_main.c hello_func.c -I .

            # 运行生成的 hello_main 程序
            $ ./hello_main

                Hello world - Makefile!
                output i=0
                output i=1
                output i=2

            注:低版本的 gcc 默认使用的 C89 的标准不支持 for 中定义循环变量,需要增加 -std=c99 或 -std=gun99 参数才能编译通过。比如:

                gcc -o hello_main hello_main.c hello_func.c -std=gnu99 -I .

        (3) Makefile 编译

            创建 Makefile 文件,内容如下:

                # 默认目标,hello_main 依赖于 hello_main.c 和 hello_func.c
                hello_main: hello_main.c hello_func.c
                    gcc -o hello_main hello_main.c hello_func.c -I .

                # clean目标,删除编译生成的中间文件
                clean:
                    rm -f *.o hello_main


            运行:

                $ make

                    gcc -o hello_main hello_main.c hello_func.c -I .

                $ ./hello_main

                    Hello world - Makefile!
                    output i=0
                    output i=1
                    output i=2

                # 再次 make,会提示 hello_main 文件已是最新
                $ make

                    make: `hello_main' is up to date.

                # 使用 touch 命令更新一下 hello_func.c 的时间
                $ touch hello_func.c

                # 再次 make,由于 hello_func.c 比 hello_main 新,所以会再编译
                $ make

                    gcc -o hello_main hello_main.c hello_func.c -I .


    3) Makefile 语法

        语法格式:

            [目标1]:[依赖]
            [命令1]
            [命令2]

            [目标2]:[依赖]
            [命令1]
            [命令2]

        说明:

            (1) 目标:指 make 要做的事情,可以是一个简单的代号,也可以是目标文件,需要顶格书写,前面不能有空格或 Tab。一个 Makefile 可以有多个目标,写在最前面的第一个目标,会被 Make 程序确立为 “默认目标”,例如前面的 target_a、hello_main;

            (2) 依赖:要达成目标需要依赖的某些文件或其它目标。例如前面的 target_a 依赖于 target_b 和target_c,又如在编译的例子中,hello_main 依赖于 hello_main.c、hello_func.c 源文件,若这些文件更新了会重新进行编译;

            (3) 命令1、命令2 … 命令n:make 达成目标所需要的命令。只有当目标不存在或依赖文件的修改时间比目标文件还要新时,才会执行命令。要特别注意命令的开头要用 “Tab” 键,不能使用空格代替,有的编辑器会把 Tab 键自动转换成空格导致出错,若出现这种情况请检查自己的编辑器配置。


posted @ 2022-12-09 13:29  垄山小站  阅读(2597)  评论(0编辑  收藏  举报