@@ -329,8 +329,20 @@ public final class ClangTargetBuildDescription {
329
329
self . derivedSources = Sources ( paths: [ ] , root: tempsPath. appending ( component: " DerivedSources " ) )
330
330
self . isWithinMixedTarget = isWithinMixedTarget
331
331
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
+
334
346
if case . custom( let customModuleMapPath) = clangTarget. moduleMapType {
335
347
if isWithinMixedTarget {
336
348
let customModuleMapContents : String = try fileSystem. readFileContents ( customModuleMapPath)
@@ -370,21 +382,29 @@ public final class ClangTargetBuildDescription {
370
382
371
383
self . moduleMap = writePath
372
384
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
388
408
)
389
409
} else {
390
410
// When not building within a mixed target, use the custom
@@ -394,13 +414,6 @@ public final class ClangTargetBuildDescription {
394
414
}
395
415
// If a generated module map is needed, generate one now in our temporary directory.
396
416
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
-
404
417
let moduleMapPath = tempsPath
405
418
. appending ( component: " Product " )
406
419
. appending ( component: moduleMapFilename)
@@ -411,6 +424,14 @@ public final class ClangTargetBuildDescription {
411
424
)
412
425
413
426
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
+ )
414
435
// The underlying Clang target is building within a Mixed
415
436
// language target and needs an auxiliary module map that
416
437
// doesn't include the generated interop header from the
@@ -420,10 +441,10 @@ public final class ClangTargetBuildDescription {
420
441
// an input (because it won't exist yet and is an output of
421
442
// that compilation command).
422
443
let unextendedModuleMapPath = tempsPath
423
- . appending ( component: " Product " )
444
+ . appending ( component: " Intermediates " )
424
445
. appending ( component: unextendedModuleMapFilename)
425
446
try moduleMapGenerator. generateModuleMap (
426
- type: generatedModuleMapType ,
447
+ type: . umbrellaDirectory ( tempsPath . appending ( component : " Intermediates " ) ) ,
427
448
at: unextendedModuleMapPath
428
449
)
429
450
}
@@ -1233,7 +1254,8 @@ public final class SwiftTargetBuildDescription {
1233
1254
1234
1255
/// Returns true if ObjC compatibility header should be emitted.
1235
1256
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)
1237
1259
}
1238
1260
1239
1261
private func writeOutputFileMap( ) throws -> AbsolutePath {
@@ -1504,42 +1526,93 @@ public final class MixedTargetBuildDescription {
1504
1526
isWithinMixedTarget: true
1505
1527
)
1506
1528
1507
- if target. type == . library {
1529
+ if target. type == . library || target . type == . test {
1508
1530
// Compiling the mixed target will require a Clang VFS overlay file
1509
1531
// with mappings to the target's module map and public headers.
1510
1532
let publicHeadersPath = clangTargetBuildDescription. clangTarget. includeDir
1511
- let buildArtifactDirectory = swiftTargetBuildDescription. tempsPath
1512
- let buildArtifactProductDirectory = buildArtifactDirectory. appending ( component: " Product " )
1513
1533
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
1515
1544
. appending ( component: " all-product-headers.yaml " )
1516
1545
1517
1546
// The auxilliary module map is passed to the Clang compiler
1518
1547
// via a VFS overlay, represented by the below YAML file.
1519
- let unextendedModuleMapOverlayPath = buildArtifactDirectory
1548
+ let unextendedModuleMapOverlayPath = buildArtifactIntermediatesDirectory
1520
1549
. appending ( component: " unextended-module-overlay.yaml " )
1521
1550
try VFSOverlay ( roots: [
1522
1551
VFSOverlay . Directory (
1523
- name: buildArtifactProductDirectory . pathString,
1552
+ name: buildArtifactIntermediatesDirectory . pathString,
1524
1553
contents: [
1525
1554
VFSOverlay . File (
1526
1555
name: moduleMapFilename,
1527
- externalContents: buildArtifactProductDirectory
1556
+ externalContents: buildArtifactIntermediatesDirectory
1528
1557
. appending ( component: unextendedModuleMapFilename)
1529
1558
. pathString
1530
1559
)
1531
1560
]
1532
1561
)
1533
1562
] ) . write ( to: unextendedModuleMapOverlayPath, fileSystem: fileSystem)
1534
1563
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
+
1535
1603
// TODO(ncooke3): What happens if a custom module map exists with a
1536
1604
// name other than `module.modulemap`?
1605
+ try VFSOverlay ( roots: roots)
1606
+ . write ( to: allProductHeadersPath, fileSystem: fileSystem)
1607
+
1608
+ // For Product directory
1537
1609
try VFSOverlay ( roots: [
1538
1610
VFSOverlay . Directory (
1539
- name: buildArtifactProductDirectory. pathString,
1611
+ name: buildArtifactDirectory
1612
+ . appending ( component: " Product " ) . pathString,
1540
1613
contents:
1541
1614
// Public headers
1542
- try VFSOverlay . overlayResources (
1615
+ try VFSOverlay . overlayResources (
1543
1616
directoryPath: publicHeadersPath,
1544
1617
fileSystem: fileSystem,
1545
1618
shouldInclude: {
@@ -1555,15 +1628,15 @@ public final class MixedTargetBuildDescription {
1555
1628
)
1556
1629
]
1557
1630
)
1558
- ] ) . write ( to: allProductHeadersPath , fileSystem: fileSystem)
1631
+ ] ) . write ( to: allProductHeadersPathProduct , fileSystem: fileSystem)
1559
1632
1560
1633
swiftTargetBuildDescription. additionalFlags += [
1561
1634
// Builds Objective-C portion of module.
1562
1635
" -import-underlying-module " ,
1563
1636
// Add the location of the module's Objective-C module map as
1564
1637
// a header search path.
1565
1638
" -I " ,
1566
- buildArtifactProductDirectory . pathString
1639
+ buildArtifactIntermediatesDirectory . pathString
1567
1640
]
1568
1641
1569
1642
swiftTargetBuildDescription. appendClangFlags (
@@ -1579,12 +1652,12 @@ public final class MixedTargetBuildDescription {
1579
1652
// generated interop Swift header.
1580
1653
clangTargetBuildDescription. additionalFlags += [
1581
1654
" -I " ,
1582
- buildArtifactProductDirectory . pathString,
1655
+ buildArtifactIntermediatesDirectory . pathString,
1583
1656
" -ivfsoverlay " ,
1584
1657
allProductHeadersPath. pathString
1585
1658
]
1586
1659
1587
- self . allProductHeadersOverlay = allProductHeadersPath
1660
+ self . allProductHeadersOverlay = allProductHeadersPathProduct
1588
1661
}
1589
1662
}
1590
1663
}
0 commit comments