g++常用命令行格式与参数

gcc 和 g++分别是 GNU 的 C 和 C++的编译器,在 g++编译器工作时,总共需要 4 个步骤:

  1. 预处理.cpp 文件生成.i 文件。由预处理器 cpp 完成。
  2. 将预处理后的文件转换成汇编语言,生成.s 文件。有编译器 egcs 完成。
  3. 将汇编语言转换为目标代码,生成.o 文件。由汇编器 as 完成。
  4. 连接目标代码,生成可执行程序。由链接器 ld 完成。

g++常用的参数和使用格式可参考下表。

参数功能使用格式
-c只激活预处理、编译和汇编生成.o 文件g++ -c hello.cpp
-S只激活预处理和编译,生成.s 文件g++ -S hello.cpp
-E只激活预处理,不生成文件需要重定向输出g++ -E hello.cpp > pp.txt
-o指定目标.o 文件的名称g++ -o hello.exe hello.cpp
-ansi关闭 GNU C++中与 ANSI C++不兼容的特性
-fno-asm禁止将asminlinetypeof作为关键字
-fPIC生成与位置无关的代码
-include-file包含某个代码,相当于在代码中使用#include <filename>g++ hello.cpp -include /roo/pp.h
-Dmarco相当于#define macro
-Dmarco=defn相当于#define macro=defn
-Umacro相当于#undef macro
-ldir指定#inlcude对于头文件的查找目录,多个目录使用:分隔
-Wa,optionoption传递给汇编程序,如果有多个选项可以使用逗号分开
-Wl,optionoption传递给连接程序,如果有多个选项可以使用逗号分开
-llibrary指定编译时使用库g++ -lcurses hello.cpp
-Ldir指定编译时搜索库的路径
-On编译器的优化选项,可以取 0-3,分别从无优化到最高优化
-static禁止使用动态链接库
-shared尽量使用动态链接库

生成静态链接库

静态链接库使用-static选项进行编译,常用以下命令:

# 编译相关的cpp源文件,以下命令生成hello.o
g++ -c hello.cpp
# 使用ar创建静态库文件,cr命令通知ar将.o文件封装
ar cr libstatic.a hello.o

无论 Linux 还是 Windows,在输出静态链接库时都需要使用打包工具,将.o 文件或者.obj 文件打包为一个集合,静态库中的内容会在打包时进行编号和索引。

生成动态链接库

Windows 与 Linux 的可执行文件格式不同,所以在生成动态链接库时会有一些差异。

  • Windows 系统中可执行文件为 PE 格式,动态链接库需要一个DllMain函数作为初始化的入口,被导出的函数需要使用__declspec(dllexport)关键字声明。
  • Linux 系统中可执行文件为 ELF 格式,动态链接库不需要初始化入口,也不需要任何额外的声明。

编译动态链接库常用以下命令:

g++ -m32 hello.cpp -fPIC -shared -o libhello.so

参数-m32表示生成 32 位动态链接库,-m64表示生成 64 位动态链接库。-fPIC-shared通常同时使用来生成动态链接库。

在使用 MinGW(g++的 Windows 版本)中创建动态链接库时,应该同样使用__declspec(dllexport)进行修饰。直接使用-shared生成的动态链接库中导出的函数尾部是带有@nn标记的,可以通过在编译时附加-Wl,--kill-at选项予以去除。使用 MinGW 编译的动态链接库一般会依赖libgcc-xx.dll或者libg++-xx.dll,这可以通过在编译时使用-static-libgcc-static-libg++将这两个库静态链接以去除。

关于extern "C"

很多生成动态链接库的代码中,都会出现这个声明。extern "C"表示其中的这部分代码按照 C 语言进行编译。主要用于以下情况中:

  1. C++语言中调用 C 语言的代码。
  2. 在 C++的头文件中使用。
  3. 交替使用 C 语言和 C++语言进行开发。

通常头文件中会这样书写以兼容两种语言:

#ifndef LIBRARY_A
#define LIBRARY_A
#ifndef __cplusplus
extern "C" {
#endif
    //其他声明内容
#ifndef __cplusplus
}
#endif

C 语言不支持函数重载,所以需要使用extern "C"来解决函数重名的问题。

__declspec的用法

__declspec是指定给定类型实例与微软相关的存储方式,是一种扩展定义,不包含在 ANSI 标准中。这个扩展定义简化并标准化了 C++关于微软的扩展。__declspec的用法为__declspec(扩展spec修饰符),下表中为常用的修饰符,一个声明中可以使用多个修饰符,修饰符之间使用空格隔开。

修饰符功能
align(n)仅用于 C++,控制数据的对齐
allocate("segname")为数据指定存储的数据段
dllimport从 dll 导入函数或者数据
dllexport向 dll 中导出函数或者数据、对象等,可免去模块定义.def 文件

在 Windows 下使用 MinGW 生成动态链接库需要在被导出的标识符,例如类名后添加__declspec(dllexport),并且类的友元函数前也需要添加这个标识。

动态链接库的使用

对于动态链接库,可以在程序中包含其头文件,并将其加入链接即可调用其中的内容。