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


138

我有一小段代码,它依赖于许多静态库(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)。有没有一种很好的方法可以只包含实际需要的内容?


这看起来与如何将多个C / C ++库合并为一个库密切相关

Answers:


76

静态库不与其他静态库链接。做到这一点的唯一方法是使用您的图书馆员/档案管理员工具(例如Linux上的ar),通过串联多个库来创建一个新的静态库。

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


嗨,尼尔,我已经更新了问题-您知道仅包含必要的.o文件的任何方式吗?
杰森·桑德拉姆

更新-如果您发现自己想要这样做,请退后一步,然后进行其他操作(除非约翰·诺勒指出,否则您正在使用Visual Studio)。我花了很多时间来研究这种方法,却没有得到任何有用的信息。
杰森·桑德拉姆

GNU ld工具提供了一个选项-r,可以将输出用作ld的输入。如果链接一次,您应该可以重新定位,则可以替代您的库。(尝试过)。
哈珀2014年

49

如果使用的是Visual Studio,则可以。

Visual Studio附带的库构建器工具允许您在命令行上将库连接在一起。我不知道如何在可视化编辑器中执行此操作。

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

5
在VS2008中,在Librarian / General下的Compositelib的项目属性中,如果选中[x]链接库依赖项,则如果lib1和lib2是Compositelib的依赖项,它将为您执行此操作。似乎有点错误,我将在每个构建配置中分别设置复选框,而不是在“所有配置”中一次设置。
Spike0xff

2
VS2015 IDE-您是否不使用Librarian / General下的“ Additional Dependencies”将其他库直接链接到项目正在构建的库中?
davidbak's

@davidbak我正在尝试在最近几天解决这个问题,显然该选项已过时,什么也没做?
蒙塔尔多

20

在Linux或MingW上,通过GNU工具链:

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

如果您不删除liba.alibb.a,则可以进行“精简归档”:

ar crsT libab.a liba.a libb.a

在Windows上,使用MSVC工具链:

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

很高兴知道,但实际上并不能解决OP的问题,因为您将libb.a中的所有内容都包含到联合lib中,如果仅需要libb中的几个模块,则联合lib可能会变得很大。
Elmar Zander 2015年

1
@ElmarZander但是您可以使用ar crsT,它执行“符号链接”之类的操作而不是复制,然后只需要传送一份数据即可。
辉煌之星2015年



6

另外,以Link Library Dependencies在项目属性还有另一种方式在Visual Studio链接库。

  1. 打开要与其他库组合的库(X)的项目。
  2. 添加要与X结合使用的其他库(右键单击Add Existing Item...)。
  3. 去他们的财产,并确保Item TypeLibrary

这将包括X中的其他库,就好像您在运行

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

嗨,我使用的是Intel IPP,我构建了自己的函数,我希望将所有函数包装到一个(静态)库中。但是,当我创建库,然后将项目发送到仅希望使用创建的库才能编译项目的其他计算机时,我收到一条错误消息,指出需要Intel IPP库的.h文件。任何想法?
罗伊

lib文件通常是不够的。如果要使用它,则还需要包括头文件。但这不是主题,因为该线程谈论链接,而您的问题是在编译阶段。
evpo 2015年

好。为了帮助您,我将需要更多信息。查看构建输出或日志,看看丢失的.h文件有什么抱怨。我认为它是cl.exe。如果是这样,它将为您提供使用标头的已编译.cpp / .cc / .c文件的名称。.cpp文件的名称是什么,它属于哪个项目?
evpo 2015年

我感到很困惑。在我阅读本文之前,它似乎从未奏效(这就是我的项目已被配置的方式)。但是,既然我已经阅读并重置了项目,那么它显然正在运行。去搞清楚!:(
Mordachai

1
@Mordachai下面的haiku完美地描述了您的体验:昨天工作了今天不工作Windows就是这样
evpo

5

在阅读其余内容之前,请注意:这里显示的shell脚本肯定不安全使用,并且未经良好测试。使用后果自负!

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

请注意,所包含的符号仍被报告为undefined 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

libwhatever是您要在其中包含符号的位置。但是,我认为将所有内容首先复制到一个单独的目录中是最安全的。我不会太信任我的脚本(但是,它对我有用;我可以将libgsl.a包含在我的数字库中,而不必使用-lgsl编译器开关)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.