Open carns opened 2 years ago
This seems an interesting use case. We don't analyze compiler flags to automatically check for conflicts in them, and doing so is probably a daunting task. What we might be able to do though is to let the users customize, e.g. in packages.yaml
, the directives being present in the packages by extending them.
The idea is that, if you could express in your environment that each package needs to be augmented with:
conflicts('cflags="-fsanitize=address -fno-omit-frame-pointer -g -Wall"')
you'll be able to solve the issues with --reuse
.
@tgamblin @becker33 Do you have any thoughts on this?
Two things:
I actually don't have any problem with adding (gradually) constraints for particular compiler flags. I don't think we have to do it for all of them but we can pretty easily make it possible for folks to contribute conflicts in, say, a separate .lp
file next to concretize.lp
. We've already talked about adding more compatibility rules for OS's.
We likely need flag rules anyway -- to manage how linking is done for particular packages, particularly for compiler interop. So I'm actually not opposed to doing this the "right "way - I just don't think it has to happen all at once.
I'm not sure it's a bug if you ask for global reuse and get the previously compiled json-c
with address sanitizer options, though I can see why you would want that particular flag to omit an install from consideration. I think it's probably more of a bug if something depends on json-c
and reuses a sanitized build accidentally. You probably want some constraints like:
:- depends_on(Package, Dependency, "link"),
node_flag(Package, "-fsanitize=address"), not node_flag(Dependency, "-fsanitize=address").
:- depends_on(Package, Dependency, "link"),
not node_flag(Package, "-fsanitize=address"), node_flag(Dependency, "-fsanitize=address").
So that the solver can't pick the sanitized binary if the root isn't sanitized, or vice versa. Or, really, we should generalize that and just have certain flags that need to be together for compatibility:
:- depends_on(Package, Dependency, "link"), synced_flag(Flag),
node_flag(Package, Flag), not node_flag(Dependency, Flag).
:- depends_on(Package, Dependency, "link"), synced_flag(Flag),
not node_flag(Package, Flag), node_flag(Dependency, Flag).
synced_flag("-fsanitize=address").
% etc.
@tgamblin Slightly OT but for 1. look at https://github.com/spack/spack/pull/28941 which changed the reuse
argument to accept a list of specs instead of being just a boolean:
With that API change it should be easy to pick any set of specs we want to be reused into a solve.
Thanks for considering this.
FWIW, I actually would like the ability to reuse packages across environments (as long as the full spec, including flags, variants, etc. matches exactly).
My use case is maybe a little odd. I have many spack environments that I use on my laptop. I help to maintain several packages in a dependency chain, for example x->y->z. If I'm working on z, then I activate an environment that has y as a root spec so that I can compile/develop/debug z by hand. If I'm working on y, then I activate an environment that has x as a root spec so that I can compile/develop/debug y by hand. Both of them may as well use the same x. In practice they probably share more like a dozen common dependencies.
That much works fine. The problem that prompted this issue report is that rather than having one environment to work on z in the above example, I actually have at least two. One of them may be called "z-dev" and has all sorts of debugging variants, cflags, etc. set that help me write correct code. One of them may be called "z-fast" and is built for speed with no debugging variants or sanitizers. I switch over to the latter to sanity check microbenchmarks to make sure the code is fast, and not just correct.
So for this use case I would like cross-environment reuse (because I have many environments that might share dozens of identical dependencies) yet I need them to not mix and match explicit cflags and variants because at any given time I really need my entire collection of packages to be built either all for debugging or all for speed. It really ends up being worse than just 2 categories of packages (debug or speed) because I might use multiple debugging tools that are incompatible and thus end up with multiple dev environments. As a concrete example, address sanitizer and valgrind do not get along, but neither covers a proper subset of the checks that the other does, so sometimes you need both to track down a problem. So then you have one build with address sanitizer, one with debugging symbols and some debugging variants, and one built for speed.
I think for the time being my work flow the safest thing is for me to avoid --reuse, accept that I'm going to have some duplicate packages installed, and use spack gc
to clean things up when it seems like it's getting out of hand. If I had some kind of flag to set that told --reuse to not just consider the package name and version, but the full spec precisely, then that would cover my use case. I don't actually want to try to figure out which subsets of flags are compatible per se, I would be fine just knowing if they are an exact match or not.
Steps to reproduce
I'm using the json-c package with address sanitizer options as a simple example, but this bug isn't particular to that package or those options, it's just an illustration.
I start by creating two different environment configurations, they are identical except that one sets custom cflags and ldflags for development/debugging purposes:
I then create an environment using the yaml that specifies custom
cflags
andldflags
:And finally I create another environment, without the custom
cflags
orldflags
, and install using the--reuse
option:The second environment reused the package from the previous environment that had been compiled with address sanitizer options, even though they weren't requested in this one.
I'm not exactly sure if that is a bug, but it is surprising to me so I thought I would report it. I maintain a variety of software packages and like being able to switch back and forth between different build scenarios for development and debugging. I would like to use the
--reuse
option to avoid piling up so many packages when I switch back and forth between development efforts, but I can't because it pollutes the build environment when I do that.Error message
There is no error. I was just surprised that spack would reuse packages with differing build options.
Information on your system
General information
spack debug report
and reported the version of Spack/Python/Platform