Skip to content

Commit

Permalink
[Build] Add lang std flag per source file
Browse files Browse the repository at this point in the history
We were adding language standard flag per target which is wrong because
a Clang target can contain mixed C and C++ files.

- <rdar://problem/35782488> [SR-6430]: [SwiftPM] Build error passing invalid C standard to a C source file
  • Loading branch information
aciidgh committed Nov 30, 2017
1 parent 4f7a99f commit 90abb3c
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 26 deletions.
3 changes: 0 additions & 3 deletions Sources/Build/BuildPlan.swift
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,6 @@ public final class ClangTargetDescription {
#endif
args += ["-fblocks"]
args += ["-fmodules", "-fmodule-name=" + target.c99name]
if let languageStandard = clangTarget.languageStandard {
args += ["-std=\(languageStandard)"]
}
args += ["-I", clangTarget.includeDir.asString]
args += additionalFlags
args += moduleCacheArgs
Expand Down
16 changes: 16 additions & 0 deletions Sources/Build/llbuild.swift
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,25 @@ public struct LLBuildManifestGenerator {

/// Create a llbuild target for a Clang target description.
private func createClangCompileTarget(_ target: ClangTargetDescription) -> Target {

let standards = [
(target.clangTarget.cxxLanguageStandard, SupportedLanguageExtension.cppExtensions),
(target.clangTarget.cLanguageStandard, SupportedLanguageExtension.cExtensions),
]

let commands: [Command] = target.compilePaths().map({ path in
var args = target.basicArguments()
args += ["-MD", "-MT", "dependencies", "-MF", path.deps.asString]

// Add language standard flag if needed.
if let ext = path.source.extension {
for (standard, validExtensions) in standards {
if let languageStandard = standard, validExtensions.contains(ext) {
args += ["-std=\(languageStandard)"]
}
}
}

args += ["-c", path.source.asString, "-o", path.object.asString]
let clang = ClangTool(
desc: "Compile \(target.target.name) \(path.filename.asString)",
Expand Down
8 changes: 2 additions & 6 deletions Sources/PackageLoading/PackageBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -791,14 +791,10 @@ public final class PackageBuilder {

let sources = Sources(paths: cSources, root: potentialModule.path)

// Select the right language standard.
let isCXX = sources.containsCXXFiles
let languageStandard = isCXX ? manifest.package.cxxLanguageStandard?.rawValue : manifest.package.cLanguageStandard?.rawValue

return ClangTarget(
name: potentialModule.name,
isCXX: isCXX,
languageStandard: languageStandard,
cLanguageStandard: manifest.package.cLanguageStandard?.rawValue,
cxxLanguageStandard: manifest.package.cxxLanguageStandard?.rawValue,
includeDir: publicHeadersPath,
isTest: potentialModule.isTest,
sources: sources,
Expand Down
17 changes: 10 additions & 7 deletions Sources/PackageModel/Module.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,24 +140,27 @@ public class ClangTarget: Target {
/// True if this is a C++ target.
public let isCXX: Bool

/// The C or C++ language standard flag.
public let languageStandard: String?
/// The C language standard flag.
public let cLanguageStandard: String?

/// The C++ language standard flag.
public let cxxLanguageStandard: String?

public init(
name: String,
isCXX: Bool,
languageStandard: String?,
cLanguageStandard: String?,
cxxLanguageStandard: String?,
includeDir: AbsolutePath,
isTest: Bool = false,
sources: Sources,
dependencies: [Target] = [],
productDependencies: [(name: String, package: String?)] = []
) {
assert(includeDir.contains(sources.root), "\(includeDir) should be contained in the source root \(sources.root)")
assert(sources.containsCXXFiles == isCXX)
let type: Kind = isTest ? .test : sources.computeModuleType()
self.isCXX = isCXX
self.languageStandard = languageStandard
self.isCXX = sources.containsCXXFiles
self.cLanguageStandard = cLanguageStandard
self.cxxLanguageStandard = cxxLanguageStandard
self.includeDir = includeDir
super.init(
name: name,
Expand Down
25 changes: 16 additions & 9 deletions Tests/BuildTests/BuildPlanTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ final class BuildPlanTests: XCTestCase {
let fs = InMemoryFileSystem(emptyFiles:
"/Pkg/Sources/exe/main.cpp",
"/Pkg/Sources/lib/lib.c",
"/Pkg/Sources/lib/libx.cpp",
"/Pkg/Sources/lib/include/lib.h"
)
let pkg = PackageDescription4.Package(
Expand All @@ -272,33 +273,39 @@ final class BuildPlanTests: XCTestCase {
)
let diagnostics = DiagnosticsEngine()
let graph = loadMockPackageGraph4(["/Pkg": pkg], root: "/Pkg", diagnostics: diagnostics, in: fs)
let result = BuildPlanResult(plan: try BuildPlan(buildParameters: mockBuildParameters(), graph: graph, fileSystem: fs))
let plan = try BuildPlan(buildParameters: mockBuildParameters(), graph: graph, fileSystem: fs)
let result = BuildPlanResult(plan: plan)

result.checkProductsCount(1)
result.checkTargetsCount(2)

let lib = try result.target(for: "lib").clangTarget()
XCTAssertTrue(lib.basicArguments().contains("-std=gnu99"))

let exe = try result.target(for: "exe").clangTarget()
XCTAssertTrue(exe.basicArguments().contains("-std=c++1z"))

#if os(macOS)
XCTAssertEqual(try result.buildProduct(for: "exe").linkArguments(), [
"/fake/path/to/swiftc", "-lc++", "-g", "-L", "/path/to/build/debug", "-o",
"/path/to/build/debug/exe", "-module-name", "exe", "-emit-executable",
"/path/to/build/debug/exe.build/main.cpp.o",
"/path/to/build/debug/lib.build/lib.c.o"
"/path/to/build/debug/lib.build/lib.c.o",
"/path/to/build/debug/lib.build/libx.cpp.o"
])
#else
XCTAssertEqual(try result.buildProduct(for: "exe").linkArguments(), [
"/fake/path/to/swiftc", "-lstdc++", "-g", "-L", "/path/to/build/debug", "-o",
"/path/to/build/debug/exe", "-module-name", "exe", "-emit-executable",
"-Xlinker", "-rpath=$ORIGIN",
"/path/to/build/debug/exe.build/main.cpp.o",
"/path/to/build/debug/lib.build/lib.c.o"
"/path/to/build/debug/lib.build/lib.c.o",
"/path/to/build/debug/lib.build/libx.cpp.o"
])
#endif

mktmpdir { path in
let yaml = path.appending(component: "debug.yaml")
let llbuild = LLBuildManifestGenerator(plan)
try llbuild.generateManifest(at: yaml)
let contents = try localFileSystem.readFileContents(yaml).asString!
XCTAssertTrue(contents.contains("-std=gnu99\",\"-c\",\"/Pkg/Sources/lib/lib.c"))
XCTAssertTrue(contents.contains("-std=c++1z\",\"-c\",\"/Pkg/Sources/lib/libx.cpp"))
}
}

func testSwiftCMixed() throws {
Expand Down
2 changes: 1 addition & 1 deletion Tests/PackageLoadingTests/ModuleMapGenerationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ class ModuleMapGeneration: XCTestCase {

func ModuleMapTester(_ name: String, includeDir: String = "include", in fileSystem: FileSystem, _ body: (ModuleMapResult) -> Void) {
let includeDir = AbsolutePath.root.appending(component: includeDir)
let target = ClangTarget(name: name, isCXX: false, languageStandard: nil, includeDir: includeDir, isTest: false, sources: Sources(paths: [], root: .root))
let target = ClangTarget(name: name, cLanguageStandard: nil, cxxLanguageStandard: nil, includeDir: includeDir, isTest: false, sources: Sources(paths: [], root: .root))
let warningStream = BufferedOutputByteStream()
var generator = ModuleMapGenerator(for: target, fileSystem: fileSystem, warningStream: warningStream)
var diagnostics = Set<String>()
Expand Down

0 comments on commit 90abb3c

Please sign in to comment.