clang -dynamiclib 不支持递归编译多目录源文件,必须显式列出路径或用 find + xargs 构建列表;cmake 是更可靠的方案,可自动处理源文件发现、符号可见性(如 cxx_visibility_preset hidden)、架构切片(-arch arm64)及 @rpath 安装名配置。

源文件分散在多个子目录时,clang -dynamiclib 不能直接递归编译
Clang 本身不支持像 cmake 或 make 那样自动扫描多级目录下的 .c 或 .cpp 文件。如果你把代码按模块分在 src/utils/、src/core/、src/platform/ 下,直接运行 clang -dynamiclib -o libfoo.dylib src/ 会报错:error: no input files —— 它根本不会进入子目录找源码。
必须显式列出所有待编译的源文件路径,或先用 shell 命令收集再传给 clang。
- 推荐做法:用
find+xargs构建源文件列表(注意顺序和重复) - 避免用
**/*.c(zsh/bash 的 globstar),它在某些 macOS 版本或 CI 环境中不可靠 - 头文件搜索路径也要逐级添加:
-Isrc/utils -Isrc/core -Isrc/platform,不能只写-Isrc
CMakeLists.txt 是管理多目录动态库的合理选择
当目录结构变复杂(比如含公共头文件、条件编译、平台差异),硬写 clang 命令很快失控。CMake 不仅能自动发现源文件,还能处理依赖顺序、符号可见性、架构切片(arm64/x86_64)等真实问题。
例如,你有:
mylib/ ├── CMakeLists.txt ├── include/ │ └── mylib.h ├── src/ │ ├── core/ │ │ └── calc.c │ └── platform/ │ └── ios_impl.c
对应 CMakeLists.txt 关键片段:
Clang 22.1.3 Windows 64 位历史版本安装包,适合旧项目兼容、LLVM/Clang 工具链回退、编译行为对比、链接问题复现和 C/C++ 构建环境维护。
cmake_minimum_required(VERSION 3.10) project(mylib VERSION 1.0 LANGUAGES C) <p>add_library(mylib SHARED src/core/calc.c src/platform/ios_impl.c )</p><p>target_include_directories(mylib PUBLIC $<build_interface:> $<include> )</include></build_interface:></p><h1>iOS 必须导出符号,否则 dlopen 失败</h1><p>set_target_properties(mylib PROPERTIES POSITION_INDEPENDENT_CODE ON CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON )</p>
-
add_library(... SHARED)对应 clang 的-dynamiclib -
POSITION_INDEPENDENT_CODE ON等价于 clang 的-fPIC,iOS 动态库强制要求 - 不要用
file(GLOB ...)自动收集源码——新增文件后 CMake 不会自动 reconfigure
iOS 上多目录动态库必须处理符号可见性与架构
即使 clang 编译成功、CMake 生成 dylib,放到 iOS 工程里仍可能链接失败或运行时崩溃。常见原因不是目录组织,而是:
- 默认所有符号是
hidden的,add()函数若没显式标记__attribute__((visibility("default"))),Xcode 就找不到它 - clang 默认只编译当前 host 架构(比如 macOS 上是 x86_64),但 iOS 真机需要
arm64,必须加-arch arm64 -isysroot <sdk></sdk> - 动态库路径未嵌入
@rpath,导致 app 启动时报dyld: Library not loaded
所以多目录组织只是第一步,真正卡住的是这些平台约束细节。
别忽略 install_name 和 @rpath 配置
clang 生成 dylib 时,默认 install_name 是绝对路径(如 /usr/local/lib/libmylib.dylib),而 iOS 要求它是相对路径,比如 @rpath/libmylib.dylib。否则 Xcode 打包时无法重写加载路径。
正确做法:
- clang 方式:加
-install_name "@rpath/libmylib.dylib" - CMake 方式:用
set_target_properties(mylib PROPERTIES INSTALL_NAME_DIR "@rpath") - 验证命令:
otool -l libmylib.dylib | grep -A2 LC_ID_DYLIB,确认name字段是@rpath/...
多目录本身不增加复杂度,但容易让人误以为“只要文件放对位置就万事大吉”。实际最难调试的,永远是符号导出规则、架构匹配、加载路径这三件事。










