| # Copyright 2020 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 tools that use GNU build system.""" |
| |
| from collections import namedtuple |
| |
| from recipe_engine.config import Enum, ReturnSchema, Single |
| from recipe_engine.recipe_api import Property |
| |
| |
| DEPS = [ |
| "fuchsia/macos_sdk", |
| "fuchsia/upload", |
| "recipe_engine/buildbucket", |
| "recipe_engine/cipd", |
| "recipe_engine/context", |
| "recipe_engine/file", |
| "recipe_engine/path", |
| "recipe_engine/platform", |
| "recipe_engine/raw_io", |
| "recipe_engine/step", |
| ] |
| |
| |
| def sysroot(api, cipd_dir): |
| if api.platform.is_linux: |
| return cipd_dir.join("sysroot") |
| elif api.platform.is_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(name="sdk-path", add_output_log=True), |
| step_test_data=lambda: api.raw_io.test_api.stream_output( |
| "/some/xcode/path" |
| ), |
| ) |
| return step_result.stdout.strip() |
| raise api.step.StepFailure("unsupported platform") # pragma: no cover |
| |
| |
| def build( |
| api, |
| name, |
| version, |
| cipd_dir, |
| platform, |
| patches=(), |
| options=(), |
| cflags=(), |
| cxxflags=(), |
| ldflags=(), |
| ): |
| work_dir = api.path["start_dir"].join(name) |
| |
| with api.context(infra_steps=True): |
| src_dir = work_dir.join("source") |
| pkgs = api.cipd.EnsureFile() |
| pkgs.add_package("fuchsia/third_party/source/%s" % name, "version:%s" % version) |
| api.cipd.ensure(src_dir, pkgs) |
| |
| build_dir = work_dir.join("build") |
| install_dir = work_dir.join("install") |
| |
| api.file.ensure_directory("create build dir", build_dir) |
| with api.context(cwd=build_dir): |
| flags = ["--sysroot=%s" % sysroot(api, cipd_dir), "-O3"] |
| if not api.platform.is_mac: |
| # TODO: LTO is currently failing on macOS |
| flags.append("-flto") |
| variables = { |
| "CC": cipd_dir.join("bin", "clang"), |
| "CXX": cipd_dir.join("bin", "clang++"), |
| "CFLAGS": " ".join(flags + list(cflags)), |
| "CPPFLAGS": " ".join(flags + list(cflags)), |
| "CXXFLAGS": " ".join(flags + list(cxxflags)), |
| "LDFLAGS": " ".join(flags + list(ldflags)), |
| } |
| if api.platform.is_linux: |
| variables.update( |
| { |
| "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"), |
| } |
| ) |
| for patch in patches: |
| api.step( |
| "apply %s" % api.path.basename(patch), |
| ["patch", "-d", src_dir, "-i", patch, "-p1"], |
| ) |
| api.step( |
| "configure", |
| [src_dir.join("configure"), "--prefix=", "--disable-silent-rules"] |
| + list(options) |
| + sorted(["%s=%s" % (k, v) for k, v in variables.iteritems()]), |
| ) |
| api.step( |
| "make", ["make", "-j%d" % api.platform.cpu_count], |
| ) |
| # TODO: run `make check` |
| api.step( |
| "make install", ["make", "install", "DESTDIR=%s" % install_dir], |
| ) |
| |
| if api.buildbucket.builder_id.bucket == "ci": |
| isolated = api.upload.upload_isolated(install_dir) |
| if api.buildbucket.builder_id.bucket == "prod": |
| api.upload.cipd_package( |
| "fuchsia/third_party/%s/%s" % (name, platform), |
| install_dir, |
| [api.upload.DirectoryPath(install_dir)], |
| {"version": version}, |
| ) |
| |
| return install_dir |
| |
| |
| def RunSteps(api): |
| # TODO: factor this out into a host_build recipe module. |
| platform = "%s-%s" % ( |
| api.platform.name.replace("win", "windows"), |
| {"intel": {32: "386", 64: "amd64",}, "arm": {32: "armv6", 64: "arm64",},}[ |
| api.platform.arch |
| ][api.platform.bits], |
| ) |
| |
| 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("fuchsia/third_party/clang/${platform}", "integration") |
| if api.platform.is_linux: |
| # TODO: factor this out into a linux_sdk recipe |
| pkgs.add_package( |
| "fuchsia/third_party/sysroot/linux", |
| "git_revision:c912d089c3d46d8982fdef76a50514cca79b6132", |
| "sysroot", |
| ) |
| api.cipd.ensure(cipd_dir, pkgs) |
| |
| Package = namedtuple( |
| "Package", |
| ["name", "version", "patches", "options", "cflags", "cxxflags", "ldflags"], |
| ) |
| Package.__new__.__defaults__ = (None, None, [], [], [], [], []) |
| |
| # NOTE: packages are ordered in the order of dependencies. |
| packages = [ |
| Package( |
| name="make", version="4.3", options=["--disable-dependency-tracking",], |
| ), |
| Package( |
| name="m4", version="1.4.18", options=["--disable-dependency-tracking",], |
| ), |
| Package( |
| name="autoconf", |
| version="2.69", |
| patches=[api.resource("0001-Make-autoconf-relocatable.patch")], |
| ), |
| Package( |
| name="automake", |
| version="1.16.2", |
| patches=[api.resource("0001-Make-automake-relocatable.patch")], |
| ), |
| Package(name="help2man", version="1.47.16",), |
| Package( |
| name="libtool", |
| version="2.4.6", |
| patches=[api.resource("0001-Make-libtool-relocatable.patch")], |
| options=[ |
| "--disable-dependency-tracking", |
| "--disable-shared", |
| "--enable-ltdl-install", |
| "--enable-static", |
| ], |
| ), |
| Package( |
| name="pkg-config", |
| version="0.29.2", |
| options=[ |
| "--disable-debug", |
| "--disable-host-tool", |
| "--disable-shared", |
| "--enable-static", |
| "--with-internal-glib", |
| "--with-pc-path=", |
| "--with-system-include-path=", |
| "--with-system-library-path=", |
| ], |
| ldflags=["-framework CoreFoundation", "-framework CoreServices"] |
| if api.platform.is_mac |
| else [], |
| ), |
| Package( |
| name="bison", |
| version="3.7", |
| options=[ |
| "--disable-dependency-tracking", |
| "--enable-relocatable", |
| "--disable-rpath", |
| "--disable-nls", |
| ], |
| ), |
| Package( |
| name="flex", |
| version="2.6.4", |
| options=[ |
| "--disable-dependency-tracking", |
| "--disable-shared", |
| "--disable-bootstrap", |
| "--disable-rpath", |
| "--disable-nls", |
| ], |
| ), |
| ] |
| |
| flatten = lambda l: [item for sublist in l for item in sublist] |
| |
| with api.macos_sdk(): |
| # TODO: to avoid full dependency tracking for now, we order the package |
| # in the order in which they depend on each other, and we ensure that |
| # each package can depend on all packages built before. |
| pkg_dirs = [] |
| for package in packages: |
| with api.step.nest(package.name), api.context( |
| # Every package has access to all packages built before it. |
| env={ |
| "PKG_CONFIG_PATH": "", |
| "PKG_CONFIG_SYSROOT_DIR": cipd_dir.join("sysroot"), |
| "PKG_CONFIG_ALLOW_SYSTEM_CFLAGS": 1, |
| "PKG_CONFIG_ALLOW_SYSTEM_LIBS": 1, |
| "PKG_CONFIG_LIBDIR": ":".join( |
| flatten( |
| [ |
| [ |
| str(d.join("lib", "pkgconfig")), |
| str(d.join("share", "pkgconfig")), |
| ] |
| for d in pkg_dirs |
| ] |
| ) |
| ), |
| }, |
| env_prefixes={"PATH": [d.join("bin") for d in pkg_dirs]}, |
| ): |
| install_dir = build( |
| api, |
| package.name, |
| package.version, |
| cipd_dir, |
| platform, |
| package.patches, |
| package.options, |
| package.cflags, |
| package.cxxflags, |
| package.ldflags, |
| ) |
| pkg_dirs.append(install_dir) |
| |
| |
| def GenTests(api): |
| yield api.test("ci") + api.buildbucket.ci_build( |
| project="fuchsia", bucket="ci", |
| ) + api.platform.name("linux") |
| yield api.test("prod") + api.buildbucket.ci_build( |
| project="fuchsia", bucket="prod", |
| ) + api.platform.name("mac") |