diff options
-rw-r--r-- | README.md | 156 | ||||
-rw-r--r-- | cc/makevars.go | 48 |
2 files changed, 203 insertions, 1 deletions
diff --git a/README.md b/README.md new file mode 100644 index 00000000..df092e73 --- /dev/null +++ b/README.md @@ -0,0 +1,156 @@ +# Soong + +Soong is the replacement for the old Android make-based build system. It +replaces Android.mk files with Android.bp files, which are JSON-like simple +declarative descriptions of modules to build. + +## Android.bp file format + +By design, Android.bp files are very simple. There are no conditionals or +control flow statements - any complexity is handled in build logic written in +Go. + +### Modules + +A module in an Android.bp file starts with a module type, followed by a set of +properties in `name: value,` format: + +``` +cc_binary { + name: "gzip", + srcs: ["src/test/minigzip.c"], + shared_libs: ["libz"], + stl: "none", +} +``` + +Every module must have a `name` property, and the value must be unique across +all Android.bp files. + +For a list of valid module types and their properties see +[$OUT_DIR/soong/.bootstrap/docs/soong_build.html](https://android-build.googleplex.com/builds/latest/branches/aosp-build-tools/targets/linux/soong_build.html). + +### Variables + +An Android.bp file may contain top-level variable assignments: +``` +gzip_srcs = ["src/test/minigzip.c"], + +cc_binary { + name: "gzip", + srcs: gzip_srcs, + shared_libs: ["libz"], + stl: "none", +} +``` + +Variables are scoped to the remainder of the file they are declared in, as well +as any child blueprint files. Variables are immutable with one exception - they +can be appended to with a += assignment, but only before they have been +referenced. + +### Comments +Android.bp files can contain C-style multiline `/* */` and C++ style single-line +`//` comments. + +### Types + +Variables and properties are strongly typed, variables dynamically based on the +first assignment, and properties statically by the module type. The supported +types are: +* Bool (`true` or `false`) +* Strings (`"string"`) +* Lists of strings (`["string1", "string2"]`) +* Maps (`{key1: "value1", key2: ["value2"]}`) + +Maps may values of any type, including nested maps. Lists and maps may have +trailing commas after the last value. + +### Operators + +Strings, lists of strings, and maps can be appended using the `+` operator. +Appending a map produces the union of keys in both maps, appending the values +of any keys that are present in both maps. + +### Defaults modules + +A defaults module can be used to repeat the same properties in multiple modules. +For example: + +``` +cc_defaults { + name: "gzip_defaults", + shared_libs: ["libz"], + stl: "none", +} + +cc_binary { + name: "gzip", + defaults: ["gzip_defaults"], + srcs: ["src/test/minigzip.c"], +} +``` + +### Formatter + +Soong includes a canonical formatter for blueprint files, similar to +[gofmt](https://golang.org/cmd/gofmt/). To recursively reformat all Android.bp files +in the current directory: +``` +bpfmt -w . +``` + +The canonical format includes 4 space indents, newlines after every element of a +multi-element list, and always includes a trailing comma in lists and maps. + +### Convert Android.mk files + +Soong includes a tool perform a first pass at converting Android.mk files +to Android.bp files: + +``` +androidmk Android.mk > Android.bp +``` + +The tool converts variables, modules, comments, and some conditionals, but any +custom Makefile rules or complex conditionals must be converted by hand. + +## Build logic + +The build logic is written in Go using the +[blueprint](http://godoc.org/github.com/google/blueprint) framework. Build +logic receives module definitions parsed into Go structures using reflection +and produces build rules. The build rules are collected by blueprint and +written to a [ninja](http://ninja-build.org) build file. + +## FAQ + +### How do I write conditionals? + +Soong deliberately does not support conditionals in Android.bp files. +Instead, complexity in build rules that would require conditionals are handled +in Go, where high level language features can be used and implicit dependencies +introduced by conditionals can be tracked. Most conditionals are converted +to a map property, where one of the values in the map will be selected and +appended to the top level properties. + +For example, to support architecture specific files: +``` +cc_library { + ... + srcs: ["generic.cpp"], + arch: { + arm: { + srcs: ["arm.cpp"], + }, + x86: { + srcs: ["x86.cpp"], + }, + }, +} +``` + +## Contact + +Email android-building@googlegroups.com (external) for any questions, or see +[go/soong](http://go/soong) (internal). diff --git a/cc/makevars.go b/cc/makevars.go index a4fe0770..0e75329e 100644 --- a/cc/makevars.go +++ b/cc/makevars.go @@ -42,6 +42,14 @@ func makeVarsProvider(ctx android.MakeVarsContext) { ctx.Strict("GLOBAL_CLANG_CPPFLAGS_NO_OVERRIDE", "") ctx.Strict("NDK_PREBUILT_SHARED_LIBRARIES", strings.Join(ndkPrebuiltSharedLibs, " ")) + includeFlags, err := ctx.Eval("${commonGlobalIncludes}") + if err != nil { + panic(err) + } + includes, systemIncludes := splitSystemIncludes(ctx, includeFlags) + ctx.StrictRaw("SRC_HEADERS", strings.Join(includes, " ")) + ctx.StrictRaw("SRC_SYSTEM_HEADERS", strings.Join(systemIncludes, " ")) + hostTargets := ctx.Config().Targets[android.Host] makeVarsToolchain(ctx, "", hostTargets[0]) if len(hostTargets) > 1 { @@ -115,7 +123,9 @@ func makeVarsToolchain(ctx android.MakeVarsContext, secondPrefix string, if err != nil { panic(err) } - ctx.StrictRaw(makePrefix+"C_INCLUDES", strings.Replace(includeFlags, "-isystem ", "", -1)) + includes, systemIncludes := splitSystemIncludes(ctx, includeFlags) + ctx.StrictRaw(makePrefix+"C_INCLUDES", strings.Join(includes, " ")) + ctx.StrictRaw(makePrefix+"C_SYSTEM_INCLUDES", strings.Join(systemIncludes, " ")) if target.Arch.ArchType == android.Arm { flags, err := toolchain.InstructionSetFlags("arm") @@ -195,3 +205,39 @@ func makeVarsToolchain(ctx android.MakeVarsContext, secondPrefix string, ctx.Strict(makePrefix+"SHLIB_SUFFIX", toolchain.ShlibSuffix()) ctx.Strict(makePrefix+"EXECUTABLE_SUFFIX", toolchain.ExecutableSuffix()) } + +func splitSystemIncludes(ctx android.MakeVarsContext, val string) (includes, systemIncludes []string) { + flags, err := ctx.Eval(val) + if err != nil { + panic(err) + } + + extract := func(flags string, dirs []string, prefix string) (string, []string, bool) { + if strings.HasPrefix(flags, prefix) { + flags = strings.TrimPrefix(flags, prefix) + flags = strings.TrimLeft(flags, " ") + s := strings.SplitN(flags, " ", 2) + dirs = append(dirs, s[0]) + if len(s) > 1 { + return strings.TrimLeft(s[1], " "), dirs, true + } + return "", dirs, true + } else { + return flags, dirs, false + } + } + + flags = strings.TrimLeft(flags, " ") + for flags != "" { + found := false + flags, includes, found = extract(flags, includes, "-I") + if !found { + flags, systemIncludes, found = extract(flags, systemIncludes, "-isystem ") + } + if !found { + panic(fmt.Errorf("Unexpected flag in %q", flags)) + } + } + + return includes, systemIncludes +} |