[build][scripts] Integrate Zircon via new GN build rather than old make build
build-zircon.sh and thus `fx build-zircon` now runs gn (if necessary) and
ninja (just once) rather than running `make` several times. The extra
arguments previously taken as make arguments are now taken as either GN
build arguments or ninja arguments.
`fx set` now runs Zircon's `gn gen` before Fuchsia's `gn gen`, which
consumes files generated by the former.
Zircon-related GN build arguments are gone. Zircon configuration
can be controlled via arguments to build-zircon.sh instead.
Note this also means that `zircon_boot_groups="all"` behavior is now
always on. That is, the BOOTFS in the Fuchsia boot images will be
fatter and contain all of the Zircon tools and tests in `/boot`.
Zircon tests now appear in `/boot/test` rather than `/system/test`.
Bug: BLD-325 #comment Fuchsia GN integration adapted to Zircon GN legacy support
Test: manual
Change-Id: I6e0b49b65c78a27e71078d32e40d0b22d366d666
diff --git a/build/config/fuchsia/BUILD.gn b/build/config/fuchsia/BUILD.gn
index 4864667..2580aa0c 100644
--- a/build/config/fuchsia/BUILD.gn
+++ b/build/config/fuchsia/BUILD.gn
@@ -114,12 +114,16 @@
}
config("fdio_config") {
- libs = [ "fdio" ]
-
# TODO(pylaligand): find a better way to let executables link in fdio.
# Ideally their dependencies should be set up in such a way that it would get
# inherited from them.
- lib_dirs = [ "$zircon_build_dir/system/ulib/fdio" ]
+ foreach(image, zircon_images) {
+ if (image.name == "fdio" && image.cpu == current_cpu) {
+ assert(image.type == "so")
+ libs = [ "$zircon_root_build_dir/${image.path}" ]
+ }
+ }
+ assert(defined(libs), "fdio.so missing from Zircon images.json")
}
config("executable_config") {
diff --git a/build/config/fuchsia/zircon.gni b/build/config/fuchsia/zircon.gni
index 27a700e1..75064ab 100644
--- a/build/config/fuchsia/zircon.gni
+++ b/build/config/fuchsia/zircon.gni
@@ -4,59 +4,19 @@
import("//build/config/clang/clang.gni")
-declare_args() {
- # Where to find Zircon's host-side tools that are run as part of the build.
- zircon_tools_dir = "//out/build-zircon/tools"
+# This is $root_build_dir in the Zircon GN build.
+zircon_root_build_dir = "//out/build-zircon"
- # Zircon build directory for `target_cpu`, containing link-time `.so.abi`
- # files that GN `deps` on //zircon/public libraries will link against.
- # This should not be a sanitizer build.
- zircon_build_abi_dir = "//out/build-zircon/build-$target_cpu"
+# The top-level `tools` Ninja target in Zircon puts the tool binaries here.
+zircon_tools_dir = "$zircon_root_build_dir/tools"
- # Zircon build directory for `target_cpu`, containing `.manifest` and
- # `.zbi` files for Zircon's BOOTFS and kernel. This provides the kernel
- # and Zircon components used in the boot image. It also provides the
- # Zircon shared libraries used at runtime in Fuchsia packages.
- #
- # If left `""` (the default), then this is computed from
- # [`zircon_build_abi_dir`](#zircon_build_abi_dir) and
- # [`zircon_use_asan`](#zircon_use_asan).
- zircon_build_dir = ""
+# The `gn gen` stage of the Zircon GN build writes this file.
+# It's a list of {name=... path=... type=...} scopes.
+zircon_images = read_file("$zircon_root_build_dir/images.json", "json")
- # Zircon `USE_ASAN=true` build directory for `target_cpu` containing
- # `bootfs.manifest` with libraries and `devhost.asan`.
- #
- # If left `""` (the default), then this is computed from
- # [`zircon_build_dir`](#zircon_build_dir) and
- # [`zircon_use_asan`](#zircon_use_asan).
- zircon_asan_build_dir = ""
-
- # Set this if [`zircon_build_dir`](#zircon_build_dir) was built with
- # `USE_ASAN=true`, e.g. `//scripts/build-zircon.sh -A`. This mainly
- # affects the defaults for [`zircon_build_dir`](#zircon_build_dir) and
- # [`zircon_build_abi_dir`](#zircon_build_abi_dir). It also gets noticed
- # by //scripts/fx commands that rebuild Zircon so that they use `-A`
- # again next time.
- zircon_use_asan = false
-
- # Path to `make` binary. By default, `make` is assumed to be in the
- # path. Used in the script that generates the Zircon build rules. N.B. this
- # path is *not* rebased, just used as is.
- zircon_make_path = "make"
-}
-
-if (zircon_build_dir == "") {
- zircon_build_dir = zircon_build_abi_dir
- if (zircon_use_asan) {
- zircon_build_dir += "-asan"
- }
-}
-
-if (zircon_asan_build_dir == "") {
- if (zircon_use_asan) {
- zircon_asan_build_dir = zircon_build_dir
- } else {
- zircon_asan_build_dir = "${zircon_build_dir}-asan"
+foreach(image, zircon_images) {
+ if (image.name == "kernel" && image.type == "zbi" && image.cpu == target_cpu) {
+ zircon_kernel_zbi = "$zircon_root_build_dir/${image.path}"
}
}
diff --git a/build/gn/BUILD.gn b/build/gn/BUILD.gn
index 26b64c6..3b74bcc 100644
--- a/build/gn/BUILD.gn
+++ b/build/gn/BUILD.gn
@@ -112,14 +112,10 @@
[
"--out",
rebase_path("//zircon/public"),
- "--staging",
- rebase_path("$root_out_dir/zircon-gn"),
- "--zircon-user-build",
- rebase_path(zircon_build_abi_dir),
- "--zircon-tool-build",
- rebase_path("$zircon_tools_dir/.."),
- "--make",
- zircon_make_path,
+ "--zircon-build",
+ rebase_path(zircon_root_build_dir),
+ "--zircon-manifest",
+ rebase_path("$zircon_root_build_dir/export/manifest-$target_cpu"),
],
"",
zircon_files + supporting_templates)
@@ -134,24 +130,6 @@
"FUCHSIA_BUILD_DIR='${_relative_build_dir}'",
"FUCHSIA_ARCH='${target_cpu}'",
]
-if (use_goma) {
- _fx_config_lines += [
- "# This will affect Zircon's make via //scripts/build-zircon.sh.",
- "export GOMACC='${goma_dir}/gomacc'",
- ]
-}
-_fx_build_zircon_args = ""
-if (zircon_use_asan) {
- _fx_build_zircon_args += " -A"
-}
-foreach(selector, select_variant) {
- if (selector == "host_asan") {
- _fx_build_zircon_args += " -H"
- }
-}
-if (_fx_build_zircon_args != "") {
- _fx_config_lines += [ "FUCHSIA_BUILD_ZIRCON_ARGS=($_fx_build_zircon_args)" ]
-}
write_file("$root_build_dir/fx.config", _fx_config_lines)
# Generates breakpad symbol data for unstripped binaries.
diff --git a/build/images/BUILD.gn b/build/images/BUILD.gn
index e0f790f..4458773 100644
--- a/build/images/BUILD.gn
+++ b/build/images/BUILD.gn
@@ -19,40 +19,11 @@
import("//garnet/go/src/pm/pm.gni")
declare_args() {
- # Groups to include from the Zircon /boot manifest into /boot.
- # This is either "all" or a comma-separated list of one or more of:
- # core -- necessary to boot
- # misc -- utilities in /bin
- # test -- test binaries in /bin and /test
- zircon_boot_groups = "core"
-
# Path to manifest file containing data to place into the initial /data
# partition.
data_partition_manifest = ""
}
-declare_args() {
- # Groups to include from the Zircon /boot manifest into /system
- # (instead of into /boot like Zircon's own bootdata.bin does).
- # Should not include any groups that are also in zircon_boot_groups,
- # which see. If zircon_boot_groups is "all" then this should be "".
- # **TODO(mcgrathr)**: _Could default to "" for `!is_debug`, or "production
- # build". Note including `"test"` here places all of Zircon's tests into
- # `/system/test`, which means that Fuchsia bots run those tests too._
- zircon_system_groups = "misc,test"
- if (zircon_boot_groups == "all") {
- zircon_system_groups = ""
- }
-}
-
-if (zircon_boot_groups == "all") {
- assert(zircon_system_groups == "",
- "zircon_boot_groups already has everything")
-} else {
- assert(zircon_system_groups != "all" && zircon_system_groups != "core",
- "zircon_system_groups cannot include core (or all)")
-}
-
# This will collect a list of scopes describing each image exported.
# See json.gni.
images = [
@@ -290,10 +261,10 @@
# /system manifest files can assume that the /boot files are visible at
# runtime, so dependencies already in /boot won't be copied into /system.
bootfs_manifest = boot_manifest
- bootfs_zircon_groups = zircon_boot_groups
+ bootfs_zircon_groups = "all"
# Collect whatever we want from Zircon that didn't go into /boot.
- zircon_groups = zircon_system_groups
+ zircon_groups = ""
# Now each package() target in the build contributes manifest entries.
# For system_image packages, these contain binaries that need their
@@ -469,14 +440,12 @@
}
sdk = "qemu-kernel.bin"
deps = []
- if (current_cpu == "arm64") {
- sources = [
- "$zircon_build_dir/qemu-boot-shim.bin",
- ]
- } else if (current_cpu == "x64") {
- sources = [
- "$zircon_build_dir/multiboot.bin",
- ]
+ foreach(image, zircon_images) {
+ if (image.name == "qemu-kernel" && image.cpu == target_cpu) {
+ sources = [
+ "$zircon_root_build_dir/${image.path}",
+ ]
+ }
}
},
]
@@ -563,7 +532,7 @@
":system_image.manifest",
]
inputs = [
- "${zircon_build_dir}/kernel.zbi",
+ zircon_kernel_zbi,
boot_manifest,
]
manifest = [
@@ -1502,6 +1471,9 @@
###
### Build ID maps.
###
+### TODO(TC-303): ids.txt is deprecated and will be removed.
+### The toolchain rules already populate $root_build_dir/.build-id/.
+###
# Combine the /boot, /system, and package build ID maps into one.
# Nothing in the build uses this, but top-level targets always update
@@ -1512,8 +1484,6 @@
deps = [
":kernel-ids.txt",
":system_image.manifest",
- ":zircon-asan-build-id",
- ":zircon-build-id",
]
sources = [
"$target_out_dir/kernel-ids.txt",
@@ -1549,7 +1519,7 @@
action("kernel-ids.txt") {
script = "manifest.py"
sources = [
- "$zircon_build_dir/ids.txt",
+ "$zircon_root_build_dir/ids-$current_cpu.txt",
]
outputs = [
"$target_out_dir/kernel-ids.txt",
@@ -1557,45 +1527,12 @@
args = [
"--separator= ",
"--output=" + rebase_path(outputs[0], root_build_dir),
- "--include-source=*/libzircon.so",
+ "--include-source=*/libzircon.so.debug",
"--include-source=*/zircon.elf",
"--manifest=" + rebase_path(sources[0], root_build_dir),
]
}
-# TODO(TC-303): This is a temporary hack to get all of Zircon's debug files
-# into the $root_build_dir/.build-id hierarchy. The Zircon build produces
-# its own .build-id hierarchy under $zircon_build_dir, but using its ids.txt
-# is the simpler way to populate the one in this build. When ids.txt is fully
-# obsolete, hopefully Zircon will be in the unified build anyway.
-foreach(target,
- [
- {
- name = "zircon-build-id"
- sources = [
- "$zircon_build_dir/ids.txt",
- ]
- },
- {
- name = "zircon-asan-build-id"
- sources = [
- "$zircon_asan_build_dir/ids.txt",
- ]
- },
- ]) {
- action(target.name) {
- visibility = [ ":ids.txt" ]
- script = "//scripts/build_id_conv.py"
- sources = target.sources
- outputs = [
- "$root_build_dir/${target_name}.stamp",
- ]
- args =
- [ "--stamp=" + rebase_path(outputs[0], root_build_dir) ] +
- rebase_path(sources + [ "$root_build_dir/.build-id" ], root_build_dir)
- }
-}
-
images += [
{
deps = [
diff --git a/build/images/boot.gni b/build/images/boot.gni
index f66f0e8..07c6905 100644
--- a/build/images/boot.gni
+++ b/build/images/boot.gni
@@ -65,7 +65,11 @@
# The Multiboot trampoline is the "kernel" (`--vmlinuz` switch) and the
# ZBI is the RAM disk (`--bootloader` switch).
assert(current_cpu == "x64")
- kernel = "${zircon_build_dir}/multiboot.bin"
+ foreach(image, zircon_images) {
+ if (image.name == "multiboot-kernel" && image.cpu == target_cpu) {
+ kernel = "$zircon_root_build_dir/${image.path}"
+ }
+ }
inputs += [ kernel ]
args = [
@@ -182,7 +186,12 @@
}
if (target_cpu == "x64") {
- gigaboot_bin = "${zircon_build_dir}/bootloader/bootx64.efi"
+ foreach(image, zircon_images) {
+ if (image.name == "bootloader" && image.type == "efi" &&
+ image.cpu == target_cpu) {
+ gigaboot_bin = "$zircon_root_build_dir/${image.path}"
+ }
+ }
args += [
"--efi-bootloader",
rebase_path(gigaboot_bin),
diff --git a/build/images/custom_signing.gni b/build/images/custom_signing.gni
index 6a895a4..ff8085e 100644
--- a/build/images/custom_signing.gni
+++ b/build/images/custom_signing.gni
@@ -93,7 +93,7 @@
"-v",
rebase_path(vbmeta_file, root_build_dir),
"-B",
- rebase_path(zircon_build_dir, root_build_dir),
+ rebase_path(zircon_root_build_dir, root_build_dir),
]
}
}
diff --git a/build/images/finalize_manifests.py b/build/images/finalize_manifests.py
index cb05b79..0163dae 100755
--- a/build/images/finalize_manifests.py
+++ b/build/images/finalize_manifests.py
@@ -258,11 +258,15 @@
def find_debug_file(filename):
# In the Zircon makefile build, the file to be installed is called
- # foo.strip and the unstripped file is called foo. In the GN build,
- # the file to be installed is called foo and the unstripped file has
- # the same name in the exe.unstripped or lib.unstripped subdirectory.
+ # foo.strip and the unstripped file is called foo. In the new Zircon
+ # GN build, the file to be installed is called foo and the unstripped
+ # file is called foo.debug. In the Fuchsia GN build, the file to be
+ # installed is called foo and the unstripped file has the same name in
+ # the exe.unstripped or lib.unstripped subdirectory.
if filename.endswith('.strip'):
debugfile = filename[:-6]
+ elif os.path.exists(filename + '.debug'):
+ debugfile = filename + '.debug'
else:
dir, file = os.path.split(filename)
if file.endswith('.so') or '.so.' in file:
diff --git a/build/images/guest/BUILD.gn b/build/images/guest/BUILD.gn
index 6812232..c4c5fbc 100644
--- a/build/images/guest/BUILD.gn
+++ b/build/images/guest/BUILD.gn
@@ -53,7 +53,7 @@
testonly = true
bootfs_manifest = boot_manifest
- bootfs_zircon_groups = "misc,test"
+ bootfs_zircon_groups = "all"
args = []
deps = []
@@ -224,10 +224,15 @@
":devmgr_config.txt",
":guest.manifest",
]
- inputs = [
- "${zircon_build_dir}/zircon.zbi",
- boot_manifest,
- ]
+ foreach(image, zircon_images) {
+ if (image.cpu == current_cpu && image.type == "zbi" &&
+ image.name == current_cpu) {
+ inputs = [
+ "$zircon_root_build_dir/${image.path}",
+ ]
+ }
+ }
+ inputs += [ boot_manifest ]
manifest = [
{
outputs = [
diff --git a/build/images/manifest.gni b/build/images/manifest.gni
index e13f2cf..0c2451d 100644
--- a/build/images/manifest.gni
+++ b/build/images/manifest.gni
@@ -15,38 +15,20 @@
root_build_dir),
]
- # Manifest files describing extra libraries from a Zircon build
- # not included in `zircon_boot_manifests`, such as an ASan build.
- # Can be either // source paths or absolute system paths.
- #
- # Since Zircon manifest files are relative to a Zircon source directory
- # rather than to the directory containing the manifest, these are assumed
- # to reside in a build directory that's a direct subdirectory of the
- # Zircon source directory and thus their contents can be taken as
- # relative to `get_path_info(entry, "dir") + "/.."`.
- # TODO(mcgrathr): Make Zircon manifests self-relative too and then
- # merge this and toolchain_manifests into generic aux_manifests.
- if (zircon_use_asan) {
- zircon_aux_manifests = [ "$zircon_build_abi_dir/bootfs.manifest" ]
- } else {
- zircon_aux_manifests = [ "$zircon_asan_build_dir/bootfs.manifest" ]
- }
-
- # Manifest files describing files to go into the `/boot` filesystem.
- # Can be either // source paths or absolute system paths.
- # `zircon_boot_groups` controls which files are actually selected.
- #
- # Since Zircon manifest files are relative to a Zircon source directory
- # rather than to the directory containing the manifest, these are assumed
- # to reside in a build directory that's a direct subdirectory of the
- # Zircon source directory and thus their contents can be taken as
- # relative to `get_path_info(entry, "dir") + "/.."`.
- zircon_boot_manifests = [ "$zircon_build_dir/bootfs.manifest" ]
-
# Extra args to globally apply to the manifest generation script.
extra_manifest_args = []
}
+foreach(image, zircon_images) {
+ if (image.type == "manifest") {
+ if (image.name == "legacy-image-$target_cpu") {
+ zircon_boot_manifests = [ "$zircon_root_build_dir/${image.path}" ]
+ } else if (image.name == "asan-libs" && image.cpu == target_cpu) {
+ zircon_aux_manifests = [ "$zircon_root_build_dir/${image.path}" ]
+ }
+ }
+}
+
# Action target that generates a response file in GN's "shlex" format.
#
# Parameters
@@ -193,7 +175,7 @@
}
sources += zircon_aux_manifests + zircon_boot_manifests
foreach(manifest, zircon_aux_manifests + zircon_boot_manifests) {
- manifest_cwd = get_path_info(rebase_path(manifest), "dir") + "/.."
+ manifest_cwd = rebase_path(zircon_root_build_dir)
response_file_contents += [
"--cwd=$manifest_cwd",
"--manifest=" + rebase_path(manifest),
@@ -220,6 +202,10 @@
response_file_contents += [
"--exclude=bin/devhost",
"--exclude=bin/devhost.asan",
+
+ # Elide the empty file deposited by the Zircon build, since
+ # we will add our own.
+ "--exclude=config/devmgr",
]
}
@@ -243,7 +229,7 @@
response_file_contents += [ "--groups=${manifest.groups}" ]
sources += zircon_boot_manifests
foreach(manifest, zircon_boot_manifests) {
- manifest_cwd = get_path_info(rebase_path(manifest), "dir") + "/.."
+ manifest_cwd = rebase_path(zircon_root_build_dir)
response_file_contents += [
"--cwd=$manifest_cwd",
"--manifest=" + rebase_path(manifest),
diff --git a/build/images/zedboot/BUILD.gn b/build/images/zedboot/BUILD.gn
index 1bb2a68..cc1b270 100644
--- a/build/images/zedboot/BUILD.gn
+++ b/build/images/zedboot/BUILD.gn
@@ -100,7 +100,7 @@
":zedboot.manifest",
]
inputs = [
- "${zircon_build_dir}/kernel.zbi",
+ zircon_kernel_zbi,
manifest_file,
]
manifest = [
diff --git a/build/zircon/create_gn_rules.py b/build/zircon/create_gn_rules.py
index 8c2df11..85a0c1e 100755
--- a/build/zircon/create_gn_rules.py
+++ b/build/zircon/create_gn_rules.py
@@ -92,8 +92,10 @@
return
if current_list and current_map:
raise Exception('Found both map-style and list-style section')
- result[current_section] = (current_map if current_map
- else current_list)
+ if current_map:
+ result[current_section] = current_map
+ elif current_list:
+ result[current_section] = current_list
for line in lines:
section_match = section_exp.match(line)
if section_match:
@@ -118,9 +120,8 @@
# name: foo/bar.h
# path: <SOURCE|BUILD>/somewhere/under/zircon/foo/bar.h
(full_path, changes) = re.subn('^SOURCE', context.source_base, path)
- build_base = context.tool_build_base if is_tool else context.user_build_base
if not changes:
- (full_path, changes) = re.subn('^BUILD', build_base, path)
+ (full_path, changes) = re.subn('^BUILD', context.build_base, path)
if not changes:
raise Exception('Unknown pattern type: %s' % path)
folder = None
@@ -444,12 +445,10 @@
class GenerationContext(object):
'''Describes the context in which GN rules should be generated.'''
- def __init__(self, out_dir, source_base, user_build_base, tool_build_base,
- templates):
+ def __init__(self, out_dir, source_base, build_base, templates):
self.out_dir = out_dir
self.source_base = source_base
- self.user_build_base = user_build_base
- self.tool_build_base = tool_build_base
+ self.build_base = build_base
self.templates = templates
@@ -458,21 +457,15 @@
parser.add_argument('--out',
help='Path to the output directory',
required=True)
- parser.add_argument('--staging',
- help='Path to the staging directory',
+ parser.add_argument('--zircon-build',
+ help='Path to the Zircon build directory',
required=True)
- parser.add_argument('--zircon-user-build',
- help='Path to the Zircon "user" build directory',
- required=True)
- parser.add_argument('--zircon-tool-build',
- help='Path to the Zircon "tools" build directory',
+ parser.add_argument('--zircon-manifest',
+ help='Path to the Zircon export/manifest file',
required=True)
parser.add_argument('--debug',
help='Whether to print out debug information',
action='store_true')
- parser.add_argument('--make',
- help='Path to make binary',
- required=True)
args = parser.parse_args()
out_dir = os.path.abspath(args.out)
@@ -484,29 +477,13 @@
shutil.rmtree(os.path.join(out_dir, 'tool'), True)
debug = args.debug
- # Generate package descriptions through Zircon's build.
- zircon_dir = os.path.abspath(args.staging)
- shutil.rmtree(zircon_dir, True)
- if debug:
- print('Building Zircon in: %s' % zircon_dir)
- make_args = [
- args.make,
- 'packages',
- 'BUILDDIR=%s' % zircon_dir,
- ]
-
- env = {}
- env['PATH'] = os.environ['PATH']
- if not debug:
- env['QUIET'] = '1'
- subprocess.check_call(make_args, cwd=ZIRCON_ROOT, env=env)
- # Parse package definitions.
+ # Parse package definitions from Zircon's build.
packages = []
- with open(os.path.join(zircon_dir, 'export', 'manifest'), 'r') as manifest:
- package_files = map(lambda line: line.strip(), manifest.readlines())
- for file in package_files:
- with open(os.path.join(zircon_dir, 'export', file), 'r') as pkg_file:
- packages.append(parse_package(pkg_file.readlines()))
+ with open(args.zircon_manifest, 'r') as manifest:
+ for file in manifest:
+ file = file.strip()
+ with open(os.path.join(args.zircon_build, 'export', file), 'r') as pkg_file:
+ packages.append(parse_package(pkg_file.readlines()))
if debug:
print('Found %s packages:' % len(packages))
names = sorted(map(lambda p: p['package']['name'], packages))
@@ -517,8 +494,7 @@
context = GenerationContext(
out_dir,
ZIRCON_ROOT,
- os.path.abspath(args.zircon_user_build),
- os.path.abspath(args.zircon_tool_build),
+ os.path.abspath(args.zircon_build),
TemplateLookup(directories=[SCRIPT_DIR]),
)
for package in packages:
@@ -552,10 +528,14 @@
if debug:
print('Processed %s (%s)' % (name, type))
- board_path = os.path.join(zircon_dir, 'export', 'all-boards.list')
- with open(board_path, 'r') as board_file:
- package = parse_package(board_file.readlines())
- generate_board_list(package, context)
+ board_file_lines = []
+ for cpu in ['arm64', 'x64']:
+ board_path = os.path.join(args.zircon_build, 'export',
+ 'boards-%s.list' % cpu)
+ with open(board_path, 'r') as board_file:
+ board_file_lines += [ '[%s]' % cpu ] + board_file.readlines()
+ package = parse_package(board_file_lines)
+ generate_board_list(package, context)
if __name__ == '__main__':
diff --git a/scripts/build-zircon.sh b/scripts/build-zircon.sh
index f18edf4..6c20f37 100755
--- a/scripts/build-zircon.sh
+++ b/scripts/build-zircon.sh
@@ -6,32 +6,41 @@
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
readonly ROOT_DIR="$(dirname "${SCRIPT_DIR}")"
-JOBS=`getconf _NPROCESSORS_ONLN` || {
- Cannot get number of processors
- exit 1
-}
-
set -eo pipefail; [[ "${TRACE}" ]] && set -x
usage() {
- echo "$0 <options> <extra-make-arguments>"
+ echo "$0 <options> [<gn_build_arg>=<value> ...] [<ninja_arg> ...]"
echo ""
echo "Options:"
echo " -c: Clean before building"
+ echo " -g: Run GN but not Ninja"
+ echo " -G: Run Ninja but not GN (Ninja will re-run GN as needed)"
echo " -v: Level 1 verbosity"
echo " -V: Level 2 verbosity"
echo " -A: Build with ASan"
echo " -H: Build host tools with ASan"
- echo " -n: Just print make recipes to STDOUT."
+ echo " -n: Just print build commands to STDOUT."
echo " -l: Only build tools; do not build zircon."
echo " -j N: Passed along to make (number of parallel jobs)"
echo " -t <target>: Architecture (GN style) to build, instead of all"
echo " -o <outdir>: Directory in which to put the build-zircon directory."
echo ""
- echo "Additional arguments may be passed to make using standard FOO=bar syntax."
- echo "E.g., build-zircon.sh USE_CLANG=true"
+ echo 'Additional arguments containing `=` will be used as GN build arguments.'
+ echo "Other additional arguments will be passed as extra Ninja arguments."
+ echo "e.g., $0 use_goma=true core-tests-x64"
+ echo ""
+ echo 'Note that -A and -H translate into a `variants=...` build argument.'
+ echo "You can't use those switches and also such a build argument."
+ echo "Note that if GN no build arguments (nor -c) are specified and the file"
+ echo "<outdir>/build-zircon/args.gn already exists, it will be reused."
+ echo "For nontrivial configuration changes, edit the args.gn file by hand"
+ echo "either from scratch or after a run of this script with switches;"
+ echo "then run this script with neither build arguments nor -A or -H."
}
+readonly GN="${ROOT_DIR}/zircon/prebuilt/downloads/gn"
+readonly NINJA="${ROOT_DIR}/zircon/prebuilt/downloads/ninja"
+
declare ASAN="false"
declare CLEAN="false"
declare DRY_RUN="false"
@@ -40,11 +49,16 @@
declare OUTDIR="${ROOT_DIR}/out"
declare VERBOSE="0"
declare -a ARCHLIST=(arm64 x64)
+declare JOBS=0
+declare RUN_GN="true"
+declare RUN_NINJA="true"
-while getopts "AcHhlnj:t:p:o:vV" opt; do
+while getopts "AcgGHhlnj:t:p:o:vV" opt; do
case "${opt}" in
A) ASAN="true" ;;
c) CLEAN="true" ;;
+ g) RUN_NINJA="false" ;;
+ G) RUN_GN="false" ;;
H) HOST_ASAN="true" ;;
h) usage ; exit 0 ;;
n) DRY_RUN="true" ;;
@@ -67,51 +81,90 @@
rm -rf -- "${ZIRCON_BUILDROOT}"
fi
-# These variables are picked up by make from the environment.
-case "${VERBOSE}" in
- 1) QUIET=0 ; V=0 ;;
- 2) QUIET=0 ; V=1 ;;
- *) QUIET=1 ; V=0 ;;
-esac
-export QUIET V
+GN_CMD=("$GN" gen "$ZIRCON_BUILDROOT" --root="${ROOT_DIR}/zircon")
+NINJA_CMD=("$NINJA" -C "$ZIRCON_BUILDROOT")
+VARIANTS=()
+GN_ARGS=()
-if [[ "${ASAN}" = "true" ]]; then
- readonly NOT_ASAN=false
+if $ASAN; then
+ VARIANTS+=(asan)
+fi
+if $HOST_ASAN; then
+ VARIANTS+=(host_asan)
+fi
+if [ ${#VARIANTS[@]} -gt 0 ]; then
+ VARIANTS_ARG='variants = ['
+ for variant in "${VARIANTS[@]}"; do
+ VARIANTS_ARG+="\"${variant}\", "
+ done
+ VARIANTS_ARG+=']'
+ GN_ARGS+=("$VARIANTS_ARG")
+fi
+
+if [[ $VERBOSE -lt 1 ]]; then
+ GN_CMD+=(-q)
+ # Ninja doesn't have a --quiet switch.
+fi
+if [[ $VERBOSE -ge 2 ]]; then
+ NINJA_CMD+=(-v)
+fi
+
+if $DRY_RUN; then
+ NINJA_CMD+=(-n)
+fi
+
+if [[ "$JOBS" != 0 ]]; then
+ NINJA_CMD+=(-j "$JOBS")
+fi
+
+if $TOOLS_ONLY; then
+ NINJA_CMD+=(tools)
else
- readonly NOT_ASAN=true
+ NINJA_CMD+=(legacy-host_tests)
+ for arch in "${ARCHLIST[@]}"; do
+ NINJA_CMD+=("manifest-$arch")
+ done
fi
-if [[ "${DRY_RUN}" = "true" ]]; then
- readonly DRY_RUN_ARGS="-Bnwk"
+for arg in "$@"; do
+ # TODO(BLD-325): Special case for argument used by bot recipes.
+ # Remove this after infra transitions.
+ if [[ "$arg" == GOMACC=* ]]; then
+ goma_dir="$(dirname "${arg#GOMACC=}")"
+ GN_ARGS+=(use_goma=true "goma_dir=\"$goma_dir\"")
+ elif [[ "$arg" == *=* ]]; then
+ GN_ARGS+=("$arg")
+ elif $RUN_NINJA; then
+ NINJA_CMD+=("$arg")
+ else
+ echo >&2 "Extra Ninja arguments given when -g says not to run Ninja"
+ exit 2
+ fi
+done
+
+if [[ ${#GN_ARGS[@]} -gt 0 ]]; then
+ if ! $RUN_GN; then
+ echo >&2 "GN build arguments specified when -G says not to run GN"
+ echo >&2 "Consider editting $ZIRCON_BUILDROOT/args.gn by hand instead."
+ exit 2
+ fi
+ GN_CMD+=("--args=${GN_ARGS[*]}")
+elif $RUN_GN && [[ $VERBOSE -gt 0 && -r "$ZIRCON_BUILDROOT/args.gn" ]]; then
+ echo >&2 "Reusing existing $ZIRCON_BUILDROOT/args.gn file."
fi
-make_zircon_common() {
- (test $QUIET -ne 0 || set -x
- exec make ${DRY_RUN_ARGS} --no-print-directory -C "${ROOT_DIR}/zircon" \
- -j ${JOBS} DEBUG_BUILDROOT=../../zircon "$@")
+run_cmd() {
+ if [[ $VERBOSE -gt 0 ]]; then
+ (set -x; "$@")
+ else
+ "$@"
+ fi
}
-# Build host tools.
-make_zircon_common \
- BUILDDIR=${OUTDIR}/build-zircon HOST_USE_ASAN="${HOST_ASAN}" tools "$@"
-
-if [[ "${TOOLS_ONLY}" = "true" ]]; then
+if ! $RUN_GN && ! $RUN_NINJA; then
+ echo >&2 "Doing nothing since -g and -G say not to."
exit 0
fi
-make_zircon_target() {
- make_zircon_common \
- BUILDROOT=${ZIRCON_BUILDROOT} TOOLS=${OUTDIR}/build-zircon/tools "$@"
-}
-
-for ARCH in "${ARCHLIST[@]}"; do
- # Build without ASan for sysroot. If all of userland will be ASan,
- # then this build is only user libraries.
- make_zircon_target PROJECT="${ARCH}" \
- BUILDDIR_SUFFIX= ENABLE_ULIB_ONLY="${ASAN}" "$@"
-
- # Always build at least the libraries with ASan, but never the sysroot.
- make_zircon_target PROJECT="${ARCH}" \
- BUILDDIR_SUFFIX=-asan USE_ASAN=true ENABLE_BUILD_SYSROOT=false \
- ENABLE_ULIB_ONLY="${NOT_ASAN}"
-done
+! $RUN_GN || run_cmd "${GN_CMD[@]}"
+! $RUN_NINJA || run_cmd "${NINJA_CMD[@]}"
diff --git a/scripts/devshell/build b/scripts/devshell/build
index 97ae565..7d0609f 100755
--- a/scripts/devshell/build
+++ b/scripts/devshell/build
@@ -3,63 +3,16 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-### build Fuchsia
+### Run Ninja to build Fuchsia
-## usage: fx build [ninja option,...] [target,...]
+## usage: fx build [ninja arguments ...]
+## Run `fx build -h` to see Ninja argument details.
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/lib/vars.sh || exit $?
fx-config-read
function main {
- local args=()
- local have_load=false
- local have_jobs=false
- while [[ $# -gt 0 ]]; do
- case "$1" in
- -l) have_load=true ;;
- -j) have_jobs=true ;;
- esac
- args+=("$1")
- shift
- done
-
- if ! $have_load; then
- if [[ "$(uname -s)" == "Darwin" ]]; then
- # Load level on Darwin is quite different from that of Linux, wherein a
- # load level of 1 per CPU is not necessarily a prohibitive load level. An
- # unscientific study of build side effects suggests that cpus*20 is a
- # reaosnable value to prevent catastrophic load (i.e. user can not kill
- # the build, can not lock the screen, etc).
- local cpus="$(fx-cpu-count)"
- args=("-l" $(($cpus * 20)) "${args[@]}")
- fi
- fi
-
- if ! $have_jobs; then
- local concurrency="$(fx-choose-build-concurrency)"
- # macOS in particular has a low default for number of open file descriptors
- # per process, which is prohibitive for higher job counts. Here we raise
- # the number of allowed file descriptors per process if it appears to be
- # low in order to avoid failures due to the limit. See `getrlimit(2)` for
- # more information.
- local min_limit=$((${concurrency} * 2))
- if [[ $(ulimit -n) -lt "${min_limit}" ]]; then
- ulimit -n "${min_limit}"
- fi
- args=("-j" "${concurrency}" "${args[@]}")
- fi
-
-
- # TERM is passed for the pretty ninja UI
- # PATH is passed as some tools are referenced via $PATH due to platform differences.
- # TMPDIR is passed for Goma on macOS. TMPDIR must be set, or unset, not
- # empty. Some Dart build tools have been observed writing into source paths
- # when TMPDIR="" - it is deliberately unquoted and using the ${+} expansion
- # expression).
- fx-try-locked env -i TERM="${TERM}" PATH="${PATH}" \
- ${NINJA_STATUS+"NINJA_STATUS=${NINJA_STATUS}"} \
- ${TMPDIR+"TMPDIR=$TMPDIR"} \
- "${FUCHSIA_DIR}/buildtools/ninja" -C "${FUCHSIA_BUILD_DIR}" "${args[@]}"
+ fx-run-ninja "${FUCHSIA_DIR}/buildtools/ninja" -C "${FUCHSIA_BUILD_DIR}" "$@"
}
main "$@"
diff --git a/scripts/devshell/build-zircon b/scripts/devshell/build-zircon
index 2071072..12f5507 100755
--- a/scripts/devshell/build-zircon
+++ b/scripts/devshell/build-zircon
@@ -3,13 +3,19 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-### build the kernel
+### Run //scripts/build-zircon.sh to build Zircon.
+## Arguments are passed to build-zircon.sh; run with -h for details.
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/lib/vars.sh || exit $?
fx-config-read
-echo "Building zircon..."
-"${FUCHSIA_DIR}/scripts/build-zircon.sh" \
+# If `fx set` or `fx build-zircon` has already been run, then the explicit
+# `gn gen` run is superfluous and Ninja will do it as needed.
+if [[ -r "${ZIRCON_BUILDROOT}/args.gn" ]]; then
+ set -- -G "$@"
+fi
+
+fx-run-ninja "${FUCHSIA_DIR}/scripts/build-zircon.sh" \
-t "${FUCHSIA_ARCH}" \
-j "$(fx-choose-build-concurrency)" \
- "${FUCHSIA_BUILD_ZIRCON_ARGS[@]}" "$@"
+ "$@"
diff --git a/scripts/devshell/full-build b/scripts/devshell/full-build
index 3fb0c5a..5218479 100755
--- a/scripts/devshell/full-build
+++ b/scripts/devshell/full-build
@@ -4,7 +4,8 @@
# found in the LICENSE file.
### build zircon, then build fuchsia
-## build zircon, then build fuchsia
+## Runs exactly `fx build-zircon` followed by `fx build`.
+## Arguments are ignored. To pass arguments, run each step separately.
set -e
diff --git a/scripts/devshell/lib/vars.sh b/scripts/devshell/lib/vars.sh
index 4c13d10..b5d8628 100644
--- a/scripts/devshell/lib/vars.sh
+++ b/scripts/devshell/lib/vars.sh
@@ -115,22 +115,14 @@
local -r build_dir="$1"
if [[ "$build_dir" == /* ]]; then
local -r args_file="${build_dir}/args.gn"
- local -r zircon_args_file="${build_dir}.zircon-args"
else
local -r args_file="${FUCHSIA_DIR}/${build_dir}/args.gn"
- local -r zircon_args_file="${FUCHSIA_DIR}/${build_dir}.zircon-args"
fi
- local arch zircon_args
- arch="$(fx-config-glean-arch "$args_file")" || return
- if [[ -f "${zircon_args_file}" ]]; then
- zircon_args=$(<"${zircon_args_file}")
- fi
- shift
+ local arch="$(fx-config-glean-arch "$args_file")" || return
echo > "${FUCHSIA_CONFIG}" "\
# Generated by \`fx set\` or \`fx use\`.
FUCHSIA_BUILD_DIR='${build_dir}'
FUCHSIA_ARCH='${arch}'
-FUCHSIA_BUILD_ZIRCON_ARGS=(${zircon_args})
"
}
@@ -333,3 +325,57 @@
function fx-exit-on-failure {
"$@" || exit $?
}
+
+# Massage a ninja command line to add default -j and/or -l switches.
+# Note this takes the ninja command itself as first argument.
+# This can be used both to run ninja directly or to run a wrapper script.
+function fx-run-ninja {
+ local args=()
+ local have_load=false
+ local have_jobs=false
+ while [[ $# -gt 0 ]]; do
+ case "$1" in
+ -l) have_load=true ;;
+ -j) have_jobs=true ;;
+ esac
+ args+=("$1")
+ shift
+ done
+
+ if ! $have_load; then
+ if [[ "$(uname -s)" == "Darwin" ]]; then
+ # Load level on Darwin is quite different from that of Linux, wherein a
+ # load level of 1 per CPU is not necessarily a prohibitive load level. An
+ # unscientific study of build side effects suggests that cpus*20 is a
+ # reaosnable value to prevent catastrophic load (i.e. user can not kill
+ # the build, can not lock the screen, etc).
+ local cpus="$(fx-cpu-count)"
+ args+=("-l" $(($cpus * 20)))
+ fi
+ fi
+
+ if ! $have_jobs; then
+ local concurrency="$(fx-choose-build-concurrency)"
+ # macOS in particular has a low default for number of open file descriptors
+ # per process, which is prohibitive for higher job counts. Here we raise
+ # the number of allowed file descriptors per process if it appears to be
+ # low in order to avoid failures due to the limit. See `getrlimit(2)` for
+ # more information.
+ local min_limit=$((${concurrency} * 2))
+ if [[ $(ulimit -n) -lt "${min_limit}" ]]; then
+ ulimit -n "${min_limit}"
+ fi
+ args+=("-j" "${concurrency}")
+ fi
+
+ # TERM is passed for the pretty ninja UI
+ # PATH is passed as some tools are referenced via $PATH due to platform differences.
+ # TMPDIR is passed for Goma on macOS. TMPDIR must be set, or unset, not
+ # empty. Some Dart build tools have been observed writing into source paths
+ # when TMPDIR="" - it is deliberately unquoted and using the ${+} expansion
+ # expression).
+ fx-try-locked env -i TERM="${TERM}" PATH="${PATH}" \
+ ${NINJA_STATUS+"NINJA_STATUS=${NINJA_STATUS}"} \
+ ${TMPDIR+"TMPDIR=$TMPDIR"} \
+ "${args[@]}"
+}
diff --git a/scripts/devshell/run-host-tests b/scripts/devshell/run-host-tests
index 3ffd338..61653ec 100755
--- a/scripts/devshell/run-host-tests
+++ b/scripts/devshell/run-host-tests
@@ -40,7 +40,7 @@
done
if [[ $ZIRCON -eq 1 ]]; then
- host_test_dir="${ZIRCON_BUILD_DIR}/host_tests"
+ host_test_dir="${ZIRCON_BUILDROOT}/host_tests"
fx-command-run build-zircon "-v"
else
host_test_dir="${FUCHSIA_BUILD_DIR}/host_tests"
diff --git a/scripts/devshell/set b/scripts/devshell/set
index 6b6153d..b4478ab 100755
--- a/scripts/devshell/set
+++ b/scripts/devshell/set
@@ -134,8 +134,8 @@
## build.
## This flag is deprecated, please use one of
## --available, --preinstall, or --monolith.
-## --zircon-arg ARG Additional arguments to pass to Zircon make. Can be given
-## multiple times.
+## --zircon-arg ARG Additional arguments to pass to build-zircon.sh.
+## Can be given multiple times.
##
## Example:
##
@@ -238,7 +238,7 @@
local preinstall=()
local monolith=()
local packages=()
- local zircon_args=()
+ local zircon_args=(-v -g -t "$arch")
local extra_packages=()
local build_dir=
local variant=
@@ -501,6 +501,7 @@
# Add goma or ccache settings as appropriate.
if [[ "${use_goma}" -eq 1 ]]; then
gn_args+=" use_goma=true goma_dir=\"${goma_dir}\""
+ zircon_args+=(use_goma=true "goma_dir=\"${goma_dir}\"")
elif [[ "${ccache}" -eq 1 ]]; then
gn_args+=" use_ccache=true"
fi
@@ -545,14 +546,14 @@
gn_args+=" select_variant=[${variant}]"
fi
- mkdir -p "${build_dir}"
- echo "${zircon_args[@]}" > "${build_dir}.zircon-args"
-
# Using a subshell with -x prints out the gn command precisely with shell
# quoting so a cut&paste to the command line works. Always show the real
# meaning of what this script does so everyone learns how GN works.
(
- set -x
+ set -x -e
+ # Zircon's `gn gen` phase has to be done before Fuchsia's `gn gen`.
+ # The former produces the legacy-$cpu.json file consumed by the latter.
+ "${FUCHSIA_DIR}/scripts/build-zircon.sh" "${zircon_args[@]}"
"${FUCHSIA_DIR}/buildtools/gn" ${gn_cmd} "${build_dir}" \
"${gn_switches[@]}" --args="${gn_args}" "$@"
# If GN failed, don't update .config.