Skip to content

Commit

Permalink
support static linking of ctranslate2 (#148)
Browse files Browse the repository at this point in the history
* support static linking of ctranslate2

* update

* remove submodule rust-cxx-cmake-bridge

* support alwayslink with whole-archive

* update

* move export_libs

* update docker config

* update ctranslate2

* remove

* update

* update build.rs

* parse external libs

* cleanup

* add cargo fmt
  • Loading branch information
wsxiaoys authored May 27, 2023
1 parent 3788710 commit 06cf34a
Show file tree
Hide file tree
Showing 12 changed files with 428 additions and 20 deletions.
1 change: 1 addition & 0 deletions crates/ctranslate2-bindings/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/target
/Cargo.lock
/build
16 changes: 16 additions & 0 deletions crates/ctranslate2-bindings/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
cmake_minimum_required(VERSION 3.7)

project(ctranslate2_bindings)

add_subdirectory(CTranslate2)

add_library(dummy
src/dummy.cc
)

target_link_libraries(dummy
PRIVATE ctranslate2
)

include(cmake/export_libs.cmake)
export_all_target_libs(dummy)
1 change: 1 addition & 0 deletions crates/ctranslate2-bindings/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ tokenizers = "0.13.3"
bindgen = "0.53.1"
cxx-build = "1.0"
cmake = "0.1"
rust-cxx-cmake-bridge = { path = "../rust-cxx-cmake-bridge" }
40 changes: 22 additions & 18 deletions crates/ctranslate2-bindings/build.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
use cmake::Config;
use rust_cxx_cmake_bridge::read_cmake_generated;

fn main() {
let mut config = Config::new("CTranslate2");
let mut config = Config::new(".");
config
.define("CMAKE_BUILD_TYPE", "Release")
.define("BUILD_CLI", "OFF")
.define("BUILD_SHARED_LIBS", "ON")
.define("CMAKE_INSTALL_RPATH_USE_LINK_PATH", "ON");
.define("CMAKE_INSTALL_RPATH_USE_LINK_PATH", "ON")
.define("BUILD_SHARED_LIBS", "OFF");

if cfg!(target_os = "macos") {
config
.define("CMAKE_OSX_ARCHITECTURES", "arm64")
.define("WITH_ACCELERATE", "ON")
.define("WITH_MKL", "OFF")
.define("OPENMP_RUNTIME", "NONE")
.define("WITH_RUY", "ON");
} else if cfg!(target_os = "linux") {
if cfg!(target_os = "linux") {
config
.define("WITH_CUDA", "ON")
.define("WITH_CUDNN", "ON")
Expand All @@ -24,16 +18,26 @@ fn main() {
.define("OPENMP_RUNTIME", "COMP")
.cxxflag("-msse4.1")
.define("CUDA_NVCC_FLAGS", "-Xfatbin=-compress-all")
.define("CUDA_ARCH_LIST", "Common");
}
.define("CUDA_ARCH_LIST", "Common")
} else if cfg!(target_os = "macos") {
config
.define("CMAKE_OSX_ARCHITECTURES", "arm64")
.define("WITH_ACCELERATE", "ON")
.define("WITH_MKL", "OFF")
.define("OPENMP_RUNTIME", "NONE")
.define("WITH_RUY", "ON")
} else {
panic!("Invalid target")
};

let dst = config.build();

println!(
"cargo:rustc-link-search=native={}",
dst.join("lib").display()
);
println!("cargo:rustc-link-lib=ctranslate2");
// Read static lib from generated deps.
let cmake_generated_libs_str = std::fs::read_to_string(
&format!("/{}/build/cmake_generated_libs", dst.display()).to_string(),
)
.unwrap();
read_cmake_generated(&cmake_generated_libs_str);

// Tell cargo to invalidate the built crate whenever the wrapper changes
println!("cargo:rerun-if-changed=include/ctranslate2.h");
Expand Down
25 changes: 25 additions & 0 deletions crates/ctranslate2-bindings/cmake/debug_cmake.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#! /bin/bash

set -e
set -x

UNAME="$(uname -s)"
case "${UNAME}" in
Linux*) MACHINE=linux;;
Darwin*) MACHINE=macos;;
*) exit 1;;
esac

rm -rf build
mkdir build && cd build

if [[ "$MACHINE" == "macos" ]]; then
CMAKE_EXTRA_OPTIONS='-DCMAKE_OSX_ARCHITECTURES=arm64 -DWITH_ACCELERATE=ON -DWITH_MKL=OFF -DOPENMP_RUNTIME=NONE -DWITH_RUY=ON'
elif [[ "$MACHINE" == "linux" ]]; then
CMAKE_EXTRA_OPTIONS='-DWITH_CUDA=ON -DWITH_CUDNN=ON -DWITH_MKL=ON -DWITH_DNNL=ON -DOPENMP_RUNTIME=COMP -DCUDA_NVCC_FLAGS=-Xfatbin=-compress-all -DCUDA_ARCH_LIST=Common -DCXXFLAGS=-msse4.1'
fi


cmake -DBULID_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release -DBUILD_CLI=OFF -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON $CMAKE_EXTRA_OPTIONS ..

