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

时间:2010-01-28 20:14:23

标签: c++ linker ar .a

我有一小段代码依赖于许多静态库(a_1-a_n)。我想将该代码打包到静态库中,并将其提供给其他人。

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

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

有没有办法可以创建一个新的静态库,Y包含X和X所需的所有功能(a_1 - a_n中的选定位),这样我就可以只为人们分发Y来链接他们的程序?


更新:

我看过只是用 ar 转储所有内容并制作一个mega-lib,然而,最终会包含许多不需要的符号(所有.o文件大约为700个但是,MB,静态链接的可执行文件是7 MB)。有没有一种很好的方法只包括实际需要的东西?


这看起来与How to combine several C/C++ libraries into one?密切相关。

6 个答案:

答案 0 :(得分:61)

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

编辑:为了响应您的更新,我知道只选择所需符号的唯一方法是从包含它们的.o文件子集中手动创建库。这很困难,耗时且容易出错。我不知道有任何工具可以帮助做到这一点(并不是说它们不存在),但它会产生一个非常有趣的项目来制作它。

答案 1 :(得分:41)

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

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

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

答案 2 :(得分:17)

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

ar -M <<EOM
    CREATE libab.a
    ADDLIB liba.a
    ADDLIB libb.a
    SAVE
    END
EOM
ranlib libab.a

如果您不删除liba.alibb.a,则可以制作一个&#34;精简档案&#34;:

ar crsT libab.a liba.a libb.a

在Windows上,使用MSVC工具链:

lib.exe /OUT:libab.lib liba.lib libb.lib

答案 3 :(得分:8)

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

答案 4 :(得分:5)

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

  1. 打开要与其他库组合的库(X)项目。
  2. 添加您想要与X结合使用的其他库(右键单击,Add Existing Item...)。
  3. 转到他们的媒体资源,确保Item TypeLibrary
  4. 这将包括X中的其他库,就像您运行

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

答案 5 :(得分:3)

在阅读其余内容之前请注意:此处显示的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

其中lib是你想要包含符号的地方。但是,我认为最先将所有内容复制到一个单独的目录中是最安全的。我不太相信我的脚本(但是,它对我有用;我可以将libgsl.a包含到我的数字库中,并省略-lgsl编译器开关)。