aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJayant Chowdhary <jchowdhary@google.com>2017-02-08 13:45:53 -0800
committerJayant Chowdhary <jchowdhary@google.com>2017-04-14 19:48:10 -0700
commit3e231fd8bd61f2eb77e76e06a1877e2904564358 (patch)
tree9eeb71dc0e91b1fa2d198ed8504a843f6245b5db
parentc43ae770c56808c802916e6346576f3f0c047194 (diff)
downloadbuild_soong-3e231fd8bd61f2eb77e76e06a1877e2904564358.tar.gz
build_soong-3e231fd8bd61f2eb77e76e06a1877e2904564358.tar.bz2
build_soong-3e231fd8bd61f2eb77e76e06a1877e2904564358.zip
Add header-abi-checker for Vndk abi checks.
header-abi-dumper: dumps abi exported by source files for Vndk. header-abi-linker: links abi dumps produced by header-abi-dumper. header-abi-diff: compares linked dumps. Test: mm -j64 showcommands > make_log in bionic/libc. This produced linked dumps in out/soong/.intermediates. Copied these dumps to prebuilts/abi-dumps/ndk/current/arm64/source-based/. Changed the abi and re-ran mm -j64 showcommands > make_log confirmed that the build reported compatibility breakge without actually failing (advisory mode). Change-Id: Iccad6908fe68a80f47230751671d156893b96ead
-rw-r--r--Android.bp1
-rw-r--r--android/paths.go24
-rw-r--r--cc/androidmk.go7
-rw-r--r--cc/builder.go104
-rw-r--r--cc/cc.go30
-rw-r--r--cc/library.go57
-rw-r--r--cc/sabi.go63
-rw-r--r--cc/util.go2
8 files changed, 287 insertions, 1 deletions
diff --git a/Android.bp b/Android.bp
index 2ae993f7..61ef41e3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -127,6 +127,7 @@ bootstrap_go_package {
"cc/proto.go",
"cc/relocation_packer.go",
"cc/sanitize.go",
+ "cc/sabi.go",
"cc/stl.go",
"cc/strip.go",
"cc/tidy.go",
diff --git a/android/paths.go b/android/paths.go
index 969c7537..75e5980e 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -576,6 +576,30 @@ type ModuleOutPath struct {
var _ Path = ModuleOutPath{}
+// PathForVndkRefDump returns an OptionalPath representing the path of the reference
+// abi dump for the given module. This is not guaranteed to be valid.
+func PathForVndkRefAbiDump(ctx ModuleContext, version, fileName string, vndkOrNdk, isSourceDump bool) OptionalPath {
+ archName := ctx.Arch().ArchType.Name
+ var sourceOrBinaryDir string
+ var vndkOrNdkDir string
+ var ext string
+ if isSourceDump {
+ ext = ".lsdump"
+ sourceOrBinaryDir = "source-based"
+ } else {
+ ext = ".bdump"
+ sourceOrBinaryDir = "binary-based"
+ }
+ if vndkOrNdk {
+ vndkOrNdkDir = "vndk"
+ } else {
+ vndkOrNdkDir = "ndk"
+ }
+ refDumpFileStr := "prebuilts/abi-dumps/" + vndkOrNdkDir + "/" + version + "/" +
+ archName + "/" + sourceOrBinaryDir + "/" + fileName + ext
+ return OptionalPathForSource(ctx, "", refDumpFileStr)
+}
+
// PathForModuleOut returns a Path representing the paths... under the module's
// output directory.
func PathForModuleOut(ctx ModuleContext, paths ...string) ModuleOutPath {
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 59a1db89..481dbb4c 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -141,6 +141,13 @@ func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.An
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) error {
library.androidMkWriteExportedFlags(w)
+ fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES := ")
+ if library.sAbiOutputFile.Valid() {
+ fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES += ", library.sAbiOutputFile.String())
+ if library.sAbiDiff.Valid() && !library.static() {
+ fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES += ", library.sAbiDiff.String())
+ }
+ }
fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+outputFile.Ext())
diff --git a/cc/builder.go b/cc/builder.go
index 0694cb7d..96b41589 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -168,6 +168,41 @@ var (
Description: "yasm $out",
},
"asFlags")
+
+ _ = pctx.SourcePathVariable("sAbiDumper", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/header-abi-dumper")
+
+ sAbiDump = pctx.AndroidStaticRule("sAbiDump",
+ blueprint.RuleParams{
+ Command: "rm -f $out && $sAbiDumper -o ${out} $in $exportDirs -- $cFlags -Wno-packed -isystem ${config.RSIncludePath}",
+ CommandDeps: []string{"$sAbiDumper"},
+ Description: "header-abi-dumper $in -o $out $exportDirs",
+ },
+ "cFlags", "exportDirs")
+
+ _ = pctx.SourcePathVariable("sAbiLinker", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/header-abi-linker")
+
+ sAbiLink = pctx.AndroidStaticRule("sAbiLink",
+ blueprint.RuleParams{
+ Command: "$sAbiLinker -o ${out} $symbolFile -arch $arch -api $api $exportedHeaderFlags @${out}.rsp ",
+ CommandDeps: []string{"$sAbiLinker"},
+ Description: "header-abi-linker $in -o $out",
+ Rspfile: "${out}.rsp",
+ RspfileContent: "${in}",
+ },
+ "symbolFile", "arch", "api", "exportedHeaderFlags")
+
+ _ = pctx.SourcePathVariable("sAbiDiffer", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/header-abi-diff")
+ // The output file is different from what the build system knows about.
+ // This is done since we have to create a report file even when builds
+ // fail in this case. Abidiff check turned on in advice-only mode. Builds
+ // will not fail on abi incompatibilties / extensions.
+ sAbiDiff = pctx.AndroidStaticRule("sAbiDiff",
+ blueprint.RuleParams{
+ Command: "$sAbiDiffer -advice-only -o ${out}s -new $in -old $referenceDump",
+ CommandDeps: []string{"$sAbiDiffer"},
+ Description: "header-abi-diff -o ${out} -new $in -old $referenceDump",
+ },
+ "referenceDump")
)
func init() {
@@ -194,12 +229,14 @@ type builderFlags struct {
yaccFlags string
protoFlags string
tidyFlags string
+ sAbiFlags string
yasmFlags string
aidlFlags string
toolchain config.Toolchain
clang bool
tidy bool
coverage bool
+ sAbiDump bool
systemIncludeFlags string
@@ -214,6 +251,7 @@ type Objects struct {
objFiles android.Paths
tidyFiles android.Paths
coverageFiles android.Paths
+ sAbiDumpFiles android.Paths
}
func (a Objects) Copy() Objects {
@@ -221,6 +259,7 @@ func (a Objects) Copy() Objects {
objFiles: append(android.Paths{}, a.objFiles...),
tidyFiles: append(android.Paths{}, a.tidyFiles...),
coverageFiles: append(android.Paths{}, a.coverageFiles...),
+ sAbiDumpFiles: append(android.Paths{}, a.sAbiDumpFiles...),
}
}
@@ -229,6 +268,7 @@ func (a Objects) Append(b Objects) Objects {
objFiles: append(a.objFiles, b.objFiles...),
tidyFiles: append(a.tidyFiles, b.tidyFiles...),
coverageFiles: append(a.coverageFiles, b.coverageFiles...),
+ sAbiDumpFiles: append(a.sAbiDumpFiles, b.sAbiDumpFiles...),
}
}
@@ -265,6 +305,10 @@ func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles and
flags.systemIncludeFlags,
flags.asFlags,
}, " ")
+ var sAbiDumpFiles android.Paths
+ if flags.sAbiDump && flags.clang {
+ sAbiDumpFiles = make(android.Paths, 0, len(srcFiles))
+ }
if flags.clang {
cflags += " ${config.NoOverrideClangGlobalCflags}"
@@ -296,6 +340,7 @@ func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles and
var ccCmd string
tidy := flags.tidy && flags.clang
coverage := flags.coverage
+ dump := flags.sAbiDump && flags.clang
switch srcFile.Ext() {
case ".S", ".s":
@@ -303,6 +348,7 @@ func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles and
moduleCflags = asflags
tidy = false
coverage = false
+ dump = false
case ".c":
ccCmd = "gcc"
moduleCflags = cflags
@@ -366,12 +412,29 @@ func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles and
})
}
+ if dump {
+ sAbiDumpFile := android.ObjPathWithExt(ctx, subdir, srcFile, "sdump")
+ sAbiDumpFiles = append(sAbiDumpFiles, sAbiDumpFile)
+
+ ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+ Rule: sAbiDump,
+ Output: sAbiDumpFile,
+ Input: srcFile,
+ Implicit: objFile,
+ Args: map[string]string{
+ "cFlags": moduleCflags,
+ "exportDirs": flags.sAbiFlags,
+ },
+ })
+ }
+
}
return Objects{
objFiles: objFiles,
tidyFiles: tidyFiles,
coverageFiles: coverageFiles,
+ sAbiDumpFiles: sAbiDumpFiles,
}
}
@@ -554,6 +617,47 @@ func TransformObjToDynamicBinary(ctx android.ModuleContext,
})
}
+// Generate a rule to combine .dump sAbi dump files from multiple source files
+// into a single .ldump sAbi dump file
+func TransformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Paths,
+ symbolFile android.OptionalPath, apiLevel, baseName, exportedHeaderFlags string) android.OptionalPath {
+ outputFile := android.PathForModuleOut(ctx, baseName+".lsdump")
+ var symbolFileStr string
+ var linkedDumpDep android.Path
+ if symbolFile.Valid() {
+ symbolFileStr = "-v " + symbolFile.Path().String()
+ linkedDumpDep = symbolFile.Path()
+ }
+ ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+ Rule: sAbiLink,
+ Output: outputFile,
+ Inputs: sAbiDumps,
+ Implicit: linkedDumpDep,
+ Args: map[string]string{
+ "symbolFile": symbolFileStr,
+ "arch": ctx.Arch().ArchType.Name,
+ "api": apiLevel,
+ "exportedHeaderFlags": exportedHeaderFlags,
+ },
+ })
+ return android.OptionalPathForPath(outputFile)
+}
+
+func SourceAbiDiff(ctx android.ModuleContext, inputDump android.Path, referenceDump android.Path,
+ baseName string) android.OptionalPath {
+ outputFile := android.PathForModuleOut(ctx, baseName+".abidiff")
+ ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+ Rule: sAbiDiff,
+ Output: outputFile,
+ Input: inputDump,
+ Implicit: referenceDump,
+ Args: map[string]string{
+ "referenceDump": referenceDump.String(),
+ },
+ })
+ return android.OptionalPathForPath(outputFile)
+}
+
// Generate a rule for extract a table of contents from a shared library (.so)
func TransformSharedObjectToToc(ctx android.ModuleContext, inputFile android.WritablePath,
outputFile android.WritablePath, flags builderFlags) {
diff --git a/cc/cc.go b/cc/cc.go
index 63caf3a4..6e2f6a50 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -49,6 +49,7 @@ func init() {
ctx.BottomUp("tsan", sanitizerMutator(tsan)).Parallel()
ctx.BottomUp("coverage", coverageLinkingMutator).Parallel()
+ ctx.TopDown("vndk_deps", sabiDepsMutator)
})
pctx.Import("android/soong/cc/config")
@@ -108,6 +109,7 @@ type Flags struct {
LdFlags []string // Flags that apply to linker command lines
libFlags []string // Flags to add libraries early to the link order
TidyFlags []string // Flags that apply to clang-tidy
+ SAbiFlags []string // Flags that apply to header-abi-dumper
YasmFlags []string // Flags that apply to yasm assembly source files
// Global include flags that apply to C, C++, and assembly source files
@@ -118,6 +120,7 @@ type Flags struct {
Clang bool
Tidy bool
Coverage bool
+ SAbiDump bool
RequiredInstructionSet string
DynamicLinker string
@@ -177,6 +180,7 @@ type ModuleContextIntf interface {
sdk() bool
sdkVersion() string
vndk() bool
+ createVndkSourceAbiDump() bool
selectedStl() string
baseModuleName() string
}
@@ -283,6 +287,7 @@ type Module struct {
stl *stl
sanitize *sanitize
coverage *coverage
+ sabi *sabi
androidMkSharedLibDeps []string
@@ -316,6 +321,9 @@ func (c *Module) Init() (blueprint.Module, []interface{}) {
if c.coverage != nil {
props = append(props, c.coverage.props()...)
}
+ if c.sabi != nil {
+ props = append(props, c.sabi.props()...)
+ }
for _, feature := range c.features {
props = append(props, feature.props()...)
}
@@ -418,6 +426,12 @@ func (ctx *moduleContextImpl) vndk() bool {
return ctx.mod.vndk()
}
+// Create source abi dumps if the module belongs to the list of VndkLibraries.
+func (ctx *moduleContextImpl) createVndkSourceAbiDump() bool {
+ return ctx.ctx.Device() && (inList(ctx.baseModuleName(), config.LLndkLibraries())) ||
+ (inList(ctx.baseModuleName(), config.VndkLibraries()))
+}
+
func (ctx *moduleContextImpl) selectedStl() string {
if stl := ctx.mod.stl; stl != nil {
return stl.Properties.SelectedStl
@@ -444,6 +458,7 @@ func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Mo
module.stl = &stl{}
module.sanitize = &sanitize{}
module.coverage = &coverage{}
+ module.sabi = &sabi{}
return module
}
@@ -492,6 +507,9 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
if c.coverage != nil {
flags = c.coverage.flags(ctx, flags)
}
+ if c.sabi != nil {
+ flags = c.sabi.flags(ctx, flags)
+ }
for _, feature := range c.features {
flags = feature.flags(ctx, flags)
}
@@ -566,6 +584,9 @@ func (c *Module) begin(ctx BaseModuleContext) {
if c.coverage != nil {
c.coverage.begin(ctx)
}
+ if c.sabi != nil {
+ c.sabi.begin(ctx)
+ }
for _, feature := range c.features {
feature.begin(ctx)
}
@@ -596,6 +617,9 @@ func (c *Module) deps(ctx DepsContext) Deps {
if c.coverage != nil {
deps = c.coverage.deps(ctx, deps)
}
+ if c.sabi != nil {
+ deps = c.sabi.deps(ctx, deps)
+ }
for _, feature := range c.features {
deps = feature.deps(ctx, deps)
}
@@ -999,9 +1023,12 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
}
// When combining coverage files for shared libraries and executables, coverage files
- // in static libraries act as if they were whole static libraries.
+ // in static libraries act as if they were whole static libraries. The same goes for
+ // source based Abi dump files.
depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles,
staticLib.objs().coverageFiles...)
+ depPaths.StaticLibObjs.sAbiDumpFiles = append(depPaths.StaticLibObjs.sAbiDumpFiles,
+ staticLib.objs().sAbiDumpFiles...)
}
if ptr != nil {
@@ -1085,6 +1112,7 @@ func DefaultsFactory(props ...interface{}) (blueprint.Module, []interface{}) {
&InstallerProperties{},
&TidyProperties{},
&CoverageProperties{},
+ &SAbiProperties{},
)
return android.InitDefaultsModule(module, module, props...)
diff --git a/cc/library.go b/cc/library.go
index cb85bd3b..e2ec5849 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -21,6 +21,7 @@ import (
"github.com/google/blueprint/pathtools"
"android/soong/android"
+ "android/soong/cc/config"
)
type LibraryProperties struct {
@@ -220,9 +221,17 @@ type libraryDecorator struct {
sanitize *sanitize
+ sabi *sabi
+
// Output archive of gcno coverage information files
coverageOutputFile android.OptionalPath
+ // linked Source Abi Dump
+ sAbiOutputFile android.OptionalPath
+
+ // Source Abi Diff
+ sAbiDiff android.OptionalPath
+
// Decorated interafaces
*baseCompiler
*baseLinker
@@ -316,7 +325,20 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa
}
return Objects{}
}
+ if ctx.createVndkSourceAbiDump() || (library.sabi.Properties.CreateSAbiDumps && ctx.Device()) {
+ exportIncludeDirs := android.PathsForModuleSrc(ctx, library.flagExporter.Properties.Export_include_dirs)
+ var SourceAbiFlags []string
+ for _, dir := range exportIncludeDirs.Strings() {
+ SourceAbiFlags = append(SourceAbiFlags, "-I "+dir)
+ }
+ flags.SAbiFlags = SourceAbiFlags
+ total_length := len(library.baseCompiler.Properties.Srcs) + len(deps.GeneratedSources) + len(library.Properties.Shared.Srcs) +
+ len(library.Properties.Static.Srcs)
+ if total_length > 0 {
+ flags.SAbiDump = true
+ }
+ }
objs := library.baseCompiler.compile(ctx, flags, deps)
library.reuseObjects = objs
buildFlags := flagsToBuilderFlags(flags)
@@ -534,11 +556,45 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext,
objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...)
objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
+
+ objs.sAbiDumpFiles = append(objs.sAbiDumpFiles, deps.StaticLibObjs.sAbiDumpFiles...)
+ objs.sAbiDumpFiles = append(objs.sAbiDumpFiles, deps.WholeStaticLibObjs.sAbiDumpFiles...)
+
library.coverageOutputFile = TransformCoverageFilesToLib(ctx, objs, builderFlags, library.getLibName(ctx))
+ library.linkSAbiDumpFiles(ctx, objs, fileName)
return ret
}
+func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string) {
+ //Also take into account object re-use.
+ if len(objs.sAbiDumpFiles) > 0 && ctx.createVndkSourceAbiDump() {
+ refSourceDumpFile := android.PathForVndkRefAbiDump(ctx, "current", fileName, vndkVsNdk(ctx), true)
+ versionScript := android.OptionalPathForModuleSrc(ctx, library.Properties.Version_script)
+ var symbolFile android.OptionalPath
+ if versionScript.Valid() {
+ symbolFile = versionScript
+ }
+ exportIncludeDirs := android.PathsForModuleSrc(ctx, library.flagExporter.Properties.Export_include_dirs)
+ var SourceAbiFlags []string
+ for _, dir := range exportIncludeDirs.Strings() {
+ SourceAbiFlags = append(SourceAbiFlags, "-I "+dir)
+ }
+ exportedHeaderFlags := strings.Join(SourceAbiFlags, " ")
+ library.sAbiOutputFile = TransformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, symbolFile, "current", fileName, exportedHeaderFlags)
+ if refSourceDumpFile.Valid() {
+ library.sAbiDiff = SourceAbiDiff(ctx, library.sAbiOutputFile.Path(), refSourceDumpFile.Path(), fileName)
+ }
+ }
+}
+
+func vndkVsNdk(ctx ModuleContext) bool {
+ if inList(ctx.baseModuleName(), config.LLndkLibraries()) {
+ return false
+ }
+ return true
+}
+
func (library *libraryDecorator) link(ctx ModuleContext,
flags Flags, deps PathDeps, objs Objects) android.Path {
@@ -656,6 +712,7 @@ func NewLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator)
baseLinker: NewBaseLinker(),
baseInstaller: NewBaseInstaller("lib", "lib64", InstallInSystem),
sanitize: module.sanitize,
+ sabi: module.sabi,
}
module.compiler = library
diff --git a/cc/sabi.go b/cc/sabi.go
new file mode 100644
index 00000000..7ae31c97
--- /dev/null
+++ b/cc/sabi.go
@@ -0,0 +1,63 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+ "android/soong/android"
+ "github.com/google/blueprint"
+
+ "android/soong/cc/config"
+)
+
+type SAbiProperties struct {
+ CreateSAbiDumps bool `blueprint:"mutated"`
+}
+
+type sabi struct {
+ Properties SAbiProperties
+}
+
+func (sabimod *sabi) props() []interface{} {
+ return []interface{}{&sabimod.Properties}
+}
+
+func (sabimod *sabi) begin(ctx BaseModuleContext) {}
+
+func (sabimod *sabi) deps(ctx BaseModuleContext, deps Deps) Deps {
+ return deps
+}
+
+func (sabimod *sabi) flags(ctx ModuleContext, flags Flags) Flags {
+ return flags
+}
+
+func sabiDepsMutator(mctx android.TopDownMutatorContext) {
+ if c, ok := mctx.Module().(*Module); ok &&
+ ((inList(c.Name(), config.VndkLibraries())) || (inList(c.Name(), config.LLndkLibraries())) ||
+ (c.sabi != nil && c.sabi.Properties.CreateSAbiDumps)) {
+ mctx.VisitDirectDeps(func(m blueprint.Module) {
+ tag := mctx.OtherModuleDependencyTag(m)
+ switch tag {
+ case staticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag:
+
+ cc, _ := m.(*Module)
+ if cc == nil {
+ return
+ }
+ cc.sabi.Properties.CreateSAbiDumps = true
+ }
+ })
+ }
+}
diff --git a/cc/util.go b/cc/util.go
index 36d8dd26..18ad8a6b 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -99,11 +99,13 @@ func flagsToBuilderFlags(in Flags) builderFlags {
ldFlags: strings.Join(in.LdFlags, " "),
libFlags: strings.Join(in.libFlags, " "),
tidyFlags: strings.Join(in.TidyFlags, " "),
+ sAbiFlags: strings.Join(in.SAbiFlags, " "),
yasmFlags: strings.Join(in.YasmFlags, " "),
toolchain: in.Toolchain,
clang: in.Clang,
coverage: in.Coverage,
tidy: in.Tidy,
+ sAbiDump: in.SAbiDump,
systemIncludeFlags: strings.Join(in.SystemIncludeFlags, " "),