aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md156
-rw-r--r--cc/makevars.go48
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
+}