g++常用命令行格式与参数
gcc 和 g++分别是 GNU 的 C 和 C++的编译器,在 g++编译器工作时,总共需要 4 个步骤:
- 预处理.cpp 文件生成.i 文件。由预处理器 cpp 完成。
- 将预处理后的文件转换成汇编语言,生成.s 文件。有编译器 egcs 完成。
- 将汇编语言转换为目标代码,生成.o 文件。由汇编器 as 完成。
- 连接目标代码,生成可执行程序。由链接器 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 | 禁止将asm 、inline 和typeof 作为关键字 | |
-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,option | 将option 传递给汇编程序,如果有多个选项可以使用逗号分开 | |
-Wl,option | 将option 传递给连接程序,如果有多个选项可以使用逗号分开 | |
-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 语言进行编译。主要用于以下情况中:
- C++语言中调用 C 语言的代码。
- 在 C++的头文件中使用。
- 交替使用 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)
,并且类的友元函数前也需要添加这个标识。
动态链接库的使用
对于动态链接库,可以在程序中包含其头文件,并将其加入链接即可调用其中的内容。