ATE Build System is a non-recursive set of makefile definitions and templates that can be used to simplify the definition of targets. It is based on Make and allows to build the following types of targets:
- Native binaries
- Shared libraries
- Static libraries
Its design was inspired by the AOSP build system, although it is much lighter and simple.
In addition to GNU make, you will need also Python 3.
sudo apt install make python3A top level makefile system should include the top.mk file inside this repository. Targets can be defined in build.mk files. There are a few macros that can be used when writing target scripts. In particular, the following user-defined functions are very commonly used in custom build files:
all-makefiles-under: Takes a single directory input and finds allbuild.mkfiles inside it. Paired with an include directory is used to include subdirectories to the build system.current-dir: Obtains the path of the current file. It needs to be called before including any other file, otherwise an erroneous result will be returned.
BUILD_SYSTEM_DIR := tools/build_system
include $(BUILD_SYSTEM_DIR)/top.mk
include $(call all-makefiles-under, .)In order to define targets local variables are used. To ensure that they are empty when defining a new target, we use the following include:
include $(CLEAR_VARS)This will clear all local variables. Then we can define our local variables for the current target. Once we are done, we need to include one of the following three types of targets:
include $(BUILD_BINARY)
include $(BUILD_SHARED_LIBRARY)
include $(BUILD_STATIC_LIBRARY)The following is an example of how to define a binary target and link it against a static library:
LOCAL_DIR := $(call current-dir)
include $(CLEAR_VARS)
LOCAL_NAME := test
LOCAL_CFLAGS := \
-Os \
-g3 \
-I$(LOCAL_DIR)/Inc \
-Wall \
-Werror
LOCAL_LDFLAGS := -lc
LOCAL_SRC := \
$(LOCAL_DIR)/Src/main.c
LOCAL_STATIC_LIBS := \
libtest_static
include $(BUILD_BINARY)By defining the LOCAL_STATIC_LIBS, all exported header paths are automatically included when building the binary. To define the static library we could use the following:
LOCAL_DIR := $(call current-dir)
include $(CLEAR_VARS)
LOCAL_NAME := test_static
LOCAL_CFLAGS := \
-Os \
-g3 \
-I$(LOCAL_DIR)/Inc \
-Wall \
-Werror
LOCAL_ARFLAGS := -rcs
LOCAL_SRC := \
$(LOCAL_DIR)/Src/testlib.c
LOCAL_EXPORTED_DIRS := \
$(LOCAL_DIR)/Inc
include $(BUILD_STATIC_LIB)LOCAL_EXPORTED_DIRS is used to define the exported headers for the library. These are the ones that will get included when building binaries that link against this library. More than one path can be specified. All exported directories are included in the targets that link against this library.
ATE Build System supports custom compiler profiles. These are complex predefined compiler configurations that can be applied for each target. Currently it supports:
arm_clang: Usesclangwith thearm-none-eabitriplet. In addition, it uses the sysroot from thearm-none-eabi-gcctoolchain, which is automatically detected from thearm-none-eabi-gccbinary present in your PATH environment variable. Links againstlibc_nanoandlibstdc++_nano. Uses the-nostdliblinker flag.
When you define binary or library target the following make autogenerated targets are created:
$(LOCAL_NAME): builds the target binary or library.clean_$(LOCAL_NAME): cleans the target binary or library, leaving other targets untouched.run_$(LOCAL_NAME): runs the target binary. As you may expect, this is only available for binaries.
A compilation database is automatically generated. If you don't want to symlink the compilation database to the root of the top level makefile, then define the following variable after including the top.mk file:
include buildsystem/top.mk
SYMLINK_COMP_DB :=You can also specify another path for the symbolic link:
include buildsystem/top.mk
SYMLINK_COMP_DB := my_root_dirThe output tree has the following layout:
build/
├── compile_commands.json
├── intermediates
│ ├── target_name
│ │ └── target_dir
│ │ └── src
│ │ ├── main.d
│ │ ├── main.db
│ │ └── main.o
├── lib
│ ├── exports
│ │ ├── target_name
│ │ │ └── target_dir
│ │ │ └── exported
│ │ │ ├── header.d
│ │ │ └── header.h
│ ├── shared_lib_target_name.so
│ └── static_lib_target_name.a
└── targets
├── binary_target_name
└── binary_target_name.map
.dbfiles identify partial compiler database entries. They are built into a singlecompile_commands.jsonfile in the build directory..dfiles represent dependencies for specific files. Header files are not explicitly handled as dependencies. Instead, when the compiler compiles a translation unit into an object file it generates each.dfiles with the dependencies of the translation unit (all included header files).- Exported header files are copied into the
build/lib/exports/target_namedirectory, as they are needed when distributing a shared or static library, so they should be in the output tree. - All build outputs for each target are isolated in their own directory, ensuring that there are no name collisions, as target names need to be unique.
It is possible to specify a different name for the output build directory. This can be done by setting the BUILD_DIR variable to a suitable relative or absolute path. This can be done either in the top level makefile before including the build system top.mk file or by dynamically setting it when invoking make.
BUILD_DIR := my_ouput_dir
include buildsystem/top.mk$ make BUILD_DIR=my_output_dirWhen debugging and verifying that your build rules work as expected it is particularly useful to print all command invocations. This can be done by turning on verbose output dynamically by invoking main like:
make SILENT=Overriding the SILENT variable makes the build system display all commands with verbose output.