summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorChris Green <greenc@fnal.gov>2018-06-08 15:49:31 -0500
committerscheibelp <scheibel1@llnl.gov>2018-06-08 13:49:31 -0700
commit15c98fa57c0022df3c3788f19b3febd484d8ccd7 (patch)
treef285eb74e697f4ff2ad581eee8c3d69c06a5a7d7 /lib
parentceb2790f30c5ad5a9d90121057bb93f45448778e (diff)
downloadspack-15c98fa57c0022df3c3788f19b3febd484d8ccd7.tar.gz
spack-15c98fa57c0022df3c3788f19b3febd484d8ccd7.tar.bz2
spack-15c98fa57c0022df3c3788f19b3febd484d8ccd7.tar.xz
spack-15c98fa57c0022df3c3788f19b3febd484d8ccd7.zip
compiler flags: add cxx98 standard support (#7601)
The following improvements are made to cxx standard support (e.g. compiler.cxxNN_flag functions) in compilers: * Add cxx98_flag property * Add support for throwing an exception when a flag is not supported (previously if a flag was not supported the application was terminated with tty.die) * The name of the flag associated with e.g. c++14 standard support changes for different compiler versions (e.g. c++1y vs c++14). This makes a few corrections on what flag to return for which version. * Added tests to confirm that versions report expected flags for various c++ standards (or raise an exception for versions that don't provide a given cxx standard) Note that if a given cxx standard is the default, the associated flag property will return ""; cxx98 is assumed to be the default standard so this is the behavior for the associated property in the base compiler class. Package changes: * Improvements to the boost spec to take advantage of the improved standard flag facility. * Update the clingo spec to catch the new exception rather than look for an empty flag to indicate non-support (which is not part of the compiler flag API)
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/docs/packaging_guide.rst4
-rw-r--r--lib/spack/spack/compiler.py48
-rw-r--r--lib/spack/spack/compilers/clang.py43
-rw-r--r--lib/spack/spack/compilers/gcc.py35
-rw-r--r--lib/spack/spack/compilers/intel.py16
-rw-r--r--lib/spack/spack/compilers/xl.py10
-rw-r--r--lib/spack/spack/compilers/xl_r.py10
-rw-r--r--lib/spack/spack/test/compilers.py169
8 files changed, 285 insertions, 50 deletions
diff --git a/lib/spack/docs/packaging_guide.rst b/lib/spack/docs/packaging_guide.rst
index ca21092f26..34be562c29 100644
--- a/lib/spack/docs/packaging_guide.rst
+++ b/lib/spack/docs/packaging_guide.rst
@@ -2654,8 +2654,8 @@ In rare circumstances such as compiling and running small unit tests, a
package developer may need to know what are the appropriate compiler
flags to enable features like ``OpenMP``, ``c++11``, ``c++14`` and
alike. To that end the compiler classes in ``spack`` implement the
-following **properties**: ``openmp_flag``, ``cxx11_flag``,
-``cxx14_flag``, which can be accessed in a package by
+following **properties**: ``openmp_flag``, ``cxx98_flag``, ``cxx11_flag``,
+``cxx14_flag``, and ``cxx17_flag``, which can be accessed in a package by
``self.compiler.cxx11_flag`` and alike. Note that the implementation is
such that if a given compiler version does not support this feature, an
error will be produced. Therefore package developers can also use these
diff --git a/lib/spack/spack/compiler.py b/lib/spack/spack/compiler.py
index 6d9742150e..b219eee09d 100644
--- a/lib/spack/spack/compiler.py
+++ b/lib/spack/spack/compiler.py
@@ -178,40 +178,40 @@ class Compiler(object):
@property
def openmp_flag(self):
# If it is not overridden, assume it is not supported and warn the user
- tty.die(
- "The compiler you have chosen does not currently support OpenMP.",
- "If you think it should, please edit the compiler subclass and",
- "submit a pull request or issue.")
+ raise UnsupportedCompilerFlag(self, "OpenMP", "openmp_flag")
+
+ # This property should be overridden in the compiler subclass if
+ # C++98 is not the default standard for that compiler
+ @property
+ def cxx98_flag(self):
+ return ""
# This property should be overridden in the compiler subclass if
# C++11 is supported by that compiler
@property
def cxx11_flag(self):
# If it is not overridden, assume it is not supported and warn the user
- tty.die(
- "The compiler you have chosen does not currently support C++11.",
- "If you think it should, please edit the compiler subclass and",
- "submit a pull request or issue.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++11 standard",
+ "cxx11_flag")
# This property should be overridden in the compiler subclass if
# C++14 is supported by that compiler
@property
def cxx14_flag(self):
# If it is not overridden, assume it is not supported and warn the user
- tty.die(
- "The compiler you have chosen does not currently support C++14.",
- "If you think it should, please edit the compiler subclass and",
- "submit a pull request or issue.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++14 standard",
+ "cxx14_flag")
# This property should be overridden in the compiler subclass if
# C++17 is supported by that compiler
@property
def cxx17_flag(self):
# If it is not overridden, assume it is not supported and warn the user
- tty.die(
- "The compiler you have chosen does not currently support C++17.",
- "If you think it should, please edit the compiler subclass and",
- "submit a pull request or issue.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++17 standard",
+ "cxx17_flag")
#
# Compiler classes have methods for querying the version of
@@ -339,3 +339,19 @@ class InvalidCompilerError(spack.error.SpackError):
def __init__(self):
super(InvalidCompilerError, self).__init__(
"Compiler has no executables.")
+
+
+class UnsupportedCompilerFlag(spack.error.SpackError):
+
+ def __init__(self, compiler, feature, flag_name, ver_string=None):
+ super(UnsupportedCompilerFlag, self).__init__(
+ "{0} ({1}) does not support {2} (as compiler.{3})."
+ .format(compiler.name,
+ ver_string if ver_string else compiler.version,
+ feature,
+ flag_name),
+ "If you think it should, please edit the compiler.{0} subclass to"
+ .format(compiler.name) +
+ " implement the {0} property and submit a pull request or issue."
+ .format(flag_name)
+ )
diff --git a/lib/spack/spack/compilers/clang.py b/lib/spack/spack/compilers/clang.py
index ce54e49c79..2aa958ab91 100644
--- a/lib/spack/spack/compilers/clang.py
+++ b/lib/spack/spack/compilers/clang.py
@@ -30,7 +30,7 @@ from shutil import copytree, ignore_patterns
import llnl.util.tty as tty
import spack.paths
-from spack.compiler import Compiler, _version_cache
+from spack.compiler import Compiler, _version_cache, UnsupportedCompilerFlag
from spack.util.executable import Executable
from spack.version import ver
@@ -69,7 +69,10 @@ class Clang(Compiler):
@property
def openmp_flag(self):
if self.is_apple:
- tty.die("Clang from Apple does not support Openmp yet.")
+ raise UnsupportedCompilerFlag(self,
+ "OpenMP",
+ "openmp_flag",
+ "Xcode {0}".format(self.version))
else:
return "-fopenmp"
@@ -77,14 +80,20 @@ class Clang(Compiler):
def cxx11_flag(self):
if self.is_apple:
# Adapted from CMake's AppleClang-CXX rules
- # Spack's AppleClang detection only valid form Xcode >= 4.6
+ # Spack's AppleClang detection only valid from Xcode >= 4.6
if self.version < ver('4.0.0'):
- tty.die("Only Apple LLVM 4.0 and above support c++11")
+ raise UnsupportedCompilerFlag(self,
+ "the C++11 standard",
+ "cxx11_flag",
+ "Xcode < 4.0.0")
else:
return "-std=c++11"
else:
if self.version < ver('3.3'):
- tty.die("Only Clang 3.3 and above support c++11.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++11 standard",
+ "cxx11_flag",
+ "< 3.3")
else:
return "-std=c++11"
@@ -93,14 +102,20 @@ class Clang(Compiler):
if self.is_apple:
# Adapted from CMake's rules for AppleClang
if self.version < ver('5.1.0'):
- tty.die("Only Apple LLVM 5.1 and above support c++14.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++14 standard",
+ "cxx14_flag",
+ "Xcode < 5.1.0")
elif self.version < ver('6.1.0'):
return "-std=c++1y"
else:
return "-std=c++14"
else:
if self.version < ver('3.4'):
- tty.die("Only Clang 3.4 and above support c++14.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++14 standard",
+ "cxx14_flag",
+ "< 3.5")
elif self.version < ver('3.5'):
return "-std=c++1y"
else:
@@ -111,14 +126,22 @@ class Clang(Compiler):
if self.is_apple:
# Adapted from CMake's rules for AppleClang
if self.version < ver('6.1.0'):
- tty.die("Only Apple LLVM 6.1 and above support c++17.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++17 standard",
+ "cxx17_flag",
+ "Xcode < 6.1.0")
else:
return "-std=c++1z"
else:
if self.version < ver('3.5'):
- tty.die("Only Clang 3.5 and above support c++17.")
- else:
+ raise UnsupportedCompilerFlag(self,
+ "the C++17 standard",
+ "cxx17_flag",
+ "< 5.0")
+ elif self.version < ver('5.0'):
return "-std=c++1z"
+ else:
+ return "-std=c++17"
@property
def pic_flag(self):
diff --git a/lib/spack/spack/compilers/gcc.py b/lib/spack/spack/compilers/gcc.py
index e52dd5c047..489e87e544 100644
--- a/lib/spack/spack/compilers/gcc.py
+++ b/lib/spack/spack/compilers/gcc.py
@@ -22,10 +22,9 @@
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
-import llnl.util.tty as tty
-
import spack.compilers.clang
-from spack.compiler import Compiler, get_compiler_version
+from spack.compiler import \
+ Compiler, get_compiler_version, UnsupportedCompilerFlag
from spack.version import ver
@@ -61,9 +60,19 @@ class Gcc(Compiler):
return "-fopenmp"
@property
+ def cxx98_flag(self):
+ if self.version < ver('6.0'):
+ return ""
+ else:
+ return "-std=c++98"
+
+ @property
def cxx11_flag(self):
if self.version < ver('4.3'):
- tty.die("Only gcc 4.3 and above support c++11.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++11 standard",
+ "cxx11_flag",
+ " < 4.3")
elif self.version < ver('4.7'):
return "-std=c++0x"
else:
@@ -72,18 +81,28 @@ class Gcc(Compiler):
@property
def cxx14_flag(self):
if self.version < ver('4.8'):
- tty.die("Only gcc 4.8 and above support c++14.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++14 standard",
+ "cxx14_flag",
+ "< 4.8")
elif self.version < ver('4.9'):
return "-std=c++1y"
- else:
+ elif self.version < ver('6.0'):
return "-std=c++14"
+ else:
+ return ""
@property
def cxx17_flag(self):
if self.version < ver('5.0'):
- tty.die("Only gcc 5.0 and above support c++17.")
- else:
+ raise UnsupportedCompilerFlag(self,
+ "the C++17 standard",
+ "cxx17_flag",
+ "< 5.0")
+ elif self.version < ver('6.0'):
return "-std=c++1z"
+ else:
+ return "-std=c++17"
@property
def pic_flag(self):
diff --git a/lib/spack/spack/compilers/intel.py b/lib/spack/spack/compilers/intel.py
index 0c5ba3ab40..962120362e 100644
--- a/lib/spack/spack/compilers/intel.py
+++ b/lib/spack/spack/compilers/intel.py
@@ -22,9 +22,8 @@
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
-import llnl.util.tty as tty
-
-from spack.compiler import Compiler, get_compiler_version
+from spack.compiler import \
+ Compiler, get_compiler_version, UnsupportedCompilerFlag
from spack.version import ver
@@ -60,7 +59,11 @@ class Intel(Compiler):
@property
def cxx11_flag(self):
if self.version < ver('11.1'):
- tty.die("Only intel 11.1 and above support c++11.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++11 standard",
+ "cxx11_flag",
+ "< 11.1")
+
elif self.version < ver('13'):
return "-std=c++0x"
else:
@@ -70,7 +73,10 @@ class Intel(Compiler):
def cxx14_flag(self):
# Adapted from CMake's Intel-CXX rules.
if self.version < ver('15'):
- tty.die("Only intel 15.0 and above support c++14.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++14 standard",
+ "cxx14_flag",
+ "< 15")
elif self.version < ver('15.0.2'):
return "-std=c++1y"
else:
diff --git a/lib/spack/spack/compilers/xl.py b/lib/spack/spack/compilers/xl.py
index 7b5bd3994b..4448efbb98 100644
--- a/lib/spack/spack/compilers/xl.py
+++ b/lib/spack/spack/compilers/xl.py
@@ -22,9 +22,8 @@
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
-import llnl.util.tty as tty
-
-from spack.compiler import Compiler, get_compiler_version
+from spack.compiler import \
+ Compiler, get_compiler_version, UnsupportedCompilerFlag
from spack.version import ver
@@ -54,7 +53,10 @@ class Xl(Compiler):
@property
def cxx11_flag(self):
if self.version < ver('13.1'):
- tty.die("Only xlC 13.1 and above have some c++11 support.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++11 standard",
+ "cxx11_flag",
+ "< 13.1")
else:
return "-qlanglvl=extended0x"
diff --git a/lib/spack/spack/compilers/xl_r.py b/lib/spack/spack/compilers/xl_r.py
index 774db363af..9aa12a03ce 100644
--- a/lib/spack/spack/compilers/xl_r.py
+++ b/lib/spack/spack/compilers/xl_r.py
@@ -23,9 +23,8 @@
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
-import llnl.util.tty as tty
-
-from spack.compiler import Compiler, get_compiler_version
+from spack.compiler import \
+ Compiler, get_compiler_version, UnsupportedCompilerFlag
from spack.version import ver
@@ -55,7 +54,10 @@ class XlR(Compiler):
@property
def cxx11_flag(self):
if self.version < ver('13.1'):
- tty.die("Only xlC 13.1 and above have some c++11 support.")
+ raise UnsupportedCompilerFlag(self,
+ "the C++11 standard",
+ "cxx11_flag",
+ "< 13.1")
else:
return "-qlanglvl=extended0x"
diff --git a/lib/spack/spack/test/compilers.py b/lib/spack/spack/test/compilers.py
index 2c9d68f674..4e14641b63 100644
--- a/lib/spack/spack/test/compilers.py
+++ b/lib/spack/spack/test/compilers.py
@@ -22,11 +22,12 @@
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
+from copy import copy
from six import iteritems
import spack.spec
import spack.compilers as compilers
-from spack.compiler import _get_versioned_tuple
+from spack.compiler import _get_versioned_tuple, Compiler
def test_get_compiler_duplicates(config):
@@ -79,3 +80,169 @@ def test_compiler_flags_from_config_are_grouped():
compiler = compilers.compiler_from_config_entry(compiler_entry)
assert any(x == '-foo-flag foo-val' for x in compiler.flags['cflags'])
+
+
+# Test behavior of flags and UnsupportedCompilerFlag.
+
+# Utility function to test most flags.
+default_compiler_entry = {
+ 'spec': 'clang@2.0.0-apple',
+ 'operating_system': 'foo-os',
+ 'paths': {
+ 'cc': 'cc-path',
+ 'cxx': 'cxx-path',
+ 'fc': None,
+ 'f77': None
+ },
+ 'flags': {},
+ 'modules': None
+}
+
+
+# Fake up a mock compiler where everything is defaulted.
+class MockCompiler(Compiler):
+ def __init__(self):
+ super(MockCompiler, self).__init__(
+ "badcompiler@1.0.0",
+ default_compiler_entry['operating_system'],
+ None,
+ [default_compiler_entry['paths']['cc'],
+ default_compiler_entry['paths']['cxx'],
+ default_compiler_entry['paths']['fc'],
+ default_compiler_entry['paths']['f77']])
+
+ @property
+ def name(self):
+ return "mockcompiler"
+
+ @property
+ def version(self):
+ return "1.0.0"
+
+
+# Get the desired flag from the specified compiler spec.
+def flag_value(flag, spec):
+ compiler = None
+ if spec is None:
+ compiler = MockCompiler()
+ else:
+ compiler_entry = copy(default_compiler_entry)
+ compiler_entry['spec'] = spec
+ # Disable faulty id()-based cache (issue #7647).
+ compilers._compiler_cache = {}
+ compiler = compilers.compiler_from_config_entry(compiler_entry)
+
+ return getattr(compiler, flag)
+
+
+# Utility function to verify that the expected exception is thrown for
+# an unsupported flag.
+def unsupported_flag_test(flag, spec=None):
+ caught_exception = None
+ try:
+ flag_value(flag, spec)
+ except spack.compiler.UnsupportedCompilerFlag:
+ caught_exception = True
+
+ assert(caught_exception and "Expected exception not thrown.")
+
+
+# Verify the expected flag value for the give compiler spec.
+def supported_flag_test(flag, flag_value_ref, spec=None):
+ assert(flag_value(flag, spec) == flag_value_ref)
+
+
+# Tests for UnsupportedCompilerFlag exceptions from default
+# implementations of flags.
+def test_default_flags():
+ unsupported_flag_test("openmp_flag")
+ unsupported_flag_test("cxx11_flag")
+ unsupported_flag_test("cxx14_flag")
+ unsupported_flag_test("cxx17_flag")
+ supported_flag_test("cxx98_flag", "")
+
+
+# Verify behavior of particular compiler definitions.
+def test_clang_flags():
+ # Common
+ supported_flag_test("pic_flag", "-fPIC", "gcc@4.0")
+
+ # Apple Clang.
+ unsupported_flag_test("openmp_flag", "clang@2.0.0-apple")
+ unsupported_flag_test("cxx11_flag", "clang@2.0.0-apple")
+ supported_flag_test("cxx11_flag", "-std=c++11", "clang@4.0.0-apple")
+ unsupported_flag_test("cxx14_flag", "clang@5.0.0-apple")
+ supported_flag_test("cxx14_flag", "-std=c++1y", "clang@5.1.0-apple")
+ supported_flag_test("cxx14_flag", "-std=c++14", "clang@6.1.0-apple")
+ unsupported_flag_test("cxx17_flag", "clang@6.0.0-apple")
+ supported_flag_test("cxx17_flag", "-std=c++1z", "clang@6.1.0-apple")
+
+ # non-Apple Clang.
+ supported_flag_test("openmp_flag", "-fopenmp", "clang@3.3")
+ unsupported_flag_test("cxx11_flag", "clang@3.2")
+ supported_flag_test("cxx11_flag", "-std=c++11", "clang@3.3")
+ unsupported_flag_test("cxx14_flag", "clang@3.3")
+ supported_flag_test("cxx14_flag", "-std=c++1y", "clang@3.4")
+ supported_flag_test("cxx14_flag", "-std=c++14", "clang@3.5")
+ unsupported_flag_test("cxx17_flag", "clang@3.4")
+ supported_flag_test("cxx17_flag", "-std=c++1z", "clang@3.5")
+ supported_flag_test("cxx17_flag", "-std=c++17", "clang@5.0")
+
+
+def test_cce_flags():
+ supported_flag_test("openmp_flag", "-h omp", "cce@1.0")
+ supported_flag_test("cxx11_flag", "-h std=c++11", "cce@1.0")
+ supported_flag_test("pic_flag", "-h PIC", "cce@1.0")
+
+
+def test_gcc_flags():
+ supported_flag_test("openmp_flag", "-fopenmp", "gcc@4.1")
+ supported_flag_test("cxx98_flag", "", "gcc@5.2")
+ supported_flag_test("cxx98_flag", "-std=c++98", "gcc@6.0")
+ unsupported_flag_test("cxx11_flag", "gcc@4.2")
+ supported_flag_test("cxx11_flag", "-std=c++0x", "gcc@4.3")
+ supported_flag_test("cxx11_flag", "-std=c++11", "gcc@4.7")
+ unsupported_flag_test("cxx14_flag", "gcc@4.7")
+ supported_flag_test("cxx14_flag", "-std=c++1y", "gcc@4.8")
+ supported_flag_test("cxx14_flag", "-std=c++14", "gcc@4.9")
+ supported_flag_test("cxx14_flag", "", "gcc@6.0")
+ unsupported_flag_test("cxx17_flag", "gcc@4.9")
+ supported_flag_test("pic_flag", "-fPIC", "gcc@4.0")
+
+
+def test_intel_flags():
+ supported_flag_test("openmp_flag", "-openmp", "intel@15.0")
+ supported_flag_test("openmp_flag", "-qopenmp", "intel@16.0")
+ unsupported_flag_test("cxx11_flag", "intel@11.0")
+ supported_flag_test("cxx11_flag", "-std=c++0x", "intel@12.0")
+ supported_flag_test("cxx11_flag", "-std=c++11", "intel@13")
+ unsupported_flag_test("cxx14_flag", "intel@14.0")
+ supported_flag_test("cxx14_flag", "-std=c++1y", "intel@15.0")
+ supported_flag_test("cxx14_flag", "-std=c++14", "intel@15.0.2")
+ supported_flag_test("pic_flag", "-fPIC", "intel@1.0")
+
+
+def test_nag_flags():
+ supported_flag_test("openmp_flag", "-openmp", "nag@1.0")
+ supported_flag_test("cxx11_flag", "-std=c++11", "nag@1.0")
+ supported_flag_test("pic_flag", "-PIC", "nag@1.0")
+
+
+def test_pgi_flags():
+ supported_flag_test("openmp_flag", "-mp", "pgi@1.0")
+ supported_flag_test("cxx11_flag", "-std=c++11", "pgi@1.0")
+ supported_flag_test("pic_flag", "-fpic", "pgi@1.0")
+
+
+def test_xl_flags():
+ supported_flag_test("openmp_flag", "-qsmp=omp", "xl@1.0")
+ unsupported_flag_test("cxx11_flag", "xl@13.0")
+ supported_flag_test("cxx11_flag", "-qlanglvl=extended0x", "xl@13.1")
+ supported_flag_test("pic_flag", "-qpic", "xl@1.0")
+
+
+def test_xl_r_flags():
+ supported_flag_test("openmp_flag", "-qsmp=omp", "xl_r@1.0")
+ unsupported_flag_test("cxx11_flag", "xl_r@13.0")
+ supported_flag_test("cxx11_flag", "-qlanglvl=extended0x", "xl_r@13.1")
+ supported_flag_test("pic_flag", "-qpic", "xl_r@1.0")