Steps to reproduce
Spack's quoting of specs for the shell is currently broken for the
case of variants containing spaces. For example:
$ spack spec zlib cflags="-g -O"
==> Error: trying to set variant "O" in package "zlib",
but the package has no such variant [happened during concretization of zlib cflags="-g" ~O]
Some compiler or linker flags were provided without quoting their arguments,
which now causes spack to try to parse the *next* argument as a spec component
such as a variant instead of an additional compiler or linker flag. If the
intent was to set multiple flags, try quoting them together as described below.
Possible flag quotation errors (with the correctly-quoted version after the =>):
(1) cflags=-g -O => cflags="-g -O"
Ironically, the suggested "fix" is exactly what I wrote as the original input.
I suspect that the problem is sometime during processing the command
line, spack is passing the line as a string to the shell and failing
to properly re-quote the string in such a way that the shell will
correctly re-tokenize the string.
So, in the above example, the shell is handing spack cflags=-g -O as
a single token. But passing this to shell without any re-quoting
splits the token into two tokens cflags=-g and -O which fails
because there is no boolean variant O.
This works as a workaround:
$ spack spec zlib cflags='"-g -O"'
Here, the shell hands spack cflags="-g -O" as a single token, so
reparsing by the shell keeps cflags=-g -O together as a single
token (and also removes one level of quotes).
The above works as a workaround, but it shouldn't be necessary. You
don't want to go down the road of: "this string will be parsed by the
shell X number of times, so I need X level of quotes."
This also works as a workaround, but it shouldn't.
$ spack spec zlib cflags=\"-g -O\"
The shell will parse this as separate tokens cflags="-g and -O".
Here, -O" is an invalid variant and this should fail. Instead,
putting this together as a single string, the shell re-combines the
quotes and this "works" as cflags=-g -O.
Here's a truly strange case:
$ spack spec zlib cflags="" -g
Input spec
--------------------------------
zlib cflags="-g"
Concretized
--------------------------------
zlib@1.2.13%gcc@8.5.0 cflags="-g" +optimize+pic+shared build_system=makefile arch=linux-rhel8-zen
This should set cflags to empty and fail because -g is not a valid
variant. Instead, spack is combining two separate but adjacent
tokens. In effect, spack is trying to out-think the shell, thinking
that the user wrote cflags= -g or some such.
I believe that the basic problem is that once spack forms an internal
representation of the spec, whenever it passes it to the shell, it
should first add quotes to the tokens in such a way that the shell will
parse (and remove) the quotes to exactly reproduce the original spec.
I tracked down the problem to this commit.
commit 0c7fd9bd8ca0e38cb5a497acdfc40f51170a07f8
Author: Danny McClanahan <1305167+cosmicexplorer@users.noreply.github.com>
Date: Sat Jun 11 15:35:46 2022 -0400
fix doubly shell quoting args to `spack spec` (#29282)
* add test to verify fix works
* fix spec cflags/variants parsing test (breaking change)
* fix `spack spec` arg quoting issue
* add error report for deprecated cflags coalescing
* use .group(n) vs subscript regex group extraction for 3.5 compat
* add random test for untested functionality to pass codecov
* fix new test failure since rebase
M lib/spack/spack/cmd/__init__.py
M lib/spack/spack/cmd/spec.py
M lib/spack/spack/test/cmd/common/arguments.py
M lib/spack/spack/test/cmd/spec.py
M lib/spack/spack/test/spec_semantics.py
ping @alalazo @becker33 @cosmic
Error message
No response
Information on your system
- Spack: 0.20.0.dev0 (4e13b53)
- Python: 3.8.12
- Platform: linux-rhel8-zen2
- Concretizer: clingo
General information
Steps to reproduce
Spack's quoting of specs for the shell is currently broken for the
case of variants containing spaces. For example:
Ironically, the suggested "fix" is exactly what I wrote as the original input.
I suspect that the problem is sometime during processing the command
line, spack is passing the line as a string to the shell and failing
to properly re-quote the string in such a way that the shell will
correctly re-tokenize the string.
So, in the above example, the shell is handing spack
cflags=-g -Oasa single token. But passing this to shell without any re-quoting
splits the token into two tokens
cflags=-gand-Owhich failsbecause there is no boolean variant
O.This works as a workaround:
Here, the shell hands spack
cflags="-g -O"as a single token, soreparsing by the shell keeps
cflags=-g -Otogether as a singletoken (and also removes one level of quotes).
The above works as a workaround, but it shouldn't be necessary. You
don't want to go down the road of: "this string will be parsed by the
shell X number of times, so I need X level of quotes."
This also works as a workaround, but it shouldn't.
The shell will parse this as separate tokens
cflags="-gand-O".Here,
-O"is an invalid variant and this should fail. Instead,putting this together as a single string, the shell re-combines the
quotes and this "works" as
cflags=-g -O.Here's a truly strange case:
This should set
cflagsto empty and fail because-gis not a validvariant. Instead, spack is combining two separate but adjacent
tokens. In effect, spack is trying to out-think the shell, thinking
that the user wrote
cflags= -gor some such.I believe that the basic problem is that once spack forms an internal
representation of the spec, whenever it passes it to the shell, it
should first add quotes to the tokens in such a way that the shell will
parse (and remove) the quotes to exactly reproduce the original spec.
I tracked down the problem to this commit.
ping @alalazo @becker33 @cosmic
Error message
No response
Information on your system
General information
spack debug reportand reported the version of Spack/Python/Platform