Bootstrap make reproducibly (#817)

* Make cc_toolchain_utils.bzl more reusable

By using getattr, the helper functions in this file can be reused in
rules that do not define all of the framework attributes, e.g. bootstrap
rules.

* Bootstrap make reproducibly on Linux and macOS

Uses the Bazel C/C++ toolchain to bootstrap make and ensure that the
resulting binary contains no absolute and thus non-hermetic paths.

Building make reproducibly helps with remote caching and removes the
dependency on a C compiler installed on the host.
This commit is contained in:
Fabian Meumertzheim 2021-11-30 16:58:53 +01:00 committed by GitHub
parent a2f1e5d8c3
commit 0cf751c053
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 81 additions and 5 deletions

View File

@ -8,6 +8,13 @@ load(
"FOREIGN_CC_BUILT_TOOLS_HOST_FRAGMENTS", "FOREIGN_CC_BUILT_TOOLS_HOST_FRAGMENTS",
"built_tool_rule_impl", "built_tool_rule_impl",
) )
load(
"//foreign_cc/private:cc_toolchain_util.bzl",
"absolutize_path_in_str",
"get_env_vars",
"get_flags_info",
"get_tools_info",
)
load("//foreign_cc/private/framework:platform.bzl", "os_name") load("//foreign_cc/private/framework:platform.bzl", "os_name")
def _make_tool_impl(ctx): def _make_tool_impl(ctx):
@ -29,8 +36,54 @@ def _make_tool_impl(ctx):
"cp -p ./{}/gnumake.exe $$INSTALLDIR$$/bin/make.exe".format(dist_dir), "cp -p ./{}/gnumake.exe $$INSTALLDIR$$/bin/make.exe".format(dist_dir),
] ]
else: else:
env = get_env_vars(ctx)
flags_info = get_flags_info(ctx)
tools_info = get_tools_info(ctx)
ar_path = tools_info.cxx_linker_static
frozen_arflags = flags_info.cxx_linker_static
cc_path = tools_info.cc
cflags = flags_info.cc
sysroot_cflags = [flag for flag in cflags if flag.startswith("--sysroot=")]
non_sysroot_cflags = [flag for flag in cflags if not flag.startswith("--sysroot=")]
ld_path = tools_info.cxx_linker_executable
ldflags = flags_info.cxx_linker_executable
sysroot_ldflags = [flag for flag in ldflags if flag.startswith("--sysroot=")]
non_sysroot_ldflags = [flag for flag in ldflags if not flag.startswith("--sysroot=")]
# Make's build script does not forward CFLAGS to all compiler and linker
# invocations, so we append --sysroot flags directly to CC and LD.
absolute_cc = _absolutize(ctx.workspace_name, cc_path, True)
if sysroot_cflags:
absolute_cc += " " + _join_flags_list(ctx.workspace_name, sysroot_cflags)
absolute_ld = _absolutize(ctx.workspace_name, ld_path, True)
if sysroot_ldflags:
absolute_ld += " " + _join_flags_list(ctx.workspace_name, sysroot_ldflags)
# If libtool is used as AR, the output file has to be prefixed with
# "-o". Since the make Makefile only uses ar-style invocations, the
# output file always comes first and we can append this argument to the
# flags list.
absolute_ar = _absolutize(ctx.workspace_name, ar_path, True)
arflags = [e for e in frozen_arflags]
if absolute_ar == "libtool" or absolute_ar.endswith("/libtool"):
arflags.append("-o")
env.update({
"AR": absolute_ar,
"ARFLAGS": _join_flags_list(ctx.workspace_name, arflags),
"CC": absolute_cc,
"CFLAGS": _join_flags_list(ctx.workspace_name, non_sysroot_cflags),
"LD": absolute_ld,
"LDFLAGS": _join_flags_list(ctx.workspace_name, non_sysroot_ldflags),
})
configure_env = " ".join(["%s=\"%s\"" % (key, value) for key, value in env.items()])
script = [ script = [
"./configure --without-guile --with-guile=no --disable-dependency-tracking --prefix=$$INSTALLDIR$$", "%s ./configure --without-guile --with-guile=no --disable-dependency-tracking --prefix=$$INSTALLDIR$$" % configure_env,
"cat build.cfg",
"./build.sh", "./build.sh",
"./make install", "./make install",
] ]
@ -54,3 +107,9 @@ make_tool = rule(
"@bazel_tools//tools/cpp:toolchain_type", "@bazel_tools//tools/cpp:toolchain_type",
], ],
) )
def _absolutize(workspace_name, text, force = False):
return absolutize_path_in_str(workspace_name, "$$EXT_BUILD_ROOT$$/", text, force)
def _join_flags_list(workspace_name, flags):
return " ".join([_absolutize(workspace_name, flag) for flag in flags])

