Skip to content

Commit

Permalink
AutotoolsPackage: minor improvements (spack#2859)
Browse files Browse the repository at this point in the history
* AutotoolsPackage: added configure_directory to permit build out of source. The configure script executable is now invoked with an absolute path. Modified a few packages accordingly.

* build_systems: functions returning directories are now properties

* build_systems: fixed issues with tcl and tk

* AutotoolsPackage: reworked recipe for autoreconf
  • Loading branch information
alalazo authored and diaena committed May 26, 2017
1 parent a6a3e60 commit 646c440
Show file tree
Hide file tree
Showing 27 changed files with 178 additions and 172 deletions.
98 changes: 82 additions & 16 deletions lib/spack/spack/build_systems/autotools.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@
from subprocess import PIPE
from subprocess import check_call

from llnl.util.filesystem import working_dir
from spack.package import PackageBase, run_after
import llnl.util.tty as tty
from llnl.util.filesystem import working_dir, join_path, force_remove
from spack.package import PackageBase, run_after, run_before
from spack.util.executable import Executable


class AutotoolsPackage(PackageBase):
Expand Down Expand Up @@ -79,8 +81,14 @@ class AutotoolsPackage(PackageBase):
#: phase
install_targets = ['install']

#: Callback names for build-time test
build_time_test_callbacks = ['check']

#: Set to true to force the autoreconf step even if configure is present
force_autoreconf = False
#: Options to be passed to autoreconf when using the default implementation
autoreconf_extra_args = []

def _do_patch_config_guess(self):
"""Some packages ship with an older config.guess and need to have
this updated when installed on a newer architecture."""
Expand Down Expand Up @@ -147,9 +155,26 @@ def _do_patch_config_guess(self):

return False

@property
def configure_directory(self):
"""Returns the directory where 'configure' resides.
:return: directory where to find configure
"""
return self.stage.source_path

@property
def configure_abs_path(self):
# Absolute path to configure
configure_abs_path = join_path(
os.path.abspath(self.configure_directory), 'configure'
)
return configure_abs_path

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

def patch(self):
"""Patches config.guess if
Expand All @@ -165,21 +190,62 @@ def patch(self):
if not self._do_patch_config_guess():
raise RuntimeError('Failed to find suitable config.guess')

@run_before('autoreconf')
def delete_configure_to_force_update(self):
if self.force_autoreconf:
force_remove(self.configure_abs_path)

def autoreconf(self, spec, prefix):
"""Not needed usually, configure should be already there"""
pass
# If configure exists nothing needs to be done
if os.path.exists(self.configure_abs_path):
return
# Else try to regenerate it
autotools = ['m4', 'autoconf', 'automake', 'libtool']
missing = [x for x in autotools if x not in spec]
if missing:
msg = 'Cannot generate configure: missing dependencies {0}'
raise RuntimeError(msg.format(missing))
tty.msg('Configure script not found: trying to generate it')
tty.warn('*********************************************************')
tty.warn('* If the default procedure fails, consider implementing *')
tty.warn('* a custom AUTORECONF phase in the package *')
tty.warn('*********************************************************')
with working_dir(self.configure_directory):
m = inspect.getmodule(self)
# This part should be redundant in principle, but
# won't hurt
m.libtoolize()
m.aclocal()
# This line is what is needed most of the time
# --install, --verbose, --force
autoreconf_args = ['-ivf']
if 'pkg-config' in spec:
autoreconf_args += [
'-I',
join_path(spec['pkg-config'].prefix, 'share', 'aclocal'),
]
autoreconf_args += self.autoreconf_extra_args
m.autoreconf(*autoreconf_args)

@run_after('autoreconf')
def is_configure_or_die(self):
"""Checks the presence of a `configure` file after the
:py:meth:`.autoreconf` phase.
def set_configure_or_die(self):
"""Checks the presence of a ``configure`` file after the
autoreconf phase. If it is found sets a module attribute
appropriately, otherwise raises an error.
:raise RuntimeError: if the ``configure`` script does not exist.
:raises RuntimeError: if a configure script is not found in
:py:meth:`~.configure_directory`
"""
with working_dir(self.build_directory()):
if not os.path.exists('configure'):
raise RuntimeError(
'configure script not found in {0}'.format(os.getcwd()))
# Check if a configure script is there. If not raise a RuntimeError.
if not os.path.exists(self.configure_abs_path):
msg = 'configure script not found in {0}'
raise RuntimeError(msg.format(self.configure_directory))

# Monkey-patch the configure script in the corresponding module
inspect.getmodule(self).configure = Executable(
self.configure_abs_path
)

def configure_args(self):
"""Produces a list containing all the arguments that must be passed to
Expand All @@ -195,21 +261,21 @@ def configure(self, spec, prefix):
"""
options = ['--prefix={0}'.format(prefix)] + self.configure_args()

with working_dir(self.build_directory()):
with working_dir(self.build_directory, create=True):
inspect.getmodule(self).configure(*options)

def build(self, spec, prefix):
"""Makes the build targets specified by
:py:attr:``~.AutotoolsPackage.build_targets``
"""
with working_dir(self.build_directory()):
with working_dir(self.build_directory):
inspect.getmodule(self).make(*self.build_targets)

def install(self, spec, prefix):
"""Makes the install targets specified by
:py:attr:``~.AutotoolsPackage.install_targets``
"""
with working_dir(self.build_directory()):
with working_dir(self.build_directory):
inspect.getmodule(self).make(*self.install_targets)

run_after('build')(PackageBase._run_default_build_time_test_callbacks)
Expand All @@ -218,7 +284,7 @@ def check(self):
"""Searches the Makefile for targets ``test`` and ``check``
and runs them if found.
"""
with working_dir(self.build_directory()):
with working_dir(self.build_directory):
self._if_make_target_execute('test')
self._if_make_target_execute('check')

Expand Down
12 changes: 7 additions & 5 deletions lib/spack/spack/build_systems/cmake.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ def build_type(self):
"""
return 'RelWithDebInfo'

@property
def root_cmakelists_dir(self):
"""Returns the location of the root CMakeLists.txt
Expand Down Expand Up @@ -119,6 +120,7 @@ def _std_args(pkg):
args.append('-DCMAKE_INSTALL_RPATH:STRING={0}'.format(rpaths))
return args

@property
def build_directory(self):
"""Returns the directory to use when building the package
Expand All @@ -141,19 +143,19 @@ def cmake_args(self):

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

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

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

run_after('build')(PackageBase._run_default_build_time_test_callbacks)
Expand All @@ -162,7 +164,7 @@ def check(self):
"""Searches the CMake-generated Makefile for the target ``test``
and runs it if found.
"""
with working_dir(self.build_directory()):
with working_dir(self.build_directory):
self._if_make_target_execute('test')

# Check that self.prefix is there after installation
Expand Down
5 changes: 3 additions & 2 deletions lib/spack/spack/build_systems/makefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class MakefilePackage(PackageBase):
#: phase
install_targets = ['install']

@property
def build_directory(self):
"""Returns the directory containing the main Makefile
Expand All @@ -89,14 +90,14 @@ def build(self, spec, prefix):
"""Calls make, passing :py:attr:`~.MakefilePackage.build_targets`
as targets.
"""
with working_dir(self.build_directory()):
with working_dir(self.build_directory):
inspect.getmodule(self).make(*self.build_targets)

def install(self, spec, prefix):
"""Calls make, passing :py:attr:`~.MakefilePackage.install_targets`
as targets.
"""
with working_dir(self.build_directory()):
with working_dir(self.build_directory):
inspect.getmodule(self).make(*self.install_targets)

# Check that self.prefix is there after installation
Expand Down
5 changes: 3 additions & 2 deletions lib/spack/spack/build_systems/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,11 @@ def configure(self, spec, prefix):

extends('python')

def setup_file(self, spec, prefix):
def setup_file(self):
"""Returns the name of the setup file to use."""
return 'setup.py'

@property
def build_directory(self):
"""The directory containing the ``setup.py`` file."""
return self.stage.source_path
Expand All @@ -109,7 +110,7 @@ def python(self, *args):
inspect.getmodule(self).python(*args)

def setup_py(self, *args):
setup = self.setup_file(self.spec, self.prefix)
setup = self.setup_file()

with working_dir(self.build_directory()):
self.python(setup, '--no-user-cfg', *args)
Expand Down
1 change: 1 addition & 0 deletions var/spack/repos/builtin/packages/astyle/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Astyle(MakefilePackage):

parallel = False

@property
def build_directory(self):
return join_path(self.stage.source_path, 'build', self.compiler.name)

Expand Down
2 changes: 2 additions & 0 deletions var/spack/repos/builtin/packages/autoconf/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class Autoconf(AutotoolsPackage):

depends_on('m4@1.4.6:', type='build')

build_directory = 'spack-build'

def _make_executable(self, name):
return Executable(join_path(self.prefix.bin, name))

Expand Down
2 changes: 2 additions & 0 deletions var/spack/repos/builtin/packages/automake/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class Automake(AutotoolsPackage):

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

build_directory = 'spack-build'

def _make_executable(self, name):
return Executable(join_path(self.prefix.bin, name))

Expand Down
19 changes: 6 additions & 13 deletions var/spack/repos/builtin/packages/bash-completion/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
from spack import *


class BashCompletion(Package):
class BashCompletion(AutotoolsPackage):
"""Programmable completion functions for bash."""
homepage = "https://github.com/scop/bash-completion"
url = "https://github.com/scop/bash-completion/archive/2.3.tar.gz"
url = "https://github.com/scop/bash-completion/archive/2.3.tar.gz"

version('2.3', '67e50f5f3c804350b43f2b664c33dde811d24292')
version('develop', git='https://github.com/scop/bash-completion.git')
Expand All @@ -41,16 +41,9 @@ class BashCompletion(Package):
# Other dependencies
depends_on('bash@4.1:', type='run')

def install(self, spec, prefix):
make_args = ['--prefix=%s' % prefix]

autoreconf('-i')
configure(*make_args)
make()
# make("check") # optional, requires dejagnu and tcllib
make("install",
parallel=False)

@run_after('install')
def show_message_to_user(self):
prefix = self.prefix
# Guidelines for individual user as provided by the author at
# https://github.com/scop/bash-completion
print('=====================================================')
Expand All @@ -59,6 +52,6 @@ def install(self, spec, prefix):
print('')
print('# Use bash-completion, if available')
print('[[ $PS1 && -f %s/share/bash-completion/bash_completion ]] && \ ' % prefix) # NOQA: ignore=E501
print(' . %s/share/bash-completion/bash_completion' % prefix)
print(' . %s/share/bash-completion/bash_completion' % prefix)
print('')
print('=====================================================')
2 changes: 2 additions & 0 deletions var/spack/repos/builtin/packages/bison/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ class Bison(AutotoolsPackage):
version('3.0.4', 'a586e11cd4aff49c3ff6d3b6a4c9ccf8')

depends_on("m4", type='build')

build_directory = 'spack-build'
16 changes: 0 additions & 16 deletions var/spack/repos/builtin/packages/czmq/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,3 @@ class Czmq(AutotoolsPackage):
depends_on('autoconf', type='build')
depends_on('pkg-config', type='build')
depends_on('zeromq')

def autoreconf(self, spec, prefix):
# Work around autogen.sh oddities
# bash = which("bash")
# bash("./autogen.sh")
mkdirp("config")
autoreconf = which("autoreconf")
autoreconf("--install", "--verbose", "--force",
"-I", "config",
"-I", join_path(spec['pkg-config'].prefix,
"share", "aclocal"),
"-I", join_path(spec['automake'].prefix,
"share", "aclocal"),
"-I", join_path(spec['libtool'].prefix,
"share", "aclocal"),
)
8 changes: 4 additions & 4 deletions var/spack/repos/builtin/packages/elfutils/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ class Elfutils(AutotoolsPackage):

homepage = "https://fedorahosted.org/elfutils/"

depends_on('libtool', type='build')
depends_on('automake', type='build')
depends_on('autoconf', type='build')

version('0.163',
git='git://git.fedorahosted.org/git/elfutils.git',
tag='elfutils-0.163')

provides('elf')

def autoreconf(self, spec, prefix):
autoreconf = which('autoreconf')
autoreconf('-if')

def configure_args(self):
return ['--enable-maintainer-mode']
8 changes: 0 additions & 8 deletions var/spack/repos/builtin/packages/flex/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,3 @@ def url_for_version(self, version):
url += "/archive/flex-{0}.tar.gz".format(version.dashed)

return url

def autoreconf(self, spec, prefix):
pass

@when('@:2.6.0')
def autoreconf(self, spec, prefix):
libtoolize('--install', '--force')
autoreconf('--install', '--force')

0 comments on commit 646c440

Please sign in to comment.