diff --git a/Makefile b/Makefile index 6d4a096..4fd6899 100644 --- a/Makefile +++ b/Makefile @@ -29,12 +29,22 @@ ifneq (,$(findstring MINGW,$(detected_OS))) endif # liblibchat and librln are both Rust staticlibs that embed Rust std, -# resulting in duplicate symbol errors at link time. To mitigate that, -# --allow-multiple-definition is added. +# resulting in duplicate symbol errors at link time. +# On Linux, --allow-multiple-definition suppresses the error. +# On Darwin, Apple ld does not support that flag; instead we partial-link +# liblibchat.a with ld -r, keeping only its public API symbols exported so +# that all Rust std internals (including _rust_eh_personality) are hidden +# and cannot conflict with the copy embedded in librln.a. ifeq ($(detected_OS),Linux) LDFLAGS := --passL:-Wl,--allow-multiple-definition endif +ifeq ($(detected_OS),Darwin) + LIBCHAT_A := build/liblibchat_clean.a +else + LIBCHAT_A := vendor/libchat/target/release/liblibchat.a +endif + ########## ## Main ## ########## @@ -106,13 +116,23 @@ build-waku-nat: build-libchat: @echo "Start building libchat" cd vendor/libchat && cargo build --release +ifeq ($(detected_OS),Darwin) + @mkdir -p build + @nm --no-llvm-bc -gjU vendor/libchat/target/release/liblibchat.a 2>/dev/null | \ + grep -E '^_(chat_|double_ratchet_|encrypt_result_|ffi_c_string_|installation_key_pair_|ratchet_state_|create_context|installation_name|destroy_context|destroy_string|create_intro_bundle|create_new_private_convo|send_content|handle_payload|destroy_intro_result|destroy_send_content_result|destroy_handle_payload_result|destroy_convo_result)' \ + > build/libchat_exports.txt + @ld -r -exported_symbols_list build/libchat_exports.txt \ + vendor/libchat/target/release/liblibchat.a \ + -o build/liblibchat_clean.o + @libtool -static -o $(LIBCHAT_A) build/liblibchat_clean.o +endif @echo "Completed building libchat" .PHONY: tests tests: | build-waku-librln build-waku-nat build-libchat logos_chat.nims echo -e $(BUILD_MSG) "build/$@" && \ $(ENV_SCRIPT) nim tests $(NIM_PARAMS) \ - --passL:vendor/libchat/target/release/liblibchat.a \ + --passL:$(LIBCHAT_A) \ $(LDFLAGS) \ logos_chat.nims @@ -125,7 +145,7 @@ tests: | build-waku-librln build-waku-nat build-libchat logos_chat.nims tui bot_echo pingpong: | build-waku-librln build-waku-nat build-libchat logos_chat.nims echo -e $(BUILD_MSG) "build/$@" && \ $(ENV_SCRIPT) nim $@ $(NIM_PARAMS) \ - --passL:vendor/libchat/target/release/liblibchat.a \ + --passL:$(LIBCHAT_A) \ $(LDFLAGS) \ --path:src logos_chat.nims @@ -148,7 +168,7 @@ LIBLOGOSCHAT := build/liblogoschat.$(LIBLOGOSCHAT_EXT) liblogoschat: | build-waku-librln build-waku-nat build-libchat logos_chat.nims echo -e $(BUILD_MSG) "$(LIBLOGOSCHAT)" && \ $(ENV_SCRIPT) nim liblogoschat $(NIM_PARAMS) \ - --passL:vendor/libchat/target/release/liblibchat.a \ + --passL:$(LIBCHAT_A) \ $(LDFLAGS) \ --path:src logos_chat.nims && \ echo -e "\n\x1B[92mLibrary built successfully:\x1B[39m" && \ diff --git a/nix/libchat.nix b/nix/libchat.nix index 393b6d0..f2f889d 100644 --- a/nix/libchat.nix +++ b/nix/libchat.nix @@ -31,6 +31,20 @@ in rPlatform.buildRustPackage { cp target/release/liblibchat.so $out/lib/ 2>/dev/null || true cp target/release/liblibchat.dylib $out/lib/ 2>/dev/null || true cp target/release/liblibchat.a $out/lib/ 2>/dev/null || true + ${lib.optionalString stdenv.isDarwin '' + # Partial-link liblibchat.a, keeping only its public API symbols exported. + # This hides all Rust std symbols (including _rust_eh_personality) so they + # do not conflict with the copy embedded in librln.a at final link time. + if [ -f "$out/lib/liblibchat.a" ]; then + nm --no-llvm-bc -gjU $out/lib/liblibchat.a 2>/dev/null | \ + grep -E '^_(chat_|double_ratchet_|encrypt_result_|ffi_c_string_|installation_key_pair_|ratchet_state_|create_context|installation_name|destroy_context|destroy_string|create_intro_bundle|create_new_private_convo|send_content|handle_payload|destroy_intro_result|destroy_send_content_result|destroy_handle_payload_result|destroy_convo_result)' \ + > $TMPDIR/libchat_exports.txt + ld -r -exported_symbols_list $TMPDIR/libchat_exports.txt \ + $out/lib/liblibchat.a \ + -o $TMPDIR/liblibchat_clean.o + libtool -static -o $out/lib/liblibchat.a $TMPDIR/liblibchat_clean.o + fi + ''} runHook postInstall ''; }