diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/spack/docs/packaging_guide.rst | 4 | ||||
-rw-r--r-- | lib/spack/spack/compiler.py | 48 | ||||
-rw-r--r-- | lib/spack/spack/compilers/clang.py | 43 | ||||
-rw-r--r-- | lib/spack/spack/compilers/gcc.py | 35 | ||||
-rw-r--r-- | lib/spack/spack/compilers/intel.py | 16 | ||||
-rw-r--r-- | lib/spack/spack/compilers/xl.py | 10 | ||||
-rw-r--r-- | lib/spack/spack/compilers/xl_r.py | 10 | ||||
-rw-r--r-- | lib/spack/spack/test/compilers.py | 169 |
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") |