Getting started with platform2

What is platform2?

platform2 is an effort to make the build of platform packages faster and simpler; it uses GN and ninja to build everything.

The common build system includes:

  • protobuf and dbus adaptors generation
  • incremental builds
  • pkg-config support
  • dependencies extraction (dependencies are extracted from your GN files and be used to generate pkg-config files)

The platform2 philosophy

Given a package ${package_name}:

  1. The code should live in src/platform2/${package_name}.
  2. The code should be built from a single GN file src/platform2/${package_name}/BUILD.gn.
  3. Each package should have their own ebuild. The logic to build platform2 packages is contained in platform.eclass.

How to write an ebuild for a platform2 package

Packages in platform2 should have very lean ebuilds. Most of the build configuration should happen behind the scene (platform.eclass) or in the common GN logic. In most cases, your ebuild will only contain dependencies, an install section, and a list of tests to run.

Note: as for all cros_workon packages, you only need to create the -9999 version of the ebuild (${package_name}-9999.ebuild). The CQ will automatically create the stable version of the ebuild (${package_name}-x.y.z-r${revision_number}.ebuild).

Example ebuild:

# Copyright 2019 The Chromium OS Authors. All rights reserved.
# Distributed under the terms of the GNU General Public License v2

EAPI="6"

CROS_WORKON_INCREMENTAL_BUILD=1
CROS_WORKON_LOCALNAME="platform2"
CROS_WORKON_PROJECT="chromiumos/platform2"
CROS_WORKON_DESTDIR="${S}/platform2"

PLATFORM_SUBDIR="package" # name of the directory in src/platform2

inherit cros-workon platform

DESCRIPTION="description"
HOMEPAGE="http://www.chromium.org/"

LICENSE="BSD-Google"
SLOT=0
KEYWORDS="~*"

RDEPEND="
  chromeos-base/libbrillo
"

DEPEND="
  ${RDEPEND}
"

src_install() {
  # ${OUT} is the build output directory containing all your binaries.
  dobin "${OUT}/binary"
}

platform_pkg_test() {
  local tests=(
    package_test # name of tests defined in GN
  )

  local test_bin
  for test_bin in "${tests[@]}"; do
    # platform_test takes care of setting up your test environment.
    platform_test "run" "${OUT}/${test_bin}"
  done
}

Adding generators

platform2 already has pre-made generators for dbus-xml2cpp and protoc, but if you need to add a new generator, here's how.

  1. Create a new .gni file under src/platform2/common-mk/ named appropriately to describe your generator.
  2. Copy the contents of an existing one, such as dbus_glib.gni
  3. Modify the rule specified to call your tool with the arguments
  4. Update the inputs/outputs lists to reflect the files your tool will generate. (Ensure your tool is in virtual/target-sdk if necessary.)

You can now include this generator in a target for a project you're porting to platform2, by writing a target in your project that uses the template you just wrote.

Adding a new USE flag conditional

It is possible to have conditional GN rules that depend on the value of a USE flag at the time of build. This is useful, for example, if certain targets must only be built if a certain feature (controlled by a USE flag) is enabled.

  • Make sure the USE flag is listed in the ${package_name}-9999.ebuild in IUSE.
  • Add the USE flag to src/platform2/common-mk/use.gni.
  • USE_flagname may now be used in the package's GN file.

Rapid development

cros_workon_make will use the ebuild to build a package, but will build incrementally and skip as many steps as possible from the normal emerge process (not checking dependencies, not installing, etc.). However, please use this command with caution because it allows ebuilds to directly modify the source repository. For example, it may delete some files.

For extra speed, you can also use --noreconf to skip the configure stage (creating the ninja file from the GN files):

cros_workon_make --board=${BOARD} --noreconf shill

You can inspect the produced artifacts and test binaries in /build/${BOARD}/var/cache/portage/chromeos-base/shill.

Running the unittests in gdb

Once your unittests are built, you need to enter the sysroot (in /build/${BOARD}) with platform2_test.py. platform2_test.py will set up the environment so that the binaries can be executed correctly (entering the sysroot, using qemu, etc.).

Note: qemu doesn‘t support the ptrace syscall used by gdb, so even though the program will run under the debugger, breakpoints/traps/etc won’t work.

To run a shell within the sysroot:

common-mk/platform2_test.py --board=${BOARD} /bin/bash

From within the shell, you can run your binaries (including unit tests), and run them with gdb. Within the sysroot, the gdb accessible from $PATH is the correct target gdb. Since you have entered the sysroot, you will find the build artifacts under /var/cache/portage/chromeos-base/${package_name}.

Running unit tests

You have 2 options for running unit tests for a package residing in platform2:

# Use cros_workon_make to run unit tests.
cros_workon_make --board=${BOARD} ${PACKAGE_NAME} --test

# Alternatively, use your board-specific emerge - this might give
# additional useful output.
FEATURES=test emerge-${BOARD} ${PACKAGE_NAME}

You can select a subset of tests to run by setting P2_TEST_FILTER. cros_workon_make will run only the tests whose name match one of the regex specified in P2_TEST_FILTER. E.g.

# Run the string utilities unit tests for libchromeos.
P2_TEST_FILTER="StringUtils.*" cros_workon_make --test libchromeos

For more information, consult the upstream gtest documentation.

Further reading

  • GN on Google Git