Invalid XCFramweork when generated with BUILD_LIBRARY_FOR_DISTRIBUTION=YES

Hi all,

I'm attempting to generate an XCFramework that must maintain ABI stability. The framework is created from an SPM using the following script:

#!/bin/bash

set -x
set -e

# Pass scheme name as the first argument to the script
NAME=$1


cd ..

# Build the scheme for all platforms that we plan to support
for PLATFORM in "iOS" "iOS Simulator"; do

    echo "$PLATFORM"

    case $PLATFORM in
    "iOS")
    RELEASE_FOLDER="Release-iphoneos"
    ;;
    "iOS Simulator")
    RELEASE_FOLDER="Release-iphonesimulator"
    ;;
    esac

    ARCHIVE_PATH=$RELEASE_FOLDER

    # Rewrite Package.swift so that it declaras dynamic libraries, since the approach does not work with static libraries
    perl -i -p0e 's/type: .static,//g' Package.swift
    perl -i -p0e 's/type: .dynamic,//g' Package.swift
    perl -i -p0e 's/(library[^,]*,)/$1 type: .dynamic,/g' Package.swift
    
    xcodebuild archive -workspace . -scheme $NAME \
            -destination "generic/platform=$PLATFORM" \
            -archivePath $ARCHIVE_PATH \
            -configuration Release \
            -derivedDataPath ".build/$RELEASE_FOLDER" \
            SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES

    FRAMEWORK_PATH="$ARCHIVE_PATH.xcarchive/Products/usr/local/lib/$NAME.framework"
    MODULES_PATH="$FRAMEWORK_PATH/Modules"
    HEADERS_PATH="$FRAMEWORK_PATH/Headers"
    mkdir -p $MODULES_PATH
    mkdir -p $HEADERS_PATH

    BUILD_PRODUCTS_PATH=".build/$RELEASE_FOLDER/Build/Intermediates.noindex/ArchiveIntermediates/$NAME/BuildProductsPath"
    INTERMEDIATE_BUILD_FILES_PATH=".build/$RELEASE_FOLDER/Build/Intermediates.noindex/ArchiveIntermediates/$NAME/IntermediateBuildFilesPath/$NAME.build/$RELEASE_FOLDER"
    RELEASE_PATH="$BUILD_PRODUCTS_PATH/$RELEASE_FOLDER"
    SWIFT_MODULE_PATH="$RELEASE_PATH/$NAME.swiftmodule"
    RESOURCES_BUNDLE_PATH="$RELEASE_PATH/${NAME}_${NAME}.bundle"

    # Copy Swift modules
    if [ -d "$SWIFT_MODULE_PATH" ]
    then
        cp -r $SWIFT_MODULE_PATH $MODULES_PATH
    fi
    
        # Copy ObjC Headers
    if [ -d "$HEADERS_PATH" ]
    then
        for EXPORTED_MODULE in "ModuleA" "ModuleB" "ModuleC" "ModuleD"; do
            
            cp -r "$INTERMEDIATE_BUILD_FILES_PATH/$EXPORTED_MODULE.build/$EXPORTED_MODULE.modulemap" $HEADERS_PATH
            
            EXPORTED_HEADER="$INTERMEDIATE_BUILD_FILES_PATH/$EXPORTED_MODULE.build/Objects-normal/arm64/$EXPORTED_MODULE-Swift.h"
            cp $EXPORTED_HEADER  $HEADERS_PATH

              HEADER_TO_MODIFY="$HEADERS_PATH/$EXPORTED_MODULE-Swift.h"

              sed -i '' 's/@import MyFramework;/#import < MyFramework\/ModuleA-Swift.h>/' $HEADER_TO_MODIFY
              sed -i '' 's/@import ModuleH;/#import < MyFramework\/ModuleH-Swift.h>/' $HEADER_TO_MODIFY
              sed -i '' 's/@import ModuleC;/#import < MyFramework\/ModuleC-Swift.h>/' $HEADER_TO_MODIFY
              sed -i '' 's/@import ModuleA;/#import < MyFramework\/ModuleA-Swift.h>/' $HEADER_TO_MODIFY
        done
    fi
         

#     Copy resources bundle, if exists
    if [ -e $RESOURCES_BUNDLE_PATH ]
    then
        cp -r $RESOURCES_BUNDLE_PATH $FRAMEWORK_PATH
    fi

done

xcodebuild -create-xcframework \
-framework Release-iphoneos.xcarchive/Products/usr/local/lib/$NAME.framework \
-framework Release-iphonesimulator.xcarchive/Products/usr/local/lib/$NAME.framework \
-output $NAME.xcframework

