说服gcc忽略系统库,转而使用本地安装的库

时间:2013-12-10 18:23:16

标签: linux gcc linker

我正在尝试构建一个使用boost_serialization和boost_iostreams的简单可执行文件。

#include <fstream>
#include <iostream>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/device/file.hpp>

int main()
{
    using namespace boost::iostreams;
    filtering_ostream os;
    os.push(boost::iostreams::gzip_compressor());
    os.push(boost::iostreams::file_sink("emptyGzipBug.txt.gz"));
}

不幸的是,我正在使用的系统在/ usr / lib /中有一个非常过时的boost_serialization版本,我无法改变它。

当我使用

构建示例时,我非常确定
g++ -o main main.cpp -lboost_serialization -lboost_iostreams

导致链接器错误,因为gcc使用的是boost_serialization的系统版本,而不是我本地安装的版本。将LIBRARY_PATH和LD_LIBRARY_PATH设置为/ home / andrew / install / lib不起作用。当我使用

构建时
g++ -o main main.cpp -L/home/andrew/install/lib -lboost_serialization -lboost_iostreams
然后一切正常。

我的问题是:

  1. 如何让gcc告诉我它使用的库的文件名?

  2. 是否可以设置环境,以便我不必在gcc的命令行中指定本地boost的绝对路径。

2 个答案:

答案 0 :(得分:4)

PS输入以下信息后,我认为我很善良,并为您的具体案例添加所需内容:

g++ -Wl,-rpath,/home/andrew/install/lib -o main main.cpp -I/home/andrew/install/include -L/home/andrew/install/lib -lboost_serialization -lboost_iostreams

gcc本身并不关心这些库。链接器确实;)。 即使链接器需要找到共享库以便它可以解析 符号,它通常不会将这些库的路径存储在可执行文件中。

因此,首先,让我们在链接后找出二进制文件中的实际内容:

$ readelf -d main | grep 'libboost'
 0x0000000000000001 (NEEDED)             Shared library: [libboost_serialization.so.1.54.0]
 0x0000000000000001 (NEEDED)             Shared library: [libboost_iostreams.so.1.54.0]

这就是名字。

实际使用的库由/lib/ld-linux.so.*确定。 在运行时间:

$ ldd main | grep libboost
        libboost_serialization.so.1.54.0 => /usr/lib/x86_64-linux-gnu/libboost_serialization.so.1.54.0 (0x00007fd8fa920000)
        libboost_iostreams.so.1.54.0 => /usr/lib/x86_64-linux-gnu/libboost_iostreams.so.1.54.0 (0x00007fd8fa700000)

通过查看/etc/ld.so.cache找到路径(通常是这样 通过运行ldconfig编译)。您可以使用以下方式打印其内容:

ldconfig -p | grep libboost_iostreams
    libboost_iostreams.so.1.54.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libboost_iostreams.so.1.54.0
    libboost_iostreams.so.1.49.0 (libc6,x86-64) => /usr/lib/libboost_iostreams.so.1.49.0
    libboost_iostreams.so (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libboost_iostreams.so

但由于这只是之前查找的缓存结果, 你对以下的输出更感兴趣:

$ ldconfig -v 2>/dev/null | egrep '^[^[:space:]]|libboost_iostreams'
/lib/i386-linux-gnu:
/usr/lib/i386-linux-gnu:
/usr/local/lib:
/lib/x86_64-linux-gnu:
/usr/lib/x86_64-linux-gnu:
    libboost_iostreams.so.1.54.0 -> libboost_iostreams.so.1.54.0
/lib32:
/usr/lib32:
/lib:
/usr/lib:
    libboost_iostreams.so.1.49.0 -> libboost_iostreams.so.1.49.0

显示在查找结果之前查看的路径。 请注意,如果要链接64位程序,它会找到32位 图书馆首先(或反之亦然)然后将被跳过 不相容。否则,使用找到的第一个。

用于搜索的路径在/etc/ld.so.conf中指定 读取(通常在启动时,或安装新的东西后) 以root身份运行ldconfig时。

但是,优先级将路径指定为冒号分隔列表 环境变量LD_LIBRARY_PATH中的路径。 例如,如果我这样做:

$ export LD_LIBRARY_PATH=/tmp
$ cp /usr/lib/libboost_iostreams.so.1.49.0 /tmp/libboost_iostreams.so.1.54.0
$ ldd main | grep libboost_iostreams
    libboost_iostreams.so.1.54.0 => /tmp/libboost_iostreams.so.1.54.0 (0x00007f621add8000)
然后它找到&#39; libboost_iostreams.so.1.54.0&#39;在/ tmp中(即使它是一个libboost_iostreams.so.1.49.0)。

请注意,您可以通过传递-rpath来硬编码可执行文件中的路径 链接器:

$ unset LD_LIBRARY_PATH
$ g++ -Wl,-rpath,/tmp -o main main.cpp -lboost_serialization -lboost_iostreams
$ ldd main | grep libboost_iostreams
    libboost_iostreams.so.1.54.0 => /tmp/libboost_iostreams.so.1.54.0 (0x00007fbd8bcd8000)

可以通过

显示
$ readelf -d main | grep RPATH
 0x000000000000000f (RPATH)              Library rpath: [/tmp]

您可以使用-print-search-dirs命令行选项显示gcc在编译(链接)时使用的搜索路径:

$ g++ -print-search-dirs  | grep libraries
libraries: =/usr/lib/gcc/x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../x86_64-linux-gnu/lib/x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../x86_64-linux-gnu/lib/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../x86_64-linux-gnu/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib/:/lib/x86_64-linux-gnu/4.7/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/4.7/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../x86_64-linux-gnu/lib/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../:/lib/:/usr/lib/

这可以通过添加-L命令行选项来影响。如果在使用-L选项指定的路径中找不到库,则它会查找通过环境变量GCC_EXEC_PREFIX找到的路径(请参见手册页),如果失败则使用环境变量LIBRARY_PATH。 / p>

使用-v选项运行g ++时,它将打印使用的LIBRARY_PATH。

LIBRARY_PATH=/tmp/lib g++ -v -o main main.cpp -lboost_serialization -lboost_iostreams 2>&1 | grep LIBRARY_PATH
LIBRARY_PATH=/tmp/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/tmp/lib/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../:/lib/:/usr/lib/

最后,请注意,尤其是对于提升(但总的来说),你应该这样做 使用与正确版本匹配的头文件!所以,如果你的图书馆 在运行时链接是版本xyz你应该使用-I命令行选项让g ++找到相应的头文件,或者事情可能没有链接或更糟,导致无法解释的崩溃。

答案 1 :(得分:0)

-nodefaultlibs

       Do not use the standard system libraries when linking.  Only the
       libraries you specify are passed to the linker, and options
       specifying linkage of the system libraries, such as
       -static-libgcc or -shared-libgcc, are ignored.  The standard
       startup files are used normally, unless -nostartfiles is used.

       The compiler may generate calls to "memcmp", "memset", "memcpy"
       and "memmove".  These entries are usually resolved by entries in
       libc.  These entry points should be supplied through some other
       mechanism when this option is specified.

我自己没有使用过它,但是听起来完全像要求的那样。