Linux gcc/g++链接编译顺序详解

gcc/g++链接时对库的顺序要求

-Ldir
    Add directory dir to the list of directories to be searched for -l. 

-llibrary
-l library
    Search the library named library when linking. (The second
    alternative with the library as a separate argument is only for POSIX
    compliance and is not recommended.)

    It makes a difference where in the command you write this option;
    the linker searches and processes libraries and object files in
    the order they are specified. Thus, `foo.o -lz bar.o‘ searches
    library `z‘ after file foo.o but before bar.o. If bar.o refers to
    functions in `z‘, those functions may not be loaded.

    The linker searches a standard list of directories for the
    library, which is actually a file named liblibrary.a. The linker
    then uses this file as if it had been specified precisely by name.

    The directories searched include several standard system
    directories plus any that you specify with -L.

    Normally the files found this way are library files—archive files
    whose members are object files. The linker handles an archive file
    by scanning through it for members which define symbols that have
    so far been referenced but not defined. But if the file that is
    found is an ordinary object file, it is linked in the usual
    fashion. The only difference between using an -l option and
    specifying a file name is that -l surrounds library with `lib‘ and
    `.a‘ and searches several directories.    

以上来源于gcc手册

对于library的查找

查找需要连接的符号名是从前向后找,根据-L指定的路径顺序查找;不同 目录下的同名的库,只取第一个(从左向右),后面同名库被忽略;

对于符号的查找

从左向右查找,如果是主程序块和静态库,不能定位地址就报错: ‘undefined reference to: xxx’如果是链接成动态库,则假设该符号在load 的

时候地址重定位。如果找不到对应的动态库,则会在load的时候报:“undefined symbol: xxx“这样的错误。

–as-needed对链接动态库的影响

gcc-4.6默认开启ld的–as-needed选项。

--as-needed
--no-as-needed
    This option affects ELF DT_NEEDED tags for dynamic libraries mentioned on the command line after the --as-needed
    option.  Normally the linker will add a DT_NEEDED tag for each dynamic library mentioned on the command line,
    regardless of whether the library is actually needed or not.  --as-needed causes a DT_NEEDED tag to only be emitted for
    a library that satisfies an undefined symbol reference from a regular object file or, if the library is not found in
    the DT_NEEDED lists of other libraries linked up to that point, an undefined symbol reference from another dynamic
    library.  --no-as-needed restores the default behaviour.

--add-needed
--no-add-needed
    These two options have been deprecated because of the similarity of their names to the --as-needed and --no-as-needed
    options.  They have been replaced by --copy-dt-needed-entries and --no-copy-dt-needed-entries.

--copy-dt-needed-entries
--no-copy-dt-needed-entries
    This option affects the treatment of dynamic libraries referred to by DT_NEEDED tags inside ELF dynamic libraries
    mentioned on the command line.  Normally the linker won‘t add a DT_NEEDED tag to the output binary for each library
    mentioned in a DT_NEEDED tag in an input dynamic library.  With --copy-dt-needed-entries specified on the command line
    however any dynamic libraries that follow it will have their DT_NEEDED entries added.  The default behaviour can be
    restored with --no-copy-dt-needed-entries.

    This option also has an effect on the resolution of symbols in dynamic libraries.  With --copy-dt-needed-entries
    dynamic libraries mentioned on the command line will be recursively searched, following their DT_NEEDED tags to other
    libraries, in order to resolve symbols required by the output binary.  With the default setting however the searching
    of dynamic libraries that follow it will stop with the dynamic library itself.  No DT_NEEDED links will be traversed to
    resolve symbols.--以上来源于man手册
--add-needed                Set DT_NEEDED tags for DT_NEEDED entries in   following dynamic libs
--no-add-needed             Do not set DT_NEEDED tags for DT_NEEDED entries   in following dynamic libs
--as-needed                 Only set DT_NEEDED for following dynamic libs if used
--no-as-needed              Always set DT_NEEDED for following dynamic libs

as-needed,意思大概是:只给用到的动态库设置DT_NEEDED。
例如:

g++ -shared a.o -ltest1 -lxxx -lrt -o libtest2.so

当链接生成libtest2.so的时候,如果libtest2.so里面用到了libtest1.so,但是没有用到libxxx.so。
当开启–as-needed选项的时候,就不会链接libxxx.so文件
–as-needed就是忽略链接时没有用到的动态库,只将用到的动态库set NEEDED。

常见错误

1.链接主程序模块或者是静态库的时的‘undefined reference to: xxx’

g++ -Wl,--as-needed -ltest1 -lc -lm -ldl -lpthread -L/home/ocaml/lib/ -lrt -o app main.o

假设main.o依赖libtest1.so中的东西。因为gcc对库的顺序要求(gcc编译时,由左向右)和–as-needed选项的开启(因为libtest1.so在main.o的左边,

所以gcc认为没有使用到它,–as-needed将其忽略),ld忽略libtest1.so,定位main.o的符号的时候当然会找不到符号的定义。

所以会出现‘undefined reference to’这个错误!

正确写法是:是:

g++ -Wl,--as-needed main.o -ltest1 -lc -lm -ldl -lpthread   -L/home/ocaml/lib/  -lrt -o app

2.编译动态库(shared library)的时候会导致一个比较隐晦的错误

编译出来的动态库的时候没有问题,但是加载的时候有“undefined symbol: xxx”这样的错误。假如像这也链接PyGalaxy.so

g++ -shared -Wl,--as-needed -lGalaxyParser -lc -lm -ldl -lpthread -L/home/ocaml/lib/ -lrt -o PyGalaxy.so PyGalaxy.o

load PyGalaxy.so的时候会有上面的运行时错误!

简单分析原因:因为libGalaxyParser.so在mutex.o的左边,所以gcc认为没 有用到它,–as-needed将其忽略。但是前面说的动态库符号解析的特点导 致ld认为某些符号是加载的时候才去地址重定位的。但是 libGalaxyParser.so已经被忽略了。所以就算你写上了依赖的库,load的时 候也会找不到符号。但是为什么没有-Wl–as-needed的时候是正确的呢?没 有的话,ld会set NEEDED libGalaxyParser.so(用前面提到的查看动态库 依赖关系的办法可以验证)。load的时候还是可以找到符号的,所以正确。

正确的链接方式是:

g++ -shared -Wl,--as-needed PyGalaxy.o -lGalaxyParser -lc -lm -ldl -lpthread -L/home/ocaml/lib/ -lrt -o PyGalaxy.so

解决方案

在项目开发过层中尽量让lib是垂直关系,避免循环依赖;越是底层的库,越是往后面写!
例如:
g++ ... obj($?) -l(上层逻辑lib) -l(中间封装lib) -l(基础lib) -l(系统lib) -o [email protected]
这样写可以避免很多问题,这个是在搭建项目的构建环境的过程中需要考虑清楚地,在编译和链接上浪费太多的生命不值得!

原文地址:https://www.cnblogs.com/zhanggaofeng/p/9255668.html

时间: 2024-11-09 15:16:20

Linux gcc/g++链接编译顺序详解的相关文章

linux软连接硬链接操作与详解

1.Linux硬链接和软连接  ln命令,创建连接 .命令参数: 必要参数: -b 删除,覆盖以前建立的链接 -d 允许超级用户制作目录的硬链接 -f 强制执行 -i 交互模式,文件存在则提示用户是否覆盖 -s 软链接(符号链接) -v 显示详细的处理过程     Linux链接分两种,一种被称为硬链接(Hard Link),另一种被称为符号链接(Symbolic Link).默认情况下,ln命令产生硬链接. [硬连接]    硬连接指通过索引节点来进行连接.在Linux的文件系统中,保存在磁盘

gcc/g++等编译器 编译原理: 预处理,编译,汇编,链接各步骤详解

摘自http://blog.csdn.net/elfprincexu/article/details/45043971 gcc/g++等编译器 编译原理: 预处理,编译,汇编,链接各步骤详解 C和C++编译器是集成的,编译一般分为四个步骤: 预处理(preprocessing)  ----------------- cpp/ gcc -E  编译(compilation) ------------------ cc1 / gcc -S 汇编(assembly)  ----------------

gcc/g++链接时.o文件及库的顺序问题

折腾gcc/g++链接时.o文件及库的顺序问题 链接静态库的顺序问题 GCC 编译使用动态链接库和静态链接库--及先后顺序----及环境变量设置总结

CentOS程序包管理器rpm、yum以及程序包编译安装详解

一.程序包管理器RPM和Yum简介 程序包管理器:将编译好的应用程序的各组成文件打包成一个或几个程序包文件,可以更方便地实现程序包的安装.升级.卸载和查询等管理操作. rpm软件包管理器(RPM Package Manager):rpm包存在依赖关系,依赖关系复杂,安装时间很长,虽然可以忽略依赖关系,但是可能会导致程序包安装后无法正常使用. yum程序包管理器( Yellow dog Updater, Modified):yum是基于RPM包管理,自动解决程序包间的依赖关系.根据配置文件的资源地

linux添加开机自启动脚本示例详解

来源: linux添加开机自启动脚本示例详解 linux下(以RedHat为范本)添加开机自启动脚本有两种方法,先来简单的; 一.在/etc/rc.local中添加如果不想将脚本粘来粘去,或创建链接什么的,则:step1. 先修改好脚本,使其所有模块都能在任意目录启动时正常执行;step2. 再在/etc/rc.local的末尾添加一行以绝对路径启动脚本的行;如:$ vim /etc/rc.local#!/bin/sh## This script will be executed *after*

Linux用户态程序计时方式详解

前言 良好的计时器可帮助程序开发人员确定程序的性能瓶颈,或对不同算法进行性能比较.但要精确测量程序的运行时间并不容易,因为进程切换.中断.共享的多用户.网络流量.高速缓存访问及转移预测等因素都会对程序计时产生影响. 本文将不考虑这些影响因素(相关资料可参考<深入理解计算机系统>一书),而仅仅关注Linux系统中用户态程序执行时间的计算方式.除本文所述计时方式外,还可借助外部工具统计耗时,如<Linux调试分析诊断利器——strace>一文中介绍的strace. 本文示例代码的运行环

Linux进程间通信与线程间同步详解(全面详细)

引用:http://community.csdn.net/Expert/TopicView3.asp?id=4374496linux下进程间通信的几种主要手段简介: 1. 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信:   2. 信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身

Apache服务简介及编译安装详解

Apache服务简介及编译安装详解 一.Apache简介 Apache HTTP Server(简称Apache)是Apache软件基金会的一个开放源码的网页服务器,是目前世界上使用最广泛的一种web server,它以跨平台,高效和稳定而闻名,可以运行在几乎所有广泛使用的计算机平台上.Apache的特点是简单.速度快.性能稳定,并可做代理服务器来使用. Apache是用C语言开发的基于模块化设计的web应用,总体上看起来代码的可读性高于php代码,它的核心代码并不多,大多数的功能都被分割到各种

DockerFile 编译语法详解(5)

title: DockerFile 编译语法详解(5) date: 2018-12-16 16:53:20 tags: Docker categories: Docker copyright: true --- Docker是基于Go语言实现的开源容器项目,Docker让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙箱机制,相互之间不会有任何接口,Docker诞生于2013年年初,最初发起者是dotCloud公