You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mac下仅含函数声明的动态库构建问题:与Linux差异及解决

问题背景

尝试构建一个仅包含函数声明、实现位于主程序中的动态库(dylib),该动态库的初始化函数会调用注册函数。此代码及编译方式在Linux平台可正常构建运行,但在Mac平台报错。

相关代码

dll.c

#include <stdio.h>
#include <stdlib.h>
 
typedef struct test {
    int i;
    void (*echo_fun)(struct test *p);
}Test;
 
void my_register(Test *p);
 
static void printf_test(Test *p) {
    printf("i = %d\n", p->i);
}
 
static Test config = {
    .i = 0,
    .echo_fun = printf_test,
};
 
void __attribute__((constructor)) my_init(void) {
    printf("init\n");
    my_register(&config);
}

main.c

#include <stdlib.h>
#include <dlfcn.h>
#include <stdio.h>
 
typedef struct my_test {
    int i;
    void (* echo_fun)(struct __test *p);
}Test;
 
void my_register(Test *p) {
    p->i = 1;
    p->echo_fun(p);
}
 
int main(void) {
    void *handle = NULL;
    char *myso = "./dll.dylib";
 
    if((handle = dlopen(myso, RTLD_NOW)) == NULL) {
        printf("dlopen - %s\n", dlerror());
        exit(-1);
    }
 
    return 0;
}

编译命令

gcc -shared -fPIC -nostartfiles -o dll.dylib dll.c

错误信息

Apple clang version 14.0.0 (clang-1400.0.29.202)
Target: x86_64-apple-darwin22.1.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
 "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" -demangle -lto_library /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libLTO.dylib -dynamic -dylib -arch x86_64 -platform_version macos 13.0.0 13.0 -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -o dll.dylib -L/usr/local/lib dll.o -lSystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/14.0.0/lib/darwin/libclang_rt.osx.a
Undefined symbols for architecture x86_64:
  "_my_register", referenced from:
      _my_init in dll.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

提问

  1. 为何该方案在Linux平台可正常运行,却在Mac平台报错?
  2. 能否在Mac平台成功构建该动态库?具体操作方法是什么?

解答

1. 跨平台差异原因

Linux与macOS的动态链接器默认规则不同:

  • Linux平台:编译动态库时,默认允许未定义符号存在,这类符号会留到运行时由加载动态库的主程序提供,因此编译阶段不会报错。
  • macOS平台:默认要求动态库中所有符号在编译阶段必须找到定义,当检测到_my_register这类未定义符号时,链接器直接抛出错误,不会将未解析符号延迟到运行时处理。
    另外,-nostartfiles参数在两个平台的行为存在差异,但核心报错原因还是符号解析规则的不同。

2. Mac平台构建方法

可以通过修改编译参数,让macOS链接器允许未定义符号延迟到运行时解析,具体步骤如下:

步骤1:编译动态库

添加-undefined dynamic_lookup参数,告诉链接器允许未定义符号在运行时由主程序提供:

gcc -shared -fPIC -nostartfiles -undefined dynamic_lookup -o dll.dylib dll.c

步骤2:编译主程序

编译主程序时链接动态加载库:

gcc -o main main.c -ldl

步骤3:运行程序

执行生成的主程序即可:

./main

额外注意事项

  • 主程序中struct __test的定义需要和动态库中的struct test完全一致,否则会出现指针类型不匹配问题,建议将结构体定义抽为公共头文件,避免两边定义不一致。
  • macOS动态库后缀为.dylib,代码中已正确使用,无需修改。

内容的提问来源于stack exchange,提问作者B1NandZhuo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 05:37:12