uml*_*ute 5 linker gcc weak-linking jack
我在使用包含弱符号和--as-needed链接器标志的库时遇到了麻烦.
(这使用了Jack库)
$ cat <<EOF >myjack.c
#include <jack/weakjack.h>
#include <jack/jack.h>
int main() {
if (jack_client_opent)
jack_client_open("foobar", JackNoStartServer, 0, 0);
else return 1;
return 0;
}
EOF
$ gcc -o myjack myjack.c -Wl,--no-as-needed -ljack
$ ./myjack && echo "ok" || echo "K.O."
ok
$ ldd myjack | grep jack
libjack.so.0 => /usr/lib/x86_64-linux-gnu/libjack.so.0 (0x00007f16f615f000)
$ gcc -o myjack myjack.c -Wl,--as-needed -ljack
$ ./myjack && echo "ok" || echo "K.O."
K.O.
$ ldd myjack | grep jack
$
Run Code Online (Sandbox Code Playgroud)
(示例代码被编辑为不再是段错误,因为段错误不是我的实际问题)
似乎问题是:
杰克宣称所有符号都是弱的(如果我包含的话<jack/weakjack.h>).这对我很好; 我确实希望我的符号保持弱势.ESP.我的程序与OSX(-weak_framework Jackmp)上的jack弱连接,需要包括<jack/weakjack.h>
链接时--as-needed,链接器会排除任何不引用至少一个非弱符号的库.从联机帮助页:
--as-needed导致仅为库中发出DT_NEEDED标记,该库在链接中的该点满足来自常规对象文件的非弱未定义符号引用
--as-needed默认启用.现在我认为这--as-needed是一个很好的链接器功能,可以摆脱许多真正不需要的运行时依赖项.
但是,我没有看到为什么弱依赖被认为根本没有依赖.对我来说,弱依赖是启用可选功能.我确实希望在可能的情况下启用这些功能,并且决定这是否可行应该是运行时决定.使用当前行为,它成为编译时决策.(如果我想要,我会通过一些预处理器魔术禁用相关代码).
一种解决方案显然只是添加--no-as-needed到链接器标志.我不想这样:我确实想要摆脱过度链接,如果我的发行版(或编译我的二进制文件的人)认为这是要做的事情.
所以我可能as-needed在我已知的弱库中链接后打开:
gcc -o myjack myjack.c -Wl,--no-as-needed -ljack -Wl,--as-needed ...
Run Code Online (Sandbox Code Playgroud)
但是这也感觉不对,因为我强制需要的库之后的所有库都被迫--as-needed(这可能不是我的发行版或编译我的二进制文件的人认为这是要做的事情).它似乎也为构建链添加了很多东西,只是因为某些库恰好只输出弱符号.我不想手动跟踪执行此操作的所有库.
我当然也可以不包括在内<jack/weakjack.h>.包含它的原因是因为应用程序也可以在OSX上运行,我希望可选地依赖于JACK框架(所以我链接-weak_framework Jackmp),并且在没有该框架的情况下保持我的程序可运行.
我真的不想混淆我的应用程序代码,因为各种平台上的链接器之间的细微差别.这可能是我所有这一切的主要问题:为什么我应该为我的应用程序添加特定于平台的代码以满足不同的链接器细节 - 我可能可以添加特定于功能的代码,例如不包括weakjack.h如果编译器没有等效的-weak_library或-weak_framework; 但目前似乎我能得到的最接近的东西#ifdef __APPLE__让我在这种情况下不寒而栗.
所以我真的很喜欢一些选项来强制只有弱符号的库才能被甩掉.
有这样的事吗?
Mik*_*han 10
我在使用包含弱符号和--as-needed链接器标志的库时遇到问题.
不你不是.
找出你的libjack.so位置,例如
$ locate libjack
/usr/lib/x86_64-linux-gnu/libjack.so
/usr/lib/x86_64-linux-gnu/libjack.so.0
/usr/lib/x86_64-linux-gnu/libjack.so.0.1.0
...
Run Code Online (Sandbox Code Playgroud)
然后用于nm检查JACK API的符号类型libjack.so:
$ nm -C -D /usr/lib/x86_64-linux-gnu/libjack.so | grep jack_
000000000000e7e0 T jack_acquire_real_time_scheduling
000000000000d530 T jack_activate
000000000002ccf0 T jack_client_close
000000000000e820 T jack_client_create_thread
....
....
000000000000f340 T jack_uuid_empty
000000000000f320 T jack_uuid_parse
000000000000f2e0 T jack_uuid_to_index
000000000000f330 T jack_uuid_unparse
Run Code Online (Sandbox Code Playgroud)
你会发现它们都是类型T(=文本部分中的普通全局符号:) man nm.有是
在图书馆的几个弱符号:
$ nm -C -D /usr/lib/x86_64-linux-gnu/libjack.so | egrep ' (w|W) '
w __cxa_finalize
w __gmon_start__
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
0000000000025410 W std::ctype<char>::do_widen(char) const
0000000000014c10 W void std::vector<unsigned short, std::allocator<unsigned short> >::_M_emplace_back_aux<unsigned short const&>(unsigned short const&)
0000000000014b10 W std::pair<std::_Rb_tree_iterator<unsigned short>, bool> std::_Rb_tree<unsigned short, unsigned short, std::_Identity<unsigned short>, std::less<unsigned short>, std::allocator<unsigned short> >::_M_insert_unique<unsigned short>(unsigned short&&)
0000000000014ad0 W std::_Rb_tree<unsigned short, unsigned short, std::_Identity<unsigned short>, std::less<unsigned short>, std::allocator<unsigned short> >::_M_erase(std::_Rb_tree_node<unsigned short>*)
Run Code Online (Sandbox Code Playgroud)
但它们都不在JACK API中.没有什么可以做的,你可以libjack.so改变你的改变.表征问题的正确方法是:
我无法将库与--as-needed链接器标志链接到程序,在该程序中我决定削弱对该库的所有引用
JACK API的定义符号引用libjack.so都很强大.您编写了一个程序,指示编译器在您的目标代码中发出对JACK API的弱未定义引用的符号,并且您发现,根据需要的链接,这些弱引用无法强制链接libjack.so以提供它们缺少定义.
似乎问题是:
jack将所有符号声明为弱(如果我包括).
当链接--as-needed时,链接器会排除任何不引用至少一个非弱符号的库.
某些操作系统(例如Ubuntu-16.04LTS)默认启用--as-needed.
最后两点是正确的.链接共享库的发行版之间的分裂 按需默认和发行版不追溯到Debian的喘息,到2013年,它走过去,视需要.从那以后,Debian派生的发行家族也纷纷效仿,而RedHat/Fedora部落则坚持现状.
第一点很困惑.libjack.so正如我们已经指出的那样,导出一个强定义的JACK API,你不能通过编写和编译新代码来改变它.如果您<jack/weakjack.h>在一个源文件中包含,那么您在代码中声明所有JACK API符号都很弱,并且编译器将为您提供一个仅包含对JACK API的弱引用的目标文件.<jack/weakjack.h>
只定义具有该效果的宏.
如果像旧的和主要的linux库一样libjack
拙劣地适应了所需的分裂,那将是令人惊讶的.我怀疑你忽略了一些小字jack/weakjack.h:
详细说明
开发人员面临的一个挑战是利用新版本[JACK]中引入的新功能,同时仍然支持旧版本的系统.通常,如果应用程序使用库/ API中的新功能,则无法在不支持该功能的库/ API的早期版本上运行.当尝试使用该功能时,此类应用程序将无法启动或崩溃.使用弱链接符号可以解决此问题.
...
一个具体的例子会有帮助.假设有人使用JACK客户端版本,我们称之为"Jill".Jill与包含API的新部分的JACK版本(例如,jack_set_latency_callback())相关联,并且如果可用则希望使用它.
当Jill在具有适当"J"版本的新系统上运行时,此功能将完全正常使用.但是如果Jill在具有旧版JACK的系统上运行,则该功能不可用.
使用正常的符号链接,只要有人试图使用"旧"版本的JACK运行Jill,就会产生启动错误.但是,在版本0.116.2之后添加到JACK的函数都被声明为具有"弱"链接,这意味着它们的abscence在程序启动期间不会导致错误.相反,Jill可以测试符号jack_set_latency_callback是否为null.如果为null,则表示此计算机上安装的JACK太旧而无法支持此功能.如果它不为null,那么Jill可以像使用API中的任何其他函数一样使用它.例如:
Run Code Online (Sandbox Code Playgroud)if (jack_set_latency_callback) { jack_set_latency_callback (jill_client, jill_latency_callback, arg); }但是,有些客户端可能希望将此方法用于 JACK API的早于0.116.2的部分.例如,他们可能想要查看 在运行时是否存在像jack_client_open()这样的API的真正旧基本部分.
此类客户端应在任何其他JACK标头之前包含<jack/weakjack.h>. 这将使整个JACK API受到弱连接的影响,因此 可以在运行时检查是否存在 任何和所有函数.重要的是要了解很少有客户需要这样做 - 如果您使用此功能,您 应该有明确的理由这样做.
[强调补充]
这清楚地表明,jack/weakjack.h只有在引用每个JACK API符号之前测试每个JACK API符号的定义,它才能成功地运行一个程序,就像你自己一样,采取包括为了削弱对整个JACK API的引用的特殊步骤.并处理未定义的情况.你的程序不符合.这个做了:
myjack1.c
#include <jack/weakjack.h>
#include <jack/jack.h>
#include <stdio.h>
int main() {
if (jack_client_open) {
jack_client_open("foobar", JackNoStartServer, 0, 0);
} else {
puts("`jack_client_open` is not available");
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
并做到这一点:
myjack2.c
#include <jack/weakjack.h>
#include <jack/jack.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
int main() {
jack_client_t * (*jack_client_open_fp)
(const char *, jack_options_t,jack_status_t *,...) = jack_client_open;
if (!jack_client_open_fp) {
void * dsoh = dlopen("libjack.so",RTLD_LAZY);
if (!dsoh) {
fputs("`libjack` is not available\n",stderr);
exit(EXIT_FAILURE);
}
*(void**)(&jack_client_open_fp) = dlsym(dsoh,"jack_client_open");
if (!jack_client_open_fp) {
fputs("`jack_client_open` is not available\n",stderr);
exit(EXIT_FAILURE);
}
}
jack_client_open_fp("foobar", JackNoStartServer, 0, 0);
exit(EXIT_SUCCESS);
}
Run Code Online (Sandbox Code Playgroud)
它概述了可发现API的常用方法 - 适用于在可能根本不提供的系统上安装和运行的程序libjack.所以你建立它没有参考libjack
像:
gcc -o myjack2 myjack2.c -ldl
Run Code Online (Sandbox Code Playgroud)
在Ubuntu 17.04上 - 确实提供了libjack- 它可能会像:
$ ./myjack2
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for 4294967295, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for 4294967295, skipping unlock
Run Code Online (Sandbox Code Playgroud)
因此,图书馆的条款与条件在按需连接方面处于良好状态.这似乎让你在被独立不满的位置按需联动工作的它,而不是在不同的方式,将允许您将所有引用削弱到JACK API,仍然可以得到的方式libjack将需要你对其API符号的弱引用: -
我不明白为什么弱依赖被认为根本没有依赖.对我来说,弱依赖是启用可选功能.我确实希望在可能的情况下启用这些功能,并且决定这是否可行应该是运行时决定.使用当前行为,它成为编译时决策.
您认为弱符号引用导致对定义符号的库的弱连接依赖性的观点与GNU链接器没有关系.如果程序的链接需要libary提供的符号定义,程序依赖于库; 否则它不依赖于那个图书馆:没有弱的和强烈的依赖程度.(Darwin Mach-O链接器确实支持同源区别)
有弱的符号,而不是默认和通常的类型,这是强大的.{weak | strong}符号是{weakly | strong} 引用符号的简写,因为在多个链接器输入文件中可能引用相同的符号,有时或总是弱,有时或总是强.
强符号必须在链接中具有一个定义引用.
弱符号是这样的:
链接器没有义务为它找到定义:它可能在输出文件中保持未定义
链接器没有义务在不同的输入文件中对同一符号的多个弱定义进行故障.如果链接中只有一个定义引用很强,则选择该强定义并忽略所有弱定义.如果链接中的所有定义引用都很弱,则链接器将随机选择一个引用.
从第一部分可以得出一个未定义的弱引用的符号不会产生联动相关性在所有.不需要定义,并且不需要定义
的事实是程序员(例如#include <jack/weak_jack.h>)或可能由编译器做出决定的结果.如果指向仅链接所需的共享库,则链接库应该链接库以提供您或编译器已告知它不需要定义的符号定义,这是不合理的.
如果连接器均会那样,你的情况,这将构成一个链接时间决定,冻结和启用的,通过包括API jack/weak_jack.h,你已经表示要完全保留了运行时发现.
链接您的问题程序-no-as-needed是成功的,以扼杀程序中的错误.该错误是通过包含jack/weak_jack.h
您自己承诺整个API的运行时发现,但不履行该承诺,而是将API的可用性视为理所当然.因此,具有按需链接的段错误.链接-no-as-needed只是取消包含的效果jack/weak_jack.h.包括它说你的程序
不需要任何API定义:-no-as-needed说,无论它们是什么,你无论如何都要得到它们.
在所有的API JACK后版本0.116.2是弱而不诉诸定义的事实光jack/weak_jack.h,我认为你根本就没有这头的任何使用,除非你确实计划程序,将有所作为上libjack失踪的主人.如果您
正在计划,那么你也没办法运行时使用的所有JACK的API,发现无论联动的约定,因为你不能链接
libjack反正.
如果没有,那么只需链接libjack,如果你仅仅是打电话jack_client_open,你的程序,在任何主机上,将动态链接所有的API定义,不管他们是在该主机上,因为你参考jack_client_open(在没有<jack/weak_jack.h>将)libjack 需要,无论是这对于进行链接的链接器是否重要.如果你想成为翻过API版本兼容,那么你就需要实现运行时检测
的记录
是任何API的文档与属性JACK_WEAK_EXPORT
-而不是JACK_OPTIONAL_WEAK_EXPORT, or JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT:后者表示只能通过强行削弱基本的API <jack/weak_jack.h>.
| 归档时间: |
|
| 查看次数: |
2572 次 |
| 最近记录: |