blob: 652585bbab75b30ec0faf931d90b9d19233f49e5 [file] [log] [blame]
# Copyright 2017 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Recipe for building QEMU."""
import shlex
from recipe_engine.recipe_api import Property, StepFailure
DEPS = [
"fuchsia/cas_util",
"fuchsia/cipd_util",
"fuchsia/git",
"fuchsia/git_checkout",
"fuchsia/goma",
"fuchsia/macos_sdk",
"fuchsia/status_check",
"recipe_engine/cipd",
"recipe_engine/context",
"recipe_engine/file",
"recipe_engine/path",
"recipe_engine/platform",
"recipe_engine/properties",
"recipe_engine/raw_io",
"recipe_engine/step",
]
PLATFORM_TO_TRIPLE = {
"linux-amd64": "x86_64-linux-gnu",
"linux-arm64": "aarch64-linux-gnu",
"mac-amd64": "x86_64-apple-darwin",
"mac-arm64": "arm64-apple-darwin",
}
PLATFORMS = PLATFORM_TO_TRIPLE.keys()
PROPERTIES = {
"repository": Property(
kind=str,
help="Git repository URL",
default="https://fuchsia.googlesource.com/third_party/qemu",
),
"ref": Property(kind=str, help="Git ref", default="refs/tags/v7.0.0"),
"revision": Property(kind=str, help="Revision", default=None),
"platform": Property(kind=str, help="CIPD platform for the target", default=None),
"prod": Property(kind=bool, help="Whether to do production build", default=True),
}
# Bump this number whenever changing this recipe in ways that affect the
# package built without also changing any upstream revision pin.
RECIPE_SALT = "1"
def RunSteps(api, repository, ref, revision, platform, prod):
api.goma.ensure()
if not revision:
if ref.startswith("refs/tags/"):
revision = api.git.get_remote_tag(
repository, ref, step_name="git ls-remote"
)
else:
revision = api.git.get_remote_branch_head(
repository, ref, step_name="git ls-remote"
)
host_platform = api.cipd_util.platform_name
target_platform = platform or host_platform
with api.step.nest("ensure_packages"):
with api.context(infra_steps=True):
cipd_dir = api.path["start_dir"].join("cipd")
pkgs = api.cipd.EnsureFile()
pkgs.add_package("infra/cmake/${platform}", "version:3.9.2")
pkgs.add_package("infra/ninja/${platform}", "version:1.8.2")
pkgs.add_package("fuchsia/third_party/clang/${platform}", "integration")
if target_platform.startswith("linux"):
pkgs.add_package(
"fuchsia/sysroot/linux-amd64",
"git_revision:a96053c799a0f1ad0b7e8ab8199edbfa18adcbb6",
"linux-amd64",
)
pkgs.add_package(
"fuchsia/sysroot/linux-arm64",
"git_revision:a96053c799a0f1ad0b7e8ab8199edbfa18adcbb6",
"linux-arm64",
)
pkgs.add_package(
"fuchsia/third_party/source/m4", "version:1.4.18", "source/m4"
)
pkgs.add_package(
"fuchsia/third_party/source/autoconf", "version:2.69", "source/autoconf"
)
pkgs.add_package(
"fuchsia/third_party/source/automake", "version:1.16", "source/automake"
)
pkgs.add_package(
"fuchsia/third_party/source/libtool", "version:2.4.6", "source/libtool"
)
pkgs.add_package(
"fuchsia/third_party/source/make", "version:4.2.1", "source/make"
)
pkgs.add_package(
"fuchsia/third_party/source/pkg-config",
"version:0.29",
"source/pkg-config",
)
pkgs.add_package(
"fuchsia/third_party/source/gettext",
"version:0.19.8.1",
"source/gettext",
)
pkgs.add_package(
"fuchsia/third_party/source/glib", "version:2.58.2", "source/glib"
)
pkgs.add_package(
"fuchsia/third_party/source/libffi", "version:3.3", "source/libffi"
)
pkgs.add_package(
"fuchsia/third_party/source/pixman", "version:0.36.0", "source/pixman"
)
pkgs.add_package(
"fuchsia/third_party/source/sdl", "version:2.0.12", "source/sdl"
)
pkgs.add_package(
"fuchsia/third_party/source/zlib", "version:1.2.11", "source/zlib"
)
api.cipd.ensure(cipd_dir, pkgs)
pkg_dir = api.path["start_dir"].join("pkgconfig")
api.file.ensure_directory("create pkg dir", pkg_dir)
variables = {
"PKG_CONFIG_SYSROOT_DIR": pkg_dir,
"PKG_CONFIG_ALLOW_SYSTEM_CFLAGS": 1,
"PKG_CONFIG_ALLOW_SYSTEM_LIBS": 1,
"PKG_CONFIG_LIBDIR": ":".join(
[
str(pkg_dir.join("share", "pkgconfig")),
str(pkg_dir.join("lib", "pkgconfig")),
]
),
}
with api.macos_sdk(), api.context(
env=variables, env_prefixes={"PATH": [pkg_dir.join("bin")]}
):
with api.step.nest("make"):
build_make(api, cipd_dir, pkg_dir, host_platform, host_platform)
with api.step.nest("m4"):
build_m4(api, cipd_dir, pkg_dir, host_platform, host_platform)
with api.step.nest("autoconf"):
build_autoconf(api, cipd_dir, pkg_dir, host_platform, host_platform)
with api.step.nest("automake"):
build_automake(api, cipd_dir, pkg_dir, host_platform, host_platform)
with api.step.nest("libtool"):
build_libtool(api, cipd_dir, pkg_dir, host_platform, host_platform)
with api.step.nest("pkg-config"):
build_pkg_config(api, cipd_dir, pkg_dir, host_platform, host_platform)
if target_platform.startswith("linux"):
with api.step.nest("sdl"):
build_sdl(api, cipd_dir, pkg_dir, target_platform, host_platform)
with api.step.nest("zlib"):
build_zlib(api, cipd_dir, pkg_dir, target_platform, host_platform)
with api.step.nest("pixman"):
build_pixman(api, cipd_dir, pkg_dir, target_platform, host_platform)
with api.step.nest("libffi"):
build_libffi(api, cipd_dir, pkg_dir, target_platform, host_platform)
with api.step.nest("gettext"):
build_gettext(api, cipd_dir, pkg_dir, target_platform, host_platform)
with api.step.nest("glib"):
build_glib(api, cipd_dir, pkg_dir, target_platform, host_platform)
with api.step.nest("qemu"):
build_qemu(api, cipd_dir, target_platform, host_platform, revision, prod)
def platform_sysroot(api, cipd_dir, platform):
if platform.startswith("linux"):
return cipd_dir.join(platform)
elif platform.startswith("mac"): # pragma: no cover
# TODO(fxbug.dev/3043): Eventually use our own hermetic sysroot as for Linux.
step_result = api.step(
"xcrun",
["xcrun", "--sdk", "macosx", "--show-sdk-path"],
stdout=api.raw_io.output_text(name="sdk-path", add_output_log=True),
step_test_data=lambda: api.raw_io.test_api.stream_output_text(
"/some/xcode/path"
),
)
return step_result.stdout.strip()
assert False, "unsupported platform" # pragma: no cover
return None # pragma: no cover
def environment(api, cipd_dir, platform, host, cflags=(), cxxflags=(), ldflags=()):
sysroot = ["--sysroot=%s" % platform_sysroot(api, cipd_dir, platform)]
target = ["--target=%s" % PLATFORM_TO_TRIPLE[platform]] if platform != host else []
opt = ["-O3"]
# TODO: Enable LTO for Mac targets.
#
# On Mac this currently fails basic Make compile checks
# configure: error: in `/opt/s/w/ir/x/w/make':
# configure: error: C compiler cannot create executables
if platform.startswith("linux"):
opt.extend(["-flto", "-fwhole-program-vtables"])
variables = {
"CC": cipd_dir.join("bin", "clang"),
"CXX": cipd_dir.join("bin", "clang++"),
"CFLAGS": " ".join(sysroot + target + opt + list(cflags)),
"CPPFLAGS": " ".join(sysroot + target + opt + list(cflags)),
"CXXFLAGS": " ".join(sysroot + target + opt + list(cxxflags)),
"LDFLAGS": " ".join(sysroot + target + opt + list(ldflags)),
"AR": cipd_dir.join("bin", "llvm-ar"),
"RANLIB": cipd_dir.join("bin", "llvm-ranlib"),
"NM": cipd_dir.join("bin", "llvm-nm"),
"STRIP": cipd_dir.join("bin", "llvm-strip"),
"OBJCOPY": cipd_dir.join("bin", "llvm-objcopy"),
}
return variables
def configure(
api,
cipd_dir,
src_dir,
platform,
host,
flags=(),
cflags=(),
cxxflags=(),
ldflags=(),
step_name="configure",
):
variables = environment(api, cipd_dir, platform, host, cflags, cxxflags, ldflags)
if platform != host:
flags.extend(
[
# config.sub used by QEMU doesn't yet recognize arm64-apple-darwin which
# is used by Clang, so replace it with aarch64-apple-darwin to make the
# script not fail.
"--build=%s"
% PLATFORM_TO_TRIPLE[host].replace(
"arm64-apple-darwin", "aarch64-apple-darwin"
),
"--host=%s"
% PLATFORM_TO_TRIPLE[platform].replace(
"arm64-apple-darwin", "aarch64-apple-darwin"
),
]
)
return api.step(
step_name,
[src_dir.join("configure")]
+ flags
+ sorted("%s=%s" % (k, v) for k, v in variables.items()),
)
def cmake(api, cipd_dir, src_dir, platform, options=None, step_name="cmake"):
options = options or []
options.extend(
[
"-DCMAKE_LINKER=%s" % cipd_dir.join("bin", "ld.lld"),
"-DCMAKE_NM=%s" % cipd_dir.join("bin", "llvm-nm"),
"-DCMAKE_OBJCOPY=%s" % cipd_dir.join("bin", "llvm-objcopy"),
"-DCMAKE_OBJDUMP=%s" % cipd_dir.join("bin", "llvm-objdump"),
"-DCMAKE_RANLIB=%s" % cipd_dir.join("bin", "llvm-ranlib"),
"-DCMAKE_STRIP=%s" % cipd_dir.join("bin", "llvm-strip"),
]
)
target = PLATFORM_TO_TRIPLE[platform]
return api.step(
step_name,
[
cipd_dir.join("bin", "cmake"),
"-GNinja",
"-DCMAKE_MAKE_PROGRAM=%s" % cipd_dir.join("ninja"),
"-DCMAKE_C_COMPILER=%s" % cipd_dir.join("bin", "clang"),
"-DCMAKE_C_COMPILER_TARGET=%s" % target,
"-DCMAKE_CXX_COMPILER=%s" % cipd_dir.join("bin", "clang++"),
"-DCMAKE_CXX_COMPILER_TARGET=%s" % target,
"-DCMAKE_SYSROOT=%s" % platform_sysroot(api, cipd_dir, platform),
]
+ options
+ [src_dir],
)
def automake(api, name, cipd_dir, pkg_dir, platform, host, cflags=()):
src_dir = cipd_dir.join("source", name)
build_dir = api.path["start_dir"].join(name)
api.file.ensure_directory(name, build_dir)
with api.context(cwd=build_dir):
configure(
api,
cipd_dir,
src_dir,
platform,
host,
["--prefix=%s" % pkg_dir],
cflags,
)
api.step("build", ["make", "-j%d" % api.goma.jobs])
api.step("install", ["make", "install"])
def build_make(api, cipd_dir, pkg_dir, platform, host):
automake(api, "make", cipd_dir, pkg_dir, platform, host)
def build_m4(api, cipd_dir, pkg_dir, platform, host):
automake(
api,
"m4",
cipd_dir,
pkg_dir,
platform,
host,
cflags=["-Wno-incompatible-function-pointer-types"],
)
def build_autoconf(api, cipd_dir, pkg_dir, platform, host):
automake(api, "autoconf", cipd_dir, pkg_dir, platform, host)
def build_automake(api, cipd_dir, pkg_dir, platform, host):
automake(api, "automake", cipd_dir, pkg_dir, platform, host)
def build_libtool(api, cipd_dir, pkg_dir, platform, host):
automake(api, "libtool", cipd_dir, pkg_dir, platform, host)
def build_pkg_config(api, cipd_dir, pkg_dir, platform, host):
src_dir = cipd_dir.join("source", "pkg-config")
build_dir = api.path["start_dir"].join("pkg-config")
api.file.ensure_directory("pkg-config", build_dir)
ldflags = ()
if host.startswith("mac"):
ldflags = ("-framework CoreFoundation", "-framework CoreServices")
with api.context(cwd=build_dir):
configure(
api,
cipd_dir,
src_dir,
platform,
host,
[
"--prefix=%s" % pkg_dir,
"--with-internal-glib",
"--disable-host-tool",
"--disable-debug",
],
ldflags=ldflags,
cflags=[
# The internal copy of glib has some violations.
"-Wno-int-conversion",
],
)
api.step("build", ["make", "-j%d" % api.goma.jobs])
api.step("install", ["make", "install"])
def build_zlib(api, cipd_dir, pkg_dir, platform, host):
src_dir = cipd_dir.join("source", "zlib")
build_dir = api.path["start_dir"].join("zlib")
api.file.ensure_directory("zlib", build_dir)
variables = environment(api, cipd_dir, platform, host, cflags=("-fPIC",))
with api.context(cwd=build_dir, env=variables):
api.step("configure", [src_dir.join("configure"), "--prefix=", "--static"])
api.step("build", ["make", "-j%d" % api.goma.jobs])
api.step("install", ["make", "install", "DESTDIR=%s" % pkg_dir])
def build_pixman(api, cipd_dir, pkg_dir, platform, host):
src_dir = cipd_dir.join("source", "pixman")
build_dir = api.path["start_dir"].join("pixman")
api.file.ensure_directory("pixman", build_dir)
with api.context(cwd=build_dir):
configure(
api,
cipd_dir,
src_dir,
platform,
host,
[
"--disable-dependency-tracking",
"--disable-gtk",
"--disable-shared",
"--disable-silent-rules",
"--enable-static",
"--prefix=",
"--with-pic",
],
)
# pixman tests do not compile under LTO due to missing symbols [0]. We
# get around this by only building/installing the pixman directory,
# then dropping then installing the `pc` files so the library can be
# found. We could also fix this by upreving pixman to a new version
# which supports skipping test/demo builds natively.
#
# Missing symbol example:
#
# ld.lld: error: undefined symbol: __floatditf
# >>> referenced by ld-temp.o
# >>> lto.tmp:(test_matrix)
# >>> referenced by ld-temp.o
# >>> lto.tmp:(test_matrix)
# >>> referenced by ld-temp.o
# >>> lto.tmp:(test_matrix)
# >>> referenced 3 more times
#
# Adding `--rtlib=compiler-rt` to LDFLAGS didn't seem to help, maybe I
# misunderstand where that symbol is supposed to come from.
api.step("build", ["make", "-C", "pixman", "-j%d" % api.goma.jobs])
api.step("install", ["make", "install", "-C", "pixman", "DESTDIR=%s" % pkg_dir])
api.step(
"install pixman-1.pc",
["make", "install-pkgconfigDATA", "DESTDIR=%s" % pkg_dir],
)
def build_sdl(
api, cipd_dir, pkg_dir, platform, host
): # pylint: disable=unused-argument
# host isn't used, but keep it for symmetry with the other build_ functions.
src_dir = cipd_dir.join("source", "sdl")
build_dir = api.path["start_dir"].join("sdl")
api.file.ensure_directory("sdl", build_dir)
with api.context(cwd=build_dir):
cmake(
api,
cipd_dir,
src_dir,
platform,
[
"-DCMAKE_INSTALL_PREFIX=",
"-DVIDEO_WAYLAND=OFF",
"-DSDL_SHARED=OFF",
"-DSDL_STATIC_PIC=ON",
"-DGCC_ATOMICS=ON",
],
)
api.step("build", [cipd_dir.join("ninja")])
with api.context(env={"DESTDIR": pkg_dir}):
api.step("install", [cipd_dir.join("ninja"), "install"])
def build_libffi(api, cipd_dir, pkg_dir, platform, host):
src_dir = cipd_dir.join("source", "libffi")
build_dir = api.path["start_dir"].join("libffi")
api.file.ensure_directory("libffi", build_dir)
with api.context(cwd=build_dir):
configure(
api,
cipd_dir,
src_dir,
platform,
host,
[
"--disable-debug",
"--disable-dependency-tracking",
"--disable-docs",
"--disable-shared",
"--enable-static",
"--prefix=",
"--target=%s"
# config.sub used by QEMU doesn't yet recognize arm64-apple-darwin which
# is used by Clang, so replace it with aarch64-apple-darwin to make the
# script not fail.
% PLATFORM_TO_TRIPLE[platform].replace(
"arm64-apple-darwin", "aarch64-apple-darwin"
),
"--with-pic",
],
)
api.step("build", ["make", "-j%d" % api.goma.jobs])
api.step("install", ["make", "install", "DESTDIR=%s" % pkg_dir])
def build_gettext(api, cipd_dir, pkg_dir, platform, host):
# Build gettext-{runtime,tools} separately, when cross-compiling we need to
# always build `tools` for the host and the `runtime` for the target. This
# is how the PACKAGING file recommends we split them.
#
# The order of tools, runtime is important here; the tools build will
# overwrite the runtimes installation.
for package in ["gettext-tools", "gettext-runtime"]:
src_dir = cipd_dir.join("source", "gettext", package)
build_dir = api.path["start_dir"].join("gettext", package)
api.file.ensure_directory("gettext", build_dir)
with api.context(cwd=build_dir):
configure(
api,
cipd_dir,
src_dir,
platform if package == "gettext-runtime" else host,
host,
[
"--disable-curses",
"--disable-dependency-tracking",
"--disable-silent-rules",
"--disable-debug",
"--disable-shared",
"--disable-java",
"--disable-csharp",
"--disable-c++",
"--disable-openmp",
"--enable-static",
"--prefix=",
"--with-pic",
"--with-included-gettext",
"--with-included-glib",
"--with-included-libcroco",
"--with-included-libunistring",
"--without-git",
"--without-cvs",
"--without-xz",
],
ldflags=["-lm"],
)
api.step("build", ["make", "-j%d" % api.goma.jobs])
api.step("install", ["make", "install", "DESTDIR=%s" % pkg_dir])
def build_glib(api, cipd_dir, pkg_dir, platform, host):
src_dir = cipd_dir.join("source", "glib")
build_dir = api.path["start_dir"].join("glib")
api.file.ensure_directory("glib", build_dir)
extra_args = []
if platform != host:
api.file.write_text(
"cache",
build_dir.join("%s.cache" % platform),
"""
glib_cv_long_long_format=ll
glib_cv_stack_grows=no
glib_cv_uscore=no
""",
)
extra_args.append("--cache-file=%s.cache" % platform)
with api.context(cwd=src_dir, env={"NOCONFIGURE": "1"}):
api.step("autogen", [src_dir.join("autogen.sh")])
with api.context(cwd=build_dir):
configure(
api,
cipd_dir,
src_dir,
platform,
host,
[
"--disable-dependency-tracking",
"--disable-silent-rules",
"--disable-dtrace",
"--disable-libelf",
"--disable-libmount",
"--disable-shared",
"--enable-static",
"--prefix=",
"--with-pic",
"--with-pcre=internal",
]
+ extra_args,
cflags=[
"-I%s" % pkg_dir.join("include"),
"-Wno-declaration-after-statement",
"-Wno-int-conversion",
],
cxxflags=["-I%s" % pkg_dir.join("include")],
ldflags=["-L%s" % pkg_dir.join("lib")],
)
api.step("build", ["make", "-j%d" % api.goma.jobs])
api.step("install", ["make", "install", "DESTDIR=%s" % pkg_dir])
def build_qemu(api, cipd_dir, platform, host, revision, prod):
repository = "https://fuchsia.googlesource.com/third_party/qemu"
src_dir, revision = api.git_checkout(repository, revision=revision, submodules=True)
build_dir = api.path["start_dir"].join("qemu", "build")
api.file.ensure_directory("qemu/build", build_dir)
install_dir = api.path["start_dir"].join("qemu", "install")
api.file.ensure_directory("qemu/install", install_dir)
target = PLATFORM_TO_TRIPLE[platform]
sysroot = ["--sysroot=%s" % platform_sysroot(api, cipd_dir, platform)]
target = ["--target=%s" % PLATFORM_TO_TRIPLE[platform]] if platform != host else []
opt = ["-O3"]
# TODO: Enable LTO for Mac targets.
if platform.startswith("linux"):
opt.extend(["-flto", "-fwhole-program-vtables"])
extra_options = {
"linux": [
"--build=%s" % PLATFORM_TO_TRIPLE[host],
"--host=%s" % target,
"--extra-cflags=%s" % " ".join(sysroot + opt + target),
"--extra-cxxflags=%s" % " ".join(sysroot + opt + target),
# Suppress warning about the unused arguments because QEMU ignores
# --disable-werror at configure time which triggers an error because
# -static-libstdc++ is unused when linking C code.
"--extra-ldflags=%s"
% " ".join(
sysroot + target + opt + ["-static-libstdc++ -Qunused-arguments"]
),
"--disable-gtk",
"--enable-sdl",
"--enable-kvm",
],
"mac": [
"--objcc=%s" % cipd_dir.join("bin", "clang"),
"--enable-cocoa",
"--extra-cflags=%s" % " ".join(sysroot + target),
"--extra-cxxflags=%s" % " ".join(sysroot + target),
"--extra-ldflags=%s"
% " ".join(
sysroot + target + ["-nostdlib++ %s" % cipd_dir.join("lib", "libc++.a")]
),
"--enable-hvf",
],
}[platform.split("-")[0]]
if platform != host:
extra_options.append("--cross-prefix=")
# NOTE: We don't want to pass --static to configure since we still link libc
# as a shared library, but we want everything else to use static linking.
variables = {
"AR": cipd_dir.join("bin", "llvm-ar"),
"RANLIB": cipd_dir.join("bin", "llvm-ranlib"),
"NM": cipd_dir.join("bin", "llvm-nm"),
"STRIP": cipd_dir.join("bin", "llvm-strip"),
"OBJCOPY": cipd_dir.join("bin", "llvm-objcopy"),
"QEMU_PKG_CONFIG_FLAGS": "--static",
}
if platform.startswith("mac"):
variables.update(
{
# A bug in Meson treats the default linker of ld64.lld as a GNU-style linker;
# explicitly override it to use ld from the xcode installation.
"CC_LD": ld_path(api),
# TODO(joshuaseaton): Pass via --extra-objcflags once
# https://patchwork.kernel.org/project/qemu-devel/patch/20220215080307.69550-3-f4bug@amsat.org/
# is mainlined. "OBJCFLAGS" is something known by meson itself, but not the
# QEMU project.
"OBJCFLAGS": " ".join(sysroot + target),
}
)
with api.context(cwd=build_dir, env=variables):
try:
api.step(
"configure qemu",
[
src_dir.join("configure"),
"--cc=%s" % cipd_dir.join("bin", "clang"),
# See function docstring for justification and associated bug.
"--cxx=%s"
% wrap_clang(api, platform, cipd_dir.join("bin", "clang++")),
"--disable-attr",
"--disable-auth-pam",
"--disable-bochs",
"--disable-brlapi",
"--disable-bzip2",
"--disable-cap-ng",
"--disable-cloop",
"--disable-curl",
"--disable-debug-info",
"--disable-debug-tcg",
"--disable-dmg",
"--disable-docs",
"--disable-gcrypt",
"--disable-glusterfs",
"--disable-gnutls",
"--disable-guest-agent",
"--disable-iconv",
"--disable-libiscsi",
"--disable-libnfs",
"--disable-libpmem",
"--disable-libusb",
"--disable-linux-aio",
"--disable-lzo",
"--disable-nettle",
"--disable-opengl",
"--disable-parallels",
"--disable-plugins",
"--disable-qcow1",
"--disable-qed",
"--disable-qom-cast-debug",
"--disable-rbd",
"--disable-rdma",
"--disable-sdl-image",
"--disable-seccomp",
"--disable-smartcard",
"--disable-snappy",
"--disable-spice",
"--disable-tcg-interpreter",
"--disable-usb-redir",
"--disable-vdi",
"--disable-vhost-scsi",
"--disable-vhost-user",
"--disable-vhost-vsock",
"--disable-virtfs",
"--disable-vnc-jpeg",
"--disable-vnc-png",
"--disable-vnc-sasl",
"--disable-vte",
"--disable-werror",
"--disable-xen",
"--enable-fdt=git", # Build libfdt from scratch.
"--enable-slirp=git", # Use slirp built from source, not system one
"--enable-vvfat", # For EFI support.
"--meson=git", # Build meson from scratch.
"--ninja=%s" % cipd_dir.join("ninja"),
"--prefix=%s" % install_dir,
"--target-list=aarch64-softmmu,arm-softmmu,riscv64-softmmu,x86_64-softmmu",
]
+ extra_options,
)
except StepFailure: # pragma: no cover
raise
finally:
api.file.read_text(
"meson-log.txt",
build_dir.join("meson-logs", "meson-log.txt"),
test_data="The Meson build system\nVersion: 1.0.0",
)
# config-host.h is a generated header consisting of #-defines detailing
# configuration settings, including whether certain features are
# enabled. It serves as an important diagnostic.
api.file.read_text(
"config-host.h",
build_dir.join("config-host.h"),
test_data="#pragma once\n#define CONFIG_FOO\n#undef CONFIG_BAR",
)
api.step("build", ["make", "-j%d" % api.platform.cpu_count])
api.step("install", ["make", "install"])
# TODO(fxbug.dev/106763): Re-enable on Linux when passing again.
if platform == host and platform.startswith("mac"):
# V=1, DEBUG=1 for more informative test output.
api.step("run unit tests", ["make", "V=1", "DEBUG=1", "check"])
qemu_version = api.file.read_text(
"version", src_dir.join("VERSION"), test_data="2.10.1"
)
assert qemu_version, "Cannot determine QEMU version"
# Upload the installation to CAS.
digest = api.cas_util.upload(install_dir, output_property="isolated")
api.step.active_result.presentation.step_text = digest
if prod:
# Upload the installation to CIPD for production builds.
api.cipd_util.upload_package(
"fuchsia/third_party/qemu/" + platform,
install_dir,
search_tag={
"git_revision": revision + (",%s" % RECIPE_SALT if RECIPE_SALT else "")
},
repository=repository,
refs=("latest",),
)
def ld_path(api):
return api.step(
"find ld",
["xcrun", "-f", "ld"],
stdout=api.raw_io.output_text(name="ld path", add_output_log=True),
step_test_data=lambda: api.raw_io.test_api.stream_output_text(
"/some/xcode/path/usr/bin/ld"
),
).stdout.strip()
# TODO(https://github.com/mesonbuild/meson/issues/8592): Meson links against
# libstdc++ by default when using clang. We use libc++ and so need to filter
# that out.
#
# TODO(https://github.com/mesonbuild/meson/issues/6377): Meson doesn't fully
# respect the linker override above (`CC_LD`). On top of that, specifying
# of that, specifying ld through `--extra-ldflags` alone appears to be
# insufficient to specify the linker everywhere. As a result, we're forced to
# bake in the specification into a wrapper.
def wrap_clang(api, platform, clang):
default_args = []
if platform.startswith("mac"):
default_args.append("--ld-path=%s" % ld_path(api))
contents = """#!/bin/sh
args=("$@")
args=("${args[@]/-lstdc++}")
exec %s %s "${args[@]}"
""" % (
shlex.join(default_args),
clang,
)
wrapper = api.path["tmp_base"].join("clang-wrapper.sh")
api.file.write_text("write %s" % api.path.basename(wrapper), wrapper, contents)
api.step(
"make %s executable" % api.path.basename(wrapper),
["chmod", "+x", wrapper],
)
return wrapper
def GenTests(api):
revision = "75b05681239cb309a23fcb4f8864f177e5aa62da"
version = "QEMU emulator version 2.8.0 (v2.8.0-15-g28cd8b6577-dirty)"
for name, ref in {"tag": "refs/tags/v6.2.0", "branch": "refs/heads/main"}.items():
suffix = "-off-%s" % name
for platform in ["linux", "mac"]:
yield (
api.status_check.test(platform + "-amd64" + suffix)
+ api.platform.name(platform)
+ api.git.get_remote_branch_head("git ls-remote", revision)
+ api.properties(platform=platform + "-amd64", ref=ref)
+ api.step_data("qemu.version", api.raw_io.stream_output_text(version))
)
yield (
api.status_check.test("linux-arm64" + suffix)
+ api.platform.name("linux")
+ api.git.get_remote_branch_head("git ls-remote", revision)
+ api.properties(platform="linux-arm64", ref=ref)
+ api.step_data("qemu.version", api.raw_io.stream_output_text(version))
)