From 3d94752b34a053af3eeaf00659ccd0761e078a6a Mon Sep 17 00:00:00 2001 From: Ivan Lozano Date: Wed, 23 Sep 2020 13:26:25 -0400 Subject: [PATCH] rust: Add rust_bindgen std version w/ cc defaults. Adds the c_std and cpp_std properties to rust_bindgen, and use the default values from cc if these are undefined. This assumes by default that the header extension indicates whether the header is a C or C++ header file. This default can be overridden by setting either c_std or cpp_std. Test: Soong tests pass, "-std=" arg included in bindgen calls Bug: 163580541 Change-Id: I5b0d3b8eae9a54dd91d8a0aca583d7803a344f27 --- rust/bindgen.go | 73 +++++++++++++++++++++++++++++++++++++++++++- rust/bindgen_test.go | 44 ++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 1 deletion(-) diff --git a/rust/bindgen.go b/rust/bindgen.go index cafdb8bfa..0d89b241e 100644 --- a/rust/bindgen.go +++ b/rust/bindgen.go @@ -21,6 +21,7 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + cc_config "android/soong/cc/config" ) var ( @@ -56,7 +57,11 @@ func init() { var _ SourceProvider = (*bindgenDecorator)(nil) type BindgenProperties struct { - // The wrapper header file + // The wrapper header file. By default this is assumed to be a C header unless the extension is ".hh" or ".hpp". + // This is used to specify how to interpret the header and determines which '-std' flag to use by default. + // + // If your C++ header must have some other extension, then the default behavior can be overridden by setting the + // cpp_std property. Wrapper_src *string `android:"path,arch_variant"` // list of bindgen-specific flags and options @@ -81,6 +86,22 @@ type BindgenProperties struct { // "my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]" Custom_bindgen string `android:"path"` + // C standard version to use. Can be a specific version (such as "gnu11"), + // "experimental" (which will use draft versions like C1x when available), + // or the empty string (which will use the default). + // + // If this is set, the file extension will be ignored and this will be used as the std version value. Setting this + // to "default" will use the build system default version. This cannot be set at the same time as cpp_std. + C_std *string + + // C++ standard version to use. Can be a specific version (such as + // "gnu++11"), "experimental" (which will use draft versions like C++1z when + // available), or the empty string (which will use the default). + // + // If this is set, the file extension will be ignored and this will be used as the std version value. Setting this + // to "default" will use the build system default version. This cannot be set at the same time as c_std. + Cpp_std *string + //TODO(b/161141999) Add support for headers from cc_library_header modules. } @@ -90,6 +111,45 @@ type bindgenDecorator struct { Properties BindgenProperties } +func (b *bindgenDecorator) getStdVersion(ctx ModuleContext, src android.Path) (string, bool) { + // Assume headers are C headers + isCpp := false + stdVersion := "" + + switch src.Ext() { + case ".hpp", ".hh": + isCpp = true + } + + if String(b.Properties.Cpp_std) != "" && String(b.Properties.C_std) != "" { + ctx.PropertyErrorf("c_std", "c_std and cpp_std cannot both be defined at the same time.") + } + + if String(b.Properties.Cpp_std) != "" { + if String(b.Properties.Cpp_std) == "experimental" { + stdVersion = cc_config.ExperimentalCppStdVersion + } else if String(b.Properties.Cpp_std) == "default" { + stdVersion = cc_config.CppStdVersion + } else { + stdVersion = String(b.Properties.Cpp_std) + } + } else if b.Properties.C_std != nil { + if String(b.Properties.C_std) == "experimental" { + stdVersion = cc_config.ExperimentalCStdVersion + } else if String(b.Properties.C_std) == "default" { + stdVersion = cc_config.CStdVersion + } else { + stdVersion = String(b.Properties.C_std) + } + } else if isCpp { + stdVersion = cc_config.CppStdVersion + } else { + stdVersion = cc_config.CStdVersion + } + + return stdVersion, isCpp +} + func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path { ccToolchain := ctx.RustModule().ccToolchain(ctx) @@ -134,6 +194,17 @@ func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) andr ctx.PropertyErrorf("wrapper_src", "invalid path to wrapper source") } + // Add C std version flag + stdVersion, isCpp := b.getStdVersion(ctx, wrapperFile.Path()) + cflags = append(cflags, "-std="+stdVersion) + + // Specify the header source language to avoid ambiguity. + if isCpp { + cflags = append(cflags, "-x c++") + } else { + cflags = append(cflags, "-x c") + } + outputFile := android.PathForModuleOut(ctx, b.BaseSourceProvider.getStem(ctx)+".rs") var cmd, cmdDesc string diff --git a/rust/bindgen_test.go b/rust/bindgen_test.go index 191da9b11..359f28b83 100644 --- a/rust/bindgen_test.go +++ b/rust/bindgen_test.go @@ -82,3 +82,47 @@ func TestRustBindgenCustomBindgen(t *testing.T) { libbindgen.Description) } } + +func TestRustBindgenStdVersions(t *testing.T) { + testRustError(t, "c_std and cpp_std cannot both be defined at the same time.", ` + rust_bindgen { + name: "libbindgen", + wrapper_src: "src/any.h", + crate_name: "bindgen", + stem: "libbindgen", + source_stem: "bindings", + c_std: "somevalue", + cpp_std: "somevalue", + } + `) + + ctx := testRust(t, ` + rust_bindgen { + name: "libbindgen_cstd", + wrapper_src: "src/any.h", + crate_name: "bindgen", + stem: "libbindgen", + source_stem: "bindings", + c_std: "foo" + } + rust_bindgen { + name: "libbindgen_cppstd", + wrapper_src: "src/any.h", + crate_name: "bindgen", + stem: "libbindgen", + source_stem: "bindings", + cpp_std: "foo" + } + `) + + libbindgen_cstd := ctx.ModuleForTests("libbindgen_cstd", "android_arm64_armv8-a").Output("bindings.rs") + libbindgen_cppstd := ctx.ModuleForTests("libbindgen_cppstd", "android_arm64_armv8-a").Output("bindings.rs") + + if !strings.Contains(libbindgen_cstd.Args["cflags"], "-std=foo") { + t.Errorf("c_std value not passed in to rust_bindgen as a clang flag") + } + + if !strings.Contains(libbindgen_cppstd.Args["cflags"], "-std=foo") { + t.Errorf("cpp_std value not passed in to rust_bindgen as a clang flag") + } +}