The issue arises when I remove the flag BUILD_LIBRARY_FOR_DISTRIBUTION=YES and add the flag -allow-internal-distribution to xcodebuild -create-xcframework. While this resolves the problem, it results in the generated module not being ABI stable. However, when attempting this approach, it raises an error regarding arm64-apple-ios-private.swiftinterface with no such file or module as soon as it encounters an import statement for ModuleX.

The package structure is as follows:

// swift-tools-version: 5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "MyFramework",
    platforms: [
        .iOS(.v17),
    ],
    products: [
        // Products define the executables and libraries a package produces, making them visible to other packages.
        .library(
            name: "MyFramework", type: .dynamic,                                                                   
            targets: [
                "MyFramework",
                "ModuleA",
                "ModuleB",
                "ModuleC",
                "ModuleD",
                "ModuleE",
                "ModuleF",
                "WolfSSLC",
                "ModuleG",
                "ModuleH",
                "ModuleI",
                "ModuleJ",
                "ModuleK",
                "ModuleL",
                "Common",
                "Logging",
            ]
        ),
        .library(name: "MyFrameworkDevelopment", type: .dynamic,                                                              targets: ["MyFrameworkDevelopment"]),
    ],
    dependencies: [
        .package(url: "https://…”)
    ],
    targets: [
        // Targets are the basic building blocks of a package, defining a module or a test suite.
        // Targets can depend on other targets in this package and products from dependencies.
        .target(name: "MyFrameworkDevelopment", dependencies: [
            "MyFramework",
            "MockServer",
        ]),
        .target(name: "MyFramework", dependencies: [
            "Logging",
            "ModuleA",
            "ModuleG",
            "ModuleC",
            "ModuleK",
            "ModuleL",
            "CoreBluetoothWrapper",
        ]),
        .testTarget(name: "MyFrameworkTests", dependencies: [
            "MyFramework",
            "ModuleI",
            "TestHelpers",
            "MyFrameworkDevelopment",
        ]),
        .testTarget(
            name: "MyFrameworkAcceptanceTests",
            dependencies: [
                "MyFramework",
                "ModuleI",
                "MockServer",
                "TestHelpers",
            ]
        ),
        .target(
            name: "ModuleA",
            dependencies: [
                "ModuleH",
                "ModuleG",
                "ModuleJ",
                "ModuleK",
                "ModuleL",
                "Logging",
                "ModuleB",
                "ModuleI",
                .product(name: "X509", package: "ISC_SDK_iOS_Swift_Certificates"),
            ]
        ),
        .testTarget(
            name: "ModuleATests",
            dependencies: [
                "ModuleA",
                "TestHelpers",
                "MockServer",
                "WolfSSLC",
                .product(name: "X509", package: "ISC_SDK_iOS_Swift_Certificates"),
            ]
        ),
        .target(
            name: "ModuleB",
            dependencies: [
                "ModuleI",
                "ModuleH",
                "ModuleG",
                "Logging",
                "Common",
            ]
        ),
        .testTarget(
            name: "ModuleBTests",
            dependencies: [
                "ModuleB",
                "ModuleI",
                "TestHelpers",
            ]
        ),
        .target(
            name: "ModuleC",
            dependencies: [
                "ModuleI",
                "CoreBluetoothWrapper",
            ]
        ),
        .testTarget(
            name: "ModuleCTests",
            dependencies: [
                "ModuleC",
                "ModuleI",
                "TestHelpers",
            ]
        ),
        .target(
            name: "ModuleD",
            dependencies: [
                "ModuleI",
            ]
        ),
        .testTarget(
            name: "ModuleDTests",
            dependencies: [
                "ModuleD",
                "ModuleI",
                "TestHelpers",
            ]
        ),
        .target(
            name: "ModuleE",
            dependencies: [
                "ModuleD",
                "Logging",
            ]
        ),
        .testTarget(
            name: "ModuleETests",
            dependencies: [
                "ModuleE",
                "TestHelpers",
            ]
        ),
        .target(
            name: "ModuleF",
            dependencies: [
                "ModuleE",
                "ModuleJ",
                "ModuleL",
                "Logging",
                "WolfSSLC",
            ]
        ),
        .testTarget(
            name: "ModuleFTests",
            dependencies: [
                "ModuleF",
                "TestHelpers",
            ]
        ),
        .target(
            name: "WolfSSLC",
            dependencies: [
                "libwolfssl",
            ]
        ),
        .binaryTarget(
            name: "libwolfssl",
            path: "libwolfssl.xcframework"
        ),
        .target(
            name: "ModuleG",
            dependencies: [
                "ModuleE",
                "ModuleF",
                "Logging",
            ]
        ),
        .testTarget(
            name: "ModuleGTests",
            dependencies: [
                "ModuleG",
                "TestHelpers",
            ]
        ),
        .target(
            name: "ModuleH",
            dependencies: [
                "Common",
            ]
        ),
        .testTarget(
            name: "ModuleHTests",
            dependencies: ["ModuleH", "TestHelpers"]
        ),
        .target(
            name: "ModuleI",
            dependencies: [
                "CoreBluetoothWrapper",
                "Common",
            ]
        ),
        .target(
            name: "CoreBluetoothWrapper"
        ),
        .testTarget(
            name: "ModuleITests",
            dependencies: [
                "ModuleI",
                "TestHelpers",
            ]
        ),
        .target(
            name: "ModuleJ",
            dependencies: [
                "InstallationAuth",
                "ModuleK",
                "ModuleL",
                .product(name: "X509", package: "ISC_SDK_iOS_Swift_Certificates"),
                "Logging",
            ]
        ),
        .testTarget(
            name: "ModuleJTests",
            dependencies: [
                "ModuleJ",
                "TestHelpers",
                "ModuleK",
                "ModuleL",
            ]
        ),
        .target(
            name: "InstallationAuth",
            dependencies: [
                "ModuleK",
                "ModuleL",
            ]
        ),
        .testTarget(
            name: "InstallationAuthTests",
            dependencies: [
                "InstallationAuth",
                "TestHelpers",
                "ModuleK",
                "ModuleL",
            ]
        ),
        .target(
            name: "ModuleK",
            dependencies: ["Logging"]
        ),
        .testTarget(
            name: "ModuleKTests",
            dependencies: [
                "ModuleK",
                "TestHelpers",
            ]
        ),
        .target(name: "ModuleL"),
        .testTarget(
            name: "ModuleLTests",
            dependencies: ["ModuleL"]
        ),
        .target(name: "Logging"),
        .target(name: "Common"),
        .testTarget(
            name: "CommonTests",
            dependencies: [
                "Common",
                "TestHelpers",
            ]
        ),
        .testTarget(
            name: "LoggingTests",
            dependencies: ["Logging"]
        ),
        .target(
            name: "MockServer",
            dependencies: [
                "ModuleL",
                .product(name: "X509", package: "ISC_SDK_iOS_Swift_Certificates"),
            ],
            path: "Tests/MockServer",
            resources: [.process("Certs")]
        ),
        .target(
            name: "TestHelpers",
            dependencies: [
                "ModuleI",
                "MyFramework",
                "MockServer",
                "ModuleF",
                "WolfSSLC",
            ],
            path: "Tests/TestHelpers",
            resources: [.process("WolfSSL/Resources")]
        ),
    ]
)

