Skip to content

Commit

Permalink
Merge pull request #147 from ikesyo/fix-collectpublicheaders-notdupli…
Browse files Browse the repository at this point in the history
…catedsymlinks

Fix collectPublicHeaders' notDuplicatedSymlinks logic
  • Loading branch information
giginet authored Oct 7, 2024
2 parents 62c122e + bfabefd commit 2b6d902
Show file tree
Hide file tree
Showing 12 changed files with 129 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ struct FrameworkComponentsCollector {
in: generatedFrameworkPath
)

let publicHeaders = try collectPublicHeader()
let publicHeaders = try collectPublicHeaders()

let resourceBundlePath = try collectResourceBundle(
of: targetName,
Expand Down Expand Up @@ -165,7 +165,7 @@ struct FrameworkComponentsCollector {
}

/// Collects public headers of clangTarget
private func collectPublicHeader() throws -> Set<AbsolutePath>? {
private func collectPublicHeaders() throws -> Set<AbsolutePath>? {
guard let clangModule = buildProduct.target.underlying as? ScipioClangModule else {
return nil
}
Expand All @@ -180,11 +180,14 @@ struct FrameworkComponentsCollector {
// Sometimes, public headers include a file and its symlink both.
// This situation raises a duplication error
// So duplicated symlinks have to be omitted
let notDuplicatedSymlinks = symlinks.filter { path in
notSymlinks.allSatisfy { FileManager.default.contentsEqual(atPath: path.pathString, andPath: $0.pathString) }
}
let notDuplicatedSymlinks = symlinks
// `FileManager.contentsEqual` does not traverse symbolic links, but compares the links themselves.
// So we need to resolve the links beforehand.
.map { $0.asURL.resolvingSymlinksInPath() }
.map(\.absolutePath)
.filter { path in
notSymlinks.allSatisfy { !FileManager.default.contentsEqual(atPath: path.pathString, andPath: $0.pathString) }
}

return Set(notSymlinks + notDuplicatedSymlinks)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// swift-tools-version: 5.7
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "ClangPackageWithSymbolicLinkHeaders",
platforms: [.iOS(.v11)],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "some_lib",
targets: ["some_lib"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
.target(
name: "some_lib",
dependencies: []
),
]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# ClangPackageWithSymbolicLinkHeaders

A description of this package.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// a.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// b.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifndef some_lib_h
#define some_lib_h

#include <stdio.h>
#include "a.h"
#include "b.h"

int add(int lhs, int rhs);

#endif /* some_lib_h */
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include "include/some_lib.h"

int add(int lhs, int rhs) {
return lhs + rhs;
}
64 changes: 64 additions & 0 deletions Tests/ScipioKitTests/RunnerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ private let binaryPackagePath = fixturePath.appendingPathComponent("BinaryPackag
private let resourcePackagePath = fixturePath.appendingPathComponent("ResourcePackage")
private let usingBinaryPackagePath = fixturePath.appendingPathComponent("UsingBinaryPackage")
private let clangPackagePath = fixturePath.appendingPathComponent("ClangPackage")
private let clangPackageWithSymbolicLinkHeadersPath = fixturePath.appendingPathComponent("ClangPackageWithSymbolicLinkHeaders")
private let clangPackageWithCustomModuleMapPath = fixturePath.appendingPathComponent("ClangPackageWithCustomModuleMap")
private let clangPackageWithUmbrellaDirectoryPath = fixturePath.appendingPathComponent("ClangPackageWithUmbrellaDirectory")

Expand Down Expand Up @@ -155,6 +156,69 @@ final class RunnerTests: XCTestCase {
}
}

func testBuildClangPackageWithSymbolicLinkHeaders() async throws {
let runner = Runner(
mode: .createPackage,
options: .init(
baseBuildOptions: .init(isSimulatorSupported: false),
shouldOnlyUseVersionsFromResolvedFile: true
)
)
do {
try await runner.run(packageDirectory: clangPackageWithSymbolicLinkHeadersPath,
frameworkOutputDir: .custom(frameworkOutputDir))
} catch {
XCTFail("Build should be succeeded. \(error.localizedDescription)")
}

for library in ["some_lib"] {
print(frameworkOutputDir)
let xcFramework = frameworkOutputDir.appendingPathComponent("\(library).xcframework")
let versionFile = frameworkOutputDir.appendingPathComponent(".\(library).version")
let framework = xcFramework.appendingPathComponent("ios-arm64")
.appendingPathComponent("\(library).framework")

XCTAssertTrue(
fileManager.fileExists(atPath: framework.appendingPathComponent("Headers/some_lib.h").path),
"Should exist an umbrella header"
)
XCTAssertTrue(
fileManager.fileExists(atPath: framework.appendingPathComponent("Headers/a.h").path),
"Should exist a header from symbolic link"
)
XCTAssertTrue(
fileManager.fileExists(atPath: framework.appendingPathComponent("Headers/b.h").path),
"Should exist another header from symbolic link"
)
XCTAssertFalse(
fileManager.fileExists(atPath: framework.appendingPathComponent("Headers/some_lib_dupe.h").path),
"Should not exist a header from symbolic link which is duplicated to non-symbolic link one"
)

let moduleMapPath = framework.appendingPathComponent("Modules/module.modulemap").path
XCTAssertTrue(
fileManager.fileExists(atPath: moduleMapPath),
"Should exist a modulemap"
)
let moduleMapContents = try XCTUnwrap(fileManager.contents(atPath: moduleMapPath).flatMap { String(decoding: $0, as: UTF8.self) })
XCTAssertEqual(
moduleMapContents,
"""
framework module some_lib {
umbrella header "some_lib.h"
export *
}
""",
"modulemap should be generated"
)

XCTAssertTrue(fileManager.fileExists(atPath: xcFramework.path),
"Should create \(library).xcframework")
XCTAssertFalse(fileManager.fileExists(atPath: versionFile.path),
"Should not create .\(library).version in create mode")
}
}

func testBuildClangPackageWithCustomModuleMap() async throws {
let runner = Runner(
mode: .createPackage,
Expand Down

0 comments on commit 2b6d902

Please sign in to comment.