在OSX上链接可执行文件

3
在Windows上,可以使用导出的符号动态链接到可执行文件。例如以下代码:
// main.c
void __declspec(dllexport) interface_function() {}
int main() {}

// ext.c
void interface_function();
void extension_function() {
    interface_function();
}

使用以下命令:

cl.exe main.c
cl.exe ext.c /LD /link main.lib

将生成可执行文件 main.exe,静态库 main.lib 用于隐式链接,以及动态库 ext.dll

在OSX中,可以通过共享库来实现类似的行为:

// main.c
void interface_function() {}
int main() {}

// ext.c
void interface_function();
void extension_function() {
    interface_function();
}

使用以下命令行指令来编译:

gcc main.c -o main
gcc ext.c -dynamiclib -undefined dynamic_lookup -o ext.dylib

这与Windows设置几乎相同。

但对于dynamiclib

> gcc ext.c -dynamiclib -o ext.dylib

并且共享

> gcc ext.c -shared -o ext.so

由于一方面存在未定义的符号以及另一方面无法使用-l标志加载可执行文件,因此我无法让它们正常工作。

我可以使用-undefined dynamic_lookup让它们在运行时解决未定义的符号。但这种方式并不可持续,因为所有的链接错误现在都会在运行时发生。

是否有一种方法可以在链接为-shared-dynamiclib时提供要动态加载的符号列表?


在链接主可执行文件时,您可以尝试选项-Wl,-export_dynamic - Lorinczy Zsigmond
1个回答

1

是的,这是可能的,但是您需要创建一个bundle而不是shared library(有关详细信息,请参见this answer)。

如果您有一个主要应用程序,如下所示:

#include <stdio.h>
#include <dlfcn.h>

int func(void)
{
    return 42;
}

int main(void)
{
    void *dl = dlopen("plugin.so", RTLD_LOCAL);
    if(!dl) return -1;

    int (*derp)(void) = dlsym(dl, "derp");
    if(!derp) return -1;

    printf("derp(): %i\n", derp());

    return 0;
}

clang -o main main.c -Wall -Wl,-export_dynamic

然后您可以这样编译包:
int func(void);

int derp(void)
{
    return -func();
}

clang -o plugin.so plugin.c -Wall -bundle -bundle_loader ./main

似乎你想要说“不,这是不可能的”,因为我的问题并不涉及bundles。 export_dynamic标志的目的是什么?在我的bundle示例中,没有使用该标志也一切正常。 - Teivaz
ld手册中可以看到:“在LTO期间保留主可执行文件中的所有全局符号。如果没有此选项,链接时优化将允许内联和删除全局函数。当主可执行文件可能加载需要来自主可执行文件的某些符号的插件时,使用此选项。” - Siguza
这很有趣。我已经构建了一个没有这个标志的测试项目,它仍然成功链接和运行。我也在一个大型Qt项目上进行了检查,它仍然可以正常工作。 - Teivaz
1
嗯,这是特定于LTO的。我不知道其他平台,但在macOS上似乎默认情况下已禁用(可以使用“-flto”启用)。如果我使用“-flto”构建我的“main.c”,则“func”将从符号表中消失。 - Siguza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接