Skip to content

Commit

Permalink
Added customization for make targets in 'build' and 'install' phases …
Browse files Browse the repository at this point in the history
…for CMakePackage (#2742)

* Added customization for make targets in 'build' and 'install' phases for CMakePackage

* Use rst in build system docs so that Sphinx generates nice API docs

* Allow AutotoolsPackages to be built in a different directory

* Flake8

* Fix missing import

* Allow configure to be located in different directory

* Update espressopp to use build targets

* Flake8

* Sphinx fix, lists must be a new paragraph

* Back out change that allowed a configure script in a different directory than build_directory

* Add missing deps, build in parallel

* Missing space for rst list
  • Loading branch information
adamjstewart authored and tgamblin committed Jan 16, 2017
1 parent 4b7b595 commit f480e34
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 78 deletions.
52 changes: 32 additions & 20 deletions lib/spack/spack/build_systems/autotools.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,25 @@
from subprocess import check_call

import llnl.util.tty as tty
from llnl.util.filesystem import working_dir
from spack.package import PackageBase


class AutotoolsPackage(PackageBase):
"""Specialized class for packages that are built using GNU Autotools
This class provides four phases that can be overridden:
- autoreconf
- configure
- build
- install
* autoreconf
* configure
* build
* install
They all have sensible defaults and for many packages the only thing
necessary will be to override `configure_args`
necessary will be to override ``configure_args``
Additionally, you may specify make targets for build and install
phases by overriding `build_targets` and `install_targets`
phases by overriding ``build_targets`` and ``install_targets``
"""
phases = ['autoreconf', 'configure', 'build', 'install']
# To be used in UI queries that require to know which
Expand Down Expand Up @@ -124,6 +126,10 @@ def do_patch_config_guess(self):

return False

def build_directory(self):
"""Override to provide another place to build the package"""
return self.stage.source_path

def patch(self):
"""Perform any required patches."""

Expand All @@ -138,39 +144,44 @@ def autoreconf(self, spec, prefix):

@PackageBase.sanity_check('autoreconf')
def is_configure_or_die(self):
"""Checks the presence of a `configure` file after the
"""Checks the presence of a ``configure`` file after the
autoreconf phase"""
if not os.path.exists('configure'):
raise RuntimeError(
'configure script not found in {0}'.format(os.getcwd()))
with working_dir(self.build_directory()):
if not os.path.exists('configure'):
raise RuntimeError(
'configure script not found in {0}'.format(os.getcwd()))

def configure_args(self):
"""Method to be overridden. Should return an iterable containing
all the arguments that must be passed to configure, except --prefix
all the arguments that must be passed to configure, except ``--prefix``
"""
return []

def configure(self, spec, prefix):
"""Runs configure with the arguments specified in `configure_args`
"""Runs configure with the arguments specified in ``configure_args``
and an appropriately set prefix
"""
options = ['--prefix={0}'.format(prefix)] + self.configure_args()
inspect.getmodule(self).configure(*options)

with working_dir(self.build_directory()):
inspect.getmodule(self).configure(*options)

def build(self, spec, prefix):
"""Make the build targets"""
inspect.getmodule(self).make(*self.build_targets)
with working_dir(self.build_directory()):
inspect.getmodule(self).make(*self.build_targets)

def install(self, spec, prefix):
"""Make the install targets"""
inspect.getmodule(self).make(*self.install_targets)
with working_dir(self.build_directory()):
inspect.getmodule(self).make(*self.install_targets)

@PackageBase.sanity_check('build')
@PackageBase.on_package_attributes(run_tests=True)
def _run_default_function(self):
"""This function is run after build if self.run_tests == True
"""This function is run after build if ``self.run_tests == True``
It will search for a method named `check` and run it. A sensible
It will search for a method named ``check`` and run it. A sensible
default is provided in the base class.
"""
try:
Expand All @@ -181,11 +192,12 @@ def _run_default_function(self):
tty.msg('Skipping default sanity checks [method `check` not implemented]') # NOQA: ignore=E501

def check(self):
"""Default test : search the Makefile for targets `test` and `check`
"""Default test: search the Makefile for targets ``test`` and ``check``
and run them if found.
"""
self._if_make_target_execute('test')
self._if_make_target_execute('check')
with working_dir(self.build_directory()):
self._if_make_target_execute('test')
self._if_make_target_execute('check')

# Check that self.prefix is there after installation
PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix)
40 changes: 23 additions & 17 deletions lib/spack/spack/build_systems/cmake.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
##############################################################################

import inspect
import os
import platform

import llnl.util.tty as tty
Expand All @@ -35,21 +34,28 @@


