Linux - g++ 命令

jc39
jc39
发布于 2026-06-14 / 2 阅读
0
0

title: Linux - g++ 命令
date: 2023-08-07 00:00:00
categories: [Linux]
tags: [Linux, g++]

Linux - g++ 命令

g++ 是 GNU 开发的 C++ 编译器,gcc 是 GNU 的 C 编译器,都是 GNU 编译器套件 GCC (GNU Compiler Collection) 的组成部分。

这里将介绍常用的命令。

1. 编译简介

g++ 编译分四个步骤:预处理 (Preprocessing)、编译 (Compilation)、汇编 (Assembly) 和链接 (Linking)。

g++ 命令包装了预处理器、编译器、汇编器和链接器,会根据不同的参数去调用这些构建程序。

以 C++ 源码文件 test.cpp 为例:

#include <iostream>

int main(void)
{
    std::cout << "Hello world!" << std::endl;

    return 0;
}

下面将 test.cpp 转换为可执行文件 test.out。

  1. 预处理 (Preprocessing)

    预处理器 cpp 将 .cpp 源码预处理为 .i 文件。预处理将处理预处理指令(如 #include、#define、#if 等)和注释,不处理编译指令 #pragma。

    # 生成预处理后的 .i 文件
    g++ -E test.cpp -o test.i
    
    # 等效命令
    cpp test.cpp -o test.i
    
  2. 编译 (Compilation)

    编译器 cc1plus 通过一系列语法分析、词法分析、语义分析及优化将 .i 文件编译为 .s 汇编代码文件。使用 -S 选项,只进行编译而不汇编,输出汇编代码。

    # 生成汇编 .s 文件
    g++ -S test.i [-o test.s]
    
    # 等效命令
    # 第一行是创建 cc1plus 软连接,第二行是使用 cc1plus 命令
    ln -s /usr/libexec/gcc/x86_64-linux-gnu/7.3.0/cc1plus /usr/local/bin
    cc1plus test.i [-o test.s]
    

    补充:GCC 编译套件中,C++ 的编译器是 cc1plus,C 是 cc1,Objective-C 是 cc1obj,Fortran 是 f771,Java 是 jc1。

  3. 汇编 (Assembly)

    汇编器 as 将 .s 文件汇编为 .o 可重定位目标文件,包含二进制代码和数据。

    # 生成二进制 .o 文件
    g++ -c test.s [-o test.o]
    
    # 等效命令
    as test.s -o test.o
    
  4. 链接 (Linking)

    链接器 ld 将 .o 文件链接为可执行目标文件,包含了完整的二进制代码和数据。

    # 生成二进制 .out 可执行文件
    g++ test.o -o test.out
    
    # 等效命令
    # 直接使用 ld 进行链接,但是需要注意使用 ld 需添加较长命令选项
    # 可以使用 g++ -v <test.o> 命令查看 collect2 所使用的命令选项
    # collect2 是对 ld 的封装,最终还是要调用 ld 来完成链接工作
    ld <collect2 命令选项> -o test.out
    

执行最后链接生成的 test.out 输出:

Hello world!

以上过程合成一步:

g++ test.cpp -o test.out

2. 命令格式

gcc [-c|-S|-E] [-std=standard]
    [-g] [-pg] [-Olevel]
    [-Wwarn...] [-Wpedantic]
    [-Idir...] [-Ldir...]
    [-Dmacro[=defn]...] [-Umacro]
    [-foption...] [-mmachine-option...]
    [-o outfile] [@file] infile...

g++ 接受与 gcc 基本相同的选项。

3. 命令选项

关于 g++ 命令选项,可以使用 man g++ 查看,或参考 GCC 官方手册:gcc.pdf (gnu.org)

下面介绍常用的命令选项。

3.1. 总体选项

-E
	只激活预处理,但不生成文件。
	可以使用重定向、管道或 -o 选项输出到文件中或查看。例如:
	g++ -E test.cpp > test.i
	g++ -E test.cpp | more
	g++ -E test.cpp -o test.i

-S   
	只激活预处理和编译,将文件编译为 .s 汇编代码文件。例如:
	g++ -S test.cpp

-c  
	只激活预处理,编译和汇编,将文件汇编为 .o 可重定位目标文件。例如:
	g++ -c test.cpp

-o
	指定目标名称。
	输出可执行目标文件时,缺省为 a.out。例如:
	g++ test.cpp -o test.out
	g++ -S test.cpp -o test.s

3.2. 目录选项

-iquote [dir]
-I[dir]
-isystem [dir]
-idirafter [dir]
	这四个命令选项都是将 dir 添加到头文件搜索路径列表。
	多个时,在各个种类内,按从左到右的优先级顺序处理。
	-iquote [dir] 仅对 #include "file" 有效。
	-I[dir], -isystem [dir], -idirafter [dir] 对 #include "file" 和 #include <file> 有效。
	因此,搜索顺序如下:
	#include "file" 头文件搜索顺序:
	当前目录 -> -iquote [dir] -> -I[dir] -> -isystem [dir] -> 系统目录 -> -idirafter [dir]
	#include <file> 头文件搜索顺序:
	-I[dir] -> -isystem [dir] -> 系统目录 -> -idirafter [dir]

-iprefix [prefix]
-iwithprefix [dir]
	一起使用,会到 prefix + dir 下查找,搜索顺序相当于 -idirafter [dir]。
	如果 prefix 为目录,应以 / 结尾。

-I-
	已弃用,现使用 -iquote [dir]。
	-I- 前(左)的 -I[dir] 仅仅对 #include "file" 有效,
	-I- 后(右)的 -I[dir] 同时对 #include "file" 和 #include <file> 有效。

-include [file]
	相当于将 #include "file" 添加到代码第一行,多个时最左边的优先级最高。
	默认路径为预处理器所在目录,建议使用绝对路径。

-L[dir]
	将 dir 添加到要搜索 -l 的路径列表中,即添加搜索库的路径。

-l[library]
	链接时将搜索名为 library 库,默认搜索系统目录。链接顺序从左到右。
	同时找到动态库和静态库时,链接器会优先链接动态库,除非使用了 -static 选项。
	推荐用于动态库,如 libtest.so,参数写作 -ltest。
	静态库直接写上绝对路径即可。

3.3. 预处理选项

-D[macro]
	相当于 #define macro。

-D[macro=defn]
	相当于 #define macro defn。
	若要定义字符串,为 -Dmacro=\"defn\"

-U[macro]
	相当于 #undef macro。

-undef
	取消任何非标准宏的定义,C++ 标准预定义的宏仍然有效。

3.4. 链接方式选项

-static
	禁止使用动态库。

-shared
	尽量使用动态库,为默认选项。

-symbolic
	建立共享目标文件的时候,把引用绑定到全局符号上。
	警告所有无法解析的引用(除非被链接选项 -Xlinker -z -Xlinker defs 覆盖)。
	只有少数系统支持该选项。

-Wl,[option]
	使用链接器 ld 参数 option。
	如果 option 中间有逗号,将分成多个选项传递给链接器。

-Wl,-Bstatic
	禁止使用动态库,如果只存在动态链接库,则链接器报错。

-Wl,-Bdynamic
	优先使用动态库,如果只存在静态链接库,则使用静态链接库。

-Wl,-rpath,[dir]
	设置运行时共享库的搜索路径为 dir。

-Wl,-s 或 -Wl,--strip-all
	剔除所有符号信息。

-Wl,-S 或 -Wl,--strip-debug
	剔除调试符号信息。

3.5. 错误与警告选项

-pedantic
	允许发出 ANSI/ISO C 标准所列出的所有警告。

-pedantic-errors
	允许发出 ANSI/ISO C 标准所列出的错误。例如:
	使用 -std=c++11 使用 c++11 标准后,若使用 c++14 语法,
	在 g++ 版本支持的情况下,仅会发出警告,仍能完成编译。
	但若启用 -pedantic-errors, 将警告转为错误,则需严格遵守标准才能编译。

-Wall
	一般使用该选项,允许发出 GCC 能够提供的所有有用的警告。
	也可以用 -W[warning] 来标记指定的警告。

-Wno-deprecated
	使用 C++ 标准废弃特性不告警。

-Werror
	将所有警告转为错误。

-Werror=[warning]
	将指定警告转为错误。例如:
	-Werror=return-type,如果函数需要返回值却没有 return 语句,则编译报错。

-Wunknown-pragmas
	遇到 GCC 无法识别的编译指导指令时,发出警告。已由 -Wall 选项包含。

-Wno-pragmas
	遇到 GCC 无法识别的编译指导指令时,不发出警告。

-w
	关闭所有警告,不建议使用。

3.6. 调试选项

-g
	可执行目标文件包含调试信息。

-gstabs
	此选项以 stabs 格式生成调试信息,但不包括 gdb 调试信息。

-gstabs+
	此选项以 stabs 格式声称调试信息,并且包含仅供 gdb 使用的额外调试信息。

-ggdb
	此选项将尽可能的生成 gdb 可以使用的调试信息。

-g<level>
	请求生成调试信息,同时用 level 指出需要多少信息,默认的 level 是 2。
	0 不产生调试信息,1 信息最少,3 包含宏信息。

-pg
	编译的过程中加入额外的代码,供性能分析工具 gprof 剖析程序的耗时情况。

3.7. 优化选项

-O0
-O1
-O2
-O3
-Os
	优化级别,在编译时间、程序大小和执行效率上有所区别。
	-O0,减少编译时间,并且不影响调试信息。是默认的编译选项。
	-O1 或 -O,优化。
	-O2,进一步优化。
	-O3,更进一步优化。
	-Os,优化大小,启用除了通常会增加代码大小的优化选项以外的所有 -O2 的优化选项。

3.8. 其他选项

-fpic
	编译器生成位置无关目标码(PIC, position-independent code),用于动态链接库。
	通过全局偏移表(GOT, Global Offset Table)访问所有常量地址。
	程序启动时通过动态加载程序解析 GOT 条目。
	如果动态链接库的 GOT 大小超过限制,链接器会报错,
	提示 -fpic 不起作用,请使用 -fPIC。

-fPIC
	同 -fpic 功能一致,生成位置无关目标码,用于生成动态链接库。
	建议使用该选项,而非 -fpic。

-v
--verbose
	显示详细的编译、汇编、链接命令。

-pipe
	使用管道代替编译过程中的临时文件。
	在使用非 gnu 汇编工具的时候,可能有些问题。例如:
	g++ -pipe -o hello.out hello.cpp

-std=[standard]
	明确语言标准,对 C 或 C++ 有效。
	比如 -std=c++11 将指定 2011 年 ISO C++ 标准及其修订版。

-ansi
	对 C 等效于 -std=c90,对 C++ 等效于 -std=C++98。
	关闭 gnu c 中与 ansi c 不兼容的特性,激活 ansi c 的专有特性。
	包括禁止一些 asm, inline, typeof 关键字,以及 UNIX, vax 等预处理宏。

-fno-asm
	此选项实现 ansi 选项功能的一部分,
	它禁止将 asm, inline 和 typeof 用作关键字。

-fno-strict-prototype
	只对 g++ 起作用,使用这个选项,
	g++ 将把函数的不带参数当作是没有显式的对参数的个数和类型说明,而不是没有参数。
	而 gcc 无论是否使用这个参数,都将对没有带参数的函数,认为没有显式说明的类型。

-fthis-is-varialble
	向传统 c++ 看齐,可以将 this 当作一般变量使用。

-fcond-mismatch
	允许条件表达式的第二和第三参数类型不匹配,表达式的值将为 void 类型。

-funsigned-char
-fno-unsigned-char
-fsigned-char
-fno-signed-char
	设置 char 的类型。

-fpermissive
	把代码的语法错误作为警告,并继续编译。请谨慎使用该选项。

-imacros [file]
	将 file 文件的宏,扩展到 gcc/g++ 的输入文件。
	宏定义本身并不出现在输入文件中。

-nostdinc
	使编译器不在系统缺省的头文件目录里面找头文件。
	一般和 -I 联合使用,明确限定头文件的位置。

-nostdin C++
	规定不在 g++ 指定的标准路经中搜索,但仍在其他路径中搜索。
	此选项在创建 libg++ 库时使用。

-C
	在预处理的时候,不删除注释信息。
	一般和 -E 使用,方便分析程序。

-m
	生成与具体 CPU 相关的程序。

-mtune=[cpu-type]
	为指定类型的 CPU 生成代码。
	cpu-type 可以是:i386,i486,i586,pentium,i686,pentium4 等等。

-m32
	生成 32 位程序。int,long 和指针位宽为 32 位。

-m64
	生成 64 位程序。int 位宽为 32 位,long 和指针位宽为 64 位。

-mmmx
-msse
-msse2
-mno-mmx
-mno-sse
-mno-sse2
	使用或者不使用 MMX,SSE,SSE2 指令。

-M
	生成文件依赖的信息,包含目标文件所依赖的所有源文件。例如:
	g++ test.cpp -M

-MM
	与 -M 相似,但是它将忽略由 #include <file> 造成的依赖关系。

-MD
	和 -M 相同,但是将结果输出到 .d 文件里。

-MMD
	和 -MM 相同,但是将结果输出到 .d 文件里。

-Wa,[option]
	此选项传递 option 给汇编器。
	如果 option 中间有逗号,就将 option 分成多个选项传递给汇编器。

-x [language] [filename]
	设定文件使用的语言,使后缀名无效。
	对以后多个文件有效,直到其他选项或参数覆盖。
	可选参数比如:
	c c-header cpp-output
	c++ c++-header c++-cpp-output
	assembler assembler-with-cpp, 等等。例如:
	gcc -x c hello.pig

-x none [filename]
	关掉上一个选项,让 gcc 根据文件名后缀,自动识别文件类型。例如:
	gcc -x c hello.pig -x none hello2.c

4. 链接注意事项

4.1. 混合链接

g++ 链接库时,若静态库与动态库相同,默认优先链接动态链接库。

静态库与动态库混合链接时,若要指定静态动态,有如下两种方法:

  1. 静态链接库使用绝对路径,动态链接库使用 -l。例如:

    g++ test.cpp -o test.out /usr/lib64/libstatic.a -L/usr/lib64 -ldynamic
    
  2. 都使用 -l,但在静态链接库前加 -Wl,-Bstatic,动态链接库前加 -Wl,-Bdynamic。例如:

    g++ test.cpp -o test.out -L/usr/lib64 -Wl,-Bstatic -lstatic -Wl,-Bdynamic -ldynamic
    

    最后需以 -Wl,-Bdynamic 结束,作用是让后续的系统库默认使用动态链接。

4.2. 选项顺序

链接时,库要放在目标文件的后面,否则会报 "undefined reference to: xxx" 错误。

具体参见 gcc 手册的如下描述:

It makes a difference where in the command you write this option;
the linker searches and processes libraries and object files in the
order they are specified.  Thus, foo.o -lz bar.o searches library z
after file foo.o but before bar.o.  If bar.o refers to functions in
z, those functions may not be loaded.

参考文章

  1. GitHub - dablelv/backend-cmd: 一个介绍 Linux 后台开发常用命令的开源书籍。
  2. g++ 编译四步骤_g++编译_库克李名的博客-CSDN博客
  3. Makefile学习笔记03|g++编译的四个步骤_g++ makefile_小马同志( ̄^ ̄)ゞ的博客-CSDN博客
  4. gcc -O0 -O1 -O2 -O3 -Os 编译优化等级_Li-Yongjun的博客-CSDN博客

评论