Skip to content

Commit 0fd2929

Browse files
authored
CI: Enable macOS static builds (#40)
1 parent a5b752b commit 0fd2929

4 files changed

Lines changed: 128 additions & 10 deletions

File tree

.github/workflows/build-release.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,62 @@ jobs:
114114
VERSION: ${{ needs.create-release.outputs.version }}
115115
run: |
116116
gh release upload ${VERSION} mrbind-linux-$(uname -m).zip --clobber
117+
118+
build-macos:
119+
needs:
120+
- create-release
121+
runs-on: ${{ matrix.runner }}
122+
strategy:
123+
fail-fast: false
124+
matrix:
125+
arch: [arm64, x64]
126+
include:
127+
- arch: arm64
128+
runner: macos-15
129+
- arch: x64
130+
runner: macos-15-intel
131+
132+
steps:
133+
- name: Checkout
134+
uses: actions/checkout@v6
135+
with:
136+
submodules: true
137+
138+
- name: Build
139+
run: |
140+
export PATH="$(brew --prefix llvm@18)/bin:$PATH"
141+
cmake -B build -G Ninja \
142+
-D Clang_DIR=$(brew --prefix llvm@18)/lib/cmake/clang \
143+
-D CMAKE_BUILD_TYPE=Release \
144+
-D MRBIND_STATIC_BUILD=ON \
145+
-D MRBIND_FORCE_LLVM_STATIC=ON \
146+
-D CMAKE_PREFIX_PATH=$(brew --prefix zstd) \
147+
-D CMAKE_OSX_DEPLOYMENT_TARGET=12.0
148+
cmake --build build --parallel $(sysctl -n hw.logicalcpu)
149+
150+
- name: Verify build
151+
run: |
152+
ls -l build/mrbind*
153+
otool -L build/mrbind*
154+
ls -1 build/mrbind* | xargs -n1 vtool -show-build
155+
156+
- name: Test
157+
run: |
158+
export CLANG_RESOURCE_DIR=$(brew --prefix llvm@18)/lib/clang/18
159+
echo clang++ > examples/cxx.txt
160+
examples/c/run.sh
161+
PYTHON=python3.11 examples/python/run.sh
162+
163+
- name: Create package
164+
run: |
165+
mkdir mrbind
166+
mv build/mrbind{,_gen_c,_gen_csharp} mrbind/
167+
cp -R $(brew --prefix llvm@18)/lib/clang/18 mrbind/resource-dir
168+
zip -r mrbind-macos-$(uname -m).zip mrbind/
169+
170+
- name: Upload package
171+
env:
172+
GH_TOKEN: ${{ github.token }}
173+
VERSION: ${{ needs.create-release.outputs.version }}
174+
run: |
175+
gh release upload ${VERSION} mrbind-macos-$(uname -m).zip --clobber

CMakeLists.txt

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ include_directories(deps/cppdecl/include)
3535

3636

3737
option(MRBIND_STATIC_BUILD "Build the parser and the generators as static binaries." OFF)
38+
option(MRBIND_FORCE_LLVM_STATIC "Use llvm-config to get LLVM static libraries for linking." OFF)
39+
# helper function to link statically with libstdc++ on some platforms
40+
function(apply_static_stdlib tgt)
41+
if(NOT APPLE AND NOT MSVC)
42+
target_link_libraries(${tgt} PRIVATE -static-libstdc++ -static-libgcc)
43+
endif()
44+
endfunction()
3845

3946

4047
add_library(mrbind_common STATIC
@@ -61,7 +68,7 @@ if(MRBIND_BUILD_PARSER)
6168
src/parser/multiplex_data.cpp
6269
)
6370

64-
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
71+
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
6572
set_source_files_properties(src/parser/disable_rtti.cpp PROPERTIES COMPILE_FLAGS -fno-rtti)
6673
endif()
6774

@@ -72,11 +79,60 @@ if(MRBIND_BUILD_PARSER)
7279
target_include_directories(mrbind PRIVATE ${LLVM_INCLUDE_DIR} ${CLANG_INCLUDE_DIR})
7380

7481
if(MRBIND_STATIC_BUILD)
75-
target_link_libraries(mrbind PRIVATE -static-libstdc++ -static-libgcc)
76-
if(NOT TARGET clangTooling)
77-
message(FATAL_ERROR "clangTooling is required for static builds")
82+
if(MRBIND_FORCE_LLVM_STATIC)
83+
# by default libclang static libraries try to link with dynamic libLLVM
84+
function(recurse_remove_llvm tgt)
85+
if(TARGET ${tgt})
86+
get_target_property(lib_deps ${tgt} INTERFACE_LINK_LIBRARIES)
87+
if(lib_deps)
88+
list(REMOVE_ITEM lib_deps LLVM)
89+
set_target_properties(${tgt} PROPERTIES INTERFACE_LINK_LIBRARIES "${lib_deps}")
90+
foreach(dep ${lib_deps})
91+
recurse_remove_llvm(${dep})
92+
endforeach()
93+
endif()
94+
endif()
95+
endfunction()
96+
recurse_remove_llvm(clangTooling)
97+
98+
# link with static LLVM libraries explicitly
99+
execute_process(
100+
COMMAND llvm-config --libdir
101+
OUTPUT_VARIABLE LLVM_LIBDIR
102+
OUTPUT_STRIP_TRAILING_WHITESPACE
103+
)
104+
execute_process(
105+
COMMAND llvm-config --link-static --libs
106+
OUTPUT_VARIABLE LLVM_STATIC_LIBS
107+
OUTPUT_STRIP_TRAILING_WHITESPACE
108+
)
109+
execute_process(
110+
COMMAND llvm-config --link-static --system-libs
111+
OUTPUT_VARIABLE LLVM_SYSTEM_LIBS
112+
OUTPUT_STRIP_TRAILING_WHITESPACE
113+
)
114+
separate_arguments(LLVM_STATIC_LIBS)
115+
separate_arguments(LLVM_SYSTEM_LIBS)
116+
117+
# link with static unwind
118+
find_library(UNWIND_STATIC NAMES libunwind.a PATHS ${LLVM_LIBDIR} NO_DEFAULT_PATH)
119+
120+
# macOS quirk: force replace dynamic zstd with static
121+
if("-lzstd" IN_LIST LLVM_SYSTEM_LIBS)
122+
find_library(ZSTD_STATIC NAMES libzstd.a REQUIRED)
123+
list(REMOVE_ITEM LLVM_SYSTEM_LIBS "-lzstd")
124+
list(APPEND LLVM_SYSTEM_LIBS ${ZSTD_STATIC})
125+
endif()
126+
127+
target_link_directories(mrbind PRIVATE ${LLVM_LIBDIR})
128+
target_link_libraries(mrbind PRIVATE clangTooling ${LLVM_STATIC_LIBS} ${LLVM_SYSTEM_LIBS} ${UNWIND_STATIC})
129+
else()
130+
apply_static_stdlib(mrbind)
131+
if(NOT TARGET clangTooling)
132+
message(FATAL_ERROR "clangTooling is required for static builds")
133+
endif()
134+
target_link_libraries(mrbind PRIVATE clangTooling)
78135
endif()
79-
target_link_libraries(mrbind PRIVATE clangTooling)
80136
else()
81137
# Clang lets you choose between large dynamic libraries, and fine-grained static libraries.
82138
# Those are the large dynamic ones. If they are not available for some reason,
@@ -138,7 +194,7 @@ if(MRBIND_BUILD_GENERATOR_C)
138194
mrbind_c_interop
139195
)
140196
if(MRBIND_STATIC_BUILD)
141-
target_link_libraries(mrbind_gen_c PRIVATE -static-libstdc++ -static-libgcc)
197+
apply_static_stdlib(mrbind_gen_c)
142198
endif()
143199
endif()
144200

