跳至主要內容

gcc/g++ 常见的编译命令

张威大约 6 分钟linux编译工具

gcc/g++ 常见的编译命令

基本编译命令

  • 编译C程序:gcc filename.c -o outputname
  • 编译C++程序:g++ filename.cpp -o outputname

添加编译选项

  • -g:添加调试信息,用于gdb等调试器。

  • -O2-O3:优化代码,提高运行效率。

  • -Wall:显示所有警告信息。

  • -Wextra:显示额外的警告信息。

  • -Werror:将所有警告当作错误处理。

    gcc -g -O2 -Wall filename.c -o outputname
    g++ main.cc -m32 -g -o main.o	#-m32指定编译为32位程序
    
image-20240310154324639
image-20240310154324639

包含头文件和库

  • -I:指定头文件搜索路径。
  • -L:指定库文件搜索路径。
  • -l:链接指定的库。 例如:gcc -I/path/to/headers -L/path/to/libs -lmylib filename.c -o outputname

编译多个源文件

gcc file1.c file2.c file3.c -o outputname

预处理、编译、汇编和链接

  • -E:只进行预处理,输出到标准输出。
  • -S:编译并汇编,输出汇编代码。
  • -c:编译并汇编,输出目标文件(.o)。

例如,只进行预处理:gcc -E filename.c -o output.i

使用静态库和动态库

静态库:在链接时,库文件会被拷贝到可执行程序中(产品中打包了库文件)

动态库:在链接时库文件会提供自己的位置,在运行时根据位置进行加载(运行时加载的库文件)

特点可执行程序的大小安装难度升级
静态
动态容易
  • 创建静态库
    • 生成目标文件gcc -c mylib.c -o amylib.o
    • 打包成库文件ar crsv libmylib.a mylib.o
  • 创建动态库
    • 编译时生成与gcc -c mylib.c -o amylib.o -fpic
    • 从目标文件生成动态文件gcc -shared -o libmylib.so mylib.o
  • 链接静态库gcc filename.c -L. -lmylib -o outputname
  • 链接动态库:除了上面的链接命令(gcc filename.c -L. -lmylib -o outputname ),还需要在运行时指定动态库的位置,可以使用LD_LIBRARY_PATH环境变量或/etc/ld.so.conf文件来实现。

如何更新动态库🍗🍗🍗

动态库的好处:用户不需要重新链接就能更新库文件

  1. 重新编译库

    gcc -shared -o libmylib.so mylib.c -fPIC
    
  2. 更新版本号:如果服务端;如果不更新协议,可以多个客户端版本共用一个服务端。

    安装新库:需要将它安装到系统中合适的位置。这通常意味着将库文件复制到某个标准库目录,如 /usr/local/lib/usr/lib

    mv libmylib.so libmylib.so.0.0.1
    sudo cp libmylib.so.0.0.1 /usr/lib/	
    
    sudo rm libmylib.so	#删除旧的软链接
    sudo ln -s libmylib.so.0.0.1 libmylib.so #重新建立新链接
    
    image-20240310173458700
    image-20240310173458700
    • 版本号决定了新旧程序
    • 保存所有版本的库文件(因为不知道新版本的库文件是否会产生bug)
    • 建立库文件和libmylib.so的软链接(为了让程序链接或运行过程中能正确找到相应的库文件)
    • 如果更新,重建软链接即可
  3. 更新库缓存:在某些系统上,如 Linux,当新的共享库被安装后,你可能需要更新系统的库缓存。这通常可以通过运行 ldconfig 命令完成,该命令会重新生成 /etc/ld.so.cache 文件,该文件包含了系统中所有共享库的列表。

    sudo ldconfig
    

    或者,如果你的库安装在一个非标准目录,你可能需要编辑 /etc/ld.so.conf 文件并添加你的库目录,然后再运行 ldconfig

gcc -fpic 什么作用(了解)

  1. 主要用于生成位置无关代码(Position Independent Code,简称 PIC)。这种代码的特性在于没有绝对跳转,所有的跳转都是相对跳转,因此代码可以被加载器加载到内存的任意位置并正确执行(因为共享库在加载到内存时,其位置不是固定的,因此必须能够处理这种不确定性)。
  2. 使用 -fPIC 选项编译的源文件在引用函数头文件时,有更宽松的尺度。例如,只需要包含函数的声明头文件,即使没有相应的 C 文件来实现这些函数,编译成共享库(.so 文件)也可以成功

ar crsv 作用

ar 是 Unix-like 系统中的一个工具,用于创建、修改和提取静态库文件(通常具有 .a 扩展名)

  • c:创建一个库。如果库已经存在,则替换它。
  • r:将文件插入库中。如果文件已存在于库中,则替换它。
  • s:创建或更新库的目标文件索引。这对于加速链接过程很有用,因为链接器可以使用索引来快速找到库中的特定符号。
  • v:详细模式。显示正在执行的操作的详细信息。

示例

当你使用 ar crsv libname.a file1.o file2.o 这样的命令时,你实际上是在告诉 ar

  1. 创建一个名为 libname.a 的静态库(如果它不存在的话)。
  2. file1.ofile2.o 这两个目标文件添加到库中(如果它们已经存在于库中,则替换它们)。
  3. 更新或创建库的索引。
  4. 显示执行过程中的详细信息。

同时存在动态库(共享库)和静态库

  1. 默认行为:在许多系统中,如果没有显式指定,链接器默认会优先链接到因为它们通常更小,多个程序可以共享同一个库文件,从而节省磁盘空间
  2. 链接器选项:链接器通常接受一些选项来控制它应该优先链接到哪种类型的库。例如,GCC 链接器接受 -static-shared 选项来分别指示链接器优先链接到静态库或动态库。

如果你想要控制链接的优先级,你可以使用以下策略:

  • 显式指定库文件:在链接时,你可以直接指定要链接的库文件的路径。例如,使用 -L 选项来添加库文件的搜索路径,并使用 -l 选项来指定库名。如果你想要链接到静态库,你可以直接指定静态库文件的路径(包括 .a 扩展名)。🍔
gcc your_program.o -L/path/to/libs -l:libmylib.a -o your_program
  • 使用链接器选项:使用 -static 选项告诉链接器优先链接静态库。🍔
gcc your_program.o -static -lmylib -o your_program_static
  • 修改环境变量:某些系统允许通过设置环境变量(如 LD_LIBRARY_PATH 对于运行时动态库搜索,或者 LIBRARY_PATH 对于链接时库搜索)来影响库的搜索顺序。