git: 69cfdc81ea7b - main - tools/build/make.py: Keep bootstrapped bmake binary up-to-date

From: Jessica Clarke <jrtc27_at_FreeBSD.org>
Date: Wed, 23 Aug 2023 17:01:25 UTC
The branch main has been updated by jrtc27:

URL: https://cgit.FreeBSD.org/src/commit/?id=69cfdc81ea7bdfe1e7300a7e1106419156aee434

commit 69cfdc81ea7bdfe1e7300a7e1106419156aee434
Author:     Jessica Clarke <jrtc27@FreeBSD.org>
AuthorDate: 2023-08-23 16:56:50 +0000
Commit:     Jessica Clarke <jrtc27@FreeBSD.org>
CommitDate: 2023-08-23 16:56:50 +0000

    tools/build/make.py: Keep bootstrapped bmake binary up-to-date
    
    We currently assume that any existing bootstrapped bmake binary will
    work, but this means it never gets updated as contrib/bmake is, and
    similarly we won't rebuild it as and when the configure arguments given
    to boot-strap change. Whilst the former isn't necessarily a huge problem
    given WANT_MAKE_VERSION rarely gets bumped in Makefile, having fewer
    variables is a good thing, and so it's easiest if we just always keep it
    up-to-date rather than trying to do something similar to what's already
    in Makefile (which may or may not be accurate, given updating FreeBSD
    gives you an updated bmake, but nothing does so for our bootstrapped
    bmake on non-FreeBSD). The latter is more problematic, though, and the
    next commit will be changing this configuration.
    
    We thus now add in two checks. The first is to compare MAKE_VERSION
    against _MAKE_VERSION from contrib/bmake/VERSION. The second is to
    record at bootstrap time the exact configuration used, and compare that
    against what we would bootstrap with.
    
    Reviewed by:    arichardson, sjg
    Differential Revision:  https://reviews.freebsd.org/D41556
---
 tools/build/make.py | 58 ++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 49 insertions(+), 9 deletions(-)

diff --git a/tools/build/make.py b/tools/build/make.py
index 74454aa51b08..e25922c9a70d 100755
--- a/tools/build/make.py
+++ b/tools/build/make.py
@@ -72,31 +72,71 @@ def run(cmd, **kwargs):
     subprocess.check_call(cmd, **kwargs)
 
 
+# Always bootstraps in order to control bmake's config to ensure compatibility
 def bootstrap_bmake(source_root, objdir_prefix):
     bmake_source_dir = source_root / "contrib/bmake"
     bmake_build_dir = objdir_prefix / "bmake-build"
     bmake_install_dir = objdir_prefix / "bmake-install"
     bmake_binary = bmake_install_dir / "bin/bmake"
+    bmake_config = bmake_install_dir / ".make-py-config"
 
-    if (bmake_install_dir / "bin/bmake").exists():
+    bmake_source_version = subprocess.run([
+        "sh", "-c", ". \"$0\"/VERSION; echo $_MAKE_VERSION",
+        bmake_source_dir], capture_output=True).stdout.strip()
+    try:
+        bmake_source_version = int(bmake_source_version)
+    except ValueError:
+        sys.exit("Invalid source bmake version '" + bmake_source_version + "'")
+
+    bmake_installed_version = 0
+    if bmake_binary.exists():
+        bmake_installed_version = subprocess.run([
+            bmake_binary, "-r", "-f", "/dev/null", "-V", "MAKE_VERSION"],
+            capture_output=True).stdout.strip()
+        try:
+            bmake_installed_version = int(bmake_installed_version.strip())
+        except ValueError:
+            print("Invalid installed bmake version '" +
+                  bmake_installed_version + "', treating as not present")
+
+    configure_args = [
+        "--with-default-sys-path=" + str(bmake_install_dir / "share/mk"),
+        "--with-machine=amd64",  # TODO? "--with-machine-arch=amd64",
+        "--without-filemon", "--prefix=" + str(bmake_install_dir)]
+
+    configure_args_str = ' '.join([shlex.quote(x) for x in configure_args])
+    if bmake_config.exists():
+        last_configure_args_str = bmake_config.read_text()
+    else:
+        last_configure_args_str = ""
+
+    debug("Source bmake version: " + str(bmake_source_version))
+    debug("Installed bmake version: " + str(bmake_installed_version))
+    debug("Configure args: " + configure_args_str)
+    debug("Last configure args: " + last_configure_args_str)
+
+    if bmake_installed_version == bmake_source_version and \
+       configure_args_str == last_configure_args_str:
         return bmake_binary
+
     print("Bootstrapping bmake...")
-    # TODO: check if the host system bmake is new enough and use that instead
-    if not bmake_build_dir.exists():
-        os.makedirs(str(bmake_build_dir))
+    if bmake_build_dir.exists():
+        shutil.rmtree(str(bmake_build_dir))
+    if bmake_install_dir.exists():
+        shutil.rmtree(str(bmake_install_dir))
+
+    os.makedirs(str(bmake_build_dir))
+
     env = os.environ.copy()
     global new_env_vars
     env.update(new_env_vars)
 
-    configure_args = [
-        "--with-default-sys-path=" + str(bmake_install_dir / "share/mk"),
-        "--with-machine=amd64",  # TODO? "--with-machine-arch=amd64",
-        "--without-filemon", "--prefix=" + str(bmake_install_dir)]
     run(["sh", bmake_source_dir / "boot-strap"] + configure_args,
         cwd=str(bmake_build_dir), env=env)
-
     run(["sh", bmake_source_dir / "boot-strap", "op=install"] + configure_args,
         cwd=str(bmake_build_dir))
+    bmake_config.write_text(configure_args_str)
+
     print("Finished bootstrapping bmake...")
     return bmake_binary