diff --git a/Sources/SwiftBuildSupport/PackagePIFBuilder+Helpers.swift b/Sources/SwiftBuildSupport/PackagePIFBuilder+Helpers.swift index cc50ae4648b..84c3928f57d 100644 --- a/Sources/SwiftBuildSupport/PackagePIFBuilder+Helpers.swift +++ b/Sources/SwiftBuildSupport/PackagePIFBuilder+Helpers.swift @@ -1001,16 +1001,18 @@ extension ProjectModel.BuildSettings { mutating func configureDynamicSettings( productName: String, targetName: String, + executableName: String, packageIdentity: PackageIdentity, packageName: String?, createDylibForDynamicProducts: Bool, installPath: String, - delegate: PackagePIFBuilder.BuildDelegate, + delegate: PackagePIFBuilder.BuildDelegate ) { self[.TARGET_NAME] = targetName - self[.PRODUCT_NAME] = productName + self[.PRODUCT_NAME] = createDylibForDynamicProducts ? productName : executableName self[.PRODUCT_MODULE_NAME] = productName self[.PRODUCT_BUNDLE_IDENTIFIER] = "\(packageIdentity).\(productName)".spm_mangledToBundleIdentifier() + self[.EXECUTABLE_NAME] = executableName self[.CLANG_ENABLE_MODULES] = "YES" self[.SWIFT_PACKAGE_NAME] = packageName ?? nil diff --git a/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Modules.swift b/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Modules.swift index 42a7aaa2506..dc926d66668 100644 --- a/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Modules.swift +++ b/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Modules.swift @@ -237,25 +237,31 @@ extension PackagePIFProjectBuilder { ) throws -> (PackagePIFBuilder.ModuleOrProduct, resourceBundleName: String?) { precondition(sourceModule.isSourceModule) + let pifProductName: String + let executableName: String let productType: ProjectModel.Target.ProductType switch desiredModuleType { case .dynamicLibrary: // We are re-using this default for dynamic targets as well. if pifBuilder.createDylibForDynamicProducts { + pifProductName = "lib\(sourceModule.name).dylib" + executableName = pifProductName productType = .dynamicLibrary } else { + pifProductName = sourceModule.name + ".framework" + executableName = sourceModule.name productType = .framework } case .staticLibrary, .executable: - #if os(Windows) // Temporary until we get a new productType in swift-build - productType = .staticArchive - #else + pifProductName = "\(sourceModule.name).o" + executableName = pifProductName productType = .objectFile - #endif case .macro: + pifProductName = sourceModule.name + executableName = pifProductName productType = .hostBuildTool } @@ -274,8 +280,8 @@ extension PackagePIFProjectBuilder { ProjectModel.Target( id: sourceModule.pifTargetGUID(suffix: targetSuffix), productType: productType, - name: sourceModule.name, - productName: "$(EXECUTABLE_NAME)", + name: "\(sourceModule.name)", + productName: pifProductName, approvedByUser: approvedByUser ) } @@ -401,11 +407,12 @@ extension PackagePIFProjectBuilder { settings.configureDynamicSettings( productName: sourceModule.name, targetName: sourceModule.name, + executableName: executableName, packageIdentity: package.identity, packageName: sourceModule.packageName, createDylibForDynamicProducts: pifBuilder.createDylibForDynamicProducts, installPath: "/usr/local/lib", - delegate: pifBuilder.delegate, + delegate: pifBuilder.delegate ) } else { settings[.TARGET_NAME] = sourceModule.name @@ -413,10 +420,22 @@ extension PackagePIFProjectBuilder { settings[.PRODUCT_MODULE_NAME] = sourceModule.c99name settings[.PRODUCT_BUNDLE_IDENTIFIER] = "\(self.package.identity).\(sourceModule.name)" .spm_mangledToBundleIdentifier() + settings[.EXECUTABLE_NAME] = executableName settings[.CLANG_ENABLE_MODULES] = "YES" settings[.GENERATE_PRELINK_OBJECT_FILE] = "NO" settings[.STRIP_INSTALLED_PRODUCT] = "NO" + // Macros build as executables, so they need slightly different + // build settings from other module types which build a "*.o". + if desiredModuleType == .macro { + settings[.MACH_O_TYPE] = "mh_execute" + } else { + settings[.MACH_O_TYPE] = "mh_object" + // Disable code coverage linker flags since we're producing .o files. + // Otherwise, we will run into duplicated symbols when there are more than one targets that produce .o + // as their product. + settings[.CLANG_COVERAGE_MAPPING_LINKER_ARGS] = "NO" + } settings[.SWIFT_PACKAGE_NAME] = sourceModule.packageName if desiredModuleType == .executable { diff --git a/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Products.swift b/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Products.swift index 9fc26226ad6..69f1d6d8e35 100644 --- a/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Products.swift +++ b/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Products.swift @@ -78,7 +78,7 @@ extension PackagePIFProjectBuilder { id: product.pifTargetGUID, productType: pifProductType, name: product.targetName(), - productName: "$(EXECUTABLE_NAME)" + productName: product.name ) } do { @@ -116,6 +116,7 @@ extension PackagePIFProjectBuilder { settings[.PRODUCT_MODULE_NAME] = product.c99name settings[.PRODUCT_BUNDLE_IDENTIFIER] = "\(self.package.identity).\(product.name)" .spm_mangledToBundleIdentifier() + settings[.EXECUTABLE_NAME] = product.name settings[.CLANG_ENABLE_MODULES] = "YES" settings[.SWIFT_PACKAGE_NAME] = mainModule.packageName @@ -607,15 +608,35 @@ extension PackagePIFProjectBuilder { // FIXME: Cleanup this mess with + let pifProductName: String + let executableName: String let productType: ProjectModel.Target.ProductType if desiredProductType == .dynamic { if pifBuilder.createDylibForDynamicProducts { + pifProductName = "lib\(product.name).dylib" + executableName = pifProductName productType = .dynamicLibrary } else { + // If a product is explicitly declared dynamic, we preserve its name, + // otherwise we will compute an automatic one. + if product.libraryType == .dynamic { + if let customExecutableName = pifBuilder.delegate + .customExecutableName(product: product.underlying) + { + executableName = customExecutableName + } else { + executableName = product.name + } + } else { + executableName = PackagePIFBuilder.computePackageProductFrameworkName(productName: product.name) + } + pifProductName = "\(executableName).framework" productType = .framework } } else { + pifProductName = "lib\(product.name).a" + executableName = pifProductName productType = .packageProduct } @@ -628,7 +649,7 @@ extension PackagePIFProjectBuilder { id: product.pifTargetGUID(suffix: targetSuffix), productType: productType, name: product.targetName(suffix: targetSuffix), - productName: product.name + productName: pifProductName ) } do { @@ -697,6 +718,7 @@ extension PackagePIFProjectBuilder { settings.configureDynamicSettings( productName: product.name, targetName: product.targetName(), + executableName: executableName, packageIdentity: package.identity, packageName: package.identity.c99name, createDylibForDynamicProducts: pifBuilder.createDylibForDynamicProducts, @@ -1027,6 +1049,7 @@ extension PackagePIFProjectBuilder { settings[.PRODUCT_MODULE_NAME] = moduleName settings[.PRODUCT_BUNDLE_IDENTIFIER] = "\(self.package.identity).\(name)" .spm_mangledToBundleIdentifier() + settings[.EXECUTABLE_NAME] = name settings[.SKIP_INSTALL] = "NO" settings[.SWIFT_VERSION] = "5.0" // This should eventually be set universally for all package targets/products. diff --git a/Sources/SwiftBuildSupport/PackagePIFProjectBuilder.swift b/Sources/SwiftBuildSupport/PackagePIFProjectBuilder.swift index 391fb15be9d..13b02f49c03 100644 --- a/Sources/SwiftBuildSupport/PackagePIFProjectBuilder.swift +++ b/Sources/SwiftBuildSupport/PackagePIFProjectBuilder.swift @@ -211,6 +211,7 @@ struct PackagePIFProjectBuilder { settings[.PRODUCT_MODULE_NAME] = bundleName settings[.PRODUCT_BUNDLE_IDENTIFIER] = "\(self.package.identity).\(module.name).resources" .spm_mangledToBundleIdentifier() + settings[.EXECUTABLE_NAME] = "" settings[.GENERATE_INFOPLIST_FILE] = "YES" settings[.PACKAGE_RESOURCE_TARGET_KIND] = "resource" diff --git a/Sources/SwiftBuildSupport/SwiftBuildSystem.swift b/Sources/SwiftBuildSupport/SwiftBuildSystem.swift index 13713ef9819..0cf90551b91 100644 --- a/Sources/SwiftBuildSupport/SwiftBuildSystem.swift +++ b/Sources/SwiftBuildSupport/SwiftBuildSystem.swift @@ -727,19 +727,16 @@ public final class SwiftBuildSystem: SPMBuildCore.BuildSystem { settings["LIBRARY_SEARCH_PATHS"] = try "$(inherited) \(buildParameters.toolchain.toolchainLibDir.pathString)" settings["OTHER_CFLAGS"] = ( - verboseFlag + ["$(inherited)"] + buildParameters.toolchain.extraFlags.cCompilerFlags.map { $0.shellEscaped() } + buildParameters.flags.cCompilerFlags.map { $0.shellEscaped() } ).joined(separator: " ") settings["OTHER_CPLUSPLUSFLAGS"] = ( - verboseFlag + ["$(inherited)"] + buildParameters.toolchain.extraFlags.cxxCompilerFlags.map { $0.shellEscaped() } + buildParameters.flags.cxxCompilerFlags.map { $0.shellEscaped() } ).joined(separator: " ") settings["OTHER_SWIFT_FLAGS"] = ( - verboseFlag + ["$(inherited)"] + buildParameters.toolchain.extraFlags.swiftCompilerFlags.map { $0.shellEscaped() } + buildParameters.flags.swiftCompilerFlags.map { $0.shellEscaped() } diff --git a/Tests/CommandsTests/BuildCommandTests.swift b/Tests/CommandsTests/BuildCommandTests.swift index a81708f0671..6a6a1c6547f 100644 --- a/Tests/CommandsTests/BuildCommandTests.swift +++ b/Tests/CommandsTests/BuildCommandTests.swift @@ -554,14 +554,19 @@ struct BuildCommandTestCases { func nonReachableProductsAndTargetsFunctional( buildSystem: BuildSystemProvider.Kind, ) async throws { - try await fixture(name: "Miscellaneous/UnreachableTargets") { fixturePath in - let aPath = fixturePath.appending("A") - - let result = try await build([], packagePath: aPath, buildSystem: buildSystem) - #expect(!result.binContents.contains("bexec")) - #expect(!result.binContents.contains("BTarget2.build")) - #expect(!result.binContents.contains("cexec")) - #expect(!result.binContents.contains("CTarget.build")) + // skipped on Xcode + try await withKnownIssue { + try await fixture(name: "Miscellaneous/UnreachableTargets") { fixturePath in + let aPath = fixturePath.appending("A") + + let result = try await build([], packagePath: aPath, buildSystem: buildSystem) + #expect(!result.binContents.contains("bexec")) + #expect(!result.binContents.contains("BTarget2.build")) + #expect(!result.binContents.contains("cexec")) + #expect(!result.binContents.contains("CTarget.build")) + } + } when: { + buildSystem == .swiftbuild && ProcessInfo.hostOperatingSystem == .windows } } diff --git a/Tests/CommandsTests/PackageCommandTests.swift b/Tests/CommandsTests/PackageCommandTests.swift index de7e948da35..a885ab93631 100644 --- a/Tests/CommandsTests/PackageCommandTests.swift +++ b/Tests/CommandsTests/PackageCommandTests.swift @@ -2722,7 +2722,7 @@ struct PackageCommandTests { #expect(try localFileSystem.readFileContents(bazTotPackageFile) == content) } } when: { - ProcessInfo.hostOperatingSystem == .linux && data.buildSystem == .swiftbuild + [.windows, .linux].contains(ProcessInfo.hostOperatingSystem) && data.buildSystem == .swiftbuild } } @@ -2738,36 +2738,40 @@ struct PackageCommandTests { func packageClean( data: BuildData, ) async throws { - try await fixture(name: "DependencyResolution/External/Simple") { fixturePath in - let packageRoot = fixturePath.appending("Bar") + try await withKnownIssue { + try await fixture(name: "DependencyResolution/External/Simple") { fixturePath in + let packageRoot = fixturePath.appending("Bar") - // Build it. - try await executeSwiftBuild( - packageRoot, - configuration: data.config, - buildSystem: data.buildSystem, - ) - let buildPath = packageRoot.appending(".build") - let binPath = try buildPath.appending(components: data.buildSystem.binPath(for: data.config, scratchPath: [])) - let binFile = binPath.appending(executableName("Bar")) - expectFileExists(at: binFile) - #expect(localFileSystem.isDirectory(buildPath)) + // Build it. + try await executeSwiftBuild( + packageRoot, + configuration: data.config, + buildSystem: data.buildSystem, + ) + let buildPath = packageRoot.appending(".build") + let binPath = try buildPath.appending(components: data.buildSystem.binPath(for: data.config, scratchPath: [])) + let binFile = binPath.appending(executableName("Bar")) + expectFileExists(at: binFile) + #expect(localFileSystem.isDirectory(buildPath)) - // Clean, and check for removal of the build directory but not Packages. - _ = try await execute( - ["clean"], - packagePath: packageRoot, - configuration: data.config, - buildSystem: data.buildSystem, - ) - expectFileDoesNotExists(at: binFile) - // Clean again to ensure we get no error. - _ = try await execute( - ["clean"], - packagePath: packageRoot, - configuration: data.config, - buildSystem: data.buildSystem, - ) + // Clean, and check for removal of the build directory but not Packages. + _ = try await execute( + ["clean"], + packagePath: packageRoot, + configuration: data.config, + buildSystem: data.buildSystem, + ) + expectFileDoesNotExists(at: binFile) + // Clean again to ensure we get no error. + _ = try await execute( + ["clean"], + packagePath: packageRoot, + configuration: data.config, + buildSystem: data.buildSystem, + ) + } + } when: { + ProcessInfo.hostOperatingSystem == .windows && data.buildSystem == .swiftbuild } } @@ -2783,49 +2787,53 @@ struct PackageCommandTests { func packageReset( data: BuildData, ) async throws { - try await fixture(name: "DependencyResolution/External/Simple") { fixturePath in - let packageRoot = fixturePath.appending("Bar") + try await withKnownIssue { + try await fixture(name: "DependencyResolution/External/Simple") { fixturePath in + let packageRoot = fixturePath.appending("Bar") - // Build it. - try await executeSwiftBuild( - packageRoot, - configuration: data.config, - buildSystem: data.buildSystem - ) - let buildPath = packageRoot.appending(".build") - let binPath = try buildPath.appending(components: data.buildSystem.binPath(for: data.config, scratchPath: [], )) - let binFile = binPath.appending(executableName("Bar")) - expectFileExists(at: binFile) - #expect(localFileSystem.isDirectory(buildPath)) - // Clean, and check for removal of the build directory but not Packages. + // Build it. + try await executeSwiftBuild( + packageRoot, + configuration: data.config, + buildSystem: data.buildSystem + ) + let buildPath = packageRoot.appending(".build") + let binPath = try buildPath.appending(components: data.buildSystem.binPath(for: data.config, scratchPath: [], )) + let binFile = binPath.appending(executableName("Bar")) + expectFileExists(at: binFile) + #expect(localFileSystem.isDirectory(buildPath)) + // Clean, and check for removal of the build directory but not Packages. - _ = try await execute( - ["clean"], - packagePath: packageRoot, - configuration: data.config, - buildSystem: data.buildSystem, - ) - expectFileDoesNotExists(at: binFile) - try #expect( - !localFileSystem.getDirectoryContents(buildPath.appending("repositories")).isEmpty - ) + _ = try await execute( + ["clean"], + packagePath: packageRoot, + configuration: data.config, + buildSystem: data.buildSystem, + ) + expectFileDoesNotExists(at: binFile) + try #expect( + !localFileSystem.getDirectoryContents(buildPath.appending("repositories")).isEmpty + ) - // Fully clean. - _ = try await execute( - ["reset"], - packagePath: packageRoot, - configuration: data.config, - buildSystem: data.buildSystem, - ) - #expect(!localFileSystem.isDirectory(buildPath)) + // Fully clean. + _ = try await execute( + ["reset"], + packagePath: packageRoot, + configuration: data.config, + buildSystem: data.buildSystem, + ) + #expect(!localFileSystem.isDirectory(buildPath)) - // Test that we can successfully run reset again. - _ = try await execute( - ["reset"], - packagePath: packageRoot, - configuration: data.config, - buildSystem: data.buildSystem, - ) + // Test that we can successfully run reset again. + _ = try await execute( + ["reset"], + packagePath: packageRoot, + configuration: data.config, + buildSystem: data.buildSystem, + ) + } + } when: { + ProcessInfo.hostOperatingSystem == .windows && data.buildSystem == .swiftbuild } } @@ -3063,7 +3071,7 @@ struct PackageCommandTests { } } } when: { - ProcessInfo.hostOperatingSystem == .linux && data.buildSystem == .swiftbuild + [.windows, .linux].contains(ProcessInfo.hostOperatingSystem) && data.buildSystem == .swiftbuild } } diff --git a/Tests/IntegrationTests/SwiftPMTests.swift b/Tests/IntegrationTests/SwiftPMTests.swift index 5f93405658a..34ad0f9e3d7 100644 --- a/Tests/IntegrationTests/SwiftPMTests.swift +++ b/Tests/IntegrationTests/SwiftPMTests.swift @@ -122,7 +122,8 @@ private struct SwiftPMTests { #expect(!runOutput.stderr.contains("error:")) #expect(runOutput.stdout.contains("Hello, world!")) } when: { - (buildSystemProvider == .swiftbuild && .linux == ProcessInfo.hostOperatingSystem && CiEnvironment.runningInSelfHostedPipeline) + (buildSystemProvider == .swiftbuild && .windows == ProcessInfo.hostOperatingSystem) + || (buildSystemProvider == .swiftbuild && .linux == ProcessInfo.hostOperatingSystem && CiEnvironment.runningInSelfHostedPipeline) } } }