class CMakePackage(PackageBase):
"""Specialized class for packages that are built using cmake
"""Specialized class for packages that are built using CMake
This class provides three phases that can be overridden:
- cmake
- build
- install
* cmake
* build
* install
They all have sensible defaults and for many packages the only thing
necessary will be to override `cmake_args`
necessary will be to override ``cmake_args``
Additionally, you may specify make targets for build and install
phases by overriding ``build_targets`` and ``install_targets``
"""
phases = ['cmake', 'build', 'install']
# To be used in UI queries that require to know which
# build-system class we are using
build_system_class = 'CMakePackage'

build_targets = []
install_targets = ['install']

depends_on('cmake', type='build')

def build_type(self):
Expand Down Expand Up @@ -97,35 +103,35 @@ def build_directory(self):
def cmake_args(self):
"""Method to be overridden. Should return an iterable containing
all the arguments that must be passed to configure, except:
- CMAKE_INSTALL_PREFIX
- CMAKE_BUILD_TYPE
* CMAKE_INSTALL_PREFIX
* CMAKE_BUILD_TYPE
"""
return []

def cmake(self, spec, prefix):
"""Run cmake in the build directory"""
options = [self.root_cmakelists_dir()] + self.std_cmake_args + \
self.cmake_args()
create = not os.path.exists(self.build_directory())
with working_dir(self.build_directory(), create=create):
with working_dir(self.build_directory(), create=True):
inspect.getmodule(self).cmake(*options)

def build(self, spec, prefix):
"""The usual `make` after cmake"""
"""Make the build targets"""
with working_dir(self.build_directory()):
inspect.getmodule(self).make()
inspect.getmodule(self).make(*self.build_targets)

def install(self, spec, prefix):
"""...and the final `make install` after cmake"""
"""Make the install targets"""
with working_dir(self.build_directory()):
inspect.getmodule(self).make('install')
inspect.getmodule(self).make(*self.install_targets)

@PackageBase.sanity_check('build')
@PackageBase.on_package_attributes(run_tests=True)
def _run_default_function(self):
"""This function is run after build if self.run_tests == True
"""This function is run after build if ``self.run_tests == True``
It will search for a method named `check` and run it. A sensible
It will search for a method named ``check`` and run it. A sensible
default is provided in the base class.
"""
try:
Expand All @@ -136,7 +142,7 @@ def _run_default_function(self):
tty.msg('Skipping default build sanity checks [method `check` not implemented]') # NOQA: ignore=E501

def check(self):
"""Default test : search the Makefile for the target `test`
"""Default test: search the Makefile for the target ``test``
and run them if found.
"""
with working_dir(self.build_directory()):
Expand Down
11 changes: 6 additions & 5 deletions lib/spack/spack/build_systems/makefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ class MakefilePackage(PackageBase):
"""Specialized class for packages that are built using editable Makefiles
This class provides three phases that can be overridden:
- edit
- build
- install
* edit
* build
* install
It is necessary to override the 'edit' phase, while 'build' and 'install'
have sensible defaults.
Expand All @@ -58,12 +59,12 @@ def edit(self, spec, prefix):
tty.msg('Using default implementation: skipping edit phase.')

def build(self, spec, prefix):
"""Default build phase : call make passing build_args"""
"""Make the build targets"""
with working_dir(self.build_directory()):
inspect.getmodule(self).make(*self.build_targets)

def install(self, spec, prefix):
"""Default install phase : call make passing install_args"""
"""Make the install targets"""
with working_dir(self.build_directory()):
inspect.getmodule(self).make(*self.install_targets)

