#!/bin/bash set -euo pipefail cd "$SRCROOT" # Calculate Bazel `--output_groups` if [ "$ACTION" == "indexbuild" ]; then echo >&2 "error: \`BazelDependencies\` should not run during Index Build." \ "Please file a bug report here:" \ "https://github.com/MobileNativeFoundation/rules_xcodeproj/issues/new?template=bug.md" exit 1 else if [[ "${ENABLE_PREVIEWS:-}" == "YES" ]]; then # Compile params, products (i.e. bundles) and index store data, and link # params readonly output_group_prefixes="bc,bp,bl" else # Products (i.e. bundles) and index store data readonly output_group_prefixes="bp" fi # In Xcode 14 the "Index" directory was renamed to "Index.noindex". # `$INDEX_DATA_STORE_DIR` is set to `$OBJROOT/INDEX_DIR/DataStore`, so we can # use it to determine the name of the directory regardless of Xcode version. readonly index_dir="${INDEX_DATA_STORE_DIR%/*}" readonly index_dir_name="${index_dir##*/}" # Xcode doesn't adjust `$OBJROOT` in scheme action scripts when building for # previews. So we need to look in the non-preview build directory for this file. readonly non_preview_objroot="${OBJROOT/\/Intermediates.noindex\/Previews\/*//Intermediates.noindex}" readonly base_objroot="${non_preview_objroot/\/$index_dir_name\/Build\/Intermediates.noindex//Build/Intermediates.noindex}" readonly build_marker_file="$non_preview_objroot/build_marker" # We need to read from `$output_groups_file` as soon as possible, as concurrent # writes to it can happen during indexing, which breaks the off-by-one-by-design # nature of it IFS=$'\n' read -r -d '' -a labels_and_output_groups < \ <( "$CALCULATE_OUTPUT_GROUPS_SCRIPT" \ "$XCODE_VERSION_ACTUAL" \ "$non_preview_objroot" \ "$base_objroot" \ "$build_marker_file" \ $output_group_prefixes \ && printf '\0' ) readonly outputgroup_regex='[^\ ]+ @{0,2}(.*)//(.*):(.*) ([^\ ]+)$' raw_labels=() raw_target_ids=() output_groups=("index_import" "target_ids_list") indexstores_filelists=() for (( i=0; i<${#labels_and_output_groups[@]}; i+=2 )); do raw_labels+=("${labels_and_output_groups[i]}") output_group="${labels_and_output_groups[i+1]}" raw_target_ids+=("${output_group#* }") output_groups+=("$output_group") output_type="${output_group%% *}" if [[ "$output_type" == 'xi' || "$output_type" == 'bi' ]]; then if [[ $output_group =~ $outputgroup_regex ]]; then repo="${BASH_REMATCH[1]}" if [[ "$repo" == "@" ]]; then repo="" fi package="${BASH_REMATCH[2]}" target="${BASH_REMATCH[3]}" configuration="${BASH_REMATCH[4]}" filelist="$configuration/bin/${repo:+"external/$repo/"}$package/$target-${output_type}.filelist" indexstores_filelists+=("$filelist") fi fi done readonly indexstores_filelists if [ "${#output_groups[@]}" -eq 1 ]; then echo "BazelDependencies invoked without any output groups set." \ "Exiting early." exit else labels=() while IFS= read -r -d '' label; do labels+=("$label") done < <(printf "%s\0" "${raw_labels[@]}" | sort -uz) target_ids=() while IFS= read -r -d '' target_id; do target_ids+=("$target_id") done < <(printf "%s\0" "${raw_target_ids[@]}" | sort -uz) fi fi # Build build_pre_config_flags=( # Include the following: # # - .indexstore directories to allow importing indexes # - .swift{doc,sourceinfo} files for indexing # - .a and .swiftmodule files for lldb # - primary compilation input files (.c, .C, .cc, .cl, .cpp, .cu, .cxx, .c++, # .m, .mm, .swift) for Xcode build input checking # - files needed for Clang importer (headers, modulemaps, yaml files, etc.) # # This is brittle. If different file extensions are used for compilation # inputs, they will need to be added to this list. Ideally we can stop doing # this once Bazel adds support for a Remote Output Service. "--remote_download_regex=.*\.indexstore/.*|.*\.(a|cfg|c|C|cc|cl|cpp|cu|cxx|c++|def|h|H|hh|hpp|hxx|h++|hmap|ilc|inc|inl|ipp|tcc|tlh|tli|tpp|m|modulemap|mm|pch|swift|swiftdoc|swiftmodule|swiftsourceinfo|yaml)$" ) apply_sanitizers=1 if [ "$ACTION" == "indexbuild" ]; then readonly config="${BAZEL_CONFIG}_indexbuild" # Index Build doesn't need sanitizers apply_sanitizers=0 elif [ "${ENABLE_PREVIEWS:-}" == "YES" ]; then readonly config="${BAZEL_CONFIG}_swiftuipreviews" elif [ "${CLANG_COVERAGE_MAPPING:-}" == YES ] && [ "${BAZEL_SUPPRESS_COVERAGE_BUILD:-}" != YES ]; then # Code coverage build # # CLANG_COVERAGE_MAPPING is set to YES when the active scheme's test action has code coverage enabled. It is configured # irrespective of the value of ENABLE_CODE_COVERAGE, and of whether the current build action is for testing or not. # # We would rather use ENABLE_CODE_COVERAGE here, but the value of that setting is often YES even when code coverage is not # enabled in the active scheme. readonly config="${BAZEL_CONFIG}_coverage" echo "warning: Code coverage is enabled. In order to maintain compatibility with Xcode, the instrumented build is not hermetic. Remote cache performance will be affected." >&2 else readonly config="_${BAZEL_CONFIG}_build" fi # Respect the "Continue building after errors" setting continue_building_value="$(defaults read com.apple.dt.Xcode IDEBuildingContinueBuildingAfterErrors 2>/dev/null || echo 0)" if [ "$continue_building_value" == "1" ]; then build_pre_config_flags+=("--keep_going") else build_pre_config_flags+=("--nokeep_going") fi # Runtime Sanitizers if [[ $apply_sanitizers -eq 1 ]]; then if [ "${ENABLE_ADDRESS_SANITIZER:-}" == "YES" ]; then build_pre_config_flags+=( --copt=-fno-omit-frame-pointer --copt=-fno-sanitize-recover=all --copt=-fsanitize=address --linkopt=-fsanitize=address --@@rules_swift+//swift:copt=-sanitize=address --copt=-Wno-macro-redefined --copt=-D_FORTIFY_SOURCE=0 ) fi if [ "${ENABLE_THREAD_SANITIZER:-}" == "YES" ]; then build_pre_config_flags+=( --copt=-fno-omit-frame-pointer --copt=-fno-sanitize-recover=all --copt=-fsanitize=thread --linkopt=-fsanitize=thread --@@rules_swift+//swift:copt=-sanitize=thread ) fi if [ "${ENABLE_UNDEFINED_BEHAVIOR_SANITIZER:-}" == "YES" ]; then build_pre_config_flags+=( --copt=-fno-omit-frame-pointer --copt=-fno-sanitize-recover=all --copt=-fsanitize=undefined --linkopt=-fsanitize=undefined ) fi fi readonly build_pre_config_flags # `bazel_build.sh` sets `output_path` source "$BAZEL_INTEGRATION_DIR/bazel_build.sh" # Async actions # # For these commands to run in the background, both stdout and stderr need to be # redirected, otherwise Xcode will block the run script. readonly log_dir="$OBJROOT/rules_xcodeproj_logs" mkdir -p "$log_dir" # Report errors from previous async actions shopt -s nullglob for log in "$log_dir"/*.async.log; do if [[ -s "$log" ]]; then command=$(basename "${log%.async.log}") echo "warning: Previous run of \"$command\" had output:" >&2 sed "s|^|warning: |" "$log" >&2 echo "warning: If you believe this is a bug, please file a report here:" \ "https://github.com/MobileNativeFoundation/rules_xcodeproj/issues/new?template=bug.md" \ >&2 fi done # Import indexes if [ -n "${indexstores_filelists:-}" ]; then if [[ "${BAZEL_SEPARATE_INDEXBUILD_OUTPUT_BASE:-}" == "YES" ]]; then "$BAZEL_INTEGRATION_DIR/import_indexstores" \ "$INDEXING_PROJECT_DIR__NO" \ "${indexstores_filelists[@]/#/$output_path/}" \ >"$log_dir/import_indexstores.async.log" 2>&1 & else "$BAZEL_INTEGRATION_DIR/import_indexstores" \ "$PROJECT_DIR" \ "${indexstores_filelists[@]/#/$BAZEL_OUT/}" \ >"$log_dir/import_indexstores.async.log" 2>&1 & fi fi