1#!/bin/bash 2# Copyright (c) Meta Platforms, Inc. and affiliates. 3# All rights reserved. 4# 5# This source code is licensed under the BSD-style license found in the 6# LICENSE file in the root directory of this source tree. 7 8set -eu 9 10function usage() { 11 echo "This script creates XCFrameworks from libraries in specified directories." 12 echo "It merges libraries using libtool and creates an XCFramework using xcodebuild." 13 echo "" 14 echo "Usage: $0 --directory=<dir> --framework=<lib> [--output=<output>]" 15 echo " --directory: Directory containing the libs" 16 echo " --framework: Framework to create in the format 'target:lib1,lib2:headers'" 17 echo " 'target' is the name of the target library." 18 echo " 'lib1,lib2' is a comma-separated list of input libraries." 19 echo " 'headers' is an optional path to a directory with headers." 20 echo " --output: Optional output directory. Defaults to the current directory." 21 echo "" 22 echo "Example:" 23 echo "$0 --directory=ios-arm64 --directory=ios-arm64-simulator --framework=\"mylib:lib1.a,lib2.a:include\" --output=output/dir" 24 exit 1 25} 26 27command -v libtool >/dev/null 2>&1 || { echo >&2 "libtool is required but it's not installed. Aborting."; exit 1; } 28command -v xcodebuild >/dev/null 2>&1 || { echo >&2 "xcodebuild is required but it's not installed. Aborting."; exit 1; } 29 30directories=() 31frameworks=() 32output=$(pwd) 33 34for arg in "$@"; do 35 case $arg in 36 -h|--help) usage ;; 37 --directory=*) directories+=("${arg#*=}") ;; 38 --framework=*) frameworks+=("${arg#*=}") ;; 39 --output=*) output="${arg#*=}" ;; 40 *) 41 echo "Invalid argument: $arg" 42 exit 1 43 ;; 44 esac 45done 46 47if [ ${#directories[@]} -eq 0 ] || [ ${#frameworks[@]} -eq 0 ]; then 48 echo "Both --directory and --framework options are required" 49 usage 50fi 51 52mkdir -p "${output}" 53 54create_xcframework() { 55 local target_library_name 56 target_library_name=$(echo "$1" | cut -d: -f1) 57 local libraries_list 58 libraries_list=$(echo "$1" | cut -d: -f2 | tr ',' '\n') 59 local headers_directory 60 headers_directory=$(echo "$1" | cut -d: -f3) 61 local dir 62 local libraries=() 63 local merged_libs=() 64 65 if [[ -n "$headers_directory" && ! -d "$headers_directory" ]]; then 66 echo "Headers directory ${headers_directory} does not exist" 67 exit 1 68 fi 69 70 # For each directory, create a merged library using libtool. 71 for dir in "${directories[@]}"; do 72 73 if [ ! -d "${dir}" ]; then 74 echo "Directory ${dir} does not exist" 75 exit 1 76 fi 77 78 local dir_suffix 79 dir_suffix=$(echo "$dir" | tr '[:upper:]' '[:lower:]' | sed 's/\//-/g') 80 local merged_lib="${output}/lib${target_library_name}-${dir_suffix}.a" 81 82 # Remove the existing .a file if it exists. 83 if [ -f "${merged_lib}" ]; then 84 echo "Removing existing file ${merged_lib}" 85 rm "${merged_lib}" 86 fi 87 88 echo -e "\nMerging libraries:\n${libraries_list}\nfrom ${dir}\ninto library ${merged_lib}" 89 90 local lib_paths=() 91 for lib in ${libraries_list}; do 92 if [ ! -f "${dir}/${lib}" ]; then 93 echo "File ${dir}/${lib} does not exist" 94 exit 1 95 fi 96 lib_paths+=("${dir}/${lib}") 97 done 98 99 libtool -static -o "${merged_lib}" "${lib_paths[@]}" 100 101 merged_libs+=("${merged_lib}") 102 103 if [[ -n "$headers_directory" ]]; then 104 echo -e "\nIncluding headers from ${headers_directory}" 105 libraries+=("-library" "${merged_lib}" "-headers" "${headers_directory}") 106 else 107 libraries+=("-library" "${merged_lib}") 108 fi 109 done 110 111 # Remove the existing .xcframework if it exists. 112 local xcframework="${output}/${target_library_name}.xcframework" 113 if [ -d "${xcframework}" ]; then 114 echo -e "\nRemoving existing XCFramework ${xcframework}" 115 rm -rf "${xcframework}" 116 fi 117 118 echo -e "\nCreating XCFramework ${xcframework}" 119 120 xcodebuild -create-xcframework "${libraries[@]}" -output "${xcframework}" 121 122 echo -e "\nDeleting intermediate libraries:" 123 for merged_lib in "${merged_libs[@]}"; do 124 if [[ -f "${merged_lib}" ]]; then 125 echo "Deleting ${merged_lib}" 126 rm "${merged_lib}" 127 fi 128 done 129} 130 131# Create an XCFramework for each target library. 132for target_lib in "${frameworks[@]}"; do 133 create_xcframework "$target_lib" 134done 135