From 50727527bc69a1b8ed26aa84a40039086db33827 Mon Sep 17 00:00:00 2001 From: Peter Scheibel Date: Mon, 11 Jan 2016 15:51:02 -0800 Subject: [PATCH 1/6] This commit makes the following changes: There are two sensible defaults for building boost libraries: build all of them or build none of them. Previously the Spack boost package took the first approach. This commit changes to building no libraries by default. The user can specify which libraries they need using variants (e.g. +iostreams to compile the boost iostreams library). If no libraries are built then a header-only install is performed (no compilation, just copy header files to prefix). The consequence of this change is that packages which specify a dependency on boost may now fail (until they are updated to specify exactly which boost libraries they need compiled). The user may now specify whether to build shared libraries (static libraries are always built) and whether to build libraries with/out multi-threading support (default is to only build with multi-threading support). The executable on the user-config.jam toolset line is set to Spack's cc script. Before, without this, the desired toolset was used but Spack deferred to the boost build system to choose the compiler version. bzip2 and zlib are always specified as dependencies when iostreams is built (before this could be controlled with the +compression variant). --- var/spack/packages/boost/package.py | 90 ++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 26 deletions(-) diff --git a/var/spack/packages/boost/package.py b/var/spack/packages/boost/package.py index 3427b74ad6..5fb6c9dc04 100644 --- a/var/spack/packages/boost/package.py +++ b/var/spack/packages/boost/package.py @@ -1,4 +1,5 @@ from spack import * +import spack class Boost(Package): """Boost provides free peer-reviewed portable C++ source @@ -44,15 +45,35 @@ class Boost(Package): version('1.34.1', '2d938467e8a448a2c9763e0a9f8ca7e5') version('1.34.0', 'ed5b9291ffad776f8757a916e1726ad0') - variant('debug', default=False, description='Switch to the debug version of Boost') - variant('python', default=False, description='Activate the component Boost.Python') - variant('mpi', default=False, description='Activate the component Boost.MPI') - variant('compression', default=True, description='Activate the compression Boost.iostreams') + libs = ['chrono', + 'date_time', + 'filesystem', + 'iostreams', + 'random', + 'regex', + 'serialization', + 'signals', + 'system', + 'thread', + 'wave', + 'mpi', + 'python'] + for lib in libs: + variant(lib, default=False, description="Compile with {0} library" + .format(lib)) + + variant('debug', default=False, description='Switch to the debug version of Boost') + variant('shared', default=True, description="Additionally build shared libraries") + variant('multithreaded', default=True, description="Build multi-threaded versions of libraries") + variant('singlethreaded', default=False, description="Build single-threaded versions of libraries") + variant('regex_icu', default=False, description="Include regex ICU support (by default false even if regex library is compiled)") + + depends_on('icu', when='+regex_icu') depends_on('python', when='+python') depends_on('mpi', when='+mpi') - depends_on('bzip2', when='+compression') - depends_on('zlib', when='+compression') + depends_on('bzip2', when='+iostreams') + depends_on('zlib', when='+iostreams') def url_for_version(self, version): """Handle Boost's weird URLs, which write the version two different ways.""" @@ -77,22 +98,20 @@ def determine_toolset(self, spec): # fallback to gcc if no toolset found return 'gcc' - def determine_bootstrap_options(self, spec, options): - options.append('--with-toolset=%s' % self.determine_toolset(spec)) + def determine_bootstrap_options(self, spec, withLibs, options): + boostToolsetId = self.determine_toolset(spec) + options.append('--with-toolset=%s' % boostToolsetId) + options.append("--with-libraries=%s" % ','.join(withLibs)) - without_libs = [] - if '~mpi' in spec: - without_libs.append('mpi') - if '~python' in spec: - without_libs.append('python') - else: + if '+python' in spec: options.append('--with-python=%s' % join_path(spec['python'].prefix.bin, 'python')) - if without_libs: - options.append('--without-libraries=%s' % ','.join(without_libs)) - with open('user-config.jam', 'w') as f: + compiler_wrapper = join_path(spack.build_env_path, 'c++') + f.write("using {0} : : {1} ;\n".format(boostToolsetId, + compiler_wrapper)) + if '+mpi' in spec: f.write('using mpi : %s ;\n' % join_path(spec['mpi'].prefix.bin, 'mpicxx')) @@ -107,12 +126,7 @@ def determine_b2_options(self, spec, options): else: options.append('variant=release') - if '~compression' in spec: - options.extend([ - '-s', 'NO_BZIP2=1', - '-s', 'NO_ZLIB=1']) - - if '+compression' in spec: + if '+iostreams' in spec: options.extend([ '-s', 'BZIP2_INCLUDE=%s' % spec['bzip2'].prefix.include, '-s', 'BZIP2_LIBPATH=%s' % spec['bzip2'].prefix.lib, @@ -120,20 +134,44 @@ def determine_b2_options(self, spec, options): '-s', 'ZLIB_LIBPATH=%s' % spec['zlib'].prefix.lib, ]) + linkTypes = ['static'] + if '+shared' in spec: + linkTypes.append('shared') + + #TODO: at least one of these two options must be active + threadingOpts = [] + if '+multithreaded' in spec: + threadingOpts.append('multi') + if '+singlethreaded' in spec: + threadingOpts.append('single') + options.extend([ 'toolset=%s' % self.determine_toolset(spec), - 'link=static,shared', - 'threading=single,multi', + 'link=%s' % ','.join(linkTypes), + 'threading=%s' % ','.join(threadingOpts), '--layout=tagged']) def install(self, spec, prefix): + withLibs = list() + for lib in Boost.libs: + if "+{0}".format(lib) in spec: + withLibs.append(lib) + if not withLibs: + # if no libraries are specified for compilation, then you dont have + # to configure/build anything, just copy over to the prefix directory. + src = join_path(self.stage.source_path, 'boost') + mkdirp(join_path(prefix, 'include')) + dst = join_path(prefix, 'include', 'boost') + install_tree(src, dst) + return + # to make Boost find the user-config.jam env['BOOST_BUILD_PATH'] = './' bootstrap = Executable('./bootstrap.sh') bootstrap_options = ['--prefix=%s' % prefix] - self.determine_bootstrap_options(spec, bootstrap_options) + self.determine_bootstrap_options(spec, withLibs, bootstrap_options) bootstrap(*bootstrap_options) From d22cf1aed1d033610481cb451909c93916848ccc Mon Sep 17 00:00:00 2001 From: Peter Scheibel Date: Fri, 15 Jan 2016 18:07:41 -0800 Subject: [PATCH 2/6] 1. raise an exception if the multithreaded and singlethreaded options are both disabled 2. invoke the b2 installation once for each enabled threading option (apparently the install fails if a single call has both options enabled for mpi) --- var/spack/packages/boost/package.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/var/spack/packages/boost/package.py b/var/spack/packages/boost/package.py index 5fb6c9dc04..1992d4d39a 100644 --- a/var/spack/packages/boost/package.py +++ b/var/spack/packages/boost/package.py @@ -138,18 +138,20 @@ def determine_b2_options(self, spec, options): if '+shared' in spec: linkTypes.append('shared') - #TODO: at least one of these two options must be active threadingOpts = [] if '+multithreaded' in spec: threadingOpts.append('multi') if '+singlethreaded' in spec: threadingOpts.append('single') + if not threadingOpts: + raise RuntimeError("At least one of {singlethreaded, multithreaded} must be enabled") options.extend([ 'toolset=%s' % self.determine_toolset(spec), 'link=%s' % ','.join(linkTypes), - 'threading=%s' % ','.join(threadingOpts), '--layout=tagged']) + + return threadingOpts def install(self, spec, prefix): withLibs = list() @@ -181,6 +183,10 @@ def install(self, spec, prefix): b2 = Executable(b2name) b2_options = ['-j', '%s' % make_jobs] - self.determine_b2_options(spec, b2_options) + threadingOpts = self.determine_b2_options(spec, b2_options) - b2('install', *b2_options) + # In theory it could be done on one call but it fails on + # Boost.MPI if the threading options are not separated. + for threadingOpt in threadingOpts: + b2('install', 'threading=%s' % threadingOpt, *b2_options) + From 2e58bc31138ee172ea55ad652aaf49b09fe6e135 Mon Sep 17 00:00:00 2001 From: Peter Scheibel Date: Thu, 21 Jan 2016 19:57:49 -0800 Subject: [PATCH 3/6] Sticking with additive approach but now most libraries are installed by default. --- .../repos/builtin/packages/boost/package.py | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/var/spack/repos/builtin/packages/boost/package.py b/var/spack/repos/builtin/packages/boost/package.py index 1992d4d39a..f31bc445b8 100644 --- a/var/spack/repos/builtin/packages/boost/package.py +++ b/var/spack/repos/builtin/packages/boost/package.py @@ -45,28 +45,36 @@ class Boost(Package): version('1.34.1', '2d938467e8a448a2c9763e0a9f8ca7e5') version('1.34.0', 'ed5b9291ffad776f8757a916e1726ad0') - libs = ['chrono', + default_install_libs = set(['chrono', 'date_time', 'filesystem', - 'iostreams', + 'graph', + 'iostreams', + 'log', + 'math', 'random', 'regex', 'serialization', 'signals', 'system', 'thread', - 'wave', - 'mpi', - 'python'] + 'wave']) - for lib in libs: - variant(lib, default=False, description="Compile with {0} library" - .format(lib)) + # These are not installed by default because they pull in many dependencies + # and/or because there is a great deal of customization possible (and it + # would be difficult or tedious to choose sensible defaults here). + default_noinstall_libs = set(['mpi', 'python']) + + all_libs = default_install_libs | default_noinstall_libs + + for lib in all_libs: + variant(lib, default=(lib in default_install_libs), + description="Compile with {0} library".format(lib)) variant('debug', default=False, description='Switch to the debug version of Boost') variant('shared', default=True, description="Additionally build shared libraries") variant('multithreaded', default=True, description="Build multi-threaded versions of libraries") - variant('singlethreaded', default=False, description="Build single-threaded versions of libraries") + variant('singlethreaded', default=True, description="Build single-threaded versions of libraries") variant('regex_icu', default=False, description="Include regex ICU support (by default false even if regex library is compiled)") depends_on('icu', when='+regex_icu') From 4a55b97d11739a0ee6ca5ddcbdf35826ca292469 Mon Sep 17 00:00:00 2001 From: Peter Scheibel Date: Fri, 22 Jan 2016 12:37:12 -0800 Subject: [PATCH 4/6] Fixed reference --- var/spack/repos/builtin/packages/boost/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/boost/package.py b/var/spack/repos/builtin/packages/boost/package.py index f31bc445b8..467e9a61c6 100644 --- a/var/spack/repos/builtin/packages/boost/package.py +++ b/var/spack/repos/builtin/packages/boost/package.py @@ -163,7 +163,7 @@ def determine_b2_options(self, spec, options): def install(self, spec, prefix): withLibs = list() - for lib in Boost.libs: + for lib in Boost.all_libs: if "+{0}".format(lib) in spec: withLibs.append(lib) if not withLibs: From 9f99ee61c733e8fee8ae4058fb9198288af40fc6 Mon Sep 17 00:00:00 2001 From: Peter Scheibel Date: Fri, 22 Jan 2016 13:25:45 -0800 Subject: [PATCH 5/6] 1. added default install libs (atomic, test, locale, program_options) 2. clarify comment for default_noinstall_libs 3. renamed regex_icu variant to icu_support (both the locale and regex libs can use it) 4. explicitly set b2 install ICU_PATH when regex_icu is activated --- .../repos/builtin/packages/boost/package.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/var/spack/repos/builtin/packages/boost/package.py b/var/spack/repos/builtin/packages/boost/package.py index 467e9a61c6..1403ea4411 100644 --- a/var/spack/repos/builtin/packages/boost/package.py +++ b/var/spack/repos/builtin/packages/boost/package.py @@ -45,24 +45,28 @@ class Boost(Package): version('1.34.1', '2d938467e8a448a2c9763e0a9f8ca7e5') version('1.34.0', 'ed5b9291ffad776f8757a916e1726ad0') - default_install_libs = set(['chrono', + default_install_libs = set(['atomic', + 'chrono', 'date_time', 'filesystem', 'graph', 'iostreams', + 'locale', 'log', 'math', + 'program_options', 'random', 'regex', 'serialization', 'signals', 'system', + 'test', 'thread', 'wave']) - # These are not installed by default because they pull in many dependencies - # and/or because there is a great deal of customization possible (and it - # would be difficult or tedious to choose sensible defaults here). + # mpi/python are not installed by default because they pull in many + # dependencies and/or because there is a great deal of customization + # possible (and it would be difficult to choose sensible defaults) default_noinstall_libs = set(['mpi', 'python']) all_libs = default_install_libs | default_noinstall_libs @@ -75,9 +79,9 @@ class Boost(Package): variant('shared', default=True, description="Additionally build shared libraries") variant('multithreaded', default=True, description="Build multi-threaded versions of libraries") variant('singlethreaded', default=True, description="Build single-threaded versions of libraries") - variant('regex_icu', default=False, description="Include regex ICU support (by default false even if regex library is compiled)") + variant('icu_support', default=False, description="Include ICU support (for regex/locale libraries)") - depends_on('icu', when='+regex_icu') + depends_on('icu', when='+icu_support') depends_on('python', when='+python') depends_on('mpi', when='+mpi') depends_on('bzip2', when='+iostreams') @@ -134,6 +138,9 @@ def determine_b2_options(self, spec, options): else: options.append('variant=release') + if '+icu_support' in spec: + options.extend(['-s', 'ICU_PATH=%s' % spec['icu'].prefix]) + if '+iostreams' in spec: options.extend([ '-s', 'BZIP2_INCLUDE=%s' % spec['bzip2'].prefix.include, From a653d2f5e2f296ff66eb41ffb9f2f6e9b9bdb3b5 Mon Sep 17 00:00:00 2001 From: Peter Scheibel Date: Fri, 22 Jan 2016 13:43:16 -0800 Subject: [PATCH 6/6] Slightly more robust approach for setting defaults for noinstall_libs --- var/spack/repos/builtin/packages/boost/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/boost/package.py b/var/spack/repos/builtin/packages/boost/package.py index 1403ea4411..a30cd7cc35 100644 --- a/var/spack/repos/builtin/packages/boost/package.py +++ b/var/spack/repos/builtin/packages/boost/package.py @@ -72,7 +72,7 @@ class Boost(Package): all_libs = default_install_libs | default_noinstall_libs for lib in all_libs: - variant(lib, default=(lib in default_install_libs), + variant(lib, default=(lib not in default_noinstall_libs), description="Compile with {0} library".format(lib)) variant('debug', default=False, description='Switch to the debug version of Boost')