Files
filament/build/linux/combine-static-libs.sh
2025-01-13 14:18:38 -08:00

149 lines
4.5 KiB
Bash
Executable File

#!/usr/bin/env bash
set -e
SELF_NAME=$(basename "$0")
function print_help {
echo "$SELF_NAME. Combine multiple static libraries using an archiver tool."
echo ""
echo "Usage:"
echo " $SELF_NAME <path-to-ar> <output-archive> <archives>..."
echo ""
echo "Notes:"
echo " <archives> must be a list of absolute paths to static library archives."
echo " Mach-O universal binaries are supported, but all archives must be homogeneous: either"
echo " all universal, or none."
echo " This script creates temporary working directories inside the current directory."
}
if [[ "$#" -lt 3 ]]; then
print_help
exit 1
fi
AR_TOOL="$1"
shift
OUTPUT_PATH="$1"
shift
ARCHIVES=("$@")
function combine_static_libs {
local output_path="$1"
shift
local archives=("$@")
# Create a temporary working directory named after the destination library.
local temp_dir="${output_path##*/}" # remove leading path, if any
temp_dir="_${temp_dir%.a}" # remove '.a' extension
mkdir -p "${temp_dir}"
pushd "${temp_dir}" >/dev/null
for a in "${archives[@]}"; do
# Create a separate directory for each archive to combine. This is necessary to avoid
# overriding object files from seprate archives that have the same name.
dir_name="${a##*/}" # remove leading path, if any
dir_name="${dir_name%.a}" # remove '.a' extension
mkdir -p "${dir_name}"
pushd "${dir_name}" >/dev/null
# Extract object files from each archive.
"${AR_TOOL}" -x "$a"
# Prepend the library name to the object file to ensure each object file has a unique name.
for o in *.o; do
mv "$o" "${dir_name}_${o}"
done
popd >/dev/null
done
popd >/dev/null
# Combine the library files into a single static library archive.
rm -f "${output_path}"
"${AR_TOOL}" -qc "${output_path}" $(find "${temp_dir}" -iname '*.o')
# Clean up. Delete objects in the temporary working directory. In theory we could leave the
# directory as a "cache" of extracted object files, but it complicates the logic to handle cases
# where object files are removed from a library.
find "${temp_dir}" -iname "*.o" -delete
}
function universal_error {
echo "Error: archives passed to $SELF_NAME must be either all universal, or all non-universal."
echo "Archives: ${ARCHIVES[*]}"
exit 1
}
# Determine if the archives are Mach-O universal binaries.
has_universal=""
for a in "${ARCHIVES[@]}"; do
if file "$a" | grep -q 'Mach-O universal'; then
if [[ "${has_universal}" == "false" ]]; then
universal_error
fi
has_universal=true
else
if [[ "${has_universal}" == "true" ]]; then
universal_error
fi
has_universal=false
fi
done
if [[ "${has_universal}" == "true" ]]; then
# If the archives are universal libraries, we have to do some extra work:
# - "thin" each archive into its individual architectures
# - for each architecture, combine the single-architecture static libraries
# - create a final universal binary from the static libraries
archs_temp_dir="${OUTPUT_PATH##*/}" # remove leading path, if any
archs_temp_dir="_${archs_temp_dir%.a}_archs" # remove '.a' extension
mkdir -p "${archs_temp_dir}"
pushd "${archs_temp_dir}" >/dev/null
# Thin each archive into its architectures.
for a in "${ARCHIVES[@]}"; do
# Determine which architectures are present in the archive.
archs=$(lipo -archs "${a}")
for arch in ${archs}; do
mkdir -p "${arch}"
lipo -thin "${arch}" -output "${arch}/${a##*/}" "$a"
done
done
popd >/dev/null
# Combine each set of single-architecture archives.
arch_outputs=()
for arch_dir in "${archs_temp_dir}"/*/ ; do
arch=$(basename "$arch_dir")
arch_output="${OUTPUT_PATH%.a}_${arch}.a"
arch_outputs+=("$arch_output")
archives=()
while IFS= read -r -d $'\0'; do
archives+=("$REPLY")
done < <(find "$(pwd)/${archs_temp_dir}/${arch}" -iname '*.a' -print0)
combine_static_libs "$arch_output" "${archives[@]}"
done
# Finally, combine the single-architecture archives into a universal binary.
lipo -create "${arch_outputs[@]}" -output "${OUTPUT_PATH}"
# Clean up.
rm "${arch_outputs[@]}"
find "${archs_temp_dir}" -iname "*.a" -delete
else
combine_static_libs "${OUTPUT_PATH}" "${ARCHIVES[@]}"
fi