@@ -156,6 +212,6 @@ if(MRBIND_BUILD_GENERATOR_CSHARP)
156212
mrbind_c_interop
157213
)
158214
if(MRBIND_STATIC_BUILD)
159-
target_link_libraries(mrbind_gen_csharp PRIVATE -static-libstdc++ -static-libgcc)
215+
apply_static_stdlib(mrbind_gen_csharp)
160216
endif()
161217
endif()

examples/c/run.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ set -x
4949

5050
# Assemble the combined input header.
5151
echo "#pragma once" >c/output/tmp/combined_input.h
52-
find input \( -name '*.h' -or -name '*.hpp' \) -printf "#include <%p>\n" >>c/output/tmp/combined_input.h
52+
find input \( -name '*.h' -or -name '*.hpp' \) -exec printf "#include <%s>\n" {} \; >>c/output/tmp/combined_input.h
5353

5454
# Parse the input header.
5555
../build/mrbind \

examples/python/run.sh

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,15 @@ if [[ $(uname -o) == Msys ]]; then
3333
EXTRA_CXX_FLAGS+=($(python3-config --libs))
3434
PYTHON_MODULE_EXT=.pyd
3535
fi
36+
if [[ $(uname -o) == Darwin ]]; then
37+
EXTRA_CXX_FLAGS+=(-undefined dynamic_lookup)
38+
fi
3639

3740
set -x
3841

3942
# Assemble the combined input header.
4043
echo "#pragma once" >python/output/tmp/combined_input.h
41-
find input \( -name '*.h' -or -name '*.hpp' \) -printf "#include <%p>\n" >>python/output/tmp/combined_input.h
44+
find input \( -name '*.h' -or -name '*.hpp' \) -exec printf "#include <%s>\n" {} \; >>python/output/tmp/combined_input.h
4245

4346
# Parse the input header.
4447
../build/mrbind \
@@ -47,7 +50,7 @@ find input \( -name '*.h' -or -name '*.hpp' \) -printf "#include <%p>\n" >>pytho
4750
-o python/output/tmp/generated.cpp \
4851
--ignore :: \
4952
--allow Example \
50-
"${EXTRA_PARSER_FLAGS[@]}" \
53+
"${EXTRA_PARSER_FLAGS[@]+"${EXTRA_PARSER_FLAGS[@]}"}" \
5154
-- \
5255
-xc++-header \
5356
-resource-dir="${CLANG_RESOURCE_DIR:-$("$CLANG_CXX" -print-resource-dir)}" \

0 commit comments

Comments
 (0)