Skip to content

Latest commit

 

History

History
179 lines (134 loc) · 6.71 KB

README.md

File metadata and controls

179 lines (134 loc) · 6.71 KB

ATE Build System

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.

Dependencies

In addition to GNU make, you will need also Python 3.

sudo apt install make python3

Using the build system

A 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 all build.mk files 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.

Top-level makefile example

BUILD_SYSTEM_DIR := tools/build_system
include $(BUILD_SYSTEM_DIR)/top.mk

include $(call all-makefiles-under, .)

Defining targets

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.

Compiler profiles

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: Uses clang with the arm-none-eabi triplet. In addition, it uses the sysroot from the arm-none-eabi-gcc toolchain, which is automatically detected from the arm-none-eabi-gcc binary present in your PATH environment variable. Links against libc_nano and libstdc++_nano. Uses the -nostdlib linker flag.

Autogenerated targets

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.

Compilation database

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_dir

Build directory tree

The 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
  • .db files identify partial compiler database entries. They are built into a single compile_commands.json file in the build directory.
  • .d files 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 .d files with the dependencies of the translation unit (all included header files).
  • Exported header files are copied into the build/lib/exports/target_name directory, 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.

Overriding the output directory

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.

Static build directory

BUILD_DIR := my_ouput_dir
include buildsystem/top.mk

Dynamic build directory

$ make BUILD_DIR=my_output_dir

Generate verbose output

When 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.