Linux 说服gcc忽略系统库而支持本地安装的库

Linux 说服gcc忽略系统库而支持本地安装的库,linux,gcc,linker,Linux,Gcc,Linker,我正在尝试构建一个使用boost_序列化和boost_iostreams的简单可执行文件 #include <fstream> #include <iostream> #include <boost/archive/xml_iarchive.hpp> #include <boost/archive/xml_oarchive.hpp> #include <boost/iostreams/filtering_stream.hpp> #inc

我正在尝试构建一个使用boost_序列化和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"));
}
导致链接器错误的原因是gcc使用boost_序列化的系统版本,而不是我的本地安装版本。将LIBRARY\u PATH和LD\u LIBRARY\u PATH设置为/home/andrew/install/lib无效。当我使用

g++ -o main main.cpp -L/home/andrew/install/lib -lboost_serialization -lboost_iostreams
然后一切都开始了

我的问题是:

  • 如何让gcc告诉我它使用的库的文件名


  • 是否可以设置环境,这样我就不必在gcc的命令行上指定本地boost的绝对路径


  • 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)
    
    然后在/tmp中找到“libboost_iostreams.so.1.54.0”(尽管它是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]
    
    请注意,LD_LIBRARY_PATH甚至优先于-rpath,除非 您还传递了-Wl、-disable-new dtag以及-rpath,前提是您正在链接一个可执行文件并且链接器支持 这面旗

    您可以使用-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

    当您使用-v选项运行g++时,它将打印所使用的库路径

    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/
    
    最后,请注意,特别是对于boost(但一般来说),您应该 使用与正确版本匹配的头文件!那么,如果你所在的图书馆 运行时与的链接是版本xyz。您应该使用-I命令行选项让g++查找相应的头文件,否则可能无法链接或更糟,导致无法解释的崩溃。

    -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.
    

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

    对于您的“系统”库版本,您可能会错过一些
    -I
    g++
    的选项(您应该首先将
    -Wall-g
    传递到
    g++
    )。你应该使用像
    -v
    这样的构建器,它应该提供一些有关它正在查找包含文件的文件夹路径的信息。
    -v
    告诉我它在正确的位置查找包含,但不告诉我库路径“是否可以设置环境,以便我不必指定”这是可能的。一切皆有可能。您拥有整个操作系统和开发工具链的源代码。但是,不建议这样做。请注意,编译时链接器不会查找SO_名称(由readelf显示)。使用-lfoo查找libfoo.so。因此,在库路径中有一个libfoo.so指向真正的库,它的名称被硬编码在里面。如果SO_名称(在运行时链接期间使用)与该文件名不同,则需要另一个符号链接,以使运行时链接器找到它!)。例如,如果SO_名称为libfoo.SO.1,文件名为libfoo.SO.1.4,则需要从libfoo.SO.1到libfoo.SO.1.4的符号链接,以便在运行时工作;)。
           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.