Skip to content

Commit

Permalink
cgosling: build our own shared library instead of using rust's cdylib…
Browse files Browse the repository at this point in the history
… target
  • Loading branch information
Richard Pospesel committed Mar 11, 2024
1 parent 757fe0f commit 733e4ce
Show file tree
Hide file tree
Showing 9 changed files with 458 additions and 142 deletions.
139 changes: 37 additions & 102 deletions source/bindings/c/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
include(CheckLinkerFlag)

find_program(PATCHELF_EXECUTABLE NAMES patchelf)

if (NOT PATCHELF_EXECUTABLE AND LINUX)
Expand All @@ -10,19 +12,15 @@ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
set(gosling_c_bindings_sources
${CARGO_TARGET_DIR}/include/cgosling.h
${CARGO_TARGET_DIR}/${CARGO_PROFILE}/${CGOSLING_STATIC}
${CARGO_TARGET_DIR}/${CARGO_PROFILE}/${CGOSLING_IMPL_STATIC}
)

set(gosling_c_bindings_outputs
${CMAKE_CURRENT_BINARY_DIR}/include/cgosling.h
${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_STATIC}
${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_IMPL_STATIC}
)

# add Shared library import library
if (WINDOWS)
list(APPEND gosling_c_bindings_sources ${CARGO_TARGET_DIR}/${CARGO_PROFILE}/${CGOSLING_IMPORT})
list(APPEND gosling_c_bindings_outputs ${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_IMPORT})
endif()

#
# Just copy header and libs from the cgosling crate build outputs
#
Expand All @@ -33,46 +31,6 @@ foreach(src dest IN ZIP_LISTS gosling_c_bindings_sources gosling_c_bindings_outp
COMMAND cp -P ${src} ${dest})
endforeach()

# Shared Library + Symlinks
if (LINUX)
add_custom_command(
DEPENDS ${CARGO_TARGET_DIR}/${CARGO_PROFILE}/${CGOSLING_SHARED}
OUTPUT
${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED}.${CGOSLING_VERSION}
${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED}.${CGOSLING_MAJOR_VERSION}
${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED}
# copy shared library and set soname
COMMAND ${CMAKE_COMMAND} -E copy ${CARGO_TARGET_DIR}/${CARGO_PROFILE}/${CGOSLING_SHARED} ${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED}.${CGOSLING_VERSION}
COMMAND patchelf --set-soname libcgosling.so.${CGOSLING_MAJOR_VERSION} ${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED}.${CGOSLING_VERSION}
# create symlinks
COMMAND ${CMAKE_COMMAND} -E create_symlink ${CGOSLING_SHARED}.${CGOSLING_VERSION} ${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED}.${CGOSLING_MAJOR_VERSION}
COMMAND ${CMAKE_COMMAND} -E create_symlink ${CGOSLING_SHARED}.${CGOSLING_MAJOR_VERSION} ${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED})
list(APPEND gosling_c_bindings_outputs ${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED}.${CGOSLING_VERSION})
list(APPEND gosling_c_bindings_outputs ${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED}.${CGOSLING_MAJOR_VERSION})
list(APPEND gosling_c_bindings_outputs ${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED})
elseif(MACOS)
add_custom_command(
DEPENDS ${CARGO_TARGET_DIR}/${CARGO_PROFILE}/${CGOSLING_SHARED}
OUTPUT
${CMAKE_CURRENT_BINARY_DIR}/lib/libcgosling.${CGOSLING_VERSION}.dylib
${CMAKE_CURRENT_BINARY_DIR}/lib/libcgosling.${CGOSLING_MAJOR_VERSION}.dylib
${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED}
# copy shared library
COMMAND ${CMAKE_COMMAND} -E copy ${CARGO_TARGET_DIR}/${CARGO_PROFILE}/${CGOSLING_SHARED} ${CMAKE_CURRENT_BINARY_DIR}/lib/libcgosling.${CGOSLING_VERSION}.dylib
# create symlinks
COMMAND ${CMAKE_COMMAND} -E create_symlink libcgosling.${CGOSLING_VERSION}.dylib ${CMAKE_CURRENT_BINARY_DIR}/lib/libcgosling.${CGOSLING_MAJOR_VERSION}.dylib
COMMAND ${CMAKE_COMMAND} -E create_symlink libcgosling.${CGOSLING_MAJOR_VERSION}.dylib ${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED})
list(APPEND gosling_c_bindings_outputs ${CMAKE_CURRENT_BINARY_DIR}/lib/libcgosling.${CGOSLING_VERSION}.dylib)
list(APPEND gosling_c_bindings_outputs ${CMAKE_CURRENT_BINARY_DIR}/lib/libcgosling.${CGOSLING_MAJOR_VERSION}.dylib)
list(APPEND gosling_c_bindings_outputs ${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED})
else()
add_custom_command(
DEPENDS ${CARGO_TARGET_DIR}/${CARGO_PROFILE}/${CGOSLING_SHARED}
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED}
COMMAND ${CMAKE_COMMAND} -E copy ${CARGO_TARGET_DIR}/${CARGO_PROFILE}/${CGOSLING_SHARED} ${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED})
list(APPEND gosling_c_bindings_outputs ${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED})
endif()

