diff --git a/android/arch.go b/android/arch.go index 583793efe..7ca733606 100644 --- a/android/arch.go +++ b/android/arch.go @@ -255,7 +255,7 @@ func (os OsType) Bionic() bool { // Linux returns true if the OS uses the Linux kernel, i.e. if the OS is Android or is Linux // with or without the Bionic libc runtime. func (os OsType) Linux() bool { - return os == Android || os == Linux || os == LinuxBionic + return os == Android || os == Linux || os == LinuxBionic || os == LinuxMusl } // newOsType constructs an OsType and adds it to the global lists. @@ -305,6 +305,8 @@ var ( NoOsType OsType // Linux is the OS for the Linux kernel plus the glibc runtime. Linux = newOsType("linux_glibc", Host, false, X86, X86_64) + // LinuxMusl is the OS for the Linux kernel plus the musl runtime. + LinuxMusl = newOsType("linux_musl", Host, false, X86, X86_64) // Darwin is the OS for MacOS/Darwin host machines. Darwin = newOsType("darwin", Host, false, X86_64) // LinuxBionic is the OS for the Linux kernel plus the Bionic libc runtime, but without the @@ -863,6 +865,8 @@ func createArchPropTypeDesc(props reflect.Type) []archPropTypeDesc { "Android64", "Android32", "Bionic", + "Glibc", + "Musl", "Linux", "Not_windows", "Arm_on_x86", @@ -1108,6 +1112,30 @@ func (m *ModuleBase) setOSProperties(ctx BottomUpMutatorContext) { } } + if os == Linux { + field := "Glibc" + prefix := "target.glibc" + if bionicProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok { + mergePropertyStruct(ctx, genProps, bionicProperties) + } + } + + if os == LinuxMusl { + field := "Musl" + prefix := "target.musl" + if bionicProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok { + mergePropertyStruct(ctx, genProps, bionicProperties) + } + + // Special case: to ease the transition from glibc to musl, apply linux_glibc + // properties (which has historically mean host linux) to musl variants. + field = "Linux_glibc" + prefix = "target.linux_glibc" + if bionicProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok { + mergePropertyStruct(ctx, genProps, bionicProperties) + } + } + // Handle target OS properties in the form: // target: { // linux_glibc: { @@ -1310,6 +1338,16 @@ func getArchProperties(ctx BaseMutatorContext, archProperties interface{}, arch if osArchProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok { result = append(result, osArchProperties) } + + if os == LinuxMusl { + // Special case: to ease the transition from glibc to musl, apply linux_glibc + // properties (which has historically mean host linux) to musl variants. + field := "Linux_glibc_" + archType.Name + userFriendlyField := "target.linux_glibc_" + archType.Name + if osArchProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok { + result = append(result, osArchProperties) + } + } } // Handle arm on x86 properties in the form: @@ -1375,11 +1413,14 @@ func (m *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) { } // determineBuildOS stores the OS and architecture used for host targets used during the build into -// config based on the runtime OS and architecture determined by Go. +// config based on the runtime OS and architecture determined by Go and the product configuration. func determineBuildOS(config *config) { config.BuildOS = func() OsType { switch runtime.GOOS { case "linux": + if Bool(config.productVariables.HostMusl) { + return LinuxMusl + } return Linux case "darwin": return Darwin diff --git a/android/arch_test.go b/android/arch_test.go index 2a2fd454e..a82832115 100644 --- a/android/arch_test.go +++ b/android/arch_test.go @@ -508,9 +508,12 @@ func TestArchProperties(t *testing.T) { bionic: { a: ["bionic"] }, host: { a: ["host"] }, android: { a: ["android"] }, + glibc: { a: ["glibc"] }, + musl: { a: ["musl"] }, linux_bionic: { a: ["linux_bionic"] }, linux: { a: ["linux"] }, linux_glibc: { a: ["linux_glibc"] }, + linux_musl: { a: ["linux_musl"] }, windows: { a: ["windows"], enabled: true }, darwin: { a: ["darwin"] }, not_windows: { a: ["not_windows"] }, @@ -522,6 +525,8 @@ func TestArchProperties(t *testing.T) { linux_x86_64: { a: ["linux_x86_64"] }, linux_glibc_x86: { a: ["linux_glibc_x86"] }, linux_glibc_x86_64: { a: ["linux_glibc_x86_64"] }, + linux_musl_x86: { a: ["linux_musl_x86"] }, + linux_musl_x86_64: { a: ["linux_musl_x86_64"] }, darwin_x86_64: { a: ["darwin_x86_64"] }, windows_x86: { a: ["windows_x86"] }, windows_x86_64: { a: ["windows_x86_64"] }, @@ -563,12 +568,12 @@ func TestArchProperties(t *testing.T) { { module: "foo", variant: "linux_glibc_x86_64", - property: []string{"root", "host", "linux", "linux_glibc", "not_windows", "x86_64", "lib64", "linux_x86_64", "linux_glibc_x86_64"}, + property: []string{"root", "host", "linux", "glibc", "linux_glibc", "not_windows", "x86_64", "lib64", "linux_x86_64", "linux_glibc_x86_64"}, }, { module: "foo", variant: "linux_glibc_x86", - property: []string{"root", "host", "linux", "linux_glibc", "not_windows", "x86", "lib32", "linux_x86", "linux_glibc_x86"}, + property: []string{"root", "host", "linux", "glibc", "linux_glibc", "not_windows", "x86", "lib32", "linux_x86", "linux_glibc_x86"}, }, }, }, @@ -594,6 +599,23 @@ func TestArchProperties(t *testing.T) { }, }, }, + { + name: "linux_musl", + goOS: "linux", + preparer: FixtureModifyConfig(modifyTestConfigForMusl), + results: []result{ + { + module: "foo", + variant: "linux_musl_x86_64", + property: []string{"root", "host", "linux", "musl", "linux_glibc", "linux_musl", "not_windows", "x86_64", "lib64", "linux_x86_64", "linux_musl_x86_64", "linux_glibc_x86_64"}, + }, + { + module: "foo", + variant: "linux_musl_x86", + property: []string{"root", "host", "linux", "musl", "linux_glibc", "linux_musl", "not_windows", "x86", "lib32", "linux_x86", "linux_musl_x86", "linux_glibc_x86"}, + }, + }, + }, { name: "darwin", goOS: "darwin", diff --git a/android/config.go b/android/config.go index 871986c7c..9addf5de9 100644 --- a/android/config.go +++ b/android/config.go @@ -362,6 +362,19 @@ func modifyTestConfigToSupportArchMutator(testConfig Config) { config.TestProductVariables.DeviceSecondaryArchVariant = proptools.StringPtr("armv7-a-neon") } +func modifyTestConfigForMusl(config Config) { + delete(config.Targets, config.BuildOS) + config.productVariables.HostMusl = boolPtr(true) + determineBuildOS(config.config) + config.Targets[config.BuildOS] = []Target{ + {config.BuildOS, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", false}, + {config.BuildOS, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", false}, + } + + config.BuildOSTarget = config.Targets[config.BuildOS][0] + config.BuildOSCommonTarget = getCommonTargets(config.Targets[config.BuildOS])[0] +} + // TestArchConfig returns a Config object suitable for using for tests that // need to run the arch mutator. func TestArchConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config { diff --git a/android/paths.go b/android/paths.go index bec8a51a2..99db22f6e 100644 --- a/android/paths.go +++ b/android/paths.go @@ -1667,7 +1667,7 @@ func pathForInstall(ctx PathContext, os OsType, arch ArchType, partition string, partionPaths = []string{"target", "product", ctx.Config().DeviceName(), partition} } else { osName := os.String() - if os == Linux { + if os == Linux || os == LinuxMusl { // instead of linux_glibc osName = "linux" } diff --git a/android/variable.go b/android/variable.go index d0a23aaa1..d32debe42 100644 --- a/android/variable.go +++ b/android/variable.go @@ -203,6 +203,7 @@ type productVariables struct { HostArch *string `json:",omitempty"` HostSecondaryArch *string `json:",omitempty"` + HostMusl *bool `json:",omitempty"` CrossHost *string `json:",omitempty"` CrossHostArch *string `json:",omitempty"` diff --git a/bazel/configurability.go b/bazel/configurability.go index 3277bd049..f5f0913ee 100644 --- a/bazel/configurability.go +++ b/bazel/configurability.go @@ -30,6 +30,7 @@ const ( osAndroid = "android" osDarwin = "darwin" osLinux = "linux_glibc" + osLinuxMusl = "linux_musl" osLinuxBionic = "linux_bionic" osWindows = "windows" @@ -41,6 +42,8 @@ const ( osArchDarwinX86_64 = "darwin_x86_64" osArchLinuxX86 = "linux_glibc_x86" osArchLinuxX86_64 = "linux_glibc_x86_64" + osArchLinuxMuslX86 = "linux_musl_x86" + osArchLinuxMuslX86_64 = "linux_musl_x86_64" osArchLinuxBionicArm64 = "linux_bionic_arm64" osArchLinuxBionicX86_64 = "linux_bionic_x86_64" osArchWindowsX86 = "windows_x86" @@ -82,6 +85,7 @@ var ( osAndroid: "//build/bazel/platforms/os:android", osDarwin: "//build/bazel/platforms/os:darwin", osLinux: "//build/bazel/platforms/os:linux", + osLinuxMusl: "//build/bazel/platforms/os:linux_musl", osLinuxBionic: "//build/bazel/platforms/os:linux_bionic", osWindows: "//build/bazel/platforms/os:windows", conditionsDefault: ConditionsDefaultSelectKey, // The default condition of an os select map. @@ -100,6 +104,8 @@ var ( osArchDarwinX86_64: "//build/bazel/platforms/os_arch:darwin_x86_64", osArchLinuxX86: "//build/bazel/platforms/os_arch:linux_glibc_x86", osArchLinuxX86_64: "//build/bazel/platforms/os_arch:linux_glibc_x86_64", + osArchLinuxMuslX86: "//build/bazel/platforms/os_arch:linux_musl_x86", + osArchLinuxMuslX86_64: "//build/bazel/platforms/os_arch:linux_musl_x86_64", osArchLinuxBionicArm64: "//build/bazel/platforms/os_arch:linux_bionic_arm64", osArchLinuxBionicX86_64: "//build/bazel/platforms/os_arch:linux_bionic_x86_64", osArchWindowsX86: "//build/bazel/platforms/os_arch:windows_x86", diff --git a/cc/binary.go b/cc/binary.go index c6d61abbb..763d2b925 100644 --- a/cc/binary.go +++ b/cc/binary.go @@ -335,7 +335,7 @@ func (binary *binaryDecorator) link(ctx ModuleContext, if flags.DynamicLinker != "" { flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-dynamic-linker,"+flags.DynamicLinker) - } else if ctx.toolchain().Bionic() && !binary.static() { + } else if (ctx.toolchain().Bionic() || ctx.toolchain().Musl()) && !binary.static() { flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--no-dynamic-linker") } diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go index ff556f179..20384a871 100644 --- a/cc/config/toolchain.go +++ b/cc/config/toolchain.go @@ -118,6 +118,8 @@ type Toolchain interface { DefaultSharedLibraries() []string Bionic() bool + Glibc() bool + Musl() bool } type toolchainBase struct { @@ -194,6 +196,14 @@ func (toolchainBase) Bionic() bool { return false } +func (toolchainBase) Glibc() bool { + return false +} + +func (toolchainBase) Musl() bool { + return false +} + func (t toolchainBase) ToolPath() string { return "" } diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go index 85d95d80f..1d66cb713 100644 --- a/cc/config/x86_linux_host.go +++ b/cc/config/x86_linux_host.go @@ -36,10 +36,18 @@ var ( "-D__STDC_CONSTANT_MACROS", "--gcc-toolchain=${LinuxGccRoot}", - "--sysroot ${LinuxGccRoot}/sysroot", "-fstack-protector-strong", } + linuxGlibcCflags = []string{ + "--sysroot ${LinuxGccRoot}/sysroot", + } + + linuxMuslCflags = []string{ + "-D_LIBCPP_HAS_MUSL_LIBC", + "-nostdlibinc", + } + linuxLdflags = []string{ "-Wl,-z,noexecstack", "-Wl,-z,relro", @@ -47,9 +55,17 @@ var ( "-Wl,--no-undefined-version", "--gcc-toolchain=${LinuxGccRoot}", + } + + linuxGlibcLdflags = []string{ "--sysroot ${LinuxGccRoot}/sysroot", } + linuxMuslLdflags = []string{ + "-nostdlib", + "-lgcc", "-lgcc_eh", + } + // Extended cflags linuxX86Cflags = []string{ "-msse3", @@ -89,6 +105,12 @@ var ( "rt", "util", }, "-l") + + muslCrtBeginStaticBinary, muslCrtEndStaticBinary = []string{"libc_musl_crtbegin_static"}, []string{"crtend_android"} + muslCrtBeginSharedBinary, muslCrtEndSharedBinary = []string{"libc_musl_crtbegin_dynamic", "musl_linker_script"}, []string{"libc_musl_crtend"} + muslCrtBeginSharedLibrary, muslCrtEndSharedLibrary = []string{"libc_musl_crtbegin_so"}, []string{"libc_musl_crtend_so"} + + muslDefaultSharedLibraries = []string{"libjemalloc5", "libc_musl"} ) const ( @@ -124,6 +146,13 @@ func init() { // Yasm flags pctx.StaticVariable("LinuxX86YasmFlags", "-f elf32 -m x86") pctx.StaticVariable("LinuxX8664YasmFlags", "-f elf64 -m amd64") + + pctx.StaticVariable("LinuxGlibcCflags", strings.Join(linuxGlibcCflags, " ")) + pctx.StaticVariable("LinuxGlibcLdflags", strings.Join(linuxGlibcLdflags, " ")) + pctx.StaticVariable("LinuxGlibcLldflags", strings.Join(linuxGlibcLdflags, " ")) + pctx.StaticVariable("LinuxMuslCflags", strings.Join(linuxMuslCflags, " ")) + pctx.StaticVariable("LinuxMuslLdflags", strings.Join(linuxMuslLdflags, " ")) + pctx.StaticVariable("LinuxMuslLldflags", strings.Join(linuxMuslLdflags, " ")) } type toolchainLinux struct { @@ -224,18 +253,146 @@ func (t *toolchainLinux) AvailableLibraries() []string { return linuxAvailableLibraries } -var toolchainLinuxX86Singleton Toolchain = &toolchainLinuxX86{} -var toolchainLinuxX8664Singleton Toolchain = &toolchainLinuxX8664{} +// glibc specialization of the linux toolchain -func linuxX86ToolchainFactory(arch android.Arch) Toolchain { - return toolchainLinuxX86Singleton +type toolchainGlibc struct { } -func linuxX8664ToolchainFactory(arch android.Arch) Toolchain { - return toolchainLinuxX8664Singleton +func (toolchainGlibc) Glibc() bool { return true } + +func (toolchainGlibc) Cflags() string { + return "${config.LinuxGlibcCflags}" +} + +func (toolchainGlibc) Ldflags() string { + return "${config.LinuxGlibcLdflags}" +} + +func (toolchainGlibc) Lldflags() string { + return "${config.LinuxGlibcLldflags}" +} + +type toolchainLinuxGlibcX86 struct { + toolchainLinuxX86 + toolchainGlibc +} + +type toolchainLinuxGlibcX8664 struct { + toolchainLinuxX8664 + toolchainGlibc +} + +func (t *toolchainLinuxGlibcX86) Cflags() string { + return t.toolchainLinuxX86.Cflags() + " " + t.toolchainGlibc.Cflags() +} + +func (t *toolchainLinuxGlibcX86) Ldflags() string { + return t.toolchainLinuxX86.Ldflags() + " " + t.toolchainGlibc.Ldflags() +} + +func (t *toolchainLinuxGlibcX86) Lldflags() string { + return t.toolchainLinuxX86.Lldflags() + " " + t.toolchainGlibc.Lldflags() +} + +func (t *toolchainLinuxGlibcX8664) Cflags() string { + return t.toolchainLinuxX8664.Cflags() + " " + t.toolchainGlibc.Cflags() +} + +func (t *toolchainLinuxGlibcX8664) Ldflags() string { + return t.toolchainLinuxX8664.Ldflags() + " " + t.toolchainGlibc.Ldflags() +} + +func (t *toolchainLinuxGlibcX8664) Lldflags() string { + return t.toolchainLinuxX8664.Lldflags() + " " + t.toolchainGlibc.Lldflags() +} + +var toolchainLinuxGlibcX86Singleton Toolchain = &toolchainLinuxGlibcX86{} +var toolchainLinuxGlibcX8664Singleton Toolchain = &toolchainLinuxGlibcX8664{} + +func linuxGlibcX86ToolchainFactory(arch android.Arch) Toolchain { + return toolchainLinuxGlibcX86Singleton +} + +func linuxGlibcX8664ToolchainFactory(arch android.Arch) Toolchain { + return toolchainLinuxGlibcX8664Singleton +} + +// musl specialization of the linux toolchain + +type toolchainMusl struct { +} + +func (toolchainMusl) Musl() bool { return true } + +func (toolchainMusl) CrtBeginStaticBinary() []string { return muslCrtBeginStaticBinary } +func (toolchainMusl) CrtBeginSharedBinary() []string { return muslCrtBeginSharedBinary } +func (toolchainMusl) CrtBeginSharedLibrary() []string { return muslCrtBeginSharedLibrary } +func (toolchainMusl) CrtEndStaticBinary() []string { return muslCrtEndStaticBinary } +func (toolchainMusl) CrtEndSharedBinary() []string { return muslCrtEndSharedBinary } +func (toolchainMusl) CrtEndSharedLibrary() []string { return muslCrtEndSharedLibrary } + +func (toolchainMusl) DefaultSharedLibraries() []string { return muslDefaultSharedLibraries } + +func (toolchainMusl) Cflags() string { + return "${config.LinuxMuslCflags}" +} + +func (toolchainMusl) Ldflags() string { + return "${config.LinuxMuslLdflags}" +} + +func (toolchainMusl) Lldflags() string { + return "${config.LinuxMuslLldflags}" +} + +type toolchainLinuxMuslX86 struct { + toolchainLinuxX86 + toolchainMusl +} + +type toolchainLinuxMuslX8664 struct { + toolchainLinuxX8664 + toolchainMusl +} + +func (t *toolchainLinuxMuslX86) Cflags() string { + return t.toolchainLinuxX86.Cflags() + " " + t.toolchainMusl.Cflags() +} + +func (t *toolchainLinuxMuslX86) Ldflags() string { + return t.toolchainLinuxX86.Ldflags() + " " + t.toolchainMusl.Ldflags() +} + +func (t *toolchainLinuxMuslX86) Lldflags() string { + return t.toolchainLinuxX86.Lldflags() + " " + t.toolchainMusl.Lldflags() +} + +func (t *toolchainLinuxMuslX8664) Cflags() string { + return t.toolchainLinuxX8664.Cflags() + " " + t.toolchainMusl.Cflags() +} + +func (t *toolchainLinuxMuslX8664) Ldflags() string { + return t.toolchainLinuxX8664.Ldflags() + " " + t.toolchainMusl.Ldflags() +} + +func (t *toolchainLinuxMuslX8664) Lldflags() string { + return t.toolchainLinuxX8664.Lldflags() + " " + t.toolchainMusl.Lldflags() +} + +var toolchainLinuxMuslX86Singleton Toolchain = &toolchainLinuxMuslX86{} +var toolchainLinuxMuslX8664Singleton Toolchain = &toolchainLinuxMuslX8664{} + +func linuxMuslX86ToolchainFactory(arch android.Arch) Toolchain { + return toolchainLinuxMuslX86Singleton +} + +func linuxMuslX8664ToolchainFactory(arch android.Arch) Toolchain { + return toolchainLinuxMuslX8664Singleton } func init() { - registerToolchainFactory(android.Linux, android.X86, linuxX86ToolchainFactory) - registerToolchainFactory(android.Linux, android.X86_64, linuxX8664ToolchainFactory) + registerToolchainFactory(android.Linux, android.X86, linuxGlibcX86ToolchainFactory) + registerToolchainFactory(android.Linux, android.X86_64, linuxGlibcX8664ToolchainFactory) + registerToolchainFactory(android.LinuxMusl, android.X86, linuxMuslX86ToolchainFactory) + registerToolchainFactory(android.LinuxMusl, android.X86_64, linuxMuslX8664ToolchainFactory) } diff --git a/cc/linker.go b/cc/linker.go index 5dd757a43..a12a018c5 100644 --- a/cc/linker.go +++ b/cc/linker.go @@ -369,6 +369,10 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps { indexList("libdl", deps.SystemSharedLibs) < indexList("libc", deps.SystemSharedLibs) { ctx.PropertyErrorf("system_shared_libs", "libdl must be after libc") } + } else if ctx.toolchain().Musl() { + if !Bool(linker.Properties.No_libcrt) && !ctx.header() { + deps.LateStaticLibs = append(deps.LateStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain())) + } } deps.LateSharedLibs = append(deps.LateSharedLibs, deps.SystemSharedLibs...) @@ -456,7 +460,7 @@ func (linker *baseLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.Ldflags()) } - if !ctx.toolchain().Bionic() { + if !ctx.toolchain().Bionic() && ctx.Os() != android.LinuxMusl { CheckBadHostLdlibs(ctx, "host_ldlibs", linker.Properties.Host_ldlibs) flags.Local.LdFlags = append(flags.Local.LdFlags, linker.Properties.Host_ldlibs...) diff --git a/cc/sanitize.go b/cc/sanitize.go index 3911f48b3..b24439437 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -472,8 +472,8 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { s.Diag.Cfi = nil } - // Disable sanitizers that depend on the UBSan runtime for windows/darwin builds. - if !ctx.Os().Linux() { + // Disable sanitizers that depend on the UBSan runtime for windows/darwin/musl builds. + if !ctx.Os().Linux() || ctx.Os() == android.LinuxMusl { s.Cfi = nil s.Diag.Cfi = nil s.Misc_undefined = nil diff --git a/cc/testing.go b/cc/testing.go index 59e8497a0..e8f348115 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -450,6 +450,25 @@ func commonDefaultModules() string { cc_library_static { name: "note_memtag_heap_sync", } + + + cc_library { + name: "libjemalloc5", + host_supported: true, + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + } + + cc_library { + name: "libc_musl", + host_supported: true, + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + } ` } diff --git a/rust/config/x86_linux_host.go b/rust/config/x86_linux_host.go index a9fdaed45..0aa534f87 100644 --- a/rust/config/x86_linux_host.go +++ b/rust/config/x86_linux_host.go @@ -37,6 +37,10 @@ func init() { registerToolchainFactory(android.Linux, android.X86_64, linuxX8664ToolchainFactory) registerToolchainFactory(android.Linux, android.X86, linuxX86ToolchainFactory) + // TODO: musl rust support + registerToolchainFactory(android.LinuxMusl, android.X86_64, linuxX8664ToolchainFactory) + registerToolchainFactory(android.LinuxMusl, android.X86, linuxX86ToolchainFactory) + pctx.StaticVariable("LinuxToolchainRustFlags", strings.Join(LinuxRustFlags, " ")) pctx.StaticVariable("LinuxToolchainLinkFlags", strings.Join(LinuxRustLinkFlags, " ")) pctx.StaticVariable("LinuxToolchainX86RustFlags", strings.Join(linuxX86Rustflags, " "))