1# Build System Best Practices 2 3## Read only source tree 4 5Never write to the source directory during the build, always write to 6`$OUT_DIR`. We expect to enforce this in the future. 7 8If you want to verify / provide an update to a checked in generated source 9file, generate that file into `$OUT_DIR` during the build, fail the build 10asking the user to run a command (either a straight command, checked in script, 11generated script, etc) to explicitly copy that file from the output into the 12source tree. 13 14## Network access 15 16Never access the network during the build. We expect to enforce this in the 17future, though there will be some level of exceptions for tools like `distcc` 18and `goma`. 19 20## Paths 21 22Don't use absolute paths in Ninja files (with make's `$(abspath)` or similar), 23as that could trigger extra rebuilds when a source directory is moved. 24 25Assume that the source directory is `$PWD`. If a script is going to change 26directories and needs to convert an input from a relative to absolute path, 27prefer to do that in the script. 28 29Don't encode absolute paths in build intermediates or outputs. This would make 30it difficult to reproduce builds on other machines. 31 32Don't assume that `$OUT_DIR` is `out`. The source and output trees are very 33large these days, so some people put these on different disks. There are many 34other uses as well. 35 36Don't assume that `$OUT_DIR` is under `$PWD`, users can set it to a relative path 37or an absolute path. 38 39## $(shell) use in Android.mk files 40 41Don't use `$(shell)` to write files, create symlinks, etc. We expect to 42enforce this in the future. Encode these as build rules in the build graph 43instead. This can be problematic in a number of ways: 44 45* `$(shell)` calls run at the beginning of every build, at minimum this slows 46 down build startup, but it can also trigger more build steps to run than are 47 necessary, since these files will change more often than necessary. 48* It's no longer possible for a stripped-down product configuration to opt-out 49 of these created files. It's better to have actual rules and dependencies set 50 up so that space isn't wasted, but the files are there when necessary. 51 52## Headers 53 54`LOCAL_COPY_HEADERS` is deprecated. Soong modules cannot use these headers, and 55when the VNDK is enabled, System modules in Make cannot declare or use them 56either. 57 58The set of global include paths provided by the build system is also being 59removed. They've been switched from using `-isystem` to `-I` already, and are 60removed entirely in some environments (vendor code when the VNDK is enabled). 61 62Instead, use `LOCAL_EXPORT_C_INCLUDE_DIRS`/`export_include_dirs`. These allow 63access to the headers automatically if you link to the associated code. 64 65If your library uses `LOCAL_EXPORT_C_INCLUDE_DIRS`/`export_include_dirs`, and 66the exported headers reference a library that you link to, use 67`LOCAL_EXPORT_SHARED_LIBRARY_HEADERS`/`LOCAL_EXPORT_STATIC_LIBRARY_HEADERS`/`LOCAL_EXPORT_HEADER_LIBRARY_HEADERS` 68(`export_shared_lib_headers`/`export_static_lib_headers`/`export_header_lib_headers`) 69to re-export the necessary headers to your users. 70 71Don't use non-local paths in your `LOCAL_EXPORT_C_INCLUDE_DIRS`, use one of the 72`LOCAL_EXPORT_*_HEADERS` instead. Non-local exported include dirs are not 73supported in Soong. You may need to either move your module definition up a 74directory (for example, if you have ./src/ and ./include/, you probably want to 75define the module in ./Android.bp, not ./src/Android.bp), define a header 76library and re-export it, or move the headers into a more appropriate location. 77 78Prefer to use header libraries (`BUILD_HEADER_LIBRARY`/ `cc_library_headers`) 79only if the headers are actually standalone, and do not have associated code. 80Sometimes there are headers that have header-only sections, but also define 81interfaces to a library. Prefer to split those header-only sections out to a 82separate header-only library containing only the header-only sections, and 83re-export that header library from the existing library. This will prevent 84accidentally linking more code than you need (slower at build and/or runtime), 85or accidentally not linking to a library that's actually necessary. 86 87Prefer `LOCAL_EXPORT_C_INCLUDE_DIRS` over `LOCAL_C_INCLUDES` as well. 88Eventually we'd like to remove `LOCAL_C_INCLUDES`, though significant cleanup 89will be required first. This will be necessary to detect cases where modules 90are using headers that shouldn't be available to them -- usually due to the 91lack of ABI/API guarantees, but for various other reasons as well: layering 92violations, planned deprecations, potential optimizations like C++ modules, 93etc. 94 95## Use defaults over variables 96 97Soong supports variable definitions in Android.bp files, but in many cases, 98it's better to use defaults modules like `cc_defaults`, `java_defaults`, etc. 99 100* It moves more information next to the values -- that the array of strings 101 will be used as a list of sources is useful, both for humans and automated 102 tools. This is even more useful if it's used inside an architecture or 103 target specific property. 104* It can collect multiple pieces of information together into logical 105 inheritable groups that can be selected with a single property. 106 107## Custom build tools 108 109If writing multiple files from a tool, declare them all in the build graph. 110* Make: Use `.KATI_IMPLICIT_OUTPUTS` 111* Android.bp: Just add them to the `out` list in genrule 112* Custom Soong Plugin: Add to `Outputs` or `ImplicitOutputs` 113 114Declare all files read by the tool, either with a dependency if you can, or by 115writing a dependency file. Ninja supports a fairly limited set of dependency 116file formats. You can verify that the dependencies are read correctly with: 117 118``` 119NINJA_ARGS="-t deps <output_file>" m 120``` 121 122Prefer to list input files on the command line, otherwise we may not know to 123re-run your command when a new input file is added. Ninja does not treat a 124change in dependencies as something that would invalidate an action -- the 125command line would need to change, or one of the inputs would need to be newer 126than the output file. If you don't include the inputs in your command line, you 127may need to add the the directories to your dependency list or dependency file, 128so that any additions or removals from those directories would trigger your 129tool to be re-run. That can be more expensive than necessary though, since many 130editors will write temporary files into the same directory, so changing a 131README could trigger the directory's timestamp to be updated. 132 133Only control output files based on the command line, not by an input file. We 134need to know which files will be created before any inputs are read, since we 135generate the entire build graph before reading source files, or running your 136tool. This comes up with Java based tools fairly often -- they'll generate 137different output files based on the classes declared in their input files. 138We've worked around these tools with the "srcjar" concept, which is just a jar 139file containing the generated sources. Our Java compilation tasks understand 140*.srcjar files, and will extract them before passing them on to the compiler. 141 142## Libraries in PRODUCT_PACKAGES 143 144Most libraries aren't necessary to include in `PRODUCT_PACKAGES`, unless 145they're used dynamically via `dlopen`. If they're only used via 146`LOCAL_SHARED_LIBRARIES` / `shared_libs`, then those dependencies will trigger 147them to be installed when necessary. Adding unnecessary libraries into 148`PRODUCT_PACKAGES` will force them to always be installed, wasting space. 149