Bug Fix : Apply Compiler Flags Specified by Manual Compiler Configuration (#1532)

* Fixed a bug causing config-specified compiler flags to be ignored.
Updated the compiler config so all flags are in a separate section.

* Updated the documentation for the `compilers.yaml` file spec.

* Implemented basic testing for the 'flags' section of compiler config.

* Fixed a few minor problems with the manual compiler config documentation.
This commit is contained in:
Joseph Ciurej 2016-10-24 14:37:03 -07:00 committed by Todd Gamblin
parent e35c023c61
commit 7dd14870ce
7 changed files with 138 additions and 65 deletions

View File

@ -218,12 +218,14 @@ If you want to see specifics on a particular compiler, you can run
$ spack compiler info intel@15 $ spack compiler info intel@15
intel@15.0.0: intel@15.0.0:
paths:
cc = /usr/local/bin/icc-15.0.090 cc = /usr/local/bin/icc-15.0.090
cxx = /usr/local/bin/icpc-15.0.090 cxx = /usr/local/bin/icpc-15.0.090
f77 = /usr/local/bin/ifort-15.0.090 f77 = /usr/local/bin/ifort-15.0.090
fc = /usr/local/bin/ifort-15.0.090 fc = /usr/local/bin/ifort-15.0.090
modules = [] modules = []
operating system = centos6 operating system = centos6
...
This shows which C, C++, and Fortran compilers were detected by Spack. This shows which C, C++, and Fortran compilers were detected by Spack.
Notice also that we didn't have to be too specific about the Notice also that we didn't have to be too specific about the
@ -244,7 +246,7 @@ Each compiler configuration in the file looks like this:
compilers: compilers:
- compiler: - compiler:
modules = [] modules: []
operating_system: centos6 operating_system: centos6
paths: paths:
cc: /usr/local/bin/icc-15.0.024-beta cc: /usr/local/bin/icc-15.0.024-beta
@ -253,39 +255,46 @@ Each compiler configuration in the file looks like this:
fc: /usr/local/bin/ifort-15.0.024-beta fc: /usr/local/bin/ifort-15.0.024-beta
spec: intel@15.0.0: spec: intel@15.0.0:
For compilers, like ``clang``, that do not support Fortran, put For compilers that do not support Fortran (like ``clang``), put
``None`` for ``f77`` and ``fc``: ``None`` for ``f77`` and ``fc``:
.. code-block:: yaml
paths:
cc: /usr/bin/clang
cxx: /usr/bin/clang++
f77: None
fc: None
spec: clang@3.3svn:
Once you save the file, the configured compilers will show up in the
list displayed by ``spack compilers``.
You can also add compiler flags to manually configured compilers. The
valid flags are ``cflags``, ``cxxflags``, ``fflags``, ``cppflags``,
``ldflags``, and ``ldlibs``. For example:
.. code-block:: yaml .. code-block:: yaml
compilers: compilers:
- compiler: - compiler:
modules = [] modules: []
operating_system: OS operating_system: centos6
paths: paths:
cc: /usr/local/bin/icc-15.0.024-beta cc: /usr/bin/clang
cxx: /usr/local/bin/icpc-15.0.024-beta cxx: /usr/bin/clang++
f77: /usr/local/bin/ifort-15.0.024-beta f77: None
fc: /usr/local/bin/ifort-15.0.024-beta fc: None
spec: clang@3.3svn
Once you save the file, the configured compilers will show up in the
list displayed by ``spack compilers``.
You can also add compiler flags to manually configured compilers. These
flags should be specified in the ``flags`` section of the compiler
specification. The valid flags are ``cflags``, ``cxxflags``, ``fflags``,
``cppflags``, ``ldflags``, and ``ldlibs``. For example:
.. code-block:: yaml
compilers:
- compiler:
modules: []
operating_system: centos6
paths:
cc: /usr/bin/gcc
cxx: /usr/bin/g++
f77: /usr/bin/gfortran
fc: /usr/bin/gfortran
flags: flags:
cflags: -O3 -fPIC
cxxflags: -O3 -fPIC
cppflags: -O3 -fPIC cppflags: -O3 -fPIC
spec: intel@15.0.0: spec: gcc@4.7.2
These flags will be treated by spack as if they were entered from These flags will be treated by spack as if they were entered from
the command line each time this compiler is used. The compiler wrappers the command line each time this compiler is used. The compiler wrappers
@ -527,7 +536,7 @@ configuration in ``compilers.yaml`` illustrates this technique:
compilers: compilers:
- compiler: - compiler:
modules = [gcc-4.9.3, intel-15.0.24] modules: [gcc-4.9.3, intel-15.0.24]
operating_system: centos7 operating_system: centos7
paths: paths:
cc: /opt/intel-15.0.24/bin/icc-15.0.24-beta cc: /opt/intel-15.0.24/bin/icc-15.0.24-beta
@ -568,7 +577,7 @@ flags to the ``icc`` command:
compilers: compilers:
- compiler: - compiler:
modules = [intel-15.0.24] modules: [intel-15.0.24]
operating_system: centos7 operating_system: centos7
paths: paths:
cc: /opt/intel-15.0.24/bin/icc-15.0.24-beta cc: /opt/intel-15.0.24/bin/icc-15.0.24-beta

View File

@ -133,10 +133,13 @@ def compiler_info(args):
else: else:
for c in compilers: for c in compilers:
print str(c.spec) + ":" print str(c.spec) + ":"
print "\tcc = %s" % c.cc print "\tpaths:"
print "\tcxx = %s" % c.cxx for cpath in ['cc', 'cxx', 'f77', 'fc']:
print "\tf77 = %s" % c.f77 print "\t\t%s = %s" % (cpath, getattr(c, cpath, None))
print "\tfc = %s" % c.fc if c.flags:
print "\tflags:"
for flag, flag_value in c.flags.iteritems():
print "\t\t%s = %s" % (flag, flag_value)
print "\tmodules = %s" % c.modules print "\tmodules = %s" % c.modules
print "\toperating system = %s" % c.operating_system print "\toperating system = %s" % c.operating_system

View File

@ -65,6 +65,7 @@ def _to_dict(compiler):
d['spec'] = str(compiler.spec) d['spec'] = str(compiler.spec)
d['paths'] = dict((attr, getattr(compiler, attr, None)) d['paths'] = dict((attr, getattr(compiler, attr, None))
for attr in _path_instance_vars) for attr in _path_instance_vars)
d['flags'] = dict((fname, fvals) for fname, fvals in compiler.flags)
d['operating_system'] = str(compiler.operating_system) d['operating_system'] = str(compiler.operating_system)
d['modules'] = compiler.modules if compiler.modules else [] d['modules'] = compiler.modules if compiler.modules else []
@ -212,7 +213,7 @@ def supported(compiler_spec):
@_auto_compiler_spec @_auto_compiler_spec
def find(compiler_spec, scope=None): def find(compiler_spec, scope=None):
"""Return specs of available compilers that match the supplied """Return specs of available compilers that match the supplied
compiler spec. Return an list if nothing found.""" compiler spec. Return an empty list if nothing found."""
return [c for c in all_compilers(scope) if c.satisfies(compiler_spec)] return [c for c in all_compilers(scope) if c.satisfies(compiler_spec)]
@ -221,7 +222,7 @@ def compilers_for_spec(compiler_spec, scope=None, **kwargs):
"""This gets all compilers that satisfy the supplied CompilerSpec. """This gets all compilers that satisfy the supplied CompilerSpec.
Returns an empty list if none are found. Returns an empty list if none are found.
""" """
platform = kwargs.get("platform", None) platform = kwargs.get('platform', None)
config = all_compilers_config(scope) config = all_compilers_config(scope)
def get_compilers(cspec): def get_compilers(cspec):
@ -241,7 +242,7 @@ def get_compilers(cspec):
compiler_paths = [] compiler_paths = []
for c in _path_instance_vars: for c in _path_instance_vars:
compiler_path = items['paths'][c] compiler_path = items['paths'][c]
if compiler_path != "None": if compiler_path != 'None':
compiler_paths.append(compiler_path) compiler_paths.append(compiler_path)
else: else:
compiler_paths.append(None) compiler_paths.append(None)
@ -250,21 +251,17 @@ def get_compilers(cspec):
if mods == 'None': if mods == 'None':
mods = [] mods = []
os = None
if 'operating_system' in items: if 'operating_system' in items:
os = spack.architecture._operating_system_from_dict( os = spack.architecture._operating_system_from_dict(
items['operating_system'], platform) items['operating_system'], platform)
else:
os = None
alias = items['alias'] if 'alias' in items else None alias = items.get('alias', None)
flags = {} compiler_flags = items.get('flags', {})
for f in spack.spec.FlagMap.valid_compiler_flags():
if f in items:
flags[f] = items[f]
compilers.append( compilers.append(
cls(cspec, os, compiler_paths, mods, alias, **flags)) cls(cspec, os, compiler_paths, mods, alias, **compiler_flags))
return compilers return compilers

View File

@ -52,7 +52,11 @@
'f77': {'anyOf': [{'type': 'string'}, 'f77': {'anyOf': [{'type': 'string'},
{'type': 'null'}]}, {'type': 'null'}]},
'fc': {'anyOf': [{'type': 'string'}, 'fc': {'anyOf': [{'type': 'string'},
{'type': 'null'}]}, {'type': 'null'}]}}},
'flags': {
'type': 'object',
'additionalProperties': False,
'properties': {
'cflags': {'anyOf': [{'type': 'string'}, 'cflags': {'anyOf': [{'type': 'string'},
{'type': 'null'}]}, {'type': 'null'}]},
'cxxflags': {'anyOf': [{'type': 'string'}, 'cxxflags': {'anyOf': [{'type': 'string'},

View File

@ -51,7 +51,7 @@
'arg5', 'arg6'] 'arg5', 'arg6']
class CompilerTest(unittest.TestCase): class CompilerWrapperTest(unittest.TestCase):
def setUp(self): def setUp(self):
self.cc = Executable(join_path(spack.build_env_path, "cc")) self.cc = Executable(join_path(spack.build_env_path, "cc"))

View File

@ -55,6 +55,21 @@
'spec': 'gcc@4.5.0', 'spec': 'gcc@4.5.0',
'operating_system': 'CNL10' 'operating_system': 'CNL10'
}}, }},
{'compiler': {
'paths': {
"cc": "/gcc422",
"cxx": "/g++422",
"f77": 'gfortran',
"fc": 'gfortran'
},
'flags': {
"cppflags": "-O0 -fpic",
"fflags": "-f77",
},
'modules': None,
'spec': 'gcc@4.2.2',
'operating_system': 'CNL10'
}},
{'compiler': { {'compiler': {
'paths': { 'paths': {
"cc": "<overwritten>", "cc": "<overwritten>",
@ -90,6 +105,21 @@
'spec': 'icc@11.1', 'spec': 'icc@11.1',
'operating_system': 'CNL10' 'operating_system': 'CNL10'
}}, }},
{'compiler': {
'paths': {
"cc": "/icc123",
"cxx": "/icp123",
"f77": 'ifort',
"fc": 'ifort'
},
'flags': {
"cppflags": "-O3",
"fflags": "-f77rtl",
},
'modules': None,
'spec': 'icc@12.3',
'operating_system': 'CNL10'
}},
{'compiler': { {'compiler': {
'paths': { 'paths': {
"cc": "<overwritten>", "cc": "<overwritten>",
@ -112,11 +142,13 @@ class ConfigTest(MockPackagesTest):
def setUp(self): def setUp(self):
super(ConfigTest, self).setUp() super(ConfigTest, self).setUp()
self.tmp_dir = mkdtemp('.tmp', 'spack-config-test-') self.tmp_dir = mkdtemp('.tmp', 'spack-config-test-')
self.a_comp_specs = [ac['compiler']['spec'] for ac in a_comps]
self.b_comp_specs = [bc['compiler']['spec'] for bc in b_comps]
spack.config.config_scopes = OrderedDict() spack.config.config_scopes = OrderedDict()
spack.config.ConfigScope( for priority in ['low', 'high']:
'test_low_priority', os.path.join(self.tmp_dir, 'low')) spack.config.ConfigScope('test_{0}_priority'.format(priority),
spack.config.ConfigScope('test_high_priority', os.path.join(self.tmp_dir, priority))
os.path.join(self.tmp_dir, 'high'))
def tearDown(self): def tearDown(self):
super(ConfigTest, self).tearDown() super(ConfigTest, self).tearDown()
@ -126,19 +158,22 @@ def check_config(self, comps, *compiler_names):
"""Check that named compilers in comps match Spack's config.""" """Check that named compilers in comps match Spack's config."""
config = spack.config.get_config('compilers') config = spack.config.get_config('compilers')
compiler_list = ['cc', 'cxx', 'f77', 'fc'] compiler_list = ['cc', 'cxx', 'f77', 'fc']
flag_list = ['cflags', 'cxxflags', 'fflags', 'cppflags',
'ldflags', 'ldlibs']
param_list = ['modules', 'paths', 'spec', 'operating_system'] param_list = ['modules', 'paths', 'spec', 'operating_system']
for compiler in config: for compiler in config:
conf = compiler['compiler'] conf = compiler['compiler']
if conf['spec'] in compiler_names: if conf['spec'] in compiler_names:
comp = None comp = next((c['compiler'] for c in comps if
for c in comps: c['compiler']['spec'] == conf['spec']), None)
if c['compiler']['spec'] == conf['spec']:
comp = c['compiler']
break
if not comp: if not comp:
self.fail('Bad config spec') self.fail('Bad config spec')
for p in param_list: for p in param_list:
self.assertEqual(conf[p], comp[p]) self.assertEqual(conf[p], comp[p])
for f in flag_list:
expected = comp.get('flags', {}).get(f, None)
actual = conf.get('flags', {}).get(f, None)
self.assertEqual(expected, actual)
for c in compiler_list: for c in compiler_list:
expected = comp['paths'][c] expected = comp['paths'][c]
actual = conf['paths'][c] actual = conf['paths'][c]
@ -156,8 +191,8 @@ def test_write_key_in_memory(self):
spack.config.update_config('compilers', b_comps, 'test_high_priority') spack.config.update_config('compilers', b_comps, 'test_high_priority')
# Make sure the config looks how we expect. # Make sure the config looks how we expect.
self.check_config(a_comps, 'gcc@4.7.3', 'gcc@4.5.0') self.check_config(a_comps, *self.a_comp_specs)
self.check_config(b_comps, 'icc@10.0', 'icc@11.1', 'clang@3.3') self.check_config(b_comps, *self.b_comp_specs)
def test_write_key_to_disk(self): def test_write_key_to_disk(self):
# Write b_comps "on top of" a_comps. # Write b_comps "on top of" a_comps.
@ -168,8 +203,8 @@ def test_write_key_to_disk(self):
spack.config.clear_config_caches() spack.config.clear_config_caches()
# Same check again, to ensure consistency. # Same check again, to ensure consistency.
self.check_config(a_comps, 'gcc@4.7.3', 'gcc@4.5.0') self.check_config(a_comps, *self.a_comp_specs)
self.check_config(b_comps, 'icc@10.0', 'icc@11.1', 'clang@3.3') self.check_config(b_comps, *self.b_comp_specs)
def test_write_to_same_priority_file(self): def test_write_to_same_priority_file(self):
# Write b_comps in the same file as a_comps. # Write b_comps in the same file as a_comps.
@ -180,5 +215,5 @@ def test_write_to_same_priority_file(self):
spack.config.clear_config_caches() spack.config.clear_config_caches()
# Same check again, to ensure consistency. # Same check again, to ensure consistency.
self.check_config(a_comps, 'gcc@4.7.3', 'gcc@4.5.0') self.check_config(a_comps, *self.a_comp_specs)
self.check_config(b_comps, 'icc@10.0', 'icc@11.1', 'clang@3.3') self.check_config(b_comps, *self.b_comp_specs)

View File

@ -136,6 +136,31 @@
f77: None f77: None
fc: None fc: None
modules: 'None' modules: 'None'
- compiler:
spec: gcc@4.7.2
operating_system: redhat6
paths:
cc: /path/to/gcc472
cxx: /path/to/g++472
f77: /path/to/gfortran472
fc: /path/to/gfortran472
flags:
cflags: -O0
cxxflags: -O0
fflags: -O0
modules: 'None'
- compiler:
spec: clang@3.5
operating_system: redhat6
paths:
cc: /path/to/clang35
cxx: /path/to/clang++35
f77: None
fc: None
flags:
cflags: -O3
cxxflags: -O3
modules: 'None'
""".format(linux_os_name, linux_os_version) """.format(linux_os_name, linux_os_version)
mock_packages_config = """\ mock_packages_config = """\