C++ 将静态库链接到其他静态库

C++ 将静态库链接到其他静态库,c++,linker,unix-ar,.a,C++,Linker,Unix Ar,.a,我有一小段代码,它依赖于许多静态库(a_1-a_n)。我想把这些代码打包到一个静态库中,让其他人可以使用 我的静态库,我们称之为X,编译得很好 我创建了一个使用X函数的简单示例程序,但是当我尝试将它链接到X时,我得到了许多关于库a_1-a_n中缺少符号的错误 有没有一种方法可以让我创建一个新的静态库Y,其中包含X和X所需的所有功能(从a_1-a_n中选择的位),这样我就可以只分发Y供人们链接他们的程序 更新: 我已经研究过如何使用ar转储所有内容,并制作一个大型库,但最终会包含许多不需要的符号

我有一小段代码,它依赖于许多静态库(a_1-a_n)。我想把这些代码打包到一个静态库中,让其他人可以使用

我的静态库,我们称之为X,编译得很好

我创建了一个使用X函数的简单示例程序,但是当我尝试将它链接到X时,我得到了许多关于库a_1-a_n中缺少符号的错误

有没有一种方法可以让我创建一个新的静态库Y,其中包含X和X所需的所有功能(从a_1-a_n中选择的位),这样我就可以只分发Y供人们链接他们的程序


更新:

我已经研究过如何使用ar转储所有内容,并制作一个大型库,但最终会包含许多不需要的符号(所有的.o文件约为700 MB,但是静态链接的可执行文件为7 MB)。是否有一个好的方法只包含实际需要的内容



这看起来与静态库密切相关。

静态库不与其他静态库链接。唯一的方法是使用library/archiver工具(例如Linux上的ar)通过连接多个库来创建一个新的静态库


编辑:响应您的更新,我所知道的仅选择所需符号的唯一方法是从包含符号的.o文件子集手动创建库。这是困难、耗时且容易出错的。我不知道有什么工具可以帮助实现这一点(并不是说它们不存在),但制作一个静态库将是一个非常有趣的项目。

静态库只是
.o
对象文件的存档。使用
ar
(假设使用Unix)提取它们,并将它们打包回一个大型库。

如果您使用的是Visual Studio,则可以执行此操作

VisualStudio附带的库生成器工具允许您在命令行上将库连接在一起。不过,我不知道在可视化编辑器中有什么方法可以做到这一点

lib.exe /OUT:compositelib.lib  lib1.lib lib2.lib