Expand Down
1 change: 1 addition & 0 deletions lib/spack/spack/build_systems/r.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class RPackage(PackageBase):
"""Specialized class for packages that are built using R
This class provides a single phase that can be overridden:
* install
It has sensible defaults and for many packages the only thing
Expand Down
21 changes: 12 additions & 9 deletions var/spack/repos/builtin/packages/espressopp/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Espressopp(CMakePackage):
url = "https://github.com/espressopp/espressopp/tarball/v1.9.4.1"

version('develop', git='https://github.com/espressopp/espressopp.git', branch='master')
version('1.9.4.1', '0da74a6d4e1bfa6a2a24fca354245a4f')
version('1.9.4.1', '0da74a6d4e1bfa6a2a24fca354245a4f')
version('1.9.4', 'f2a27993a83547ad014335006eea74ea')

variant('debug', default=False, description='Build debug version')
Expand All @@ -54,20 +54,23 @@ class Espressopp(CMakePackage):
depends_on("fftw")
depends_on("py-sphinx", when="+ug", type='build')
depends_on("py-sphinx", when="+pdf", type='build')
depends_on('py-numpy', when="+ug", type='build')
depends_on('py-numpy', when="+pdf", type='build')
depends_on('py-matplotlib', when="+ug", type='build')
depends_on('py-matplotlib', when="+pdf", type='build')
depends_on("texlive", when="+pdf", type='build')
depends_on("doxygen", when="+dg", type='build')

def cmake_args(self):
def build_type(self):
spec = self.spec
options = []
options.extend(['-DEXTERNAL_MPI4PY=ON', '-DEXTERNAL_BOOST=ON'])
if '+debug' in spec:
options.extend(['-DCMAKE_BUILD_TYPE:STRING=Debug'])
return 'Debug'
else:
options.extend(['-DCMAKE_BUILD_TYPE:STRING=Release'])

return options

return 'Release'

def cmake_args(self):
return ['-DEXTERNAL_MPI4PY=ON', '-DEXTERNAL_BOOST=ON']

def build(self, spec, prefix):
with working_dir(self.build_directory()):
make()
Expand Down
14 changes: 7 additions & 7 deletions var/spack/repos/builtin/packages/tcl/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from spack import *


class Tcl(Package):
class Tcl(AutotoolsPackage):
"""Tcl (Tool Command Language) is a very powerful but easy to
learn dynamic programming language, suitable for a very wide
range of uses, including web and desktop applications,
Expand All @@ -52,10 +52,10 @@ def setup_environment(self, spack_env, env):
env.set('TCL_LIBRARY', join_path(self.prefix.lib, 'tcl{0}'.format(
self.spec.version.up_to(2))))

def install(self, spec, prefix):
with working_dir('unix'):
configure("--prefix={0}".format(prefix))
make()
make("install")
with working_dir(prefix.bin):
def build_directory(self):
return 'unix'

@AutotoolsPackage.sanity_check('install')
def symlink_tclsh(self):
with working_dir(self.prefix.bin):
symlink('tclsh{0}'.format(self.version.up_to(2)), 'tclsh')
22 changes: 11 additions & 11 deletions var/spack/repos/builtin/packages/tk/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from spack import *


class Tk(Package):
class Tk(AutotoolsPackage):
"""Tk is a graphical user interface toolkit that takes developing
desktop applications to a higher level than conventional
approaches. Tk is the standard GUI not only for Tcl, but for
Expand All @@ -46,15 +46,15 @@ def url_for_version(self, version):
base_url = "http://prdownloads.sourceforge.net/tcl"
return "{0}/tk{1}-src.tar.gz".format(base_url, version)

def setup_environment(self, spack_env, env):
def setup_environment(self, spack_env, run_env):
# When using Tkinter from within spack provided python+tk, python
# will not be able to find Tcl/Tk unless TK_LIBRARY is set.
env.set('TK_LIBRARY', join_path(self.prefix.lib, 'tk{0}'.format(
self.spec.version.up_to(2))))

def install(self, spec, prefix):
with working_dir('unix'):
configure("--prefix={0}".format(prefix),
"--with-tcl={0}".format(spec['tcl'].prefix.lib))
make()
make("install")
run_env.set('TK_LIBRARY', join_path(self.prefix.lib, 'tk{0}'.format(
self.spec.version.up_to(2))))

def build_directory(self):
return 'unix'

def configure_args(self):
spec = self.spec
return ['--with-tcl={0}'.format(spec['tcl'].prefix.lib)]
13 changes: 4 additions & 9 deletions var/spack/repos/builtin/packages/zlib/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
from spack import *
from os import environ


class Zlib(AutotoolsPackage):
Expand All @@ -35,17 +34,13 @@ class Zlib(AutotoolsPackage):

version('1.2.10', 'd9794246f853d15ce0fcbf79b9a3cf13')
# author had this to say about 1.2.9....
# Due to the bug fixes, any installations of 1.2.9 should be immediately
# Due to the bug fixes, any installations of 1.2.9 should be immediately
# replaced with 1.2.10.
version('1.2.8', '44d667c142d7cda120332623eab69f40')

variant('pic', default=True,
description='Produce position-independent code (for shared libs)')

def configure(self, spec, prefix):

if '+pic' in spec:
environ['CFLAGS'] = self.compiler.pic_flag

config_args = ['--prefix', prefix]
configure(*config_args)
def setup_environment(self, spack_env, run_env):
if '+pic' in self.spec:
spack_env.set('CFLAGS', self.compiler.pic_flag)

0 comments on commit f480e34

Please sign in to comment.