diff --git a/.github/workflows/ci-macos.yml b/.github/workflows/ci-macos.yml new file mode 100644 index 00000000..fa6aaa82 --- /dev/null +++ b/.github/workflows/ci-macos.yml @@ -0,0 +1,28 @@ +name: ci-macos +on: [push, pull_request] +jobs: + build: + runs-on: macos-latest + env: + # /usr 受 SIP 保护,kvspace 装到 /usr/local(本仓 runtime/layout/runtime-rs 均读该变量) + KVSPACE_LIB_DIR: /usr/local/lib/kvspace + steps: + - uses: actions/checkout@v4 + - name: 构建依赖 kvspace(macOS 无预编译 ABI,从源码装到 /usr/local) + run: | + git clone --depth 1 https://github.com/array2d/kvspace.git /tmp/kvspace + cmake -S /tmp/kvspace -B /tmp/kvspace/build \ + -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local + cmake --build /tmp/kvspace/build -j + sudo cmake --install /tmp/kvspace/build + - name: 构建 layout(Rust;macOS 产物后缀为 .dylib) + run: | + cargo build --release --manifest-path layout/Cargo.toml + mkdir -p bin && cp layout/target/release/libkvlanglayout.dylib bin/ + - name: 构建 runtime(C) + run: | + cmake -S runtime -B build/runtime -DCMAKE_BUILD_TYPE=Release \ + -DKVSPACE_LIB_DIR="$KVSPACE_LIB_DIR" + cmake --build build/runtime --target kvlang_runtime -j + - name: 构建 runtime-rs(Rust) + run: cargo build --release --manifest-path runtime-rs/Cargo.toml diff --git a/layout/build.rs b/layout/build.rs index 1c92863c..230a503c 100644 --- a/layout/build.rs +++ b/layout/build.rs @@ -1,8 +1,13 @@ -// 链接 kvspace dispatch 前端(与后端同装 /usr/lib/kvspace)。布局侧只通过 extern "C" ABI 调用, +// 链接 kvspace dispatch 前端(与后端同装 /lib/kvspace)。布局侧只通过 extern "C" ABI 调用, // 运行期由前端按 DSN 选后端(shm://→kvspace-c,其余→kvspace-durable)。 +// KVSPACE_LIB_DIR 可覆盖安装目录:macOS 的 /usr 受 SIP 保护,应指向 /lib/kvspace。 fn main() { - println!("cargo:rustc-link-search=native=/usr/lib/kvspace"); + let dir = std::env::var("KVSPACE_LIB_DIR").unwrap_or_else(|_| "/usr/lib/kvspace".into()); + println!("cargo:rustc-link-search=native={dir}"); println!("cargo:rustc-link-lib=dylib=kvspace"); - println!("cargo:rustc-link-arg=-Wl,--disable-new-dtags"); // rpath 转 DT_RPATH,传递解析子依赖 - println!("cargo:rustc-link-arg=-Wl,-rpath,/usr/lib/kvspace"); + println!("cargo:rustc-link-arg=-Wl,-rpath,{dir}"); + if !cfg!(target_os = "macos") { + // rpath 转 DT_RPATH,传递解析子依赖;ld64 无 --disable-new-dtags + println!("cargo:rustc-link-arg=-Wl,--disable-new-dtags"); + } } diff --git a/runtime-rs/build.rs b/runtime-rs/build.rs index d852c32c..61877adc 100644 --- a/runtime-rs/build.rs +++ b/runtime-rs/build.rs @@ -23,18 +23,28 @@ fn main() { let manifest = env!("CARGO_MANIFEST_DIR"); let bin = format!("{manifest}/../bin"); // kvlang/bin(新构建的 libkvlang_runtime.so) + // KVSPACE_LIB_DIR 可覆盖安装目录:macOS 的 /usr 受 SIP 保护,应指向 /lib/kvspace。 + let kvspace_dir = std::env::var("KVSPACE_LIB_DIR").unwrap_or_else(|_| "/usr/lib/kvspace".into()); + println!("cargo:rustc-link-search=native={bin}"); - println!("cargo:rustc-link-search=native=/usr/lib/kvspace"); - println!("cargo:rustc-link-search=native=/usr/lib"); + println!("cargo:rustc-link-search=native={kvspace_dir}"); println!("cargo:rustc-link-lib=dylib=kvlang_runtime"); println!("cargo:rustc-link-lib=dylib=kvspace"); println!("cargo:rustc-link-lib=dylib=kvlanglayout"); - println!("cargo:rustc-link-arg=-Wl,--disable-new-dtags"); // rpath 转 DT_RPATH,传递解析子依赖 - println!("cargo:rustc-link-arg=-Wl,-rpath,$ORIGIN"); - println!("cargo:rustc-link-arg=-Wl,-rpath,$ORIGIN/../lib"); - println!("cargo:rustc-link-arg=-Wl,-rpath,/usr/lib/kvspace"); - println!("cargo:rustc-link-arg=-Wl,-rpath,/usr/lib"); + if cfg!(target_os = "macos") { + // macOS:ld64 无 --disable-new-dtags;$ORIGIN 对应 @loader_path + println!("cargo:rustc-link-arg=-Wl,-rpath,@loader_path"); + println!("cargo:rustc-link-arg=-Wl,-rpath,@loader_path/../lib"); + println!("cargo:rustc-link-arg=-Wl,-rpath,{kvspace_dir}"); + } else { + println!("cargo:rustc-link-search=native=/usr/lib"); + println!("cargo:rustc-link-arg=-Wl,--disable-new-dtags"); // rpath 转 DT_RPATH,传递解析子依赖 + println!("cargo:rustc-link-arg=-Wl,-rpath,$ORIGIN"); + println!("cargo:rustc-link-arg=-Wl,-rpath,$ORIGIN/../lib"); + println!("cargo:rustc-link-arg=-Wl,-rpath,{kvspace_dir}"); + println!("cargo:rustc-link-arg=-Wl,-rpath,/usr/lib"); + } // 内嵌顶层 stdlib/**/*.kv → EMBEDDED_KV。 let libdir = format!("{manifest}/../stdlib"); diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 40125248..67469545 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -15,10 +15,19 @@ add_library(kvlang_runtime SHARED ${KVLANG_RUNTIME_SRC}) target_include_directories(kvlang_runtime PUBLIC include src) target_compile_definitions(kvlang_runtime PRIVATE _GNU_SOURCE) -# 链接 kvspace dispatch 前端(已安装 /usr/lib),运行期按 DSN 选后端,编译期不再选后端。 -# 链接 kvspace dispatch 前端(与后端同装 /usr/lib/kvspace),运行期按 DSN 选后端,编译期不再选后端。 -target_link_directories(kvlang_runtime PRIVATE /usr/lib/kvspace) -target_link_libraries(kvlang_runtime PRIVATE kvspace m pthread) +# 链接 kvspace dispatch 前端(与后端同装 /lib/kvspace),运行期按 DSN 选后端,编译期不再选后端。 +# KVSPACE_LIB_DIR 可覆盖安装目录:macOS 的 /usr 受 SIP 保护,应指向 /lib/kvspace。 +set(KVSPACE_LIB_DIR "/usr/lib/kvspace" CACHE PATH "kvspace dispatch 前端安装目录") +target_link_directories(kvlang_runtime PRIVATE ${KVSPACE_LIB_DIR}) -# --export-dynamic 供 kvlang(term 扩展)找符号;--disable-new-dtags 使 rpath 转 DT_RPATH(传递)。 -set_target_properties(kvlang_runtime PROPERTIES LINK_FLAGS "-Wl,--export-dynamic -Wl,--disable-new-dtags -Wl,-rpath,/usr/lib/kvspace") +if(APPLE) + # macOS:数学/线程符号在 libSystem 内(无 -lm/-lpthread);ld64 无 --disable-new-dtags + target_link_libraries(kvlang_runtime PRIVATE kvspace) + set_target_properties(kvlang_runtime PROPERTIES + LINK_FLAGS "-Wl,-export_dynamic -Wl,-rpath,${KVSPACE_LIB_DIR}") +else() + target_link_libraries(kvlang_runtime PRIVATE kvspace m pthread) + # --export-dynamic 供 kvlang(term 扩展)找符号;--disable-new-dtags 使 rpath 转 DT_RPATH(传递)。 + set_target_properties(kvlang_runtime PROPERTIES + LINK_FLAGS "-Wl,--export-dynamic -Wl,--disable-new-dtags -Wl,-rpath,${KVSPACE_LIB_DIR}") +endif() diff --git a/runtime/src/logx.c b/runtime/src/logx.c index 3999c9ce..32280778 100644 --- a/runtime/src/logx.c +++ b/runtime/src/logx.c @@ -1,10 +1,16 @@ #define _GNU_SOURCE #include +#include /* getprogname(macOS/BSD) */ #include "runtime_internal.h" /* 可执行文件名(basename):runtime 诊断日志前缀,区别于 kvcode print(stdout、无前缀)。 */ static const char *kvlangExe(void) { +#if defined(__APPLE__) + /* macOS/BSD 无 glibc 的 program_invocation_short_name,用 getprogname()。 */ + const char *p = getprogname(); +#else const char *p = program_invocation_short_name; +#endif return (p && p[0]) ? p : "kvlang"; }