Skip to content

Commit 3950848

Browse files
authored
Merge pull request #10065 from owenv/owenv/modulemappath
Fix PIF MODULEMAP_PATH when a package has a hand-authored module map
2 parents 2c72f26 + 64dcc84 commit 3950848

3 files changed

Lines changed: 111 additions & 7 deletions

File tree

Sources/Basics/FileSystem/RelativePath.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,9 @@ extension TSCRelativePath {
164164
self = path.underlying
165165
}
166166
}
167+
168+
extension RelativePath {
169+
package var escapedPathString: String {
170+
self.pathString.replacing("\\", with: "\\\\")
171+
}
172+
}

Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Modules.swift

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -387,13 +387,12 @@ extension PackagePIFProjectBuilder {
387387
}
388388

389389
// Generate a module map file, if needed.
390-
var moduleMapFileContents = ""
391-
let generatedModuleMapDir = "$(GENERATED_MODULEMAP_DIR)"
392-
var generatedModuleMapPath = try RelativePath(validating:"\(generatedModuleMapDir)/\(sourceModule.name).modulemap").pathString
390+
let moduleMapFileContents: String?
391+
let moduleMapPath: String?
393392

394393
if sourceModule.usesSwift && desiredModuleType != .macro {
395394
// Generate ObjC compatibility header for Swift library targets.
396-
settings[.SWIFT_OBJC_INTERFACE_HEADER_DIR] = generatedModuleMapDir
395+
settings[.SWIFT_OBJC_INTERFACE_HEADER_DIR] = "$(GENERATED_MODULEMAP_DIR)"
397396
settings[.SWIFT_OBJC_INTERFACE_HEADER_NAME] = "\(sourceModule.name)-Swift.h"
398397

399398
moduleMapFileContents = """
@@ -402,6 +401,8 @@ extension PackagePIFProjectBuilder {
402401
export *
403402
}
404403
"""
404+
let generatedModuleMapPath = try RelativePath(validating:"$(GENERATED_MODULEMAP_DIR)/\(sourceModule.name).modulemap").pathString
405+
moduleMapPath = generatedModuleMapPath
405406
// We only need to impart this to C clients.
406407
impartedSettings[.OTHER_CFLAGS] = ["-fmodule-map-file=\(generatedModuleMapPath)", "$(inherited)"]
407408
} else {
@@ -418,13 +419,18 @@ extension PackagePIFProjectBuilder {
418419
// The modulemap was already generated, we should explicitly impart it on dependents,
419420
impartedSettings[.OTHER_CFLAGS] = ["-fmodule-map-file=\(pluginGeneratedModuleMapPath)", "$(inherited)"]
420421
impartedSettings[.OTHER_SWIFT_FLAGS] = ["-Xcc", "-fmodule-map-file=\(pluginGeneratedModuleMapPath)", "$(inherited)"]
421-
generatedModuleMapPath = pluginGeneratedModuleMapPath.pathString
422+
moduleMapFileContents = nil
423+
moduleMapPath = pluginGeneratedModuleMapPath.pathString
422424
} else {
423425
switch sourceModule.moduleMapType {
424426
case nil, .some(.none):
425427
// No modulemap, no action required.
428+
moduleMapFileContents = nil
429+
moduleMapPath = nil
426430
break
427431
case .custom(let customModuleMapPath):
432+
moduleMapFileContents = nil
433+
moduleMapPath = customModuleMapPath.pathString
428434
// We don't need to generate a modulemap, but we should explicitly impart it on dependents,
429435
// even if it will appear in search paths. See: https://github.com/swiftlang/swift-package-manager/issues/9290
430436
impartedSettings[.OTHER_CFLAGS] = ["-fmodule-map-file=\(customModuleMapPath)", "$(inherited)"]
@@ -437,6 +443,8 @@ extension PackagePIFProjectBuilder {
437443
export *
438444
}
439445
"""
446+
let generatedModuleMapPath = try RelativePath(validating:"$(GENERATED_MODULEMAP_DIR)/\(sourceModule.name).modulemap").pathString
447+
moduleMapPath = generatedModuleMapPath
440448
// Pass the path of the module map up to all direct and indirect clients.
441449
impartedSettings[.OTHER_CFLAGS] = ["-fmodule-map-file=\(generatedModuleMapPath)", "$(inherited)"]
442450
impartedSettings[.OTHER_SWIFT_FLAGS] = ["-Xcc", "-fmodule-map-file=\(generatedModuleMapPath)", "$(inherited)"]
@@ -448,6 +456,8 @@ extension PackagePIFProjectBuilder {
448456
export *
449457
}
450458
"""
459+
let generatedModuleMapPath = try RelativePath(validating:"$(GENERATED_MODULEMAP_DIR)/\(sourceModule.name).modulemap").pathString
460+
moduleMapPath = generatedModuleMapPath
451461
// Pass the path of the module map up to all direct and indirect clients.
452462
impartedSettings[.OTHER_CFLAGS] = ["-fmodule-map-file=\(generatedModuleMapPath)", "$(inherited)"]
453463
impartedSettings[.OTHER_SWIFT_FLAGS] = ["-Xcc", "-fmodule-map-file=\(generatedModuleMapPath)", "$(inherited)"]
@@ -524,8 +534,12 @@ extension PackagePIFProjectBuilder {
524534
}
525535

526536
settings[.PACKAGE_RESOURCE_TARGET_KIND] = "regular"
527-
settings[.MODULEMAP_FILE_CONTENTS] = moduleMapFileContents
528-
settings[.MODULEMAP_PATH] = generatedModuleMapPath
537+
if let moduleMapFileContents {
538+
settings[.MODULEMAP_FILE_CONTENTS] = moduleMapFileContents
539+
}
540+
if let moduleMapPath {
541+
settings[.MODULEMAP_PATH] = moduleMapPath
542+
}
529543
settings[.DEFINES_MODULE] = "YES"
530544

531545
// Settings for text-based API.

Tests/SwiftBuildSupportTests/PIFBuilderTests.swift

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,90 @@ struct PIFBuilderTests {
679679
}
680680
}
681681

682+
@Test func moduleMapPathAndContents() async throws {
683+
try await withGeneratedPIF(fromFixture: "PIFBuilder/Library") { pif, observabilitySystem in
684+
#expect(observabilitySystem.diagnostics.filter { $0.severity == .error }.isEmpty)
685+
686+
let releaseConfig = try pif.workspace
687+
.project(named: "Library")
688+
.target(named: "Library")
689+
.buildConfig(named: .release)
690+
691+
let expectedPath = try RelativePath(validating: "$(GENERATED_MODULEMAP_DIR)/Library.modulemap").pathString
692+
#expect(releaseConfig.settings[.MODULEMAP_PATH] == expectedPath)
693+
#expect(releaseConfig.settings[.MODULEMAP_FILE_CONTENTS] == """
694+
module Library {
695+
header "Library-Swift.h"
696+
export *
697+
}
698+
""")
699+
}
700+
701+
try await withGeneratedPIF(fromFixture: "CFamilyTargets/ModuleMapGenerationCases") { pif, observabilitySystem in
702+
#expect(observabilitySystem.diagnostics.filter { $0.severity == .error }.isEmpty)
703+
704+
let project = try pif.workspace.project(named: "ModuleMapGenerationCases")
705+
706+
do {
707+
let releaseConfig = try project
708+
.target(named: "NoIncludeDir")
709+
.buildConfig(named: .release)
710+
711+
#expect(releaseConfig.settings[.MODULEMAP_PATH] == nil)
712+
#expect(releaseConfig.settings[.MODULEMAP_FILE_CONTENTS] == nil)
713+
}
714+
715+
do {
716+
let releaseConfig = try project
717+
.target(named: "CustomModuleMap")
718+
.buildConfig(named: .release)
719+
720+
let path = try #require(releaseConfig.settings[.MODULEMAP_PATH])
721+
#expect(path.hasSuffix(RelativePath("CustomModuleMap")
722+
.appending(components: ["include", "module.modulemap"]).pathString))
723+
#expect(!path.contains("$(GENERATED_MODULEMAP_DIR)"))
724+
#expect(releaseConfig.settings[.MODULEMAP_FILE_CONTENTS] == nil)
725+
}
726+
727+
do {
728+
let releaseConfig = try project
729+
.target(named: "UmbrellaHeader")
730+
.buildConfig(named: .release)
731+
732+
let expectedPath = try RelativePath(
733+
validating: "$(GENERATED_MODULEMAP_DIR)/UmbrellaHeader.modulemap"
734+
).pathString
735+
#expect(releaseConfig.settings[.MODULEMAP_PATH] == expectedPath)
736+
737+
let contents = try #require(releaseConfig.settings[.MODULEMAP_FILE_CONTENTS])
738+
#expect(contents.hasPrefix("module UmbrellaHeader {"))
739+
#expect(contents.contains("umbrella header \""))
740+
#expect(contents.contains(RelativePath("UmbrellaHeader")
741+
.appending(components: ["include", "UmbrellaHeader", "UmbrellaHeader.h"]).escapedPathString))
742+
#expect(contents.contains("export *"))
743+
}
744+
745+
do {
746+
let releaseConfig = try project
747+
.target(named: "UmbrellaDirectoryInclude")
748+
.buildConfig(named: .release)
749+
750+
let expectedPath = try RelativePath(
751+
validating: "$(GENERATED_MODULEMAP_DIR)/UmbrellaDirectoryInclude.modulemap"
752+
).pathString
753+
#expect(releaseConfig.settings[.MODULEMAP_PATH] == expectedPath)
754+
755+
let contents = try #require(releaseConfig.settings[.MODULEMAP_FILE_CONTENTS])
756+
#expect(contents.hasPrefix("module UmbrellaDirectoryInclude {"))
757+
#expect(contents.contains("umbrella \""))
758+
#expect(!contents.contains("umbrella header"))
759+
#expect(contents.contains(RelativePath("UmbrellaDirectoryInclude")
760+
.appending(component: "include").escapedPathString))
761+
#expect(contents.contains("export *"))
762+
}
763+
}
764+
}
765+
682766
@Test func disablingLocalRpaths() async throws {
683767
try await withGeneratedPIF(fromFixture: "Miscellaneous/Simple") { pif, observabilitySystem in
684768
#expect(observabilitySystem.diagnostics.filter {

0 commit comments

Comments
 (0)