diff --git a/mfc.sh b/mfc.sh index bbdbb33adf..3a4ec38195 100755 --- a/mfc.sh +++ b/mfc.sh @@ -102,9 +102,12 @@ if [ $code -ne 0 ]; then error "main.py finished with a $code exit code." fi -# Deactivate the Python virtualenv in case the user "source"'d this script -log "(venv) Exiting the$MAGENTA Python$COLOR_RESET virtual environment." -deactivate +# Deactivate the Python virtualenv in case the user "source"'d this script. +# In prebuilt/spack mode the venv was never created, so there's nothing to deactivate. +if type deactivate > /dev/null 2>&1; then + log "(venv) Exiting the$MAGENTA Python$COLOR_RESET virtual environment." + deactivate +fi # Exit with proper exit code exit $code diff --git a/toolchain/bootstrap/python.sh b/toolchain/bootstrap/python.sh index 2809918b76..4193903f15 100644 --- a/toolchain/bootstrap/python.sh +++ b/toolchain/bootstrap/python.sh @@ -4,6 +4,12 @@ MFC_PYTHON_MIN_MAJOR=3 MFC_PYTHON_MIN_MINOR=9 MFC_PYTHON_MIN_STR="$MFC_PYTHON_MIN_MAJOR.$MFC_PYTHON_MIN_MINOR" +# Prebuilt/spack mode: skip the venv entirely. The caller must already have +# python3 + the MFC toolchain deps + the `mfc` package importable on PYTHONPATH. +if [ -n "${MFC_PREBUILT_PREFIX:-}" ]; then + return 0 +fi + is_python_compatible() { if ! ${1:-python3} -c "import sys; exit(int(not (sys.version_info[0]==$MFC_PYTHON_MIN_MAJOR and sys.version_info[1] >= $MFC_PYTHON_MIN_MINOR)))"; then return 1 diff --git a/toolchain/mfc/build.py b/toolchain/mfc/build.py index 01efb1a9b1..d5a13fe182 100644 --- a/toolchain/mfc/build.py +++ b/toolchain/mfc/build.py @@ -14,7 +14,7 @@ from rich.text import Text from .case import Case -from .common import MFCException, create_directory, debug, delete_directory, format_list_to_string, system +from .common import MFCException, create_directory, debug, delete_directory, format_list_to_string, get_prebuilt_prefix, system from .printer import cons from .run import input from .state import ARG, CFG, gpuConfigOptions @@ -336,6 +336,9 @@ def get_home_dirpath(self) -> str: return os.sep.join([os.getcwd()]) def get_install_binpath(self, case: Case) -> str: + prebuilt = get_prebuilt_prefix() + if prebuilt: + return os.sep.join([prebuilt, "bin", self.name]) # /install//bin/ return os.sep.join([self.get_install_dirpath(case), "bin", self.name]) @@ -359,6 +362,9 @@ def is_buildable(self) -> bool: if ARG("no_build"): return False + if get_prebuilt_prefix(): + return False + if self.isDependency and ARG(f"sys_{self.name}", False): return False diff --git a/toolchain/mfc/cli/commands.py b/toolchain/mfc/cli/commands.py index 1e1898b117..d396c95d36 100644 --- a/toolchain/mfc/cli/commands.py +++ b/toolchain/mfc/cli/commands.py @@ -274,6 +274,14 @@ default=False, dest="no_build", ), + Argument( + name="prebuilt-prefix", + help="Use prebuilt MFC binaries from /bin (e.g. a Spack install prefix). Implies --no-build. Also settable via MFC_PREBUILT_PREFIX.", + type=str, + default=None, + metavar="PREFIX", + dest="prebuilt_prefix", + ), Argument( name="wait", help="(Batch) Wait for the job to finish.", @@ -437,6 +445,14 @@ default=False, dest="no_build", ), + Argument( + name="prebuilt-prefix", + help="Use prebuilt MFC binaries from /bin (e.g. a Spack install prefix). Implies --no-build. Also settable via MFC_PREBUILT_PREFIX.", + type=str, + default=None, + metavar="PREFIX", + dest="prebuilt_prefix", + ), Argument( name="no-examples", help="Do not test example cases.", diff --git a/toolchain/mfc/common.py b/toolchain/mfc/common.py index ff066c8672..6ca1441409 100644 --- a/toolchain/mfc/common.py +++ b/toolchain/mfc/common.py @@ -42,6 +42,17 @@ def debug(msg: str): MFC_BENCH_FILEPATH = abspath(join(MFC_TOOLCHAIN_DIR, "bench.yaml")) MFC_MECHANISMS_DIR = abspath(join(MFC_TOOLCHAIN_DIR, "mechanisms")) + +def get_prebuilt_prefix() -> typing.Optional[str]: + # Returns the prebuilt install prefix when MFC is run against pre-built binaries + # (e.g. a Spack install). The CLI flag --prebuilt-prefix takes precedence over the + # MFC_PREBUILT_PREFIX environment variable. Returns None when running normally. + from .state import ARG + + cli = ARG("prebuilt_prefix", "") or None + return cli or os.environ.get("MFC_PREBUILT_PREFIX") or None + + MFC_LOGO = """\ .=++*: -+*+=. :+ -*- == =* .