#!/bin/bash # Find the transitive closure of overlay dependencies for a single overlay. # Runs the following command in a loop until the list stops growing: # xcrun -sdk macosx clang -arch x86_64 -x objective-c - -M -fmodules < <(echo '@import SceneKit;@import AppKit;') # There are two ways an overlay ``foo`` shows up in the xcrun output: # 1) as Foo.framework # 2) as /usr/include/foo/bar.h # but not: # 3) as /usr/include/foo/module.map or /usr/include/foo/modulemap.map # Overlays that only show up as a module map are not a real dependency. # Overlays that have a different name in Swift than in the output: Dispatch, ObjectiveC, XPC # XCTest is hardcoded because this method doesn't work for it. set -o pipefail set -e OVERLAY_NAME_ALTERNATION="AppKit|AssetsLibrary|AVFoundation|CallKit|CloudKit|Compression|Contacts|CoreAudio|CoreData|CoreGraphics|CoreImage|CoreLocation|CoreMedia|CoreML|CryptoTokenKit|dispatch|Foundation|GameplayKit|GLKit|HomeKit|IOKit|Intents|MapKit|objc|OpenCL|os|Photos|QuartzCore|SafariServices|SceneKit|simd|SpriteKit|UIKit|WatchKit|XCTest|xpc" function find_deps() { local OVERLAY_ARG=$1 local SDK_ARG=$2 local ARCH_ARG=$3 local PROGRAM="" # shellcheck disable=SC2013 for overlay in $(sed "s/;/ /g" <<< "$OVERLAY_ARG"); do regexp="ObjectiveC|objc|Dispatch|dispatch|XPC|xpc" if [[ ! $overlay =~ $regexp ]]; then PROGRAM+="@import $overlay;" fi done local DEPS DEPS=$(xcrun -sdk "$SDK_ARG" clang -arch "$ARCH_ARG" -x objective-c - -M -fmodules <<< "$PROGRAM" 2>&1) local ERROR_REGEX="(.*error:.*)" if [[ $DEPS =~ $ERROR_REGEX ]]; then echo "${BASH_REMATCH[1]}" >&2 exit 123 fi local REGEX="./Frameworks/(${OVERLAY_NAME_ALTERNATION}).framework/.*|.*/usr/include/(xpc|dispatch|os|objc|simd|compression)/.*\.h" # shellcheck disable=SC1004 IFS='\ ' local USED_OVERLAYS="" # shellcheck disable=SC2068 for line in ${DEPS[@]}; do if [[ $line =~ $REGEX ]]; then if [[ ${BASH_REMATCH[1]} != "" ]]; then USED_OVERLAYS+="${BASH_REMATCH[1]};" elif [[ ${BASH_REMATCH[2]} == "dispatch" ]]; then USED_OVERLAYS+="Dispatch;" elif [[ ${BASH_REMATCH[2]} == "xpc" ]]; then USED_OVERLAYS+="XPC;" elif [[ ${BASH_REMATCH[2]} == "objc" ]]; then USED_OVERLAYS+="ObjectiveC;" elif [[ ${BASH_REMATCH[2]} != "" ]]; then USED_OVERLAYS+="${BASH_REMATCH[2]};" fi fi done # Remove last ; if [[ ${#USED_OVERLAYS} -gt 0 ]]; then USED_OVERLAYS=${USED_OVERLAYS%?} fi TRIMMED=$(tr ";" "\n" <<< "$USED_OVERLAYS" | sort | uniq | tr "\n" ";") echo "${TRIMMED%?}" } if [ "$#" -ne 3 ]; then echo "error: $0 needs 3 params, instead got $#" echo "usage: $0 Overlay sdk arch" echo "example: $0 CloudKit macosx x86_64" exit 234 fi OVERLAY_ARG=$1 SDK_ARG=$2 ARCH_ARG=$3 OUT=$OVERLAY_ARG LAST_OUT=$OVERLAY_ARG # Hardcode XCTest because clang can't find its dependencies if [[ $OVERLAY_ARG == "XCTest" ]]; then case "$SDK_ARG" in macosx) OUT="XCTest;AppKit;CoreData;CoreGraphics;CoreImage;Dispatch;Foundation;IOKit;ObjectiveC;QuartzCore;XPC;os" ;; iphoneos) OUT="XCTest;CoreAudio;CoreGraphics;CoreImage;CoreMedia;Dispatch;Foundation;ObjectiveC;QuartzCore;UIKit;os" ;; appletvos) OUT="XCTest;CoreGraphics;CoreImage;Dispatch;Foundation;ObjectiveC;QuartzCore;UIKit;os" ;; *) echo "Unknown SDK: $SDK_ARG" exit 345 ;; esac else while true; do OUT=$(find_deps "$LAST_OUT" "$SDK_ARG" "$ARCH_ARG") if [[ "$LAST_OUT" == "$OUT" ]]; then break fi LAST_OUT=$OUT done fi echo "${OUT}"