"$@"
98 changes: 98 additions & 0 deletions crates/ctranslate2-bindings/cmake/export_libs.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
################################################################################

# WARNING: to list the system libraries(ie IMPORTED) you MUST set:
# set_target_properties(your_lib PROPERTIES IMPORTED_GLOBAL TRUE)
# just after the find_package call
# cf https://gitlab.kitware.com/cmake/cmake/-/issues/17256
#
# https://stackoverflow.com/questions/32756195/recursive-list-of-link-libraries-in-cmake
# https://stackoverflow.com/questions/32197663/how-can-i-remove-the-the-location-property-may-not-be-read-from-target-error-i
function(_get_link_libraries OUTPUT_LIST TARGET)
list(APPEND VISITED_TARGETS ${TARGET})

# DO NOT switch on IMPORTED or not
# An INTERFACE library CAN have LINK_LIBRARIES!
# get_target_property(IMPORTED ${TARGET} IMPORTED)
set(LIBS "")
get_target_property(LIBS_1 ${TARGET} INTERFACE_LINK_LIBRARIES)
get_target_property(LIBS_2 ${TARGET} LINK_LIBRARIES)
list(APPEND LIBS ${LIBS_1} ${LIBS_2})

set(LIB_FILES "")

foreach(LIB ${LIBS})
if (TARGET ${LIB})
list(FIND VISITED_TARGETS ${LIB} VISITED)
if (${VISITED} EQUAL -1)
# OLD: get_target_property(LIB_FILE ${LIB} LOCATION)
# NEW:
_get_link_libraries(LINK_LIB_FILES ${LIB})
set(LIB_FILE ${LIB})
list(APPEND LIB_FILES ${LINK_LIB_FILES})
list(APPEND LIB_FILES ${LIB_FILE})
endif()
elseif(EXISTS ${LIB})
set(LIB_FILE ${LIB})
list(APPEND LIB_FILES ${LIB_FILE})
endif()
endforeach()

set(VISITED_TARGETS ${VISITED_TARGETS} PARENT_SCOPE)
set(${OUTPUT_LIST} ${LIB_FILES} PARENT_SCOPE)
endfunction()

################################################################################

function(export_all_target_libs TARGET)
# NOTE: get_target_property(CIRCUIT_LIB_LINK_LIBRARIES a_target LINK_LIBRARIES) is NOT transitive
# This function will return eg: "$<TARGET_FILE:rust_cxx>;$<TARGET_FILE:circuit_lib>;"
# b/c generator expression are evaluated LATER
# cf https://stackoverflow.com/questions/59226127/cmake-generator-expression-how-to-get-target-file-property-on-list-of-targets
set(ALL_LINK_LIBRARIES "")
_get_link_libraries(ALL_LINK_LIBRARIES ${TARGET})

message(STATUS "ALL_LINK_LIBRARIES : ${ALL_LINK_LIBRARIES}")

set(ALL_LIBS "")
set(ALL_EXTERNAL_LIBS "")
# TODO move that back into get_link_libraries
# NOTE: we MUST do it in 2 steps:
# - collect all the LINK_LIBRARIES recursively
# - loop on those and get their TARGET_FILE (if not INTERFACE_LIBRARY)
# That is b/c in get_link_libraries a INTERFACE_LIBRARY CAN have link_libraries
# but we CAN NOT evaluate generator expressions at this time.
foreach(LIB ${ALL_LINK_LIBRARIES})
# MUST skip INTERFACE else:
# CMake Error at src/CMakeLists.txt:136 (add_custom_command):
# Error evaluating generator expression:
# $<TARGET_FILE:rust_cxx>
# Target "rust_cxx" is not an executable or library.
# SHARED_LIBRARY,INTERFACE_LIBRARY,STATIC_LIBRARY
#
if (TARGET ${LIB})
get_target_property(LIB_TYPE ${LIB} TYPE)
message(STATUS "LIB_TYPE : ${LIB} = ${LIB_TYPE}")

if(NOT ${LIB_TYPE} STREQUAL "INTERFACE_LIBRARY")
set(LIB_FILE $<TARGET_FILE:${LIB}>)
list(APPEND ALL_LIBS ${LIB_FILE})
endif()
elseif(EXISTS ${LIB})
set(LIB_FILE ${LIB})
message(STATUS "LIB_TYPE : ${LIB} = EXTERNAL")
list(APPEND ALL_LIBS ${LIB_FILE})
endif()
endforeach() # LIB ${ALL_LIBS}

message(STATUS "ALL_LIBS : ${ALL_LIBS}")

# add_custom_command(ie echoing only to stdout) works but more difficult to get from build.rs
# b/c when there is "ninja: no work to do" it will NOT echo on the console
add_custom_command(
TARGET ${TARGET}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo ${ALL_LIBS} > ${CMAKE_CURRENT_BINARY_DIR}/cmake_generated_libs
# OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/cmake_generated_libs
VERBATIM
)
endfunction(export_all_target_libs)
Empty file.
8 changes: 8 additions & 0 deletions crates/rust-cxx-cmake-bridge/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "rust-cxx-cmake-bridge"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
Loading

0 comments on commit 06cf34a

Please sign in to comment.