GN in ChromeOS
New packages should use GN as their build system.
See the official step-by-step introduction for the GN basics. This article discusses ChromeOS specific stuff.
How to build your package with GN
Example: arc/adbd/BUILD.gn
- Put
BUILD.gnin your package directory, which is determined byPLATFORM_SUBDIRin your ebuild. Existence ofBUILD.gnindicates to the platform2 build system that GN should be used to build this package. - Have a target named
"all"in theBUILD.gn. It's the root target built by the platform2 build system. Typically it's agrouptarget depends on all the targets to be built. common-mk/contains common templates or common settings, which your build files can utilize.pkg_config.gnidefines thepkg_configrule to generate configs for package dependencies.BUILDCONFIG.gndefines the default configs for each target type (e.g. executable). You can remove default configs in individual target withconfigs -=if needed. (example)
How to write ebuilds
Example: arc-adbd-9999.ebuild
Note we should add .gn in CROS_WORKON_SUBTREE so that the platform2 build
system can access the file.
Packages outside platform2
For packages outside platform2, use CROS_WORKON_DESTDIR to copy the
package under <workspace>/platform2/ while building it.
(example)
How to install files
Installing Targets defined in BUILD.gn
A file built by a GN target, either by executable, shared_library or
static_library, can be installed by specifying install_path.
A target that install the output must be a dependency of group("all").
Variable
install_path- An install destination path.
Installing executable targets
-
install_pathmust end inbinorsbin. -
When you specify the
install_pathsimply asbin, the binary will be installed into/usr/bin.executable("executable_target") { sources = [ "source.cc" ] install_path = "bin" }is equivalent to
dobin ${OUT}/executable_target -
If you want to change the destination, you can specify the absolute path.
executable("executable_target") { sources = [ "source.cc" ] install_path = "/sbin" }is equivalent to
into / dosbin ${OUT}/executable_target
Installing Shared Library Targets
Installing shared library requires specifying install_path in the
shared_library target.
-
The
install_pathmust end inlib. -
When you specify the
install_pathsimply aslib, the correct ABI-specific libdir (e.g./usr/libor/usr/lib64) will be used.shared_library("libtarget") { sources = [ "source.cc" ] install_path = "lib" }is equivalent to
dolib.so ${OUT}/lib/libtarget -
If you want to change the destination, you can specify the absolute path.
shared_library("libtarget") { sources = [ "source.cc" ] install_path = "/usr/local/lib" }is equivalent to
into /usr/local dolib.so ${OUT}/lib/libtarget
Installing Static Library Targets
Installing static libraries requires specifying install_path in the
static_library target.
-
The
install_pathmust end inlib. -
When you specify the
install_pathsimply aslib, it installs into/usr/lib.static_library("libtarget") { sources = [ "source.cc" ] install_path = "lib" }is equivalent to
dolib.a ${OUT}/libtarget -
If you want to change the destination, you can specify the absolute path.
static_library("libtarget") { sources = [ "source.cc" ] install_path = "/usr/local/lib" }is equivalent to
into /usr/local dolib.a ${OUT}/libtarget
Installing files not defined in BUILD.gn
You can install files that are not generated by GN and ninja by using
install_config target.
Variables
sources(required)- A list of files to be installed.
install_path(optional)- An install destination path or an alias that maps to a
corresponding destination path.
- default:
/ dbus_system_d-/etc/dbus-1/system.ddbus_system_services-/usr/share/dbus-1/system-servicesminijail_conf-/usr/share/minijailseccomp_policy-/usr/share/policytmpfilesd-/usr/lib/tmpfiles.dtmpfiled_ondemand-/usr/lib/tmpfiles.d/on-demandupstart-/etc/init
- default:
- An install destination path or an alias that maps to a
corresponding destination path.
recursive(optional)- A boolean, indicating whether to install files recursively.
- default:
false
options(optional)- A string of options for installing files.
- default:
"-m0644"
outputs(optional)- A list of new file names, if sources should be renamed too.
- When not specified, original names are used.
symlinks(optional)- A list of symbolic links to be created.
- When install_path is specified, links are created in
${install_path}/${symlink}
Usage
-
To install files, add
install_configinto dependency tree ofgroup("all").install_config("install_init") { sources = [ "init/initialize.conf" ] install_path = "upstart" }is equivalent to
insinto /etc/init doins init/initialize.conf -
To install files recursively, set
recursivetotrue.install_config("install_rec") { sources = [ "source_directory" ] install_path = "/usr/local" recursive = true }is equivalent to
insinto /usr/local doins -r source_directory -
When you want to change owner or permission, specify
options.install_config("install_exe") { sources = [ "source" ] install_path = "/usr/local" options = "-m0755" }is equivalent to
insinto /usr/local insopts -m0755 doins source -
When you want to install multiple files, specify sources all together.
install_config("install_init") { sources = [ "init/initialize1.conf", "init/initialize2.conf", ] install_path = "upstart" }is equivalent to
insinto /etc/init doins init/initialize.conf -
When you want to use
newinscommand, specify new file name asoutputs.install_config("install_policy") { sources = [ "policy/configuration.policy" ] outputs = [ "newfilename.policy" ] install_path = "seccomp_policy" }is equivalent to
insinto /usr/share/policy newins policy/configuration.policy newfilename.policy -
outputsare also used for installing multiple files.install_config("install_multiple_new") { sources = [ "old.policy", "another_old.policy", ] outputs = [ "new1.policy", "new2.policy", ] install_path = "seccomp_policy" }is equivalent to
insinto /usr/share/policy newins old.policy new1.policy newins another_old.policy new2.policy -
symlinksparameter is similar tooutputs, but it creates symbolic link bydosym.install_config("install_sym") { sources = [ "source" ] symlinks = [ "symlink" ] }is equivalent to
dosym source symlink -
When
install_pathis specified, it is added to the head ofsymlinks.install_config("install_sym") { sources = [ "source" ] symlinks = [ "symlink" ] install_path = "/path/to/install" }is equivalent to
dosym source /path/to/install/symlink
How to check USE flags in GN
In GN files, USE flags can be referred as use.foo.
(example)
Only allowed USE flags can be used. If you need to use new USE flags, update:
_IUSEconstant inplatform2/common-mk/platform2.py(example)IUSEvariable in your ebuild file (example)
You can confirm that the USE flag is available for your package by running
equery-{board} uses {package-name}
How to write unit tests
use.test flag is set to true on unit testing. Enclose test only targets with
if (use.test) {} to reduce compile time on production.
The test targets are typically executables which depend on //common-mk:test to
use gtest and gmock.
How to run unit tests doesn't change: In chroot, run
cros_workon --board=$BOARD start $package_name if you haven't. Then run
FEATURES=test emerge-$BOARD $package_name
Prepend VERBOSE=1 to see GN and ninja commands (plus other logs).
Declaring tests in BUILD.gn
-
A unit test executable can be run in the test phase by specifying
run_test = truein the executable target.executable("test_target") { sources = [ "source.cc" ] run_test = true }is equivalent to
platform_test "run" "${OUT}/test_target" -
When you want to specify config, you can use
test_configvariable.executable("test_target") { sources = [ "source.cc" ] run_test = true test_config = { run_as_root = true gtest_filter = ".RunAsRoot*-" } }is equivalent to
platform_test "run" "${OUT}/test_target" "1" "*.RunAsRoot*-"
FAQ
How to create standalone static library?
Static libraries are compiled with thin archive enabled by default i.e. not standalone.
Remove use_thin_archive from configs and add nouse_thin_archive to generate a standalone static library (example).
TODO(crbug.com/991440): consider making standalone library the default and replace static_library with source_set whenever possible.