我想要发布和归档二进制文件(带有库的可执行文件),它们向后和向前兼容尽可能多的 Linux 发行版,并且整个包可重定位。libc据我了解,还需要提供系统库,因为给定不同版本的libc. 同时libc似乎是耦合的ld-linux
(例如,在 Debian 测试上编译的二进制文件已经无法在 Ubuntu 18.04 LTS 上工作),所以我ld-linux也需要打包。
我的解决方案是将所有可执行文件和库放入一个目录并将 rpath 设置为$ORIGIN(通过使用 链接-Wl,rpath=$ORIGIN或设置chrpath或patchelf)。这使得库可以与可执行文件一起重定位,并且适用于除ld-linux链接器本身之外的所有库。
可以通过以下方式更改动态链接器路径-Wl,--dynamic-linker=/my/path/ld-linux.so或设置它patchelf,但路径必须是绝对路径:
$ORIGIN不起作用./有效,但仅当当前目录与加载器本身相同时才有效(从其他地方启动时,可执行文件会因错误而崩溃)/my/path/ld-linux.so /my/path/myexecutable $@,但这意味着我想避免另一层间接和开销。有没有办法将ld-linux相对于可执行文件的路径直接设置为可执行文件?
也许有一种方法可以静态链接 ld-linux 加载程序?
我们正在编译要在 docker 上运行的 Go 代码,并且正在调查为什么我们的二进制文件没有执行。我们发现它缺少一些动态库(尽管我们想要静态链接的二进制文件)。
这就是它的编译方式。
env GOOS=linux CGO_ENABLED=1 GO111MODULE=on GOPRIVATE=github.com/ourrepo GOPROXY=https://proxy.golang.org go build --installsuffix cgo --ldflags='-extldflags=-static' -o program main.go
使用相同的构建命令CGO_ENABLED=0最终解决了问题,并且输出二进制文件是静态链接的。
现在奇怪的部分是我们有另一个程序使用相同的构建命令,这次是CGO_ENABLED=1and...它是静态链接的!
所以我很困惑为什么在某些情况下CGO_ENABLED=1会产生动态链接,有时会产生静态链接。很高兴提供更多细节。
从文档的描述中,他们似乎做了同样的事情,除了"并非所有系统"支持共享和"只有一些系统"支持符号(不清楚这些是否是同一组系统):
-shared生成一个共享对象,然后可以将其与其他对象链接以形成可执行文件.并非所有系统都支持此选项.对于可预测的结果,还必须指定在指定此选项时用于生成代码(-fpic,-fPIC或模型子选项)的同一组选项.[1]
-symbolic在构建共享对象时绑定对全局符号的引用.警告任何未解决的引用(除非被链接编辑器选项-Xlinker -z -Xlinker defs覆盖).只有少数系统支持此选项.
我怀疑区别在于"生成一个共享对象,然后可以与其他对象链接以形成可执行文件"部分,但这听起来像任何库都是如此.是否意味着生成的共享对象也可以静态链接?
我们正在开发一个具有插件"架构"的应用程序,以允许应用程序的消费者提供他们自己的专有算法.(我们基本上会有一组解析器,并允许第三方提供自己的解析器)
域空间需要非常高的性能,因此进程外绑定不起作用,我们宁愿留下像CORBA和COM这样的重量级东西.
基本上我们正在寻找一个简单的跨平台包装器:
我认为这只是一个环绕loadlibrary()和方法调用导出.我们可以自己写这个,但我们宁愿使用现有的代码,因为我们已经足够了.
同样,吞吐量和性能非常重要.
类似的问题是:
COM的跨平台替代方案 - 这个很接近,但我们只想在进程中进行 - 不需要进程,我们的需求有点"重量轻".
这适用于非托管C++ - 我们不能使用.NET
编辑 - 我们发现了什么
我们发现Poco非常适合我们的需求.作为奖励这个页面是一个非常赞赏的关于C++开发状态和语言方向的评论...
这是一个简单的跨平台包装,我们需要Poco提供.真的没有多少,但仍然节省了我们的时间和测试.运行时没有额外的开销.
我正在开发一个使用GStreamer库的应用程序.为了便于部署,我想收集本地捆绑中的所有GStreamer库.为此我写了一个小脚本,执行以下操作:
otool -L)install_name_tool)(如果您有兴趣,可以查看Ruby脚本.)
但是,我现在看到gst_init呼叫上的运行时错误:
(process:22843): GLib-GObject-CRITICAL **: gtype.c:2458: initialization assertion failed, use g_type_init() prior to this function
(process:22843): GLib-CRITICAL **: g_once_init_leave: assertion `initialization_value != 0' failed
Run Code Online (Sandbox Code Playgroud)
只有在我使用本地化库时才会出现这些错误.
Are there certain 'common pitfalls' when it comes to using install_name_tool? Does anyone have an idea what I could be doing wrong? If you need to know certain details then feel free to ask.
Update
I changed a few things:
我有一个应用程序,称之为Animal.app.Contents/Frameworks比如,它的文件夹里面是一个框架Mammal.framework.Versions/A/Frameworks在框架的文件夹中,我有dog.dylib.安装名称dog.dylib是@ rpath/dog.dylib.对于"Runpath Search Paths"框架的设置,我已经指定了@loader_path/../Frameworks.(我对最后一个设置的推理是dylib的"loader"将是路径的框架的二进制文件Mammal.framework/Versions/A/Mammal.)
我在运行时收到一条错误消息:
Dyld Error Message:
Library not loaded: @rpath/dog.dylib
Referenced from: /Volumes/VOLUME/*/Animal.app/Contents/MacOS/../Frameworks/Mammal.framework/Versions/A/Mammal
Reason: image not found
Run Code Online (Sandbox Code Playgroud)
我已经阅读了Apple的"Run-Path Dependent Libraries"文档和Mike Ash的博客文章@rpath,但我仍然看不出我做错了什么.
gperftools文档说libprofiler应该链接到目标程序:
$ gcc myprogram.c -lprofiler
Run Code Online (Sandbox Code Playgroud)
(不改变程序代码).
然后程序应该使用特定的环境变量运行:
CPUPROFILE=/tmp/profiler_output ./a.out
Run Code Online (Sandbox Code Playgroud)
问题是:libprofile当仅仅加载探测器时,如何有机会启动和完成探查器,但是它的功能没有被调用?
该库中没有构造函数(证明). 库代码中"CPUPROFILE"的所有情况都不会引用启动分析器的任何位置.
我没有想法,在哪里看下一个?
参考以下代码
test_linker.cpp
int main() {
srand(time(0));
for (int i = 0; i < 10; ++i) {
cout << rand() % 10 << endl;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
urandom.cpp
#include <iostream>
using std::cout;
using std::endl;
#include <dlfcn.h>
int rand() throw() {
// get the original rand() function
static auto original_rand = (decltype(&rand)) dlsym(RTLD_NEXT,"rand");
cout << "Call made to rand()" << endl;
return original_rand();
}
Run Code Online (Sandbox Code Playgroud)
当我尝试使用以下命令编译代码时
g++ -std=c++11 -Wall -Werror -Wextra -Wvla -pedantic -O3 urandom.cpp -c
g++ -std=c++11 -Wall -O3 test_linker.cpp urandom.o …Run Code Online (Sandbox Code Playgroud) 根据文档,dlopen与dlopen一起dlsym用于加载库,并获取指向符号的指针。
但这已经是动态加载器/链接器所做的。此外,这两种方法都基于ld.so。
使用时实际上似乎有两个不同之处dlopen:
但是,它似乎并没有激发使用dlopen超标准加载,除了边际示例:
那么,是否有其他用途dlopen比标准动态链接/加载更受欢迎?
这是什么<some symbol>@GOTPCREL(%rip)意思?
我遇到过这一行mov var@GOTPCREL(%rip), %rax,并对奇怪的语法感到有点困惑。
有人可以推荐我应该阅读以理解这一点的相关文档吗?谢谢!
dynamic-linking ×10
c++ ×3
c ×2
gcc ×2
linux ×2
macos ×2
assembly ×1
att ×1
c++11 ×1
elf ×1
go ×1
got ×1
gperftools ×1
installation ×1
linker ×1
relocation ×1
rpath ×1
x86-64 ×1