add_custom_target(gosling_c_bindings_target
DEPENDS ${gosling_c_bindings_outputs})
add_dependencies(gosling_c_bindings_target cgosling_target)
Expand All @@ -92,12 +50,6 @@ set_target_properties(gosling_c_static_bindings PROPERTIES
IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_STATIC}
)

# Linux targets needed by rust runtime
if(LINUX)
target_link_libraries(gosling_c_static_bindings INTERFACE pthread)
target_link_libraries(gosling_c_static_bindings INTERFACE dl)
endif()

if(WINDOWS)
target_link_libraries(gosling_c_static_bindings INTERFACE ws2_32)
target_link_libraries(gosling_c_static_bindings INTERFACE userenv)
Expand All @@ -112,19 +64,41 @@ add_dependencies(gosling_c_static_bindings_target gosling_c_static_bindings)
# Shared Library
#

add_library(gosling_c_shared_bindings SHARED IMPORTED GLOBAL)
add_dependencies(gosling_c_shared_bindings gosling_c_bindings_target)

target_include_directories(gosling_c_shared_bindings INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/include)
set_target_properties(gosling_c_shared_bindings PROPERTIES
IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED}
# generate cgosling.c
set(gosling_c_shared_bindings_sources
build_c_shared_bindings.rs
Cargo.toml
cgosling.c.handlebars)

# cgosling.c basically forwards the various gosling calls in the public header
# to the _impl methods
add_custom_command(
DEPENDS ${gosling_c_shared_bindings_sources} gosling_c_bindings_target
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/cgosling.c
# generate c source
COMMAND env CARGO_TARGET_DIR=${CARGO_TARGET_DIR} RUSTFLAGS=${RUSTFLAGS} RUST_BACKTRACE=full cargo run ${CARGO_FLAGS} --bin build_c_shared_bindings ${CARGO_TARGET_DIR}/cgosling.json cgosling.c.handlebars ${CMAKE_CURRENT_BINARY_DIR}/cgosling.c
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
if (WINDOWS)
set_target_properties(gosling_c_shared_bindings PROPERTIES
IMPORTED_IMPLIB ${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_IMPORT}
)

# build our shared library
add_library(gosling_c_shared_bindings SHARED ${CMAKE_CURRENT_BINARY_DIR}/cgosling.c)
set_target_properties(gosling_c_shared_bindings
PROPERTIES
OUTPUT_NAME cgosling
VERSION ${CGOSLING_VERSION}
SOVERSION ${CGOSLING_MAJOR_VERSION})
target_include_directories(gosling_c_shared_bindings PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include)
target_link_libraries(gosling_c_shared_bindings PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_IMPL_STATIC})
# check if the --exclude-libs flag is supported by the linker
check_linker_flag(C "-Wl,--exclude-libs,ALL" LINKER_SUPPORTS_EXCLUDE_LIBS)

if(LINKER_SUPPORTS_EXCLUDE_LIBS)
# prevents the result so from re-exporting all of the static libs symbols out of the shared library
target_link_options(gosling_c_shared_bindings PRIVATE "-Wl,--exclude-libs,ALL")
endif()

target_include_directories(gosling_c_shared_bindings PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/include)

add_custom_target(gosling_c_shared_bindings_target ALL)
add_dependencies(gosling_c_shared_bindings_target gosling_c_shared_bindings)

Expand All @@ -136,44 +110,5 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/cgosling.h
TYPE INCLUDE)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_STATIC}
${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED}
TYPE LIB)
if (WINDOWS)
# .a + .dll.a goes to lib
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_STATIC}
${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_IMPORT}
TYPE LIB)
# .dll goes to bin
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED}
TYPE BIN)
elseif (LINUX)
# .so and .a go to lib
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_STATIC}
${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED}
TYPE LIB)
# versioned symlinks go to lib
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED}.${CGOSLING_MAJOR_VERSION}
${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED}.${CGOSLING_VERSION}
TYPE LIB)
elseif (MACOS)
# .dylib and .a go to lib
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_STATIC}
${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED}
TYPE LIB)
# versioned symlinks go to lib
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/lib/libcgosling.${CGOSLING_MAJOR_VERSION}.dylib
${CMAKE_CURRENT_BINARY_DIR}/lib/libcgosling.${CGOSLING_VERSION}.dylib
TYPE LIB)
else()
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_STATIC}
${CMAKE_CURRENT_BINARY_DIR}/lib/${CGOSLING_SHARED}
TYPE LIB)
endif()

install(TARGETS gosling_c_shared_bindings)
Loading

0 comments on commit 733e4ce

Please sign in to comment.