Build system
Build directories
The build system is supposed to never touch the source tree. The procedure of building components and integrating them into system scenarios is performed within a distinct build directory. One build directory targets a specific kernel and hardware platform. Because the source tree is decoupled from the build directory, one source tree can have many different build directories associated, each targeted at a different platform.
The recommended way for creating a build directory is the use of the create_builddir tool located at <genode-dir>/tool/. The tool prints usage information along with a list of supported base platforms when started without arguments. For creating a new build directory, one of the listed target platforms must be specified. By default, the new build directory is created at <genode-dir>/build/<platform>/ where <platform> corresponds to the specified argument. Alternatively, the default location can be overridden via the optional BUILD_DIR= argument. For example:
cd <genode-dir> ./tool/create_builddir x86_64 BUILD_DIR=/tmp/build.x86_64
This command creates a new build directory for the 64-bit x86 platform at /tmp/build.x86_64/. For the basic operations available from within the build directory, please refer to Section Using the build system.
Configuration
Each build directory contains a Makefile, which is a symbolic link to tool/builddir/build.mk. The makefile is the front end of the build system and not supposed to be edited. Besides the makefile, there is an etc/ subdirectory that contains the build-directory configuration. For most platforms, there exists merely a single build.conf file, which defines the source-code repositories to be incorporated into the build process along with the parameters for the run tool explained in Section Run tool.
The selection of source-code repositories is defined by the REPOSITORIES declaration, which contains a list of directories. The etc/build.conf file as found in a freshly created build directory is preconfigured to select the source-code repositories base-<platform>, base, os, and demo. There are a number of commented-out lines that can be uncommented for enabling additional repositories.
Cleaning
To remove all but kernel-related generated files, use
make clean
To remove all generated files, use
make cleanall
Both clean and cleanall won't remove any files from the bin/ subdirectory. This makes the bin/ a safe place for files that are unrelated to the build process, yet are required for the integration stage, e.g., binary data.
Controlling the verbosity
To understand the inner workings of the build process in more detail, you can tell the build system to display each directory change by specifying
make VERBOSE_DIR=
If you are interested in the arguments that are passed to each invocation of make, you can make them visible via
make VERBOSE_MK=
Furthermore, you can observe each single shell-command invocation by specifying
make VERBOSE=
Of course, you can combine these verboseness toggles for maximizing the noise.
Target descriptions
Each build target is represented by a corresponding target.mk file within the src/ subdirectory of a source-code repository. This file declares the name of the target, the source codes to be incorporated into the target, and the libraries the target depends on. The build system evaluates target descriptions using make. Hence, the syntax corresponds to the syntax of makefiles and the principle functionality of make is available for target.mk files. For example, it is possible to define custom rules as done in Section Building tools to be executed on the host platform.
Target declarations
- TARGET
-
is the name of the binary to be created. This is the only mandatory variable to be defined in each target.mk file.
- LIBS
-
is the list of libraries that are used by the target.
- SRC_CC
-
contains the list of .cc source files. The default search location for source codes is the directory where the target.mk file resides.
- SRC_C
-
contains the list of .c source files.
- SRC_S
-
contains the list of assembly .s source files.
- SRC_BIN
-
contains binary data files to be linked to the target.
- INC_DIR
-
is the list of include search locations. Directories should always be appended by using +=.
- REQUIRES
-
expresses the requirements that must be satisfied in order to build the target. More details about the underlying mechanism is provided by Section Platform specifications.
- CC_OPT
-
contains additional compiler options to be used for .c as well as for .cc files.
- CC_CXX_OPT
-
contains additional compiler options to be used for the C++ compiler only.
- CC_C_OPT
-
contains additional compiler options to be used for the C compiler only.
- EXT_OBJECTS
-
is a list of external objects or libraries. This declaration is merely used for interfacing Genode with legacy software components.
Specifying search locations
When specifying search locations for header files via the INC_DIR variable or for source files via vpath, the use of relative pathnames is illegal. Instead, the following variables can be used to reference locations within the source-code repository where the target resides:
- REP_DIR
-
is the base directory of the target's source-code repository. Normally, specifying locations relative to the base of the repository is rarely used by target.mk files but needed by library descriptions.
- PRG_DIR
-
is the directory where the target.mk file resides. This variable is always to be used when specifying a relative path.
- $(call select_from_repositories,path/relative/to/repo)
-
This function returns the absolute path for the given repository-relative path by looking at all source-code repositories in their configured order. Hereby, it is possible to access files or directories that are outside the target's source-code repository.
- $(call select_from_ports,<port-name>)
-
This function returns the absolute path for the contrib directory of the specified <port-name>. The contrib directory is located at <genode-dir>/contrib/<port-name>-<fingerprint> whereby <fingerprint> uniquely identifies the version of the port as expected by the current state of the Genode source tree.
Library descriptions
In contrast to target descriptions that are scattered across the whole source tree, library descriptions are located at the central place lib/mk. Each library corresponds to a <libname>.mk file. The base of the description file is the name of the library. Therefore, no TARGET variable needs to be defined. The location of source-code files is usually defined relative to $(REP_DIR). Library-description files support the following additional declaration:
- SHARED_LIB = yes
-
declares that the library should be built as a shared object rather than a static library. The resulting object will be called <libname>.lib.so.
Platform specifications
Building components for different platforms likely implicates that portions of code are tied to certain aspects of the target platform. For example, target platforms may differ in the following respects:
-
The API of the used kernel,
-
The hardware architecture such as x86, ARMv7,
-
Certain hardware facilities such as a custom device, or
-
Other considerations such as software license requirements.
Each of those aspects may influence the build process in different ways. The build system provides a generic mechanism to steer the build process according to such aspects. Each aspect is represented by a tag called spec value. Any platform targeted by Genode can be characterized by a set of such spec values.
The developer of a software component knows the constraints of his software and thus specifies these requirements in the build-description file of the component. The system integrator defines the platform the software will be built for by specifying the targeted platform in the SPECS declaration in the build directory's etc/specs.conf file. In addition to the (optional) etc/specs.conf file within the build directory, the build system incorporates all etc/specs.conf files found in the enabled repositories. For example, when using the Linux kernel as a platform, the base-linux/etc/specs.conf file is picked up automatically. The build directory's specs.conf file can still be used to extend the SPECS declarations, for example to enable special features.
Each <spec> in the SPECS variable instructs the build system to
-
Include the make-rules of a corresponding base/mk/spec/<specname>.mk file. This enables the customization of the build process for each platform.
-
Search for <libname>.mk files in the lib/mk/spec/<specname>/ subdirectory. This way, alternative implementations of one and the same library interface can be selected depending on the platform specification.
Before a target or library gets built, the build system checks if the REQUIRES entries of the build description file are satisfied by entries of the SPECS variable. The compilation is executed only if each entry in the REQUIRES variable is present in the SPECS variable as supplied by the build directory configuration.
Building tools to be executed on the host platform
Sometimes, software requires custom tools that are used to generate source code or other ingredients for the build process, for example IDL compilers. Such tools won't be executed on top of Genode but on the host platform during the build process. Hence, they must be compiled with the tool chain installed on the host, not the Genode tool chain.
The build system accommodates the building of such host tools as a side effect of building a library or a target. Even though it is possible to add the tool-compilation step to a regular build description file, it is recommended to introduce a dedicated pseudo library for building such tools. This way, the rules for building host tools are kept separate from rules that refer to regular targets. By convention, the pseudo library should be named <package>_host_tools and the host tools should be built at <build-dir>/tool/<package>/ where <package> refers to the name of the software package the tool belongs to, e.g., qt5 or mupdf. To build a tool named <tool>, the pseudo library contains a custom make rule like the following:
$(BUILD_BASE_DIR)/tool/<package>/<tool>: $(MSG_BUILD)$(notdir $@) $(VERBOSE)mkdir -p $(dir $@) $(VERBOSE)...build commands...
To let the build system trigger the rule, add the custom target to the HOST_TOOLS variable:
HOST_TOOLS += $(BUILD_BASE_DIR)/tool/<package>/<tool>
Once the pseudo library for building the host tools is in place, it can be referenced by each target or library that relies on the respective tools via the LIBS declaration. The tool can be invoked by referring to $(BUILD_BASE_DIR)/tool/<package>/tool.
For an example of using custom host tools, please refer to the mupdf package found within the libports repository. During the build of the mupdf library, two custom tools fontdump and cmapdump are invoked. The tools are built via the lib/mk/mupdf_host_tools.mk library description file. The actual mupdf library (lib/mk/mupdf.mk) has the pseudo library mupdf_host_tools listed in its LIBS declaration and refers to the tools relative to $(BUILD_BASE_DIR).
Building 3rd-party software
The source code of 3rd-party software is managed by the mechanism presented in Section Integration of 3rd-party software. Once prepared, such source codes resides in a subdirectory of <genode-dir>/contrib/.
If the build system encounters a target that incorporates ported source code (that is, a build-description file that calls the select_from_ports function), it looks up the respective <port-name>.hash file in the repositories as specified in the build configuration. The fingerprint found in the hash file is used to construct the path to the port directory under contrib/. If that lookup fails, a meaningful error is printed. Any number of versions of the same port can be installed at the same time. I.e., when switching Git branches that use different versions of the same port, the build system automatically finds the right port version as expected by the currently active branch.