Remove spack load dependence on modules#14062
Conversation
|
Couldn't resist making a meme for this PR... In all seriousness, I support this PR, and think it's the right direction to go if we want to continue to make Spack easy to set up and use. My only concern is that Environment Modules/Lmod are massive projects, and we're attempting to roll our own module management system here. How much of Lmod's features do we plan on supporting? How large of a codebase will this become? Using a wrapper around |
|
@adamjstewart I think we get most of this feature "for free" from other things we have to do. We already need to know the environment changes necessary to load a package (because we generate modules) and we need to know how to reverse those changes (because we deactivate environments). So far, this feature is just a thin shell script shim layer. I do think it makes sense to add tracking for which hashes are loaded, but that's also pretty trivial, and can be hooked up to the The previous state of affairs: |
|
Will there be something analogous to the module systems ability to filter things from the modulefiles? E.g. modules:
lmod:
all:
filter:
environment_blacklist: 'LD_LIBRARY_PATH'
bowtie2:
environment:
LD_LIBRARY_PATH: '$prefix/lib'Some of us (ok, at least I...) consider setting This was pretty widely discussed back in #3955. I recognize the utility of setting those variables if you're supporting folks who are linking against libraries in the Spack tree. I, on the other hand, am simply trying to use the things I've built with Spack with minimal side effects. #3955 documents I've been running with this for a while now, without the exception for python, and haven't been having any trouble. modules:
lmod:
all:
filter:
environment_blacklist: ['CPATH', 'LIBRARY_PATH', 'LD_LIBRARY_PATH', 'DYLD_LIBRARY_PATH']
environment:
set:
'${PACKAGE}_ROOT': '${PREFIX}'Sorry, no GIF.... |
|
Echo'ing a bit what I hear @adamjstewart asking, I'm worried about Spack trying to be do too many things. The only feature that I've seen for Spack load that it's trivial w/ Lmod modules is the ability to cook up an arbitrary spec and have load the appropriate module. In the few cases where my user community needed that feature I've use the module systems ability to add suffixes to provide simple names that my users can figure out w/out documentation, e.g. Beyond that it seems that it's duplicating existing work and building a monolithic system. I suppose what I'm asking is: what is the end goal for this set of features?
|
I do not think we should enable this for non-spack software. We will still generate modules for Spack-installed software, and those modules will be interoperable with the greater module ecosystem. In this PR I've refactored the On your last two points, the answer to both is environments. Spack allows environments with pithy names, and an environment with |
|
close-cycling to restart the tests, as they didn't start properly on the last push |
@hartzell: not sure if it's clear from the PR, but the only thing We're definitely not getting rid of modules; all those customizations will still be possible by generating modules, and we'll still do that. Users can still use modules through the The overarching goal here is to give users some easy ways to use Spack that a) don't require setting up an entire module system, and b) work the same on your laptop, HPC machine, etc. Does this and @becker33's comment alleviate your concerns? |
lib/spack/spack/cmd/load.py
Outdated
| tty.msg(*msg) | ||
| return 1 | ||
|
|
||
| if args.recurse_dependencies: |
There was a problem hiding this comment.
I think this should default to true -- it was always puzzling that spack load didn't load them by default -- I think the original intent was that the module system would handle loading recursive deps. Since we're not loading modules anymore, I think the default should be to load recursive deps (if they are not already loaded).
There was a problem hiding this comment.
The -r option is always default False on other packages.
I think it will be better to replace it with a --only argument like the install command has. Default will be package and dependencies, but --only can specify only dependencies or only the package itself.
There was a problem hiding this comment.
I like this idea. --only does more and has the right default.
lib/spack/spack/cmd/unload.py
Outdated
| import spack.util.environment | ||
| import spack.user_environment as uenv | ||
|
|
||
| description = "remove package from the user environment variables`" |
There was a problem hiding this comment.
I think you can omit "variables"
There was a problem hiding this comment.
Are you sure? I added it to differentiate from Spack environments, which could be "the user's active environment"
There was a problem hiding this comment.
I guess I don't like the "environment variables" part since you would normally say "the user's environment". But we have an overload with Spack environments. @adamjstewart: any suggestions for how to disambiguate this?
lib/spack/spack/cmd/load.py
Outdated
| import spack.util.environment | ||
| import spack.user_environment as uenv | ||
|
|
||
| description = "add package to the user environment variables" |
| env_mod.extend( | ||
| uenv.environment_modifications_for_spec(spec).reversed()) | ||
| env_mod.remove_path(uenv.spack_loaded_hashes_var, spec.dag_hash()) | ||
| cmds = env_mod.shell_modifications(args.shell) |
There was a problem hiding this comment.
In the current state, if you load something, then change the package so that the env mods would change, then unload the package, can any of these operations fail? @alalazo?
I was worried about this and I think EnvironmentModifications is actually written so that things like RemovePath don't fail when the path to be removed is not present. Specifically, RemovePath.execute() doesn't try to remove the thing that should be removed -- it just takes all the paths that are not the thing, which is great. So, maybe this works fine and I do not need to worry.
lib/spack/spack/cmd/unload.py
Outdated
| print_module_placeholder_help() | ||
| env = ev.get_env(args, 'unload') | ||
| specs = list(map(lambda spec: spack.cmd.disambiguate_spec(spec, env), | ||
| spack.cmd.parse_specs(args.specs))) |
There was a problem hiding this comment.
- What happens if you load something, enter an environment, and then try to unload it? Seems like it should still succeed.
- Should loaded specs continue to be loaded if you activate an environment? Or should env activate/deactivate unload/load everything in
SPACK_LOADED_HASHES? People are going to try to use these things together. - Shouldn't this just look in
SPACK_LOADED_HASHESto disambiguate? Why does it need to search everything?
|
[edit: rainbox -> rainbows] @tgamblin --
The main alleviant [SIC?] is the trust that I have that all y'all will
Well..... There are a bunch of Issues and PR's that talk about how Seems like a slippery slope; writing and supporting more code that
Sure, but a hypothetical/mythical would (at the cost of requiring lmod in addition to whatever else I'll bet a beer if/when we ever get to meet that eventually Rather than make But, the more I argue, the more I put the lie to my opening statement. Second guessing and arm chair quarterbacking... There's more than one way to do things and every set of choices You've built something great and I'm thankful to have it in my |
|
clarification on this:
I am talking about the part that looks for an |
|
@tgamblin yes I agree. I will look over the documentation either tonight or tomorrow. |
|
This is going to require a bunch or rewriting documentation. I'll get started on it tomorrow. |
|
Just tested this branch (doing more homework for #14348). If a package is renamed or deleted (but is installed), it will no longer 'spack load'. |
36c4b24 to
740acb6
Compare
740acb6 to
640c63a
Compare
|
@aweits: the installed-package issue is an issue with the module-based |
|
This change completely alters our workflow. We liked how "spack load -r packagename" loaded the requested module and all its dependencies. we also liked that it abstracted over environment-modules vs lmod.
|
|
Suppose we were to ignore the lmod modules and let spack manage what packages are loaded on its own. Once we have done a For some context, we need to rapidly figure out how to fix our documented workflow for a tutorial. One solution would be to go back to a tagged spack release, but then we lose updates to packages that are only present in origin/develop because package descriptions are embedded in the spack repo. |
This PR actually doesn’t change how modules are generated, and it doesn’t tie anything to Or just load the package using |
Try: That will give you the list of loaded packages. You can unload them with The other way you could do this is to build your package in an environment, and |
|
I’m a bit confused about the use of |
|
The
We have a few meta-problems to circle back on later, but I'll comment on quickly here: The spack documentation is clear that it shouldn't be necessary to load dependencies (and indeed we can see that rpath has correct paths where needed), but all of our packages also use pkgconfig, and right now nothing is putting the .pc dependencies in place unless we instruct spack to load dependencies. More generally when we run into these kinds of speed bumps, we can usually find a quick solution (like the As it stands we've had some bad luck with the timing of changes to spack behavior. In this case for example, its not that we care about lmod, its just that we expected to be able to |
|
With the previous behavior one could use |
Is it impossible, or impossible with |
|
You are right, I meant impossible with |
|
Here's a gist that demonstrates an alternative approach, if you're going to go the It doesn't expose the user to the In my environment I had a plethora of spack trees, built on different dates w/ different sets of packages for different use cases. The name of the "default" release lives in a file named Here's some of the commentary from the script: # The typical user's .bash_profile would include:
#
# APPS_MODULES="emacs git htop the-silver-searcher" # and etc....
# source /moose/apps/init.sh
#
# Even setting APPS_MODULES is optional if user is ok with default list...
#
# That will:
#
# 1. Fetch the name of the "current" spack tree from the Well Known
# File if the user hasn't explicitly provided one.
# 2. Use the spack executable in that tree to ask for the location of
# the Lmod directory in that tree.
# 3. Load the Lmod bash initialization file from within that Lmod dir.
# 4. Tell Lmod to use the Core dir that spack built.
# 5. Tell Lmod to use our directory of handcrafted module files.
# 6. Load the core compiler module, which makes the bulk of the
# modulefiles accessible.
# 7. Load the user's modulefiles.
#
# There are a few things that users can customize:
# Common:
# APPS_MODULES - your list of modules to load
# e.g. APPS_MODULES="emacs git htop etc etc etc..."
# Less common:
# APPS_DIR - path to top of a Spack apps tree, e.g. a team specific tree
# (must include lmod)
# APPS_SPECIAL_MODULES_DIR - path to dir of snowflake modulefiles
# Uncommon:
# APPS_CORE_COMPILER - Compiler choice for lmod hierarch. scheme
# |


Previously the
spack loadcommand was a wrapper aroundmodule load. This required some bootstrapping of modules to makespack loadwork properly.With this PR, the
spackshell function handles the environment modifications necessary to add packages to your user environment. This removes the dependence on environment modules or lmod and removes the requirement to bootstrap spack (beyond using the setup-env scripts).Included in this PR is support for MacOS when using Apple's System Integrity Protection (SIP), which is enabled by default in modern MacOS versions. SIP clears the
LD_LIBRARY_PATHandDYLD_LIBRARY_PATHvariables on process startup for executables that live in/usr(but not '/usr/local',/System,/bin, and/sbinamong other system locations. Spack cannot know theLD_LIBRARY_PATHof the calling process when executed using/bin/shand/usr/bin/python. Thespackshell function now manually forwards these two variables, if they are present, asSPACK_<VAR>and recovers those values on startup.