Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 16 additions & 22 deletions cmake/BundleStatic.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down Expand Up @@ -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 "$<TARGET_FILE:${TARGET}>" "$<TARGET_FILE:${TARGET}>.tmp" "${cmd}"
COMMAND "${CMAKE_SOURCE_DIR}/tools/bundle_static.sh" "--ar" "${CMAKE_AR}" "--ld" "${LD_LINKER}" "-o" "$<TARGET_FILE:${TARGET}>" "$<TARGET_FILE:${TARGET}>.tmp" "${cmd}"
COMMAND_EXPAND_LISTS
VERBATIM
)
Expand All @@ -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 $<TARGET_FILE:@TARGET@>
addlib $<TARGET_FILE:@TARGET@>.tmp
$<LIST:JOIN,$<LIST:TRANSFORM,@cmd@,PREPEND,addlib >,
>
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" "$<TARGET_FILE:${TARGET}>" "$<TARGET_FILE:${TARGET}>.tmp" "${cmd}"
COMMAND_EXPAND_LISTS
VERBATIM
)
return()
Expand Down
133 changes: 133 additions & 0 deletions tools/bundle_static.sh
Original file line number Diff line number Diff line change
@@ -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 <path-to-ld> --ar <path-to-ar> <output.a> <input1.a> [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!"
Loading