[AOMP] New front-end for aomp build scripts (taskification/control-flow inversion for scripts, part 2)#2274
Open
jtb20 wants to merge 71 commits into
Open
[AOMP] New front-end for aomp build scripts (taskification/control-flow inversion for scripts, part 2)#2274jtb20 wants to merge 71 commits into
jtb20 wants to merge 71 commits into
Conversation
This patch splits aomp_utils (shell utility functions) out of aomp_common_vars, in preparation for adding lots more non-configuration-related stuff to the new file. This is mostly straightfoward, but build scripts, etc. need to source the new file also as well as aomp_common_vars.
This is an experimental patch to incrementally refactor the build scripts.
The approach taken is particularly relevant to scripts which build
multiple configurations of a component.
There are several ideas here. Firstly, build scripts can be introspected
so you can see what they are doing:
$ ./build_offload.sh list_configs
asan
perf
perf+asan
debug
debug+asan
$ AOMP_BUILD_SANITIZER=0 ./build_offload.sh list_configs
perf
debug
Build steps are split into different tasks, each of which is wrapped in a
"task_foo" function (which is passed the configuration name):
$ ./build_offload.sh list_tasks perf
clean
cmake
build
install
You can list all tasks list this:
$ ./build_offload.sh list
task_precheck
task_patch
task_clean asan
task_cmake asan
task_build asan
task_install asan
task_clean perf
task_cmake perf
task_build perf
task_install perf
task_clean perf+asan
task_cmake perf+asan
task_build perf+asan
task_install perf+asan
task_clean debug
task_cmake debug
task_build debug
task_install debug
task_postinstall debug
task_clean debug+asan
task_cmake debug+asan
task_build debug+asan
task_install debug+asan
task_unpatch
Or e.g. see what will happen for different env var settings:
$ AOMP_BUILD_DEBUG=0 ./build_offload.sh list
task_precheck
task_patch
task_clean asan
task_cmake asan
task_build asan
task_install asan
task_clean perf
task_cmake perf
task_build perf
task_install perf
task_clean perf+asan
task_cmake perf+asan
task_build perf+asan
task_install perf+asan
task_unpatch
You can still invoke the build scripts the same way as at present:
$ ./build_offload.sh
[...builds everything...]
$ ./build_offload.sh cmake
[...just runs cmake steps...]
$ ./build_offload.sh nocmake
[...just runs build steps...]
$ ./build_offload.sh install
[...just runs install steps...]
Only the build_offload.sh script has been done so far, but this
backward compatibility allows other scripts to be refactored in a similar
way incrementally.
The aim (not yet realised) is to then provide a new or alternate front-end
(to build_aomp.sh) using exactly the same build scripts, allowing
fine-grained control over which components to build/rebuild, and so on.
Internally, the refactoring already done on build_offload.sh demonstrates
very much deduplication, particularly around the setting of cmake
options. Further work will allow much of the "boilerplate" in each of
the build scripts to be replaced by a central implementation.
Environment variables used to control the build are now read via two
functions (get_config_var_string and get_config_var_bool). There are
several reasons for this indirection:
- It allows us to have a single location to check which environment
variables are being used to control the build.
- (For the alternate frontend) the options can be changed via
e.g. command-line options instead of environment variables.
- The _bool function emits the string 'true' or 'false'. This allows
the use of:
if $Result; then ... fi
instead of
if [ "$Result" -eq 1 ]; then ... fi
which is shorter/somewhat easier to read.
"Actions" (the emulated "nocmake", etc. options, and the new "list",
etc. options) are implemented as functions named "do_{foo}", invoked by
the new "command_dispatcher" function.
There are a few other actions, e.g.:
$ ./build_offload.sh show_build_dir perf
/home/julbrown/git/aomp21.0/build/home/julbrown/git/aomp21.0/offload_perf
These will be more useful once more scripts are "taskified".
Refactor build_comgr.sh into the taskified control-flow-inversion form established by build_offload.sh: split work into task_* functions over default/asan configs, add introspection hooks (list_configs/list_tasks), and dispatch via command_dispatcher while preserving the existing nocmake/cmake/install CLI behavior. Add INSTALL_COMGR to the get_config_var_string allow-list in aomp_utils.
Refactor build_rocr.sh into the taskified form: split into task_* functions over default/asan/debug configs, with the debug runtime-source copy expressed as task_postinstall. Add introspection hooks and dispatch via command_dispatcher, preserving the nocmake/cmake/install CLI. Add INSTALL_ROCM to the get_config_var_string allow-list in aomp_utils.
Refactor build_project.sh into the taskified form. The single (default) config build is split into task_* functions: cmake-option assembly and the source version-banner patch move into task_cmake (via the fixup_source_banner helper), the partial/full builds into task_build, and install plus the amd* symlinks and per-driver .cfg generation into task_install. rocr/ATD patching becomes task_patch/task_unpatch. Add INSTALL_PROJECT to the get_config_var_string allow-list in aomp_utils.
Refactor the legacy-idiom build_rocBLAS.sh into the taskified form: split into task_* functions over the single (default) config, move the Tensile commit checkout and repo patching out of top-level into task_patch (so introspection has no side effects), and modernize quoting. nocmake remains unsupported via a do_nocmake override that errors, and the AOMP_STANDALONE_BUILD-only restriction is enforced in task_precheck. Add AOMP_BUILD_TENSILE and ROCBLAS_USE_HIPBLASLT to the get_config_var_bool allow-list in aomp_utils.
… vars Add the user-overridable environment variables (paths, repo names, GPU target lists, compilers, version/build-type knobs, and the flang/limit-flang booleans) to the get_config_var_string and get_config_var_bool allow-lists. This lets the build scripts route all user-supplied values through the cfgvar/cfgbool chokepoint so they can later be driven deterministically by an orchestration layer, independent of the process environment. Variables derived internally by aomp_common_vars are intentionally not added.
Read all user-supplied values (AOMP_REPOS/AOMP_PROJECT_REPO_NAME/ AOMP_COMGR_REPO_NAME for the repo path, AOMP, AOMP_CMAKE) through the cfgvar chokepoint instead of referencing the globals directly. aomp_common_vars-derived values (AOMP_INSTALL_DIR, LLVM_INSTALL_LOC, ASAN_FLAGS, RPATH arrays) remain direct references. The common/variant cmake-option split was already in place.
Split the per-config cmake options into a common base array plus variant-specific (default/asan/debug) appends, removing the prior duplication. Read user-supplied values (AOMP_REPOS/AOMP_ROCR_REPO_NAME, AOMP_CMAKE, BUILD_TYPE) through cfgvar; aomp_common_vars-derived values (AOMP_INSTALL_DIR, LLVM_INSTALL_LOC, ASAN_FLAGS, RPATH arrays) stay direct.
Read all user-supplied values through the cfgvar/cfgbool chokepoint: repo paths (AOMP_REPOS/AOMP_PROJECT_REPO_NAME/AOMP_ROCR_REPO_NAME via REPO_DIR/ROCR_REPO_DIR), AOMP, AOMP_CMAKE, AOMP_SUPP, BUILD_TYPE, AOMP_PROJECTS_LIST, GFXLIST, AOMP_VERSION_STRING, AOMP_CC/CXX_COMPILER, and the AOMP_USE_NINJA/AOMP_LEGACY_OPENMP/AOMP_SKIP_AMD_FLANGRT/ AOMP_BUILD_SANITIZER/AOMP_LIMIT_FLANG booleans. aomp_common_vars-derived values (AOMP_INSTALL_DIR, LLVM_INSTALL_LOC, AOMP_PROC, AOMP_NVPTX_TARGET, RPATH lists, CCACHE opts) remain direct references. The sanitizer cmake block was already separated from the common options.
Read user-supplied values through the cfgvar chokepoint: AOMP_REPOS (repo paths), AOMP_SUPP and AOMP (PATH export), ROCMLIBS_GFXLIST (GPU_TARGETS), and AOMP_CMAKE. aomp_common_vars-derived values (AOMP_INSTALL_DIR, LLVM_INSTALL_LOC and the CC/CXX/FC exports derived from it) stay direct.
Convert build_roct.sh to the taskified build pattern used by build_offload.sh and the other Phase 1 scripts: per-config task_* functions (default/asan/debug) driven by command_dispatcher, with common vs. variant-specific cmake options factored apart and the debug source-copy step moved to task_postinstall. User-controllable environment variables (AOMP_ROCT_REPO_NAME, INSTALL_ROCT, AOMP_CLANG_COMPILER, AOMP_CLANGXX_COMPILER) are read through the cfgvar/cfgbool wrappers; add them to the aomp_utils allowlists.
Convert build_rocminfo.sh to the taskified build pattern. rocminfo has a single (default) config, so it uses one set of task_* functions driven by command_dispatcher. Route the user-controllable environment variables AOMP_RINFO_REPO_NAME and INSTALL_RINFO through cfgvar and add them to the aomp_utils allowlist.
Convert build_xio.sh to the taskified build pattern. xio has a single (default) config. The git clone/pull of the rocm-xio source becomes an init task_fetch so it no longer runs on -h/help. The script now also sources aomp_utils (previously only aomp_common_vars). Route the user-controllable INSTALL_XIO through cfgvar and add it to the aomp_utils allowlist.
Convert build_emissary.sh to the taskified build pattern. The flavour (mpi/hdf5) is still selected from the invoking symlink name and drives the source/build subdirs and extra cmake options; the build itself runs through a single (default) config of task_* functions. The git clone/pull becomes an init task_fetch so it no longer runs on -h/help, and the script now sources aomp_utils. Route the user-controllable INSTALL_EMISSARY through cfgvar and add it to the aomp_utils allowlist.
Convert build_libdevice.sh to the taskified build pattern with a single (default) config. The optional test step (gated by SKIPTEST) is folded into task_build so it still runs on the build/nocmake paths. Route the user-controllable AOMP_LIBDEVICE_REPO_NAME, INSTALL_LIBDEVICE and SKIPTEST through cfgvar and add them to the aomp_utils allowlist.
Convert build_rocm-cmake.sh to the taskified build pattern. rocm-cmake has no make step, so its single (default) config exposes only clean/cmake/install tasks and no patching. Route the user-controllable AOMP_ROCMCMAKE_REPO_NAME through cfgvar and add it to the aomp_utils allowlist.
Convert build_rocm_smi_lib.sh to the taskified build pattern with a single (default) config. The repo name and install prefix are fixed values, so no new cfgvar allowlist entries are required.
Convert build_amdsmi.sh to the taskified build pattern with a single (default) config. The repo name and install prefix are fixed values, so no new cfgvar allowlist entries are required.
Convert build_extras.sh to the taskified build pattern. extras has no cmake/make: its "build" stage copies the utility scripts into the build dir and patches their install-path placeholders with sed, and the install stage copies them into bin (plus the standalone gpurun symlink). Route the user-controllable AOMP_REPO_NAME and INSTALL_EXTRAS through cfgvar (and AOMP_STANDALONE_BUILD through cfgbool); add the new string vars to the aomp_utils allowlist.
Convert build_hipcc.sh to the taskified build pattern with a single (default) config and no patching. Drop a stray empty export of SED_INSTALL_DIR that had been copied in from another script. Route the user-controllable INSTALL_HIPCC through cfgvar and add it to the aomp_utils allowlist.
Convert build_hipamd.sh to the taskified build pattern with default/asan/debug configs. Both the hipamd and clr repos are patched in task_patch/task_unpatch, the debug config builds only the amdhip64 target, the debug source-copy is handled in task_postinstall, and the installed hipcc/hipvars.pm path fix-ups run as the default config's postinstall. The repos and install prefix are fixed paths, so no new cfgvar allowlist entries are required.
Convert build_hipify.sh to the taskified build pattern with a single (default) config and no patching. The inline install-dir writability check is replaced by check_writable_installdir in task_precheck. Route the user-controllable INSTALL_HIPIFY through cfgvar and add it to the aomp_utils allowlist.
Convert build_hipfort.sh to the taskified build pattern with a single (default) config and patch/unpatch tasks. Route the user-controllable HIPFORT_INSTALL_DIR through cfgvar and add it to the aomp_utils allowlist.
Convert build_openmp.sh (the legacy openmp-subdir build) to the taskified pattern, mirroring build_offload.sh. Variants use composite config names (default/asan/perf/perf+asan/debug/debug+asan) gated by AOMP_LEGACY_OPENMP/SANITIZER/AOMP_BUILD_PERF/DEBUG/SANITIZER. The former recursive self-invocation for the device runtime library pass is now modeled as a parallel set of "<config>-devicertl" configs that build in the openmp-devicertl directory with the amdgcn default target triple, so a full run builds the host variants first and then the devicertl variants. The debug source-copy runs as the host debug config's postinstall. Route the user-controllable OPENMP_BUILD_DIR and ALTAOMP through cfgvar and add them to the aomp_utils allowlist.
Convert build_llvm-classic.sh to the taskified build pattern with a single (default) config that is built but not installed (clean/cmake/ build only, ninja). The early skip when flang-classic sources are absent is preserved as a top-level guard; AOMP_BUILD_FLANG_CLASSIC is computed by aomp_common_vars so it is read directly rather than via cfgbool. Route the user-controllable AOMP_LFL_DIR and AOMP_FLANG_REPO_NAME through cfgvar and add them to the aomp_utils allowlist.
Convert build_flang-classic.sh to the taskified build pattern with a single (default) config. task_clean preserves the shared llvm-classic subdir (built first by build_llvm-classic.sh), and install uses cmake --build --target install. The flang-classic enable guard is kept at the top (AOMP_BUILD_FLANG_CLASSIC is computed, read directly). No new cfgvar allowlist entries are required.
Convert build_flang.sh to the taskified build pattern with default and asan configs (asan listed when AOMP_BUILD_SANITIZER is set). Common cmake options are factored out and the asan variant adds the sanitizer prefix path, rpath, libdir, and flags. User-controllable variables are routed through cfgvar/cfgbool; INSTALL_FLANG is added to the aomp_utils string allowlist.
Convert build_flang_runtime.sh to the taskified build pattern with default and asan configs. The openmp runtime source used for OPENMP_BUILD_DIR is computed per config via get_openmp_runtime_src, and the asan variant reproduces the standalone vs non-standalone cmake prefix path, rpath, libdir, and -DSANITIZER handling. User-controllable variables are routed through cfgvar/cfgbool; no new allowlist entries are required.
Introduce a unified, introspectable build orchestrator (bin/aomp_build.py) that resolves a component set from a CUDF-style config (bin/configs/aomp.cudf), topologically orders it, elaborates per-component tasks via each script's taskified `list` interface, and runs them by number/range/continue/glob with per-task logs. Supports feature aliases, build-variant selection, env-var flags, and git version-manifest export/import. Taskify build_supp.sh (and its build_prereq.sh symlink) with the standard command_dispatcher interface (single coarse default config) so every component speaks the same interface to the orchestrator. Local runcmd renamed to supp_runcmd to avoid clashing with aomp_utils' dispatcher runcmd; legacy direct invocation is preserved.
When the classic LLVM source is absent, build_llvm-classic.sh and build_flang-classic.sh print a skip warning. Route it to stderr so the taskified introspection commands (list, list_configs, ...) keep a clean stdout for the aomp_build.py orchestrator.
- Add bin/AOMP_BUILD.md documenting the orchestrator (user workflows and internals). - Make 'continue' a trailing selector keyword: the preceding selector becomes a "from there to the end" anchor (e.g. 'comp1 comp2 continue'). - Accept comma-separated lists for --add/--remove (in addition to repeating the flag). - Drop the deprecated classic Flang stack (llvm-classic, flang-classic, pgmath, flang, flang_runtime) from the default request; still available via --add flang.
- --variant now strictly filters configs: a component builds only the requested variants it advertises, and is skipped entirely (no init/fini tasks) when none match. So '--variant default' builds each component's default and skips llvm_runtimes_standalone (its default libs come from the project build). - Accept comma-separated variant lists, e.g. '--variant debug,asan' and '--variant comp1=debug,comp2=asan'. - Update --help text and AOMP_BUILD.md accordingly.
- With no --variant, build every advertised config per component (default plus all variants like asan/debug/perf), not just default. - With --variant, always include the 'default' baseline where offered, so '--variant debug' means default+debug: default-only components still build, components offering the variant add it, and components without a default (the runtimes) build just the requested variant. Components offering neither default nor any requested variant are still skipped (so '--variant default' skips the runtimes). - Update --help and AOMP_BUILD.md.
When a component advertises only the "default" config, drop the variant segment from its task names (e.g. prereq/build instead of prereq/default/build), matching the form already used for config-less init/fini tasks. Multi-config components keep component/variant/stage. Update AOMP_BUILD.md.
--build-type now uses the same scoped grammar as --variant: a bare value applies globally, 'comp=type' sets one component's build type, and values are comma-separated and/or repeatable (e.g. 'project=Debug,comgr=Debug'). The build type is applied as BUILD_TYPE on each task's subprocess at execution time, so components can build with different CMake build types. Update AOMP_BUILD.md.
Build child scripts now run in an environment constructed by the orchestrator rather than inheriting the caller's, so build-affecting state is under aomp_build.py's control. PATH defaults to standard system locations (fixing cases where a Homebrew pkg-config shadowed the system one); --inherit-path and --pass-env opt back in to caller values. Add -i/--install (AOMP), -b/--build (BUILD_AOMP), and -p/--prereq (AOMP_SUPP) to set the core directory layout, exported as absolute paths to every child script. Make the directory options apply consistently by replacing hard-coded $HOME/local references with $AOMP_SUPP in build_rocprofiler.sh, build_rocprofiler-sdk.sh, build_hipamd.sh, build_emissary.sh, build_rccl.sh, and build_qmcpack.sh. Send the aomp_common_vars "using system cmake" warning to stderr so it no longer pollutes list_configs introspection.
Add -s/--source to set the repo/source root (AOMP_REPOS), exported as an absolute path to every child script alongside the other directory knobs. All build scripts already derive their repo path from AOMP_REPOS, so the override applies consistently with no script changes. Drop the redundant "task N:" from progress lines and show the per-task log path relative to the build root for brevity (falling back to the absolute path when the log dir lies elsewhere).
Make the [NNN/TTT] progress counter relative to the whole build: the first number is the task's absolute 1-based position in the full elaborated list and the total is the full task count, so running a subset still reports its real task numbers (zero-padded to width).
The post-install step rewrote ../../../ paths in the copied llvm-lit using a slash-delimited sed with hand-escaped slashes from $AOMP_REPOS. The escaping doubled the backslashes, producing an unescaped delimiter that aborted with "unknown option to 's'" on ordinary absolute paths. Switch to a '|' sed delimiter so the path slashes need no escaping, and drop the stray '-ie' backup suffix.
Each task records a .start stamp when it begins and a .done stamp on success, under a stamps/ dir beside the logs. 'list' shows a green check for completed tasks and a red cross for started-but-unfinished ones. Bare 'continue' resumes from the first task that is not marked done through to the end. Any run clears stamps from the lowest selected task index onward, so a full build resets all stamps and a subset/continue resets that point onward.
-C/--clean now prepends an 'install/clean' pseudo-task that wipes the versioned install dir (the symlink target) and drops the symlink, rather than gating the per-component clean tasks. Per-component 'clean' tasks are now always elaborated (before each cmake) and run unconditionally.
build_llvm_runtimes_standalone.sh read ALTAOMP without a default, so an unset ALTAOMP made CMAKE_C_COMPILER collapse to /bin/clang and cmake failed. Fall back to the just-installed compiler (LLVM_INSTALL_LOC), as build_openmp.sh and build_offload.sh already do.
offload/utils/gpurun is now a directory (script + CMakeLists), so the plain cp failed with "-r not specified". Copy the gpurun script out of the directory so it still lands as build/extras/gpurun.
build_rocBLAS.sh unconditionally cat'd rocBLAS/tensile_tag.txt to pin the Tensile commit, but that file is deprecated/removed in rocBLAS rocm-7.1; guard on its existence and otherwise build the checked-out Tensile. Also add the missing rocmlibs patch-control-file_23.0.txt (mirrors 22.0); all referenced patches were verified to apply cleanly to the 7.1 sources.
The two flags in CMAKE_CXX_FLAGS were joined with ';', which CMake treats as a list separator, breaking the compile line so the shell tried to run '-D__HIP_PLATFORM_AMD__=1' as a command. Use a space, matching rocRAND and the other rocmlibs scripts.
hipfort was defined but omitted from the default request: stanza, so aomp_build.py builds did not include it (unlike build_aomp.sh). Add it to the default install list. Also fix hipfort's declared dependency: it was depends: hipamd, flang_runtime, where flang_runtime is the deprecated classic Flang runtime. That caused --add hipfort to drag in the entire classic Flang stack (llvm-classic, flang-classic, pgmath, flang, flang_runtime). build_hipfort.sh actually compiles with the modern LLVM flang ($LLVM_INSTALL_LOC/bin/flang from the project build), so depend on hipamd, project instead. The resolved default set now matches the legacy shell build with no classic Flang components.
Several components were missing from the manifest because git_facts() required .git directly inside the source dir. The LLVM project, comgr, hipcc and llvm_runtimes_standalone all build from subdirectories of the single llvm-project checkout, so all four (LLVM being the largest) were silently dropped. - Resolve the enclosing repository via `git rev-parse --show-toplevel` so subdir sources are recorded, and add a "subdir" field (via the symlink-safe --show-prefix) identifying the build subtree. - Add an "externals" manifest section for repos pulled into a build but not standalone components; record SPIRV-LLVM-Translator there. LLVM, comgr and the SPIRV translator are tightly coupled and a frequent source of build breakage, so their exact versions are now captured. - On import, restore externals too and dedupe components that share the llvm-project checkout so it is moved only once. - Keep the "extras" component (the AOMP build-scripts repo) at HEAD on import instead of rolling it back; its dirty state no longer blocks the import. The scripts are meant to build arbitrary AOMP/ROCm versions, so pinning them would change the build logic mid-flight. Docs (AOMP_BUILD.md) updated to describe subdir/externals and the floating extras behavior.
build_aomp.sh builds the debugger by default (AOMP_BUILD_DEBUG defaults to 1), but the orchestrator's default request omitted the "debug" feature, so aomp_build.py builds were missing rocdbgapi and rocgdb (the only real difference left in a full-build audit). Add them to the default request, ordered as in build_aomp.sh (after hipfort, before rocprofiler-sdk). The resolved default set now matches the legacy shell build. Re-exclude with --remove rocgdb,rocdbgapi if not wanted.
Update AOMP_BUILD.md now that hipfort and the debug feature (rocdbgapi, rocgdb) are part of the default request: the default-set description no longer lists them as omitted, the debug feature row notes it is in the default set, and the examples use --remove debug instead of --add debug.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is a followup to #1499 from last year. I'm not sure if, in isolation, that PR made a lot of sense: it would really only open up any new possibilities when all the scripts were converted in the same way. While mechanical-ish and straightforward-ish, that's still a lot of work.
But this week, I realised I could probably point Claude at the refactoring done in that PR, and ask it to apply the same transformation to the rest of the files. I also got it to write a new front-end, which it refers to as an "orchestrator", to control which parts of which of those scripts to run, and under which configuration settings. That's written in Python.
With that, we can get full and transparent control over the build process, the set of components built, and the way those components are configured. It becomes easy to run slimmed-down builds to investigate some particular bug quickly, or extended builds to work on some component that is not built by default, using command-line flags to the new tool (aomp_build.py). Incremental builds of any part of the toolchain become very easy: the full build is split into fine-grained tasks and presented to the user as a list, and tasks (or sets of tasks) on the list can be invoked by name, glob or index.
However, because of the way the script refactoring is done, it remains possible to use the scripts in the "old way", and that still works fine -- i.e. with build options controlled by environment variables, and the overall build run by the "build_aomp.sh" script. Each individual build script presents its existing interface alongside the new introspection-based one. So, there are lot of changes here, but (E&OE) they should be "safe" from the user perspective: it's not critical for anyone to learn the new interface right away, or at all, if they so choose.
Another thing the new and unified introspection interface make possible is to ask each component "what is your source directory", and go from there to an exportable (and importable!) JSON build manifest -- the purpose of which being to help with build reproducibility (though note the import part is basically untested - YMMV!). The aomp_build.py script also makes some effort to further isolate builds from the environment: it controls the PATH given to each build script, and creates the rest of the environment (variables) from scratch, rather than passing them through from the user's shell.
I tested a full AOMP build via the new aomp_build.py and the existing build_aomp.sh, and results were (reportedly!) the same.
Full (Claude-written) instructions are in AOMP_BUILD.md.
Beware the code is only a couple of days old (apart from the year-old, hand-written bit), so probably isn't quite perfect yet.
The refactor/aomp_build.py only covers the building part of the process: aomp_clone.sh, testing and other miscellaneous scripts remain as they are.
Enjoy!