Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 97b85314 authored by Jingwen Chen's avatar Jingwen Chen
Browse files

Add bp2build support for cpp_std.

This converts cpp_std and gnu_extensions into a -std copt, if cpp_std is
specified or gnu_extensions is false if cpp_std is not specified.

I chose to go with this copts approach because the tradeoff is a much
simpler setting than adding a new attr(s) everywhere that uses features
to set the flag.

This approach limits the number of user-configurable knobs (since users
would then be able to set std in _both_ copts and the new attr). But it
does rely on the user copt overriding the toolchain's default gnu++17
version, which can mean a `-std` flag showing up twice in the action.

Fixes: b/202462232
Test: b build //system/libziparchive:libziparchive
Change-Id: I81dad029059461739b91f318d662e089edb46b84
parent 800112b9
Loading
Loading
Loading
Loading
+84 −0
Original line number Diff line number Diff line
@@ -1677,4 +1677,88 @@ cc_library {
        "//conditions:default": [],
    }),
)`}})

}

func TestCcLibraryCppStdWithGnuExtensions_ConvertstoCopt(t *testing.T) {
	type testCase struct {
		cpp_std        string
		gnu_extensions string
		bazel_cpp_std  string
	}

	testCases := []testCase{
		// Existing usages of cpp_std in AOSP are:
		// experimental, c++11, c++17, c++2a, c++98, gnu++11, gnu++17
		//
		// not set, only emit if gnu_extensions is disabled. the default (gnu+17
		// is set in the toolchain.)
		{cpp_std: "", gnu_extensions: "", bazel_cpp_std: ""},
		{cpp_std: "", gnu_extensions: "false", bazel_cpp_std: "c++17"},
		{cpp_std: "", gnu_extensions: "true", bazel_cpp_std: ""},
		// experimental defaults to gnu++2a
		{cpp_std: "experimental", gnu_extensions: "", bazel_cpp_std: "gnu++2a"},
		{cpp_std: "experimental", gnu_extensions: "false", bazel_cpp_std: "c++2a"},
		{cpp_std: "experimental", gnu_extensions: "true", bazel_cpp_std: "gnu++2a"},
		// Explicitly setting a c++ std does not use replace gnu++ std even if
		// gnu_extensions is true.
		// "c++11",
		{cpp_std: "c++11", gnu_extensions: "", bazel_cpp_std: "c++11"},
		{cpp_std: "c++11", gnu_extensions: "false", bazel_cpp_std: "c++11"},
		{cpp_std: "c++11", gnu_extensions: "true", bazel_cpp_std: "c++11"},
		// "c++17",
		{cpp_std: "c++17", gnu_extensions: "", bazel_cpp_std: "c++17"},
		{cpp_std: "c++17", gnu_extensions: "false", bazel_cpp_std: "c++17"},
		{cpp_std: "c++17", gnu_extensions: "true", bazel_cpp_std: "c++17"},
		// "c++2a",
		{cpp_std: "c++2a", gnu_extensions: "", bazel_cpp_std: "c++2a"},
		{cpp_std: "c++2a", gnu_extensions: "false", bazel_cpp_std: "c++2a"},
		{cpp_std: "c++2a", gnu_extensions: "true", bazel_cpp_std: "c++2a"},
		// "c++98",
		{cpp_std: "c++98", gnu_extensions: "", bazel_cpp_std: "c++98"},
		{cpp_std: "c++98", gnu_extensions: "false", bazel_cpp_std: "c++98"},
		{cpp_std: "c++98", gnu_extensions: "true", bazel_cpp_std: "c++98"},
		// gnu++ is replaced with c++ if gnu_extensions is explicitly false.
		// "gnu++11",
		{cpp_std: "gnu++11", gnu_extensions: "", bazel_cpp_std: "gnu++11"},
		{cpp_std: "gnu++11", gnu_extensions: "false", bazel_cpp_std: "c++11"},
		{cpp_std: "gnu++11", gnu_extensions: "true", bazel_cpp_std: "gnu++11"},
		// "gnu++17",
		{cpp_std: "gnu++17", gnu_extensions: "", bazel_cpp_std: "gnu++17"},
		{cpp_std: "gnu++17", gnu_extensions: "false", bazel_cpp_std: "c++17"},
		{cpp_std: "gnu++17", gnu_extensions: "true", bazel_cpp_std: "gnu++17"},
	}
	for _, tc := range testCases {
		cppStdAttr := ""
		if tc.cpp_std != "" {
			cppStdAttr = fmt.Sprintf("    cpp_std: \"%s\",", tc.cpp_std)
		}
		gnuExtensionsAttr := ""
		if tc.gnu_extensions != "" {
			gnuExtensionsAttr = fmt.Sprintf("    gnu_extensions: %s,", tc.gnu_extensions)
		}
		bazelCppStdAttr := ""
		if tc.bazel_cpp_std != "" {
			bazelCppStdAttr = fmt.Sprintf("\n    copts = [\"-std=%s\"],", tc.bazel_cpp_std)
		}

		runCcLibraryTestCase(t, bp2buildTestCase{
			description: fmt.Sprintf(
				"cc_library with cpp_std: %s and gnu_extensions: %s", tc.cpp_std, tc.gnu_extensions),
			moduleTypeUnderTest:                "cc_library",
			moduleTypeUnderTestFactory:         cc.LibraryFactory,
			moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
			blueprint: soongCcLibraryPreamble + fmt.Sprintf(`
