diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..6313b56c --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml new file mode 100644 index 00000000..7d8af0d3 --- /dev/null +++ b/.github/workflows/automerge.yml @@ -0,0 +1,17 @@ +name: Create PR to merge main into release branch +# In the first period after branching the release branch, we typically want to include many changes from `main` in the release branch. This workflow automatically creates a PR every Monday to merge main into the release branch. +# Later in the release cycle we should stop this practice to avoid landing risky changes by disabling this workflow. To do so, disable the workflow as described in https://docs.github.com/en/actions/managing-workflow-runs-and-deployments/managing-workflow-runs/disabling-and-enabling-a-workflow +on: + schedule: + - cron: '0 9 * * MON' + workflow_dispatch: +jobs: + create_merge_pr: + name: Create PR to merge main into release branch + uses: swiftlang/github-workflows/.github/workflows/create_automerge_pr.yml@main + with: + base_branch: release/6.2 + permissions: + contents: write + pull-requests: write + if: (github.event_name == 'schedule' && github.repository == 'swiftlang/swift-build') || (github.event_name != 'schedule') # Ensure that we don't run this on a schedule in a fork diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 00000000..efc6d05e --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,29 @@ +name: Pull request + +on: + pull_request: + types: [opened, reopened, synchronize] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + tests: + name: Test + uses: swiftlang/github-workflows/.github/workflows/swift_package_test.yml@main + with: + linux_os_versions: '["noble", "jammy", "focal", "rhel-ubi9"]' + linux_pre_build_command: command -v apt >/dev/null 2>&1 && apt update && apt install -y libsqlite3-dev libncurses-dev || (command -v yum >/dev/null 2>&1 && yum update -y && yum install -y sqlite-devel ncurses-devel) + linux_build_command: 'swift build' + linux_swift_versions: '["nightly-main", "nightly-6.2"]' + windows_swift_versions: '["nightly-main"]' + windows_build_command: 'swift build' + soundness: + name: Soundness + uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main + with: + license_header_check_project_name: "Swift" + api_breakage_check_enabled: false + unacceptable_language_check_enabled: false + format_check_enabled: false diff --git a/.license_header_template b/.license_header_template new file mode 100644 index 00000000..52d6f278 --- /dev/null +++ b/.license_header_template @@ -0,0 +1,11 @@ +@@===----------------------------------------------------------------------===@@ +@@ +@@ This source file is part of the Swift open source project +@@ +@@ Copyright (c) YEARS Apple Inc. and the Swift project authors +@@ Licensed under Apache License v2.0 with Runtime Library Exception +@@ +@@ See http://swift.org/LICENSE.txt for license information +@@ See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +@@ +@@===----------------------------------------------------------------------===@@ diff --git a/.licenseignore b/.licenseignore new file mode 100644 index 00000000..21fbce89 --- /dev/null +++ b/.licenseignore @@ -0,0 +1,9 @@ +**/*.mlmodel +**/*.pbxproj +**/*.png +**/*.xcworkspacedata +**/Package.swift +.dir-locals.el +.editorconfig +CODEOWNERS +Package.swift diff --git a/CMakeLists.txt b/CMakeLists.txt index 00f40cf7..ed60c850 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,18 @@ cmake_minimum_required(VERSION 3.26...3.29) project(SwiftBuild LANGUAGES C CXX Swift) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + +set(CMAKE_INSTALL_RPATH "$,@loader_path/..,$ORIGIN>") +set(CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH YES) + +set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreadedDLL) +set(CMAKE_Swift_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/swift) + +option(BUILD_SHARED_LIBS "Build shared libraries by default" YES) + set(CMAKE_C_VISIBILITY hidden) set(CMAKE_CXX_VISIBILITY hidden) set(CMAKE_CXX_STANDARD 17) @@ -35,7 +47,33 @@ add_compile_options("$<$:SHELL:-package-name SwiftBuild> # rdar://137809703 # "$<$:SHELL:-enable-upcoming-feature RegionBasedIsolation>" "$<$:SHELL:-enable-upcoming-feature ExistentialAny>" - "$<$:SHELL:-enable-upcoming-feature InternalImportsByDefault>") + "$<$:SHELL:-enable-upcoming-feature InternalImportsByDefault>" + "$<$:SHELL:-no-toolchain-stdlib-rpath>" + # Turn off autolinking within this project to reduce linker overhead. + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBLibc>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBAndroidPlatform>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBApplePlatform>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBBuildService>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBCLibc>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBGenericUnixPlatform>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBTaskConstruction>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBUtil>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBUniversalPlatform>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBWindowsPlatform>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SwiftBuild>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBWebAssemblyPlatform>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBCSupport>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBMacro>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBProjectModel>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBTaskExecution>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBServiceCore>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBQNXPlatform>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBProtocol>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBLLBuild>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBCore>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBCAS>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBBuildSystem>" + "$<$:SHELL:-Xfrontend -disable-autolink-library -Xfrontend SWBCore>") # Prefer the static initialization for the plugins. add_compile_definitions(USE_STATIC_PLUGIN_INITIALIZATION) @@ -50,3 +88,4 @@ find_package(Threads) find_package(SQLite3) add_subdirectory(Sources) +add_subdirectory(cmake/modules) diff --git a/CODEOWNERS b/CODEOWNERS index 4ffcd609..96347c4f 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,4 +1,4 @@ -* @jakepetroules @mirza-garibovic @mhrawdon @neonichu @owenv +* @aciidgh @jakepetroules @mirza-garibovic @mhrawdon @neonichu @owenv *XCStrings* @matthewseaman @kulpreetchilana @jakepetroules @mirza-garibovic @mhrawdon @neonichu @owenv *StringCatalog* @matthewseaman @kulpreetchilana @jakepetroules @mirza-garibovic @mhrawdon @neonichu @owenv -*Preview* @jonathanpenn @jakepetroules @mirza-garibovic @mhrawdon @neonichu @owenv \ No newline at end of file +*Preview* @jonathanpenn @jakepetroules @mirza-garibovic @mhrawdon @neonichu @owenv diff --git a/Package.swift b/Package.swift index dcee18be..baef8b0a 100644 --- a/Package.swift +++ b/Package.swift @@ -135,6 +135,7 @@ let package = Package( swiftSettings: swiftSettings(languageMode: .v5)), .target( name: "SWBCSupport", + exclude: ["empty.swift"], publicHeadersPath: ".", cSettings: [ .define("_CRT_SECURE_NO_WARNINGS", .when(platforms: [.windows])), diff --git a/Plugins/cmake-smoke-test/cmake-smoke-test.swift b/Plugins/cmake-smoke-test/cmake-smoke-test.swift index 4cd00782..f1cdba50 100644 --- a/Plugins/cmake-smoke-test/cmake-smoke-test.swift +++ b/Plugins/cmake-smoke-test/cmake-smoke-test.swift @@ -17,17 +17,22 @@ import Foundation struct CMakeSmokeTest: CommandPlugin { func performCommand(context: PluginContext, arguments: [String]) async throws { var args = ArgumentExtractor(arguments) - let hostOS = try OS.host() + guard args.extractFlag(named: "disable-sandbox") > 0 else { + throw Errors.missingRequiredOption("--disable-sandbox") + } + guard let cmakePath = args.extractOption(named: "cmake-path").last else { throw Errors.missingRequiredOption("--cmake-path") } print("using cmake at \(cmakePath)") let cmakeURL = URL(filePath: cmakePath) guard let ninjaPath = args.extractOption(named: "ninja-path").last else { throw Errors.missingRequiredOption("--ninja-path") } print("using ninja at \(ninjaPath)") let ninjaURL = URL(filePath: ninjaPath) - guard let sysrootPath = args.extractOption(named: "sysroot-path").last else { throw Errors.missingRequiredOption("--sysroot-path") } - print("using sysroot at \(sysrootPath)") + let sysrootPath = args.extractOption(named: "sysroot-path").last + if let sysrootPath { + print("using sysroot at \(sysrootPath)") + } let moduleCachePath = context.pluginWorkDirectoryURL.appending(component: "module-cache").path() @@ -35,30 +40,33 @@ struct CMakeSmokeTest: CommandPlugin { let swiftBuildBuildURL = context.pluginWorkDirectoryURL.appending(component: "swift-build") print("swift-build: \(swiftBuildURL.path())") - let swiftToolsSupportCoreURL = try findSiblingRepository("swift-tools-support-core", swiftBuildURL: swiftBuildURL) + let swiftToolsSupportCoreURL = try findDependency("swift-tools-support-core", pluginContext: context) let swiftToolsSupportCoreBuildURL = context.pluginWorkDirectoryURL.appending(component: "swift-tools-support-core") - let swiftSystemURL = try findSiblingRepository("swift-system", swiftBuildURL: swiftBuildURL) + let swiftSystemURL = try findDependency("swift-system", pluginContext: context) let swiftSystemBuildURL = context.pluginWorkDirectoryURL.appending(component: "swift-system") - let llbuildURL = try findSiblingRepository("llbuild", swiftBuildURL: swiftBuildURL) + let llbuildURL = try findDependency("swift-llbuild", pluginContext: context) let llbuildBuildURL = context.pluginWorkDirectoryURL.appending(component: "llbuild") - let swiftArgumentParserURL = try findSiblingRepository("swift-argument-parser", swiftBuildURL: swiftBuildURL) + let swiftArgumentParserURL = try findDependency("swift-argument-parser", pluginContext: context) let swiftArgumentParserBuildURL = context.pluginWorkDirectoryURL.appending(component: "swift-argument-parser") - let swiftDriverURL = try findSiblingRepository("swift-driver", swiftBuildURL: swiftBuildURL) + let swiftDriverURL = try findDependency("swift-driver", pluginContext: context) let swiftDriverBuildURL = context.pluginWorkDirectoryURL.appending(component: "swift-driver") for url in [swiftToolsSupportCoreBuildURL, swiftSystemBuildURL, llbuildBuildURL, swiftArgumentParserBuildURL, swiftDriverBuildURL, swiftBuildBuildURL] { try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true) } - let sharedSwiftFlags = [ - "-sdk", sysrootPath, + var sharedSwiftFlags = [ "-module-cache-path", moduleCachePath ] + if let sysrootPath { + sharedSwiftFlags += ["-sdk", sysrootPath] + } + let cMakeProjectArgs = [ "-DArgumentParser_DIR=\(swiftArgumentParserBuildURL.appending(components: "cmake", "modules").path())", "-DLLBuild_DIR=\(llbuildBuildURL.appending(components: "cmake", "modules").path())", @@ -107,11 +115,28 @@ struct CMakeSmokeTest: CommandPlugin { print("Built swift-build") } - func findSiblingRepository(_ name: String, swiftBuildURL: URL) throws -> URL { - let url = swiftBuildURL.deletingLastPathComponent().appending(component: name) - print("\(name): \(url.path())") - guard FileManager.default.fileExists(atPath: url.path()) else { throw Errors.missingRepository(url.path()) } - return url + func findDependency(_ name: String, pluginContext: PluginContext) throws -> URL { + var stack: [Package] = pluginContext.package.dependencies.map { $0.package } + var visited = Set(stack.map { $0.id }) + var transitiveDependencies = pluginContext.package.dependencies.map { $0.package } + while let current = stack.popLast() { + for dependency in current.dependencies { + guard visited.insert(dependency.package.id).inserted else { + continue + } + transitiveDependencies.append(dependency.package) + stack.append(dependency.package) + } + } + guard let dependency = transitiveDependencies.first(where: { $0.id == name }) else { + throw Errors.missingRepository(name) + } + let dependencyURL = dependency.directoryURL + print("\(name): \(dependencyURL.path())") + guard FileManager.default.fileExists(atPath: dependencyURL.path()) else { + throw Errors.missingRepository(dependencyURL.path()) + } + return dependencyURL } } diff --git a/Sources/SWBAndroidPlatform/CMakeLists.txt b/Sources/SWBAndroidPlatform/CMakeLists.txt index e2f2faae..9cf4c2c4 100644 --- a/Sources/SWBAndroidPlatform/CMakeLists.txt +++ b/Sources/SWBAndroidPlatform/CMakeLists.txt @@ -28,7 +28,7 @@ file(CONFIGURE ]] ESCAPE_QUOTES @ONLY NEWLINE_STYLE LF) -add_library(SWBAndroidPlatform STATIC +add_library(SWBAndroidPlatform AndroidSDK.swift Plugin.swift) target_link_libraries(SWBAndroidPlatform PUBLIC @@ -37,3 +37,11 @@ target_link_libraries(SWBAndroidPlatform PUBLIC SWBUtil) target_sources(SWBAndroidPlatform PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/resource_bundle_accessor.swift") + +set_target_properties(SWBAndroidPlatform PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBAndroidPlatform) + +install(TARGETS SWBAndroidPlatform + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBApplePlatform/CMakeLists.txt b/Sources/SWBApplePlatform/CMakeLists.txt index c636817e..fb516d7b 100644 --- a/Sources/SWBApplePlatform/CMakeLists.txt +++ b/Sources/SWBApplePlatform/CMakeLists.txt @@ -28,7 +28,7 @@ file(CONFIGURE ]] ESCAPE_QUOTES @ONLY NEWLINE_STYLE LF) -add_library(SWBApplePlatform STATIC +add_library(SWBApplePlatform AppIntentsMetadataCompiler.swift AppIntentsMetadataTaskProducer.swift AppIntentsSSUTrainingCompiler.swift @@ -75,3 +75,11 @@ target_link_libraries(SWBApplePlatform PUBLIC SWBTaskConstruction) target_sources(SWBApplePlatform PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/resource_bundle_accessor.swift") + +set_target_properties(SWBApplePlatform PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBApplePlatform) + +install(TARGETS SWBApplePlatform + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBBuildService/CMakeLists.txt b/Sources/SWBBuildService/CMakeLists.txt index 00971369..ac623f70 100644 --- a/Sources/SWBBuildService/CMakeLists.txt +++ b/Sources/SWBBuildService/CMakeLists.txt @@ -37,3 +37,11 @@ target_link_libraries(SWBBuildService PUBLIC SWBWebAssemblyPlatform SWBWindowsPlatform $<$>:SwiftSystem::SystemPackage>) + +set_target_properties(SWBBuildService PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBBuildService) + +install(TARGETS SWBBuildService + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBBuildServiceBundle/CMakeLists.txt b/Sources/SWBBuildServiceBundle/CMakeLists.txt index dcae6b91..f4a03757 100644 --- a/Sources/SWBBuildServiceBundle/CMakeLists.txt +++ b/Sources/SWBBuildServiceBundle/CMakeLists.txt @@ -20,3 +20,5 @@ target_link_libraries(SWBBuildServiceBundle PRIVATE SWBCore) install(TARGETS SWBBuildServiceBundle) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBBuildServiceBundle) diff --git a/Sources/SWBBuildSystem/BuildOperation.swift b/Sources/SWBBuildSystem/BuildOperation.swift index 934b78d2..5542c89e 100644 --- a/Sources/SWBBuildSystem/BuildOperation.swift +++ b/Sources/SWBBuildSystem/BuildOperation.swift @@ -681,7 +681,8 @@ package final class BuildOperation: BuildSystemOperation { adaptor.withActivity(ruleInfo: "CompilationCacheMetrics", executionDescription: "Report compilation cache metrics", signature: signature, target: nil, parentActivity: nil) { activity in func getSummary(hits: Int, misses: Int) -> String { let hitPercent = Int((Double(hits) / Double(hits + misses) * 100).rounded()) - return "\(hits) hit\(hits == 1 ? "" : "s") (\(hitPercent)%), \(misses) miss\(misses == 1 ? "" : "es")" + let total = hits + misses + return "\(hits) hit\(hits == 1 ? "" : "s") / \(total) cacheable task\(total == 1 ? "" : "s") (\(hitPercent)%)" } delegate.emit(diagnostic: Diagnostic(behavior: .note, location: .unknown, data: DiagnosticData(getSummary(hits: cacheHits, misses: cacheMisses))), for: activity, signature: signature) return .succeeded @@ -881,15 +882,8 @@ package final class BuildOperation: BuildSystemOperation { } package func taskDiscoveredRequiredTargetDependency(target: ConfiguredTarget, antecedent: ConfiguredTarget, reason: RequiredTargetDependencyReason, warningLevel: BooleanWarningLevel) { - let diagnosticBehavior: SWBUtil.Diagnostic.Behavior - switch warningLevel { - case .yesError: diagnosticBehavior = .error - case .yes: diagnosticBehavior = .warning - case .no: return - } - let targetDiagnosticsEngine = buildOutputDelegate.diagnosticsEngine(for: target) - if !transitiveDependencyExists(target: target, antecedent: antecedent) { + // Ensure we only diagnose missing dependencies when platform and SDK variant match. We perform this check as late as possible since computing settings can be expensive. let targetSettings = requestContext.getCachedSettings(target.parameters, target: target.target) let antecedentSettings = requestContext.getCachedSettings(antecedent.parameters, target: antecedent.target) @@ -907,8 +901,14 @@ package final class BuildOperation: BuildSystemOperation { } else { message = DiagnosticData("'\(target.target.name)' is missing a dependency on '\(antecedent.target.name)' because \(reason)") } - - targetDiagnosticsEngine.emit(Diagnostic(behavior: diagnosticBehavior, location: .unknown, data: message)) + switch warningLevel { + case .yes: + buildOutputDelegate.emit(Diagnostic(behavior: .warning, location: .unknown, data: message)) + case .yesError: + buildOutputDelegate.emit(Diagnostic(behavior: .error, location: .unknown, data: message)) + default: + break + } } } } diff --git a/Sources/SWBBuildSystem/CMakeLists.txt b/Sources/SWBBuildSystem/CMakeLists.txt index 7bef4f58..9095c4fd 100644 --- a/Sources/SWBBuildSystem/CMakeLists.txt +++ b/Sources/SWBBuildSystem/CMakeLists.txt @@ -22,3 +22,11 @@ target_link_libraries(SWBBuildSystem PUBLIC SWBCore SWBTaskConstruction SWBTaskExecution) + +set_target_properties(SWBBuildSystem PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBBuildSystem) + +install(TARGETS SWBBuildSystem + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBCAS/CMakeLists.txt b/Sources/SWBCAS/CMakeLists.txt index b35d440e..a2909820 100644 --- a/Sources/SWBCAS/CMakeLists.txt +++ b/Sources/SWBCAS/CMakeLists.txt @@ -19,3 +19,11 @@ set_target_properties(SWBCAS PROPERTIES target_link_libraries(SWBCAS PUBLIC SWBUtil SWBCSupport) + +set_target_properties(SWBCAS PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBCAS) + +install(TARGETS SWBCAS + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBCLibc/CMakeLists.txt b/Sources/SWBCLibc/CMakeLists.txt index a5d690b0..26c4f41b 100644 --- a/Sources/SWBCLibc/CMakeLists.txt +++ b/Sources/SWBCLibc/CMakeLists.txt @@ -12,3 +12,11 @@ add_library(SWBCLibc libc.c) target_include_directories(SWBCLibc INTERFACE include) + +target_include_directories(SWBCLibc PUBLIC + ${CMAKE_CURRENT_BINARY_DIR}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBCLibc) + +install(TARGETS SWBCLibc + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBCSupport/CLibRemarksHelper.h b/Sources/SWBCSupport/CLibRemarksHelper.h index d22bb643..7f2104b8 100644 --- a/Sources/SWBCSupport/CLibRemarksHelper.h +++ b/Sources/SWBCSupport/CLibRemarksHelper.h @@ -15,8 +15,10 @@ #include +#include "CSupportDefines.h" + // Swift has no way of checking if a weak_import symbol is available. // This function checks if LLVMRemarkVersion from libRemarks.dylib is available, which should be enough to assert the whole library is available as well. -bool isLibRemarksAvailable(void); +CSUPPORT_EXPORT bool isLibRemarksAvailable(void); #endif /* CLibRemarksHelper_h */ diff --git a/Sources/SWBCSupport/CLibclang.h b/Sources/SWBCSupport/CLibclang.h index 04701ae2..438c4c45 100644 --- a/Sources/SWBCSupport/CLibclang.h +++ b/Sources/SWBCSupport/CLibclang.h @@ -19,6 +19,8 @@ #include #include +#include "CSupportDefines.h" + #ifdef __cplusplus extern "C" { #endif @@ -85,85 +87,85 @@ typedef enum { /// Open an interface to libclang, from a given path. /// /// \returns nullptr on error. -libclang_t libclang_open(const char* path); +CSUPPORT_EXPORT libclang_t libclang_open(const char* path); /// Intentionally leak libclang interface. -void libclang_leak(libclang_t lib); +CSUPPORT_EXPORT void libclang_leak(libclang_t lib); /// Close an open libclang interface. -void libclang_close(libclang_t lib); +CSUPPORT_EXPORT void libclang_close(libclang_t lib); /// Get the clang version string. -void libclang_get_clang_version(libclang_t lib, void (^callback)(const char*)); +CSUPPORT_EXPORT void libclang_get_clang_version(libclang_t lib, void (^callback)(const char*)); /// Whether the libclang has the minimal set of required API. -bool libclang_has_required_api(libclang_t lib); +CSUPPORT_EXPORT bool libclang_has_required_api(libclang_t lib); /// Whether the libclang has dependency scanning support. -bool libclang_has_scanner(libclang_t lib); +CSUPPORT_EXPORT bool libclang_has_scanner(libclang_t lib); /// Whether libclang supports reporting structured scanning diagnostics. -bool libclang_has_structured_scanner_diagnostics(libclang_t lib); +CSUPPORT_EXPORT bool libclang_has_structured_scanner_diagnostics(libclang_t lib); /// Create a new scanner instance with optional CAS databases. -libclang_scanner_t libclang_scanner_create(libclang_t lib, libclang_casdatabases_t, libclang_casoptions_t); +CSUPPORT_EXPORT libclang_scanner_t libclang_scanner_create(libclang_t lib, libclang_casdatabases_t, libclang_casoptions_t); /// Dispose of a scanner. -void libclang_scanner_dispose(libclang_scanner_t scanner); +CSUPPORT_EXPORT void libclang_scanner_dispose(libclang_scanner_t scanner); /// Whether the libclang has CAS support. -bool libclang_has_cas(libclang_t lib); +CSUPPORT_EXPORT bool libclang_has_cas(libclang_t lib); /// Whether the libclang has CAS plugin support. -bool libclang_has_cas_plugin_feature(libclang_t lib); +CSUPPORT_EXPORT bool libclang_has_cas_plugin_feature(libclang_t lib); /// Whether the libclang has CAS pruning support. -bool libclang_has_cas_pruning_feature(libclang_t lib); +CSUPPORT_EXPORT bool libclang_has_cas_pruning_feature(libclang_t lib); /// Whether the libclang has CAS up-to-date checking support. -bool libclang_has_cas_up_to_date_checks_feature(libclang_t lib); +CSUPPORT_EXPORT bool libclang_has_cas_up_to_date_checks_feature(libclang_t lib); /// Whether the libclang has current working directory optimization support. -bool libclang_has_current_working_directory_optimization(libclang_t lib); +CSUPPORT_EXPORT bool libclang_has_current_working_directory_optimization(libclang_t lib); /// Create the CAS options object. -libclang_casoptions_t libclang_casoptions_create(libclang_t lib); +CSUPPORT_EXPORT libclang_casoptions_t libclang_casoptions_create(libclang_t lib); /// Dispose of the CAS options object. -void libclang_casoptions_dispose(libclang_casoptions_t); +CSUPPORT_EXPORT void libclang_casoptions_dispose(libclang_casoptions_t); /// Set the on-disk path to be used for the CAS database instances. -void libclang_casoptions_setondiskpath(libclang_casoptions_t, const char *path); +CSUPPORT_EXPORT void libclang_casoptions_setondiskpath(libclang_casoptions_t, const char *path); /// Set the plugin library path to be used for the CAS database instances. -void libclang_casoptions_setpluginpath(libclang_casoptions_t, const char *path); +CSUPPORT_EXPORT void libclang_casoptions_setpluginpath(libclang_casoptions_t, const char *path); /// Set a value for a named option that the CAS plugin supports. -void libclang_casoptions_setpluginoption(libclang_casoptions_t, const char *name, const char *value); +CSUPPORT_EXPORT void libclang_casoptions_setpluginoption(libclang_casoptions_t, const char *name, const char *value); /// Create the CAS database instances. -libclang_casdatabases_t libclang_casdatabases_create(libclang_casoptions_t, void (^error_callback)(const char *)); +CSUPPORT_EXPORT libclang_casdatabases_t libclang_casdatabases_create(libclang_casoptions_t, void (^error_callback)(const char *)); /// Dispose of the CAS databases instances. -void libclang_casdatabases_dispose(libclang_casdatabases_t); +CSUPPORT_EXPORT void libclang_casdatabases_dispose(libclang_casdatabases_t); /// Get the local storage size of the CAS/cache data in bytes. /// /// \returns the local storage size, or -1 if the implementation does not support /// reporting such size, or -2 if an error occurred. -int64_t libclang_casdatabases_get_ondisk_size(libclang_casdatabases_t, void (^error_callback)(const char *)); +CSUPPORT_EXPORT int64_t libclang_casdatabases_get_ondisk_size(libclang_casdatabases_t, void (^error_callback)(const char *)); /// Set the size for limiting disk storage growth. /// /// \param size_limit the maximum size limit in bytes. 0 means no limit. Negative values are invalid. /// \returns true if there was an error, false otherwise. -bool libclang_casdatabases_set_ondisk_size_limit(libclang_casdatabases_t, int64_t size_limit, void (^error_callback)(const char *)); +CSUPPORT_EXPORT bool libclang_casdatabases_set_ondisk_size_limit(libclang_casdatabases_t, int64_t size_limit, void (^error_callback)(const char *)); /// Prune local storage to reduce its size according to the desired size limit. /// Pruning can happen concurrently with other operations. /// /// \returns true if there was an error, false otherwise. -bool libclang_casdatabases_prune_ondisk_data(libclang_casdatabases_t, void (^error_callback)(const char *)); +CSUPPORT_EXPORT bool libclang_casdatabases_prune_ondisk_data(libclang_casdatabases_t, void (^error_callback)(const char *)); /// A callback to get the name of a given output. /// @@ -193,7 +195,7 @@ typedef size_t (^module_lookup_output_t)( /// \param callback - A block to invoke for each discovered dependency. /// \param error_callback - A block to invoke on an error. /// \returns True on success, false if the scanner failed. -bool libclang_scanner_scan_dependencies( +CSUPPORT_EXPORT bool libclang_scanner_scan_dependencies( libclang_scanner_t scanner, int argc, char *const *argv, const char *workingDirectory, __attribute__((noescape)) module_lookup_output_t module_lookup_output, __attribute__((noescape)) void (^modules_callback)(clang_module_dependency_set_t, bool), @@ -210,13 +212,13 @@ bool libclang_scanner_scan_dependencies( /// \param envp - A null terminated array of KEY=VALUE pairs (`envp`-style). /// \returns True on success, false on failure (including if the libclang cannot /// support). -bool libclang_driver_get_actions(libclang_t wrapped_lib, - int argc, - char* const* argv, - char* const* envp, - const char* working_directory, - void (^callback)(int argc, const char** argv), - void (^error_callback)(const char*)); +CSUPPORT_EXPORT bool libclang_driver_get_actions(libclang_t wrapped_lib, + int argc, + char* const* argv, + char* const* envp, + const char* working_directory, + void (^callback)(int argc, const char** argv), + void (^error_callback)(const char*)); struct libclang_diagnostic_t_ { char *file_name; @@ -255,31 +257,31 @@ struct libclang_diagnostic_set_t_ { libclang_diagnostic_t *diagnostics; }; -libclang_diagnostic_set_t libclang_read_diagnostics(libclang_t wrapped_lib, - const char* path, - const char** error_string); +CSUPPORT_EXPORT libclang_diagnostic_set_t libclang_read_diagnostics(libclang_t wrapped_lib, + const char* path, + const char** error_string); -void libclang_diagnostic_set_dispose(libclang_diagnostic_set_t diagnostic_set); +CSUPPORT_EXPORT void libclang_diagnostic_set_dispose(libclang_diagnostic_set_t diagnostic_set); -void libclang_cas_load_object_async(libclang_casdatabases_t, const char *casid, void (^callback)(libclang_cas_casobject_t, const char *error)); -void libclang_cas_casobject_dispose(libclang_cas_casobject_t); +CSUPPORT_EXPORT void libclang_cas_load_object_async(libclang_casdatabases_t, const char *casid, void (^callback)(libclang_cas_casobject_t, const char *error)); +CSUPPORT_EXPORT void libclang_cas_casobject_dispose(libclang_cas_casobject_t); -bool libclang_cas_casobject_is_materialized(libclang_casdatabases_t, const char *casid, void (^error_callback)(const char *)); +CSUPPORT_EXPORT bool libclang_cas_casobject_is_materialized(libclang_casdatabases_t, const char *casid, void (^error_callback)(const char *)); -libclang_cas_cached_compilation_t libclang_cas_get_cached_compilation(libclang_casdatabases_t, const char *cache_key, bool globally, void (^error_callback)(const char *)); -void libclang_cas_get_cached_compilation_async(libclang_casdatabases_t, const char *cache_key, bool globally, void (^callback)(libclang_cas_cached_compilation_t, const char *error)); +CSUPPORT_EXPORT libclang_cas_cached_compilation_t libclang_cas_get_cached_compilation(libclang_casdatabases_t, const char *cache_key, bool globally, void (^error_callback)(const char *)); +CSUPPORT_EXPORT void libclang_cas_get_cached_compilation_async(libclang_casdatabases_t, const char *cache_key, bool globally, void (^callback)(libclang_cas_cached_compilation_t, const char *error)); -void libclang_cas_cached_compilation_dispose(libclang_cas_cached_compilation_t); +CSUPPORT_EXPORT void libclang_cas_cached_compilation_dispose(libclang_cas_cached_compilation_t); -size_t libclang_cas_cached_compilation_get_num_outputs(libclang_cas_cached_compilation_t); -void libclang_cas_cached_compilation_get_output_name(libclang_cas_cached_compilation_t, size_t output_idx, void (^callback)(const char*)); -void libclang_cas_cached_compilation_get_output_casid(libclang_cas_cached_compilation_t, size_t output_idx, void (^callback)(const char*)); -bool libclang_cas_cached_compilation_is_output_materialized(libclang_cas_cached_compilation_t, size_t output_idx); -void libclang_cas_cached_compilation_make_global_async(libclang_cas_cached_compilation_t, void (^callback)(const char *error)); +CSUPPORT_EXPORT size_t libclang_cas_cached_compilation_get_num_outputs(libclang_cas_cached_compilation_t); +CSUPPORT_EXPORT void libclang_cas_cached_compilation_get_output_name(libclang_cas_cached_compilation_t, size_t output_idx, void (^callback)(const char*)); +CSUPPORT_EXPORT void libclang_cas_cached_compilation_get_output_casid(libclang_cas_cached_compilation_t, size_t output_idx, void (^callback)(const char*)); +CSUPPORT_EXPORT bool libclang_cas_cached_compilation_is_output_materialized(libclang_cas_cached_compilation_t, size_t output_idx); +CSUPPORT_EXPORT void libclang_cas_cached_compilation_make_global_async(libclang_cas_cached_compilation_t, void (^callback)(const char *error)); /// Synchronous call. /// \returns True on success, false on failure. -bool libclang_cas_replay_compilation(libclang_cas_cached_compilation_t, int argc, char *const *argv, const char *workingDirectory, void (^callback)(const char* diagnostic_text, const char *error)); +CSUPPORT_EXPORT bool libclang_cas_replay_compilation(libclang_cas_cached_compilation_t, int argc, char *const *argv, const char *workingDirectory, void (^callback)(const char* diagnostic_text, const char *error)); #ifdef __cplusplus } diff --git a/Sources/SWBCSupport/CMakeLists.txt b/Sources/SWBCSupport/CMakeLists.txt index 07903eae..c5c09de2 100644 --- a/Sources/SWBCSupport/CMakeLists.txt +++ b/Sources/SWBCSupport/CMakeLists.txt @@ -8,16 +8,30 @@ See http://swift.org/LICENSE.txt for license information See http://swift.org/CONTRIBUTORS.txt for Swift project authors ]] -add_library(SWBCSupport STATIC +add_library(SWBCSupport CLibclang.cpp - CLibRemarksHelper.c) + CLibRemarksHelper.c + empty.swift) +# Use swiftc as the linker so we pick up search paths for the blocks runtime, +# and enable C++ interop so it delegates to clang++. +set_target_properties(SWBCSupport PROPERTIES + LINKER_LANGUAGE Swift) +set_target_properties(SWBCSupport PROPERTIES + Swift_MODULE_NAME __SWBCSupport_Empty) +target_link_options(SWBCSupport PRIVATE + -cxx-interoperability-mode=default) target_compile_definitions(SWBCSupport PRIVATE $<$:_CRT_SECURE_NO_WARNINGS> $<$:_CRT_NONSTDC_NO_WARNINGS>) target_compile_options(SWBCSupport PRIVATE - -fblocks) + "$<$:SHELL:-fblocks>") target_include_directories(SWBCSupport PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) # TODO(compnerd) wire this up with `find_package` target_link_libraries(SWBCSupport PRIVATE $<$>:BlocksRuntime>) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBCSupport) + +install(TARGETS SWBCSupport + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBCSupport/CSupportDefines.h b/Sources/SWBCSupport/CSupportDefines.h new file mode 100644 index 00000000..49da425f --- /dev/null +++ b/Sources/SWBCSupport/CSupportDefines.h @@ -0,0 +1,17 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifdef _WIN32 +#define CSUPPORT_EXPORT __declspec(dllexport) +#else +#define CSUPPORT_EXPORT +#endif diff --git a/Sources/SWBCSupport/empty.swift b/Sources/SWBCSupport/empty.swift new file mode 100644 index 00000000..8898982c --- /dev/null +++ b/Sources/SWBCSupport/empty.swift @@ -0,0 +1,16 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +// This file is intentionally left blank. When built with CMake, +// SWBCSupport sets the link language to Swift w/ C++ interop +// to find libblocksruntime, and requires at least one Swift +// source file to avoid downstream issues. diff --git a/Sources/SWBCore/BuildRequest.swift b/Sources/SWBCore/BuildRequest.swift index 38f22129..c7720567 100644 --- a/Sources/SWBCore/BuildRequest.swift +++ b/Sources/SWBCore/BuildRequest.swift @@ -248,6 +248,15 @@ public final class BuildRequest: CustomStringConvertible, Sendable { return parameters.action == .indexBuild } + /// Whether or not this request is for building the index workspace description (as opposed to the target or + /// package description). + /// + /// Note that this is only valid when *building* the description, subsequent requests that use it will have a run + /// destination set (and thus return false). + public var buildsIndexWorkspaceDescription: Bool { + return enableIndexBuildArena && parameters.activeRunDestination == nil + } + /// The quality-of-service to use for this request. public let qos: SWBQoS diff --git a/Sources/SWBCore/CMakeLists.txt b/Sources/SWBCore/CMakeLists.txt index 467c8aa8..aecee403 100644 --- a/Sources/SWBCore/CMakeLists.txt +++ b/Sources/SWBCore/CMakeLists.txt @@ -155,11 +155,11 @@ add_library(SWBCore SpecImplementations/Tools/LaunchServicesRegisterTool.swift SpecImplementations/Tools/LinkerTools.swift SpecImplementations/Tools/Lipo.swift - SpecImplementations/Tools/MasterObjectLink.swift SpecImplementations/Tools/MergeInfoPlist.swift SpecImplementations/Tools/MkdirTool.swift SpecImplementations/Tools/ModulesVerifierTool.swift SpecImplementations/Tools/PLUtilTool.swift + SpecImplementations/Tools/PrelinkedObjectLink.swift SpecImplementations/Tools/ProcessSDKImports.swift SpecImplementations/Tools/ProcessXCFrameworkLibrary.swift SpecImplementations/Tools/ProductPackaging.swift @@ -207,3 +207,11 @@ target_link_libraries(SWBCore PUBLIC SwiftDriver) target_sources(SWBCore PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/resource_bundle_accessor.swift") + +set_target_properties(SWBCore PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBCore) + +install(TARGETS SWBCore + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBCore/DependencyResolution.swift b/Sources/SWBCore/DependencyResolution.swift index fd716988..dcf70e52 100644 --- a/Sources/SWBCore/DependencyResolution.swift +++ b/Sources/SWBCore/DependencyResolution.swift @@ -190,7 +190,7 @@ struct SpecializationParameters: Hashable, CustomStringConvertible { let toolchain = effectiveToolchainOverride(originalParameters: configuredTarget.parameters, workspaceContext: workspaceContext) return (platform == nil || platform === settings.platform) && (sdkVariant == nil || sdkVariant?.name == settings.sdkVariant?.name) && - (toolchain == nil || toolchain == settings.globalScope.evaluate(BuiltinMacros.EFFECTIVE_TOOLCHAINS_DIRS)) && + (toolchain == nil || toolchain == settings.globalScope.evaluate(BuiltinMacros.TOOLCHAINS)) && (canonicalNameSuffix == nil || canonicalNameSuffix?.nilIfEmpty == settings.sdk?.canonicalNameSuffix) } @@ -493,7 +493,7 @@ extension SpecializationParameters { self.workspaceContext = workspaceContext self.delegate = delegate - if buildRequest.enableIndexBuildArena { + if buildRequest.buildsIndexWorkspaceDescription { // For the index build, multiple build parameters are applied during configuration of a target (to configure for multiple platforms) and the build parameters for each target in the build request is not relevant. // Keep this dictionary empty so that `LinkageDependencyResolver` fallbacks to using the build parameters of the configured targets, which are the relevant ones. self.buildParametersByTarget = [:] @@ -507,7 +507,7 @@ extension SpecializationParameters { self.defaultImposedParameters = SpecializationParameters.default(workspaceContext: workspaceContext, buildRequestContext: buildRequestContext, parameters: buildRequest.parameters) - if buildRequest.enableIndexBuildArena { + if buildRequest.buildsIndexWorkspaceDescription { let hostOS = (try? workspaceContext.core.hostOperatingSystem.xcodePlatformName) ?? "unknown" // Create the build parameters for each available platform. @@ -577,7 +577,7 @@ extension SpecializationParameters { func lookupTopLevelConfiguredTarget(_ targetInfo: BuildRequest.BuildTargetInfo) -> [ConfiguredTarget] { guard !Task.isCancelled else { return [] } let (target, parameters) = (targetInfo.target, targetInfo.parameters) - if !buildRequest.enableIndexBuildArena { + if !buildRequest.buildsIndexWorkspaceDescription { // Top-level targets get defaults imposed, in case that they are themselves using "auto" anywhere. return [lookupConfiguredTarget(target, parameters: parameters, imposedParameters: defaultImposedParameters, isTopLevelLookup: true)] } @@ -585,12 +585,6 @@ extension SpecializationParameters { // Aggregate targets are only configured as dependencies. guard target.type != .aggregate else { return [] } - let isFromPackage = workspaceContext.workspace.project(for: target).isPackage - if isFromPackage { - // Configure top-level package targets using the run-destination of the build request. - return [lookupConfiguredTarget(target, parameters: parameters, imposedParameters: defaultImposedParameters, isTopLevelLookup: true)] - } - var configuredTargets: [ConfiguredTarget] = [] let unconfiguredSettings = buildRequestContext.getCachedSettings(targetInfo.parameters, target: target) let unconfiguredSupportedPlatforms = unconfiguredSettings.globalScope.evaluate(BuiltinMacros.SUPPORTED_PLATFORMS) @@ -694,10 +688,11 @@ extension SpecializationParameters { let dependencySettings = buildRequestContext.getCachedSettings(ct.parameters, target: ct.target) let dependencyPlatform = dependencySettings.platform let dependencySdkVariant = dependencySettings.sdkVariant?.name + let dependencyToolchains = dependencySettings.toolchains guard Ref(dependencyPlatform) == platform && dependencySdkVariant == sdkVariant else { return false } // For dependencies with 'auto' SDKROOT, they get their SDK 'imposed', including if it is internal vs public SDK, not just what platform it is. // For such dependencies also confirm that the existing configured dependency matches 'internal vs public' for the SDK. - if dependencyHasAutoSDKRoot, let dependencySDK = dependencySettings.sdk, let dependentSDK = sdk, dependencySDK !== dependentSDK { + if dependencyHasAutoSDKRoot, let dependencySDK = dependencySettings.sdk, let dependentSDK = sdk, dependencySDK !== dependentSDK || settings.toolchains != dependencyToolchains { return false } return true @@ -742,8 +737,9 @@ extension SpecializationParameters { continue } + let behavior: Diagnostic.Behavior = buildRequest.enableIndexBuildArena ? .warning : .error let data = DiagnosticData("multiple configured targets of '\(target.name)' are being created for \(currentSettings.platform?.displayName ?? "")") - delegate.emit(Diagnostic(behavior: .error, location: .unknown, data: data)) + delegate.emit(Diagnostic(behavior: behavior, location: .unknown, data: data)) hasMultipleTargets = true } } @@ -757,7 +753,7 @@ extension SpecializationParameters { } // At this point we know there is not a configured target for this target and parameters in our cache, so create one and return it. - let configuredTarget = ConfiguredTarget(parameters: parameters, target: target, specializeGuidForActiveRunDestination: buildRequest.enableIndexBuildArena) + let configuredTarget = ConfiguredTarget(parameters: parameters, target: target, specializeGuidForActiveRunDestination: buildRequest.buildsIndexWorkspaceDescription) configuredTargetsByTarget[configuredTarget.target, default: []].insert(configuredTarget) addSuperimposedProperties(for: configuredTarget, superimposedProperties: superimposedProperties) return configuredTarget @@ -772,7 +768,7 @@ extension SpecializationParameters { } var parameters = parameters - if buildRequest.enableIndexBuildArena { + if buildRequest.buildsIndexWorkspaceDescription { // Avoid forced propagation of "auto" overrides to targets that don't need them. If this is a host tool, // force its parameters to the host platform to avoid creating duplicate configured targets after it has // been specialized. diff --git a/Sources/SWBCore/Settings/BuiltinMacros.swift b/Sources/SWBCore/Settings/BuiltinMacros.swift index 00979bd3..1ca2ea8e 100644 --- a/Sources/SWBCore/Settings/BuiltinMacros.swift +++ b/Sources/SWBCore/Settings/BuiltinMacros.swift @@ -717,7 +717,7 @@ public final class BuiltinMacros { public static let GENERATE_EMBED_IN_CODE_ACCESSORS = BuiltinMacros.declareBooleanMacro("GENERATE_EMBED_IN_CODE_ACCESSORS") public static let GENERATE_INFOPLIST_FILE = BuiltinMacros.declareBooleanMacro("GENERATE_INFOPLIST_FILE") public static let GENERATE_KERNEL_MODULE_INFO_FILE = BuiltinMacros.declareBooleanMacro("GENERATE_KERNEL_MODULE_INFO_FILE") - public static let GENERATE_MASTER_OBJECT_FILE = BuiltinMacros.declareBooleanMacro("GENERATE_MASTER_OBJECT_FILE") + public static let GENERATE_PRELINK_OBJECT_FILE = BuiltinMacros.declareBooleanMacro("GENERATE_PRELINK_OBJECT_FILE") public static let GENERATE_PKGINFO_FILE = BuiltinMacros.declareBooleanMacro("GENERATE_PKGINFO_FILE") public static let GENERATE_RESOURCE_ACCESSORS = BuiltinMacros.declareBooleanMacro("GENERATE_RESOURCE_ACCESSORS") public static let GENERATE_TEST_ENTRY_POINT = BuiltinMacros.declareBooleanMacro("GENERATE_TEST_ENTRY_POINT") @@ -1003,6 +1003,7 @@ public final class BuiltinMacros { public static let SWIFT_EMIT_MODULE_INTERFACE = BuiltinMacros.declareBooleanMacro("SWIFT_EMIT_MODULE_INTERFACE") public static let SWIFT_ENABLE_BATCH_MODE = BuiltinMacros.declareBooleanMacro("SWIFT_ENABLE_BATCH_MODE") public static let SWIFT_ENABLE_INCREMENTAL_COMPILATION = BuiltinMacros.declareBooleanMacro("SWIFT_ENABLE_INCREMENTAL_COMPILATION") + public static let SWIFT_DISABLE_INCREMENTAL_SCAN = BuiltinMacros.declareBooleanMacro("SWIFT_DISABLE_INCREMENTAL_SCAN") public static let SWIFT_ENABLE_LAYOUT_STRING_VALUE_WITNESSES = BuiltinMacros.declareBooleanMacro("SWIFT_ENABLE_LAYOUT_STRING_VALUE_WITNESSES") public static let SWIFT_ENABLE_LIBRARY_EVOLUTION = BuiltinMacros.declareBooleanMacro("SWIFT_ENABLE_LIBRARY_EVOLUTION") public static let SWIFT_ENABLE_BARE_SLASH_REGEX = BuiltinMacros.declareBooleanMacro("SWIFT_ENABLE_BARE_SLASH_REGEX") @@ -1752,7 +1753,7 @@ public final class BuiltinMacros { GENERATE_EMBED_IN_CODE_ACCESSORS, GENERATE_INFOPLIST_FILE, GENERATE_KERNEL_MODULE_INFO_FILE, - GENERATE_MASTER_OBJECT_FILE, + GENERATE_PRELINK_OBJECT_FILE, GENERATE_PKGINFO_FILE, GENERATE_RESOURCE_ACCESSORS, GENERATE_TEST_ENTRY_POINT, @@ -2164,6 +2165,7 @@ public final class BuiltinMacros { SWIFT_EMIT_MODULE_INTERFACE, SWIFT_ENABLE_BATCH_MODE, SWIFT_ENABLE_INCREMENTAL_COMPILATION, + SWIFT_DISABLE_INCREMENTAL_SCAN, SWIFT_ENABLE_LAYOUT_STRING_VALUE_WITNESSES, SWIFT_ENABLE_LIBRARY_EVOLUTION, SWIFT_USE_INTEGRATED_DRIVER, diff --git a/Sources/SWBCore/SigningSupport.swift b/Sources/SWBCore/SigningSupport.swift index 9f874ab2..7d398c55 100644 --- a/Sources/SWBCore/SigningSupport.swift +++ b/Sources/SWBCore/SigningSupport.swift @@ -30,6 +30,8 @@ public protocol PlatformSigningContext func shouldPassEntitlementsFileContentToCodeSign() -> Bool func requiresEntitlements(_ scope: MacroEvaluationScope, hasProfile: Bool, productFileType: FileTypeSpec) -> Bool + + func supportsAppSandboxAndHardenedRuntime() -> Bool } extension PlatformSigningContext @@ -58,12 +60,19 @@ extension PlatformSigningContext { return hasProfile || scope.evaluate(BuiltinMacros.ENTITLEMENTS_REQUIRED) } + + @_spi(Testing) public func supportsAppSandboxAndHardenedRuntime() -> Bool { + return false + } } /// Provides behavior for code signing for the macOS platform. @_spi(Testing) public struct MacSigningContext: PlatformSigningContext { + @_spi(Testing) public func supportsAppSandboxAndHardenedRuntime() -> Bool { + return true + } } diff --git a/Sources/SWBCore/SpecImplementations/RegisterSpecs.swift b/Sources/SWBCore/SpecImplementations/RegisterSpecs.swift index 115a9b73..4bf7277f 100644 --- a/Sources/SWBCore/SpecImplementations/RegisterSpecs.swift +++ b/Sources/SWBCore/SpecImplementations/RegisterSpecs.swift @@ -129,7 +129,7 @@ public struct BuiltinSpecsExtension: SpecificationsExtension { ValidateDevelopmentAssets.self, ConstructStubExecutorFileListToolSpec.self, GateSpec.self, - MasterObjectLinkSpec.self, + PrelinkedObjectLinkSpec.self, SetAttributesSpec.self, WriteFileSpec.self, SignatureCollectionSpec.self, diff --git a/Sources/SWBCore/SpecImplementations/Tools/MasterObjectLink.swift b/Sources/SWBCore/SpecImplementations/Tools/PrelinkedObjectLink.swift similarity index 77% rename from Sources/SWBCore/SpecImplementations/Tools/MasterObjectLink.swift rename to Sources/SWBCore/SpecImplementations/Tools/PrelinkedObjectLink.swift index ade7bd11..d651edfb 100644 --- a/Sources/SWBCore/SpecImplementations/Tools/MasterObjectLink.swift +++ b/Sources/SWBCore/SpecImplementations/Tools/PrelinkedObjectLink.swift @@ -13,15 +13,15 @@ import SWBUtil import SWBMacro -/// Spec to use the linker to run `ld -r` to create a prelinked object file (a.k.a. "master object file"). -final class MasterObjectLinkSpec: CommandLineToolSpec, SpecImplementationType, @unchecked Sendable { - static let identifier = "com.apple.build-tools.master-object-link" +/// Spec to use the linker to run `ld -r` to create a prelinked object file. +public final class PrelinkedObjectLinkSpec: CommandLineToolSpec, SpecImplementationType, @unchecked Sendable { + public static let identifier = "com.apple.build-tools.prelinked-object-link" - class func construct(registry: SpecRegistry, proxy: SpecProxy) -> Spec { - return MasterObjectLinkSpec(registry, proxy, ruleInfoTemplate: [], commandLineTemplate: []) + public class func construct(registry: SpecRegistry, proxy: SpecProxy) -> Spec { + return PrelinkedObjectLinkSpec(registry, proxy, ruleInfoTemplate: [], commandLineTemplate: []) } - override func constructTasks(_ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate) async { + public override func constructTasks(_ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate) async { guard let toolSpecInfo = await cbc.producer.ldLinkerSpec.discoveredCommandLineToolSpecInfo(cbc.producer, cbc.scope, delegate) as? DiscoveredLdLinkerToolSpecInfo else { delegate.error("Could not find path to ld binary") return @@ -62,7 +62,7 @@ final class MasterObjectLinkSpec: CommandLineToolSpec, SpecImplementationType, @ commandLine += cbc.scope.evaluate(BuiltinMacros.PRELINK_FLAGS) let warningLdFlags = cbc.scope.evaluate(BuiltinMacros.WARNING_LDFLAGS) if !warningLdFlags.isEmpty { - // WARNING_LDFLAGS for some reason is only used for creating the master object file. + // WARNING_LDFLAGS for some reason is only used for creating the prelinked object file. delegate.warning("WARNING_LDFLAGS is deprecated; use OTHER_LDFLAGS instead.", location: .buildSetting(BuiltinMacros.WARNING_LDFLAGS)) commandLine += warningLdFlags } @@ -70,6 +70,6 @@ final class MasterObjectLinkSpec: CommandLineToolSpec, SpecImplementationType, @ commandLine += cbc.scope.evaluate(BuiltinMacros.PRELINK_LIBS) commandLine += ["-o", outputPath.str] - delegate.createTask(type: self, ruleInfo: ["MasterObjectLink", outputPath.str], commandLine: commandLine, environment: EnvironmentBindings(), workingDirectory: cbc.producer.defaultWorkingDirectory, inputs: cbc.inputs.map({ $0.absolutePath }), outputs: [outputPath], action: nil, execDescription: "Link \(outputPath.basename)", enableSandboxing: enableSandboxing) + delegate.createTask(type: self, ruleInfo: ["PrelinkedObjectLink", outputPath.str], commandLine: commandLine, environment: EnvironmentBindings(), workingDirectory: cbc.producer.defaultWorkingDirectory, inputs: cbc.inputs.map({ $0.absolutePath }), outputs: [outputPath], action: nil, execDescription: "Link \(outputPath.basename)", enableSandboxing: enableSandboxing) } } diff --git a/Sources/SWBCore/SpecImplementations/Tools/ProductPackaging.swift b/Sources/SWBCore/SpecImplementations/Tools/ProductPackaging.swift index f8f7eb58..0c095dbf 100644 --- a/Sources/SWBCore/SpecImplementations/Tools/ProductPackaging.swift +++ b/Sources/SWBCore/SpecImplementations/Tools/ProductPackaging.swift @@ -114,15 +114,12 @@ public final class ProductPackagingToolSpec : GenericCommandLineToolSpec, SpecId entitlementsDictionary["com.apple.security.get-task-allow"] = nil } - let isAppSandboxEnabled = cbc.scope.evaluate(BuiltinMacros.ENABLE_APP_SANDBOX) - let isHardenedRuntimeEnabled = cbc.scope.evaluate(BuiltinMacros.ENABLE_HARDENED_RUNTIME) - // rdar://142845111 (Turn on `AppSandboxConflictingValuesEmitsWarning` by default) if SWBFeatureFlag.enableAppSandboxConflictingValuesEmitsWarning.value { EntitlementConflictDiagnosticEmitter.checkForConflicts(cbc, delegate, entitlementsDictionary: entitlementsDictionary, entitlementsPath: codeSignEntitlementsInput?.absolutePath) } - if isAppSandboxEnabled || isHardenedRuntimeEnabled { + if cbc.producer.platform?.signingContext.supportsAppSandboxAndHardenedRuntime() == true { // Inject entitlements that are settable via build settings. // This is only supported when App Sandbox or Hardened Runtime is enabled. for (buildSetting, entitlementPrefix) in Self.sandboxFileAccessSettingsAndEntitlements { diff --git a/Sources/SWBCore/SpecImplementations/Tools/SwiftCompiler.swift b/Sources/SWBCore/SpecImplementations/Tools/SwiftCompiler.swift index cec5bb91..2e616d51 100644 --- a/Sources/SWBCore/SpecImplementations/Tools/SwiftCompiler.swift +++ b/Sources/SWBCore/SpecImplementations/Tools/SwiftCompiler.swift @@ -119,6 +119,7 @@ public struct SwiftSourceFileIndexingInfo: SourceFileIndexingInfo { "-emit-dependencies", "-serialize-diagnostics", "-incremental", + "-incremental-dependency-scan", "-parseable-output", "-use-frontend-parseable-output", "-whole-module-optimization", @@ -153,6 +154,7 @@ public struct SwiftSourceFileIndexingInfo: SourceFileIndexingInfo { // can be removed after we use the new driver instead (rdar://75851402). private static let newDriverFlags: Set = [ "-driver-print-graphviz", + "-incremental-dependency-scan", "-explicit-module-build", "-experimental-explicit-module-build", "-nonlib-dependency-scanner", @@ -1743,6 +1745,10 @@ public final class SwiftCompilerSpec : CompilerSpec, SpecIdentifierType, SwiftDi if cbc.scope.evaluate(BuiltinMacros.SWIFT_ENABLE_INCREMENTAL_COMPILATION) { args.append("-incremental") + if LibSwiftDriver.supportsDriverFlag(spelled: "-incremental-dependency-scan"), + !cbc.scope.evaluate(BuiltinMacros.SWIFT_DISABLE_INCREMENTAL_SCAN) { + args.append("-incremental-dependency-scan") + } } } @@ -3061,6 +3067,12 @@ public final class SwiftCompilerSpec : CompilerSpec, SpecIdentifierType, SwiftDi fileMapEntry.indexUnitOutputPath = indexObjectPath.str } } + let objectFilePrefix = objectFilePath.basenameWithoutSuffix + // The path to the bitcode file. This is used, for example, by LTO. + if compilationMode.compileSources { + let bitcodeFilePath = objectFileDir.join(objectFilePrefix + ".bc") + fileMapEntry.llvmBitcode = bitcodeFilePath.str + } return (objectFilePath, fileMapEntry) } @@ -3279,6 +3291,8 @@ public final class SwiftCompilerSpec : CompilerSpec, SpecIdentifierType, SwiftDi for arg in [ // Should strip this because it saves some work and avoids writing a useless incremental build record "-incremental", + // Same as above + "-incremental-dependency-scan", // Stripped because we want to end up in single file mode "-enable-batch-mode", @@ -3774,6 +3788,7 @@ struct SwiftOutputFileMap: Codable { struct Entry: Codable { var object: String? var indexUnitOutputPath: String? + var llvmBitcode: String? var remap: String? var diagnostics: String? var emitModuleDiagnostics: String? @@ -3787,6 +3802,7 @@ struct SwiftOutputFileMap: Codable { enum CodingKeys: String, CodingKey { case object case indexUnitOutputPath = "index-unit-output-path" + case llvmBitcode = "llvm-bc" case remap case diagnostics case emitModuleDiagnostics = "emit-module-diagnostics" diff --git a/Sources/SWBCore/Specs/CoreBuildSystem.xcspec b/Sources/SWBCore/Specs/CoreBuildSystem.xcspec index d48771f6..d89f2142 100644 --- a/Sources/SWBCore/Specs/CoreBuildSystem.xcspec +++ b/Sources/SWBCore/Specs/CoreBuildSystem.xcspec @@ -442,9 +442,9 @@ }; }, { - Name = "GENERATE_MASTER_OBJECT_FILE"; + Name = "GENERATE_PRELINK_OBJECT_FILE"; Type = bool; - DefaultValue = NO; + DefaultValue = "$(GENERATE_MASTER_OBJECT_FILE:default=NO)"; // ignore-unacceptable-language; kept for compatibility }, { Name = "PRELINK_LIBS"; @@ -1598,10 +1598,10 @@ When `GENERATE_INFOPLIST_FILE` is enabled, sets the value of the [CFBundleIdenti ); }, { - Name = "GENERATE_MASTER_OBJECT_FILE"; + Name = "GENERATE_PRELINK_OBJECT_FILE"; Type = Boolean; Category = "Linking - General"; - DefaultValue = NO; + DefaultValue = "$(GENERATE_MASTER_OBJECT_FILE:default=NO)"; // ignore-unacceptable-language; kept for compatibility ConditionFlavors = ( arch, sdk, diff --git a/Sources/SWBCore/Specs/en.lproj/CoreBuildSystem.strings b/Sources/SWBCore/Specs/en.lproj/CoreBuildSystem.strings index 455318c8..a33cfc4a 100644 --- a/Sources/SWBCore/Specs/en.lproj/CoreBuildSystem.strings +++ b/Sources/SWBCore/Specs/en.lproj/CoreBuildSystem.strings @@ -409,8 +409,8 @@ Generally you should not specify an order file in Debug or Development configura "[LINKER_DISPLAYS_MANGLED_NAMES]-name" = "Display Mangled Names"; "[LINKER_DISPLAYS_MANGLED_NAMES]-description" = "Activating this setting causes the linker to display mangled names for C++ symbols. Normally, this is not recommended, but turning it on can help to diagnose and solve C++ link errors."; -"[GENERATE_MASTER_OBJECT_FILE]-name" = "Perform Single-Object Prelink"; -"[GENERATE_MASTER_OBJECT_FILE]-description" = "Activating this setting will cause the object files built by a target to be prelinked using `ld -r` into a single object file, and that object file will then be linked into the final product. This is useful to force the linker to resolve symbols and link the object files into a single module before building a static library. Also, a separate set of link flags can be applied to the prelink allowing additional control over, for instance, exported symbols."; +"[GENERATE_PRELINK_OBJECT_FILE]-name" = "Perform Single-Object Prelink"; +"[GENERATE_PRELINK_OBJECT_FILE]-description" = "Activating this setting will cause the object files built by a target to be prelinked using `ld -r` into a single object file, and that object file will then be linked into the final product. This is useful to force the linker to resolve symbols and link the object files into a single module before building a static library. Also, a separate set of link flags can be applied to the prelink allowing additional control over, for instance, exported symbols."; "[PRELINK_LIBS]-name" = "Prelink libraries"; "[PRELINK_LIBS]-description" = "Additional libraries to pass when performing a single-object prelink."; diff --git a/Sources/SWBGenericUnixPlatform/CMakeLists.txt b/Sources/SWBGenericUnixPlatform/CMakeLists.txt index 8e5213b8..4a7550cf 100644 --- a/Sources/SWBGenericUnixPlatform/CMakeLists.txt +++ b/Sources/SWBGenericUnixPlatform/CMakeLists.txt @@ -28,10 +28,18 @@ file(CONFIGURE ]] ESCAPE_QUOTES @ONLY NEWLINE_STYLE LF) -add_library(SWBGenericUnixPlatform STATIC +add_library(SWBGenericUnixPlatform Plugin.swift) target_link_libraries(SWBGenericUnixPlatform PUBLIC SWBCore SWBUtil) target_sources(SWBGenericUnixPlatform PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/resource_bundle_accessor.swift") + +set_target_properties(SWBGenericUnixPlatform PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBGenericUnixPlatform) + +install(TARGETS SWBGenericUnixPlatform + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBLLBuild/CMakeLists.txt b/Sources/SWBLLBuild/CMakeLists.txt index 3f36654b..353db118 100644 --- a/Sources/SWBLLBuild/CMakeLists.txt +++ b/Sources/SWBLLBuild/CMakeLists.txt @@ -14,5 +14,12 @@ set_target_properties(SWBLLBuild PROPERTIES Swift_LANGUAGE_VERSION 6) target_link_libraries(SWBLLBuild PUBLIC SWBUtil - $<$>:libllbuild> $<$>:llbuildSwift>) + +set_target_properties(SWBLLBuild PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBLLBuild) + +install(TARGETS SWBLLBuild + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBLibc/CMakeLists.txt b/Sources/SWBLibc/CMakeLists.txt index 8e5daf61..3e9917c6 100644 --- a/Sources/SWBLibc/CMakeLists.txt +++ b/Sources/SWBLibc/CMakeLists.txt @@ -19,3 +19,11 @@ target_link_libraries(SWBLibc PUBLIC # without this explicit configuration. target_include_directories(SWBLibc PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) + +set_target_properties(SWBLibc PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBLibc) + +install(TARGETS SWBLibc + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBMacro/CMakeLists.txt b/Sources/SWBMacro/CMakeLists.txt index 4abeddf1..aaa68d49 100644 --- a/Sources/SWBMacro/CMakeLists.txt +++ b/Sources/SWBMacro/CMakeLists.txt @@ -31,5 +31,10 @@ target_link_libraries(SWBMacro PUBLIC SwiftDriver TSCBasic) -target_include_directories(SWBMacro PUBLIC - ${CMAKE_CURRENT_BINARY_DIR}) +set_target_properties(SWBMacro PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBMacro) + +install(TARGETS SWBMacro + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBProjectModel/CMakeLists.txt b/Sources/SWBProjectModel/CMakeLists.txt index 3a98c919..721ae581 100644 --- a/Sources/SWBProjectModel/CMakeLists.txt +++ b/Sources/SWBProjectModel/CMakeLists.txt @@ -20,3 +20,11 @@ set_target_properties(SWBProjectModel PROPERTIES Swift_LANGUAGE_VERSION 6) target_link_libraries(SWBProjectModel PUBLIC SWBProtocol) + +set_target_properties(SWBProjectModel PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBProjectModel) + +install(TARGETS SWBProjectModel + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBProjectModel/PIFGenerationModel.swift b/Sources/SWBProjectModel/PIFGenerationModel.swift index 975fc22b..698a7343 100644 --- a/Sources/SWBProjectModel/PIFGenerationModel.swift +++ b/Sources/SWBProjectModel/PIFGenerationModel.swift @@ -963,7 +963,7 @@ public enum PIF { public var GCC_OPTIMIZATION_LEVEL: String? public var GCC_PREPROCESSOR_DEFINITIONS: [String]? public var GENERATE_EMBED_IN_CODE_ACCESSORS: String? - public var GENERATE_MASTER_OBJECT_FILE: String? + public var GENERATE_PRELINK_OBJECT_FILE: String? public var GENERATE_RESOURCE_ACCESSORS: String? public var HEADER_SEARCH_PATHS: [String]? public var INFOPLIST_FILE: String? @@ -1045,6 +1045,9 @@ public enum PIF { public var USE_HEADERMAP: String? public var USES_SWIFTPM_UNSAFE_FLAGS: String? public var WATCHOS_DEPLOYMENT_TARGET: String? + + @available(*, deprecated, renamed: "GENERATE_PRELINK_OBJECT_FILE") + public var GENERATE_MASTER_OBJECT_FILE: String? // ignore-unacceptable-language } } diff --git a/Sources/SWBProtocol/CMakeLists.txt b/Sources/SWBProtocol/CMakeLists.txt index d00c636b..9208d4b2 100644 --- a/Sources/SWBProtocol/CMakeLists.txt +++ b/Sources/SWBProtocol/CMakeLists.txt @@ -48,3 +48,11 @@ set_target_properties(SWBProtocol PROPERTIES Swift_LANGUAGE_VERSION 6) target_link_libraries(SWBProtocol PUBLIC SWBUtil) + +set_target_properties(SWBProtocol PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBProtocol) + +install(TARGETS SWBProtocol + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBQNXPlatform/CMakeLists.txt b/Sources/SWBQNXPlatform/CMakeLists.txt index b458f8ce..23249e86 100644 --- a/Sources/SWBQNXPlatform/CMakeLists.txt +++ b/Sources/SWBQNXPlatform/CMakeLists.txt @@ -28,7 +28,7 @@ file(CONFIGURE ]] ESCAPE_QUOTES @ONLY NEWLINE_STYLE LF) -add_library(SWBQNXPlatform STATIC +add_library(SWBQNXPlatform Plugin.swift QNXSDP.swift) target_link_libraries(SWBQNXPlatform PUBLIC @@ -37,3 +37,11 @@ target_link_libraries(SWBQNXPlatform PUBLIC SWBUtil) target_sources(SWBQNXPlatform PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/resource_bundle_accessor.swift") + +set_target_properties(SWBQNXPlatform PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBQNXPlatform) + +install(TARGETS SWBQNXPlatform + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBServiceCore/CMakeLists.txt b/Sources/SWBServiceCore/CMakeLists.txt index 673eec1e..9d39ed50 100644 --- a/Sources/SWBServiceCore/CMakeLists.txt +++ b/Sources/SWBServiceCore/CMakeLists.txt @@ -18,3 +18,11 @@ set_target_properties(SWBServiceCore PROPERTIES Swift_LANGUAGE_VERSION 6) target_link_libraries(SWBServiceCore PUBLIC SWBProtocol) + +set_target_properties(SWBServiceCore PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBServiceCore) + +install(TARGETS SWBServiceCore + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBServiceCore/ServiceHostConnection.swift b/Sources/SWBServiceCore/ServiceHostConnection.swift index 34001138..59d1a172 100644 --- a/Sources/SWBServiceCore/ServiceHostConnection.swift +++ b/Sources/SWBServiceCore/ServiceHostConnection.swift @@ -46,9 +46,6 @@ final class ServiceHostConnection: @unchecked Sendable { /// Whether the queue is suspended. private let isSuspended = LockedValue(true) - /// The queue used to read incoming messages. - private let receiveQueue: SWBQueue - /// The queue used to send outgoing messages. private let sendQueue: SWBQueue @@ -69,7 +66,6 @@ final class ServiceHostConnection: @unchecked Sendable { self.inputFD = inputFD self.outputFD = outputFD // The queues for the service host connection are given .userInitiated QOS (not .utility, which most queues in Swift Build have) because we don't know whether we're servicing a user interaction request. Most requests should be shunted to a background thread unless there's a reason to send a quick response at high priority. - self.receiveQueue = SWBQueue(label: "SWBBuildService.ServiceHostConnection.receiveQueue", qos: .userInitiated, autoreleaseFrequency: .workItem) self.sendQueue = SWBQueue(label: "SWBBuildService.ServiceHostConnection.sendQueue", qos: .userInitiated, autoreleaseFrequency: .workItem) } @@ -136,7 +132,7 @@ final class ServiceHostConnection: @unchecked Sendable { // Otherwise, launch the receive pump. isSuspended.withLock { $0 = false } - receiveQueue.async { + Task(priority: .userInitiated) { // Read data forever. var data: [UInt8] = [] let tmpBufferSize = 4096 @@ -152,10 +148,13 @@ final class ServiceHostConnection: @unchecked Sendable { #endif // Read data. - let result = read(self.inputFD.rawValue, tmp.baseAddress, numericCast(tmpBufferSize)) - if result < 0 { - if errno == EINTR { continue } - error = ServiceHostIOError(message: "read from client failed", cause: SWBUtil.POSIXError(errno, context: "read")) + let result: Int + do { + let buf = try await DispatchFD(fileDescriptor: self.inputFD).readChunk(upToLength: tmpBufferSize) + result = buf.count + buf.copyBytes(to: tmp) + } catch let readError { + error = ServiceHostIOError(message: "read from client failed", cause: readError) break } if result == 0 { diff --git a/Sources/SWBTaskConstruction/CMakeLists.txt b/Sources/SWBTaskConstruction/CMakeLists.txt index 7657836a..b792f9dc 100644 --- a/Sources/SWBTaskConstruction/CMakeLists.txt +++ b/Sources/SWBTaskConstruction/CMakeLists.txt @@ -63,3 +63,11 @@ set_target_properties(SWBTaskConstruction PROPERTIES target_link_libraries(SWBTaskConstruction PUBLIC SWBCore SWBUtil) + +set_target_properties(SWBTaskConstruction PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBTaskConstruction) + +install(TARGETS SWBTaskConstruction + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBTaskConstruction/TaskProducers/BuildPhaseTaskProducers/SourcesTaskProducer.swift b/Sources/SWBTaskConstruction/TaskProducers/BuildPhaseTaskProducers/SourcesTaskProducer.swift index 89ecceaa..b2ab7c3e 100644 --- a/Sources/SWBTaskConstruction/TaskProducers/BuildPhaseTaskProducers/SourcesTaskProducer.swift +++ b/Sources/SWBTaskConstruction/TaskProducers/BuildPhaseTaskProducers/SourcesTaskProducer.swift @@ -865,14 +865,14 @@ final class SourcesTaskProducer: FilesBasedBuildPhaseTaskProducerBase, FilesBase } } - // Handle linking master objects. Presently we always do this if GENERATE_MASTER_OBJECT_FILE even if there are no other tasks, since PRELINK_LIBS or PRELINK_FLAGS might be set to values which will cause a master object file to be generated. - // FIXME: The implicitly means that if GENERATE_MASTER_OBJECT_FILE is enabled then we will always try to link. That's arguably not correct. - if !isForAPI && scope.evaluate(BuiltinMacros.GENERATE_MASTER_OBJECT_FILE) { - let executableName = scope.evaluate(BuiltinMacros.EXECUTABLE_NAME) + "-" + arch + "-master.o" + // Handle linking prelinked objects. Presently we always do this if GENERATE_PRELINK_OBJECT_FILE even if there are no other tasks, since PRELINK_LIBS or PRELINK_FLAGS might be set to values which will cause a prelinked object file to be generated. + // FIXME: The implicitly means that if GENERATE_PRELINK_OBJECT_FILE is enabled then we will always try to link. That's arguably not correct. + if !isForAPI && scope.evaluate(BuiltinMacros.GENERATE_PRELINK_OBJECT_FILE) { + let executableName = scope.evaluate(BuiltinMacros.EXECUTABLE_NAME) + "-" + arch + "-prelink.o" // FIXME: It would be more consistent to put this in the per-arch directory. let output = Path(scope.evaluate(BuiltinMacros.PER_VARIANT_OBJECT_FILE_DIR)).join(executableName) await appendGeneratedTasks(&perArchTasks, options: [.linking, .linkingRequirement, .unsignedProductRequirement]) { delegate in - await context.masterObjectLinkSpec.constructTasks(CommandBuildContext(producer: context, scope: scope, inputs: linkerInputNodes.map { FileToBuild(context: context, absolutePath: $0.path) }, output: output), delegate) + await context.prelinkedObjectLinkSpec.constructTasks(CommandBuildContext(producer: context, scope: scope, inputs: linkerInputNodes.map { FileToBuild(context: context, absolutePath: $0.path) }, output: output), delegate) } linkerInputNodes = [context.createNode(output)] } @@ -912,7 +912,7 @@ final class SourcesTaskProducer: FilesBasedBuildPhaseTaskProducerBase, FilesBase continue } - // Create the linker task. If we have no input files but decide to create the task anyway, then this task will rely on gate tasks to be properly ordered (which is what happens for the master object file task above if there are no input files). + // Create the linker task. If we have no input files but decide to create the task anyway, then this task will rely on gate tasks to be properly ordered (which is what happens for the prelinked object file task above if there are no input files). if !linkerInputNodes.isEmpty || (components.contains("build") && scope.evaluate(BuiltinMacros.MERGE_LINKED_LIBRARIES)) { // Compute the output path. let output: Path diff --git a/Sources/SWBTaskConstruction/TaskProducers/TaskProducer.swift b/Sources/SWBTaskConstruction/TaskProducers/TaskProducer.swift index d4c2cd5f..bc5e5a7b 100644 --- a/Sources/SWBTaskConstruction/TaskProducers/TaskProducer.swift +++ b/Sources/SWBTaskConstruction/TaskProducers/TaskProducer.swift @@ -228,7 +228,7 @@ public class TaskProducerContext: StaleFileRemovalContext, BuildFileResolution public let ldLinkerSpec: LdLinkerSpec public let libtoolLinkerSpec: LibtoolLinkerSpec public let lipoSpec: LipoToolSpec - let masterObjectLinkSpec: CommandLineToolSpec + let prelinkedObjectLinkSpec: CommandLineToolSpec public let mkdirSpec: MkdirToolSpec let modulesVerifierSpec: ModulesVerifierToolSpec let clangModuleVerifierInputGeneratorSpec: ClangModuleVerifierInputGeneratorSpec @@ -354,7 +354,7 @@ public class TaskProducerContext: StaleFileRemovalContext, BuildFileResolution self.ldLinkerSpec = try! workspaceContext.core.specRegistry.getSpec(domain: domain) as LdLinkerSpec self.libtoolLinkerSpec = try! workspaceContext.core.specRegistry.getSpec(domain: domain) as LibtoolLinkerSpec self.lipoSpec = workspaceContext.core.specRegistry.getSpec("com.apple.xcode.linkers.lipo", domain: domain) as! LipoToolSpec - self.masterObjectLinkSpec = workspaceContext.core.specRegistry.getSpec("com.apple.build-tools.master-object-link", domain: domain) as! CommandLineToolSpec + self.prelinkedObjectLinkSpec = workspaceContext.core.specRegistry.getSpec(PrelinkedObjectLinkSpec.identifier, domain: domain) as! CommandLineToolSpec self.mkdirSpec = workspaceContext.core.specRegistry.getSpec("com.apple.tools.mkdir", domain: domain) as! MkdirToolSpec self.modulesVerifierSpec = workspaceContext.core.specRegistry.getSpec("com.apple.build-tools.modules-verifier", domain: domain) as! ModulesVerifierToolSpec self.clangModuleVerifierInputGeneratorSpec = workspaceContext.core.specRegistry.getSpec("com.apple.build-tools.module-verifier-input-generator", domain: domain) as! ClangModuleVerifierInputGeneratorSpec @@ -724,9 +724,9 @@ public class TaskProducerContext: StaleFileRemovalContext, BuildFileResolution return false } - // If this target is generating a master object file, then we assume it will produce a binary. - // FIXME: This is nasty. See SourcesTaskProducer.generateTasks() for handling of GENERATE_MASTER_OBJECT_FILE. - guard !scope.evaluate(BuiltinMacros.GENERATE_MASTER_OBJECT_FILE) else { + // If this target is generating a prelinked object file, then we assume it will produce a binary. + // FIXME: This is nasty. See SourcesTaskProducer.generateTasks() for handling of GENERATE_PRELINK_OBJECT_FILE. + guard !scope.evaluate(BuiltinMacros.GENERATE_PRELINK_OBJECT_FILE) else { return true } diff --git a/Sources/SWBTaskExecution/BuildDescriptionManager.swift b/Sources/SWBTaskExecution/BuildDescriptionManager.swift index 6dc77926..ae355c56 100644 --- a/Sources/SWBTaskExecution/BuildDescriptionManager.swift +++ b/Sources/SWBTaskExecution/BuildDescriptionManager.swift @@ -285,7 +285,7 @@ package final class BuildDescriptionManager: Sendable { } var isIndexWorkspaceDescription: Bool { - return isForIndex && buildRequest.parameters.activeRunDestination == nil + return buildRequest.buildsIndexWorkspaceDescription } func signature(cacheDir: Path) throws -> BuildDescriptionSignature { diff --git a/Sources/SWBTaskExecution/CMakeLists.txt b/Sources/SWBTaskExecution/CMakeLists.txt index c5bab209..6c7cba03 100644 --- a/Sources/SWBTaskExecution/CMakeLists.txt +++ b/Sources/SWBTaskExecution/CMakeLists.txt @@ -82,3 +82,11 @@ target_link_libraries(SWBTaskExecution PUBLIC SWBLLBuild SWBTaskConstruction SWBUtil) + +set_target_properties(SWBTaskExecution PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBTaskExecution) + +install(TARGETS SWBTaskExecution + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBTestSupport/SkippedTestSupport.swift b/Sources/SWBTestSupport/SkippedTestSupport.swift index d6ee26e5..7ba31ee9 100644 --- a/Sources/SWBTestSupport/SkippedTestSupport.swift +++ b/Sources/SWBTestSupport/SkippedTestSupport.swift @@ -172,6 +172,10 @@ extension Trait where Self == Testing.ConditionTrait { #endif } + package static func skipInGitHubActions(_ comment: Comment? = nil) -> Self { + return .skipIfEnvironmentVariableSet(key: "GITHUB_ACTIONS") + } + package static func requireClangFeatures(_ requiredFeatures: DiscoveredClangToolSpecInfo.FeatureFlag...) -> Self { enabled("Clang compiler does not support features: \(requiredFeatures)") { let features = try await ConditionTraitContext.shared.clangFeatures @@ -235,8 +239,8 @@ extension Trait where Self == Testing.ConditionTrait { } } - package static func skipIfEnvironmentVariableSet(key: EnvironmentKey) -> Self { - disabled("environment sets '\(key)'") { + package static func skipIfEnvironmentVariableSet(key: EnvironmentKey, _ comment: Comment? = nil) -> Self { + disabled(comment ?? "environment sets '\(key)'") { getEnvironmentVariable(key) != nil } } diff --git a/Sources/SWBUniversalPlatform/CMakeLists.txt b/Sources/SWBUniversalPlatform/CMakeLists.txt index f331ab96..7b0fffd7 100644 --- a/Sources/SWBUniversalPlatform/CMakeLists.txt +++ b/Sources/SWBUniversalPlatform/CMakeLists.txt @@ -28,7 +28,7 @@ file(CONFIGURE ]] ESCAPE_QUOTES @ONLY NEWLINE_STYLE LF) -add_library(SWBUniversalPlatform STATIC +add_library(SWBUniversalPlatform CopyPlistFile.swift CopyStringsFile.swift CppTool.swift @@ -48,3 +48,11 @@ target_link_libraries(SWBUniversalPlatform PUBLIC ArgumentParser) target_sources(SWBUniversalPlatform PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/resource_bundle_accessor.swift") + +set_target_properties(SWBUniversalPlatform PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBUniversalPlatform) + +install(TARGETS SWBUniversalPlatform + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBUniversalPlatform/Specs/Clang LLVM 1.0.xcspec b/Sources/SWBUniversalPlatform/Specs/Clang LLVM 1.0.xcspec index fcdfeda1..f7ce248e 100644 --- a/Sources/SWBUniversalPlatform/Specs/Clang LLVM 1.0.xcspec +++ b/Sources/SWBUniversalPlatform/Specs/Clang LLVM 1.0.xcspec @@ -2736,6 +2736,7 @@ YES = (); NO = ( "-D_LIBCPP_HAS_NO_ASAN", + "-D_LIBCPP_HAS_ASAN=0", ); }; Condition = "$(CLANG_ADDRESS_SANITIZER)"; @@ -2924,8 +2925,13 @@ DefaultValue = compiler-default; CommandLineArgs = { compiler-default = (); - YES = ("-ftyped-cxx-new-delete"); - NO = ("-fno-typed-cxx-new-delete"); + YES = ("-ftyped-cxx-new-delete", "-ftyped-cxx-delete"); + NO = ("-fno-typed-cxx-new-delete", "-fno-typed-cxx-delete"); + }; + AdditionalLinkerArgs = { + compiler-default = (); + YES = ("-ftyped-cxx-new-delete", "-ftyped-cxx-delete"); + NO = (); }; }, // Index-while-building options, not visible in build settings. diff --git a/Sources/SWBUniversalPlatform/Specs/ProductTypes.xcspec b/Sources/SWBUniversalPlatform/Specs/ProductTypes.xcspec index 0067050f..38336aec 100644 --- a/Sources/SWBUniversalPlatform/Specs/ProductTypes.xcspec +++ b/Sources/SWBUniversalPlatform/Specs/ProductTypes.xcspec @@ -299,6 +299,8 @@ INSTALL_PATH = "$(INSTALL_PATH_XCTRUNNER_$(USES_XCTRUNNER:default=NO))"; INSTALL_PATH_XCTRUNNER_YES = "$(DEFAULT_TEST_RUNNER_APP_INSTALL_PATH)"; INSTALL_PATH_XCTRUNNER_NO = "$(DEFAULT_TEST_BUNDLE_INSTALL_PATH)"; + ENABLE_APP_SANDBOX = "$(USES_XCTRUNNER)"; + ENABLE_OUTGOING_NETWORK_CONNECTIONS = "$(USES_XCTRUNNER)"; ENTITLEMENTS_REQUIRED = NO; diff --git a/Sources/SWBUniversalPlatform/Specs/Swift.xcspec b/Sources/SWBUniversalPlatform/Specs/Swift.xcspec index 4f04b3e2..b8434e0c 100644 --- a/Sources/SWBUniversalPlatform/Specs/Swift.xcspec +++ b/Sources/SWBUniversalPlatform/Specs/Swift.xcspec @@ -569,7 +569,22 @@ Category = "Upcoming Features"; Description = "Enables strict concurrency checking to produce warnings for possible data races. This is always 'complete' when in the Swift 6 language mode and produces errors instead of warnings."; }, - + { + Name = "SWIFT_DEFAULT_ACTOR_ISOLATION"; + Type = Enumeration; + Values = ( + nonisolated, + MainActor + ); + DefaultValue = "nonisolated"; + CommandLineArgs = { + nonisolated = (); + MainActor = ( "-default-isolation=MainActor" ); + }; + DisplayName = "Default Actor Isolation"; + Category = "Language"; + Description = "Controls default actor isolation for unannotated code. When set to 'MainActor', `@MainActor` isolation will be inferred by default to mitigate false-positive data-race safety errors in sequential code."; + }, { Name = "SWIFT_STRICT_MEMORY_SAFETY"; Type = Boolean; diff --git a/Sources/SWBUtil/CMakeLists.txt b/Sources/SWBUtil/CMakeLists.txt index 0be8ed58..eae57b98 100644 --- a/Sources/SWBUtil/CMakeLists.txt +++ b/Sources/SWBUtil/CMakeLists.txt @@ -111,3 +111,11 @@ target_link_libraries(SWBUtil PUBLIC SWBLibc ArgumentParser $<$>:SwiftSystem::SystemPackage>) + +set_target_properties(SWBUtil PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBUtil) + +install(TARGETS SWBUtil + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBUtil/Dispatch+Async.swift b/Sources/SWBUtil/Dispatch+Async.swift index cde7d4c1..bf70a86d 100644 --- a/Sources/SWBUtil/Dispatch+Async.swift +++ b/Sources/SWBUtil/Dispatch+Async.swift @@ -13,7 +13,7 @@ // This file contains helpers used to bridge GCD and Swift Concurrency. // In the long term, these ideally all go away. -private import Foundation +import Foundation /// Runs an async function and synchronously waits for the response. /// - warning: This function is extremely dangerous because it blocks the calling thread and may lead to deadlock, and should only be used as a temporary transitional aid. @@ -41,6 +41,24 @@ public func runAsyncAndBlock(_ block: @Sendable @escaping () asy return try result.value!.get() } +extension DispatchFD { + public func readChunk(upToLength maxLength: Int) async throws -> SWBDispatchData { + return try await withCheckedThrowingContinuation { continuation in + SWBDispatchIO.read( + fromFileDescriptor: self, + maxLength: maxLength, + runningHandlerOn: .global() + ) { data, error in + if error != 0 { + continuation.resume(throwing: POSIXError(error)) + return + } + continuation.resume(returning: data) + } + } + } +} + extension AsyncThrowingStream where Element == UInt8, Failure == any Error { /// Returns an async stream which reads bytes from the specified file descriptor. Unlike `FileHandle.bytes`, it does not block the caller. @available(macOS, deprecated: 15.0, message: "Use the AsyncSequence-returning overload.") diff --git a/Sources/SWBUtil/FSProxy.swift b/Sources/SWBUtil/FSProxy.swift index ae89474c..974bc667 100644 --- a/Sources/SWBUtil/FSProxy.swift +++ b/Sources/SWBUtil/FSProxy.swift @@ -615,69 +615,15 @@ class LocalFS: FSProxy, @unchecked Sendable { } func touch(_ path: Path) throws { - #if os(Windows) - let handle: HANDLE = path.withPlatformString { - CreateFileW($0, DWORD(GENERIC_WRITE), DWORD(FILE_SHARE_READ), nil, - DWORD(OPEN_EXISTING), DWORD(FILE_FLAG_BACKUP_SEMANTICS), nil) - } - if handle == INVALID_HANDLE_VALUE { - throw Win32Error(GetLastError()) - } - try handle.closeAfter { - var ft = FILETIME() - var st = SYSTEMTIME() - GetSystemTime(&st) - SystemTimeToFileTime(&st, &ft) - if !SetFileTime(handle, nil, &ft, &ft) { - Win32Error(GetLastError()) - } - } - #else - try eintrLoop { - guard utimensat(AT_FDCWD, path.str, nil, 0) == 0 else { - throw POSIXError(errno, context: "utimensat", "AT_FDCWD", path.str) - } - } - #endif + try _setFileTimestamp(path, timestamp: Date()) } func setFileTimestamp(_ path: Path, timestamp: Int) throws { - #if os(Windows) - let handle: HANDLE = path.withPlatformString { - CreateFileW($0, DWORD(GENERIC_WRITE), DWORD(FILE_SHARE_READ), nil, - DWORD(OPEN_EXISTING), DWORD(FILE_FLAG_BACKUP_SEMANTICS), nil) - } - if handle == INVALID_HANDLE_VALUE { - throw Win32Error(GetLastError()) - } - try handle.closeAfter { - // Number of 100ns intervals between 1601 and 1970 epochs - let delta = 116444736000000000 - - let ll = UInt64((timestamp * 10000000) + delta) - - var timeInt = ULARGE_INTEGER() - timeInt.QuadPart = ll + try _setFileTimestamp(path, timestamp: Date(timeIntervalSince1970: Double(timestamp))) + } - var ft = FILETIME() - ft.dwLowDateTime = timeInt.LowPart - ft.dwHighDateTime = timeInt.HighPart - if !SetFileTime(handle, nil, &ft, &ft) { - throw Win32Error(GetLastError()) - } - } - #else - try eintrLoop { - #if os(Linux) || os(Android) - let UTIME_OMIT = 1073741822 - #endif - let atime = timespec(tv_sec: 0, tv_nsec: Int(UTIME_OMIT)) - let mtime = timespec(tv_sec: time_t(timestamp), tv_nsec: 0) - guard utimensat(AT_FDCWD, path.str, [atime, mtime], 0) == 0 else { - throw POSIXError(errno, context: "utimensat", "AT_FDCWD", path.str, String(timestamp)) - } - } - #endif + private func _setFileTimestamp(_ path: Path, timestamp: Date) throws { + try fileManager.setAttributes([.modificationDate: timestamp], ofItemAtPath: path.str) } func getFileInfo(_ path: Path) throws -> FileInfo { @@ -875,28 +821,10 @@ class LocalFS: FSProxy, @unchecked Sendable { func realpath(_ path: Path) throws -> Path { #if os(Windows) - let handle: HANDLE = path.withPlatformString { - CreateFileW($0, GENERIC_READ, DWORD(FILE_SHARE_READ), nil, - DWORD(OPEN_EXISTING), DWORD(FILE_FLAG_BACKUP_SEMANTICS), nil) - } - if handle == INVALID_HANDLE_VALUE { + guard exists(path) else { throw POSIXError(ENOENT, context: "realpath", path.str) } - return try handle.closeAfter { - let dwLength: DWORD = GetFinalPathNameByHandleW(handle, nil, 0, DWORD(FILE_NAME_NORMALIZED)) - return try withUnsafeTemporaryAllocation(of: WCHAR.self, capacity: Int(dwLength)) { - guard GetFinalPathNameByHandleW(handle, $0.baseAddress!, DWORD($0.count), - DWORD(FILE_NAME_NORMALIZED)) == dwLength - 1 else { - throw Win32Error(GetLastError()) - } - let path = String(platformString: $0.baseAddress!) - // Drop UNC prefix if present - if path.hasPrefix(#"\\?\"#) { - return Path(path.dropFirst(4)) - } - return Path(path) - } - } + return Path(path.str.standardizingPath) #else guard let result = SWBLibc.realpath(path.str, nil) else { throw POSIXError(errno, context: "realpath", path.str) } defer { free(result) } diff --git a/Sources/SWBUtil/SWBDispatch.swift b/Sources/SWBUtil/SWBDispatch.swift index ecbd2506..4845461f 100644 --- a/Sources/SWBUtil/SWBDispatch.swift +++ b/Sources/SWBUtil/SWBDispatch.swift @@ -15,7 +15,7 @@ private import Dispatch public import SWBLibc -import Foundation +public import Foundation #if canImport(System) public import System @@ -123,6 +123,12 @@ extension SWBDispatchData: RandomAccessCollection { } } +extension SWBDispatchData: DataProtocol { + public var regions: DispatchData.Regions { + dispatchData.regions + } +} + /// Thin wrapper for `DispatchSemaphore` to isolate it from the rest of the codebase and help migration away from it. internal final class SWBDispatchSemaphore: Sendable { private let semaphore: DispatchSemaphore @@ -183,6 +189,13 @@ public final class SWBDispatchIO: Sendable { io = DispatchIO(type: .stream, fileDescriptor: numericCast(fileDescriptor), queue: queue.queue, cleanupHandler: cleanupHandler) } + public static func read(fromFileDescriptor fileDescriptor: DispatchFD, maxLength: Int, runningHandlerOn queue: SWBQueue, handler: @escaping (SWBDispatchData, Int32) -> Void) { + // Most of the dispatch APIs take a parameter called "fileDescriptor". On Windows (except makeReadSource and makeWriteSource) it is actually a HANDLE, so convert it accordingly. + DispatchIO.read(fromFileDescriptor: numericCast(fileDescriptor.rawValue), maxLength: maxLength, runningHandlerOn: queue.queue) { data, error in + handler(SWBDispatchData(data), error) + } + } + public static func stream(fileDescriptor: DispatchFD, queue: SWBQueue, cleanupHandler: @escaping (Int32) -> Void) -> SWBDispatchIO { // Most of the dispatch APIs take a parameter called "fileDescriptor". On Windows (except makeReadSource and makeWriteSource) it is actually a HANDLE, so convert it accordingly. SWBDispatchIO(fileDescriptor: numericCast(fileDescriptor.rawValue), queue: queue, cleanupHandler: cleanupHandler) @@ -282,17 +295,8 @@ public final class SWBQueue: Sendable { } } - public func async(group: SWBDispatchGroup? = nil, execute body: @escaping @Sendable () -> Void) { - return queue.async(group: group?.group, execute: body) - } - - // Temporary hack until rdar://98401196 (Use Swift Concurrency for low-level IO in ServiceHostConnection) lands. This should be safe because we only ever call `async` once in the place we use this. - public func async(qos: SWBQoS = .unspecified, execute work: @Sendable @escaping () async -> Void) { - queue.async(group: nil, qos: qos.dispatchQoS, flags: []) { - Task { - await work() - } - } + public func async(group: SWBDispatchGroup? = nil, qos: SWBQoS = .unspecified, execute body: @escaping @Sendable () -> Void) { + return queue.async(group: group?.group, qos: qos.dispatchQoS, execute: body) } public static func global() -> Self { diff --git a/Sources/SWBWebAssemblyPlatform/CMakeLists.txt b/Sources/SWBWebAssemblyPlatform/CMakeLists.txt index 8953a5aa..0c12e39a 100644 --- a/Sources/SWBWebAssemblyPlatform/CMakeLists.txt +++ b/Sources/SWBWebAssemblyPlatform/CMakeLists.txt @@ -28,7 +28,7 @@ file(CONFIGURE ]] ESCAPE_QUOTES @ONLY NEWLINE_STYLE LF) -add_library(SWBWebAssemblyPlatform STATIC +add_library(SWBWebAssemblyPlatform Plugin.swift) target_link_libraries(SWBWebAssemblyPlatform PUBLIC SWBCore @@ -36,3 +36,11 @@ target_link_libraries(SWBWebAssemblyPlatform PUBLIC SWBUtil) target_sources(SWBWebAssemblyPlatform PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/resource_bundle_accessor.swift") + +set_target_properties(SWBWebAssemblyPlatform PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBWebAssemblyPlatform) + +install(TARGETS SWBWebAssemblyPlatform + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SWBWindowsPlatform/CMakeLists.txt b/Sources/SWBWindowsPlatform/CMakeLists.txt index 79e016d4..8f40d3c5 100644 --- a/Sources/SWBWindowsPlatform/CMakeLists.txt +++ b/Sources/SWBWindowsPlatform/CMakeLists.txt @@ -28,7 +28,7 @@ file(CONFIGURE ]] ESCAPE_QUOTES @ONLY NEWLINE_STYLE LF) -add_library(SWBWindowsPlatform STATIC +add_library(SWBWindowsPlatform KnownFolders.swift Plugin.swift VSInstallation.swift) @@ -38,3 +38,11 @@ target_link_libraries(SWBWindowsPlatform PUBLIC SWBUtil) target_sources(SWBWindowsPlatform PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/resource_bundle_accessor.swift") + +set_target_properties(SWBWindowsPlatform PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SWBWindowsPlatform) + +install(TARGETS SWBWindowsPlatform + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SwiftBuild/CMakeLists.txt b/Sources/SwiftBuild/CMakeLists.txt index 8d1343bc..45970977 100644 --- a/Sources/SwiftBuild/CMakeLists.txt +++ b/Sources/SwiftBuild/CMakeLists.txt @@ -66,3 +66,11 @@ target_link_libraries(SwiftBuild PUBLIC SWBProtocol SWBUtil SWBProjectModel) + +set_target_properties(SwiftBuild PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) + +set_property(GLOBAL APPEND PROPERTY SWIFTBUILD_EXPORTS SwiftBuild) + +install(TARGETS SwiftBuild + ARCHIVE DESTINATION "${SwiftBuild_INSTALL_LIBDIR}") diff --git a/Sources/SwiftBuild/ProjectModel/BuildSettings.swift b/Sources/SwiftBuild/ProjectModel/BuildSettings.swift index 33e50e9f..3d3ff3c4 100644 --- a/Sources/SwiftBuild/ProjectModel/BuildSettings.swift +++ b/Sources/SwiftBuild/ProjectModel/BuildSettings.swift @@ -40,7 +40,7 @@ extension ProjectModel { case GENERATE_INFOPLIST_FILE case GCC_C_LANGUAGE_STANDARD case GCC_OPTIMIZATION_LEVEL - case GENERATE_MASTER_OBJECT_FILE + case GENERATE_PRELINK_OBJECT_FILE case INFOPLIST_FILE case IPHONEOS_DEPLOYMENT_TARGET case KEEP_PRIVATE_EXTERNS diff --git a/Tests/SWBBuildSystemTests/BuildOperationTests.swift b/Tests/SWBBuildSystemTests/BuildOperationTests.swift index 31466ea4..70778e4a 100644 --- a/Tests/SWBBuildSystemTests/BuildOperationTests.swift +++ b/Tests/SWBBuildSystemTests/BuildOperationTests.swift @@ -397,7 +397,7 @@ fileprivate struct BuildOperationTests: CoreBasedTests { } } - @Test(.skipHostOS(.macOS), .skipHostOS(.windows, "cannot find testing library"), .requireThreadSafeWorkingDirectory) + @Test(.requireSDKs(.host), .skipHostOS(.macOS), .skipHostOS(.windows, "cannot find testing library"), .requireThreadSafeWorkingDirectory) func unitTestWithGeneratedEntryPoint() async throws { try await withTemporaryDirectory { (tmpDir: Path) in let testProject = try await TestProject( @@ -453,7 +453,7 @@ fileprivate struct BuildOperationTests: CoreBasedTests { buildPhases: [ TestSourcesBuildPhase(["library.swift"]), ], - ), + ) ]) let core = try await getCore() let tester = try await BuildOperationTester(core, testProject, simulated: false) diff --git a/Tests/SWBBuildSystemTests/ClangCompilationCachingTests.swift b/Tests/SWBBuildSystemTests/ClangCompilationCachingTests.swift index 20192674..e8b436e0 100644 --- a/Tests/SWBBuildSystemTests/ClangCompilationCachingTests.swift +++ b/Tests/SWBBuildSystemTests/ClangCompilationCachingTests.swift @@ -234,7 +234,7 @@ fileprivate struct ClangCompilationCachingTests: CoreBasedTests { // Make sure scanning happens before compilation... results.check(event: .taskHadEvent(scanTask, event: .completed), precedes: .taskHadEvent(compileTask, event: .started)) - results.checkNote("0 hits (0%), 1 miss") + results.checkNote("0 hits / 1 cacheable task (0%)") results.checkCompileCacheMiss(compileTask) results.checkNoDiagnostics() } @@ -262,7 +262,7 @@ fileprivate struct ClangCompilationCachingTests: CoreBasedTests { // Make sure scanning happens before compilation. results.check(event: .taskHadEvent(scanTask, event: .completed), precedes: .taskHadEvent(compileTask, event: .started)) - results.checkNote("1 hit (100%), 0 misses") + results.checkNote("1 hit / 1 cacheable task (100%)") results.checkCompileCacheHit(compileTask) } results.checkNoDiagnostics() diff --git a/Tests/SWBBuildSystemTests/ClangExplicitModulesTests.swift b/Tests/SWBBuildSystemTests/ClangExplicitModulesTests.swift index 95d636b7..70d31af9 100644 --- a/Tests/SWBBuildSystemTests/ClangExplicitModulesTests.swift +++ b/Tests/SWBBuildSystemTests/ClangExplicitModulesTests.swift @@ -2969,9 +2969,9 @@ fileprivate struct ClangExplicitModulesTests: CoreBasedTests { try await tester.checkBuild(runDestination: destination, buildRequest: buildRequest, persistent: true) { results in switch warningLevel { case .yes: - results.checkWarning("'Framework2' is missing a dependency on 'Framework1' because dependency scan of 'file_2.c' discovered a dependency on 'Framework1' (in target 'Framework2' from project 'aProject')") + results.checkWarning("'Framework2' is missing a dependency on 'Framework1' because dependency scan of 'file_2.c' discovered a dependency on 'Framework1'") case .yesError: - results.checkError("'Framework2' is missing a dependency on 'Framework1' because dependency scan of 'file_2.c' discovered a dependency on 'Framework1' (in target 'Framework2' from project 'aProject')") + results.checkError("'Framework2' is missing a dependency on 'Framework1' because dependency scan of 'file_2.c' discovered a dependency on 'Framework1'") default: break } diff --git a/Tests/SWBBuildSystemTests/EntitlementsBuildOperationTests.swift b/Tests/SWBBuildSystemTests/EntitlementsBuildOperationTests.swift index 2f77cc1a..683395e7 100644 --- a/Tests/SWBBuildSystemTests/EntitlementsBuildOperationTests.swift +++ b/Tests/SWBBuildSystemTests/EntitlementsBuildOperationTests.swift @@ -238,24 +238,24 @@ fileprivate struct EntitlementsBuildOperationTests: CoreBasedTests { } } - /// Test that the `ProcessProductEntitlementsTaskAction` does not embed build settings based entitlements that are dependent on App Sandbox being enabled, when App Sandbox is disabled. - @Test(.requireSDKs(.macOS)) - func macOSAppSandboxEnabledEntitlementsWithSandboxDisabled() async throws { + /// Test that the `ProcessProductEntitlementsTaskAction` does not embed build settings that only apply to macOS. + @Test(.requireSDKs(.macOS, .iOS)) + func iOSAppSandboxAndHardenedRuntimeBuildSettingEnabled() async throws { try await withTemporaryDirectory { tmpDirPath async throws -> Void in let testWorkspace = entitlementsTestWorkspace( sourceRoot: tmpDirPath, buildSettings: [ "PRODUCT_NAME": "$(TARGET_NAME)", "INFOPLIST_FILE": "Info.plist", - "CODE_SIGN_IDENTITY": "-", - "RUNTIME_EXCEPTION_ALLOW_DYLD_ENVIRONMENT_VARIABLES": "NO", - "RUNTIME_EXCEPTION_ALLOW_JIT": "NO", - "RUNTIME_EXCEPTION_ALLOW_UNSIGNED_EXECUTABLE_MEMORY": "NO", - "AUTOMATION_APPLE_EVENTS": "NO", - "RUNTIME_EXCEPTION_DEBUGGING_TOOL": "NO", - "RUNTIME_EXCEPTION_DISABLE_EXECUTABLE_PAGE_PROTECTION": "NO", - "RUNTIME_EXCEPTION_DISABLE_LIBRARY_VALIDATION": "NO", - "ENABLE_APP_SANDBOX": "NO", + "AD_HOC_CODE_SIGNING_ALLOWED": "YES", + "RUNTIME_EXCEPTION_ALLOW_DYLD_ENVIRONMENT_VARIABLES": "YES", + "RUNTIME_EXCEPTION_ALLOW_JIT": "YES", + "RUNTIME_EXCEPTION_ALLOW_UNSIGNED_EXECUTABLE_MEMORY": "YES", + "AUTOMATION_APPLE_EVENTS": "YES", + "RUNTIME_EXCEPTION_DEBUGGING_TOOL": "YES", + "RUNTIME_EXCEPTION_DISABLE_EXECUTABLE_PAGE_PROTECTION": "YES", + "RUNTIME_EXCEPTION_DISABLE_LIBRARY_VALIDATION": "YES", + "ENABLE_APP_SANDBOX": "YES", "ENABLE_FILE_ACCESS_DOWNLOADS_FOLDER": "readwrite", "ENABLE_FILE_ACCESS_PICTURE_FOLDER": "readonly", "ENABLE_FILE_ACCESS_MUSIC_FOLDER": "readwrite", @@ -271,7 +271,7 @@ fileprivate struct EntitlementsBuildOperationTests: CoreBasedTests { "ENABLE_RESOURCE_ACCESS_PHOTO_LIBRARY": "YES", "ENABLE_RESOURCE_ACCESS_USB": "YES", "ENABLE_RESOURCE_ACCESS_PRINTING": "YES", - "SDKROOT": "macosx" + "SDKROOT": "iphoneos" ] ) @@ -481,47 +481,6 @@ fileprivate struct EntitlementsBuildOperationTests: CoreBasedTests { } } - /// Test that the `ProcessProductEntitlementsTaskAction` does not embed build settings based entitlements that are dependent on Hardened Runtime being enabled, when Hardened Runtime is disabled. - @Test(.requireSDKs(.macOS)) - func macOSHardenedRuntimeEnabledEntitlementsWithHardenedRuntimeDisabled() async throws { - try await withTemporaryDirectory { tmpDirPath async throws -> Void in - let testWorkspace = entitlementsTestWorkspace( - sourceRoot: tmpDirPath, - buildSettings: [ - "PRODUCT_NAME": "$(TARGET_NAME)", - "INFOPLIST_FILE": "Info.plist", - "CODE_SIGN_IDENTITY": "-", - "ENABLE_HARDENED_RUNTIME": "NO", - "RUNTIME_EXCEPTION_ALLOW_DYLD_ENVIRONMENT_VARIABLES": "YES", - "RUNTIME_EXCEPTION_ALLOW_JIT": "YES", - "RUNTIME_EXCEPTION_ALLOW_UNSIGNED_EXECUTABLE_MEMORY": "YES", - "AUTOMATION_APPLE_EVENTS": "YES", - "RUNTIME_EXCEPTION_DEBUGGING_TOOL": "YES", - "RUNTIME_EXCEPTION_DISABLE_EXECUTABLE_PAGE_PROTECTION": "YES", - "RUNTIME_EXCEPTION_DISABLE_LIBRARY_VALIDATION": "YES", - "ENABLE_FILE_ACCESS_DOWNLOADS_FOLDER": "readwrite", - "ENABLE_FILE_ACCESS_PICTURE_FOLDER": "readonly", - "ENABLE_FILE_ACCESS_MUSIC_FOLDER": "readwrite", - "ENABLE_FILE_ACCESS_MOVIES_FOLDER": "readonly", - "ENABLE_INCOMING_NETWORK_CONNECTIONS": "YES", - "ENABLE_OUTGOING_NETWORK_CONNECTIONS": "YES", - "ENABLE_RESOURCE_ACCESS_AUDIO_INPUT": "YES", - "ENABLE_RESOURCE_ACCESS_BLUETOOTH": "YES", - "ENABLE_RESOURCE_ACCESS_CALENDARS": "YES", - "ENABLE_RESOURCE_ACCESS_CAMERA": "YES", - "ENABLE_RESOURCE_ACCESS_CONTACTS": "YES", - "ENABLE_RESOURCE_ACCESS_LOCATION": "YES", - "ENABLE_RESOURCE_ACCESS_PHOTO_LIBRARY": "YES", - "SDKROOT": "macosx" - ] - ) - - try await buildTestBinaryAndValidateEntitlements(testWorkspace: testWorkspace, expectedEntitlements: [ - "com.apple.application-identifier": "$(AppIdentifierPrefix)$(CFBundleIdentifier)", - ]) - } - } - @Test(.requireSDKs(.iOS)) func simulatorEntitlementsSections() async throws { try await withTemporaryDirectory { tmpDirPath in diff --git a/Tests/SWBBuildSystemTests/HostBuildToolBuildOperationTests.swift b/Tests/SWBBuildSystemTests/HostBuildToolBuildOperationTests.swift index e872af3f..1e4748d3 100644 --- a/Tests/SWBBuildSystemTests/HostBuildToolBuildOperationTests.swift +++ b/Tests/SWBBuildSystemTests/HostBuildToolBuildOperationTests.swift @@ -439,6 +439,181 @@ fileprivate struct HostBuildToolBuildOperationTests: CoreBasedTests { } } + @Test(.requireSDKs(.macOS)) + func testHostToolsAndDependenciesAreBuiltDuringIndexingPreparationForPackage() async throws { + try await withTemporaryDirectory { tmpDirPath async throws -> Void in + let depPackage = try await TestPackageProject( + "DepPackage", + groupTree: TestGroup("Foo", children: [ + TestFile("transitivedep.swift"), + TestFile("dep.swift"), + ]), + buildConfigurations: [ + TestBuildConfiguration( + "Debug", + buildSettings: [ + "SWIFT_VERSION": swiftVersion, + "GENERATE_INFOPLIST_FILE": "YES", + "PRODUCT_NAME": "$(TARGET_NAME)", + "CODE_SIGNING_ALLOWED": "NO", + ]), + ], + targets: [ + TestStandardTarget("TransitivePackageDep", type: .objectFile, buildConfigurations: [ + TestBuildConfiguration( + "Debug", + buildSettings: [ + "SDKROOT": "auto", + "SUPPORTED_PLATFORMS": "macosx iphoneos iphonesimulator", + ], + impartedBuildProperties: + TestImpartedBuildProperties( + buildSettings: [ + "SWIFT_ACTIVE_COMPILATION_CONDITIONS": "IMPARTED_SETTINGS" + ]) + ), + ], buildPhases: [ + TestSourcesBuildPhase(["transitivedep.swift"]) + ]), + TestStandardTarget("PackageDep", type: .staticLibrary, buildConfigurations: [ + TestBuildConfiguration( + "Debug", + buildSettings: [ + "SDKROOT": "auto", + "SUPPORTED_PLATFORMS": "macosx iphoneos iphonesimulator", + ]), + ], buildPhases: [ + TestSourcesBuildPhase(["dep.swift"]), + TestFrameworksBuildPhase([ + TestBuildFile(.target("TransitivePackageDep")) + ]) + ], dependencies: [ + "TransitivePackageDep" + ]), + TestPackageProductTarget("PackageDepProduct", frameworksBuildPhase: + TestFrameworksBuildPhase([ + TestBuildFile(.target("PackageDep")), + ] + ), buildConfigurations: [ + TestBuildConfiguration( + "Debug", + buildSettings: [ + "SDKROOT": "auto", + "SUPPORTED_PLATFORMS": "macosx iphoneos iphonesimulator", + ]), + ], dependencies: [ + "PackageDep" + ]), + ]) + + let hostToolsPackage = try await TestPackageProject( + "HostToolsPackage", + groupTree: TestGroup("Foo", children: [ + TestFile("tool.swift"), + TestFile("lib.swift"), + ]), + buildConfigurations: [ + TestBuildConfiguration( + "Debug", + buildSettings: [ + "SWIFT_VERSION": swiftVersion, + "GENERATE_INFOPLIST_FILE": "YES", + "PRODUCT_NAME": "$(TARGET_NAME)", + "CODE_SIGNING_ALLOWED": "NO", + ]), + ], + targets: [ + TestStandardTarget("HostTool", type: .hostBuildTool, buildConfigurations: [ + TestBuildConfiguration( + "Debug", + buildSettings: [ + "SDKROOT": "auto", + ]) + ], buildPhases: [ + TestSourcesBuildPhase(["tool.swift"]), + TestFrameworksBuildPhase([TestBuildFile(.target("PackageDepProduct"))]) + ], dependencies: [ + "PackageDepProduct" + ]), + TestStandardTarget("HostToolClientLib", type: .objectFile, buildConfigurations: [ + TestBuildConfiguration( + "Debug", + buildSettings: [ + "SDKROOT": "auto", + "SUPPORTED_PLATFORMS": "macosx iphoneos iphonesimulator", + ]), + ], buildPhases: [ + TestSourcesBuildPhase(["lib.swift"]), + ], dependencies: [ + "HostTool" + ]), + TestPackageProductTarget("HostToolClientLibProduct", frameworksBuildPhase: + TestFrameworksBuildPhase([TestBuildFile(.target("HostToolClientLib"))] + ), buildConfigurations: [ + TestBuildConfiguration( + "Debug", + buildSettings: [ + "SDKROOT": "auto", + "SUPPORTED_PLATFORMS": "macosx iphoneos iphonesimulator", + ]), + ], dependencies: [ + "HostToolClientLib" + ]), + ]) + + let testWorkspace = TestWorkspace("aWorkspace", sourceRoot: tmpDirPath.join("Test"), projects: [depPackage, hostToolsPackage]) + let tester = try await BuildOperationTester(getCore(), testWorkspace, simulated: false, systemInfo: .init(operatingSystemVersion: Version(99, 98, 97), productBuildVersion: "99A98", nativeArchitecture: Architecture.host.stringValue ?? "undefined_arch")) + + try await tester.fs.writeFileContents(testWorkspace.sourceRoot.join("DepPackage/transitivedep.swift")) { stream in + stream <<< + """ + public let transitiveDependencyMessage = "Hello from host tool transitive dependency!" + """ + } + + try await tester.fs.writeFileContents(testWorkspace.sourceRoot.join("DepPackage/dep.swift")) { stream in + stream <<< + """ + import TransitivePackageDep + + public let dependencyMessage = "Hello from host tool dependency! " + transitiveDependencyMessage + #if !IMPARTED_SETTINGS + #error("settings not imparted") + #endif + """ + } + + try await tester.fs.writeFileContents(testWorkspace.sourceRoot.join("HostToolsPackage/tool.swift")) { stream in + stream <<< + """ + import PackageDep + + @main struct Foo { + static func main() { + print("Hello from host tool! " + dependencyMessage) + } + } + """ + } + + try await tester.fs.writeFileContents(testWorkspace.sourceRoot.join("HostToolsPackage/lib.swift")) { stream in + stream <<< + """ + public class MyClass {} + """ + } + + try await tester.checkIndexBuild(prepareTargets: hostToolsPackage.targets.map(\.guid), workspaceOperation: false, runDestination: .anyMac, persistent: true) { results in + results.checkNoDiagnostics() + + results.checkTaskExists(.matchTargetName("HostTool"), .matchRuleType("Ld")) + try results.checkTask(.matchTargetName("HostTool"), .matchRuleType(ProductPlan.preparedForIndexPreCompilationRuleName)) { task in + try results.checkTaskFollows(task, .matchTargetName("PackageDep"), .matchRuleType("Libtool")) + } + } + } + } + @Test(.requireSDKs(.macOS)) func hostToolsAreSkippedDuringIndexingPreparationWhenUnapproved() async throws { try await withTemporaryDirectory { tmpDirPath async throws -> Void in diff --git a/Tests/SWBBuildSystemTests/PreviewsBuildOperationTests.swift b/Tests/SWBBuildSystemTests/PreviewsBuildOperationTests.swift index 7df199bf..0911fb0c 100644 --- a/Tests/SWBBuildSystemTests/PreviewsBuildOperationTests.swift +++ b/Tests/SWBBuildSystemTests/PreviewsBuildOperationTests.swift @@ -831,6 +831,7 @@ fileprivate struct PreviewsBuildOperationTests: CoreBasedTests { "ENABLE_PREVIEWS": "YES", "CLANG_ENABLE_MODULES": "YES", "SDK_STAT_CACHE_ENABLE": "NO", + "SWIFT_DISABLE_INCREMENTAL_SCAN": "YES", "SWIFT_ENABLE_EXPLICIT_MODULES": explicitModules ? "YES" : "NO", diff --git a/Tests/SWBBuildSystemTests/SwiftCompilationCachingTests.swift b/Tests/SWBBuildSystemTests/SwiftCompilationCachingTests.swift index 4a82aacd..c01277a9 100644 --- a/Tests/SWBBuildSystemTests/SwiftCompilationCachingTests.swift +++ b/Tests/SWBBuildSystemTests/SwiftCompilationCachingTests.swift @@ -110,7 +110,7 @@ fileprivate struct SwiftCompilationCachingTests: CoreBasedTests { numCompile += tasks.count } - results.checkNote("0 hits (0%), 4 misses") + results.checkNote("0 hits / 4 cacheable tasks (0%)") results.checkNoTask() } @@ -126,7 +126,7 @@ fileprivate struct SwiftCompilationCachingTests: CoreBasedTests { results.checkKeyQueryCacheHit(task) } - results.checkNote("4 hits (100%), 0 misses") + results.checkNote("4 hits / 4 cacheable tasks (100%)") } #expect(try readMetrics("two").contains("\"swiftCacheHits\":\(numCompile),\"swiftCacheMisses\":0")) } diff --git a/Tests/SWBBuildSystemTests/SwiftDriverTests.swift b/Tests/SWBBuildSystemTests/SwiftDriverTests.swift index ed5d3f05..8b79d853 100644 --- a/Tests/SWBBuildSystemTests/SwiftDriverTests.swift +++ b/Tests/SWBBuildSystemTests/SwiftDriverTests.swift @@ -3616,6 +3616,7 @@ fileprivate struct SwiftDriverTests: CoreBasedTests { "ENABLE_PREVIEWS": "YES", "SWIFT_USE_INTEGRATED_DRIVER": useIntegratedDriver ? "YES" : "NO", "SWIFT_ENABLE_EXPLICIT_MODULES": useIntegratedDriver ? "YES" : "NO", + "SWIFT_DISABLE_INCREMENTAL_SCAN": "YES", "_EXPERIMENTAL_SWIFT_EXPLICIT_MODULES": useIntegratedDriver ? "YES" : "NO", // Eager linking is not supported when using the driver binary. "EAGER_LINKING": "NO", @@ -4597,11 +4598,11 @@ fileprivate struct SwiftDriverTests: CoreBasedTests { try await tester.checkBuild(runDestination: .macOS, buildRequest: buildRequest, persistent: true) { results in switch warningLevel { case .yes: - results.checkWarning("'Framework3' is missing a dependency on 'Framework1' because dependency scan of Swift module 'Framework3' discovered a dependency on 'Framework1' (in target 'Framework3' from project 'aProject')") - results.checkWarning("'Framework3' is missing a dependency on 'Framework2' because dependency scan of Swift module 'Framework3' discovered a dependency on 'Framework2' (in target 'Framework3' from project 'aProject')") + results.checkWarning("'Framework3' is missing a dependency on 'Framework1' because dependency scan of Swift module 'Framework3' discovered a dependency on 'Framework1'") + results.checkWarning("'Framework3' is missing a dependency on 'Framework2' because dependency scan of Swift module 'Framework3' discovered a dependency on 'Framework2'") case .yesError: - results.checkError("'Framework3' is missing a dependency on 'Framework1' because dependency scan of Swift module 'Framework3' discovered a dependency on 'Framework1' (in target 'Framework3' from project 'aProject')") - results.checkError("'Framework3' is missing a dependency on 'Framework2' because dependency scan of Swift module 'Framework3' discovered a dependency on 'Framework2' (in target 'Framework3' from project 'aProject')") + results.checkError("'Framework3' is missing a dependency on 'Framework1' because dependency scan of Swift module 'Framework3' discovered a dependency on 'Framework1'") + results.checkError("'Framework3' is missing a dependency on 'Framework2' because dependency scan of Swift module 'Framework3' discovered a dependency on 'Framework2'") default: break } diff --git a/Tests/SWBCoreTests/IndexSelectConfiguredTargetTests.swift b/Tests/SWBCoreTests/IndexSelectConfiguredTargetTests.swift index 7484e43f..99951832 100644 --- a/Tests/SWBCoreTests/IndexSelectConfiguredTargetTests.swift +++ b/Tests/SWBCoreTests/IndexSelectConfiguredTargetTests.swift @@ -58,7 +58,7 @@ import SWBUtil ])]) let tester = try await BuildOperationTester(core, workspace, simulated: false) - try await tester.checkIndexBuildGraph(targets: [appTarget]) { results in + try await tester.checkIndexBuildGraph(targets: [appTarget], workspaceOperation: true) { results in try results.checkSelectedPlatform(of: appTarget, "macos", "iphoneos", .macOS, expectedPlatform: "macos") try results.checkSelectedPlatform(of: appTarget, "iosmac", "macos", .macOS, expectedPlatform: "macos") try results.checkSelectedPlatform(of: appTarget, "macos", "iosmac", .watchOS, expectedPlatform: "macos") diff --git a/Tests/SWBCoreTests/IndexTargetDependencyResolverTests.swift b/Tests/SWBCoreTests/IndexTargetDependencyResolverTests.swift index 40756fd9..c787f3f7 100644 --- a/Tests/SWBCoreTests/IndexTargetDependencyResolverTests.swift +++ b/Tests/SWBCoreTests/IndexTargetDependencyResolverTests.swift @@ -134,7 +134,7 @@ import SWBUtil ])]) let tester = try await BuildOperationTester(core, workspace, simulated: false) - try await tester.checkIndexBuildGraph(targets: [macApp, macApp2, iosApp, iosApp2, fwkTarget_mac, fwkTarget_ios]) { results in + try await tester.checkIndexBuildGraph(targets: [macApp, macApp2, iosApp, iosApp2, fwkTarget_mac, fwkTarget_ios], workspaceOperation: true) { results in #expect(results.targets().map { results.targetNameAndPlatform($0) } == [ "FwkTarget_mac-macos", "macApp-macos", "macApp2-macos", "FwkTarget_ios-iphoneos", "iosApp-iphoneos", "FwkTarget_ios-iphonesimulator", "iosApp-iphonesimulator", "iosApp2-iphoneos", "iosApp2-iphonesimulator", @@ -260,7 +260,7 @@ import SWBUtil ])]) let tester = try await BuildOperationTester(core, workspace, simulated: false) - try await tester.checkIndexBuildGraph(targets: [macApp, iosApp, watchKitApp, watchKitExt]) { results in + try await tester.checkIndexBuildGraph(targets: [macApp, iosApp, watchKitApp, watchKitExt], workspaceOperation: true) { results in #expect(results.targets().map { results.targetNameAndPlatform($0) } == [ "macApp-macos", "iosApp-iphoneos", "iosApp-iphonesimulator", "Watchable WatchKit Extension-watchos", "Watchable WatchKit App-watchos", "Watchable WatchKit Extension-watchsimulator", "Watchable WatchKit App-watchsimulator", @@ -364,7 +364,7 @@ import SWBUtil ])]) let tester = try await BuildOperationTester(core, workspace, simulated: false) - try await tester.checkIndexBuildGraph(targets: [iosApp, watchApp, hostTool, hostToolDep]) { results in + try await tester.checkIndexBuildGraph(targets: [iosApp, watchApp, hostTool, hostToolDep], workspaceOperation: true) { results in #expect(results.targets().map { results.targetNameAndPlatform($0) } == [ "hostToolDep-macos", "hostTool-macos", "iosApp-iphoneos", "iosApp-iphonesimulator", @@ -452,7 +452,7 @@ import SWBUtil ])]) let tester = try await BuildOperationTester(core, workspace, simulated: false) - try await tester.checkIndexBuildGraph(targets: [iosApp, hostTool, commonDep]) { results in + try await tester.checkIndexBuildGraph(targets: [iosApp, hostTool, commonDep], workspaceOperation: true) { results in #expect(results.targets().map { results.targetNameAndPlatform($0) } == [ "commonDep-macos", "hostTool-macos", "commonDep-iphoneos", "iosApp-iphoneos", "commonDep-iphonesimulator", "iosApp-iphonesimulator", "commonDep-iosmac" ]) @@ -573,7 +573,7 @@ import SWBUtil var iosApp2_iosConfTarget: ConfiguredTarget! let tester = try await BuildOperationTester(core, workspace, simulated: false) - try await tester.checkIndexBuildGraph(targets: targetsToCheck) { results in + try await tester.checkIndexBuildGraph(targets: targetsToCheck, workspaceOperation: true) { results in #expect(results.targets().map { results.targetNameAndPlatform($0) } == [ "macApp2-macos", "Aggregate-macos", @@ -593,7 +593,7 @@ import SWBUtil } // Same request but with reversed order of top-level targets. Make sure the graph is same. - try await tester.checkIndexBuildGraph(targets: targetsToCheck.reversed()) { results in + try await tester.checkIndexBuildGraph(targets: targetsToCheck.reversed(), workspaceOperation: true) { results in #expect(results.targets().map { results.targetNameAndPlatform($0) } == [ "iosApp2-iphoneos", "iosApp2-iphonesimulator", @@ -608,11 +608,11 @@ import SWBUtil try checkDependencies(results) } - try await tester.checkIndexBuildGraph(targets: [macApp]) { results throws in + try await tester.checkIndexBuildGraph(targets: [macApp], workspaceOperation: true) { results throws in #expect(try results.target(.init(macApp2, "macos")).guid == macApp2_macosConfTarget.guid) } - try await tester.checkIndexBuildGraph(targets: [iosApp]) { results throws in + try await tester.checkIndexBuildGraph(targets: [iosApp], workspaceOperation: true) { results throws in #expect(try results.target(.init(iosApp2, "iphoneos")).guid == iosApp2_iosConfTarget.guid) } } @@ -755,7 +755,7 @@ import SWBUtil ])]) let tester = try await BuildOperationTester(core, workspace, simulated: false) - try await tester.checkIndexBuildGraph(targets: [catalystAppTarget1, catalystAppTarget2, catalystAppTarget3, osxAppTarget, osxAppTarget_iosmac, fwkTarget, fwkTarget_osx]) { results in + try await tester.checkIndexBuildGraph(targets: [catalystAppTarget1, catalystAppTarget2, catalystAppTarget3, osxAppTarget, osxAppTarget_iosmac, fwkTarget, fwkTarget_osx], workspaceOperation: true) { results in #expect(results.targets().map { results.targetNameAndPlatform($0) } == [ "FwkTarget-iphoneos", "catalystApp1-iphoneos", "FwkTarget-iphonesimulator", "catalystApp1-iphonesimulator", "FwkTarget-iosmac", "catalystApp1-iosmac", "catalystApp2-iphoneos", "catalystApp2-iphonesimulator", "catalystApp2-iosmac", "catalystApp3-iphoneos", "catalystApp3-iphonesimulator", "catalystApp3-iosmac", "FwkTarget_osx-macos", "catalystApp3-macos", "osxApp-macos", "osxApp_iosmac-iosmac", "FwkTarget_osx-iosmac", ]) @@ -912,7 +912,7 @@ import SWBUtil ]), package]) let tester = try await BuildOperationTester(core, workspace, simulated: false) - try await tester.checkIndexBuildGraph(targets: [macAppTarget, iosAppTarget]) { results in + try await tester.checkIndexBuildGraph(targets: [macAppTarget, iosAppTarget], workspaceOperation: true) { results in #expect(results.targets(macAppTarget).map { results.targetNameAndPlatform($0) } == [ "macAppTarget-macos", ]) @@ -993,7 +993,7 @@ import SWBUtil ])]) let tester = try await BuildOperationTester(core, workspace, simulated: false) - try await tester.checkIndexBuildGraph(targets: [iosApp]) { results in + try await tester.checkIndexBuildGraph(targets: [iosApp], workspaceOperation: true) { results in #expect(results.targets().map { results.targetNameAndPlatform($0) } == [ "iosApp-iphoneos", "iosApp-iphonesimulator", ]) @@ -1048,7 +1048,7 @@ import SWBUtil func checkTargetArch(_ arch: String, expected: [String: String], sourceLocation: SourceLocation = #_sourceLocation) async throws { let tester = try await BuildOperationTester(core, workspace, simulated: false) tester.systemInfo = SystemInfo(operatingSystemVersion: Version(99, 98, 97), productBuildVersion: "99A98", nativeArchitecture: arch) - try await tester.checkIndexBuildGraph(targets: [macosApp, iosApp, driver]) { results in + try await tester.checkIndexBuildGraph(targets: [macosApp, iosApp, driver], workspaceOperation: true) { results in var actual: [String: String] = [:] for target in results.targets() { actual[target.nameAndPlatform] = target.parameters.activeArchitecture diff --git a/Tests/SWBCoreTests/ProductTypesTests.swift b/Tests/SWBCoreTests/ProductTypesTests.swift index 3baeb0ef..5bc412bb 100644 --- a/Tests/SWBCoreTests/ProductTypesTests.swift +++ b/Tests/SWBCoreTests/ProductTypesTests.swift @@ -1,9 +1,14 @@ +//===----------------------------------------------------------------------===// // -// ProductTypesTests.swift -// SWBCoreTests +// This source file is part of the Swift open source project // -// Copyright © 2024 Apple Inc. All rights reserved. +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception // +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// import Testing diff --git a/Tests/SWBLLBuildTests/LLBuildTests.swift b/Tests/SWBLLBuildTests/LLBuildTests.swift index 19d3186f..6f50c9d7 100644 --- a/Tests/SWBLLBuildTests/LLBuildTests.swift +++ b/Tests/SWBLLBuildTests/LLBuildTests.swift @@ -17,137 +17,154 @@ import SWBUtil import struct SWBLLBuild.Diagnostic import Foundation +import Synchronization fileprivate class LoggingDelegate: BuildSystemDelegate { - let queue = SWBQueue(label: "LLBuildTests.LoggingDelegate.queue", qos: UserDefaults.defaultRequestQoS) var buildSystem: BuildSystem? = nil let fs: (any SWBLLBuild.FileSystem)? let fsProxy: any FSProxy - var log: [String] = [] - var errors: [String] = [] + private struct Output: Sendable { + var log: [String] = [] + var errors: [String] = [] + } + private let output = SWBMutex(.init()) let ignoreStatusChanges: Bool + var log: [String] { + output.withLock { $0.log } + } + + var errors: [String] { + output.withLock { $0.errors } + } + init(fs: any FSProxy, ignoreStatusChanges: Bool = false) { self.fs = SWBLLBuild.FileSystemImpl(fs) self.fsProxy = fs self.ignoreStatusChanges = ignoreStatusChanges } + func append(log: String) { + output.withLock { output in + output.log.append(log) + } + } + func lookupTool(_ name: String) -> (any Tool)? { return nil } func hadCommandFailure() { - queue.blocking_sync { - self.log.append("had-command-failure") + output.withLock { output in + output.log.append("had-command-failure") } buildSystem?.cancel() } func handleDiagnostic(_ diagnostic: Diagnostic) { - queue.blocking_sync { - self.log.append("\(diagnostic.kind): \(diagnostic.message)") - self.errors.append("\(diagnostic.kind): \(diagnostic.message)") + output.withLock { output in + output.log.append("\(diagnostic.kind): \(diagnostic.message)") + output.errors.append("\(diagnostic.kind): \(diagnostic.message)") } } func commandStatusChanged(_ command: Command, kind: CommandStatusKind) { if !ignoreStatusChanges { - queue.blocking_sync { - self.log.append("command-status-changed: \(command.name), to: \(kind)") + output.withLock { output in + output.log.append("command-status-changed: \(command.name), to: \(kind)") } } } func commandPreparing(_ command: Command) { - queue.blocking_sync { - self.log.append("command-preparing: \(command.name)") + output.withLock { output in + output.log.append("command-preparing: \(command.name)") } } func commandStarted(_ command: Command) { - queue.blocking_sync { - self.log.append("command-started: \(command.name)") + output.withLock { output in + output.log.append("command-started: \(command.name)") } } func shouldCommandStart(_ command: Command) -> Bool { - queue.blocking_sync { - self.log.append("should-command-start: \(command.name)") + output.withLock { output in + output.log.append("should-command-start: \(command.name)") } return true } func commandFinished(_ command: Command, result: CommandResult) { - queue.blocking_sync { - self.log.append("command-finished: \(command.name)") + output.withLock { output in + output.log.append("command-finished: \(command.name)") } } func commandFoundDiscoveredDependency(_ command: Command, path: String, kind: DiscoveredDependencyKind) { - queue.blocking_sync { - self.log.append("command-found-discovered-dependency: \(path) \(kind)") + output.withLock { output in + output.log.append("command-found-discovered-dependency: \(path) \(kind)") } } func commandHadError(_ command: Command, message: String) { - queue.blocking_sync { - self.log.append("command-had-error: \(command.name): \(message)") - self.errors.append("command-had-error: \(command.name): \(message)") + output.withLock { output in + output.log.append("command-had-error: \(command.name): \(message)") + output.errors.append("command-had-error: \(command.name): \(message)") } } func commandHadNote(_ command: Command, message: String) { - queue.blocking_sync { - self.log.append("command-had-note: \(command.name): \(message)") + output.withLock { output in + output.log.append("command-had-note: \(command.name): \(message)") } } func commandHadWarning(_ command: Command, message: String) { - queue.blocking_sync { - self.log.append("command-had-warning: \(command.name): \(message)") + output.withLock { output in + output.log.append("command-had-warning: \(command.name): \(message)") } } func commandProcessStarted(_ command: Command, process: ProcessHandle) { - queue.blocking_sync { - self.log.append("command-process-started: \(command.name) -- \(command.description)") + output.withLock { output in + output.log.append("command-process-started: \(command.name) -- \(command.description)") } } func commandProcessHadError(_ command: Command, process: ProcessHandle, message: String) { - queue.blocking_sync { - self.log.append("command-process-error: \(message)") + output.withLock { output in + output.log.append("command-process-error: \(message)") } } func commandProcessHadOutput(_ command: Command, process: ProcessHandle, data: [UInt8]) { - queue.blocking_sync { - self.log.append("command-process-output: \(command.name): \(ByteString(data).bytes.asReadableString().debugDescription)") + output.withLock { output in + output.log.append("command-process-output: \(command.name): \(ByteString(data).bytes.asReadableString().debugDescription)") } } func commandProcessFinished(_ command: Command, process: ProcessHandle, result: CommandExtendedResult) { - queue.blocking_sync { - self.log.append("command-process-finished: \(command.name)") + output.withLock { output in + output.log.append("command-process-finished: \(command.name)") } } func determinedRuleNeedsToRun(_ rule: BuildKey, reason: RuleRunReason, inputRule: BuildKey?) { - queue.blocking_sync { - self.log.append("determined-rule-needs-to-run: \(rule.description)") + output.withLock { output in + output.log.append("determined-rule-needs-to-run: \(rule.description)") } } func cycleDetected(rules: [BuildKey]) { - queue.blocking_sync { - self.log.append("cycle-detected: \(rules.map{ $0.key })") + output.withLock { output in + output.log.append("cycle-detected: \(rules.map{ $0.key })") } } func commandCannotBuildOutputDueToMissingInputs(_ command: Command, output: BuildKey, inputs: [BuildKey]) { - queue.blocking_sync { + self.output.withLock { outputBox in let msg = "commandCannotBuildOutputDueToMissingInputs: \(command.name) \(output.key) \(inputs.map { $0.key })" - self.log.append(msg) - self.errors.append(msg) + outputBox.log.append(msg) + outputBox.errors.append(msg) } } func cannotBuildNodeDueToMultipleProducers(output: BuildKey, commands: [Command]) { - queue.blocking_sync { + self.output.withLock { outputBox in let msg = "cannotBuildNodeDueToMultipleProducers: \(output.key) \(commands.map { $0.name })" - self.log.append(msg) - self.errors.append(msg) + outputBox.log.append(msg) + outputBox.errors.append(msg) } } func shouldResolveCycle(rules: [BuildKey], candidate: BuildKey, action: CycleAction) -> Bool { - queue.blocking_sync { - self.log.append("should-resolve-cycle: \(rules.map{ $0.key })") + output.withLock { output in + output.log.append("should-resolve-cycle: \(rules.map{ $0.key })") } return false; } @@ -521,7 +538,7 @@ fileprivate class LoggingDelegate: BuildSystemDelegate { } func execute(_ command: Command, _ commandInterface: BuildSystemCommandInterface) -> Bool { - delegate.log.append("write-command: execute") + delegate.append(log: "write-command: execute") do { try delegate.fsProxy.write(Static.outputPath, contents: []) return true diff --git a/Tests/SWBTaskConstructionTests/IndexBuildTaskConstructionTests.swift b/Tests/SWBTaskConstructionTests/IndexBuildTaskConstructionTests.swift index c5a7234f..fd95be85 100644 --- a/Tests/SWBTaskConstructionTests/IndexBuildTaskConstructionTests.swift +++ b/Tests/SWBTaskConstructionTests/IndexBuildTaskConstructionTests.swift @@ -366,7 +366,7 @@ fileprivate struct IndexBuildTaskConstructionTests: CoreBasedTests { results.checkNoDiagnostics() } - try await tester.checkIndexBuild(targets: [fwkTarget1]) { results in + try await tester.checkIndexBuild(targets: [fwkTarget1], workspaceOperation: true) { results in results.checkWriteAuxiliaryFileTask(.matchRulePattern(["WriteAuxiliaryFile", .suffix("VFS-iphonesimulator/all-product-headers.yaml")])) { task, contents in #expect(contents == vfs_sim) } diff --git a/Tests/SWBTaskConstructionTests/MasterObjectFileTests.swift b/Tests/SWBTaskConstructionTests/PrelinkedObjectFileTests.swift similarity index 90% rename from Tests/SWBTaskConstructionTests/MasterObjectFileTests.swift rename to Tests/SWBTaskConstructionTests/PrelinkedObjectFileTests.swift index dea36b88..3c805622 100644 --- a/Tests/SWBTaskConstructionTests/MasterObjectFileTests.swift +++ b/Tests/SWBTaskConstructionTests/PrelinkedObjectFileTests.swift @@ -18,10 +18,10 @@ import SWBUtil import SWBProtocol @Suite -fileprivate struct MasterObjectFileTests: CoreBasedTests { - // Test interesting permutations of generating a master object file. +fileprivate struct PrelinkedObjectFileTests: CoreBasedTests { + // Test interesting permutations of generating a prelinked object file. @Test(.requireSDKs(.macOS)) - func masterObjectFileGeneration() async throws { + func prelinkedObjectFileGeneration() async throws { let core = try await getCore() let testProject = TestProject( "aProject", @@ -46,7 +46,7 @@ fileprivate struct MasterObjectFileTests: CoreBasedTests { TestBuildConfiguration( "Debug", buildSettings: [ - "GENERATE_MASTER_OBJECT_FILE": "YES", + "GENERATE_PRELINK_OBJECT_FILE": "YES", "WARNING_LDFLAGS": "-lWarningLibrary", "PRELINK_LIBS": "-lSomeLibrary -lAnotherLibrary", "PRELINK_FLAGS": "-exported_symbols_list Exports.exp", @@ -71,9 +71,9 @@ fileprivate struct MasterObjectFileTests: CoreBasedTests { results.checkTasks(.matchRuleType("RegisterExecutionPolicyException")) { _ in } results.checkTarget("AllLibraries") { target in - // There should be tasks to create the master object file and then the static library. - results.checkTask(.matchTarget(target), .matchRuleType("MasterObjectLink")) { task in - task.checkCommandLineMatches([.suffix("ld"), "-r", "-arch", "x86_64", "-syslibroot", .equal(core.loadSDK(.macOS).path.str), "-exported_symbols_list", "Exports.exp", "-lWarningLibrary", "-lSomeLibrary", "-lAnotherLibrary", "-o", .equal("\(SRCROOT)/build/aProject.build/Debug/AllLibraries.build/Objects-normal/libAllLibraries.a-x86_64-master.o")]) + // There should be tasks to create the prelinked object file and then the static library. + results.checkTask(.matchTarget(target), .matchRuleType("PrelinkedObjectLink")) { task in + task.checkCommandLineMatches([.suffix("ld"), "-r", "-arch", "x86_64", "-syslibroot", .equal(core.loadSDK(.macOS).path.str), "-exported_symbols_list", "Exports.exp", "-lWarningLibrary", "-lSomeLibrary", "-lAnotherLibrary", "-o", .equal("\(SRCROOT)/build/aProject.build/Debug/AllLibraries.build/Objects-normal/libAllLibraries.a-x86_64-prelink.o")]) } results.checkTask(.matchTarget(target), .matchRuleType("Libtool")) { task in task.checkCommandLineMatches([.suffix("libtool"), "-static", "-arch_only", "x86_64", "-D", "-syslibroot", .equal(core.loadSDK(.macOS).path.str), .equal("-L\(SRCROOT)/build/Debug"), "-filelist", .equal("\(SRCROOT)/build/aProject.build/Debug/AllLibraries.build/Objects-normal/x86_64/AllLibraries.LinkFileList"), "-dependency_info", "\(SRCROOT)/build/aProject.build/Debug/AllLibraries.build/Objects-normal/x86_64/AllLibraries_libtool_dependency_info.dat", "-o", .equal("\(SRCROOT)/build/Debug/libAllLibraries.a")]) @@ -100,9 +100,9 @@ fileprivate struct MasterObjectFileTests: CoreBasedTests { results.checkTasks(.matchRuleType("RegisterExecutionPolicyException")) { _ in } results.checkTarget("AllLibraries") { target in - // There should be tasks to create the master object file and then the static library. - results.checkTask(.matchTarget(target), .matchRuleType("MasterObjectLink")) { task in - task.checkCommandLineMatches([.suffix("ld"), "-r", "-arch", "x86_64", "-syslibroot", .equal(core.loadSDK(.macOS).path.str), "-exported_symbols_list", "Exports.exp", "-lWarningLibrary", "-lSomeLibrary", "-lAnotherLibrary", "-o", .equal("\(SRCROOT)/build/aProject.build/Debug/AllLibraries.build/Objects-normal/libAllLibraries.a-x86_64-master.o")]) + // There should be tasks to create the prelinked object file and then the static library. + results.checkTask(.matchTarget(target), .matchRuleType("PrelinkedObjectLink")) { task in + task.checkCommandLineMatches([.suffix("ld"), "-r", "-arch", "x86_64", "-syslibroot", .equal(core.loadSDK(.macOS).path.str), "-exported_symbols_list", "Exports.exp", "-lWarningLibrary", "-lSomeLibrary", "-lAnotherLibrary", "-o", .equal("\(SRCROOT)/build/aProject.build/Debug/AllLibraries.build/Objects-normal/libAllLibraries.a-x86_64-prelink.o")]) } results.checkTask(.matchTarget(target), .matchRuleType("Libtool")) { task in task.checkCommandLineMatches([.suffix("libtool"), "-static", "-arch_only", "x86_64", "-D", "-syslibroot", .equal(core.loadSDK(.macOS).path.str), .equal("-L\(SRCROOT)/build/Debug/BuiltProducts"), "-filelist", .equal("\(SRCROOT)/build/aProject.build/Debug/AllLibraries.build/Objects-normal/x86_64/AllLibraries.LinkFileList"), "-dependency_info", "\(SRCROOT)/build/aProject.build/Debug/AllLibraries.build/Objects-normal/x86_64/AllLibraries_libtool_dependency_info.dat", "-o", "/tmp/aProject.dst/usr/local/lib/libAllLibraries.a"]) @@ -137,8 +137,8 @@ fileprivate struct MasterObjectFileTests: CoreBasedTests { results.checkTasks(.matchRuleType("CreateBuildDirectory")) { _ in } results.checkTarget("AllLibraries") { target in - // There should be tasks to create the master object file and then the static library. - results.checkNoTask(.matchTarget(target), .matchRuleType("MasterObjectLink")) + // There should be tasks to create the prelinked object file and then the static library. + results.checkNoTask(.matchTarget(target), .matchRuleType("PrelinkedObjectLink")) } // There should be no other tasks. @@ -153,9 +153,9 @@ fileprivate struct MasterObjectFileTests: CoreBasedTests { } @Test(.requireSDKs(.macOS, .iOS)) - func masterObjectFileGenerationVariant_macCatalyst() async throws { + func prelinkedObjectFileGenerationVariant_macCatalyst() async throws { let core = try await getCore() - // Test that a master object file gets generated even if the target contains no sources or libraries in its build phases. + // Test that a prelinked object file gets generated even if the target contains no sources or libraries in its build phases. let testProject = TestProject( "aProject", groupTree: TestGroup( @@ -179,7 +179,7 @@ fileprivate struct MasterObjectFileTests: CoreBasedTests { TestBuildConfiguration( "Debug", buildSettings: [ - "GENERATE_MASTER_OBJECT_FILE": "YES", + "GENERATE_PRELINK_OBJECT_FILE": "YES", ]), ], buildPhases: [ @@ -201,9 +201,9 @@ fileprivate struct MasterObjectFileTests: CoreBasedTests { results.checkTasks(.matchRuleType("RegisterExecutionPolicyException")) { _ in } results.checkTarget("AllLibraries") { target in - // There should be tasks to create the master object file and then the static library. - results.checkTask(.matchTarget(target), .matchRuleType("MasterObjectLink")) { task in - task.checkCommandLineMatches([.suffix("ld"), "-r", "-arch", "x86_64", "-syslibroot", .equal(core.loadSDK(.macOS).path.str), "-o", .equal("\(SRCROOT)/build/aProject.build/Debug-maccatalyst/AllLibraries.build/Objects-normal/libAllLibraries.a-x86_64-master.o")]) + // There should be tasks to create the prelinked object file and then the static library. + results.checkTask(.matchTarget(target), .matchRuleType("PrelinkedObjectLink")) { task in + task.checkCommandLineMatches([.suffix("ld"), "-r", "-arch", "x86_64", "-syslibroot", .equal(core.loadSDK(.macOS).path.str), "-o", .equal("\(SRCROOT)/build/aProject.build/Debug-maccatalyst/AllLibraries.build/Objects-normal/libAllLibraries.a-x86_64-prelink.o")]) } results.checkTask(.matchTarget(target), .matchRuleType("Libtool")) { task in task.checkCommandLineMatches([.suffix("libtool"), "-static", "-arch_only", "x86_64", "-D", "-syslibroot", .equal(core.loadSDK(.macOS).path.str), .equal("-L\(SRCROOT)/build/Debug-maccatalyst"), "-L\(core.loadSDK(.macOS).path.str)/System/iOSSupport/usr/lib", "-L\(core.developerPath.path.str)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/maccatalyst", "-L\(core.loadSDK(.macOS).path.str)/System/iOSSupport/usr/lib", "-L\(core.developerPath.path.str)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/maccatalyst", "-filelist", .equal("\(SRCROOT)/build/aProject.build/Debug-maccatalyst/AllLibraries.build/Objects-normal/x86_64/AllLibraries.LinkFileList"), "-dependency_info", "\(SRCROOT)/build/aProject.build/Debug-maccatalyst/AllLibraries.build/Objects-normal/x86_64/AllLibraries_libtool_dependency_info.dat", "-o", .equal("\(SRCROOT)/build/Debug-maccatalyst/libAllLibraries.a")]) @@ -222,9 +222,9 @@ fileprivate struct MasterObjectFileTests: CoreBasedTests { } @Test(.requireSDKs(.iOS)) - func masterObjectFileGenerationVariant_ios() async throws { + func prelinkedObjectFileGenerationVariant_ios() async throws { let core = try await getCore() - // Test that a master object file gets generated even if the target contains no sources or libraries in its build phases. + // Test that a prelinked object file gets generated even if the target contains no sources or libraries in its build phases. let testProject = TestProject( "aProject", groupTree: TestGroup( @@ -248,7 +248,7 @@ fileprivate struct MasterObjectFileTests: CoreBasedTests { TestBuildConfiguration( "Debug", buildSettings: [ - "GENERATE_MASTER_OBJECT_FILE": "YES", + "GENERATE_PRELINK_OBJECT_FILE": "YES", ]), ], buildPhases: [ @@ -270,9 +270,9 @@ fileprivate struct MasterObjectFileTests: CoreBasedTests { results.checkTasks(.matchRuleType("RegisterExecutionPolicyException")) { _ in } results.checkTarget("AllLibraries") { target in - // There should be tasks to create the master object file and then the static library. - results.checkTask(.matchTarget(target), .matchRuleType("MasterObjectLink")) { task in - task.checkCommandLineMatches([.suffix("ld"), "-r", "-arch", "arm64", "-syslibroot", .equal(results.runDestinationSDK.path.str), "-o", .equal("\(SRCROOT)/build/aProject.build/Debug-iphoneos/AllLibraries.build/Objects-normal/libAllLibraries.a-arm64-master.o")]) + // There should be tasks to create the prelinked object file and then the static library. + results.checkTask(.matchTarget(target), .matchRuleType("PrelinkedObjectLink")) { task in + task.checkCommandLineMatches([.suffix("ld"), "-r", "-arch", "arm64", "-syslibroot", .equal(results.runDestinationSDK.path.str), "-o", .equal("\(SRCROOT)/build/aProject.build/Debug-iphoneos/AllLibraries.build/Objects-normal/libAllLibraries.a-arm64-prelink.o")]) } results.checkTask(.matchTarget(target), .matchRuleType("Libtool")) { task in task.checkCommandLineMatches([.suffix("libtool"), "-static", "-arch_only", "arm64", "-D", "-syslibroot", .equal(results.runDestinationSDK.path.str), .equal("-L\(SRCROOT)/build/Debug-iphoneos"), "-filelist", .equal("\(SRCROOT)/build/aProject.build/Debug-iphoneos/AllLibraries.build/Objects-normal/arm64/AllLibraries.LinkFileList"), "-dependency_info", "\(SRCROOT)/build/aProject.build/Debug-iphoneos/AllLibraries.build/Objects-normal/arm64/AllLibraries_libtool_dependency_info.dat", "-o", .equal("\(SRCROOT)/build/Debug-iphoneos/libAllLibraries.a")]) @@ -291,7 +291,7 @@ fileprivate struct MasterObjectFileTests: CoreBasedTests { } @Test(.requireSDKs(.iOS)) - func masterObjectFileGenerationVariant_ios_simulator() async throws { + func prelinkedObjectFileGenerationVariant_ios_simulator() async throws { let core = try await getCore() let testProject = TestProject( "aProject", @@ -316,7 +316,7 @@ fileprivate struct MasterObjectFileTests: CoreBasedTests { TestBuildConfiguration( "Debug", buildSettings: [ - "GENERATE_MASTER_OBJECT_FILE": "YES", + "GENERATE_PRELINK_OBJECT_FILE": "YES", ]), ], buildPhases: [ @@ -338,9 +338,9 @@ fileprivate struct MasterObjectFileTests: CoreBasedTests { results.checkTasks(.matchRuleType("RegisterExecutionPolicyException")) { _ in } results.checkTarget("AllLibraries") { target in - // There should be tasks to create the master object file and then the static library. - results.checkTask(.matchTarget(target), .matchRuleType("MasterObjectLink")) { task in - task.checkCommandLineMatches([.suffix("ld"), "-r", "-arch", "x86_64", "-syslibroot", .equal(results.runDestinationSDK.path.str), "-o", .equal("\(SRCROOT)/build/aProject.build/Debug-iphonesimulator/AllLibraries.build/Objects-normal/libAllLibraries.a-x86_64-master.o")]) + // There should be tasks to create the prelinked object file and then the static library. + results.checkTask(.matchTarget(target), .matchRuleType("PrelinkedObjectLink")) { task in + task.checkCommandLineMatches([.suffix("ld"), "-r", "-arch", "x86_64", "-syslibroot", .equal(results.runDestinationSDK.path.str), "-o", .equal("\(SRCROOT)/build/aProject.build/Debug-iphonesimulator/AllLibraries.build/Objects-normal/libAllLibraries.a-x86_64-prelink.o")]) } results.checkTask(.matchTarget(target), .matchRuleType("Libtool")) { task in task.checkCommandLineMatches([.suffix("libtool"), "-static", "-arch_only", "x86_64", "-D", "-syslibroot", .equal(results.runDestinationSDK.path.str), .equal("-L\(SRCROOT)/build/Debug-iphonesimulator"), "-filelist", .equal("\(SRCROOT)/build/aProject.build/Debug-iphonesimulator/AllLibraries.build/Objects-normal/x86_64/AllLibraries.LinkFileList"), "-dependency_info", "\(SRCROOT)/build/aProject.build/Debug-iphonesimulator/AllLibraries.build/Objects-normal/x86_64/AllLibraries_libtool_dependency_info.dat", "-o", .equal("\(SRCROOT)/build/Debug-iphonesimulator/libAllLibraries.a")]) diff --git a/Tests/SWBTaskConstructionTests/SwiftTaskConstructionTests.swift b/Tests/SWBTaskConstructionTests/SwiftTaskConstructionTests.swift index 997e5fec..f68b8ef3 100644 --- a/Tests/SWBTaskConstructionTests/SwiftTaskConstructionTests.swift +++ b/Tests/SWBTaskConstructionTests/SwiftTaskConstructionTests.swift @@ -326,10 +326,11 @@ fileprivate struct SwiftTaskConstructionTests: CoreBasedTests { #expect(fileDict["dependencies"]?.stringValue == "\(SRCROOT)/build/aProject.build/Debug/AppTarget.build/Objects-normal/x86_64/\(filename).d") #expect(fileDict["swift-dependencies"]?.stringValue == "\(SRCROOT)/build/aProject.build/Debug/AppTarget.build/Objects-normal/x86_64/\(filename).swiftdeps") #expect(fileDict["swiftmodule"]?.stringValue == "\(SRCROOT)/build/aProject.build/Debug/AppTarget.build/Objects-normal/x86_64/\(filename)~partial.swiftmodule") + #expect(fileDict["llvm-bc"]?.stringValue == "\(SRCROOT)/build/aProject.build/Debug/AppTarget.build/Objects-normal/x86_64/\(filename).bc") #expect(fileDict["const-values"]?.stringValue == "\(SRCROOT)/build/aProject.build/Debug/AppTarget.build/Objects-normal/x86_64/\(filename).swiftconstvalues") if swiftFeatures.has(.indexUnitOutputPathWithoutWarning) { #expect(fileDict["index-unit-output-path"]?.stringValue == "/aProject.build/Debug/AppTarget.build/Objects-normal/x86_64/\(filename).o") - #expect(fileDict.count == 7) + #expect(fileDict.count == 8) } else { #expect(fileDict.count == 6) } @@ -645,6 +646,7 @@ fileprivate struct SwiftTaskConstructionTests: CoreBasedTests { "SWIFT_PACKAGE_NAME": "FooPkg", "SWIFT_EMIT_MODULE_INTERFACE": "YES", "SWIFT_ENABLE_EXPLICIT_MODULES": "YES", + "SWIFT_DISABLE_INCREMENTAL_SCAN": "YES", ]), ], buildPhases: [ @@ -830,6 +832,7 @@ fileprivate struct SwiftTaskConstructionTests: CoreBasedTests { "DEFINES_MODULE": "YES", "SWIFT_VERSION": swiftVersion, "SWIFT_EMIT_MODULE_INTERFACE": "YES", + "SWIFT_DISABLE_INCREMENTAL_SCAN": "YES", ]), ], buildPhases: [ @@ -1263,9 +1266,11 @@ fileprivate struct SwiftTaskConstructionTests: CoreBasedTests { } else { compileTask.checkCommandLineContains(["-lto=llvm-thin"]) } + compileTask.checkOutputs(contain: [.namePattern(.suffix("Bar.bc"))]) } results.checkTask(.matchTarget(target), .matchRuleType("Libtool")) { archiverTask in results.checkTaskFollows(archiverTask, .matchTarget(target), .matchRuleType("SwiftDriver Compilation")) + archiverTask.checkInputs(contain: [.namePattern(.suffix("Bar.bc"))]) } } results.checkTarget("CoreFoo") { target in @@ -1275,9 +1280,11 @@ fileprivate struct SwiftTaskConstructionTests: CoreBasedTests { } else { compileTask.checkCommandLineContains(["-lto=llvm-thin"]) } + compileTask.checkOutputs(contain: [.namePattern(.suffix("Foo.bc"))]) } results.checkTask(.matchTarget(target), .matchRuleType("Ld")) { linkerTask in results.checkTaskFollows(linkerTask, .matchTarget(target), .matchRuleType("SwiftDriver Compilation")) + linkerTask.checkInputs(contain: [.namePattern(.suffix("Foo.bc"))]) if ltoSetting == "YES_THIN" { linkerTask.checkCommandLineMatches([.anySequence, "-Xlinker", "-cache_path_lto", "-Xlinker", .suffix("/LTOCache"), .anySequence]) } @@ -1530,6 +1537,64 @@ fileprivate struct SwiftTaskConstructionTests: CoreBasedTests { } } + @Test(.requireSDKs(.macOS), .enabled(if: LibSwiftDriver.supportsDriverFlag(spelled: "-incremental-dependency-scan"))) + func optOutIncrementalScanning() async throws { + let testProject = try await TestProject( + "aProject", + groupTree: TestGroup( + "SomeFiles", path: "Sources", + children: [ + TestFile("main.swift"), + ]), + buildConfigurations: [ + TestBuildConfiguration( + "Debug", + buildSettings: [ + "PRODUCT_NAME": "$(TARGET_NAME)", + "SWIFT_ENABLE_EXPLICIT_MODULES": "YES", + ]), + ], + targets: [ + TestStandardTarget( + "Exec", type: .commandLineTool, + buildConfigurations: [ + TestBuildConfiguration("Debug", + buildSettings: [ + "SWIFT_EXEC": swiftCompilerPath.str, + "SWIFT_VERSION": swiftVersion, + ]), + ], + buildPhases: [ + TestSourcesBuildPhase([ + "main.swift", + ]), + ]) + ]) + let tester = try await TaskConstructionTester(getCore(), testProject) + + await tester.checkBuild(runDestination: .macOS) { results in + results.checkTarget("Exec") { target in + results.checkTask(.matchTarget(target), .matchRuleType("SwiftDriver Compilation Requirements")) { task in + task.checkCommandLineContains(["-explicit-module-build"]) + task.checkCommandLineContains(["-incremental"]) + task.checkCommandLineContains(["-incremental-dependency-scan"]) + } + } + results.checkNoDiagnostics() + } + + await tester.checkBuild(BuildParameters(configuration: "Debug", overrides: ["SWIFT_DISABLE_INCREMENTAL_SCAN": "YES"]), runDestination: .macOS) { results in + results.checkTarget("Exec") { target in + results.checkTask(.matchTarget(target), .matchRuleType("SwiftDriver Compilation Requirements")) { task in + task.checkCommandLineContains(["-explicit-module-build"]) + task.checkCommandLineContains(["-incremental"]) + task.checkCommandLineDoesNotContain("-incremental-dependency-scan") + } + } + results.checkNoDiagnostics() + } + } + @Test(.requireSDKs(.macOS)) func swift4DisablesExplicitModules() async throws { let testProject = try await TestProject( @@ -3468,6 +3533,94 @@ fileprivate struct SwiftTaskConstructionTests: CoreBasedTests { } } + @Test(.requireSDKs(.macOS)) + func defaultIsolationFlag() async throws { + try await withTemporaryDirectory { tmpDir in + let srcRoot = tmpDir.join("srcroot") + let testProject = try await TestProject( + "ProjectName", + sourceRoot: srcRoot, + groupTree: TestGroup( + "SomeFiles", path: "Sources", + children: [ + TestFile("File1.swift"), + TestFile("File2.swift"), + TestFile("File3.swift"), + ]), + targets: [ + TestStandardTarget( + "Default", + type: .framework, + buildConfigurations: [ + TestBuildConfiguration("Debug", buildSettings: [ + "GENERATE_INFOPLIST_FILE": "YES", + "PRODUCT_NAME": "$(TARGET_NAME)", + "SWIFT_EXEC": swiftCompilerPath.str, + "SWIFT_VERSION": "5.0", + ]), + ], + buildPhases: [ + TestSourcesBuildPhase([ + TestBuildFile("File1.swift"), + ]), + ], dependencies: ["Nonisolated", "MainActor"]), + TestStandardTarget( + "Nonisolated", + type: .framework, + buildConfigurations: [ + TestBuildConfiguration("Debug", buildSettings: [ + "GENERATE_INFOPLIST_FILE": "YES", + "PRODUCT_NAME": "$(TARGET_NAME)", + "SWIFT_EXEC": swiftCompilerPath.str, + "SWIFT_VERSION": "5.0", + "SWIFT_DEFAULT_ACTOR_ISOLATION": "nonisolated", + ]), + ], + buildPhases: [ + TestSourcesBuildPhase([ + TestBuildFile("File2.swift"), + ]), + ]), + TestStandardTarget( + "MainActor", + type: .framework, + buildConfigurations: [ + TestBuildConfiguration("Debug", buildSettings: [ + "GENERATE_INFOPLIST_FILE": "YES", + "PRODUCT_NAME": "$(TARGET_NAME)", + "SWIFT_EXEC": swiftCompilerPath.str, + "SWIFT_VERSION": "5.0", + "SWIFT_DEFAULT_ACTOR_ISOLATION": "MainActor", + ]), + ], + buildPhases: [ + TestSourcesBuildPhase([ + TestBuildFile("File3.swift"), + ]), + ]), + ]) + + let tester = try await TaskConstructionTester(getCore(), testProject) + await tester.checkBuild(BuildParameters(action: .install, configuration: "Debug"), runDestination: .macOS) { results in + results.checkTarget("Default") { target in + results.checkTask(.matchTarget(target), .matchRuleType("SwiftDriver Compilation")) { task in + task.checkCommandLineNoMatch([.prefix("-default-isolation")]) + } + } + results.checkTarget("Nonisolated") { target in + results.checkTask(.matchTarget(target), .matchRuleType("SwiftDriver Compilation")) { task in + task.checkCommandLineNoMatch([.prefix("-default-isolation")]) + } + } + results.checkTarget("MainActor") { target in + results.checkTask(.matchTarget(target), .matchRuleType("SwiftDriver Compilation")) { task in + task.checkCommandLineContains(["-default-isolation=MainActor"]) + } + } + } + } + } + // Test frontend flag -library-level inference from the INSTALL_PATH. @Test(.requireSDKs(.macOS)) func libraryLevel() async throws { diff --git a/Tests/SWBTaskConstructionTests/TaskConstructionTests.swift b/Tests/SWBTaskConstructionTests/TaskConstructionTests.swift index 4511d270..a40e9382 100644 --- a/Tests/SWBTaskConstructionTests/TaskConstructionTests.swift +++ b/Tests/SWBTaskConstructionTests/TaskConstructionTests.swift @@ -97,7 +97,7 @@ fileprivate struct TaskConstructionTests: CoreBasedTests { "ALTERNATE_OWNER": "fooOwner", "ALTERNATE_GROUP": "", "ALTERNATE_MODE": "", - "GENERATE_MASTER_OBJECT_FILE": "YES", + "GENERATE_PRELINK_OBJECT_FILE": "YES", ]), ], targets: [ @@ -885,9 +885,9 @@ fileprivate struct TaskConstructionTests: CoreBasedTests { } results.checkNoTask(.matchTarget(target), .matchRuleType("Copy")) - // There should be one master object link task. - results.checkTask(.matchTarget(target), .matchRuleType("MasterObjectLink")) { task in - task.checkRuleInfo(["MasterObjectLink", "\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/AppTarget-x86_64-master.o"]) + // There should be one prelinked object link task. + results.checkTask(.matchTarget(target), .matchRuleType("PrelinkedObjectLink")) { task in + task.checkRuleInfo(["PrelinkedObjectLink", "\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/AppTarget-x86_64-prelink.o"]) let nonUniqueObjs = task.commandLineAsStrings.filter { $0.contains("NonUnique") } if nonUniqueObjs.count != 2 { #expect(nonUniqueObjs.count == 2) @@ -895,7 +895,7 @@ fileprivate struct TaskConstructionTests: CoreBasedTests { } #expect(nonUniqueObjs[0] != nonUniqueObjs[1]) - task.checkCommandLineMatches([StringPattern.suffix("ld"), "-r", "-arch", "x86_64", "-syslibroot", .equal(core.loadSDK(.macOS).path.str), .equal("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/x86_64/SourceFile.o"), .equal("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/x86_64/SourceFile-Matched-Excluded.o"), .equal("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/x86_64/SourceFile-Matched-Included.o"), .equal(nonUniqueObjs[0]), .equal(nonUniqueObjs[1]), .equal("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/x86_64/SourceFile_MRR.o"), .equal("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/x86_64/Lex.yy.o"), .equal("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/x86_64/y.tab.o"), .equal("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/x86_64/Script-Output-Custom-SourceFile.o"), .equal("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/x86_64/Script-Output-Standard-SourceFile.o"), "-o", .equal("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/AppTarget-x86_64-master.o")]) + task.checkCommandLineMatches([StringPattern.suffix("ld"), "-r", "-arch", "x86_64", "-syslibroot", .equal(core.loadSDK(.macOS).path.str), .equal("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/x86_64/SourceFile.o"), .equal("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/x86_64/SourceFile-Matched-Excluded.o"), .equal("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/x86_64/SourceFile-Matched-Included.o"), .equal(nonUniqueObjs[0]), .equal(nonUniqueObjs[1]), .equal("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/x86_64/SourceFile_MRR.o"), .equal("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/x86_64/Lex.yy.o"), .equal("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/x86_64/y.tab.o"), .equal("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/x86_64/Script-Output-Custom-SourceFile.o"), .equal("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/x86_64/Script-Output-Standard-SourceFile.o"), "-o", .equal("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/AppTarget-x86_64-prelink.o")]) task.checkInputs([ .path("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/x86_64/SourceFile.o"), @@ -915,7 +915,7 @@ fileprivate struct TaskConstructionTests: CoreBasedTests { .namePattern(.prefix("target-"))]) task.checkOutputs([ - .path("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/AppTarget-x86_64-master.o"),]) + .path("\(SRCROOT)/build/aProject.build/Release/AppTarget.build/Objects-normal/AppTarget-x86_64-prelink.o"),]) } @@ -4135,7 +4135,7 @@ fileprivate struct TaskConstructionTests: CoreBasedTests { // There should be one CompileC task, which includes the ASan option, and which puts its output in a -asan directory. results.checkTask(.matchTarget(target), .matchRuleType("CompileC")) { task in task.checkRuleInfo([.equal("CompileC"), .equal("\(SRCROOT)/build/aProject.build/Debug/\(targetName).build/Objects-normal-asan/x86_64/SourceFile.o"), .suffix("SourceFile.m"), .any, .any, .any, .any]) - task.checkCommandLineContains(["\(core.developerPath.path.str)/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang", "-fsanitize=address", "-D_LIBCPP_HAS_NO_ASAN", "\(SRCROOT)/build/aProject.build/Debug/\(targetName).build/Objects-normal-asan/x86_64/SourceFile.o"]) + task.checkCommandLineContains(["\(core.developerPath.path.str)/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang", "-fsanitize=address", "-D_LIBCPP_HAS_NO_ASAN", "-D_LIBCPP_HAS_ASAN=0", "\(SRCROOT)/build/aProject.build/Debug/\(targetName).build/Objects-normal-asan/x86_64/SourceFile.o"]) } // There should be one CompileSwiftSources task, which includes the ASan option, and which puts its output in a -asan directory. @@ -8478,12 +8478,14 @@ fileprivate struct TaskConstructionTests: CoreBasedTests { } } else if let val = overrides[typedMemoryOperationsCXX] { if val == "YES" { - task.checkCommandLineContains(["-ftyped-cxx-new-delete"]) + task.checkCommandLineContains(["-ftyped-cxx-new-delete", "-ftyped-cxx-delete"]) } else if val == "NO" { - task.checkCommandLineContains(["-fno-typed-cxx-new-delete"]) + task.checkCommandLineContains(["-fno-typed-cxx-new-delete", "-fno-typed-cxx-delete"]) } else if val == "compiler-default" { task.checkCommandLineDoesNotContain("-ftyped-cxx-new-delete") + task.checkCommandLineDoesNotContain("-ftyped-cxx-delete") task.checkCommandLineDoesNotContain("-fno-typed-cxx-new-delete") + task.checkCommandLineDoesNotContain("-fno-typed-cxx-delete") } } } @@ -8501,6 +8503,11 @@ fileprivate struct TaskConstructionTests: CoreBasedTests { await tester.checkBuild(BuildParameters(configuration: "Debug", overrides: override), runDestination: .macOS, fs: fs) { results -> Void in results.checkTarget("AppTarget") { target -> Void in results.checkTask(.matchTarget(target), .matchRuleType("CompileC"), body: {task in test(task: task, overrides: override)}) + if let val = override[typedMemoryOperationsCXX], val == "YES" { + results.checkTask(.matchTarget(target), .matchRuleType("Ld"), body: {task in + task.checkCommandLineContains(["-ftyped-cxx-new-delete", "-ftyped-cxx-delete"]) + }) + } } } } diff --git a/Tests/SWBTaskExecutionTests/PBXCpTests.swift b/Tests/SWBTaskExecutionTests/PBXCpTests.swift index c4b0237f..109bba4d 100644 --- a/Tests/SWBTaskExecutionTests/PBXCpTests.swift +++ b/Tests/SWBTaskExecutionTests/PBXCpTests.swift @@ -442,7 +442,8 @@ fileprivate struct PBXCpTests: CoreBasedTests { fileprivate let buffer0 = [UInt8](repeating: 0xAA, count: 1024 * 513) fileprivate let buffer1 = [UInt8](repeating: 0x55, count: 1024 * 513) - @Test(.skipHostOS(.windows, "LocalFS needs to use stat64 on windows....")) + @Test(.skipHostOS(.windows, "LocalFS needs to use stat64 on windows...."), + .skipInGitHubActions("GitHub action runners do not have enough storage space for this test")) func largerFile() async throws { try await withTemporaryDirectory { tmp in // Test copying a large file. diff --git a/Tests/SwiftBuildTests/TestData/CommandLineTool/CommandLineTool/main.c b/Tests/SwiftBuildTests/TestData/CommandLineTool/CommandLineTool/main.c index 33c14ce1..cdee1235 100644 --- a/Tests/SwiftBuildTests/TestData/CommandLineTool/CommandLineTool/main.c +++ b/Tests/SwiftBuildTests/TestData/CommandLineTool/CommandLineTool/main.c @@ -1,3 +1,15 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + int main() { return 0; } diff --git a/Tests/SwiftBuildTests/TestData/CommandLineToolPackage/Sources/CommandLineToolPackage/main.swift b/Tests/SwiftBuildTests/TestData/CommandLineToolPackage/Sources/CommandLineToolPackage/main.swift index e69de29b..380508dc 100644 --- a/Tests/SwiftBuildTests/TestData/CommandLineToolPackage/Sources/CommandLineToolPackage/main.swift +++ b/Tests/SwiftBuildTests/TestData/CommandLineToolPackage/Sources/CommandLineToolPackage/main.swift @@ -0,0 +1,12 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + diff --git a/Utilities/swift-ci-perf-tests.sh b/Utilities/swift-ci-perf-tests.sh index 255c7e09..f8787e78 100755 --- a/Utilities/swift-ci-perf-tests.sh +++ b/Utilities/swift-ci-perf-tests.sh @@ -1,8 +1,19 @@ -#!/usr/bin/env bash +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift open source project +## +## Copyright (c) 2025 Apple Inc. and the Swift project authors +## Licensed under Apache License v2.0 with Runtime Library Exception +## +## See http://swift.org/LICENSE.txt for license information +## See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +## +##===----------------------------------------------------------------------===## set -euo pipefail __dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -cd ${__dir}/.. +cd "${__dir}"/.. swift test -c release --filter Perf diff --git a/cmake/modules/CMakeLists.txt b/cmake/modules/CMakeLists.txt new file mode 100644 index 00000000..1f05107b --- /dev/null +++ b/cmake/modules/CMakeLists.txt @@ -0,0 +1,9 @@ +set(SWIFTBUILD_EXPORTS_FILE ${CMAKE_CURRENT_BINARY_DIR}/SwiftBuildExports.cmake) + +configure_file(SwiftBuildConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/SwiftBuildConfig.cmake) + +get_property(SWIFTBUILD_EXPORTS GLOBAL PROPERTY SWIFTBUILD_EXPORTS) +export(TARGETS ${SWIFTBUILD_EXPORTS} + NAMESPACE SwiftBuild:: + FILE ${SWIFTBUILD_EXPORTS_FILE}) diff --git a/cmake/modules/SwiftBuildConfig.cmake.in b/cmake/modules/SwiftBuildConfig.cmake.in new file mode 100644 index 00000000..b996ae36 --- /dev/null +++ b/cmake/modules/SwiftBuildConfig.cmake.in @@ -0,0 +1,14 @@ +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift open source project +## +## Copyright (c) YEARS Apple Inc. and the Swift project authors +## Licensed under Apache License v2.0 with Runtime Library Exception +## +## See http://swift.org/LICENSE.txt for license information +## See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +## +##===----------------------------------------------------------------------===## +if(NOT TARGET SwiftBuild::SwiftBuild) + include(@SWIFTBUILD_EXPORTS_FILE@) +endif()