C++编译过程简介

本文详细介绍了代码编译的四个阶段:预处理、编译、汇编和链接,并重点讨论了静态库.a和动态库.so的生成。静态库的创建只需编译和打包目标文件,而动态库的生成涉及更复杂的步骤,包括使用ld、gcc-shared或libtool。在链接阶段,动态库不会立即进行符号解析和重定位,而是在运行时完成。当遇到Undefined reference to错误时,可以使用nm和ldd命令进行排查。
摘要由CSDN通过智能技术生成

广义的代码编译过程,实际上应该细分为:预处理,编译,汇编,链接。

       预处理过程,负责头文件展开,宏替换,条件编译的选择,删除注释等工作。gcc –E表示进行预处理。

       编译过程,负载将预处理生成的文件,经过词法分析,语法分析,语义分析及优化后生成汇编文件。gcc –S表示进行编译。

       汇编,是将汇编代码转换为机器可执行指令的过程。通过使用gcc –C或者as命令完成。

       链接,负载根据目标文件及所需的库文件产生最终的可执行文件。链接主要解决了模块间的相互引用的问题,分为地址和空间分配,符号解析和重定位几个步骤。实际上在编译阶段生成目标文件时,会暂时搁置那些外部引用,而这些外部引用就是在链接时进行确定的。链接器在链接时,会根据符号名称去相应模块中寻找对应符号。待符号确定之后,链接器会重写之前那些未确定的符号的地址,这个过程就是重定位。

图片

       .so和.a的生成,可执行文件的生成。.a的生成只需要编译阶段,而可执行文件的生成还需要进行链接。静态库文件的生成很简单,主要就是分两步,第一步将源文件生成目标文件,可以使用gcc –c,第二步就是将目标文件打包,可以通过ar实现。所以该过程只要求源文件能够通过gcc –c这个命令即可。

共享库的生成要复杂一些。可以有三种方法生成:
$ld -G
$gcc -shared
$libtool
       用ld最复杂,用gcc -shared就简单的多,但是-shared并非在任何平台都可以使用。-shared 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。GNU提供了一个更好的工具libtool,专门用来在各种平台上生成各种库。在编译生成某个.so文件时,比如liba.so,虽然它里面可能用到了libb.so的东西,但是在生成a.so时是可以不加-lb的,因为so的生成不会进行符号解析和重定位。

       以GCC为例,它在编译静态库/动态库时到底使用了什么命令?比如:gcc –v -shared hello.c -o libhello.so。ld –G用来产生.so文件,也是gcc链接时实际调用的命令。

       生成可执行文件时,如果链接的是静态库,那么链接器会按照静态链接规则,将对应的符号引用进行重定位。而如果是动态库,链接器会将这个符号标记为动态链接的符号,不进行重定位,而是在装载时再进行。所以,尽管是动态链接,如果是已经进入到了链接阶段,那么也需要能在相应的.so中找到某符号的定义,否则也会引发Undefined reference to的链接错误。因为链接器只有通过.so文件,才能判断某符号是个动态链接符号,所以也需要读取这些.so文件,找到相应符号的定义。

       一般而言,编译通过,启动程序触发Undefined reference to的链接错误,可以通过两种方式进行排查。

       第一种,使用linux命令 nm。nm ***.so -u 可以显示所有未定义的符号。


NAME
       nm - list symbols from object files

SYNOPSIS
       nm [-A|-o|--print-file-name] [-a|--debug-syms]
          [-B|--format=bsd] [-C|--demangle[=style]]
          [-D|--dynamic] [-fformat|--format=format]
          [-g|--extern-only] [-h|--help]
          [-l|--line-numbers] [-n|-v|--numeric-sort]
          [-P|--portability] [-p|--no-sort]
          [-r|--reverse-sort] [-S|--print-size]
          [-s|--print-armap] [-t radix|--radix=radix]
          [-u|--undefined-only] [-V|--version]
          [-X 32_64] [--defined-only] [--no-demangle]
          [--plugin name] [--size-sort] [--special-syms]
          [--synthetic] [--target=bfdname]
          [objfile...]

DESCRIPTION
       GNU nm lists the symbols from object files objfile....  If no object
       files are listed as arguments, nm assumes the file a.out.

       For each symbol, nm shows:
        # ... run man nm for detials.

 第二种,使用ldd命令。ldd -r ***.so可以查看所有未定义的符号。

图片

点赞再看,月入百万!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值