Skip to content

Fix swift-symbolgraph-extract search paths #7621

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 23 additions & 10 deletions Sources/Build/BuildDescription/ClangTargetBuildDescription.swift
Original file line number Diff line number Diff line change
Expand Up @@ -209,15 +209,19 @@ public final class ClangTargetBuildDescription {

/// Determines the arguments needed to run `swift-symbolgraph-extract` for
/// this module.
public func symbolGraphExtractArguments() throws -> [String] {
package func symbolGraphExtractArguments() throws -> [String] {
var args = [String]()

if self.clangTarget.isCXX {
args += ["-cxx-interoperability-mode=default"]
}
if let cxxLanguageStandard = self.clangTarget.cxxLanguageStandard {
args += ["-Xcc", "-std=\(cxxLanguageStandard)"]
}
args += ["-I", self.clangTarget.includeDir.pathString]
args += self.additionalFlags.asSwiftcCCompilerFlags()
// Unconditionally use clang modules with swift tools.
args += try self.clangModuleArguments().asSwiftcCCompilerFlags()
args += try self.currentModuleMapFileArguments().asSwiftcCCompilerFlags()
return args
}

Expand Down Expand Up @@ -263,7 +267,7 @@ public final class ClangTargetBuildDescription {
// clang modules aren't fully supported in C++ mode in the current Darwin SDKs.
let enableModules = triple.isDarwin() && !isCXX
if enableModules {
args += ["-fmodules", "-fmodule-name=" + target.c99name]
args += try self.clangModuleArguments()
}

// Only add the build path to the framework search path if there are binary frameworks to link against.
Expand All @@ -273,9 +277,7 @@ public final class ClangTargetBuildDescription {

args += ["-I", clangTarget.includeDir.pathString]
args += additionalFlags
if enableModules {
args += try moduleCacheArgs
}

args += buildParameters.sanitizers.compileCFlags()

// Add arguments from declared build settings.
Expand Down Expand Up @@ -433,11 +435,22 @@ public final class ClangTargetBuildDescription {
return compilationConditions
}

/// Module cache arguments.
private var moduleCacheArgs: [String] {
get throws {
try ["-fmodules-cache-path=\(buildParameters.moduleCache.pathString)"]
/// Enable Clang module flags.
private func clangModuleArguments() throws -> [String] {
let cachePath = try self.buildParameters.moduleCache.pathString
return [
"-fmodules",
"-fmodule-name=\(self.target.c99name)",
"-fmodules-cache-path=\(cachePath)",
]
}

private func currentModuleMapFileArguments() throws -> [String] {
// Pass the path to the current module's module map if present.
if let moduleMap = self.moduleMap {
return ["-fmodule-map-file=\(moduleMap.pathString)"]
}
return []
}

/// Generate the resource bundle accessor, if appropriate.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -624,10 +624,26 @@ public final class SwiftTargetBuildDescription {

/// Determines the arguments needed to run `swift-symbolgraph-extract` for
/// this module.
public func symbolGraphExtractArguments() throws -> [String] {
package func symbolGraphExtractArguments() throws -> [String] {
var args = [String]()
args += try self.cxxInteroperabilityModeArguments(
propagateFromCurrentModuleOtherSwiftFlags: true)

args += self.buildParameters.toolchain.extraFlags.swiftCompilerFlags

// Include search paths determined during planning
args += self.additionalFlags
// FIXME: only pass paths to the actual dependencies of the module
// Include search paths for swift module dependencies.
args += ["-I", self.modulesPath.pathString]

// FIXME: Only include valid args
// This condition should instead only include args which are known to be
// compatible instead of filtering out specific unknown args.
//
// swift-symbolgraph-extract does not support parsing `-use-ld=lld` and
// will silently error failing the operation.
args = args.filter { !$0.starts(with: "-use-ld=") }
return args
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public enum TargetBuildDescription {

/// Determines the arguments needed to run `swift-symbolgraph-extract` for
/// this module.
public func symbolGraphExtractArguments() throws -> [String] {
package func symbolGraphExtractArguments() throws -> [String] {
switch self {
case .swift(let target): try target.symbolGraphExtractArguments()
case .clang(let target): try target.symbolGraphExtractArguments()
Expand Down
2 changes: 2 additions & 0 deletions Sources/Build/BuildPlan/BuildPlan.swift
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,8 @@ public class BuildPlan: SPMBuildCore.BuildPlan {
}
}

/// Determines the arguments needed to run `swift-symbolgraph-extract` for
/// a particular module.
public func symbolGraphExtractArguments(for module: ResolvedModule) throws -> [String] {
guard let description = self.targetMap[module.id] else {
throw InternalError("Expected description for module \(module)")
Expand Down
1 change: 0 additions & 1 deletion Sources/Commands/Utilities/SymbolGraphExtract.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ public struct SymbolGraphExtract {
// FIXME: everything here should be in symbolGraphExtractArguments
commandLine += ["-module-name", module.c99name]
commandLine += try buildParameters.tripleArgs(for: module)
commandLine += try buildPlan.createAPIToolCommonArgs(includeLibrarySearchPaths: true)
commandLine += ["-module-cache-path", try buildParameters.moduleCache.pathString]
if verboseOutput {
commandLine += ["-v"]
Expand Down
2 changes: 2 additions & 0 deletions Sources/SPMBuildCore/BuildSystem/BuildSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ public protocol BuildPlan {
func createAPIToolCommonArgs(includeLibrarySearchPaths: Bool) throws -> [String]
func createREPLArguments() throws -> [String]

/// Determines the arguments needed to run `swift-symbolgraph-extract` for
/// a particular module.
func symbolGraphExtractArguments(for module: ResolvedModule) throws -> [String]
}

Expand Down
146 changes: 129 additions & 17 deletions Tests/BuildTests/BuildPlanTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1410,13 +1410,13 @@ final class BuildPlanTests: XCTestCase {
args += ["-O0", "-DSWIFT_PACKAGE=1", "-DDEBUG=1"]
args += ["-fblocks"]
#if os(macOS) // FIXME(5473) - support modules on non-Apple platforms
args += ["-fmodules", "-fmodule-name=extlib"]
args += [
"-fmodules",
"-fmodule-name=extlib",
"-fmodules-cache-path=\(buildPath.appending(components: "ModuleCache"))",
]
#endif
args += ["-I", ExtPkg.appending(components: "Sources", "extlib", "include").pathString]
#if os(macOS) // FIXME(5473) - support modules on non-Apple platforms
args += ["-fmodules-cache-path=\(buildPath.appending(components: "ModuleCache"))"]
#endif

args += [hostTriple.isWindows() ? "-gdwarf" : "-g"]

if hostTriple.isLinux() {
Expand All @@ -1439,7 +1439,11 @@ final class BuildPlanTests: XCTestCase {
args += ["-O0", "-DSWIFT_PACKAGE=1", "-DDEBUG=1"]
args += ["-fblocks"]
#if os(macOS) // FIXME(5473) - support modules on non-Apple platforms
args += ["-fmodules", "-fmodule-name=exe"]
args += [
"-fmodules",
"-fmodule-name=exe",
"-fmodules-cache-path=\(buildPath.appending(components: "ModuleCache"))",
]
#endif
args += [
"-I", Pkg.appending(components: "Sources", "exe", "include").pathString,
Expand All @@ -1448,9 +1452,6 @@ final class BuildPlanTests: XCTestCase {
"-I", ExtPkg.appending(components: "Sources", "extlib", "include").pathString,
"-fmodule-map-file=\(buildPath.appending(components: "extlib.build", "module.modulemap"))",
]
#if os(macOS) // FIXME(5473) - support modules on non-Apple platforms
args += ["-fmodules-cache-path=\(buildPath.appending(components: "ModuleCache"))"]
#endif
args += [hostTriple.isWindows() ? "-gdwarf" : "-g"]

if hostTriple.isLinux() {
Expand Down Expand Up @@ -1796,12 +1797,13 @@ final class BuildPlanTests: XCTestCase {
args += ["-O0", "-DSWIFT_PACKAGE=1", "-DDEBUG=1"]
args += ["-fblocks"]
#if os(macOS) // FIXME(5473) - support modules on non-Apple platforms
args += ["-fmodules", "-fmodule-name=lib"]
args += [
"-fmodules",
"-fmodule-name=lib",
"-fmodules-cache-path=\(buildPath.appending(components: "ModuleCache"))",
]
#endif
args += ["-I", Pkg.appending(components: "Sources", "lib", "include").pathString]
#if os(macOS) // FIXME(5473) - support modules on non-Apple platforms
args += ["-fmodules-cache-path=\(buildPath.appending(components: "ModuleCache"))"]
#endif
args += [hostTriple.isWindows() ? "-gdwarf" : "-g"]

if hostTriple.isLinux() {
Expand Down Expand Up @@ -1999,6 +2001,115 @@ final class BuildPlanTests: XCTestCase {
}
}

func test_symbolGraphExtract_arguments() throws {
// ModuleGraph:
// .
// ├── A (Swift)
// │ ├── B (Swift)
// │   └── C (C)
// └── D (C)
// ├── B (Swift)
//   └── C (C)

let Pkg: AbsolutePath = "/Pkg"
let fs: FileSystem = InMemoryFileSystem(
emptyFiles:
// A
Pkg.appending(components: "Sources", "A", "A.swift").pathString,
// B
Pkg.appending(components: "Sources", "B", "B.swift").pathString,
// C
Pkg.appending(components: "Sources", "C", "C.c").pathString,
Pkg.appending(components: "Sources", "C", "include", "C.h").pathString,
// D
Pkg.appending(components: "Sources", "D", "D.c").pathString,
Pkg.appending(components: "Sources", "D", "include", "D.h").pathString
)

let observability = ObservabilitySystem.makeForTesting()
let graph = try loadModulesGraph(
fileSystem: fs,
manifests: [
Manifest.createRootManifest(
displayName: "Pkg",
path: .init(validating: Pkg.pathString),
targets: [
TargetDescription(name: "A", dependencies: ["B", "C"]),
TargetDescription(name: "B", dependencies: []),
TargetDescription(name: "C", dependencies: []),
TargetDescription(name: "D", dependencies: ["B", "C"]),
]
),
],
observabilityScope: observability.topScope
)
XCTAssertNoDiagnostics(observability.diagnostics)

let plan = try mockBuildPlan(
graph: graph,
fileSystem: fs,
observabilityScope: observability.topScope
)

let result = try BuildPlanResult(plan: plan)
let triple = result.plan.destinationBuildParameters.triple

func XCTAssertMatchesSubSequences(
_ value: [String],
_ patterns: [StringPattern]...,
file: StaticString = #file,
line: UInt = #line
) {
for pattern in patterns {
var pattern = pattern
pattern.insert(.anySequence, at: 0)
pattern.append(.anySequence)
XCTAssertMatch(value, pattern, file: file, line: line)
}
}

// A
do {
try XCTAssertMatchesSubSequences(
result.target(for: "A").symbolGraphExtractArguments(),
// Swift Module dependencies
["-I", "/path/to/build/\(triple)/debug/Modules"],
// C Module dependencies
["-Xcc", "-I", "-Xcc", "/Pkg/Sources/C/include"],
["-Xcc", "-fmodule-map-file=/path/to/build/\(triple)/debug/C.build/module.modulemap"]
)
}

// D
do {
try XCTAssertMatchesSubSequences(
result.target(for: "D").symbolGraphExtractArguments(),
// Self Module
["-I", "/Pkg/Sources/D/include"],
["-Xcc", "-fmodule-map-file=/path/to/build/\(triple)/debug/D.build/module.modulemap"],

// C Module dependencies
["-Xcc", "-I", "-Xcc", "/Pkg/Sources/C/include"],
["-Xcc", "-fmodule-map-file=/path/to/build/\(triple)/debug/C.build/module.modulemap"],

// General Args
[
"-Xcc", "-fmodules",
"-Xcc", "-fmodule-name=D",
"-Xcc", "-fmodules-cache-path=/path/to/build/\(triple)/debug/ModuleCache",
]
)

#if os(macOS)
try XCTAssertMatchesSubSequences(
result.target(for: "D").symbolGraphExtractArguments(),
// Swift Module dependencies
["-Xcc", "-fmodule-map-file=/path/to/build/\(triple)/debug/B.build/module.modulemap"]
)
#endif
}
}

func testREPLArguments() throws {
let Dep = AbsolutePath("/Dep")
let fs = InMemoryFileSystem(
Expand Down Expand Up @@ -3035,12 +3146,13 @@ final class BuildPlanTests: XCTestCase {
expectedExeBasicArgs += ["-target", defaultTargetTriple]
expectedExeBasicArgs += ["-O0", "-DSWIFT_PACKAGE=1", "-DDEBUG=1", "-fblocks"]
#if os(macOS) // FIXME(5473) - support modules on non-Apple platforms
expectedExeBasicArgs += ["-fmodules", "-fmodule-name=exe"]
expectedExeBasicArgs += [
"-fmodules",
"-fmodule-name=exe",
"-fmodules-cache-path=\(buildPath.appending(components: "ModuleCache"))"
]
#endif
expectedExeBasicArgs += ["-I", Pkg.appending(components: "Sources", "exe", "include").pathString]
#if os(macOS) // FIXME(5473) - support modules on non-Apple platforms
expectedExeBasicArgs += ["-fmodules-cache-path=\(buildPath.appending(components: "ModuleCache"))"]
#endif

expectedExeBasicArgs += [triple.isWindows() ? "-gdwarf" : "-g"]

Expand Down