Skip to content

Commit 6083a00

Browse files
committed
Expose internal headers to Swift-half of target
1 parent 8ba7789 commit 6083a00

File tree

1 file changed

+113
-40
lines changed

1 file changed

+113
-40
lines changed

Sources/Build/BuildPlan.swift

Lines changed: 113 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -329,8 +329,20 @@ public final class ClangTargetBuildDescription {
329329
self.derivedSources = Sources(paths: [], root: tempsPath.appending(component: "DerivedSources"))
330330
self.isWithinMixedTarget = isWithinMixedTarget
331331

332-
// Try computing modulemap path for a C library. This also creates the file in the file system, if needed.
333-
if target.type == .library {
332+
// Try computing the modulemap path, creating a module map in the
333+
// file system if necessary, for either a Clang source library or a
334+
// Clang source test target being built within a mixed test target,
335+
// The latter of which is allowed to support sharing test utilities
336+
// between mixed language test files within a single test target.
337+
if target.type == .library || (target.type == .test && isWithinMixedTarget) {
338+
339+
let moduleMapGenerator = ModuleMapGenerator(
340+
targetName: clangTarget.name,
341+
moduleName: clangTarget.c99name,
342+
publicHeadersDir: clangTarget.includeDir,
343+
fileSystem: fileSystem
344+
)
345+
334346
if case .custom(let customModuleMapPath) = clangTarget.moduleMapType {
335347
if isWithinMixedTarget {
336348
let customModuleMapContents: String = try fileSystem.readFileContents(customModuleMapPath)
@@ -370,21 +382,29 @@ public final class ClangTargetBuildDescription {
370382

371383
self.moduleMap = writePath
372384

373-
// The unextended module map purposefully excludes the
374-
// generated Swift header. This is so, when compiling the
375-
// mixed target's Swift part, the generated Swift header is
376-
// not considered an input (the header is an output of
377-
// compiling the mixed target's Swift part).
378-
//
379-
// At this point, the custom module map has been checked
380-
// that it does not include the Swift submodule. For that
381-
// reason, it can be copied to the build directory to
382-
// double as the unextended module map.
383-
try? fileSystem.copy(
384-
from: customModuleMapPath,
385-
to: tempsPath
386-
.appending(component: "Product")
387-
.appending(component: unextendedModuleMapFilename)
385+
// Intermediates module maps
386+
let intermediateModuleMapPath = tempsPath
387+
.appending(component: "Intermediates")
388+
.appending(component: moduleMapFilename)
389+
try moduleMapGenerator.generateModuleMap(
390+
type: .umbrellaDirectory(tempsPath.appending(component: "Intermediates")),
391+
at: intermediateModuleMapPath,
392+
addSwiftSubmodule: true
393+
)
394+
// The underlying Clang target is building within a Mixed
395+
// language target and needs an auxiliary module map that
396+
// doesn't include the generated interop header from the
397+
// Swift half of the mixed target. This will later allow the
398+
// Clang half of the module to be built when compiling the
399+
// Swift part without the generated header being considered
400+
// an input (because it won't exist yet and is an output of
401+
// that compilation command).
402+
let unextendedModuleMapPath = tempsPath
403+
.appending(component: "Intermediates")
404+
.appending(component: unextendedModuleMapFilename)
405+
try moduleMapGenerator.generateModuleMap(
406+
type: .umbrellaDirectory(tempsPath.appending(component: "Intermediates")),
407+
at: unextendedModuleMapPath
388408
)
389409
} else {
390410
// When not building within a mixed target, use the custom
@@ -394,13 +414,6 @@ public final class ClangTargetBuildDescription {
394414
}
395415
// If a generated module map is needed, generate one now in our temporary directory.
396416
else if let generatedModuleMapType = clangTarget.moduleMapType.generatedModuleMapType {
397-
let moduleMapGenerator = ModuleMapGenerator(
398-
targetName: clangTarget.name,
399-
moduleName: clangTarget.c99name,
400-
publicHeadersDir: clangTarget.includeDir,
401-
fileSystem: fileSystem
402-
)
403-
404417
let moduleMapPath = tempsPath
405418
.appending(component: "Product")
406419
.appending(component: moduleMapFilename)
@@ -411,6 +424,14 @@ public final class ClangTargetBuildDescription {
411424
)
412425

413426
if isWithinMixedTarget {
427+
let intermediateModuleMapPath = tempsPath
428+
.appending(component: "Intermediates")
429+
.appending(component: moduleMapFilename)
430+
try moduleMapGenerator.generateModuleMap(
431+
type: .umbrellaDirectory(tempsPath.appending(component: "Intermediates")),
432+
at: intermediateModuleMapPath,
433+
addSwiftSubmodule: true
434+
)
414435
// The underlying Clang target is building within a Mixed
415436
// language target and needs an auxiliary module map that
416437
// doesn't include the generated interop header from the
@@ -420,10 +441,10 @@ public final class ClangTargetBuildDescription {
420441
// an input (because it won't exist yet and is an output of
421442
// that compilation command).
422443
let unextendedModuleMapPath = tempsPath
423-
.appending(component: "Product")
444+
.appending(component: "Intermediates")
424445
.appending(component: unextendedModuleMapFilename)
425446
try moduleMapGenerator.generateModuleMap(
426-
type: generatedModuleMapType,
447+
type: .umbrellaDirectory(tempsPath.appending(component: "Intermediates")),
427448
at: unextendedModuleMapPath
428449
)
429450
}
@@ -1233,7 +1254,8 @@ public final class SwiftTargetBuildDescription {
12331254

12341255
/// Returns true if ObjC compatibility header should be emitted.
12351256
private var shouldEmitObjCCompatibilityHeader: Bool {
1236-
return buildParameters.triple.isDarwin() && target.type == .library
1257+
return buildParameters.triple.isDarwin() &&
1258+
(target.type == .library || target.type == .test && isWithinMixedTarget)
12371259
}
12381260

12391261
private func writeOutputFileMap() throws -> AbsolutePath {
@@ -1504,42 +1526,93 @@ public final class MixedTargetBuildDescription {
15041526
isWithinMixedTarget: true
15051527
)
15061528

1507-
if target.type == .library {
1529+
if target.type == .library || target.type == .test {
15081530
// Compiling the mixed target will require a Clang VFS overlay file
15091531
// with mappings to the target's module map and public headers.
15101532
let publicHeadersPath = clangTargetBuildDescription.clangTarget.includeDir
1511-
let buildArtifactDirectory = swiftTargetBuildDescription.tempsPath
1512-
let buildArtifactProductDirectory = buildArtifactDirectory.appending(component: "Product")
15131533
let generatedInteropHeaderPath = swiftTargetBuildDescription.objCompatibilityHeaderPath
1514-
let allProductHeadersPath = buildArtifactDirectory
1534+
1535+
let buildArtifactDirectory = swiftTargetBuildDescription.tempsPath
1536+
let allProductHeadersPathProduct = buildArtifactDirectory
1537+
.appending(component: "Product")
1538+
.appending(component: "all-product-headers.yaml")
1539+
1540+
let buildArtifactIntermediatesDirectory = buildArtifactDirectory
1541+
.appending(component: "Intermediates")
1542+
1543+
let allProductHeadersPath = buildArtifactIntermediatesDirectory
15151544
.appending(component: "all-product-headers.yaml")
15161545

15171546
// The auxilliary module map is passed to the Clang compiler
15181547
// via a VFS overlay, represented by the below YAML file.
1519-
let unextendedModuleMapOverlayPath = buildArtifactDirectory
1548+
let unextendedModuleMapOverlayPath = buildArtifactIntermediatesDirectory
15201549
.appending(component: "unextended-module-overlay.yaml")
15211550
try VFSOverlay(roots: [
15221551
VFSOverlay.Directory(
1523-
name: buildArtifactProductDirectory.pathString,
1552+
name: buildArtifactIntermediatesDirectory.pathString,
15241553
contents: [
15251554
VFSOverlay.File(
15261555
name: moduleMapFilename,
1527-
externalContents: buildArtifactProductDirectory
1556+
externalContents: buildArtifactIntermediatesDirectory
15281557
.appending(component: unextendedModuleMapFilename)
15291558
.pathString
15301559
)
15311560
]
15321561
)
15331562
]).write(to: unextendedModuleMapOverlayPath, fileSystem: fileSystem)
15341563

1564+
// TODO(ncooke3): Use @resultBuilder for this.
1565+
var roots = [
1566+
VFSOverlay.Directory(
1567+
name: buildArtifactIntermediatesDirectory.pathString,
1568+
contents:
1569+
// All headers
1570+
try VFSOverlay.overlayResources(
1571+
// TODO(ncooke3): Figure out a way to get the root sources path.
1572+
directoryPath: publicHeadersPath.parentDirectory,
1573+
fileSystem: fileSystem,
1574+
shouldInclude: {
1575+
// Only include headers.
1576+
fileSystem.isDirectory($0) || $0.pathString.hasSuffix(".h")
1577+
}
1578+
) + [
1579+
VFSOverlay.File(
1580+
name: generatedInteropHeaderPath.basename,
1581+
externalContents: generatedInteropHeaderPath.pathString
1582+
)
1583+
]
1584+
)
1585+
]
1586+
1587+
if case .custom(let customModuleMapPath) = clangTargetBuildDescription.clangTarget.moduleMapType {
1588+
roots.append(
1589+
VFSOverlay.Directory(
1590+
name: customModuleMapPath.parentDirectory.pathString,
1591+
contents: [
1592+
VFSOverlay.File(
1593+
name: customModuleMapPath.basename,
1594+
externalContents: buildArtifactIntermediatesDirectory
1595+
.appending(component: "module.modulemap")
1596+
.pathString
1597+
)
1598+
]
1599+
)
1600+
)
1601+
}
1602+
15351603
// TODO(ncooke3): What happens if a custom module map exists with a
15361604
// name other than `module.modulemap`?
1605+
try VFSOverlay(roots: roots)
1606+
.write(to: allProductHeadersPath, fileSystem: fileSystem)
1607+
1608+
// For Product directory
15371609
try VFSOverlay(roots: [
15381610
VFSOverlay.Directory(
1539-
name: buildArtifactProductDirectory.pathString,
1611+
name: buildArtifactDirectory
1612+
.appending(component: "Product").pathString,
15401613
contents:
15411614
// Public headers
1542-
try VFSOverlay.overlayResources(
1615+
try VFSOverlay.overlayResources(
15431616
directoryPath: publicHeadersPath,
15441617
fileSystem: fileSystem,
15451618
shouldInclude: {
@@ -1555,15 +1628,15 @@ public final class MixedTargetBuildDescription {
15551628
)
15561629
]
15571630
)
1558-
]).write(to: allProductHeadersPath, fileSystem: fileSystem)
1631+
]).write(to: allProductHeadersPathProduct, fileSystem: fileSystem)
15591632

15601633
swiftTargetBuildDescription.additionalFlags += [
15611634
// Builds Objective-C portion of module.
15621635
"-import-underlying-module",
15631636
// Add the location of the module's Objective-C module map as
15641637
// a header search path.
15651638
"-I",
1566-
buildArtifactProductDirectory.pathString
1639+
buildArtifactIntermediatesDirectory.pathString
15671640
]
15681641

15691642
swiftTargetBuildDescription.appendClangFlags(
@@ -1579,12 +1652,12 @@ public final class MixedTargetBuildDescription {
15791652
// generated interop Swift header.
15801653
clangTargetBuildDescription.additionalFlags += [
15811654
"-I",
1582-
buildArtifactProductDirectory.pathString,
1655+
buildArtifactIntermediatesDirectory.pathString,
15831656
"-ivfsoverlay",
15841657
allProductHeadersPath.pathString
15851658
]
15861659

1587-
self.allProductHeadersOverlay = allProductHeadersPath
1660+
self.allProductHeadersOverlay = allProductHeadersPathProduct
15881661
}
15891662
}
15901663
}

0 commit comments

Comments
 (0)