@@ -246,7 +246,7 @@ private func createResolvedPackages(
246
246
247
247
// Resolve module aliases, if specified, for targets and their dependencies
248
248
// across packages. Aliasing will result in target renaming.
249
- try resolveModuleAliases ( packageBuilders: packageBuilders)
249
+ let moduleAliasingUsed = try resolveModuleAliases ( packageBuilders: packageBuilders)
250
250
251
251
// Scan and validate the dependencies
252
252
for packageBuilder in packageBuilders {
@@ -383,25 +383,67 @@ private func createResolvedPackages(
383
383
}
384
384
385
385
// Find duplicate products in the package graph.
386
- let duplicateProducts = packageBuilders
387
- . flatMap ( { $0. products } )
388
- . map ( { $0. product } )
389
- . spm_findDuplicateElements ( by: \. name)
390
- . map ( { $0 [ 0 ] . name } )
391
-
392
- // Emit diagnostics for duplicate products.
393
- for productName in duplicateProducts {
394
- let packages = packageBuilders
395
- . filter ( { $0. products. contains ( where: { $0. product. name == productName } ) } )
396
- . map { $0. package . identity. description }
397
- . sorted ( )
398
-
399
- observabilityScope. emit ( PackageGraphError . duplicateProduct ( product: productName, packages: packages) )
400
- }
401
-
402
- // Remove the duplicate products from the builders.
403
- for packageBuilder in packageBuilders {
404
- packageBuilder. products = packageBuilder. products. filter ( { !duplicateProducts. contains ( $0. product. name) } )
386
+ let productList = packageBuilders. flatMap ( { $0. products } ) . map ( { $0. product } )
387
+
388
+ if moduleAliasingUsed {
389
+ // FIXME: If moduleAliasingUsed, we want to allow duplicate product names
390
+ // from different packages as often times the product name of a package is
391
+ // same as its target name which might have a conflict with the name of the
392
+ // product itself or its target from another package.
393
+ // The following is a workaround; eventually we want to allow duplicate product
394
+ // names even when module aliasing is not used, which is a cleaner solution.
395
+ // Ref rdar://94744134.
396
+
397
+ // We first divide the products by type which determines whether to use
398
+ // the product ID (unique, fully qualified name) or name to look up duplicates.
399
+
400
+ // There are no shared dirs/files created for automatic library products, so look
401
+ // up duplicates with the ID property for those products.
402
+ let autoLibProducts = productList
403
+ . filter { $0. isDefaultLibrary }
404
+ . spm_findDuplicateElements ( by: \. ID)
405
+ . map ( { $0 [ 0 ] } )
406
+
407
+ // Building other products, i.e. static libs, dylibs, executables, result in
408
+ // shared dirs/files, e.g. Foo.product (dir), libFoo.dylib, etc., so we want
409
+ // to keep the original product names for those. Thus, use the name property
410
+ // to look up duplicates.
411
+ let otherProducts = productList
412
+ . filter { !$0. isDefaultLibrary }
413
+ . spm_findDuplicateElements ( by: \. name)
414
+ . map ( { $0 [ 0 ] } )
415
+
416
+ let allProducts = autoLibProducts + otherProducts
417
+ // Emit diagnostics for duplicate products.
418
+ for dupProduct in allProducts {
419
+ let packages = packageBuilders
420
+ . filter ( { $0. products. contains ( where: { $0. product. isDefaultLibrary ? $0. product. ID == dupProduct. ID : $0. product. name == dupProduct. name } ) } )
421
+ . map { $0. package . identity. description }
422
+ . sorted ( )
423
+ observabilityScope. emit ( PackageGraphError . duplicateProduct ( product: dupProduct. name, packages: packages) )
424
+ }
425
+ // Remove the duplicate products from the builders.
426
+ let autoLibProductIDs = autoLibProducts. map { $0. ID }
427
+ let otherProductNames = otherProducts. map { $0. name }
428
+ for packageBuilder in packageBuilders {
429
+ packageBuilder. products = packageBuilder. products. filter { $0. product. isDefaultLibrary ? !autoLibProductIDs. contains ( $0. product. ID) : !otherProductNames. contains ( $0. product. name) }
430
+ }
431
+ } else {
432
+ let duplicateProducts = productList
433
+ . spm_findDuplicateElements ( by: \. name)
434
+ . map ( { $0 [ 0 ] } )
435
+ // Emit diagnostics for duplicate products.
436
+ for dupProduct in duplicateProducts {
437
+ let packages = packageBuilders
438
+ . filter ( { $0. products. contains ( where: { $0. product. name == dupProduct. name } ) } )
439
+ . map { $0. package . identity. description }
440
+ . sorted ( )
441
+ observabilityScope. emit ( PackageGraphError . duplicateProduct ( product: dupProduct. name, packages: packages) )
442
+ }
443
+ // Remove the duplicate products from the builders.
444
+ for packageBuilder in packageBuilders {
445
+ packageBuilder. products = packageBuilder. products. filter { !duplicateProducts. map { $0. name} . contains ( $0. product. name) }
446
+ }
405
447
}
406
448
407
449
// The set of all target names.
@@ -436,7 +478,7 @@ private func createResolvedPackages(
436
478
let explicit = Set ( dependency. package . manifest. products. lazy. map ( { $0. name } ) )
437
479
return dependency. products. filter ( { explicit. contains ( $0. product. name) } )
438
480
} )
439
- let productDependencyMap = productDependencies. spm_createDictionary ( { ( $0. product. name, $0) } )
481
+ let productDependencyMap = moduleAliasingUsed ? productDependencies . spm_createDictionary ( { ( $0 . product . ID , $0 ) } ) : productDependencies. spm_createDictionary ( { ( $0. product. name, $0) } )
440
482
441
483
// Establish dependencies in each target.
442
484
for targetBuilder in packageBuilder. targets {
@@ -449,7 +491,9 @@ private func createResolvedPackages(
449
491
// Establish product dependencies.
450
492
for case . product( let productRef, let conditions) in targetBuilder. target. dependencies {
451
493
// Find the product in this package's dependency products.
452
- guard let product = productDependencyMap [ productRef. name] else {
494
+ // Look it up by ID if module aliasing is used, otherwise by name.
495
+ let product = moduleAliasingUsed ? productDependencyMap [ productRef. ID] : productDependencyMap [ productRef. name]
496
+ guard let product = product else {
453
497
// Only emit a diagnostic if there are no other diagnostics.
454
498
// This avoids flooding the diagnostics with product not
455
499
// found errors when there are more important errors to
@@ -514,9 +558,16 @@ private func createResolvedPackages(
514
558
}
515
559
}
516
560
}
561
+
517
562
return try packageBuilders. map { try $0. construct ( ) }
518
563
}
519
564
565
+ fileprivate extension Product {
566
+ var isDefaultLibrary : Bool {
567
+ return type == . library( . automatic)
568
+ }
569
+ }
570
+
520
571
private func computePlatforms(
521
572
package : Package ,
522
573
usingXCTest: Bool ,
@@ -590,7 +641,7 @@ private func computePlatforms(
590
641
}
591
642
592
643
// Track and override module aliases specified for targets in a package graph
593
- private func resolveModuleAliases( packageBuilders: [ ResolvedPackageBuilder ] ) throws {
644
+ private func resolveModuleAliases( packageBuilders: [ ResolvedPackageBuilder ] ) throws -> Bool {
594
645
595
646
// If there are no module aliases specified, return early
596
647
let hasAliases = packageBuilders. contains { $0. package . targets. contains {
@@ -603,7 +654,7 @@ private func resolveModuleAliases(packageBuilders: [ResolvedPackageBuilder]) thr
603
654
}
604
655
}
605
656
606
- guard hasAliases else { return }
657
+ guard hasAliases else { return false }
607
658
let aliasTracker = ModuleAliasTracker ( )
608
659
for packageBuilder in packageBuilders {
609
660
try aliasTracker. addTargetAliases ( targets: packageBuilder. package . targets,
@@ -626,10 +677,11 @@ private func resolveModuleAliases(packageBuilders: [ResolvedPackageBuilder]) thr
626
677
// upstream can be overriden.
627
678
for packageBuilder in packageBuilders {
628
679
for product in packageBuilder. package . products {
629
- try aliasTracker. validateAndApplyAliases ( product: product. name ,
680
+ try aliasTracker. validateAndApplyAliases ( product: product,
630
681
package : packageBuilder. package . identity)
631
682
}
632
683
}
684
+ return true
633
685
}
634
686
635
687
/// A generic builder for `Resolved` models.
0 commit comments