From aa7a7eec96f12a96e5723637a8ed3f990b60f153 Mon Sep 17 00:00:00 2001 From: Brentley Jones Date: Fri, 6 Oct 2023 14:10:27 -0500 Subject: [PATCH] Convert `import_indexstores.sh` into Swift binary This is mainly to be able to do more complex stuff in the near future for incremental generators. It has the side benefit of being faster. Signed-off-by: Brentley Jones --- distribution/BUILD | 3 + ...port_indexstores.sh => import_indexstores} | 0 ...port_indexstores.sh => import_indexstores} | 0 ...port_indexstores.sh => import_indexstores} | 0 tools/BUILD | 20 ++ tools/import_indexstores/BUILD | 59 +++++ tools/import_indexstores/BUILD.release.bazel | 1 + tools/import_indexstores/Errors.swift | 29 +++ .../ImportIndexstores.swift | 216 ++++++++++++++++++ tools/import_indexstores/Remaps.swift | 68 ++++++ tools/import_indexstores/TemporaryFile.swift | 14 ++ tools/swiftc_stub/BUILD | 1 + .../internal/bazel_integration_files/BUILD | 30 ++- .../generate_bazel_dependencies.sh | 2 +- ...generate_index_build_bazel_dependencies.sh | 2 +- .../import_indexstores.sh | 126 ---------- xcodeproj/internal/templates/installer.sh | 2 +- 17 files changed, 439 insertions(+), 134 deletions(-) rename examples/integration/test/fixtures/bwb.xcodeproj/rules_xcodeproj/bazel/{import_indexstores.sh => import_indexstores} (100%) mode change 100755 => 100644 rename examples/integration/test/fixtures/bwx.xcodeproj/rules_xcodeproj/bazel/{import_indexstores.sh => import_indexstores} (100%) mode change 100755 => 100644 rename examples/rules_ios/test/fixtures/bwb.xcodeproj/rules_xcodeproj/bazel/{import_indexstores.sh => import_indexstores} (100%) mode change 100755 => 100644 create mode 100644 tools/import_indexstores/BUILD create mode 100644 tools/import_indexstores/BUILD.release.bazel create mode 100644 tools/import_indexstores/Errors.swift create mode 100644 tools/import_indexstores/ImportIndexstores.swift create mode 100644 tools/import_indexstores/Remaps.swift create mode 100644 tools/import_indexstores/TemporaryFile.swift delete mode 100755 xcodeproj/internal/bazel_integration_files/import_indexstores.sh diff --git a/distribution/BUILD b/distribution/BUILD index 5ede87594b..c1df3b2f53 100644 --- a/distribution/BUILD +++ b/distribution/BUILD @@ -52,6 +52,9 @@ pkg_tar( remap_paths = dicts.add( { "MODULE.release.bazel": "MODULE.bazel", + "tools/import_indexstores/BUILD.release.bazel": ( + "tools/import_indexstores/BUILD" + ), "tools/swiftc_stub/BUILD.release.bazel": "tools/swiftc_stub/BUILD", "xcodeproj/repositories.release.bzl": "xcodeproj/repositories.bzl", }, diff --git a/examples/integration/test/fixtures/bwb.xcodeproj/rules_xcodeproj/bazel/import_indexstores.sh b/examples/integration/test/fixtures/bwb.xcodeproj/rules_xcodeproj/bazel/import_indexstores old mode 100755 new mode 100644 similarity index 100% rename from examples/integration/test/fixtures/bwb.xcodeproj/rules_xcodeproj/bazel/import_indexstores.sh rename to examples/integration/test/fixtures/bwb.xcodeproj/rules_xcodeproj/bazel/import_indexstores diff --git a/examples/integration/test/fixtures/bwx.xcodeproj/rules_xcodeproj/bazel/import_indexstores.sh b/examples/integration/test/fixtures/bwx.xcodeproj/rules_xcodeproj/bazel/import_indexstores old mode 100755 new mode 100644 similarity index 100% rename from examples/integration/test/fixtures/bwx.xcodeproj/rules_xcodeproj/bazel/import_indexstores.sh rename to examples/integration/test/fixtures/bwx.xcodeproj/rules_xcodeproj/bazel/import_indexstores diff --git a/examples/rules_ios/test/fixtures/bwb.xcodeproj/rules_xcodeproj/bazel/import_indexstores.sh b/examples/rules_ios/test/fixtures/bwb.xcodeproj/rules_xcodeproj/bazel/import_indexstores old mode 100755 new mode 100644 similarity index 100% rename from examples/rules_ios/test/fixtures/bwb.xcodeproj/rules_xcodeproj/bazel/import_indexstores.sh rename to examples/rules_ios/test/fixtures/bwb.xcodeproj/rules_xcodeproj/bazel/import_indexstores diff --git a/tools/BUILD b/tools/BUILD index 615dbbf6e0..e0a48b9d76 100644 --- a/tools/BUILD +++ b/tools/BUILD @@ -5,6 +5,7 @@ load("//xcodeproj/internal:collections.bzl", "flatten", "uniq") _TOOLS = { "files_and_groups": "//tools/generators/files_and_groups", + "import_indexstores": "//tools/import_indexstores", "pbxproj_prefix": "//tools/generators/pbxproj_prefix", "pbxtargetdependencies": "//tools/generators/pbxtargetdependencies", "swiftc_stub": "//tools/swiftc_stub:swiftc", @@ -75,6 +76,24 @@ _SCHEMES = [ diagnostics = _SCHEME_DIAGNOSTICS, ), ), + xcode_schemes.scheme( + name = "import_indexstores", + build_action = xcode_schemes.build_action( + targets = [ + xcode_schemes.build_target( + _TOOLS["import_indexstores"], + ), + ], + ), + launch_action = xcode_schemes.launch_action( + _TOOLS["import_indexstores"], + diagnostics = _SCHEME_DIAGNOSTICS, + ), + profile_action = xcode_schemes.profile_action( + _TOOLS["import_indexstores"], + build_configuration = "Release", + ), + ), xcode_schemes.scheme( name = "pbxproj_prefix", launch_action = xcode_schemes.launch_action( @@ -223,6 +242,7 @@ filegroup( srcs = [ "//" + package_name() + "/extension_point_identifiers_parser:release_files", "//" + package_name() + "/generators:release_files", + "//" + package_name() + "/import_indexstores:release_files", "//" + package_name() + "/params_processors:release_files", "//" + package_name() + "/swiftc_stub:release_files", "//" + package_name() + "/xccurrentversions_parser:release_files", diff --git a/tools/import_indexstores/BUILD b/tools/import_indexstores/BUILD new file mode 100644 index 0000000000..a502f5d3d0 --- /dev/null +++ b/tools/import_indexstores/BUILD @@ -0,0 +1,59 @@ +load("@build_bazel_rules_apple//apple:apple.bzl", "apple_universal_binary") +load( + "@build_bazel_rules_apple//apple:macos.bzl", + "macos_command_line_application", +) +load( + "@build_bazel_rules_swift//swift:swift.bzl", + "swift_binary", + "swift_library", +) + +# This target exists to keep configurations the same between the generator +# and the tests, which makes the Xcode development experience better. If we used +# `swift_binary` or `apple_universal_binary` in `xcodeproj`, then the +# `macos_unit_test` transition (which is used to be able to set a minimum os +# version on the tests) will create slightly different configurations for our +# `swift_library`s. Maybe https://github.com/bazelbuild/bazel/issues/6526 will +# fix that for us. +macos_command_line_application( + name = "import_indexstores", + minimum_os_version = "12.0", + visibility = ["//visibility:public"], + deps = [":import_indexstores.library"], +) + +swift_library( + name = "import_indexstores.library", + srcs = glob(["*.swift"]), + module_name = "import_indexstores", +) + +swift_binary( + name = "import_indexstores_binary", + deps = [":import_indexstores.library"], +) + +apple_universal_binary( + name = "universal_import_indexstores", + binary = ":import_indexstores_binary", + forced_cpus = [ + "x86_64", + "arm64", + ], + minimum_os_version = "12.0", + platform_type = "macos", + visibility = ["//visibility:public"], +) + +# Release + +filegroup( + name = "release_files", + srcs = [ + "BUILD.release.bazel", + ":universal_import_indexstores", + ], + tags = ["manual"], + visibility = ["//:__subpackages__"], +) diff --git a/tools/import_indexstores/BUILD.release.bazel b/tools/import_indexstores/BUILD.release.bazel new file mode 100644 index 0000000000..2f595bbb80 --- /dev/null +++ b/tools/import_indexstores/BUILD.release.bazel @@ -0,0 +1 @@ +exports_files(["universal_import_indexstores"]) diff --git a/tools/import_indexstores/Errors.swift b/tools/import_indexstores/Errors.swift new file mode 100644 index 0000000000..4ab1b78d4c --- /dev/null +++ b/tools/import_indexstores/Errors.swift @@ -0,0 +1,29 @@ +import Foundation + +/// An `Error` that represents a programming error. +public struct PreconditionError: Error { + public let message: String + public let file: StaticString + public let line: UInt + + public init( + message: String, + file: StaticString = #filePath, + line: UInt = #line + ) { + self.message = message + self.file = file + self.line = line + } +} + +extension PreconditionError: LocalizedError { + public var errorDescription: String? { + return """ +Internal precondition failure: +\(file):\(line): \(message) +Please file a bug report at \ +https://github.com/MobileNativeFoundation/rules_xcodeproj/issues/new?template=bug.md +""" + } +} diff --git a/tools/import_indexstores/ImportIndexstores.swift b/tools/import_indexstores/ImportIndexstores.swift new file mode 100644 index 0000000000..d06335128b --- /dev/null +++ b/tools/import_indexstores/ImportIndexstores.swift @@ -0,0 +1,216 @@ +import Foundation + +@main +struct ImportIndex { + static func main() async throws { + let args = CommandLine.arguments + let pidFile = + try getEnvironmentVariable("OBJROOT") + "/import_indexstores.pid" + + guard args.count > 1 else { + throw PreconditionError( + message: "Not enough arguments, expected path to execution root" + ) + } + let buildExecutionRoot = args[1] + + // Exit early if no indexstore filelists were provided + if args.count == 2 { + return + } + + // MARK: pidFile + + // Kill any previously running import + if FileManager.default.fileExists(atPath: pidFile) { + let pid = try String(contentsOfFile: pidFile) + + try runSubProcess("/bin/kill", [pid]) + while true { + if try runSubProcess("/bin/kill", ["-0", pid]) != 0 { + break + } + sleep(1) + } + } + + // Set pid to allow cleanup later + try String(ProcessInfo.processInfo.processIdentifier) + .write(toFile: pidFile, atomically: true, encoding: .utf8) + defer { + try? FileManager.default.removeItem(atPath: pidFile) + } + + // MARK: filelist + + let projectDirPrefix = try getEnvironmentVariable("PROJECT_DIR") + "/" + + // Merge all filelists into a single file + var indexStores: Set = [] + for filePath in args.dropFirst(2) { + let url = URL(fileURLWithPath: filePath) + for try await indexStore in url.lines { + indexStores.insert(indexStore) + } + } + + // Exit early if no indexstores were provided + guard !indexStores.isEmpty else { + return + } + + let filelistContent = indexStores + .map { projectDirPrefix + $0 + "\n" } + .joined() + let filelist = try TemporaryFile() + try filelistContent + .write(to: filelist.url, atomically: true, encoding: .utf8) + + // MARK: Remaps + + // We remove any `/private` prefix from the current execution_root, + // since it's removed in the Project navigator + let xcodeExecutionRoot: String + if buildExecutionRoot.hasPrefix("/private") { + xcodeExecutionRoot = String(buildExecutionRoot.dropFirst(8)) + } else { + xcodeExecutionRoot = buildExecutionRoot + } + + let projectTempDir = try getEnvironmentVariable("PROJECT_TEMP_DIR") + + let objectFilePrefix: String + if try getEnvironmentVariable("ACTION") == "indexbuild" { + // Remove `Index.noindex/` part of path + objectFilePrefix = projectTempDir.replacingOccurrences( + of: "/Index.noindex/Build/Intermediates.noindex/", + with: "/Build/Intermediates.noindex/" + ) + } else { + // Remove SwiftUI Previews part of path + objectFilePrefix = try projectTempDir.replacingRegex( + matching: #""" +Intermediates\.noindex/Previews/[^/]*/Intermediates\.noindex +"""#, + with: "Intermediates.noindex" + ) + } + + let xcodeOutputBase = xcodeExecutionRoot + .split(separator: "/") + .dropLast(2) + .joined(separator: "/") + + let archs = try getEnvironmentVariable("ARCHS") + let arch = String(archs.split(separator: " ", maxSplits: 1).first!) + + let remaps = remapArgs( + arch: arch, + developerDir: try getEnvironmentVariable("DEVELOPER_DIR"), + objectFilePrefix: objectFilePrefix, + srcRoot: try getEnvironmentVariable("SRCROOT"), + xcodeExecutionRoot: xcodeExecutionRoot, + xcodeOutputBase: xcodeOutputBase + ) + + // MARK: Import + + let indexDataStoreDir = URL( + fileURLWithPath: try getEnvironmentVariable("INDEX_DATA_STORE_DIR") + ) + let recordsDir = indexDataStoreDir.appendingPathComponent("v5/records") + + try FileManager.default.createDirectory( + at: recordsDir, + withIntermediateDirectories: true + ) + + try runSubProcess( + try getEnvironmentVariable("INDEX_IMPORT"), + remaps + [ + "-undo-rules_swift-renames", + "-incremental", + "@\(filelist.url.path)", + indexDataStoreDir.path, + ] + ) + + // Unit files are created fresh, but record files are copied from + // `bazel-out/`, which are read-only. We need to adjust their + // permissions. + // TODO: do this in `index-import` + try setWritePermissions(in: recordsDir) + } +} + +private func getEnvironmentVariable( + _ key: String, + file: StaticString = #filePath, + line: UInt = #line +) throws -> String { + guard let value = ProcessInfo.processInfo.environment[key] else { + throw PreconditionError( + message: #"Environment variable "\#(key)" not set"#, + file: file, + line: line + ) + } + guard !value.isEmpty else { + throw PreconditionError( + message: #""" +Environment variable "\#(key)" is set to an empty string +"""#, + file: file, + line: line + ) + } + return value +} + +@discardableResult private func runSubProcess( + _ executable: String, + _ args: [String] +) throws -> Int32 { + let task = Process() + task.launchPath = executable + task.arguments = args + try task.run() + task.waitUntilExit() + return task.terminationStatus +} + +private func setWritePermissions(in url: URL) throws { + let enumerator = FileManager.default.enumerator( + at: url, + includingPropertiesForKeys: [.isDirectoryKey] + )! + for case let url as URL in enumerator { + let resourceValues = try url.resourceValues(forKeys: [.isDirectoryKey]) + if resourceValues.isDirectory! { + try FileManager.default.setAttributes( + [.posixPermissions: 0o755], + ofItemAtPath: url.path + ) + } else { + try FileManager.default.setAttributes( + [.posixPermissions: 0o644], + ofItemAtPath: url.path + ) + } + } +} + +extension String { + func replacingRegex( + matching pattern: String, + with template: String + ) throws -> String { + let regex = try NSRegularExpression(pattern: pattern) + let range = NSRange(startIndex..., in: self) + return regex.stringByReplacingMatches( + in: self, + range: range, + withTemplate: template + ) + } + } diff --git a/tools/import_indexstores/Remaps.swift b/tools/import_indexstores/Remaps.swift new file mode 100644 index 0000000000..e3f1039fe5 --- /dev/null +++ b/tools/import_indexstores/Remaps.swift @@ -0,0 +1,68 @@ +// We only support importing indexes built with rules_xcodeproj, and we override +// our output bases, so we know the the ending of the execution root +let executionRootRegex = #".*/[^/]+/(?:_)?rules_xcodeproj(?:\.noindex)?/[^/]+_output_base/execroot/[^/]+"# + +func remapArgs( + arch: String, + developerDir: String, + objectFilePrefix: String, + srcRoot: String, + xcodeExecutionRoot: String, + xcodeOutputBase: String +) -> [String] { + // The order of remaps is important. The first match is used. So we try the + // most specific first. This also allows us to assume previous matches have + // taken care of those types of files, so more general matches still work + // later. + return [ + // Object files + // + // These currently come back relative, but we have the execution_root as + // an optional prefix in case this changes in the future. The path is + // based on rules_swift's current logic: + // https://github.com/bazelbuild/rules_swift/blob/6153a848f747e90248a8673869c49631f1323ff3/swift/internal/derived_files.bzl#L114-L119 + // When we add support for C-based index imports we will have to use + // another pattern: + // https://github.com/bazelbuild/bazel/blob/c4a1ab8b6577c4376aaaa5c3c2d4ef07d524175c/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java#L1358 + "-remap", + #"^(?:\#(executionRootRegex)/|\./)?(bazel-out/[^/]+/bin/)(?:_swift_incremental/)?(.*?)([^/]+)_objs/.*?([^/]+?)(?:\.swift)?\.o$=\#(objectFilePrefix)/$1$2$3/Objects-normal/\#(arch)/$4.o"#, + + // Generated sources and swiftmodules + // + // With object files taken care of, any other paths with `bazel-out/` as + // their prefix (relative to the execution_root) are assumed to be + // generated outputs. The two kinds of generated outputs used in the + // unit files are swiftmodule and source paths. So we map that, along + // with the `external/` prefix for external sources, to the current + // execution_root. Finally, currently these paths are returned as + // absolute, but a future change might make them relative, similar to + // the object files, so we have the execution_root as an optional + // prefix. + "-remap", + #"^(?:\#(executionRootRegex)/|\./)?bazel-out/=\#(xcodeExecutionRoot)/bazel-out/"#, + + // External sources + // + // External sources need to be handled differently, since we use the + // non-symlinked version in Xcode. + "-remap", + #"^(?:\#(executionRootRegex)/|\./)?external/=\#(xcodeOutputBase)/external/"#, + + // Project sources + // + // With the other source files and generated files taken care of, all + // other execution_root prefixed paths should be project sources. + "-remap", + #"^\#(executionRootRegex)=\#(srcRoot)"#, + + // Sysroot + // + // The only other type of path in the unit files are sysroot based. + // While these should always be Xcode.app relative, our regex supports + // command-line tools based paths as well. + // `DEVELOPER_DIR` has an optional `./` prefix, because index-import + // adds `./` to all relative paths. + "-remap", + #"^(?:.*?/[^/]+/Contents/Developer|(?:./)?DEVELOPER_DIR|/PLACEHOLDER_DEVELOPER_DIR|/Library/Developer/CommandLineTools).*?/SDKs/([^\d.]+)=\#(developerDir)/Platforms/$1.platform/Developer/SDKs/$1"# + ] +} diff --git a/tools/import_indexstores/TemporaryFile.swift b/tools/import_indexstores/TemporaryFile.swift new file mode 100644 index 0000000000..6f6cd051b5 --- /dev/null +++ b/tools/import_indexstores/TemporaryFile.swift @@ -0,0 +1,14 @@ +import Foundation + +class TemporaryFile { + let url: URL + + init() throws { + url = FileManager.default.temporaryDirectory + .appendingPathComponent(UUID().uuidString) + } + + deinit { + _ = try? FileManager.default.removeItem(at: url) + } +} diff --git a/tools/swiftc_stub/BUILD b/tools/swiftc_stub/BUILD index e1028a6bbf..68c2cbe827 100644 --- a/tools/swiftc_stub/BUILD +++ b/tools/swiftc_stub/BUILD @@ -26,6 +26,7 @@ macos_command_line_application( swift_library( name = "swiftc_stub.library", srcs = ["main.swift"], + module_name = "swiftc_stub", ) swift_binary( diff --git a/xcodeproj/internal/bazel_integration_files/BUILD b/xcodeproj/internal/bazel_integration_files/BUILD index c98132eeb3..311111652b 100644 --- a/xcodeproj/internal/bazel_integration_files/BUILD +++ b/xcodeproj/internal/bazel_integration_files/BUILD @@ -3,7 +3,7 @@ _BASE_FILES = [ "copy_dsyms.sh", "create_lldbinit.sh", "generate_bazel_dependencies.sh", - "import_indexstores.sh", + ":renamed_import_indexstores", "process_bazel_build_log.py", ] @@ -17,8 +17,8 @@ filegroup( filegroup( name = "bazel_integration_files", srcs = [ + ":renamed_swiftc_stub", ":rsync_excludes", - ":swiftc", ] + glob( ["**/*"], exclude = _BASE_FILES + [ @@ -93,10 +93,30 @@ echo '/*.framework/SwiftUIPreviewsFrameworks/***' >> "framework.exclude.rsynclis ) genrule( - name = "swiftc_stub", + name = "renamed_import_indexstores", + srcs = ["//tools/import_indexstores:universal_import_indexstores"], + outs = ["import_indexstores"], + # Make `import_indexstores` have the right name + cmd = """\ +readonly output="$@" +if [[ $$(stat -f '%d' "$<") == $$(stat -f '%d' "$${output%/*}") ]]; then + cp -c "$<" "$@" +else + cp "$<" "$@" +fi +""", + message = "Renaming import_indexstores", + tags = [ + "manual", + "no-sandbox", + ], +) + +genrule( + name = "renamed_swiftc_stub", srcs = ["//tools/swiftc_stub:universal_swiftc_stub"], outs = ["swiftc"], - # Make the swiftc_stub have the right name + # Make `swiftc_stub` have the right name cmd = """\ readonly output="$@" if [[ $$(stat -f '%d' "$<") == $$(stat -f '%d' "$${output%/*}") ]]; then @@ -105,7 +125,7 @@ else cp "$<" "$@" fi """, - message = "Renaming swiftc stub", + message = "Renaming swiftc_stub", tags = [ "manual", "no-sandbox", diff --git a/xcodeproj/internal/bazel_integration_files/generate_bazel_dependencies.sh b/xcodeproj/internal/bazel_integration_files/generate_bazel_dependencies.sh index 1c6607e5e8..bc3350ad2a 100755 --- a/xcodeproj/internal/bazel_integration_files/generate_bazel_dependencies.sh +++ b/xcodeproj/internal/bazel_integration_files/generate_bazel_dependencies.sh @@ -182,7 +182,7 @@ done # Import indexes if [ -n "${indexstores_filelists:-}" ]; then - "$BAZEL_INTEGRATION_DIR/import_indexstores.sh" \ + "$BAZEL_INTEGRATION_DIR/import_indexstores" \ "$INDEXING_PROJECT_DIR__NO" \ "${indexstores_filelists[@]/#/$output_path/}" \ >"$log_dir/import_indexstores.async.log" 2>&1 & diff --git a/xcodeproj/internal/bazel_integration_files/generate_index_build_bazel_dependencies.sh b/xcodeproj/internal/bazel_integration_files/generate_index_build_bazel_dependencies.sh index 47921531a0..a1d6011705 100755 --- a/xcodeproj/internal/bazel_integration_files/generate_index_build_bazel_dependencies.sh +++ b/xcodeproj/internal/bazel_integration_files/generate_index_build_bazel_dependencies.sh @@ -48,7 +48,7 @@ source "$BAZEL_INTEGRATION_DIR/bazel_build.sh" # Import indexes if [ -n "${indexstores_filelists:-}" ]; then - "$BAZEL_INTEGRATION_DIR/import_indexstores.sh" \ + "$BAZEL_INTEGRATION_DIR/import_indexstores" \ "$INDEXING_PROJECT_DIR__NO" \ "${indexstores_filelists[@]/#/$output_path/}" fi diff --git a/xcodeproj/internal/bazel_integration_files/import_indexstores.sh b/xcodeproj/internal/bazel_integration_files/import_indexstores.sh deleted file mode 100755 index 9d48def60f..0000000000 --- a/xcodeproj/internal/bazel_integration_files/import_indexstores.sh +++ /dev/null @@ -1,126 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -readonly pidfile="$OBJROOT/import_indexstores.pid" -readonly build_execution_root="$1" -shift - -# Exit early if no indexstore filelists were provided -if [ $# -eq 0 ]; then - exit -fi - -# Kill previously running import -if [[ -s "$pidfile" ]]; then - pid=$(cat "$pidfile") - kill "$pid" 2>/dev/null || true - while kill -0 "$pid" 2>/dev/null; do - sleep 1 - done -fi - -# Set pid to allow cleanup later -echo $$ > "$pidfile" -trap 'rm "$pidfile" 2>/dev/null || true' EXIT - -# Merge all filelists into a single file -filelist="$(mktemp)" -/usr/bin/sort -u "$@" | sed "s|^|$PROJECT_DIR/|" > "$filelist" - -# Exit early if no indexstores were provided -if [ ! -s "$filelist" ]; then - exit -fi - -# Set remaps - -# We only support importing indexes built with rules_xcodeproj, and we override -# our output bases, so we know the the ending of the execution root -readonly execution_root_regex='.*/[^/]+/(?:_)?rules_xcodeproj(?:\.noindex)?/[^/]+_output_base/execroot/[^/]+' - -# We remove any `/private` prefix from the current execution_root, since it's -# removed in the Project navigator. -readonly xcode_execution_root="${build_execution_root#/private}" - -if [[ "$RULES_XCODEPROJ_BUILD_MODE" == "xcode" && \ - "$XCODE_VERSION_ACTUAL" -gt "1330" ]] -then - # In BwX mode, Xcode 13.3+ uses `-index-unit-output-path` to create hermetic - # object file paths. We need to remap the same way to get unit file hash - # matches. - readonly object_file_prefix="/${PROJECT_TEMP_DIR##*/}" -elif [[ "$ACTION" == "indexbuild" ]]; then - # Remove `Index.noindex/` part of path - readonly object_file_prefix="${PROJECT_TEMP_DIR/\/Index.noindex\/Build\/Intermediates.noindex\///Build/Intermediates.noindex/}" -else - # Remove SwiftUI Previews part of path - readonly object_file_prefix="${PROJECT_TEMP_DIR/\/Intermediates.noindex\/Previews\/*\/Intermediates.noindex\///Intermediates.noindex/}" -fi - -# The order of remaps is important. The first match is used. So we try the most -# specific first. This also allows us to assume previous matches have taken care -# of those types of files, so more general matches still work later. -remaps=( - # Object files - # - # These currently come back relative, but we have the execution_root as an - # optional prefix in case this changes in the future. The path is based on - # rules_swift's current logic: - # https://github.com/bazelbuild/rules_swift/blob/6153a848f747e90248a8673869c49631f1323ff3/swift/internal/derived_files.bzl#L114-L119 - # When we add support for C-based index imports we will have to use another - # pattern: - # https://github.com/bazelbuild/bazel/blob/c4a1ab8b6577c4376aaaa5c3c2d4ef07d524175c/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java#L1358 - -remap "^(?:$execution_root_regex/|\./)?(bazel-out/[^/]+/bin/)(?:_swift_incremental/)?(.*?)([^/]+)_objs/.*?([^/]+?)(?:\.swift)?\.o\$=$object_file_prefix/\$1\$2\$3/Objects-normal/${ARCHS%% *}/\$4.o" - - # Generated sources and swiftmodules - # - # With object files taken care of, any other paths with `bazel-out/` as their - # prefix (relative to the execution_root) are assumed to be generated outputs. - # The two kinds of generated outputs used in the unit files are swiftmodule - # and source paths. So we map that, along with the `external/` prefix for - # external sources, to the current execution_root. Finally, currently these - # paths are returned as absolute, but a future change might make them - # relative, similar to the object files, so we have the execution_root as an - # optional prefix. - -remap "^(?:$execution_root_regex/|\./)?bazel-out/=$xcode_execution_root/bazel-out/" - - # External sources - # - # External sources need to be handled differently, since we use the - # non-symlinked version in Xcode. - -remap "^(?:$execution_root_regex/|\./)?external/=${xcode_execution_root%/*/*}/external/" - - # Project sources - # - # With the other source files and generated files taken care of, all other - # execution_root prefixed paths should be project sources. - -remap "^$execution_root_regex=$SRCROOT" - - # Sysroot - # - # The only other type of path in the unit files are sysroot based. While - # these should always be Xcode.app relative, our regex supports command-line - # tools based paths as well. - # `DEVELOPER_DIR` has an optional `./` prefix, because index-import adds `./` - # to all relative paths. - -remap "^(?:.*?/[^/]+/Contents/Developer|(?:./)?DEVELOPER_DIR|/PLACEHOLDER_DEVELOPER_DIR|/Library/Developer/CommandLineTools).*?/SDKs/([^\\d.]+)=$DEVELOPER_DIR/Platforms/\$1.platform/Developer/SDKs/\$1" -) - -# Import - -mkdir -p "$INDEX_DATA_STORE_DIR" - -"$INDEX_IMPORT" \ - -undo-rules_swift-renames \ - "${remaps[@]}" \ - -incremental \ - @"$filelist" \ - "$INDEX_DATA_STORE_DIR" - -rm "$filelist" - -# Unit files are created fresh, but record files are copied from `bazel-out/`, -# which are read-only. We need to adjust their permissions. -# TODO: Do this in `index-import` -chmod -R u+w "$INDEX_DATA_STORE_DIR" diff --git a/xcodeproj/internal/templates/installer.sh b/xcodeproj/internal/templates/installer.sh index 6ba495ad4f..05bce45700 100644 --- a/xcodeproj/internal/templates/installer.sh +++ b/xcodeproj/internal/templates/installer.sh @@ -192,7 +192,7 @@ find "$dest/rules_xcodeproj/bazel" \ -type f \( -name "*.sh" -o -name "*.py" \) \ -print0 | xargs -0 chmod u+x find "$dest/rules_xcodeproj/bazel" \ - -type f ! \( -name "swiftc" -o -name "*.sh" -o -name "*.py" \) \ + -type f ! \( -name "swiftc" -o -name "import_indexstores" -o -name "*.sh" -o -name "*.py" \) \ -print0 | xargs -0 chmod -x # Copy over project.xcworkspace/contents.xcworkspacedata if needed