| Dan Willemsen | 7733862 | 2017-11-08 16:39:18 -0800 | [diff] [blame] | 1 | # Build System Changes for Android.mk Writers |
| 2 | |
| Dan Willemsen | 6dbb33d | 2018-10-21 19:41:49 -0700 | [diff] [blame^] | 3 | ## `BUILD_NUMBER` removal from Android.mk {#BUILD_NUMBER} |
| 4 | |
| 5 | `BUILD_NUMBER` should not be used directly in Android.mk files, as it would |
| 6 | trigger them to be re-read every time the `BUILD_NUMBER` changes (which it does |
| 7 | on every build server build). If possible, just remove the use so that your |
| 8 | builds are more reproducible. If you do need it, use `BUILD_NUMBER_FROM_FILE`: |
| 9 | |
| 10 | ``` make |
| 11 | $(LOCAL_BUILT_MODULE): |
| 12 | mytool --build_number $(BUILD_NUMBER_FROM_FILE) -o $@ |
| 13 | ``` |
| 14 | |
| 15 | That will expand out to a subshell that will read the current `BUILD_NUMBER` |
| 16 | whenever it's run. It will not re-run your command if the build number has |
| 17 | changed, so incremental builds will have the build number from the last time |
| 18 | the particular output was rebuilt. |
| 19 | |
| Dan Willemsen | 78c40be | 2018-10-17 16:50:49 -0700 | [diff] [blame] | 20 | ## `DIST_DIR`, `dist_goal`, and `dist-for-goals` {#dist} |
| 21 | |
| 22 | `DIST_DIR` and `dist_goal` are no longer available when reading Android.mk |
| 23 | files (or other build tasks). Always use `dist-for-goals` instead, which takes |
| 24 | a PHONY goal, and a list of files to copy to `$DIST_DIR`. Whenever `dist` is |
| 25 | specified, and the goal would be built (either explicitly on the command line, |
| 26 | or as a dependency of something on the command line), that file will be copied |
| 27 | into `$DIST_DIR`. For example, |
| 28 | |
| 29 | ``` make |
| 30 | $(call dist-for-goals,foo,bar/baz) |
| 31 | ``` |
| 32 | |
| 33 | will copy `bar/baz` into `$DIST_DIR/baz` when `m foo dist` is run. |
| 34 | |
| 35 | #### Renames during copy |
| 36 | |
| 37 | Instead of specifying just a file, a destination name can be specified, |
| 38 | including subdirectories: |
| 39 | |
| 40 | ``` make |
| 41 | $(call dist-for-goals,foo,bar/baz:logs/foo.log) |
| 42 | ``` |
| 43 | |
| 44 | will copy `bar/baz` into `$DIST_DIR/logs/foo.log` when `m foo dist` is run. |
| 45 | |
| Dan Willemsen | 5fb16a6 | 2018-09-04 16:23:14 -0700 | [diff] [blame] | 46 | ## `.PHONY` rule enforcement {#phony_targets} |
| 47 | |
| 48 | There are several new warnings/errors meant to ensure the proper use of |
| 49 | `.PHONY` targets in order to improve the speed and reliability of incremental |
| 50 | builds. |
| 51 | |
| 52 | `.PHONY`-marked targets are often used as shortcuts to provide "friendly" names |
| 53 | for real files to be built, but any target marked with `.PHONY` is also always |
| 54 | considered dirty, needing to be rebuilt every build. This isn't a problem for |
| 55 | aliases or one-off user-requested operations, but if real builds steps depend |
| 56 | on a `.PHONY` target, it can get quite expensive for what should be a tiny |
| 57 | build. |
| 58 | |
| 59 | ``` make |
| 60 | ...mk:42: warning: PHONY target "out/.../foo" looks like a real file (contains a "/") |
| 61 | ``` |
| 62 | |
| 63 | Between this warning and the next, we're requiring that `.PHONY` targets do not |
| 64 | have "/" in them, and real file targets do have a "/". This makes it more |
| 65 | obvious when reading makefiles what is happening, and will help the build |
| 66 | system differentiate these in the future too. |
| 67 | |
| 68 | ``` make |
| 69 | ...mk:42: warning: writing to readonly directory: "kernel-modules" |
| 70 | ``` |
| 71 | |
| 72 | This warning will show up for one of two reasons: |
| 73 | |
| 74 | 1. The target isn't intended to be a real file, and should be marked with |
| 75 | `.PHONY`. This would be the case for this example. |
| 76 | 2. The target is a real file, but it's outside the output directories. All |
| 77 | outputs from the build system should be within the output directory, |
| 78 | otherwise `m clean` is unable to clean the build, and future builds may not |
| 79 | work properly. |
| 80 | |
| 81 | ``` make |
| 82 | ...mk:42: warning: real file "out/.../foo" depends on PHONY target "buildbins" |
| 83 | ``` |
| 84 | |
| 85 | If the first target isn't intended to be a real file, then it should be marked |
| 86 | with `.PHONY`, which will satisfy this warning. This isn't the case for this |
| 87 | example, as we require `.PHONY` targets not to have '/' in them. |
| 88 | |
| 89 | If the second (PHONY) target is a real file, it may unnecessarily be marked |
| 90 | with `.PHONY`. |
| 91 | |
| 92 | ### `.PHONY` and calling other build systems |
| 93 | |
| 94 | One common pattern (mostly outside AOSP) that we've seen hit these warning is |
| 95 | when building with external build systems (firmware, bootloader, kernel, etc). |
| 96 | Those are often marked as `.PHONY` because the Android build system doesn't |
| 97 | have enough dependencies to know when to run the other build system again |
| 98 | during an incremental build. |
| 99 | |
| 100 | We recommend to build these outside of Android, and deliver prebuilts into the |
| 101 | Android tree instead of decreasing the speed and reliability of the incremental |
| 102 | Android build. |
| 103 | |
| 104 | In cases where that's not desired, to preserve the speed of Android |
| 105 | incrementals, over-specifying dependencies is likely a better option than |
| 106 | marking it with `.PHONY`: |
| 107 | |
| 108 | ``` make |
| 109 | out/target/.../zImage: $(sort $(shell find -L $(KERNEL_SRCDIR))) |
| 110 | ... |
| 111 | ``` |
| 112 | |
| 113 | For reliability, many of these other build systems do not guarantee the same |
| 114 | level of incremental build assurances as the Android Build is attempting to do |
| 115 | -- without custom checks, Make doesn't rebuild objects when CFLAGS change, etc. |
| 116 | In order to fix this, our recommendation is to do clean builds for each of |
| 117 | these external build systems every time anything they rely on changes. For |
| 118 | relatively smaller builds (like the kernel), this may be reasonable as long as |
| 119 | you're not trying to actively debug the kernel. |
| 120 | |
| 121 | ## `export` and `unexport` deprecation {#export_keyword} |
| Dan Willemsen | 8b9c3cc | 2018-02-27 02:15:32 -0800 | [diff] [blame] | 122 | |
| 123 | The `export` and `unexport` keywords have been deprecated, and will throw |
| 124 | warnings or errors depending on where they are used. |
| 125 | |
| 126 | Early in the make system, during product configuration and BoardConfig.mk |
| 127 | reading: these will throw a warnings, and will be an error in the future. |
| 128 | Device specific configuration should not be able to affect common core build |
| 129 | steps -- we're looking at triggering build steps to be invalidated if the set |
| 130 | of environment variables they can access changes. If device specific |
| 131 | configuration is allowed to change those, switching devices with the same |
| 132 | output directory could become significantly more expensive than it already can |
| 133 | be. |
| 134 | |
| 135 | Later, during Android.mk files, and later tasks: these will throw errors, since |
| 136 | it is increasingly likely that they are being used incorrectly, attempting to |
| 137 | change the environment for a single build step, and instead setting it for |
| 138 | hundreds of thousands. |
| 139 | |
| 140 | It is not recommended to just move the environment variable setting outside of |
| 141 | the build (in vendorsetup.sh, or some other configuration script or wrapper). |
| 142 | We expect to limit the environment variables that the build respects in the |
| 143 | future, others will be cleared. (There will be methods to get custom variables |
| 144 | into the build, just not to every build step) |
| 145 | |
| 146 | Instead, write the export commands into the rule command lines themselves: |
| 147 | |
| 148 | ``` make |
| 149 | $(intermediates)/generated_output.img: |
| 150 | rm -rf $@ |
| 151 | export MY_ENV_A="$(MY_A)"; make ... |
| 152 | ``` |
| 153 | |
| 154 | If you want to set many environment variables, and/or use them many times, |
| 155 | write them out to a script and source the script: |
| 156 | |
| 157 | ``` make |
| 158 | envsh := $(intermediates)/env.sh |
| 159 | $(envsh): |
| 160 | rm -rf $@ |
| 161 | echo 'export MY_ENV_A="$(MY_A)"' >$@ |
| 162 | echo 'export MY_ENV_B="$(MY_B)"' >>$@ |
| 163 | |
| 164 | $(intermediates)/generated_output.img: PRIVATE_ENV := $(envsh) |
| 165 | $(intermediates)/generated_output.img: $(envsh) a/b/c/package.sh |
| 166 | rm -rf $@ |
| 167 | source $(PRIVATE_ENV); make ... |
| 168 | source $(PRIVATE_ENV); a/b/c/package.sh ... |
| 169 | ``` |
| 170 | |
| Dan Willemsen | 5f76fc0 | 2018-06-21 21:42:29 -0700 | [diff] [blame] | 171 | ## Implicit make rules are obsolete {#implicit_rules} |
| Dan Willemsen | 62db0f0 | 2018-06-16 09:37:13 -0700 | [diff] [blame] | 172 | |
| 173 | Implicit rules look something like the following: |
| 174 | |
| 175 | ``` make |
| 176 | $(TARGET_OUT_SHARED_LIBRARIES)/%_vendor.so: $(TARGET_OUT_SHARED_LIBRARIES)/%.so |
| 177 | ... |
| 178 | |
| 179 | %.o : %.foo |
| 180 | ... |
| 181 | ``` |
| 182 | |
| Dan Willemsen | 5f76fc0 | 2018-06-21 21:42:29 -0700 | [diff] [blame] | 183 | These can have wide ranging effects across unrelated modules, so they're now obsolete. Instead, use static pattern rules, which are similar, but explicitly match the specified outputs: |
| Dan Willemsen | 62db0f0 | 2018-06-16 09:37:13 -0700 | [diff] [blame] | 184 | |
| 185 | ``` make |
| 186 | libs := $(foreach lib,libfoo libbar,$(TARGET_OUT_SHARED_LIBRARIES)/$(lib)_vendor.so) |
| 187 | $(libs): %_vendor.so: %.so |
| 188 | ... |
| 189 | |
| 190 | files := $(wildcard $(LOCAL_PATH)/*.foo) |
| 191 | gen := $(patsubst $(LOCAL_PATH)/%.foo,$(intermediates)/%.o,$(files)) |
| 192 | $(gen): %.o : %.foo |
| 193 | ... |
| 194 | ``` |
| 195 | |
| Dan Willemsen | ac92659 | 2018-06-11 22:28:00 -0700 | [diff] [blame] | 196 | ## Removing '/' from Valid Module Names {#name_slash} |
| 197 | |
| 198 | The build system uses module names in path names in many places. Having an |
| 199 | extra '/' or '../' being inserted can cause problems -- and not just build |
| 200 | breaks, but stranger invalid behavior. |
| 201 | |
| 202 | In every case we've seen, the fix is relatively simple: move the directory into |
| 203 | `LOCAL_MODULE_RELATIVE_PATH` (or `LOCAL_MODULE_PATH` if you're still using it). |
| 204 | If this causes multiple modules to be named the same, use unique module names |
| 205 | and `LOCAL_MODULE_STEM` to change the installed file name: |
| 206 | |
| 207 | ``` make |
| 208 | include $(CLEAR_VARS) |
| 209 | LOCAL_MODULE := ver1/code.bin |
| 210 | LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/firmware |
| 211 | ... |
| 212 | include $(BUILD_PREBUILT) |
| 213 | |
| 214 | include $(CLEAR_VARS) |
| 215 | LOCAL_MODULE := ver2/code.bin |
| 216 | LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/firmware |
| 217 | ... |
| 218 | include $(BUILD_PREBUILT) |
| 219 | ``` |
| 220 | |
| 221 | Can be rewritten as: |
| 222 | |
| 223 | ``` |
| 224 | include $(CLEAR_VARS) |
| 225 | LOCAL_MODULE := ver1_code.bin |
| 226 | LOCAL_MODULE_STEM := code.bin |
| 227 | LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/firmware/ver1 |
| 228 | ... |
| 229 | include $(BUILD_PREBUILT) |
| 230 | |
| 231 | include $(CLEAR_VARS) |
| 232 | LOCAL_MODULE := ver2_code.bin |
| 233 | LOCAL_MODULE_STEM := code.bin |
| 234 | LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/firmware/ver2 |
| 235 | ... |
| 236 | include $(BUILD_PREBUILT) |
| 237 | ``` |
| 238 | |
| 239 | You just need to make sure that any other references (`PRODUCT_PACKAGES`, |
| 240 | `LOCAL_REQUIRED_MODULES`, etc) are converted to the new names. |
| 241 | |
| Dan Willemsen | bbe6a02 | 2018-06-10 14:49:01 -0700 | [diff] [blame] | 242 | ## Valid Module Names {#name} |
| 243 | |
| 244 | We've adopted lexical requirements very similar to [Bazel's |
| 245 | requirements](https://docs.bazel.build/versions/master/build-ref.html#name) for |
| 246 | target names. Valid characters are `a-z`, `A-Z`, `0-9`, and the special |
| Dan Willemsen | ac92659 | 2018-06-11 22:28:00 -0700 | [diff] [blame] | 247 | characters `_.+-=,@~`. This currently applies to `LOCAL_PACKAGE_NAME`, |
| Dan Willemsen | bbe6a02 | 2018-06-10 14:49:01 -0700 | [diff] [blame] | 248 | `LOCAL_MODULE`, and `LOCAL_MODULE_SUFFIX`, and `LOCAL_MODULE_STEM*`. |
| 249 | |
| 250 | Many other characters already caused problems if you used them, so we don't |
| 251 | expect this to have a large effect. |
| 252 | |
| Dan Willemsen | 5039ef4 | 2018-05-18 11:00:17 -0700 | [diff] [blame] | 253 | ## PATH Tools {#PATH_Tools} |
| 254 | |
| 255 | The build has started restricting the external host tools usable inside the |
| 256 | build. This will help ensure that build results are reproducible across |
| 257 | different machines, and catch mistakes before they become larger issues. |
| 258 | |
| 259 | To start with, this includes replacing the $PATH with our own directory of |
| 260 | tools, mirroring that of the host PATH. The only difference so far is the |
| 261 | removal of the host GCC tools. Anything that is not explicitly in the |
| 262 | configuration as allowed will continue functioning, but will generate a log |
| 263 | message. This is expected to become more restrictive over time. |
| 264 | |
| 265 | The configuration is located in build/soong/ui/build/paths/config.go, and |
| 266 | contains all the common tools in use in many builds. Anything not in that list |
| 267 | will currently print a warning in the `$OUT_DIR/soong.log` file, including the |
| 268 | command and arguments used, and the process tree in order to help locate the |
| 269 | usage. |
| 270 | |
| 271 | In order to fix any issues brought up by these checks, the best way to fix them |
| 272 | is to use tools checked into the tree -- either as prebuilts, or building them |
| 273 | as host tools during the build. |
| 274 | |
| 275 | As a temporary measure, you can set `TEMPORARY_DISABLE_PATH_RESTRICTIONS=true` |
| 276 | in your environment to temporarily turn off the error checks and allow any tool |
| 277 | to be used (with logging). Beware that GCC didn't work well with the interposer |
| 278 | used for logging, so this may not help in all cases. |
| 279 | |
| Dan Willemsen | 79fd696 | 2017-11-28 22:32:05 -0800 | [diff] [blame] | 280 | ## Deprecating / obsoleting envsetup.sh variables in Makefiles |
| Dan Willemsen | 7733862 | 2017-11-08 16:39:18 -0800 | [diff] [blame] | 281 | |
| 282 | It is not required to source envsetup.sh before running a build. Many scripts, |
| 283 | including a majority of our automated build systems, do not do so. Make will |
| 284 | transparently make every environment variable available as a make variable. |
| 285 | This means that relying on environment variables only set up in envsetup.sh will |
| 286 | produce different output for local users and scripted users. |
| 287 | |
| 288 | Many of these variables also include absolute path names, which we'd like to |
| 289 | keep out of the generated files, so that you don't need to do a full rebuild if |
| 290 | you move the source tree. |
| 291 | |
| 292 | To fix this, we're marking the variables that are set in envsetup.sh as |
| 293 | deprecated in the makefiles. This will trigger a warning every time one is read |
| Dan Willemsen | 79fd696 | 2017-11-28 22:32:05 -0800 | [diff] [blame] | 294 | (or written) inside Kati. Once all the warnings have been removed for a |
| 295 | particular variable, we'll switch it to obsolete, and any references will become |
| 296 | errors. |
| Dan Willemsen | 7733862 | 2017-11-08 16:39:18 -0800 | [diff] [blame] | 297 | |
| 298 | ### envsetup.sh variables with make equivalents |
| 299 | |
| 300 | | instead of | use | |
| 301 | |--------------------------------------------------------------|----------------------| |
| 302 | | OUT {#OUT} | OUT_DIR | |
| 303 | | ANDROID_HOST_OUT {#ANDROID_HOST_OUT} | HOST_OUT | |
| 304 | | ANDROID_PRODUCT_OUT {#ANDROID_PRODUCT_OUT} | PRODUCT_OUT | |
| 305 | | ANDROID_HOST_OUT_TESTCASES {#ANDROID_HOST_OUT_TESTCASES} | HOST_OUT_TESTCASES | |
| 306 | | ANDROID_TARGET_OUT_TESTCASES {#ANDROID_TARGET_OUT_TESTCASES} | TARGET_OUT_TESTCASES | |
| 307 | |
| 308 | All of the make variables may be relative paths from the current directory, or |
| 309 | absolute paths if the output directory was specified as an absolute path. If you |
| 310 | need an absolute variable, convert it to absolute during a rule, so that it's |
| 311 | not expanded into the generated ninja file: |
| 312 | |
| 313 | ``` make |
| 314 | $(PRODUCT_OUT)/gen.img: my/src/path/gen.sh |
| 315 | export PRODUCT_OUT=$$(cd $(PRODUCT_OUT); pwd); cd my/src/path; ./gen.sh -o $${PRODUCT_OUT}/gen.img |
| 316 | ``` |
| 317 | |
| 318 | ### ANDROID_BUILD_TOP {#ANDROID_BUILD_TOP} |
| 319 | |
| 320 | In Android.mk files, you can always assume that the current directory is the |
| 321 | root of the source tree, so this can just be replaced with '.' (which is what |
| 322 | $TOP is hardcoded to), or removed entirely. If you need an absolute path, see |
| 323 | the instructions above. |
| 324 | |
| 325 | ### Stop using PATH directly {#PATH} |
| 326 | |
| 327 | This isn't only set by envsetup.sh, but it is modified by it. Due to that it's |
| 328 | rather easy for this to change between different shells, and it's not ideal to |
| 329 | reread the makefiles every time this changes. |
| 330 | |
| 331 | In most cases, you shouldn't need to touch PATH at all. When you need to have a |
| 332 | rule reference a particular binary that's part of the source tree or outputs, |
| 333 | it's preferrable to just use the path to the file itself (since you should |
| 334 | already be adding that as a dependency). |
| 335 | |
| 336 | Depending on the rule, passing the file path itself may not be feasible due to |
| 337 | layers of unchangable scripts/binaries. In that case, be sure to add the |
| 338 | dependency, but modify the PATH within the rule itself: |
| 339 | |
| 340 | ``` make |
| 341 | $(TARGET): myscript my/path/binary |
| 342 | PATH=my/path:$$PATH myscript -o $@ |
| 343 | ``` |
| 344 | |
| 345 | ### Stop using PYTHONPATH directly {#PYTHONPATH} |
| 346 | |
| 347 | Like PATH, this isn't only set by envsetup.sh, but it is modified by it. Due to |
| 348 | that it's rather easy for this to change between different shells, and it's not |
| 349 | ideal to reread the makefiles every time. |
| 350 | |
| 351 | The best solution here is to start switching to Soong's python building support, |
| 352 | which packages the python interpreter, libraries, and script all into one file |
| 353 | that no longer needs PYTHONPATH. See fontchain_lint for examples of this: |
| 354 | |
| 355 | * [external/fonttools/Lib/fontTools/Android.bp] for python_library_host |
| 356 | * [frameworks/base/Android.bp] for python_binary_host |
| 357 | * [frameworks/base/data/fonts/Android.mk] to execute the python binary |
| 358 | |
| 359 | If you still need to use PYTHONPATH, do so within the rule itself, just like |
| 360 | path: |
| 361 | |
| 362 | ``` make |
| 363 | $(TARGET): myscript.py $(sort $(shell find my/python/lib -name '*.py')) |
| 364 | PYTHONPATH=my/python/lib:$$PYTHONPATH myscript.py -o $@ |
| 365 | ``` |
| Yifan Hong | 97de88c | 2017-12-12 18:01:09 -0800 | [diff] [blame] | 366 | ### Stop using PRODUCT_COMPATIBILITY_MATRIX_LEVEL_OVERRIDE directly {#PRODUCT_COMPATIBILITY_MATRIX_LEVEL_OVERRIDE} |
| 367 | |
| 368 | Specify Framework Compatibility Matrix Version in device manifest by adding a `target-level` |
| 369 | attribute to the root element `<manifest>`. If `PRODUCT_COMPATIBILITY_MATRIX_LEVEL_OVERRIDE` |
| 370 | is 26 or 27, you can add `"target-level"="1"` to your device manifest instead. |
| Dan Willemsen | 7733862 | 2017-11-08 16:39:18 -0800 | [diff] [blame] | 371 | |
| Stephen Hines | 178cf8e | 2018-01-11 11:54:48 -0800 | [diff] [blame] | 372 | ### Stop using USE_CLANG_PLATFORM_BUILD {#USE_CLANG_PLATFORM_BUILD} |
| 373 | |
| 374 | Clang is the default and only supported Android compiler, so there is no reason |
| 375 | for this option to exist. |
| 376 | |
| Dan Willemsen | 7733862 | 2017-11-08 16:39:18 -0800 | [diff] [blame] | 377 | ### Other envsetup.sh variables {#other_envsetup_variables} |
| 378 | |
| 379 | * ANDROID_TOOLCHAIN |
| 380 | * ANDROID_TOOLCHAIN_2ND_ARCH |
| 381 | * ANDROID_DEV_SCRIPTS |
| 382 | * ANDROID_EMULATOR_PREBUILTS |
| 383 | * ANDROID_PRE_BUILD_PATHS |
| 384 | |
| 385 | These are all exported from envsetup.sh, but don't have clear equivalents within |
| 386 | the makefile system. If you need one of them, you'll have to set up your own |
| 387 | version. |
| 388 | |
| 389 | |
| 390 | [build/soong/Changes.md]: https://android.googlesource.com/platform/build/soong/+/master/Changes.md |
| 391 | [external/fonttools/Lib/fontTools/Android.bp]: https://android.googlesource.com/platform/external/fonttools/+/master/Lib/fontTools/Android.bp |
| 392 | [frameworks/base/Android.bp]: https://android.googlesource.com/platform/frameworks/base/+/master/Android.bp |
| 393 | [frameworks/base/data/fonts/Android.mk]: https://android.googlesource.com/platform/frameworks/base/+/master/data/fonts/Android.mk |