本文采用知识共享署名 4.0 国际许可协议进行许可,转载时请注明原文链接,图片在使用时请保留全部内容,可适当缩放并在引用处附上图片所在的文章链接。
常用的gcc编译命令
GCC Make CMake
GCC,Make,以及CMake,GCC是C/C++语言的编译工具,Make是增量式(编译)批处理工具,CMake是Make脚本生成工具。 在现代C/C++项目的构建中,它们的关系如下。
1
2
|
cmake make gcc
CMakelist.txt -----> Makefile ----> Cmds ---> Binary
|
GCC
编译流程
1
2
3
|
-E -S -c
b.c ------> b.i ------> b.s ------> b.o ------> a.out
gcc gcc as ld
|
- -E,(prEprocessing),执行到预处理步骤之后,即处理C/C++源码中#开头的指令,包括宏展开以及#include头文件引入等等。 该指令默认不输出文件,可以使用-o指令输出约定后缀为*.i的文件。*
- -S,(aSsembly),执行到编译步骤之后,生成汇编文件,但不生成二进制机器码。 该指令默认的输出文件后缀为*.s。
- -c,(compilation),执行到汇编步骤之后,调用工具as,从汇编码生成二进制机器码,但不进行链接。 该指令默认的输出文件后缀为*.o(object)。
- 不带以上参数调用gcc将会完整执行以上流程,即执行到到链接(linking)步骤之后。 链接步骤实际上调用链接工具ld来执行,会将源码生成的二进制文件,库文件,以及程序的启动部分进行组合,从而形成一个完整的二进制可执行文件。
- 特别的,使用指令-o,(output),可以指定输出文件的名称。 例如gcc b.c -o b.bin,将生成可执行文件b.bin,而不是默认的a.out。
编译选项
- cpu架构的优化选项,通常是-mcpu(将被取消);-march,-mtune
- 通过
-Wall参数启用所有警告
- 使用-save-temps参数产生所有的中间步骤的文件
1
|
a.out main.c main.i main.o main.s
|
-
使用-l参数链接共享库
-
使用-Werror将警告升级为错误
-
使用-fPIC产生位置无关的代码
当产生共享库的时候,应该创建位置无关的代码,这会让共享库使用任意的地址而不是固定的地址,要实现这个功能,需要使用-fPIC参数。
1
2
|
$ gcc -c -Wall -Werror -fPIC Cfile.c
$ gcc -shared -o libCfile.so Cfile.o
|
参数-V提供详细的信息,打印出gcc编译一个文件的时候所有的步骤。
1
2
3
4
5
6
7
8
9
10
11
|
$ gcc -Wall -v main.c -o main
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-linux-gnu/4.6/lto-wrapper
Target: i686-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.3-1ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=i686-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu
Thread model: posix
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
...
...
...
|
参数D可以用作定义编译时的宏。
1
2
3
4
5
6
7
8
9
10
11
|
#include<stdio.h>
int main(void)
{
#ifdef MY_MACRO
printf("\n Macro defined \n");
#endif
char c = -10;
// Print the string
printf("\n The Geek Stuff [%d]\n", c);
return 0;
}
|
1
2
3
4
|
$ gcc -Wall -DMY_MACRO main.c -o main
$ ./main
Macro defined
The Geek Stuff [-10]
|
可以看到宏被定义了,并打印出了结果。
如果没有使用-static,默认使用libstdc++共享库,而-static-libstdc++可以指定使用libstdc++静态库。
1
2
3
4
5
6
7
8
9
10
|
gcc -M main.c
main.o: main.c /usr/include/stdc-predef.h /usr/include/stdio.h \
/usr/include/features.h /usr/include/sys/cdefs.h \
/usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
/usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
|
gcc参数可以从文件中读取,通过@后跟文件名的方式提供, 多个参数可以使用空格区隔。
1
2
|
$ cat opt_file
-Wall -omain
|
opt_file包含编译参数。
使用@参数:
1
2
3
4
5
6
|
$ gcc main.c @opt_file
main.c: In function ‘main’:
main.c:6:11: warning: ‘i’ is used uninitialized in this function [-Wuninitialized]
$ ls main
main
|
输出结果表明参数的确从文件中读取了,并且正确的应用到编译过程中。
通过这个参数, char类型被看作为 unsigned char类型。
- 使用
-fsigned-char将char解释为有符号的char
-Wl,–no-as-needed
选项 -Wl,--no-as-needed 是一个链接器选项,用于告诉链接器在链接时不应该忽略库中未使用的符号。当使用此选项时,即使库中未使用的符号也会被链接到可执行文件中,以确保这些符号在运行时可用。 这个选项通常在编写共享库时使用,因为共享库需要导出所有的符号,以便其他程序可以使用这些符号。但是,如果链接器在链接时忽略了未使用的符号,这些符号将不会被导出,这可能会导致共享库无法正常工作。 需要注意的是,这个选项可能会导致可执行文件的大小增加,并且可能会导致一些未使用的符号被链接到可执行文件中,这可能会增加可执行文件的运行时开销。
-Wl,–export-all-symbols
选项 -Wl,--export-all-symbols 是一个链接器选项,用于导出共享库或目标文件中的所有符号。当使用此选项时,库或目标文件中定义的所有符号(函数、变量等)将对链接到它的其他程序可见。 当您想要创建一个共享库可供其他程序使用,并且希望确保库中的所有符号对这些程序可见时,此选项非常有用。 请注意,此选项特定于 GNU 链接器( ld ),可能在其他系统或链接器上不可用。
CMAKE