| # 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 |
| |
| DEPS = [ |
| "fuchsia/buildbucket_util", |
| "fuchsia/cas_util", |
| "fuchsia/cipd_util", |
| "fuchsia/macos_sdk", |
| "recipe_engine/buildbucket", |
| "recipe_engine/cipd", |
| "recipe_engine/context", |
| "recipe_engine/file", |
| "recipe_engine/path", |
| "recipe_engine/platform", |
| "recipe_engine/step", |
| ] |
| |
| |
| def RunSteps(api): |
| with api.step.nest("ensure packages"): |
| with api.context(infra_steps=True): |
| cipd_dir = api.path.start_dir / "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", |
| "integration", |
| "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"], |
| cflags=["-Wno-incompatible-function-pointer-types"], |
| ), |
| 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=", |
| ], |
| cflags=["-Wno-int-conversion"], |
| 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", |
| ], |
| cflags=["-Wno-incompatible-function-pointer-types"], |
| ), |
| Package( |
| name="flex", |
| version="2.6.4", |
| options=[ |
| "--disable-dependency-tracking", |
| "--disable-shared", |
| "--disable-bootstrap", |
| "--disable-rpath", |
| "--disable-nls", |
| ], |
| ), |
| Package( |
| name="texinfo", |
| version="6.8.0", |
| patches=[api.resource("0001-Attempt-to-make-texi2any-relocatable.patch")], |
| options=[ |
| "--disable-dependency-tracking", |
| "--disable-rpath", |
| "--disable-nls", |
| "--disable-perl-xs", |
| "--disable-perl-api-texi-build", |
| ], |
| ), |
| Package( |
| name="dejagnu", |
| version="1.6.2", |
| options=[ |
| "--disable-dependency-tracking", |
| "--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 / "sysroot", |
| "PKG_CONFIG_ALLOW_SYSTEM_CFLAGS": 1, |
| "PKG_CONFIG_ALLOW_SYSTEM_LIBS": 1, |
| "PKG_CONFIG_LIBDIR": ":".join( |
| flatten( |
| [ |
| [ |
| str(d / "lib" / "pkgconfig"), |
| str(d / "share" / "pkgconfig"), |
| ] |
| for d in pkg_dirs |
| ] |
| ) |
| ), |
| }, |
| env_prefixes={"PATH": [d / "bin" for d in pkg_dirs]}, |
| ): |
| install_dir = build( |
| api, |
| package.name, |
| package.version, |
| cipd_dir, |
| package.patches, |
| package.options, |
| package.cflags, |
| package.cxxflags, |
| package.ldflags, |
| ) |
| pkg_dirs.append(install_dir) |
| |
| |
| def sysroot(api, cipd_dir): |
| if api.platform.is_linux: |
| return cipd_dir / "sysroot" |
| elif api.platform.is_mac: # pragma: no cover |
| # TODO(fxbug.dev/3043): Eventually use our own hermetic sysroot as for Linux. |
| return api.macos_sdk.sysroot |
| raise api.step.StepFailure("unsupported platform") # pragma: no cover |
| |
| |
| def build( |
| api, |
| name, |
| version, |
| cipd_dir, |
| patches=(), |
| options=(), |
| cflags=(), |
| cxxflags=(), |
| ldflags=(), |
| ): |
| work_dir = api.path.start_dir / name |
| |
| with api.context(infra_steps=True): |
| src_dir = work_dir / "source" |
| pkgs = api.cipd.EnsureFile() |
| pkgs.add_package(f"fuchsia/third_party/source/{name}", f"version:{version}") |
| api.cipd.ensure(src_dir, pkgs) |
| |
| build_dir = work_dir / "build" |
| install_dir = work_dir / "install" |
| |
| api.file.ensure_directory("create build dir", build_dir) |
| with api.context(cwd=build_dir): |
| flags = [f"--sysroot={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.joinpath("bin", "clang"), |
| "CXX": cipd_dir.joinpath("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.joinpath("bin", "llvm-ar"), |
| "RANLIB": cipd_dir.joinpath("bin", "llvm-ranlib"), |
| "NM": cipd_dir.joinpath("bin", "llvm-nm"), |
| "STRIP": cipd_dir.joinpath("bin", "llvm-strip"), |
| "OBJCOPY": cipd_dir.joinpath("bin", "llvm-objcopy"), |
| } |
| ) |
| for patch in patches: |
| api.step( |
| f"apply {api.path.basename(patch)}", |
| ["patch", "-d", src_dir, "-i", patch, "-p1"], |
| ) |
| api.step( |
| "configure", |
| [src_dir / "configure", "--prefix=", "--disable-silent-rules"] |
| + list(options) |
| + sorted([f"{k}={v}" for k, v in variables.items()]), |
| ) |
| api.step( |
| "make", |
| ["make", f"-j{int(api.platform.cpu_count)}"], |
| ) |
| # TODO: run `make check` |
| api.step( |
| "make install", |
| ["make", "install", f"DESTDIR={install_dir}"], |
| ) |
| |
| api.cas_util.upload(install_dir, output_property="isolated") |
| if api.buildbucket.build.builder.bucket == "prod": |
| api.cipd_util.upload_package( |
| f"fuchsia/third_party/{name}/{api.cipd_util.platform_name}", |
| install_dir, |
| search_tag={"version": version}, |
| ) |
| |
| return install_dir |
| |
| |
| def GenTests(api): |
| yield api.buildbucket_util.test("ci") |
| yield api.buildbucket_util.test("prod", bucket="prod") + api.platform.name("mac") |