The generated xcframework structure is as follows:

MyLibrary.xcframework
├── Info.plist
├── ios-arm64
│   └── MyLibrary.framework
│       ├── Headers
│       │   ├── ModuleH-Swift.h
│       │   ├── ModuleH.modulemap
│       │   ├── ModuleC-Swift.h
│       │   ├── ModuleC.modulemap
│       │   ├── ModuleA-Swift.h
│       │   ├── ModuleA.modulemap
│       │   ├── MyLibrary-Swift.h
│       │   └── MyLibrary.modulemap
│       ├── Info.plist
│       ├── Modules
│       │   └── MyLibrary.swiftmodule
│       │       ├── arm64-apple-ios.abi.json
│       │       ├── arm64-apple-ios.swiftdoc
│       │       └── arm64-apple-ios.swiftmodule
│       └── MyLibrary
└── ios-arm64_x86_64-simulator
    └── MyLibrary.framework
        ├── Headers
        │   ├── ModuleH-Swift.h
        │   ├── ModuleH.modulemap
        │   ├── ModuleC-Swift.h
        │   ├── ModuleC.modulemap
        │   ├── ModuleA-Swift.h
        │   ├── ModuleA.modulemap
        │   ├── MyLibrary-Swift.h
        │   └── MyLibrary.modulemap
        ├── Info.plist
        ├── Modules
        │   └── MyLibrary.swiftmodule
        │       ├── arm64-apple-ios-simulator.abi.json
        │       ├── arm64-apple-ios-simulator.swiftdoc
        │       ├── arm64-apple-ios-simulator.swiftmodule
        │       ├── x86_64-apple-ios-simulator.abi.json
        │       ├── x86_64-apple-ios-simulator.swiftdoc
        │       └── x86_64-apple-ios-simulator.swiftmodule
        ├── MyLibrary
        └── _CodeSignature
            └── CodeResources

It's worth mentioning that the library must be compatible with both Objective-C and Swift, and Modules A, C, and H are imported into the MyLibrary module as @_exported modules, which is why I included the headers and module maps.

Thank you in advance for your assistance.