1af6a4c17SAlex Richardson#!/usr/bin/env python3 2af6a4c17SAlex Richardson# PYTHON_ARGCOMPLETE_OKAY 3af6a4c17SAlex Richardson# - 44d846d26SWarner Losh# SPDX-License-Identifier: BSD-2-Clause 5af6a4c17SAlex Richardson# 6af6a4c17SAlex Richardson# Copyright (c) 2018 Alex Richardson <arichardson@FreeBSD.org> 7af6a4c17SAlex Richardson# 8af6a4c17SAlex Richardson# Redistribution and use in source and binary forms, with or without 9af6a4c17SAlex Richardson# modification, are permitted provided that the following conditions 10af6a4c17SAlex Richardson# are met: 11af6a4c17SAlex Richardson# 1. Redistributions of source code must retain the above copyright 12af6a4c17SAlex Richardson# notice, this list of conditions and the following disclaimer. 13af6a4c17SAlex Richardson# 2. Redistributions in binary form must reproduce the above copyright 14af6a4c17SAlex Richardson# notice, this list of conditions and the following disclaimer in the 15af6a4c17SAlex Richardson# documentation and/or other materials provided with the distribution. 16af6a4c17SAlex Richardson# 17af6a4c17SAlex Richardson# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18af6a4c17SAlex Richardson# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19af6a4c17SAlex Richardson# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20af6a4c17SAlex Richardson# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21af6a4c17SAlex Richardson# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22af6a4c17SAlex Richardson# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23af6a4c17SAlex Richardson# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24af6a4c17SAlex Richardson# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25af6a4c17SAlex Richardson# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26af6a4c17SAlex Richardson# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27af6a4c17SAlex Richardson# SUCH DAMAGE. 28af6a4c17SAlex Richardson# 29af6a4c17SAlex Richardson# 30af6a4c17SAlex Richardson 31af6a4c17SAlex Richardson# This script makes it easier to build on non-FreeBSD systems by bootstrapping 32af6a4c17SAlex Richardson# bmake and inferring required compiler variables. 33af6a4c17SAlex Richardson# 34af6a4c17SAlex Richardson# On FreeBSD you can use it the same way as just calling make: 35af6a4c17SAlex Richardson# `MAKEOBJDIRPREFIX=~/obj ./tools/build/make.py buildworld -DWITH_FOO` 36af6a4c17SAlex Richardson# 37af6a4c17SAlex Richardson# On Linux and MacOS you will either need to set XCC/XCXX/XLD/XCPP or pass 38af6a4c17SAlex Richardson# --cross-bindir to specify the path to the cross-compiler bindir: 39af6a4c17SAlex Richardson# `MAKEOBJDIRPREFIX=~/obj ./tools/build/make.py 40af6a4c17SAlex Richardson# --cross-bindir=/path/to/cross/compiler buildworld -DWITH_FOO TARGET=foo 41af6a4c17SAlex Richardson# TARGET_ARCH=bar` 42af6a4c17SAlex Richardsonimport argparse 43af6a4c17SAlex Richardsonimport os 44af6a4c17SAlex Richardsonimport shlex 45af6a4c17SAlex Richardsonimport shutil 46af6a4c17SAlex Richardsonimport subprocess 47af6a4c17SAlex Richardsonimport sys 48af6a4c17SAlex Richardsonfrom pathlib import Path 49af6a4c17SAlex Richardson 50af6a4c17SAlex Richardson 515157b451SJessica Clarke# List of targets that are independent of TARGET/TARGET_ARCH and thus do not 525157b451SJessica Clarke# need them to be set. Keep in the same order as Makefile documents them (if 535157b451SJessica Clarke# they are documented). 545157b451SJessica Clarkemach_indep_targets = [ 555157b451SJessica Clarke "cleanuniverse", 565157b451SJessica Clarke "universe", 575157b451SJessica Clarke "universe-toolchain", 58edec803cSJessica Clarke "tinderbox", 595157b451SJessica Clarke "worlds", 605157b451SJessica Clarke "kernels", 615157b451SJessica Clarke "kernel-toolchains", 625157b451SJessica Clarke "targets", 635157b451SJessica Clarke "toolchains", 645157b451SJessica Clarke "makeman", 655157b451SJessica Clarke "sysent", 665157b451SJessica Clarke] 675157b451SJessica Clarke 685157b451SJessica Clarke 69af6a4c17SAlex Richardsondef run(cmd, **kwargs): 70af6a4c17SAlex Richardson cmd = list(map(str, cmd)) # convert all Path objects to str 71af6a4c17SAlex Richardson debug("Running", cmd) 72af6a4c17SAlex Richardson subprocess.check_call(cmd, **kwargs) 73af6a4c17SAlex Richardson 74af6a4c17SAlex Richardson 7569cfdc81SJessica Clarke# Always bootstraps in order to control bmake's config to ensure compatibility 76af6a4c17SAlex Richardsondef bootstrap_bmake(source_root, objdir_prefix): 77af6a4c17SAlex Richardson bmake_source_dir = source_root / "contrib/bmake" 78af6a4c17SAlex Richardson bmake_build_dir = objdir_prefix / "bmake-build" 79af6a4c17SAlex Richardson bmake_install_dir = objdir_prefix / "bmake-install" 80af6a4c17SAlex Richardson bmake_binary = bmake_install_dir / "bin/bmake" 8169cfdc81SJessica Clarke bmake_config = bmake_install_dir / ".make-py-config" 82af6a4c17SAlex Richardson 8369cfdc81SJessica Clarke bmake_source_version = subprocess.run([ 84b771d570SJessica Clarke "sh", "-c", ". \"$0\"/VERSION; echo $_MAKE_VERSION", bmake_source_dir], 85b771d570SJessica Clarke stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.strip() 8669cfdc81SJessica Clarke try: 8769cfdc81SJessica Clarke bmake_source_version = int(bmake_source_version) 8869cfdc81SJessica Clarke except ValueError: 8969cfdc81SJessica Clarke sys.exit("Invalid source bmake version '" + bmake_source_version + "'") 9069cfdc81SJessica Clarke 9169cfdc81SJessica Clarke bmake_installed_version = 0 9269cfdc81SJessica Clarke if bmake_binary.exists(): 9369cfdc81SJessica Clarke bmake_installed_version = subprocess.run([ 9469cfdc81SJessica Clarke bmake_binary, "-r", "-f", "/dev/null", "-V", "MAKE_VERSION"], 95b771d570SJessica Clarke stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.strip() 9669cfdc81SJessica Clarke try: 9769cfdc81SJessica Clarke bmake_installed_version = int(bmake_installed_version.strip()) 9869cfdc81SJessica Clarke except ValueError: 9969cfdc81SJessica Clarke print("Invalid installed bmake version '" + 10069cfdc81SJessica Clarke bmake_installed_version + "', treating as not present") 101af6a4c17SAlex Richardson 102af6a4c17SAlex Richardson configure_args = [ 10362f243acSJessica Clarke "--with-default-sys-path=.../share/mk:" + 10462f243acSJessica Clarke str(bmake_install_dir / "share/mk"), 105af6a4c17SAlex Richardson "--with-machine=amd64", # TODO? "--with-machine-arch=amd64", 106af6a4c17SAlex Richardson "--without-filemon", "--prefix=" + str(bmake_install_dir)] 10769cfdc81SJessica Clarke 10869cfdc81SJessica Clarke configure_args_str = ' '.join([shlex.quote(x) for x in configure_args]) 10969cfdc81SJessica Clarke if bmake_config.exists(): 11069cfdc81SJessica Clarke last_configure_args_str = bmake_config.read_text() 11169cfdc81SJessica Clarke else: 11269cfdc81SJessica Clarke last_configure_args_str = "" 11369cfdc81SJessica Clarke 11469cfdc81SJessica Clarke debug("Source bmake version: " + str(bmake_source_version)) 11569cfdc81SJessica Clarke debug("Installed bmake version: " + str(bmake_installed_version)) 11669cfdc81SJessica Clarke debug("Configure args: " + configure_args_str) 11769cfdc81SJessica Clarke debug("Last configure args: " + last_configure_args_str) 11869cfdc81SJessica Clarke 11969cfdc81SJessica Clarke if bmake_installed_version == bmake_source_version and \ 12069cfdc81SJessica Clarke configure_args_str == last_configure_args_str: 12169cfdc81SJessica Clarke return bmake_binary 12269cfdc81SJessica Clarke 12369cfdc81SJessica Clarke print("Bootstrapping bmake...") 12469cfdc81SJessica Clarke if bmake_build_dir.exists(): 12569cfdc81SJessica Clarke shutil.rmtree(str(bmake_build_dir)) 12669cfdc81SJessica Clarke if bmake_install_dir.exists(): 12769cfdc81SJessica Clarke shutil.rmtree(str(bmake_install_dir)) 12869cfdc81SJessica Clarke 12969cfdc81SJessica Clarke os.makedirs(str(bmake_build_dir)) 13069cfdc81SJessica Clarke 13169cfdc81SJessica Clarke env = os.environ.copy() 13269cfdc81SJessica Clarke global new_env_vars 13369cfdc81SJessica Clarke env.update(new_env_vars) 13469cfdc81SJessica Clarke 135af6a4c17SAlex Richardson run(["sh", bmake_source_dir / "boot-strap"] + configure_args, 136af6a4c17SAlex Richardson cwd=str(bmake_build_dir), env=env) 137af6a4c17SAlex Richardson run(["sh", bmake_source_dir / "boot-strap", "op=install"] + configure_args, 138af6a4c17SAlex Richardson cwd=str(bmake_build_dir)) 13969cfdc81SJessica Clarke bmake_config.write_text(configure_args_str) 14069cfdc81SJessica Clarke 141af6a4c17SAlex Richardson print("Finished bootstrapping bmake...") 142af6a4c17SAlex Richardson return bmake_binary 143af6a4c17SAlex Richardson 144af6a4c17SAlex Richardson 145af6a4c17SAlex Richardsondef debug(*args, **kwargs): 146af6a4c17SAlex Richardson global parsed_args 147af6a4c17SAlex Richardson if parsed_args.debug: 148af6a4c17SAlex Richardson print(*args, **kwargs) 149af6a4c17SAlex Richardson 150af6a4c17SAlex Richardson 151af6a4c17SAlex Richardsondef is_make_var_set(var): 152af6a4c17SAlex Richardson return any( 153af6a4c17SAlex Richardson x.startswith(var + "=") or x == ("-D" + var) for x in sys.argv[1:]) 154af6a4c17SAlex Richardson 155af6a4c17SAlex Richardson 156af6a4c17SAlex Richardsondef check_required_make_env_var(varname, binary_name, bindir): 157af6a4c17SAlex Richardson global new_env_vars 158af6a4c17SAlex Richardson if os.getenv(varname): 159af6a4c17SAlex Richardson return 160af6a4c17SAlex Richardson if not bindir: 161af6a4c17SAlex Richardson sys.exit("Could not infer value for $" + varname + ". Either set $" + 162af6a4c17SAlex Richardson varname + " or pass --cross-bindir=/cross/compiler/dir/bin") 163af6a4c17SAlex Richardson # try to infer the path to the tool 164af6a4c17SAlex Richardson guess = os.path.join(bindir, binary_name) 165af6a4c17SAlex Richardson if not os.path.isfile(guess): 166af6a4c17SAlex Richardson sys.exit("Could not infer value for $" + varname + ": " + guess + 167af6a4c17SAlex Richardson " does not exist") 168af6a4c17SAlex Richardson new_env_vars[varname] = guess 169af6a4c17SAlex Richardson debug("Inferred", varname, "as", guess) 170accf9611SUlrich Spörlein global parsed_args 171accf9611SUlrich Spörlein if parsed_args.debug: 172accf9611SUlrich Spörlein run([guess, "--version"]) 173af6a4c17SAlex Richardson 1743b4da25eSJessica Clarke 1752b181156SAlex Richardsondef check_xtool_make_env_var(varname, binary_name): 1762b181156SAlex Richardson # Avoid calling brew --prefix on macOS if all variables are already set: 1772b181156SAlex Richardson if os.getenv(varname): 1782b181156SAlex Richardson return 1792b181156SAlex Richardson global parsed_args 1802b181156SAlex Richardson if parsed_args.cross_bindir is None: 1812b181156SAlex Richardson parsed_args.cross_bindir = default_cross_toolchain() 1822b181156SAlex Richardson return check_required_make_env_var(varname, binary_name, 1832b181156SAlex Richardson parsed_args.cross_bindir) 184af6a4c17SAlex Richardson 1853b4da25eSJessica Clarke 186af6a4c17SAlex Richardsondef default_cross_toolchain(): 187af6a4c17SAlex Richardson # default to homebrew-installed clang on MacOS if available 188af6a4c17SAlex Richardson if sys.platform.startswith("darwin"): 189af6a4c17SAlex Richardson if shutil.which("brew"): 190b771d570SJessica Clarke llvm_dir = subprocess.run([ 191b771d570SJessica Clarke "brew", "--prefix", "llvm"], 192b771d570SJessica Clarke stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.strip() 193a26ace4dSAlex Richardson debug("Inferred LLVM dir as", llvm_dir) 194a26ace4dSAlex Richardson try: 195a26ace4dSAlex Richardson if llvm_dir and Path(llvm_dir.decode("utf-8"), "bin").exists(): 196a26ace4dSAlex Richardson return str(Path(llvm_dir.decode("utf-8"), "bin")) 197a26ace4dSAlex Richardson except OSError: 198a26ace4dSAlex Richardson return None 199af6a4c17SAlex Richardson return None 200af6a4c17SAlex Richardson 201af6a4c17SAlex Richardson 202af6a4c17SAlex Richardsonif __name__ == "__main__": 203af6a4c17SAlex Richardson parser = argparse.ArgumentParser( 204af6a4c17SAlex Richardson formatter_class=argparse.ArgumentDefaultsHelpFormatter) 205af6a4c17SAlex Richardson parser.add_argument("--host-bindir", 206af6a4c17SAlex Richardson help="Directory to look for cc/c++/cpp/ld to build " 207af6a4c17SAlex Richardson "host (" + sys.platform + ") binaries", 208af6a4c17SAlex Richardson default="/usr/bin") 209a26ace4dSAlex Richardson parser.add_argument("--cross-bindir", default=None, 210af6a4c17SAlex Richardson help="Directory to look for cc/c++/cpp/ld to build " 211af6a4c17SAlex Richardson "target binaries (only needed if XCC/XCPP/XLD " 212af6a4c17SAlex Richardson "are not set)") 213af6a4c17SAlex Richardson parser.add_argument("--cross-compiler-type", choices=("clang", "gcc"), 214af6a4c17SAlex Richardson default="clang", 215af6a4c17SAlex Richardson help="Compiler type to find in --cross-bindir (only " 216af6a4c17SAlex Richardson "needed if XCC/XCPP/XLD are not set)" 217af6a4c17SAlex Richardson "Note: using CC is currently highly experimental") 218af6a4c17SAlex Richardson parser.add_argument("--host-compiler-type", choices=("cc", "clang", "gcc"), 219af6a4c17SAlex Richardson default="cc", 220af6a4c17SAlex Richardson help="Compiler type to find in --host-bindir (only " 221af6a4c17SAlex Richardson "needed if CC/CPP/CXX are not set). ") 222af6a4c17SAlex Richardson parser.add_argument("--debug", action="store_true", 223af6a4c17SAlex Richardson help="Print information on inferred env vars") 22431ba4ce8SAlex Richardson parser.add_argument("--bootstrap-toolchain", action="store_true", 22531ba4ce8SAlex Richardson help="Bootstrap the toolchain instead of using an " 22631ba4ce8SAlex Richardson "external one (experimental and not recommended)") 227af6a4c17SAlex Richardson parser.add_argument("--clean", action="store_true", 228af6a4c17SAlex Richardson help="Do a clean rebuild instead of building with " 22943e083beSAlex Richardson "-DWITHOUT_CLEAN") 230af6a4c17SAlex Richardson parser.add_argument("--no-clean", action="store_false", dest="clean", 231af6a4c17SAlex Richardson help="Do a clean rebuild instead of building with " 23243e083beSAlex Richardson "-DWITHOUT_CLEAN") 233af6a4c17SAlex Richardson try: 234af6a4c17SAlex Richardson import argcomplete # bash completion: 235af6a4c17SAlex Richardson 236af6a4c17SAlex Richardson argcomplete.autocomplete(parser) 237af6a4c17SAlex Richardson except ImportError: 238af6a4c17SAlex Richardson pass 239af6a4c17SAlex Richardson parsed_args, bmake_args = parser.parse_known_args() 240af6a4c17SAlex Richardson 241af6a4c17SAlex Richardson MAKEOBJDIRPREFIX = os.getenv("MAKEOBJDIRPREFIX") 242af6a4c17SAlex Richardson if not MAKEOBJDIRPREFIX: 243af6a4c17SAlex Richardson sys.exit("MAKEOBJDIRPREFIX is not set, cannot continue!") 244af6a4c17SAlex Richardson if not Path(MAKEOBJDIRPREFIX).is_dir(): 245af6a4c17SAlex Richardson sys.exit( 246*d55de30eSJose Luis Duran "Chosen MAKEOBJDIRPREFIX=" + MAKEOBJDIRPREFIX + " doesn't exist!") 247af6a4c17SAlex Richardson objdir_prefix = Path(MAKEOBJDIRPREFIX).absolute() 248af6a4c17SAlex Richardson source_root = Path(__file__).absolute().parent.parent.parent 249af6a4c17SAlex Richardson 250af6a4c17SAlex Richardson new_env_vars = {} 251af6a4c17SAlex Richardson if not sys.platform.startswith("freebsd"): 252af6a4c17SAlex Richardson if not is_make_var_set("TARGET") or not is_make_var_set("TARGET_ARCH"): 2535157b451SJessica Clarke if not set(sys.argv).intersection(set(mach_indep_targets)): 254af6a4c17SAlex Richardson sys.exit("TARGET= and TARGET_ARCH= must be set explicitly " 255af6a4c17SAlex Richardson "when building on non-FreeBSD") 25631ba4ce8SAlex Richardson if not parsed_args.bootstrap_toolchain: 257af6a4c17SAlex Richardson # infer values for CC/CXX/CPP 258af6a4c17SAlex Richardson if parsed_args.host_compiler_type == "gcc": 259af6a4c17SAlex Richardson default_cc, default_cxx, default_cpp = ("gcc", "g++", "cpp") 260accf9611SUlrich Spörlein # FIXME: this should take values like `clang-9` and then look for 261accf9611SUlrich Spörlein # clang-cpp-9, etc. Would alleviate the need to set the bindir on 262accf9611SUlrich Spörlein # ubuntu/debian at least. 263af6a4c17SAlex Richardson elif parsed_args.host_compiler_type == "clang": 264af6a4c17SAlex Richardson default_cc, default_cxx, default_cpp = ( 265af6a4c17SAlex Richardson "clang", "clang++", "clang-cpp") 266af6a4c17SAlex Richardson else: 267af6a4c17SAlex Richardson default_cc, default_cxx, default_cpp = ("cc", "c++", "cpp") 268af6a4c17SAlex Richardson 269af6a4c17SAlex Richardson check_required_make_env_var("CC", default_cc, parsed_args.host_bindir) 270af6a4c17SAlex Richardson check_required_make_env_var("CXX", default_cxx, 271af6a4c17SAlex Richardson parsed_args.host_bindir) 272af6a4c17SAlex Richardson check_required_make_env_var("CPP", default_cpp, 273af6a4c17SAlex Richardson parsed_args.host_bindir) 274af6a4c17SAlex Richardson # Using the default value for LD is fine (but not for XLD!) 275af6a4c17SAlex Richardson 276af6a4c17SAlex Richardson # On non-FreeBSD we need to explicitly pass XCC/XLD/X_COMPILER_TYPE 277d037edf8SAlex Richardson use_cross_gcc = parsed_args.cross_compiler_type == "gcc" 2782b181156SAlex Richardson check_xtool_make_env_var("XCC", "gcc" if use_cross_gcc else "clang") 2792b181156SAlex Richardson check_xtool_make_env_var("XCXX", "g++" if use_cross_gcc else "clang++") 2802b181156SAlex Richardson check_xtool_make_env_var("XCPP", 2812b181156SAlex Richardson "cpp" if use_cross_gcc else "clang-cpp") 2822b181156SAlex Richardson check_xtool_make_env_var("XLD", "ld" if use_cross_gcc else "ld.lld") 283d037edf8SAlex Richardson 284d037edf8SAlex Richardson # We also need to set STRIPBIN if there is no working strip binary 285d037edf8SAlex Richardson # in $PATH. 286d037edf8SAlex Richardson if not shutil.which("strip"): 287d037edf8SAlex Richardson if sys.platform.startswith("darwin"): 288d037edf8SAlex Richardson # On macOS systems we have to use /usr/bin/strip. 28988db1cc9SAlex Richardson sys.exit("Cannot find required tool 'strip'. Please install " 29088db1cc9SAlex Richardson "the host compiler and command line tools.") 291d037edf8SAlex Richardson if parsed_args.host_compiler_type == "clang": 292d037edf8SAlex Richardson strip_binary = "llvm-strip" 293d037edf8SAlex Richardson else: 294d037edf8SAlex Richardson strip_binary = "strip" 295d037edf8SAlex Richardson check_required_make_env_var("STRIPBIN", strip_binary, 2962b181156SAlex Richardson parsed_args.host_bindir) 297d037edf8SAlex Richardson if os.getenv("STRIPBIN") or "STRIPBIN" in new_env_vars: 298d037edf8SAlex Richardson # If we are setting STRIPBIN, we have to set XSTRIPBIN to the 299d037edf8SAlex Richardson # default if it is not set otherwise already. 300d037edf8SAlex Richardson if not os.getenv("XSTRIPBIN") and not is_make_var_set("XSTRIPBIN"): 301d037edf8SAlex Richardson # Use the bootstrapped elftoolchain strip: 302d037edf8SAlex Richardson new_env_vars["XSTRIPBIN"] = "strip" 303af6a4c17SAlex Richardson 304af6a4c17SAlex Richardson bmake_binary = bootstrap_bmake(source_root, objdir_prefix) 305af6a4c17SAlex Richardson # at -j1 cleandir+obj is unbearably slow. AUTO_OBJ helps a lot 306af6a4c17SAlex Richardson debug("Adding -DWITH_AUTO_OBJ") 307af6a4c17SAlex Richardson bmake_args.append("-DWITH_AUTO_OBJ") 308af6a4c17SAlex Richardson if parsed_args.clean is False: 309af6a4c17SAlex Richardson bmake_args.append("-DWITHOUT_CLEAN") 310af6a4c17SAlex Richardson if (parsed_args.clean is None and not is_make_var_set("NO_CLEAN") 311af6a4c17SAlex Richardson and not is_make_var_set("WITHOUT_CLEAN")): 312af6a4c17SAlex Richardson # Avoid accidentally deleting all of the build tree and wasting lots of 313af6a4c17SAlex Richardson # time cleaning directories instead of just doing a rm -rf ${.OBJDIR} 3143b4da25eSJessica Clarke want_clean = input("You did not set -DWITHOUT_CLEAN/--(no-)clean." 315af6a4c17SAlex Richardson " Did you really mean to do a clean build? y/[N] ") 316af6a4c17SAlex Richardson if not want_clean.lower().startswith("y"): 31743e083beSAlex Richardson bmake_args.append("-DWITHOUT_CLEAN") 318af6a4c17SAlex Richardson 319af6a4c17SAlex Richardson env_cmd_str = " ".join( 320af6a4c17SAlex Richardson shlex.quote(k + "=" + v) for k, v in new_env_vars.items()) 321af6a4c17SAlex Richardson make_cmd_str = " ".join( 322af6a4c17SAlex Richardson shlex.quote(s) for s in [str(bmake_binary)] + bmake_args) 323af6a4c17SAlex Richardson debug("Running `env ", env_cmd_str, " ", make_cmd_str, "`", sep="") 324af6a4c17SAlex Richardson os.environ.update(new_env_vars) 325b7ac17b4SAlfredo Dal'Ava Junior 326b7ac17b4SAlfredo Dal'Ava Junior # Fedora defines bash function wrapper for some shell commands and this 327b7ac17b4SAlfredo Dal'Ava Junior # makes 'which <command>' return the function's source code instead of 328b7ac17b4SAlfredo Dal'Ava Junior # the binary path. Undefine it to restore the original behavior. 329b7ac17b4SAlfredo Dal'Ava Junior os.unsetenv("BASH_FUNC_which%%") 330b7ac17b4SAlfredo Dal'Ava Junior os.unsetenv("BASH_FUNC_ml%%") 331b7ac17b4SAlfredo Dal'Ava Junior os.unsetenv("BASH_FUNC_module%%") 332b7ac17b4SAlfredo Dal'Ava Junior 333af6a4c17SAlex Richardson os.chdir(str(source_root)) 334af6a4c17SAlex Richardson os.execv(str(bmake_binary), [str(bmake_binary)] + bmake_args) 335