Add better generator support to CMakePackage (#4988)

* Add better generator support to CMakePackage

* List valid CMake generators on error
This commit is contained in:
Adam J. Stewart 2017-08-16 12:25:37 -05:00 committed by GitHub
parent db657d938d
commit 11b3ce27b7
4 changed files with 71 additions and 31 deletions

View File

@ -30,12 +30,15 @@
import spack.build_environment import spack.build_environment
from llnl.util.filesystem import working_dir, join_path from llnl.util.filesystem import working_dir, join_path
from spack.directives import depends_on, variant from spack.directives import depends_on, variant
from spack.package import PackageBase, run_after from spack.package import PackageBase, InstallError, run_after
class CMakePackage(PackageBase): class CMakePackage(PackageBase):
"""Specialized class for packages built using CMake """Specialized class for packages built using CMake
For more information on the CMake build system, see:
https://cmake.org/cmake/help/latest/
This class provides three phases that can be overridden: This class provides three phases that can be overridden:
1. :py:meth:`~.CMakePackage.cmake` 1. :py:meth:`~.CMakePackage.cmake`
@ -69,6 +72,16 @@ class CMakePackage(PackageBase):
build_time_test_callbacks = ['check'] build_time_test_callbacks = ['check']
#: The build system generator to use.
#:
#: See ``cmake --help`` for a list of valid generators.
#: Currently, "Unix Makefiles" and "Ninja" are the only generators
#: that Spack supports. Defaults to "Unix Makefiles".
#:
#: See https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html
#: for more information.
generator = 'Unix Makefiles'
# https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html # https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html
variant('build_type', default='RelWithDebInfo', variant('build_type', default='RelWithDebInfo',
description='The build type to build', description='The build type to build',
@ -100,14 +113,31 @@ def std_cmake_args(self):
@staticmethod @staticmethod
def _std_args(pkg): def _std_args(pkg):
"""Computes the standard cmake arguments for a generic package""" """Computes the standard cmake arguments for a generic package"""
try:
generator = pkg.generator
except AttributeError:
generator = 'Unix Makefiles'
# Make sure a valid generator was chosen
valid_generators = ['Unix Makefiles', 'Ninja']
if generator not in valid_generators:
msg = "Invalid CMake generator: '{0}'\n".format(generator)
msg += "CMakePackage currently supports the following "
msg += "generators: '{0}'".format("', '".join(valid_generators))
raise InstallError(msg)
try: try:
build_type = pkg.spec.variants['build_type'].value build_type = pkg.spec.variants['build_type'].value
except KeyError: except KeyError:
build_type = 'RelWithDebInfo' build_type = 'RelWithDebInfo'
args = ['-DCMAKE_INSTALL_PREFIX:PATH={0}'.format(pkg.prefix), args = [
'-G', generator,
'-DCMAKE_INSTALL_PREFIX:PATH={0}'.format(pkg.prefix),
'-DCMAKE_BUILD_TYPE:STRING={0}'.format(build_type), '-DCMAKE_BUILD_TYPE:STRING={0}'.format(build_type),
'-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON'] '-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON'
]
if platform.mac_ver()[0]: if platform.mac_ver()[0]:
args.append('-DCMAKE_FIND_FRAMEWORK:STRING=LAST') args.append('-DCMAKE_FIND_FRAMEWORK:STRING=LAST')
@ -158,12 +188,18 @@ def cmake(self, spec, prefix):
def build(self, spec, prefix): def build(self, spec, prefix):
"""Make the build targets""" """Make the build targets"""
with working_dir(self.build_directory): with working_dir(self.build_directory):
if self.generator == 'Unix Makefiles':
inspect.getmodule(self).make(*self.build_targets) inspect.getmodule(self).make(*self.build_targets)
elif self.generator == 'Ninja':
inspect.getmodule(self).ninja(*self.build_targets)
def install(self, spec, prefix): def install(self, spec, prefix):
"""Make the install targets""" """Make the install targets"""
with working_dir(self.build_directory): with working_dir(self.build_directory):
if self.generator == 'Unix Makefiles':
inspect.getmodule(self).make(*self.install_targets) inspect.getmodule(self).make(*self.install_targets)
elif self.generator == 'Ninja':
inspect.getmodule(self).ninja(*self.install_targets)
run_after('build')(PackageBase._run_default_build_time_test_callbacks) run_after('build')(PackageBase._run_default_build_time_test_callbacks)
@ -172,7 +208,10 @@ def check(self):
and runs it if found. and runs it if found.
""" """
with working_dir(self.build_directory): with working_dir(self.build_directory):
if self.generator == 'Unix Makefiles':
self._if_make_target_execute('test') self._if_make_target_execute('test')
elif self.generator == 'Ninja':
self._if_ninja_target_execute('test')
# Check that self.prefix is there after installation # Check that self.prefix is there after installation
run_after('install')(PackageBase.sanity_check_prefix) run_after('install')(PackageBase.sanity_check_prefix)

View File

@ -1091,12 +1091,30 @@ def _if_make_target_execute(self, target):
matches = [line for line in f.readlines() if regex.match(line)] matches = [line for line in f.readlines() if regex.match(line)]
if not matches: if not matches:
tty.msg('Target \'' + target + ':\' not found in Makefile') tty.msg("Target '" + target + ":' not found in Makefile")
return return
# Execute target # Execute target
inspect.getmodule(self).make(target) inspect.getmodule(self).make(target)
def _if_ninja_target_execute(self, target):
# Check if we have a ninja build script
if not os.path.exists('build.ninja'):
tty.msg('No ninja build script found in the build directory')
return
# Check if 'target' is in the ninja build script
regex = re.compile('^build ' + target + ':')
with open('build.ninja', 'r') as f:
matches = [line for line in f.readlines() if regex.match(line)]
if not matches:
tty.msg("Target 'build " + target + ":' not found in build.ninja")
return
# Execute target
inspect.getmodule(self).ninja(target)
def _get_needed_resources(self): def _get_needed_resources(self):
resources = [] resources = []
# Select the resources that are needed for this build # Select the resources that are needed for this build

View File

@ -36,22 +36,14 @@ class Archer(CMakePackage):
depends_on('cmake@3.4.3:', type='build') depends_on('cmake@3.4.3:', type='build')
depends_on('llvm') depends_on('llvm')
depends_on('ninja', type='build') depends_on('ninja@1.5:', type='build')
depends_on('llvm-openmp-ompt') depends_on('llvm-openmp-ompt')
generator = 'Ninja'
def cmake_args(self): def cmake_args(self):
return [ return [
'-G', 'Ninja',
'-DCMAKE_C_COMPILER=clang', '-DCMAKE_C_COMPILER=clang',
'-DCMAKE_CXX_COMPILER=clang++', '-DCMAKE_CXX_COMPILER=clang++',
'-DOMP_PREFIX:PATH=%s' % self.spec['llvm-openmp-ompt'].prefix, '-DOMP_PREFIX:PATH=%s' % self.spec['llvm-openmp-ompt'].prefix,
] ]
# TODO: Add better ninja support to CMakePackage
def build(self, spec, prefix):
with working_dir(self.build_directory):
ninja()
def install(self, spec, prefix):
with working_dir(self.build_directory):
ninja('install')

View File

@ -44,24 +44,15 @@ class LlvmOpenmpOmpt(CMakePackage):
depends_on('cmake@2.8:', type='build') depends_on('cmake@2.8:', type='build')
depends_on('llvm') depends_on('llvm')
depends_on('ninja', type='build') depends_on('ninja@1.5:', type='build')
generator = 'Ninja'
def cmake_args(self): def cmake_args(self):
return [ return [
'-G', 'Ninja',
'-DCMAKE_C_COMPILER=clang', '-DCMAKE_C_COMPILER=clang',
'-DCMAKE_CXX_COMPILER=clang++', '-DCMAKE_CXX_COMPILER=clang++',
'-DCMAKE_BUILD_TYPE=Release',
'-DLIBOMP_OMPT_SUPPORT=on', '-DLIBOMP_OMPT_SUPPORT=on',
'-DLIBOMP_OMPT_BLAME=on', '-DLIBOMP_OMPT_BLAME=on',
'-DLIBOMP_OMPT_TRACE=on' '-DLIBOMP_OMPT_TRACE=on'
] ]
# TODO: Add better ninja support to CMakePackage
def build(self, spec, prefix):
with working_dir(self.build_directory):
ninja()
def install(self, spec, prefix):
with working_dir(self.build_directory):
ninja('install')