除了在项目属性中链接库依赖项之外,还有另一种在Visual Studio中链接库的方法

  • 打开要与其他库组合的库(X)的项目
  • 添加要与X组合的其他库(右键单击,
    添加现有项…
  • 转到其属性并确保
    项目类型
  • 这将包括X中的其他库,就像您运行

    lib /out:X.lib X.lib other1.lib other2.lib
    

    在Linux或MingW上,使用GNU工具链:

    ar -M <<EOM
        CREATE libab.a
        ADDLIB liba.a
        ADDLIB libb.a
        SAVE
        END
    EOM
    ranlib libab.a
    
    lib.exe /OUT:libab.lib liba.lib libb.lib
    
    在Windows上,使用MSVC工具链:

    ar -M <<EOM
        CREATE libab.a
        ADDLIB liba.a
        ADDLIB libb.a
        SAVE
        END
    EOM
    ranlib libab.a
    
    lib.exe /OUT:libab.lib liba.lib libb.lib
    

    在阅读其余部分之前请注意:这里显示的shell脚本使用起来肯定不安全,而且经过了良好的测试。使用风险自负

    我编写了一个bash脚本来完成这项任务。假设您的库是lib1,需要从中包含一些符号的库是lib2。脚本现在在循环中运行,首先检查lib1中哪些未定义的符号可以在lib2中找到。然后,它用
    ar
    从lib2中提取相应的对象文件,稍微重命名它们,并将它们放入lib1中。现在可能会有更多缺少的符号,因为您从lib2中包含的内容需要lib2中的其他内容,而我们还没有包含这些内容,因此循环需要再次运行。如果在循环的某些过程之后不再有任何更改,即没有来自lib2的对象文件添加到lib1,则循环可以停止

    请注意,
    nm
    仍将包含的符号报告为未定义,因此我将跟踪添加到lib1中的对象文件,以确定是否可以停止循环

    #! /bin/bash
    
    lib1="$1"
    lib2="$2"
    
    if [ ! -e $lib1.backup ]; then
        echo backing up
        cp $lib1 $lib1.backup
    fi
    
    remove_later=""
    
    new_tmp_file() {
        file=$(mktemp)
        remove_later="$remove_later $file"
        eval $1=$file
    }
    remove_tmp_files() {
        rm $remove_later
    }
    trap remove_tmp_files EXIT
    
    find_symbols() {
        nm $1 $2 | cut -c20- | sort | uniq 
    }
    
    new_tmp_file lib2symbols
    new_tmp_file currsymbols
    
    nm $lib2 -s --defined-only > $lib2symbols
    
    prefix="xyz_import_"
    pass=0
    while true; do
        ((pass++))
        echo "Starting pass #$pass"
        curr=$lib1
        find_symbols $curr "--undefined-only" > $currsymbols
        changed=0
        for sym in $(cat $currsymbols); do
            for obj in $(egrep "^$sym in .*\.o" $lib2symbols | cut -d" " -f3); do
                echo "  Found $sym in $obj."
                if [ -e "$prefix$obj" ]; then continue; fi
                echo "    -> Adding $obj to $lib1"
                ar x $lib2 $obj
                mv $obj "$prefix$obj"
                ar -r -s $lib1 "$prefix$obj"
                remove_later="$remove_later $prefix$obj"
                ((changed=changed+1))
            done
        done
        echo "Found $changed changes in pass #$pass"
    
        if [[ $changed == 0 ]]; then break; fi
    done
    
    我将该脚本命名为
    libcomp
    ,因此您可以使用

    ./libcomp libmylib.a libwhatever.a
    

    其中libanywhere是您希望包含符号的位置。然而,我认为首先将所有内容复制到单独的目录中是最安全的。我不太相信我的脚本(不过,它对我来说很有效;我可以将libgsl.a包含到我的数字库中,而不使用-lgsl编译器开关)。

    嗨,尼尔,我已经更新了这个问题——你知道有什么方法只包含必要的.o文件吗?更新——如果你发现自己想这样做,请后退一步,并追求其他东西(除非,正如约翰·克诺勒所指出的,您正在使用VisualStudio)。我花了很多时间在这种方法上,没有得到任何有用的东西。GNU ld工具提供了一个选项
    -r
    ,可以将输出用作ld的输入。如果你链接一次,你应该得到一个可重新定位的链接,那么它就可以替代你的库。在VS2008中,在Library/General下compositelib的项目属性中,如果您选中[x]链接库依赖项,那么如果lib1和lib2是compositelib的依赖项,它将为您执行此操作。这似乎有点问题,我会在每个构建配置中分别设置复选框,而不是在“所有配置”中设置一次。VS2015 IDE-您不使用“其他依赖项”吗在图书管理员/将军的领导下,让更多的图书馆直接链接到你的项目正在建设的图书馆?@davidbak我在过去几天里试图解决这个问题,显然这个选项已经过时了,没有任何作用?很高兴知道,但并没有真正解决OP的问题,由于您将libb.a中的所有内容都包含在联合库中,如果您只需要libb中的几个模块,联合库可能会变得非常大。@ElmarZander但是您可以使用
    ar crsT
    ,它可以执行类似“符号链接”的操作,而不是复制,然后,您只需提供一份数据副本。精简归档主要用于Linux内核v4.19:您好,我使用的是Intel IPP,我构建了自己的函数,我希望所有函数都打包到一个(静态)库中。然而,当我创建lib,然后将项目发送到另一台计算机时,我希望它能够仅使用我创建的lib编译项目,我得到了一个错误,即