View File

@ -118,7 +118,7 @@ def _files_map(files_list):
return by_names_map return by_names_map
def _defines_from_deps(ctx): def _defines_from_deps(ctx):
return depset(transitive = [dep[CcInfo].compilation_context.defines for dep in ctx.attr.deps]) return depset(transitive = [dep[CcInfo].compilation_context.defines for dep in getattr(ctx.attr, "deps", [])])
def _build_cc_link_params( def _build_cc_link_params(
ctx, ctx,
@ -301,9 +301,9 @@ def get_flags_info(ctx, link_output_file = None):
cc_toolchain = cc_toolchain_, cc_toolchain = cc_toolchain_,
) )
copts = (ctx.fragments.cpp.copts + ctx.fragments.cpp.conlyopts + ctx.attr.copts) or [] copts = (ctx.fragments.cpp.copts + ctx.fragments.cpp.conlyopts + getattr(ctx.attr, "copts", [])) or []
cxxopts = (ctx.fragments.cpp.copts + ctx.fragments.cpp.cxxopts + ctx.attr.copts) or [] cxxopts = (ctx.fragments.cpp.copts + ctx.fragments.cpp.cxxopts + getattr(ctx.attr, "copts", [])) or []
linkopts = (ctx.fragments.cpp.linkopts + ctx.attr.linkopts) or [] linkopts = (ctx.fragments.cpp.linkopts + getattr(ctx.attr, "linkopts", [])) or []
defines = _defines_from_deps(ctx) defines = _defines_from_deps(ctx)
flags = CxxFlagsInfo( flags = CxxFlagsInfo(

View File

@ -412,6 +412,7 @@ def _make_toolchain(version):
http_archive, http_archive,
name = "gnumake_src", name = "gnumake_src",
build_file_content = _ALL_CONTENT, build_file_content = _ALL_CONTENT,
patches = ["@rules_foreign_cc//toolchains:make-reproducible-bootstrap.patch"],
sha256 = "e05fdde47c5f7ca45cb697e973894ff4f5d79e13b750ed57d7b66d8defc78e19", sha256 = "e05fdde47c5f7ca45cb697e973894ff4f5d79e13b750ed57d7b66d8defc78e19",
strip_prefix = "make-4.3", strip_prefix = "make-4.3",
urls = [ urls = [

View File

@ -0,0 +1,16 @@
diff --git Makefile.in Makefile.in
index 9535058..0b12e99 100644
--- Makefile.in
+++ Makefile.in
@@ -1042,8 +1042,8 @@ make_LDADD = $(LIBOBJS) $(GUILE_LIBS) lib/libgnu.a $(GETLOADAVG_LIBS) \
@LIBINTL@
AM_CPPFLAGS = -Isrc -I$(top_srcdir)/src -Ilib -I$(top_srcdir)/lib \
- -DLIBDIR=\"$(libdir)\" -DINCLUDEDIR=\"$(includedir)\" \
- -DLOCALEDIR=\"$(localedir)\" $(am__append_2)
+ -DLIBDIR=\".\" -DINCLUDEDIR=\"external/rules_foreign_cc/toolchains/make/include\" \
+ -DLOCALEDIR=\"external/rules_foreign_cc/toolchains/make/share/locale\" $(am__append_2)
AM_CFLAGS = $(GUILE_CFLAGS)
# Extra stuff to include in the distribution.