diff --git a/cmake/BundleStatic.cmake b/cmake/BundleStatic.cmake index dec8a901c222..be4671c54fa1 100644 --- a/cmake/BundleStatic.cmake +++ b/cmake/BundleStatic.cmake @@ -22,10 +22,15 @@ function(_bundle_static_check_output VAR) set("${VAR}" "${${VAR}}" PARENT_SCOPE) endfunction() -function(_bundle_static_is_apple_libtool result_var item) - _bundle_static_check_output(version_info "${item}" -V) - if (NOT version_info MATCHES "Apple,? Inc\\.") - set(${result_var} 0 PARENT_SCOPE) + +function(_bundle_static_is_apple_ld result_var ld_tool) + execute_process(COMMAND "${ld_tool}" -v + OUTPUT_VARIABLE captured_output + ERROR_VARIABLE captured_error + RESULT_VARIABLE return_code + ) + if (captured_error MATCHES "Apple") + set(${result_var} 1 PARENT_SCOPE) endif () endfunction() @@ -85,12 +90,13 @@ function(bundle_static TARGET) ) return() endif () - - find_program(LIBTOOL libtool VALIDATOR _bundle_static_is_apple_libtool) - if (APPLE AND LIBTOOL) + + find_program(LD_LINKER ld HINTS "${CMAKE_LD}") + _bundle_static_is_apple_ld(is_apple_ld "${LD_LINKER}") + if (APPLE AND is_apple_ld) add_custom_command( TARGET "${TARGET}" POST_BUILD - COMMAND "${LIBTOOL}" -static -o "$" "$.tmp" "${cmd}" + COMMAND "${CMAKE_SOURCE_DIR}/tools/bundle_static.sh" "--ar" "${CMAKE_AR}" "--ld" "${LD_LINKER}" "-o" "$" "$.tmp" "${cmd}" COMMAND_EXPAND_LISTS VERBATIM ) @@ -99,22 +105,10 @@ function(bundle_static TARGET) _bundle_static_check_output(version_info "${CMAKE_AR}" V) if (version_info MATCHES "GNU") - string(CONFIGURE [[ - create $ - addlib $.tmp - $, - > - save - end - ]] mri_script) - string(REGEX REPLACE "(^|\n) +" "\\1" mri_script "${mri_script}") - - file(GENERATE OUTPUT "fuse-${TARGET}.mri" - CONTENT "${mri_script}" TARGET "${TARGET}") - add_custom_command( TARGET "${TARGET}" POST_BUILD - COMMAND "${CMAKE_AR}" -M < "${CMAKE_CURRENT_BINARY_DIR}/fuse-${TARGET}.mri" + COMMAND "${CMAKE_SOURCE_DIR}/tools/bundle_static.sh" "--ar" "${CMAKE_AR}" "--ld" "${LD_LINKER}" "-o" "$" "$.tmp" "${cmd}" + COMMAND_EXPAND_LISTS VERBATIM ) return() diff --git a/tools/bundle_static.sh b/tools/bundle_static.sh new file mode 100755 index 000000000000..9e52719f164a --- /dev/null +++ b/tools/bundle_static.sh @@ -0,0 +1,133 @@ +#!/bin/bash +# This script combines a bunch of static libs and does a partial link across all object +# files to resolve all internal references to produce a merged static lib. + +# Check if at least two arguments are provided (input libraries + output library) +if [ "$#" -lt 2 ]; then + echo "Usage: $0 --ld --ar [input2.a ...]" + exit 1 +fi + +POSITIONAL_ARGS=() +LD_TOOL="ld" +AR_TOOL="ar" +OUTPUT_LIB="" + +while [[ $# -gt 0 ]]; do + case $1 in + -l|--ld) + LD_TOOL="$2" + shift # past argument + shift # past value + ;; + -a|--ar) + AR_TOOL="$2" + shift # past argument + shift # past value + ;; + -o|--output) + OUTPUT_LIB="$2" + shift # past argument + shift # past value + ;; + -*|--*) + echo "Unknown option $1" + exit 1 + ;; + *) + POSITIONAL_ARGS+=("$1") # save positional arg + shift # past argument + ;; + esac +done + +set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters + +OS=$(uname -s) +OS="`uname`" +case $OS in + 'Linux') + LD_FLAGS="-Ur" + ;; + 'Darwin') + LD_FLAGS="-r" + ;; + *) ;; +esac + +echo "Creating merged library $OUTPUT_LIB ..." +OUTPUT_OBJ="${OUTPUT_LIB%.*}.o" + +# Create a temporary directory to extract object files +TEMP_DIR=$(mktemp -d) +echo "Creating temporary directory $TEMP_DIR ..." +if [ $? -ne 0 ]; then + echo "Error: Could not create temporary directory." + exit 1 +fi +cd $TEMP_DIR + +# Process each input library +MERGE_OBJS=() +for LIB in "$@"; do + if [ ! -f "$LIB" ]; then + echo "Error: Input library '$LIB' not found." + rm -rf "$TEMP_DIR" + exit 1 + fi + echo "Extracting objects from $LIB ..." + LIB_NAME="$(basename $LIB)" + + # Extract object files from each input library into + # a subdir in the temporary directory + mkdir "$TEMP_DIR/$LIB_NAME" + if [ $? -ne 0 ]; then + echo "Error: Failed to create dir $TEMP_DIR/$LIB_NAME." + exit 1 + fi + + cd "$TEMP_DIR/$LIB_NAME" + $AR_TOOL -x "$LIB" + if [ $? -ne 0 ]; then + echo "Error: Failed to extract objects from $LIB." + exit 1 + fi + + # Rename the library object files and prepend the library name + # to the object file name in the top level temporary directory + cd "$TEMP_DIR" + for OBJ_FILE in "$LIB_NAME"/*.o; do + OBJ_NAME="$(basename $OBJ_FILE)" + mv "$OBJ_FILE" "$TEMP_DIR/$LIB_NAME-$OBJ_NAME" + MERGE_OBJS+=("$TEMP_DIR/$LIB_NAME-$OBJ_NAME") + done + if [ $? -ne 0 ]; then + echo "Error: Failed to extract objects from $LIB." + exit 1 + fi +done + +# Do a partial-link from all extracted object files to resolve internal references +cd "$TEMP_DIR" +echo "Creating merged object file $OUTPUT_OBJ ..." +$LD_TOOL "$LD_FLAGS" -o "$OUTPUT_OBJ" "${MERGE_OBJS[@]}" +if [ $? -ne 0 ]; then + echo "Error: Failed to create the merged library." + rm -r "$TEMP_DIR" + exit 1 +fi + +# Create the final static lib +echo "Creating merged library $OUTPUT_LIB ..." +$AR_TOOL -rcsv "$OUTPUT_LIB" "$OUTPUT_OBJ" +if [ $? -ne 0 ]; then + echo "Error: Failed to create the merged library." + rm -r "$TEMP_DIR" + exit 1 +fi + +# Clean up the temporary directory +echo "Cleaning up temporary directory..." +rm -r "$TEMP_DIR" + +echo "Done!" \ No newline at end of file