Control Werror by converting to Wno-error (#30882)
Using `-Werror` is good practice for development and testing, but causes us a great deal of heartburn supporting multiple compiler versions, especially as newer compiler versions add warnings for released packages. This PR adds support for suppressing `-Werror` through spack's compiler wrappers. There are currently three modes for the `flags:keep_werror` setting: * `none`: (default) cancel all `-Werror`, `-Werror=*` and `-Werror-*` flags by converting them to `-Wno-error[=]*` flags * `specific`: preserve explicitly selected warnings as errors, such as `-Werror=format-truncation`, but reverse the blanket `-Werror` * `all`: keeps all `-Werror` flags These can be set globally in config.yaml, through the config command-line flags, or overridden by a particular package (some packages use Werror as a proxy for determining support for other compiler features). We chose to use this approach because: 1. removing `-Werror` flags entirely broke *many* build systems, especially autoconf based ones, because of things like checking `-Werror=feature` and making the assumption that if that did not error other flags related to that feature would also work 2. Attempting to preserve `-Werror` in some phases but not others caused similar issues 3. The per-package setting came about because some packages, even with all these protections, still use `-Werror` unsafely. Currently there are roughly 3 such packages known.
This commit is contained in:
parent
bf1b846f26
commit
0182603609
@ -214,4 +214,9 @@ config:
|
|||||||
|
|
||||||
# Number of seconds a buildcache's index.json is cached locally before probing
|
# Number of seconds a buildcache's index.json is cached locally before probing
|
||||||
# for updates, within a single Spack invocation. Defaults to 10 minutes.
|
# for updates, within a single Spack invocation. Defaults to 10 minutes.
|
||||||
binary_index_ttl: 600
|
binary_index_ttl: 600
|
||||||
|
|
||||||
|
flags:
|
||||||
|
# Whether to keep -Werror flags active in package builds.
|
||||||
|
keep_werror: 'none'
|
||||||
|
|
||||||
|
41
lib/spack/env/cc
vendored
41
lib/spack/env/cc
vendored
@ -440,6 +440,47 @@ while [ $# -ne 0 ]; do
|
|||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -n "${SPACK_COMPILER_FLAGS_KEEP}" ] ; then
|
||||||
|
# NOTE: the eval is required to allow `|` alternatives inside the variable
|
||||||
|
eval "\
|
||||||
|
case \"\$1\" in
|
||||||
|
$SPACK_COMPILER_FLAGS_KEEP)
|
||||||
|
append other_args_list \"\$1\"
|
||||||
|
shift
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
"
|
||||||
|
fi
|
||||||
|
# the replace list is a space-separated list of pipe-separated pairs,
|
||||||
|
# the first in each pair is the original prefix to be matched, the
|
||||||
|
# second is the replacement prefix
|
||||||
|
if [ -n "${SPACK_COMPILER_FLAGS_REPLACE}" ] ; then
|
||||||
|
for rep in ${SPACK_COMPILER_FLAGS_REPLACE} ; do
|
||||||
|
before=${rep%|*}
|
||||||
|
after=${rep#*|}
|
||||||
|
eval "\
|
||||||
|
stripped=\"\${1##$before}\"
|
||||||
|
"
|
||||||
|
if [ "$stripped" = "$1" ] ; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
replaced="$after$stripped"
|
||||||
|
|
||||||
|
# it matched, remove it
|
||||||
|
shift
|
||||||
|
|
||||||
|
if [ -z "$replaced" ] ; then
|
||||||
|
# completely removed, continue OUTER loop
|
||||||
|
continue 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# re-build argument list with replacement
|
||||||
|
set -- "$replaced" "$@"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
-isystem*)
|
-isystem*)
|
||||||
arg="${1#-isystem}"
|
arg="${1#-isystem}"
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
import types
|
import types
|
||||||
|
from typing import List, Tuple
|
||||||
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
from llnl.util.filesystem import install, install_tree, mkdirp
|
from llnl.util.filesystem import install, install_tree, mkdirp
|
||||||
@ -284,6 +285,23 @@ def clean_environment():
|
|||||||
return env
|
return env
|
||||||
|
|
||||||
|
|
||||||
|
def _add_werror_handling(keep_werror, env):
|
||||||
|
keep_flags = set()
|
||||||
|
# set of pairs
|
||||||
|
replace_flags = [] # type: List[Tuple[str,str]]
|
||||||
|
if keep_werror == "all":
|
||||||
|
keep_flags.add("-Werror*")
|
||||||
|
else:
|
||||||
|
if keep_werror == "specific":
|
||||||
|
keep_flags.add("-Werror-*")
|
||||||
|
keep_flags.add("-Werror=*")
|
||||||
|
# This extra case is to handle -Werror-implicit-function-declaration
|
||||||
|
replace_flags.append(("-Werror-", "-Wno-error="))
|
||||||
|
replace_flags.append(("-Werror", "-Wno-error"))
|
||||||
|
env.set("SPACK_COMPILER_FLAGS_KEEP", "|".join(keep_flags))
|
||||||
|
env.set("SPACK_COMPILER_FLAGS_REPLACE", " ".join(["|".join(item) for item in replace_flags]))
|
||||||
|
|
||||||
|
|
||||||
def set_compiler_environment_variables(pkg, env):
|
def set_compiler_environment_variables(pkg, env):
|
||||||
assert pkg.spec.concrete
|
assert pkg.spec.concrete
|
||||||
compiler = pkg.compiler
|
compiler = pkg.compiler
|
||||||
@ -330,6 +348,13 @@ def set_compiler_environment_variables(pkg, env):
|
|||||||
env.set("SPACK_DTAGS_TO_STRIP", compiler.disable_new_dtags)
|
env.set("SPACK_DTAGS_TO_STRIP", compiler.disable_new_dtags)
|
||||||
env.set("SPACK_DTAGS_TO_ADD", compiler.enable_new_dtags)
|
env.set("SPACK_DTAGS_TO_ADD", compiler.enable_new_dtags)
|
||||||
|
|
||||||
|
if pkg.keep_werror is not None:
|
||||||
|
keep_werror = pkg.keep_werror
|
||||||
|
else:
|
||||||
|
keep_werror = spack.config.get("config:flags:keep_werror")
|
||||||
|
|
||||||
|
_add_werror_handling(keep_werror, env)
|
||||||
|
|
||||||
# Set the target parameters that the compiler will add
|
# Set the target parameters that the compiler will add
|
||||||
# Don't set on cray platform because the targeting module handles this
|
# Don't set on cray platform because the targeting module handles this
|
||||||
if spec.satisfies("platform=cray"):
|
if spec.satisfies("platform=cray"):
|
||||||
|
@ -546,6 +546,10 @@ class PackageBase(WindowsRPath, PackageViewMixin, metaclass=PackageMeta):
|
|||||||
#: By default do not setup mockup XCode on macOS with Clang
|
#: By default do not setup mockup XCode on macOS with Clang
|
||||||
use_xcode = False
|
use_xcode = False
|
||||||
|
|
||||||
|
#: Keep -Werror flags, matches config:flags:keep_werror to override config
|
||||||
|
# NOTE: should be type Optional[Literal['all', 'specific', 'none']] in 3.8+
|
||||||
|
keep_werror = None # type: Optional[str]
|
||||||
|
|
||||||
#: Most packages are NOT extendable. Set to True if you want extensions.
|
#: Most packages are NOT extendable. Set to True if you want extensions.
|
||||||
extendable = False
|
extendable = False
|
||||||
|
|
||||||
|
@ -18,6 +18,12 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"default": {},
|
"default": {},
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"flags": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"keep_werror": {"type": "string", "enum": ["all", "specific", "none"]},
|
||||||
|
},
|
||||||
|
},
|
||||||
"shared_linking": {
|
"shared_linking": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{"type": "string", "enum": ["rpath", "runpath"]},
|
{"type": "string", "enum": ["rpath", "runpath"]},
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
import spack.build_environment
|
||||||
|
import spack.config
|
||||||
|
import spack.spec
|
||||||
from spack.paths import build_env_path
|
from spack.paths import build_env_path
|
||||||
from spack.util.environment import set_env, system_dirs
|
from spack.util.environment import set_env, system_dirs
|
||||||
from spack.util.executable import Executable, ProcessError
|
from spack.util.executable import Executable, ProcessError
|
||||||
@ -50,6 +53,7 @@
|
|||||||
"-llib4",
|
"-llib4",
|
||||||
"arg5",
|
"arg5",
|
||||||
"arg6",
|
"arg6",
|
||||||
|
"-DGCC_ARG_WITH_PERENS=(A B C)",
|
||||||
'"-DDOUBLE_QUOTED_ARG"',
|
'"-DDOUBLE_QUOTED_ARG"',
|
||||||
"'-DSINGLE_QUOTED_ARG'",
|
"'-DSINGLE_QUOTED_ARG'",
|
||||||
]
|
]
|
||||||
@ -101,6 +105,7 @@
|
|||||||
"-llib4",
|
"-llib4",
|
||||||
"arg5",
|
"arg5",
|
||||||
"arg6",
|
"arg6",
|
||||||
|
"-DGCC_ARG_WITH_PERENS=(A B C)",
|
||||||
'"-DDOUBLE_QUOTED_ARG"',
|
'"-DDOUBLE_QUOTED_ARG"',
|
||||||
"'-DSINGLE_QUOTED_ARG'",
|
"'-DSINGLE_QUOTED_ARG'",
|
||||||
]
|
]
|
||||||
@ -167,6 +172,8 @@ def wrapper_environment():
|
|||||||
SPACK_LINKER_ARG="-Wl,",
|
SPACK_LINKER_ARG="-Wl,",
|
||||||
SPACK_DTAGS_TO_ADD="--disable-new-dtags",
|
SPACK_DTAGS_TO_ADD="--disable-new-dtags",
|
||||||
SPACK_DTAGS_TO_STRIP="--enable-new-dtags",
|
SPACK_DTAGS_TO_STRIP="--enable-new-dtags",
|
||||||
|
SPACK_COMPILER_FLAGS_KEEP="",
|
||||||
|
SPACK_COMPILER_FLAGS_REPLACE="-Werror*",
|
||||||
):
|
):
|
||||||
yield
|
yield
|
||||||
|
|
||||||
@ -196,6 +203,22 @@ def check_args(cc, args, expected):
|
|||||||
assert expected == cc_modified_args
|
assert expected == cc_modified_args
|
||||||
|
|
||||||
|
|
||||||
|
def check_args_contents(cc, args, must_contain, must_not_contain):
|
||||||
|
"""Check output arguments that cc produces when called with args.
|
||||||
|
|
||||||
|
This assumes that cc will print debug command output with one element
|
||||||
|
per line, so that we see whether arguments that should (or shouldn't)
|
||||||
|
contain spaces are parsed correctly.
|
||||||
|
"""
|
||||||
|
with set_env(SPACK_TEST_COMMAND="dump-args"):
|
||||||
|
cc_modified_args = cc(*args, output=str).strip().split("\n")
|
||||||
|
print(cc_modified_args)
|
||||||
|
for a in must_contain:
|
||||||
|
assert a in cc_modified_args
|
||||||
|
for a in must_not_contain:
|
||||||
|
assert a not in cc_modified_args
|
||||||
|
|
||||||
|
|
||||||
def check_env_var(executable, var, expected):
|
def check_env_var(executable, var, expected):
|
||||||
"""Check environment variables updated by the passed compiler wrapper
|
"""Check environment variables updated by the passed compiler wrapper
|
||||||
|
|
||||||
@ -690,6 +713,83 @@ def test_no_ccache_prepend_for_fc(wrapper_environment):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_keep_and_replace(wrapper_environment):
|
||||||
|
werror_specific = ["-Werror=meh"]
|
||||||
|
werror = ["-Werror"]
|
||||||
|
werror_all = werror_specific + werror
|
||||||
|
with set_env(
|
||||||
|
SPACK_COMPILER_FLAGS_KEEP="",
|
||||||
|
SPACK_COMPILER_FLAGS_REPLACE="-Werror*|",
|
||||||
|
):
|
||||||
|
check_args_contents(cc, test_args + werror_all, ["-Wl,--end-group"], werror_all)
|
||||||
|
with set_env(
|
||||||
|
SPACK_COMPILER_FLAGS_KEEP="-Werror=*",
|
||||||
|
SPACK_COMPILER_FLAGS_REPLACE="-Werror*|",
|
||||||
|
):
|
||||||
|
check_args_contents(cc, test_args + werror_all, werror_specific, werror)
|
||||||
|
with set_env(
|
||||||
|
SPACK_COMPILER_FLAGS_KEEP="-Werror=*",
|
||||||
|
SPACK_COMPILER_FLAGS_REPLACE="-Werror*| -llib1| -Wl*|",
|
||||||
|
):
|
||||||
|
check_args_contents(
|
||||||
|
cc, test_args + werror_all, werror_specific, werror + ["-llib1", "-Wl,--rpath"]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"cfg_override,initial,expected,must_be_gone",
|
||||||
|
[
|
||||||
|
# Set and unset variables
|
||||||
|
(
|
||||||
|
"config:flags:keep_werror:all",
|
||||||
|
["-Werror", "-Werror=specific", "-bah"],
|
||||||
|
["-Werror", "-Werror=specific", "-bah"],
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"config:flags:keep_werror:specific",
|
||||||
|
["-Werror", "-Werror=specific", "-bah"],
|
||||||
|
["-Werror=specific", "-bah"],
|
||||||
|
["-Werror"],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"config:flags:keep_werror:none",
|
||||||
|
["-Werror", "-Werror=specific", "-bah"],
|
||||||
|
["-bah", "-Wno-error", "-Wno-error=specific"],
|
||||||
|
["-Werror", "-Werror=specific"],
|
||||||
|
),
|
||||||
|
# check non-standard -Werror opts like -Werror-implicit-function-declaration
|
||||||
|
(
|
||||||
|
"config:flags:keep_werror:all",
|
||||||
|
["-Werror", "-Werror-implicit-function-declaration", "-bah"],
|
||||||
|
["-Werror", "-Werror-implicit-function-declaration", "-bah"],
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"config:flags:keep_werror:specific",
|
||||||
|
["-Werror", "-Werror-implicit-function-declaration", "-bah"],
|
||||||
|
["-Werror-implicit-function-declaration", "-bah", "-Wno-error"],
|
||||||
|
["-Werror"],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"config:flags:keep_werror:none",
|
||||||
|
["-Werror", "-Werror-implicit-function-declaration", "-bah"],
|
||||||
|
["-bah", "-Wno-error=implicit-function-declaration"],
|
||||||
|
["-Werror", "-Werror-implicit-function-declaration"],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@pytest.mark.usefixtures("wrapper_environment", "mutable_config")
|
||||||
|
def test_flag_modification(cfg_override, initial, expected, must_be_gone):
|
||||||
|
spack.config.add(cfg_override)
|
||||||
|
env = spack.build_environment.clean_environment()
|
||||||
|
|
||||||
|
keep_werror = spack.config.get("config:flags:keep_werror")
|
||||||
|
spack.build_environment._add_werror_handling(keep_werror, env)
|
||||||
|
env.apply_modifications()
|
||||||
|
check_args_contents(cc, test_args[:3] + initial, expected, must_be_gone)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.regression("9160")
|
@pytest.mark.regression("9160")
|
||||||
def test_disable_new_dtags(wrapper_environment, wrapper_flags):
|
def test_disable_new_dtags(wrapper_environment, wrapper_flags):
|
||||||
with set_env(SPACK_TEST_COMMAND="dump-args"):
|
with set_env(SPACK_TEST_COMMAND="dump-args"):
|
||||||
|
@ -29,6 +29,7 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage):
|
|||||||
git = "git://gcc.gnu.org/git/gcc.git"
|
git = "git://gcc.gnu.org/git/gcc.git"
|
||||||
list_url = "https://ftp.gnu.org/gnu/gcc/"
|
list_url = "https://ftp.gnu.org/gnu/gcc/"
|
||||||
list_depth = 1
|
list_depth = 1
|
||||||
|
keep_werror = "all"
|
||||||
|
|
||||||
maintainers = ["michaelkuhn", "alalazo"]
|
maintainers = ["michaelkuhn", "alalazo"]
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ class RdmaCore(CMakePackage):
|
|||||||
homepage = "https://github.com/linux-rdma/rdma-core"
|
homepage = "https://github.com/linux-rdma/rdma-core"
|
||||||
url = "https://github.com/linux-rdma/rdma-core/releases/download/v17.1/rdma-core-17.1.tar.gz"
|
url = "https://github.com/linux-rdma/rdma-core/releases/download/v17.1/rdma-core-17.1.tar.gz"
|
||||||
libraries = ["librdmacm.so"]
|
libraries = ["librdmacm.so"]
|
||||||
|
keep_werror = "all"
|
||||||
|
|
||||||
version("41.0", sha256="e0b7deb8a71f229796a0cfe0fa25192c530cd3d86b755b6b28d1a5986a77507b")
|
version("41.0", sha256="e0b7deb8a71f229796a0cfe0fa25192c530cd3d86b755b6b28d1a5986a77507b")
|
||||||
version("40.0", sha256="8844edb71311e3212e55e28fa4bdc6e06dd6c7b839ed56ee4b606e4220d94ee8")
|
version("40.0", sha256="8844edb71311e3212e55e28fa4bdc6e06dd6c7b839ed56ee4b606e4220d94ee8")
|
||||||
|
Loading…
Reference in New Issue
Block a user