cc_library {
	name: "a",
%s // cpp_std: *string
%s // gnu_extensions: *bool
	include_build_directory: false,
}
`, cppStdAttr, gnuExtensionsAttr),
			expectedBazelTargets: []string{fmt.Sprintf(`cc_library(
    name = "a",%s
)`, bazelCppStdAttr)},
		})
	}
}
+18 −1
Original line number Diff line number Diff line
@@ -277,7 +277,24 @@ func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Modul
					srcs.SetSelectValue(axis, config, srcsList)
				}

				archVariantCopts := parseCommandLineFlags(baseCompilerProps.Cflags)
				var archVariantCopts []string
				if axis == bazel.NoConfigAxis {
					// If cpp_std is not specified, don't generate it in the
					// BUILD file. For readability purposes, cpp_std and gnu_extensions are
					// combined into a single -std=<version> copt, except in the
					// default case where cpp_std is nil and gnu_extensions is true or unspecified,
					// then the toolchain's default "gnu++17" will be used.
					if baseCompilerProps.Cpp_std != nil {
						// TODO(b/202491296): Handle C_std.
						// These transformations are shared with compiler.go.
						cppStdVal := parseCppStd(baseCompilerProps.Cpp_std)
						_, cppStdVal = maybeReplaceGnuToC(baseCompilerProps.Gnu_extensions, "", cppStdVal)
						archVariantCopts = append(archVariantCopts, "-std="+cppStdVal)
					} else if baseCompilerProps.Gnu_extensions != nil && !*baseCompilerProps.Gnu_extensions {
						archVariantCopts = append(archVariantCopts, "-std=c++17")
					}
				}
				archVariantCopts = append(archVariantCopts, parseCommandLineFlags(baseCompilerProps.Cflags)...)
				archVariantAsflags := parseCommandLineFlags(baseCompilerProps.Asflags)

				localIncludeDirs := baseCompilerProps.Local_include_dirs
+21 −11
Original line number Diff line number Diff line
@@ -305,6 +305,25 @@ func addToModuleList(ctx ModuleContext, key android.OnceKey, module string) {
	getNamedMapForConfig(ctx.Config(), key).Store(module, true)
}

func maybeReplaceGnuToC(gnuExtensions *bool, cStd string, cppStd string) (string, string) {
	if gnuExtensions != nil && *gnuExtensions == false {
		cStd = gnuToCReplacer.Replace(cStd)
		cppStd = gnuToCReplacer.Replace(cppStd)
	}
	return cStd, cppStd
}

func parseCppStd(cppStdPtr *string) string {
	cppStd := String(cppStdPtr)
	switch cppStd {
	case "":
		cppStd = config.CppStdVersion
	case "experimental":
		cppStd = config.ExperimentalCppStdVersion
	}
	return cppStd
}

// Create a Flags struct that collects the compile flags from global values,
// per-target values, module type values, and per-module Blueprints properties
func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags {
@@ -484,18 +503,9 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps
		cStd = String(compiler.Properties.C_std)
	}

	cppStd := String(compiler.Properties.Cpp_std)
	switch String(compiler.Properties.Cpp_std) {
	case "":
		cppStd = config.CppStdVersion
	case "experimental":
		cppStd = config.ExperimentalCppStdVersion
	}
	cppStd := parseCppStd(compiler.Properties.Cpp_std)

	if compiler.Properties.Gnu_extensions != nil && *compiler.Properties.Gnu_extensions == false {
		cStd = gnuToCReplacer.Replace(cStd)
		cppStd = gnuToCReplacer.Replace(cppStd)
	}
	cStd, cppStd = maybeReplaceGnuToC(compiler.Properties.Gnu_extensions, cStd, cppStd)

	flags.Local.ConlyFlags = append([]string{"-std=" + cStd}, flags.Local.ConlyFlags...)
	flags.Local.CppFlags = append([]string{"-std=" + cppStd}, flags.Local.CppFlags...)