swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.09k stars 10.33k forks source link

Enabling library evolution breaks module aliasing #71883

Open nesium opened 5 months ago

nesium commented 5 months ago

Description

Hello!

Aliasing immediate and transient dependencies in a Swift package breaks builds with Swift 5.9.2 (Xcode 15.2) when library evolution is enabled. It fails with an error like this:

error: cannot refer to module as 'MyLibClocks' because it has been aliased; use 'Clocks' instead
@_exported import MyLibClocks
                  ^~~~~~~~~~~
                  Clocks

The following build commands failed:
  SwiftVerifyEmittedModuleInterface normal arm64 Verifying emitted module interface MyLibClocks.private.swiftinterface TRUNCATED/MyLibClocks.build/Objects-normal/arm64/MyLibClocks.private.swiftinterface (in target 'MyLibClocks' from project 'swift-clocks')
(1 failure)

The build used to work with Swift 5.7.2 (Xcode 14.2).

Reproduction

The issue can easily be reproduced by trying to build the following Swift package…

// swift-tools-version: 5.7

import PackageDescription

let package = Package(
  name: "my-library",
  platforms: [.iOS(.v13), .macOS(.v10_15), .macCatalyst(.v14)],
  products: [
    .library(name: "MyLibrary", targets: ["MyLibrary"]),
  ],
  dependencies: [
    .package(
      url: "https://github.com/pointfreeco/swift-composable-architecture.git",
      from: "1.8.2"
    ),
  ],
  targets: [
    .target(
      name: "MyLibrary",
      dependencies: [
        .product(
          name: "ComposableArchitecture",
          package: "swift-composable-architecture",
          moduleAliases: [
            "CasePaths": "MyLibCasePaths",
            "Clocks": "MyLibClocks",
            "CombineSchedulers": "MyLibCombineSchedulers",
            "ComposableArchitecture": "MyLibComposableArchitecture",
            "CustomDump": "MyLibCustomDump",
            "Dependencies": "MyLibDependencies",
            "IdentifiedCollections": "MyLibIdentifiedCollections",
            "OrderedCollections": "MyLibOrderedCollections",
            "SwiftUINavigation": "MyLibSwiftUINavigation",
            "XCTestDynamicOverlay": "MyLibXCTestDynamicOverlay",
          ]
        ),
      ]
    ),
  ]
)

… with the following build script…

#!/bin/bash
set -e

# Resolves the package dependencies and removes docc bundles. 
# 
# Otherwise the build with module aliasing fails on Xcode 14.2 with 
# > module aliasing can only be used for Swift based targets; 
# > non-Swift sources found in target 'CasePaths' for product 
# > '${PRODUCT}' from package '${PACKAGE}'
# 
# Note that this is not required when building with Xcode 15.2.
resolve_and_fix_dependencies() {
  xcrun xcodebuild -resolvePackageDependencies \
    -workspace "MyLibrary" \
    -scheme "my-library" \
    -derivedDataPath "Build/DerivedData" || true

  find "Build/DerivedData/SourcePackages/checkouts" -name "*.docc" -type d -prune -exec rm -rf {} \;
}

rm -rf Build/DerivedData

resolve_and_fix_dependencies

xcrun xcodebuild archive \
  -workspace "MyLibrary" \
  -scheme "my-library" \
  -destination "generic/platform=iOS" \
  -archivePath "Build/Archives/MyLibrary.xcarchive" \
  -derivedDataPath "Build/DerivedData" \
  BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
  SWIFT_SERIALIZE_DEBUGGING_OPTIONS=NO \
  SWIFT_INSTALL_OBJC_HEADER=YES \
  SKIP_INSTALL=NO

Expected behavior

The build should succeed when building with Swift 5.9.2

Environment

Non-working version:

swift-driver version: 1.87.3 Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5)
Target: arm64-apple-macosx14.0

Working version:

swift-driver version: 1.62.15 Apple Swift version 5.7.2 (swiftlang-5.7.2.135.5 clang-1400.0.29.51)
Target: arm64-apple-macosx14.0

Additional information

For context: We're distributing an SDK in binary form and using module aliasing as a way to prevent issues with duplicate symbols. Unfortunately it broke immediately after introduction with this specific set of dependencies. It seems to work perfectly fine - even when aliasing transient dependencies - with simpler dependency trees.

simonliotier commented 1 month ago

Hello!

I have the same use case as @nesium and I observe the same issues. I've just tested with Swift 6.0/Xcode 16 and the problem is still happening. The more aliases we define, the more likely we are to get build errors.