From 1f2e56e1f3452fdc9b6dde349a67efc217292b04 Mon Sep 17 00:00:00 2001 From: Mark Olesen Date: Wed, 21 Jun 2017 17:35:31 +0100 Subject: [PATCH] refactor openfoam packages (#3669) * Several improvements for the openfoam packages -- Refactor openfoam packages by adding an OpenfoamArch class Use separate configure, build, install phases. Provide FOAM_PROJECT_DIR dependent env for openfoam packages - easier way to locate Eliminate intermediate installation directories - unneeded clutter. - makes it less than easy to find the etc/bashrc file Add versioning for all openfoam patches - no certainty which parts (if any) will be needed in future versions, especially if we strive to ensure that the upstream version builds well with spack to begin with. Support build of develop branches - helps track build regressions for future openfoam releases STYLE: use common/ and assets/ to provide additional (build) resources ... * - adjust OpenFOAM provider Move openfoam-com up front since this is the one being used as a base for the others --- etc/spack/defaults/packages.yaml | 2 +- .../builtin/packages/foam-extend/package.py | 290 +++----- .../packages/openfoam-com/common/README | 2 + .../packages/openfoam-com/common/README-spack | 15 + .../openfoam-com/common/change-sitedir.sh | 94 +++ .../openfoam-com/common/change-userdir.sh | 94 +++ .../openfoam-com/common/spack-Allwmake | 22 + .../common/spack-derived-Allwmake | 26 + .../openfoam-com/mgridgen-lib-1612.patch | 41 ++ ...am-site.patch => openfoam-site-1612.patch} | 6 +- .../openfoam-com/openfoam-site-plus.patch | 35 + .../builtin/packages/openfoam-com/package.py | 677 ++++++++++-------- .../openfoam-org/assets/bin/foamEtcFile | 417 +++++++++++ ...foam-site.patch => openfoam-site-41.patch} | 6 +- .../builtin/packages/openfoam-org/package.py | 340 +++------ 15 files changed, 1313 insertions(+), 754 deletions(-) create mode 100644 var/spack/repos/builtin/packages/openfoam-com/common/README create mode 100644 var/spack/repos/builtin/packages/openfoam-com/common/README-spack create mode 100644 var/spack/repos/builtin/packages/openfoam-com/common/change-sitedir.sh create mode 100644 var/spack/repos/builtin/packages/openfoam-com/common/change-userdir.sh create mode 100755 var/spack/repos/builtin/packages/openfoam-com/common/spack-Allwmake create mode 100755 var/spack/repos/builtin/packages/openfoam-com/common/spack-derived-Allwmake create mode 100644 var/spack/repos/builtin/packages/openfoam-com/mgridgen-lib-1612.patch rename var/spack/repos/builtin/packages/openfoam-com/{openfoam-site.patch => openfoam-site-1612.patch} (86%) create mode 100644 var/spack/repos/builtin/packages/openfoam-com/openfoam-site-plus.patch create mode 100755 var/spack/repos/builtin/packages/openfoam-org/assets/bin/foamEtcFile rename var/spack/repos/builtin/packages/openfoam-org/{openfoam-site.patch => openfoam-site-41.patch} (86%) diff --git a/etc/spack/defaults/packages.yaml b/etc/spack/defaults/packages.yaml index 0cafab28e90..d04ce76e6b4 100644 --- a/etc/spack/defaults/packages.yaml +++ b/etc/spack/defaults/packages.yaml @@ -28,6 +28,6 @@ packages: mpe: [mpe2] mpi: [openmpi, mpich] opencl: [pocl] - openfoam: [foam-extend] + openfoam: [openfoam-com, openfoam-org, foam-extend] pil: [py-pillow] scalapack: [netlib-scalapack] diff --git a/var/spack/repos/builtin/packages/foam-extend/package.py b/var/spack/repos/builtin/packages/foam-extend/package.py index c68e570c0fd..d417ef8cf33 100644 --- a/var/spack/repos/builtin/packages/foam-extend/package.py +++ b/var/spack/repos/builtin/packages/foam-extend/package.py @@ -48,16 +48,17 @@ # - reworked to mirror the openfoam-com package. # If changes are needed here, consider if they need applying there too. # +# Known issues +# - Combining +parmgridgen with +float32 probably won't work. +# ############################################################################## from spack import * from spack.environment import * -import multiprocessing import glob import re import shutil import os -from os.path import isdir, isfile from spack.pkg.builtin.openfoam_com import * @@ -77,10 +78,9 @@ class FoamExtend(Package): version('3.0', git='http://git.code.sf.net/p/foam-extend/foam-extend-3.0') # variant('int64', default=False, - # description='Compile with 64-bit labels') + # description='Compile with 64-bit label') variant('float32', default=False, description='Compile with 32-bit scalar (single-precision)') - variant('paraview', default=False, description='Build paraview plugins (eg, paraFoam)') variant('scotch', default=True, @@ -96,10 +96,6 @@ class FoamExtend(Package): variant('source', default=True, description='Install library/application sources and tutorials') - #: Map spack compiler names to OpenFOAM compiler names - # By default, simply capitalize the first letter - compiler_mapping = {'intel': 'icc'} - provides('openfoam') depends_on('mpi') depends_on('python') @@ -111,25 +107,22 @@ class FoamExtend(Package): depends_on('scotch~metis+mpi', when='+ptscotch') depends_on('metis@5:', when='+metis') depends_on('parmetis', when='+parmetis') - depends_on('parmgridgen', when='+parmgridgen') + # mgridgen is statically linked + depends_on('parmgridgen', when='+parmgridgen', type='build') depends_on('paraview@:5.0.1', when='+paraview') - # Some user settings, to be adjusted manually or via variants - foam_cfg = { - 'WM_COMPILER': 'Gcc', # <- %compiler - 'WM_ARCH_OPTION': '64', # (32/64-bit on x86_64) - # FUTURE? 'WM_LABEL_SIZE': '32', # <- +int64 - 'WM_PRECISION_OPTION': 'DP', # <- +float32 - 'WM_COMPILE_OPTION': 'SPACKOpt', # Do not change - 'WM_MPLIB': 'USER', # USER | USERMPI + # General patches + common = ['spack-Allwmake', 'README-spack'] + assets = [] + + # Some user config settings + config = { + 'label-size': False, # <- No int32/int64 support + 'mplib': 'USERMPI', # USER | USERMPI } - # The system description is frequently needed - foam_sys = { - 'WM_ARCH': None, - 'WM_COMPILER': None, - 'WM_OPTIONS': None, - } + # The openfoam architecture, compiler information etc + _foam_arch = None # Content for etc/prefs.{csh,sh} etc_prefs = {} @@ -137,163 +130,54 @@ class FoamExtend(Package): # Content for etc/config.{csh,sh}/ files etc_config = {} - build_script = './spack-Allwmake' # <- Generated by patch() method. - # phases = ['configure', 'build', 'install'] - # build_system_class = 'OpenfoamCom' + phases = ['configure', 'build', 'install'] + build_script = './spack-Allwmake' # <- Added by patch() method. + + # + # - End of definitions / setup - + # def setup_environment(self, spack_env, run_env): - run_env.set('FOAM_INST_DIR', self.prefix) + run_env.set('FOAM_INST_DIR', os.path.dirname(self.projectdir)), + run_env.set('FOAM_PROJECT_DIR', self.projectdir) run_env.set('WM_PROJECT_DIR', self.projectdir) + for d in ['wmake', self.archbin]: # bin already added automatically + run_env.prepend_path('PATH', join_path(self.projectdir, d)) + run_env.set('MPI_BUFFER_SIZE', "20000000") - @property - def _canonical(self): - """Canonical name for this package and version""" - return 'foam-extend-{0}'.format(self.version.up_to(2)) + def setup_dependent_environment(self, spack_env, run_env, dependent_spec): + """Provide location of the OpenFOAM project. + This is identical to the WM_PROJECT_DIR value, but we avoid that + variable since it would mask the normal OpenFOAM cleanup of + previous versions. + """ + spack_env.set('FOAM_PROJECT_DIR', self.projectdir) @property def projectdir(self): """Absolute location of project directory: WM_PROJECT_DIR/""" - return join_path(self.prefix, self._canonical) # <- prefix/canonical + return self.prefix # <- install directly under prefix @property - def etc(self): - """Absolute location of the OpenFOAM etc/ directory""" - return join_path(self.projectdir, 'etc') + def foam_arch(self): + if not self._foam_arch: + self._foam_arch = OpenfoamArch(self.spec, **self.config) + return self._foam_arch @property def archbin(self): """Relative location of architecture-specific executables""" - wm_options = self.set_openfoam() - return join_path('applications', 'bin', wm_options) + return join_path('applications', 'bin', self.foam_arch) @property def archlib(self): """Relative location of architecture-specific libraries""" - wm_options = self.set_openfoam() - return join_path('lib', wm_options) - - @property - def wm_options(self): - """The architecture+compiler+options for OpenFOAM""" - opts = self.set_openfoam() - return opts - - @property - def rpath_info(self): - """Define 'SPACKOpt' compiler optimization file to have wmake - use spack information with minimum modifications to OpenFOAM - """ - build_libpath = join_path(self.stage.source_path, self.archlib) - install_libpath = join_path(self.projectdir, self.archlib) - - # 'DBUG': rpaths - return '{0}{1} {2}{3}'.format( - self.compiler.cxx_rpath_arg, install_libpath, - self.compiler.cxx_rpath_arg, build_libpath) - - def openfoam_arch(self): - """Return an architecture value similar to what OpenFOAM does in - etc/config.sh/settings, but slightly more generous. - Uses and may adjust foam_cfg[WM_ARCH_OPTION] as a side-effect - """ - # spec.architecture.platform is like `uname -s`, but lower-case - platform = self.spec.architecture.platform - - # spec.architecture.target is like `uname -m` - target = self.spec.architecture.target - - if platform == 'linux': - if target == 'i686': - self.foam_cfg['WM_ARCH_OPTION'] = '32' # Force consistency - elif target == 'x86_64': - if self.foam_cfg['WM_ARCH_OPTION'] == '64': - platform += '64' - elif target == 'ia64': - platform += 'ia64' - elif target == 'armv7l': - platform += 'ARM7' - elif target == ppc64: - platform += 'PPC64' - elif target == ppc64le: - platform += 'PPC64le' - elif platform == 'darwin': - if target == 'x86_64': - platform += 'Intel' - if self.foam_cfg['WM_ARCH_OPTION'] == '64': - platform += '64' - # ... and others? - return platform - - def openfoam_compiler(self): - """Capitalized version of the compiler name, which usually corresponds - to how OpenFOAM will camel-case things. - Use compiler_mapping to handing special cases. - Also handle special compiler options (eg, KNL) - """ - comp = self.compiler.name - if comp in self.compiler_mapping: - comp = self.compiler_mapping[comp] - comp = comp.capitalize() - - if '+knl' in self.spec: - comp += 'KNL' - return comp - - # For foam-extend: does not yet support +int64 - def set_openfoam(self): - """Populate foam_cfg, foam_sys according to - variants, architecture, compiler. - Returns WM_OPTIONS. - """ - # Run once - opts = self.foam_sys['WM_OPTIONS'] - if opts: - return opts - - wm_arch = self.openfoam_arch() - wm_compiler = self.openfoam_compiler() - compileOpt = self.foam_cfg['WM_COMPILE_OPTION'] - - # Insist on a wmake rule for this architecture/compiler combination - archCompiler = wm_arch + wm_compiler - compiler_rule = join_path( - self.stage.source_path, 'wmake', 'rules', archCompiler) - - if not isdir(compiler_rule): - raise RuntimeError( - 'No wmake rule for {0}'.format(archCompiler)) - if not re.match(r'.+Opt$', compileOpt): - raise RuntimeError( - "WM_COMPILE_OPTION={0} is not type '*Opt'".format(compileOpt)) - - # Adjust for variants - # FUTURE? self.foam_cfg['WM_LABEL_SIZE'] = ( - # FUTURE? '64' if '+int64' in self.spec else '32' - # FUTURE? ) - self.foam_cfg['WM_PRECISION_OPTION'] = ( - 'SP' if '+float32' in self.spec else 'DP' - ) - - # ---- - # WM_OPTIONS=$WM_ARCH$WM_COMPILER$WM_PRECISION_OPTION$WM_COMPILE_OPTION - # ---- - self.foam_sys['WM_ARCH'] = wm_arch - self.foam_sys['WM_COMPILER'] = wm_compiler - self.foam_cfg['WM_COMPILER'] = wm_compiler # For bashrc,cshrc too - self.foam_sys['WM_OPTIONS'] = ''.join([ - wm_arch, - wm_compiler, - self.foam_cfg['WM_PRECISION_OPTION'], - # FUTURE? 'Int', self.foam_cfg['WM_LABEL_SIZE'], # Int32/Int64 - compileOpt - ]) - return self.foam_sys['WM_OPTIONS'] + return join_path('lib', self.foam_arch) def patch(self): - """Adjust OpenFOAM build for spack. Where needed, apply filter as an - alternative to normal patching. - """ - self.set_openfoam() # May need foam_cfg/foam_sys information + """Adjust OpenFOAM build for spack. + Where needed, apply filter as an alternative to normal patching.""" + add_extra_files(self, self.common, self.assets) # Adjust ParMGridGen - this is still a mess files = [ @@ -319,23 +203,7 @@ def patch(self): filter_file( r'#if YY_FLEX_SUBMINOR_VERSION < 34', r'#if YY_FLEX_MAJOR_VERSION <= 2 && YY_FLEX_MINOR_VERSION <= 5 && YY_FLEX_SUBMINOR_VERSION < 34', # noqa: E501 - f, backup=False - ) - - # Build wrapper script - with open(self.build_script, 'w') as out: - out.write( - """#!/bin/bash -export FOAM_INST_DIR=$(cd .. && pwd -L) -. $PWD/etc/bashrc '' # No arguments -mkdir -p $FOAM_APPBIN $FOAM_LIBBIN 2>/dev/null # Allow interrupt -echo Build openfoam with SPACK -echo WM_PROJECT_DIR = $WM_PROJECT_DIR -./Allwmake # No arguments -# -""") - set_executable(self.build_script) - self.configure(self.spec, self.prefix) # Should be a separate phase + f, backup=False) def configure(self, spec, prefix): """Make adjustments to the OpenFOAM configuration files in their various @@ -343,8 +211,6 @@ def configure(self, spec, prefix): don't properly fit get placed in the etc/prefs.sh file (similiarly for csh). """ - self.set_openfoam() # Need foam_cfg/foam_sys information - # Content for etc/prefs.{csh,sh} self.etc_prefs = { '000': { # Sort first @@ -373,7 +239,7 @@ def configure(self, spec, prefix): }, } # Adjust configuration via prefs - sort second - self.etc_prefs['001'].update(self.foam_cfg) + self.etc_prefs['001'].update(self.foam_arch.foam_dict()) if '+scotch' in spec or '+ptscotch' in spec: pkg = spec['scotch'].prefix @@ -434,41 +300,33 @@ def configure(self, spec, prefix): posix=join_path('etc', 'prefs.sh'), cshell=join_path('etc', 'prefs.csh')) - archCompiler = self.foam_sys['WM_ARCH'] + self.foam_sys['WM_COMPILER'] - compileOpt = self.foam_cfg['WM_COMPILE_OPTION'] - # general_rule = join_path('wmake', 'rules', 'General') - compiler_rule = join_path('wmake', 'rules', archCompiler) - generate_mplib_rules(compiler_rule, self.spec) - generate_compiler_rules(compiler_rule, compileOpt, self.rpath_info) - # Record the spack spec information - with open("log.spack-spec", 'w') as outfile: - outfile.write(spec.tree()) - def build(self, spec, prefix): """Build using the OpenFOAM Allwmake script, with a wrapper to source its environment first. + Only build if the compiler is known to be supported. """ - self.set_openfoam() # Force proper population of foam_cfg/foam_sys + self.foam_arch.has_rule(self.stage.source_path) + self.foam_arch.create_rules(self.stage.source_path, self) + args = [] if self.parallel: # Build in parallel? - pass via the environment - os.environ['WM_NCOMPPROCS'] = str(self.make_jobs) \ - if self.make_jobs else str(multiprocessing.cpu_count()) + os.environ['WM_NCOMPPROCS'] = str(make_jobs) builder = Executable(self.build_script) builder(*args) def install(self, spec, prefix): - """Install under the projectdir (== prefix/name-version)""" - self.build(spec, prefix) # Should be a separate phase - opts = self.wm_options + """Install under the projectdir""" + opts = str(self.foam_arch) # Fairly ugly since intermediate targets are scattered inside sources appdir = 'applications' + projdir = os.path.basename(self.projectdir) mkdirp(self.projectdir, join_path(self.projectdir, appdir)) - - # Retain build log file - out = "spack-build.out" - if isfile(out): - install(out, join_path(self.projectdir, "log." + opts)) + # Filtering: bashrc, cshrc + edits = { + 'WM_PROJECT_INST_DIR': os.path.dirname(self.projectdir), + 'WM_PROJECT_DIR': join_path('$WM_PROJECT_INST_DIR', projdir), + } # All top-level files, except spack build info and possibly Allwmake if '+source' in spec: @@ -477,36 +335,52 @@ def install(self, spec, prefix): ignored = re.compile(r'^(Allclean|Allwmake|spack-).*') files = [ - f for f in glob.glob("*") if isfile(f) and not ignored.search(f) + f for f in glob.glob("*") + if os.path.isfile(f) and not ignored.search(f) ] for f in files: install(f, self.projectdir) # Install directories. install applications/bin directly - for d in ['bin', 'etc', 'wmake', 'lib', join_path(appdir, 'bin')]: + # Install 'etc' before 'bin' (for symlinks) + for d in ['etc', 'bin', 'wmake', 'lib', join_path(appdir, 'bin')]: install_tree( d, - join_path(self.projectdir, d)) + join_path(self.projectdir, d), + symlinks=True) if '+source' in spec: subitem = join_path(appdir, 'Allwmake') install(subitem, join_path(self.projectdir, subitem)) - ignored = [opts] # Intermediate targets + ignored = [opts] # Ignore intermediate targets for d in ['src', 'tutorials']: install_tree( d, join_path(self.projectdir, d), - ignore=shutil.ignore_patterns(*ignored)) + ignore=shutil.ignore_patterns(*ignored), + symlinks=True) for d in ['solvers', 'utilities']: install_tree( join_path(appdir, d), join_path(self.projectdir, appdir, d), - ignore=shutil.ignore_patterns(*ignored)) + ignore=shutil.ignore_patterns(*ignored), + symlinks=True) + + etc_dir = join_path(self.projectdir, 'etc') + rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc + edits, + posix=join_path(etc_dir, 'bashrc'), + cshell=join_path(etc_dir, 'cshrc')) + self.install_links() def install_links(self): """Add symlinks into bin/, lib/ (eg, for other applications)""" - return + # Make build log visible - it contains OpenFOAM-specific information + with working_dir(self.projectdir): + os.symlink( + join_path('.spack', 'build.out'), + join_path('log.' + str(self.foam_arch))) # ----------------------------------------------------------------------------- diff --git a/var/spack/repos/builtin/packages/openfoam-com/common/README b/var/spack/repos/builtin/packages/openfoam-com/common/README new file mode 100644 index 00000000000..d116bbaa23d --- /dev/null +++ b/var/spack/repos/builtin/packages/openfoam-com/common/README @@ -0,0 +1,2 @@ +Some helper tools for packaging applications/libraries dependent on an +openfoam provider. diff --git a/var/spack/repos/builtin/packages/openfoam-com/common/README-spack b/var/spack/repos/builtin/packages/openfoam-com/common/README-spack new file mode 100644 index 00000000000..83b606dda17 --- /dev/null +++ b/var/spack/repos/builtin/packages/openfoam-com/common/README-spack @@ -0,0 +1,15 @@ +Additional notes for spack +-------------------------- + +OpenFOAM largely manages its own PATH and LD_LIBRARY_PATH settings. +The spack build currently also follows this and only provides +a minimum modules environment. + +The variable FOAM_PROJECT_DIR points to the location of the OpenFOAM project +and shall contain a $FOAM_PROJECT_DIR/etc/bashrc file for OpenFOAM. +The variable FOAM_INST_DIR may also be provided for older OpenFOAM versions. + +It is the aim for the future to use spack to provide the environment directly, +but this still needs more work. + +2017-04-18 diff --git a/var/spack/repos/builtin/packages/openfoam-com/common/change-sitedir.sh b/var/spack/repos/builtin/packages/openfoam-com/common/change-sitedir.sh new file mode 100644 index 00000000000..61d9c3ea8b6 --- /dev/null +++ b/var/spack/repos/builtin/packages/openfoam-com/common/change-sitedir.sh @@ -0,0 +1,94 @@ +#----------------------------------*-sh-*-------------------------------------- +# ========= | +# \\ / F ield | OpenFOAM: The Open Source CFD Toolbox +# \\ / O peration | +# \\ / A nd | Copyright (C) 2017 OpenCFD Ltd. +# \\/ M anipulation | +#------------------------------------------------------------------------------ +# License +# This file is part of OpenFOAM. +# +# OpenFOAM is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# OpenFOAM is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with OpenFOAM. If not, see . +# +# Script +# . change-sitedir.sh PREFIX [SUFFIX] +# +# Shortcuts (prefix) +# -prefix "$WM_PROJECT_INST_DIR/site" +# -project "$WM_PROJECT_DIR/site" +# -none remove from environment +# +# Shortcuts (suffix) +# -platforms "platforms/$WM_OPTIONS" +# +# Description +# Change WM_PROJECT_SITE, FOAM_SITE_APPBIN, FOAM_SITE_LIBBIN +# and the respective entries in PATH, LD_LIBRARY_PATH. +# +# This can be useful when temporarily reassigning the site directory +# when packaging OpenFOAM. +# +# The suffix value should normally include "platforms/$WM_OPTIONS" +# +# Example +# . /path/change-sitedir.sh -prefix -platforms +# +# corresponds to the standard site location: +# +# $WM_PROJECT_INST_DIR/site{/$WM_PROJECT_VERSION/platforms/$WM_OPTIONS} +# +#------------------------------------------------------------------------------ + +if [ "$#" -ge 1 ] +then + prefix="$1" + suffix="$2" + + foamOldDirs="$FOAM_SITE_APPBIN $FOAM_SITE_LIBBIN \ + $WM_PROJECT_SITE $WM_PROJECT_INST_DIR/site $WM_PROJECT_DIR/site" + foamClean=$WM_PROJECT_DIR/bin/foamCleanPath + if [ -x "$foamClean" ] + then + cleaned=$($foamClean "$PATH" "$foamOldDirs") && PATH="$cleaned" + cleaned=$($foamClean "$LD_LIBRARY_PATH" "$foamOldDirs") \ + && LD_LIBRARY_PATH="$cleaned" + fi + + case "$suffix" in + -plat*) suffix="platforms/$WM_OPTIONS" ;; + esac + case "$prefix" in + -prefix) prefix="$WM_PROJECT_INST_DIR/site" ;; + -project) prefix="$WM_PROJECT_DIR/site" ;; + -none) unset prefix ;; + esac + + if [ -n "$prefix" ] + then + export WM_PROJECT_SITE="$prefix" + + prefix="$prefix/${WM_PROJECT_VERSION:-unknown}${suffix:+/}${suffix}" + + export FOAM_SITE_APPBIN="$prefix/bin" + export FOAM_SITE_LIBBIN="$prefix/lib" + PATH="$FOAM_SITE_APPBIN:$PATH" + LD_LIBRARY_PATH="$FOAM_SITE_LIBBIN:$LD_LIBRARY_PATH" + else + unset WM_PROJECT_SITE FOAM_SITE_APPBIN FOAM_SITE_LIBBIN + fi +fi + +unset foamClean foamOldDirs cleaned prefix suffix + +#------------------------------------------------------------------------------ diff --git a/var/spack/repos/builtin/packages/openfoam-com/common/change-userdir.sh b/var/spack/repos/builtin/packages/openfoam-com/common/change-userdir.sh new file mode 100644 index 00000000000..d126fcfe5d1 --- /dev/null +++ b/var/spack/repos/builtin/packages/openfoam-com/common/change-userdir.sh @@ -0,0 +1,94 @@ +#----------------------------------*-sh-*-------------------------------------- +# ========= | +# \\ / F ield | OpenFOAM: The Open Source CFD Toolbox +# \\ / O peration | +# \\ / A nd | Copyright (C) 2017 OpenCFD Ltd. +# \\/ M anipulation | +#------------------------------------------------------------------------------ +# License +# This file is part of OpenFOAM. +# +# OpenFOAM is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# OpenFOAM is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with OpenFOAM. If not, see . +# +# Script +# . change-userdir.sh PREFIX [SUFFIX] +# +# Shortcuts (prefix) +# -home "$HOME/OpenFOAM/$USER-$WM_PROJECT_VERSION" +# -none remove from environment +# +# Shortcuts (suffix) +# -platforms "platforms/$WM_OPTIONS" +# +# Description +# Change WM_PROJECT_USER_DIR, FOAM_USER_APPBIN, FOAM_USER_LIBBIN +# and the respective entries in PATH, LD_LIBRARY_PATH. +# Also adjusts FOAM_RUN. +# +# This can be useful with compiling additional OpenFOAM programs +# (that use FOAM_USER_APPBIN, FOAM_USER_LIBBIN for their build), +# to avoid conflicts with the normal user bin/lib files. +# +# The suffix value should normally include "platforms/$WM_OPTIONS" +# +# Example +# . /path/change-userdir.sh -home -platforms +# +# corresponds to the standard user location: +# +# $HOME/OpenFOAM/$USER-$WM_PROJECT_VERSION/platforms/$WM_OPTIONS +# +#------------------------------------------------------------------------------ + +if [ "$#" -ge 1 ] +then + prefix="$1" + suffix="$2" + + foamOldDirs="$FOAM_USER_APPBIN $FOAM_USER_LIBBIN" + foamClean=$WM_PROJECT_DIR/bin/foamCleanPath + if [ -x "$foamClean" ] + then + cleaned=$($foamClean "$PATH" "$foamOldDirs") && PATH="$cleaned" + cleaned=$($foamClean "$LD_LIBRARY_PATH" "$foamOldDirs") \ + && LD_LIBRARY_PATH="$cleaned" + fi + + case "$suffix" in + -plat*) suffix="platforms/$WM_OPTIONS" ;; + esac + case "$prefix" in + -home) prefix="$HOME/OpenFOAM/$USER-${WM_PROJECT_VERSION:-unknown}" ;; + -none) unset prefix ;; + esac + + if [ -n "$prefix" ] + then + export WM_PROJECT_USER_DIR="$prefix" + export FOAM_RUN="$prefix/run" + + prefix="$prefix${suffix:+/}${suffix}" + export FOAM_USER_APPBIN="$prefix/bin" + export FOAM_USER_LIBBIN="$prefix/lib" + + PATH="$FOAM_USER_APPBIN:$PATH" + LD_LIBRARY_PATH="$FOAM_USER_LIBBIN:$LD_LIBRARY_PATH" + else + unset WM_PROJECT_USER_DIR FOAM_RUN FOAM_USER_APPBIN FOAM_USER_LIBBIN + fi +fi + +unset foamClean foamOldDirs cleaned prefix suffix + +#------------------------------------------------------------------------------ diff --git a/var/spack/repos/builtin/packages/openfoam-com/common/spack-Allwmake b/var/spack/repos/builtin/packages/openfoam-com/common/spack-Allwmake new file mode 100755 index 00000000000..cff22daf100 --- /dev/null +++ b/var/spack/repos/builtin/packages/openfoam-com/common/spack-Allwmake @@ -0,0 +1,22 @@ +#!/bin/bash +# Build wrapper script - FOAM_INST_DIR is only required by foam-extend +export FOAM_INST_DIR=$(cd .. && pwd -L) +. $PWD/etc/bashrc '' # No arguments +mkdir -p $FOAM_APPBIN $FOAM_LIBBIN 2>/dev/null # Allow interrupt +echo "Build openfoam with SPACK ($@)" +echo WM_PROJECT_DIR = $WM_PROJECT_DIR +./Allwmake $@ # Pass arguments + +# Link non-dummy MPI_FOAM type to parent-dir, where rpath can find it +if [ "${FOAM_MPI:=dummy}" != dummy -a -d "$FOAM_LIBBIN/$FOAM_MPI" ] +then +( + cd "$FOAM_LIBBIN" || exit 1 + for i in $FOAM_MPI/lib*.so + do + [ -f $i ] && ln -sf $i "${i##*/}" + done +) +fi + +# ----------------------------------------------------------------------------- diff --git a/var/spack/repos/builtin/packages/openfoam-com/common/spack-derived-Allwmake b/var/spack/repos/builtin/packages/openfoam-com/common/spack-derived-Allwmake new file mode 100755 index 00000000000..407ad734e8c --- /dev/null +++ b/var/spack/repos/builtin/packages/openfoam-com/common/spack-derived-Allwmake @@ -0,0 +1,26 @@ +#!/bin/bash +# The openfoam providers must export 'FOAM_PROJECT_DIR' +# The package is expected to supply an appropriate Allwmake file. + +[ -d "$FOAM_PROJECT_DIR" -a -f "$FOAM_PROJECT_DIR/etc/bashrc" ] || { + echo "Error: no PROJECT=$FOAM_PROJECT_DIR" 1>&2 + echo " or no etc/bashrc found" 1>&2 + exit 1 +} + +export FOAM_INST_DIR=$(cd $FOAM_PROJECT_DIR/.. && pwd -L) # Needed by foam-extend +. $FOAM_PROJECT_DIR/etc/bashrc '' # No arguments + +# Package-specific adjustments +[ -f spack-config.sh ] && . ./spack-config.sh '' # No arguments + +echo "========================================" +date "+%Y-%m-%d %H:%M:%S %z" 2>/dev/null || echo "date is unknown" +echo "Build with ${WM_PROJECT}-${WM_PROJECT_VERSION}" +echo " WM_PROJECT_DIR = $WM_PROJECT_DIR" +echo " $WM_COMPILER $WM_COMPILER_TYPE compiler" +echo " $WM_OPTIONS - with $WM_MPLIB $FOAM_MPI" +echo + +./Allwmake $@ # Pass arguments +# ----------------------------------------------------------------------------- diff --git a/var/spack/repos/builtin/packages/openfoam-com/mgridgen-lib-1612.patch b/var/spack/repos/builtin/packages/openfoam-com/mgridgen-lib-1612.patch new file mode 100644 index 00000000000..8dc0b995ff8 --- /dev/null +++ b/var/spack/repos/builtin/packages/openfoam-com/mgridgen-lib-1612.patch @@ -0,0 +1,41 @@ +--- OpenFOAM-v1612+.orig/src/fvAgglomerationMethods/Allwmake 2017-01-02 09:56:17.578558265 +0100 ++++ OpenFOAM-v1612+/src/fvAgglomerationMethods/Allwmake 2017-04-18 18:58:38.236795902 +0200 +@@ -4,9 +4,13 @@ + # Parse arguments for library compilation + . $WM_PROJECT_DIR/wmake/scripts/AllwmakeParseArguments + +-export ParMGridGen=$WM_THIRD_PARTY_DIR/ParMGridGen-1.0 ++unset MGRIDGEN_ARCH_PATH ++if settings=$($WM_PROJECT_DIR/bin/foamEtcFile config.sh/mgridgen) ++then ++ . $settings ++fi + +-if [ -e "$FOAM_LIBBIN/libMGridGen.so" ] ++if [ -e "$MGRIDGEN_ARCH_PATH/include/mgridgen.h" ] + then + wmake $targetType MGridGenGamgAgglomeration + fi +--- OpenFOAM-v1612+.orig/src/fvAgglomerationMethods/MGridGenGamgAgglomeration/Make/options 2017-01-02 09:56:17.578558265 +0100 ++++ OpenFOAM-v1612+/src/fvAgglomerationMethods/MGridGenGamgAgglomeration/Make/options 2017-04-18 18:59:16.860662811 +0200 +@@ -1,15 +1,9 @@ +-/* Needs ParMGridGen environment variable set. (see Allwmake script) */ +- +-TYPE_REAL= +-#if defined(WM_SP) +-TYPE_REAL=-DTYPE_REAL +-#endif +- + EXE_INC = \ + -I$(LIB_SRC)/finiteVolume/lnInclude \ +- -I$(ParMGridGen)/MGridGen/Lib/lnInclude \ +- -I$(ParMGridGen)/MGridGen/IMlib/lnInclude \ +- $(TYPE_REAL) ++ -I$(MGRIDGEN_ARCH_PATH)/include + + LIB_LIBS = \ +- -L$(FOAM_EXT_LIBBIN) -lMGridGen ++ -L$(FOAM_EXT_LIBBIN) \ ++ -L$(MGRIDGEN_ARCH_PATH)/lib \ ++ -L$(MGRIDGEN_ARCH_PATH)/lib$(WM_COMPILER_LIB_ARCH) \ ++ -lmgrid diff --git a/var/spack/repos/builtin/packages/openfoam-com/openfoam-site.patch b/var/spack/repos/builtin/packages/openfoam-com/openfoam-site-1612.patch similarity index 86% rename from var/spack/repos/builtin/packages/openfoam-com/openfoam-site.patch rename to var/spack/repos/builtin/packages/openfoam-com/openfoam-site-1612.patch index 66310257885..d988c2f9b85 100644 --- a/var/spack/repos/builtin/packages/openfoam-com/openfoam-site.patch +++ b/var/spack/repos/builtin/packages/openfoam-com/openfoam-site-1612.patch @@ -6,7 +6,7 @@ diff -uw OpenFOAM-v1612+.orig/etc/config.sh/settings OpenFOAM-v1612+/etc/config. # Location of the jobControl directory -export FOAM_JOB_DIR=$WM_PROJECT_INST_DIR/jobControl -+export FOAM_JOB_DIR=$HOME/$WM_PROJECT/jobControl #SPACK: non-central location ++export FOAM_JOB_DIR=$HOME/.OpenFOAM/jobControl #SPACK: non-central location # wmake configuration export WM_DIR=$WM_PROJECT_DIR/wmake @@ -15,7 +15,7 @@ diff -uw OpenFOAM-v1612+.orig/etc/config.sh/settings OpenFOAM-v1612+/etc/config. # Site-specific directory -siteDir="${WM_PROJECT_SITE:-$WM_PROJECT_INST_DIR/site}" -+siteDir="${WM_PROJECT_SITE:-$WM_PROJECT/site}" #SPACK: not in parent directory ++siteDir="${WM_PROJECT_SITE:-$WM_PROJECT_DIR/site}" #SPACK: not in parent directory # Shared site executables/libraries # Similar naming convention as ~OpenFOAM expansion @@ -27,7 +27,7 @@ diff -uw OpenFOAM-v1612+.orig/etc/config.csh/settings OpenFOAM-v1612+/etc/config # Location of the jobControl directory -setenv FOAM_JOB_DIR $WM_PROJECT_INST_DIR/jobControl -+setenv FOAM_JOB_DIR=$HOME/$WM_PROJECT/jobControl #SPACK: non-central location ++setenv FOAM_JOB_DIR=$HOME/.OpenFOAM/jobControl #SPACK: non-central location # wmake configuration setenv WM_DIR $WM_PROJECT_DIR/wmake diff --git a/var/spack/repos/builtin/packages/openfoam-com/openfoam-site-plus.patch b/var/spack/repos/builtin/packages/openfoam-com/openfoam-site-plus.patch new file mode 100644 index 00000000000..a1f5d8a08a2 --- /dev/null +++ b/var/spack/repos/builtin/packages/openfoam-com/openfoam-site-plus.patch @@ -0,0 +1,35 @@ +diff -uw OpenFOAM-plus.orig/etc/config.sh/settings OpenFOAM-plus/etc/config.sh/settings +--- OpenFOAM-plus.orig/etc/config.sh/settings 2017-04-04 17:34:29.875873400 +0200 ++++ OpenFOAM-plus/etc/config.sh/settings 2017-04-04 17:38:40.174992466 +0200 +@@ -154,10 +154,10 @@ + export FOAM_LIBBIN=$WM_PROJECT_DIR/platforms/$WM_OPTIONS/lib + + # External (ThirdParty) libraries +-export FOAM_EXT_LIBBIN=$WM_THIRD_PARTY_DIR/platforms/$WM_ARCH$WM_COMPILER$WM_PRECISION_OPTION$WM_LABEL_OPTION/lib ++unset FOAM_EXT_LIBBIN #SPACK: none + + # Site-specific directory +-siteDir="${WM_PROJECT_SITE:-$WM_PROJECT_INST_DIR/site}" ++siteDir="${WM_PROJECT_SITE:-$WM_PROJECT_DIR/site}" #SPACK: not in parent directory + + # Shared site executables/libraries + # Similar naming convention as ~OpenFOAM expansion +diff -uw OpenFOAM-plus.orig/etc/config.csh/settings OpenFOAM-plus/etc/config.csh/settings +--- OpenFOAM-plus.orig/etc/config.csh/settings 2017-04-04 17:34:28.255879107 +0200 ++++ OpenFOAM-plus/etc/config.csh/settings 2017-04-04 17:39:22.214844670 +0200 +@@ -151,13 +151,13 @@ + setenv FOAM_LIBBIN $WM_PROJECT_DIR/platforms/$WM_OPTIONS/lib + + # External (ThirdParty) libraries +-setenv FOAM_EXT_LIBBIN $WM_THIRD_PARTY_DIR/platforms/$WM_ARCH$WM_COMPILER$WM_PRECISION_OPTION$WM_LABEL_OPTION/lib ++unsetenv FOAM_EXT_LIBBIN #SPACK: none + + # Site-specific directory + if ( $?WM_PROJECT_SITE ) then + set siteDir=$WM_PROJECT_SITE + else +- set siteDir=$WM_PROJECT_INST_DIR/site ++ set siteDir=$WM_PROJECT_DIR/site #SPACK: not in parent directory + endif + + # Shared site executables/libraries diff --git a/var/spack/repos/builtin/packages/openfoam-com/package.py b/var/spack/repos/builtin/packages/openfoam-com/package.py index 15c4f8fdd40..c6dd6dbe9ad 100644 --- a/var/spack/repos/builtin/packages/openfoam-com/package.py +++ b/var/spack/repos/builtin/packages/openfoam-com/package.py @@ -50,38 +50,74 @@ # variants: +plugins +qt # in ~/.spack/packages.yaml # +# Known issues # - Combining +zoltan with +int64 has not been tested, but probably won't work. +# - Combining +mgridgen with +int64 or +float32 probably won't work. # ############################################################################## from spack import * from spack.environment import * +import llnl.util.tty as tty import glob import re import shutil import os -from os.path import isdir, isfile # Not the nice way of doing things, but is a start for refactoring __all__ = [ - 'format_export', - 'format_setenv', + 'add_extra_files', 'write_environ', 'rewrite_environ_files', 'mplib_content', - 'generate_mplib_rules', - 'generate_compiler_rules', + 'foamAddPath', + 'foamAddLib', + 'OpenfoamArch', ] +def add_extra_files(foam_pkg, common, local, **kwargs): + """Copy additional common and local files into the stage.source_path + from the openfoam-com/common and the package/assets directories, + respectively + """ + outdir = foam_pkg.stage.source_path + + indir = join_path(os.path.dirname(__file__), 'common') + for f in common: + tty.info('Added file {0}'.format(f)) + install(join_path(indir, f), join_path(outdir, f)) + + indir = join_path(foam_pkg.package_dir, 'assets') + for f in local: + tty.info('Added file {0}'.format(f)) + install(join_path(indir, f), join_path(outdir, f)) + + def format_export(key, value): - """Format key,value pair as 'export' with newline for POSIX shell.""" - return 'export {0}={1}\n'.format(key, value) + """Format key,value pair as 'export' with newline for POSIX shell. + A leading '#' for key adds a comment character to the entire line. + A value of 'None' corresponds to 'unset'. + """ + if key.startswith('#'): + return '## export {0}={1}\n'.format(re.sub(r'^#+\s*', '', key), value) + elif value is None: + return 'unset {0}\n'.format(key) + else: + return 'export {0}={1}\n'.format(key, value) def format_setenv(key, value): - """Format key,value pair as 'setenv' with newline for C-shell.""" - return 'setenv {0} {1}\n'.format(key, value) + """Format key,value pair as 'setenv' with newline for C-shell. + A leading '#' for key adds a comment character to the entire line. + A value of 'None' corresponds to 'unsetenv'. + """ + if key.startswith('#'): + return '## setenv {0} {1}\n'.format(re.sub(r'^#+\s*', '', key), value) + elif value is None: + return 'unsetenv {0}\n'.format(key) + else: + return 'setenv {0} {1}\n'.format(key, value) def _write_environ_entries(outfile, environ, formatter): @@ -139,7 +175,7 @@ def rewrite_environ_files(environ, **kwargs): cshell[=None] If set, the name of the C-shell file to rewrite. """ posix = kwargs.get('posix', None) - if posix and isfile(posix): + if posix and os.path.isfile(posix): for k, v in environ.items(): filter_file( r'^(\s*export\s+%s)=.*$' % k, @@ -147,7 +183,7 @@ def rewrite_environ_files(environ, **kwargs): posix, backup=False) cshell = kwargs.get('cshell', None) - if cshell and isfile(cshell): + if cshell and os.path.isfile(cshell): for k, v in environ.items(): filter_file( r'^(\s*setenv\s+%s)\s+.*$' % k, @@ -156,19 +192,35 @@ def rewrite_environ_files(environ, **kwargs): backup=False) -def pkglib(package): - """Get lib64 or lib from package prefix""" +def foamAddPath(*args): + """A string with args prepended to 'PATH'""" + return '"' + ':'.join(args) + ':${PATH}"' + + +def foamAddLib(*args): + """A string with args prepended to 'LD_LIBRARY_PATH'""" + return '"' + ':'.join(args) + ':${LD_LIBRARY_PATH}"' + + +def pkglib(package, pre=None): + """Get lib64 or lib from package prefix. + + Optional parameter 'pre' to provide alternative prefix + """ libdir = package.prefix.lib64 - if isdir(libdir): + if not os.path.isdir(libdir): + libdir = package.prefix.lib + if pre: + return join_path(pre, os.path.basename(libdir)) + else: return libdir - return package.prefix.lib def mplib_content(spec, pre=None): """The mpi settings to have wmake use spack information with minimum modifications to OpenFOAM. - Optional parameter 'pre' to provid alternative prefix + Optional parameter 'pre' to provide alternative prefix """ mpi_spec = spec['mpi'] bin = mpi_spec.prefix.bin @@ -194,36 +246,7 @@ def mplib_content(spec, pre=None): return info -def generate_mplib_rules(directory, spec): - """ Create mplibUSER,mplibUSERMPI rules in the specified directory""" - content = mplib_content(spec) - with working_dir(directory): - for mplib in ['mplibUSER', 'mplibUSERMPI']: - with open(mplib, 'w') as out: - out.write("""# Use mpi from spack ({name})\n -PFLAGS = {FLAGS} -PINC = {PINC} -PLIBS = {PLIBS} -""".format(**content)) - - -def generate_compiler_rules(directory, compOpt, value): - """ Create cSPACKOpt,c++SPACKOpt rules in the specified directory. - The file content is copied and filtered from the corresponding - cOpt,c++Opt rules""" - # Compiler options for SPACK - eg, wmake/rules/linux64Gcc/ - # Copy from existing cOpt, c++Opt and modify DBUG value - with working_dir(directory): - for lang in ['c', 'c++']: - src = '{0}Opt'.format(lang) - dst = '{0}{1}'.format(lang, compOpt) - shutil.copyfile(src, dst) # src -> dst - filter_file( - r'^(\S+DBUG\s*)=.*$', - r'\1= %s' % value, - dst, - backup=False) - +# ----------------------------------------------------------------------------- class OpenfoamCom(Package): """OpenFOAM is a GPL-opensource C++ CFD-toolbox. @@ -239,31 +262,28 @@ class OpenfoamCom(Package): version('1612', 'ca02c491369150ab127cbb88ec60fbdf', url=baseurl + '/v1612+/OpenFOAM-v1612+.tgz') + version('plus', branch='develop', # Note: needs user credentials + git='https://develop.openfoam.com/Development/OpenFOAM-plus.git') variant('int64', default=False, - description='Compile with 64-bit labels') + description='Compile with 64-bit label') variant('float32', default=False, description='Compile with 32-bit scalar (single-precision)') variant('knl', default=False, description='Use KNL compiler settings') - variant('scotch', default=True, description='With scotch/ptscotch for decomposition') variant('metis', default=False, description='With metis for decomposition') variant('zoltan', default=False, description='With zoltan renumbering') - # TODO?# variant('parmgridgen', default=True, - # TODO?# description='With parmgridgen support') - variant('source', default=True, - description='Install library/application sources and tutorials') - + # TODO?# variant('scalasca', default=False, + # TODO?# description='With scalasca profiling') + variant('mgridgen', default=False, description='With mgridgen support') variant('paraview', default=True, description='Build paraview plugins and runtime post-processing') - - #: Map spack compiler names to OpenFOAM compiler names - # By default, simply capitalize the first letter - compiler_mapping = {'intel': 'icc'} + variant('source', default=True, + description='Install library/application sources and tutorials') provides('openfoam') depends_on('mpi') @@ -275,12 +295,14 @@ class OpenfoamCom(Package): depends_on('cmake', type='build') # Require scotch with ptscotch - corresponds to standard OpenFOAM setup - depends_on('scotch~int64+mpi', when='+scotch~int64') - depends_on('scotch+int64+mpi', when='+scotch+int64') + depends_on('scotch~metis+mpi~int64', when='+scotch~int64') + depends_on('scotch~metis+mpi+int64', when='+scotch+int64') depends_on('metis@5:', when='+metis') depends_on('metis+int64', when='+metis+int64') - depends_on('parmgridgen', when='+parmgridgen') + # mgridgen is statically linked + depends_on('parmgridgen', when='+mgridgen', type='build') depends_on('zoltan', when='+zoltan') + # TODO?# depends_on('scalasca', when='+scalasca') # For OpenFOAM plugins and run-time post-processing this should just be # 'paraview+plugins' but that resolves poorly. @@ -289,36 +311,36 @@ class OpenfoamCom(Package): # 1612 plugins need older paraview # The native reader in paraview 5.2 is broken, so start after that - depends_on('paraview@:5.0.1', when='@:1612+paraview') + depends_on('paraview@:5.0.1', when='@1612+paraview') depends_on('paraview@5.3:', when='@1706:+paraview') + depends_on('paraview@5.3:', when='@plus+paraview') # General patches - patch('openfoam-site.patch') + common = ['spack-Allwmake', 'README-spack'] + assets = [] # Version-specific patches patch('openfoam-bin-1612.patch', when='@1612') patch('openfoam-etc-1612.patch', when='@1612') + patch('openfoam-site-1612.patch', when='@1612') patch('openfoam-mpi-1612.patch', when='@1612') patch('openfoam-build-1612.patch', when='@1612') + patch('mgridgen-lib-1612.patch', when='@1612') patch('scotch-metis-lib-1612.patch', when='@1612') patch('zoltan-lib-1612.patch', when='@1612') - # Some user settings, to be adjusted manually or via variants - foam_cfg = { - 'WM_COMPILER': 'Gcc', # <- %compiler - 'WM_ARCH_OPTION': '64', # (32/64-bit on x86_64) - 'WM_LABEL_SIZE': '32', # <- +int64 - 'WM_PRECISION_OPTION': 'DP', # <- +float32 - 'WM_COMPILE_OPTION': 'SPACKOpt', # Do not change - 'WM_MPLIB': 'USERMPI', # Use user mpi for spack + patch('openfoam-site-plus.patch', when='@plus') + + # Some user config settings + # default: 'compile-option': 'RpathOpt', + # default: 'mplib': 'USERMPI', # Use user mpi for spack + config = { + # Add links into bin/, lib/ (eg, for other applications) + 'link': False } - # The system description is frequently needed - foam_sys = { - 'WM_ARCH': None, - 'WM_COMPILER': None, - 'WM_OPTIONS': None, - } + # The openfoam architecture, compiler information etc + _foam_arch = None # Content for etc/prefs.{csh,sh} etc_prefs = {} @@ -326,23 +348,27 @@ class OpenfoamCom(Package): # Content for etc/config.{csh,sh}/ files etc_config = {} - build_script = './spack-Allwmake' # <- Generated by patch() method. - # phases = ['configure', 'build', 'install'] - # build_system_class = 'OpenfoamCom' + phases = ['configure', 'build', 'install'] + build_script = './spack-Allwmake' # <- Added by patch() method. - # Add symlinks into bin/, lib/ (eg, for other applications) - extra_symlinks = False - - # Quickly enable/disable testing with the current develop branch - if False: - version( - 'plus', - branch='develop', - git='file://{0}/{1}' - .format(os.path.expanduser("~"), 'openfoam/OpenFOAM-plus/.git')) + # + # - End of definitions / setup - + # def setup_environment(self, spack_env, run_env): + run_env.set('FOAM_PROJECT_DIR', self.projectdir) run_env.set('WM_PROJECT_DIR', self.projectdir) + for d in ['wmake', self.archbin]: # bin already added automatically + run_env.prepend_path('PATH', join_path(self.projectdir, d)) + run_env.set('MPI_BUFFER_SIZE', "20000000") + + def setup_dependent_environment(self, spack_env, run_env, dependent_spec): + """Provide location of the OpenFOAM project. + This is identical to the WM_PROJECT_DIR value, but we avoid that + variable since it would mask the normal OpenFOAM cleanup of + previous versions. + """ + spack_env.set('FOAM_PROJECT_DIR', self.projectdir) @property def projectdir(self): @@ -350,195 +376,50 @@ def projectdir(self): return self.prefix # <- install directly under prefix @property - def etc(self): - """Absolute location of the OpenFOAM etc/ directory""" - return join_path(self.projectdir, 'etc') + def foam_arch(self): + if not self._foam_arch: + self._foam_arch = OpenfoamArch(self.spec, **self.config) + return self._foam_arch @property def archbin(self): """Relative location of architecture-specific executables""" - return join_path('platforms', self.wm_options, 'bin') + return join_path('platforms', self.foam_arch, 'bin') @property def archlib(self): """Relative location of architecture-specific libraries""" - return join_path('platforms', self.wm_options, 'lib') - - @property - def wm_options(self): - """The architecture+compiler+options for OpenFOAM""" - opts = self.set_openfoam() - return opts - - @property - def rpath_info(self): - """Define 'SPACKOpt' compiler optimization file to have wmake - use spack information with minimum modifications to OpenFOAM - """ - build_libpath = join_path(self.stage.source_path, self.archlib) - install_libpath = join_path(self.projectdir, self.archlib) - - # 'DBUG': rpaths - return '{0}{1} {2}{3}'.format( - self.compiler.cxx_rpath_arg, install_libpath, - self.compiler.cxx_rpath_arg, build_libpath) - - def openfoam_arch(self): - """Return an architecture value similar to what OpenFOAM does in - etc/config.sh/settings, but slightly more generous. - Uses and may adjust foam_cfg[WM_ARCH_OPTION] as a side-effect - """ - # spec.architecture.platform is like `uname -s`, but lower-case - platform = self.spec.architecture.platform - - # spec.architecture.target is like `uname -m` - target = self.spec.architecture.target - - if platform == 'linux': - if target == 'i686': - self.foam_cfg['WM_ARCH_OPTION'] = '32' # Force consistency - elif target == 'x86_64': - if self.foam_cfg['WM_ARCH_OPTION'] == '64': - platform += '64' - elif target == 'ia64': - platform += 'ia64' - elif target == 'armv7l': - platform += 'ARM7' - elif target == ppc64: - platform += 'PPC64' - elif target == ppc64le: - platform += 'PPC64le' - elif platform == 'darwin': - if target == 'x86_64': - platform += 'Intel' - if self.foam_cfg['WM_ARCH_OPTION'] == '64': - platform += '64' - # ... and others? - return platform - - def openfoam_compiler(self): - """Capitalized version of the compiler name, which usually corresponds - to how OpenFOAM will camel-case things. - Use compiler_mapping to handing special cases. - Also handle special compiler options (eg, KNL) - """ - comp = self.compiler.name - if comp in self.compiler_mapping: - comp = self.compiler_mapping[comp] - comp = comp.capitalize() - - if '+knl' in self.spec: - comp += 'KNL' - return comp - - def set_openfoam(self): - """Populate foam_cfg, foam_sys according to - variants, architecture, compiler. - Returns WM_OPTIONS. - """ - # Run once - opts = self.foam_sys['WM_OPTIONS'] - if opts: - return opts - - wm_arch = self.openfoam_arch() - wm_compiler = self.openfoam_compiler() - compileOpt = self.foam_cfg['WM_COMPILE_OPTION'] - - # Insist on a wmake rule for this architecture/compiler combination - archCompiler = wm_arch + wm_compiler - compiler_rule = join_path( - self.stage.source_path, 'wmake', 'rules', archCompiler) - - if not isdir(compiler_rule): - raise RuntimeError( - 'No wmake rule for {0}'.format(archCompiler)) - if not re.match(r'.+Opt$', compileOpt): - raise RuntimeError( - "WM_COMPILE_OPTION={0} is not type '*Opt'".format(compileOpt)) - - # Adjust for variants - self.foam_cfg['WM_LABEL_SIZE'] = ( - '64' if '+int64' in self.spec else '32' - ) - self.foam_cfg['WM_PRECISION_OPTION'] = ( - 'SP' if '+float32' in self.spec else 'DP' - ) - - # ---- - # WM_LABEL_OPTION=Int$WM_LABEL_SIZE - # WM_OPTIONS=$WM_ARCH$WM_COMPILER$WM_PRECISION_OPTION$WM_LABEL_OPTION$WM_COMPILE_OPTION - # ---- - self.foam_sys['WM_ARCH'] = wm_arch - self.foam_sys['WM_COMPILER'] = wm_compiler - self.foam_cfg['WM_COMPILER'] = wm_compiler # For bashrc,cshrc too - self.foam_sys['WM_OPTIONS'] = ''.join([ - wm_arch, - wm_compiler, - self.foam_cfg['WM_PRECISION_OPTION'], - 'Int', self.foam_cfg['WM_LABEL_SIZE'], # Int32/Int64 - compileOpt - ]) - return self.foam_sys['WM_OPTIONS'] + return join_path('platforms', self.foam_arch, 'lib') def patch(self): - """Adjust OpenFOAM build for spack. Where needed, apply filter as an - alternative to normal patching. - """ - self.set_openfoam() # May need foam_cfg/foam_sys information + """Adjust OpenFOAM build for spack. + Where needed, apply filter as an alternative to normal patching.""" + add_extra_files(self, self.common, self.assets) # Avoid WM_PROJECT_INST_DIR for ThirdParty, site or jobControl. # Use openfoam-site.patch to handle jobControl, site. # - # Filter (not patch) bashrc,cshrc for additional flexibility - wm_setting = { + # Filtering: bashrc,cshrc (using a patch is less flexible) + edits = { 'WM_THIRD_PARTY_DIR': r'$WM_PROJECT_DIR/ThirdParty #SPACK: No separate third-party', } - rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc - wm_setting, + edits, posix=join_path('etc', 'bashrc'), cshell=join_path('etc', 'cshrc')) - # Adjust ParMGridGen - this is still a mess. - # We also have no assurances about sizes (int/long, float/double) etc. - # - # Need to adjust src/fvAgglomerationMethods/Allwmake - # "export ParMGridGen=%s" % spec['parmgridgen'].prefix - # - # and src/fvAgglomerationMethods/MGridGenGamgAgglomeration/Make/options - # "-I=%s" % spec['parmgridgen'].include - # "-L=%s -lmgrid" % spec['parmgridgen'].lib - - # Build wrapper script - with open(self.build_script, 'w') as out: - out.write( - """#!/bin/bash -. $PWD/etc/bashrc '' # No arguments -mkdir -p $FOAM_APPBIN $FOAM_LIBBIN 2>/dev/null # Allow interrupt -echo Build openfoam with SPACK -echo WM_PROJECT_DIR = $WM_PROJECT_DIR -./Allwmake $@ -# -""") - set_executable(self.build_script) - self.configure(self.spec, self.prefix) # Should be a separate phase - def configure(self, spec, prefix): """Make adjustments to the OpenFOAM configuration files in their various locations: etc/bashrc, etc/config.sh/FEATURE and customizations that don't properly fit get placed in the etc/prefs.sh file (similiarly for csh). """ - self.set_openfoam() # Need foam_cfg/foam_sys information - - # Some settings for filtering bashrc, cshrc - wm_setting = {} - wm_setting.update(self.foam_cfg) - + # Filtering bashrc, cshrc + edits = {} + edits.update(self.foam_arch.foam_dict()) rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc - wm_setting, + edits, posix=join_path('etc', 'bashrc'), cshell=join_path('etc', 'cshrc')) @@ -551,27 +432,34 @@ def configure(self, spec, prefix): } # MPI content, using MPI_ARCH_PATH - content = mplib_content(spec, '${MPI_ARCH_PATH}') + user_mpi = mplib_content(spec, '${MPI_ARCH_PATH}') # Content for etc/config.{csh,sh}/ files self.etc_config = { - 'CGAL': { - 'BOOST_ARCH_PATH': spec['boost'].prefix, - 'CGAL_ARCH_PATH': spec['cgal'].prefix, - }, - 'FFTW': { - 'FFTW_ARCH_PATH': spec['fftw'].prefix, - }, + 'CGAL': [ + ('BOOST_ARCH_PATH', spec['boost'].prefix), + ('CGAL_ARCH_PATH', spec['cgal'].prefix), + ('LD_LIBRARY_PATH', + foamAddLib( + pkglib(spec['boost'], '${BOOST_ARCH_PATH}'), + pkglib(spec['cgal'], '${CGAL_ARCH_PATH}'))), + ], + 'FFTW': [ + ('FFTW_ARCH_PATH', spec['fftw'].prefix), # Absolute + ('LD_LIBRARY_PATH', + foamAddLib( + pkglib(spec['fftw'], '${BOOST_ARCH_PATH}'))), + ], # User-defined MPI 'mpi-user': [ ('MPI_ARCH_PATH', spec['mpi'].prefix), # Absolute - ('LD_LIBRARY_PATH', - '"%s:${LD_LIBRARY_PATH}"' % content['libdir']), - ('PATH', '"%s:${PATH}"' % content['bindir']), + ('LD_LIBRARY_PATH', foamAddLib(user_mpi['libdir'])), + ('PATH', foamAddPath(user_mpi['bindir'])), ], 'scotch': {}, 'metis': {}, 'paraview': [], + 'gperftools': [], # Currently unused } if '+scotch' in spec: @@ -590,15 +478,15 @@ def configure(self, spec, prefix): pvMajor = 'paraview-{0}'.format(spec['paraview'].version.up_to(2)) self.etc_config['paraview'] = [ ('ParaView_DIR', spec['paraview'].prefix), - ('ParaView_INCLUDE_DIR', '$ParaView_DIR/include/' + pvMajor), + ('ParaView_INCLUDE_DIR', '${ParaView_DIR}/include/' + pvMajor), ('PV_PLUGIN_PATH', '$FOAM_LIBBIN/' + pvMajor), - ('PATH', '"${ParaView_DIR}/bin:${PATH}"'), + ('PATH', foamAddPath('${ParaView_DIR}/bin')), ] - # Not normally included as etc/config file - if '+parmgridgen' in spec: - self.etc_config['parmgridgen'] = { - 'PARMGRIDGEN_ARCH_PATH': spec['parmgridgen'].prefix + # Optional + if '+mgridgen' in spec: + self.etc_config['mgridgen'] = { + 'MGRIDGEN_ARCH_PATH': spec['parmgridgen'].prefix } # Optional @@ -622,45 +510,30 @@ def configure(self, spec, prefix): posix=join_path('etc', 'config.sh', component), cshell=join_path('etc', 'config.csh', component)) - archCompiler = self.foam_sys['WM_ARCH'] + self.foam_sys['WM_COMPILER'] - compileOpt = self.foam_cfg['WM_COMPILE_OPTION'] - general_rule = join_path('wmake', 'rules', 'General') - compiler_rule = join_path('wmake', 'rules', archCompiler) - generate_mplib_rules(general_rule, self.spec) - generate_compiler_rules(compiler_rule, compileOpt, self.rpath_info) - # Record the spack spec information - with open("log.spack-spec", 'w') as outfile: - outfile.write(spec.tree()) - def build(self, spec, prefix): """Build using the OpenFOAM Allwmake script, with a wrapper to source its environment first. + Only build if the compiler is known to be supported. """ - self.set_openfoam() # Force proper population of foam_cfg/foam_sys + self.foam_arch.has_rule(self.stage.source_path) + self.foam_arch.create_rules(self.stage.source_path, self) + args = ['-silent'] if self.parallel: # Build in parallel? - pass as an argument - args.append( - '-j{0}'.format(str(self.make_jobs) if self.make_jobs else '')) + args.append('-j{0}'.format(make_jobs)) builder = Executable(self.build_script) builder(*args) def install(self, spec, prefix): - """Install under the projectdir (== prefix)""" - self.build(spec, prefix) # Should be a separate phase - opts = self.wm_options - + """Install under the projectdir""" mkdirp(self.projectdir) projdir = os.path.basename(self.projectdir) - wm_setting = { + # Filtering: bashrc, cshrc + edits = { 'WM_PROJECT_INST_DIR': os.path.dirname(self.projectdir), 'WM_PROJECT_DIR': join_path('$WM_PROJECT_INST_DIR', projdir), } - # Retain build log file - out = "spack-build.out" - if isfile(out): - install(out, join_path(self.projectdir, "log." + opts)) - # All top-level files, except spack build info and possibly Allwmake if '+source' in spec: ignored = re.compile(r'^spack-.*') @@ -668,20 +541,23 @@ def install(self, spec, prefix): ignored = re.compile(r'^(Allwmake|spack-).*') files = [ - f for f in glob.glob("*") if isfile(f) and not ignored.search(f) + f for f in glob.glob("*") + if os.path.isfile(f) and not ignored.search(f) ] for f in files: install(f, self.projectdir) - # Having wmake without sources is actually somewhat pointless... - dirs = ['bin', 'etc', 'wmake'] + # Having wmake and ~source is actually somewhat pointless... + # Install 'etc' before 'bin' (for symlinks) + dirs = ['etc', 'bin', 'wmake'] if '+source' in spec: dirs.extend(['applications', 'src', 'tutorials']) for d in dirs: install_tree( d, - join_path(self.projectdir, d)) + join_path(self.projectdir, d), + symlinks=True) dirs = ['platforms'] if '+source' in spec: @@ -693,30 +569,229 @@ def install(self, spec, prefix): install_tree( d, join_path(self.projectdir, d), - ignore=shutil.ignore_patterns(*ignored)) + ignore=shutil.ignore_patterns(*ignored), + symlinks=True) + etc_dir = join_path(self.projectdir, 'etc') rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc - wm_setting, - posix=join_path(self.etc, 'bashrc'), - cshell=join_path(self.etc, 'cshrc')) + edits, + posix=join_path(etc_dir, 'bashrc'), + cshell=join_path(etc_dir, 'cshrc')) self.install_links() def install_links(self): """Add symlinks into bin/, lib/ (eg, for other applications)""" - if not self.extra_symlinks: + # Make build log visible - it contains OpenFOAM-specific information + with working_dir(self.projectdir): + os.symlink( + join_path('.spack', 'build.out'), + join_path('log.' + str(self.foam_arch))) + + if not self.config['link']: return # ln -s platforms/linux64GccXXX/lib lib with working_dir(self.projectdir): - if isdir(self.archlib): + if os.path.isdir(self.archlib): os.symlink(self.archlib, 'lib') # (cd bin && ln -s ../platforms/linux64GccXXX/bin/* .) with working_dir(join_path(self.projectdir, 'bin')): for f in [ f for f in glob.glob(join_path('..', self.archbin, "*")) - if isfile(f) + if os.path.isfile(f) ]: os.symlink(f, os.path.basename(f)) + def openfoam_run_environment(self, projdir): + # This seems to bomb out with an ImportError 'site'! + # mods = EnvironmentModifications.from_sourcing_files( + # join_path(projdir, 'etc/bashrc')) + pass + + +# ----------------------------------------------------------------------------- + +class OpenfoamArch(object): + """OpenfoamArch represents architecture/compiler settings for OpenFOAM. + The string representation is WM_OPTIONS. + + Keywords + label-size=[True] supports int32/int64 + compile-option[=RpathOpt] + mplib[=USERMPI] + """ + + #: Map spack compiler names to OpenFOAM compiler names + # By default, simply capitalize the first letter + compiler_mapping = {'intel': 'icc'} + + def __init__(self, spec, **kwargs): + # Some user settings, to be adjusted manually or via variants + self.compiler = None # <- %compiler + self.arch_option = '64' # (32/64-bit on x86_64) + self.label_size = None # <- +int64 + self.precision_option = 'DP' # <- +float32 + self.compile_option = kwargs.get('compile-option', 'RpathOpt') + self.arch = None + self.options = None + self.rule = None + self.mplib = kwargs.get('mplib', 'USERMPI') + + # Normally support WM_LABEL_OPTION, but not yet for foam-extend + if '+int64' in spec: + self.label_size = '64' + elif kwargs.get('label-size', True): + self.label_size = '32' + + if '+float32' in spec: + self.precision_option = 'SP' + + # spec.architecture.platform is like `uname -s`, but lower-case + platform = spec.architecture.platform + + # spec.architecture.target is like `uname -m` + target = spec.architecture.target + + if platform == 'linux': + if target == 'i686': + self.arch_option = '32' # Force consistency + elif target == 'x86_64': + if self.arch_option == '64': + platform += '64' + elif target == 'ia64': + platform += 'ia64' + elif target == 'armv7l': + platform += 'ARM7' + elif target == ppc64: + platform += 'PPC64' + elif target == ppc64le: + platform += 'PPC64le' + elif platform == 'darwin': + if target == 'x86_64': + platform += 'Intel' + if self.arch_option == '64': + platform += '64' + # ... and others? + + self.arch = platform + + # Capitalized version of the compiler name, which usually corresponds + # to how OpenFOAM will camel-case things. + # Use compiler_mapping to handing special cases. + # Also handle special compiler options (eg, KNL) + comp = spec.compiler.name + + if comp in self.compiler_mapping: + comp = self.compiler_mapping[comp] + comp = comp.capitalize() + + if '+knl' in spec: + comp += 'KNL' + self.compiler = comp + self.rule = self.arch + self.compiler + + # Build WM_OPTIONS + # ---- + # WM_LABEL_OPTION=Int$WM_LABEL_SIZE + # WM_OPTIONS=$WM_ARCH$WM_COMPILER$WM_PRECISION_OPTION$WM_LABEL_OPTION$WM_COMPILE_OPTION + # or + # WM_OPTIONS=$WM_ARCH$WM_COMPILER$WM_PRECISION_OPTION$WM_COMPILE_OPTION + # ---- + self.options = ''.join([ + self.rule, + self.precision_option, + ('Int' + self.label_size if self.label_size else ''), + self.compile_option]) + + def __str__(self): + return self.options + + def __repr__(self): + return str(self) + + def foam_dict(self): + """Returns a dictionary for OpenFOAM prefs, bashrc, cshrc.""" + return dict([ + ('WM_COMPILER', self.compiler), + ('WM_ARCH_OPTION', self.arch_option), + ('WM_LABEL_SIZE', self.label_size), + ('WM_PRECISION_OPTION', self.precision_option), + ('WM_COMPILE_OPTION', self.compile_option), + ('WM_MPLIB', self.mplib), + ]) + + def _rule_directory(self, projdir=None, general=False): + """The wmake/rules/ compiler directory""" + if general: + relative = os.path.join('wmake', 'rules', 'General') + else: + relative = os.path.join('wmake', 'rules', self.rule) + if projdir: + return os.path.join(projdir, relative) + else: + return relative + + def has_rule(self, projdir): + """Verify that a wmake/rules/ compiler rule exists in the project + directory. + """ + # Insist on a wmake rule for this architecture/compiler combination + rule_dir = self._rule_directory(projdir) + + if not os.path.isdir(rule_dir): + raise InstallError( + 'No wmake rule for {0}'.format(self.rule)) + if not re.match(r'.+Opt$', self.compile_option): + raise InstallError( + "WM_COMPILE_OPTION={0} is not type '*Opt'" + .format(self.compile_option)) + return True + + def create_rules(self, projdir, foam_pkg): + """ Create cRpathOpt,c++RpathOpt and mplibUSER,mplibUSERMPI + rules in the specified project directory. + The compiler rules are based on the respective cOpt,c++Opt rules + but with additional rpath information for the OpenFOAM libraries. + + The rpath rules allow wmake to use spack information with minimal + modification to OpenFOAM. + The rpath is used for the installed libpath (continue to use + LD_LIBRARY_PATH for values during the build). + """ + # Note: the 'c' rules normally don't need rpath, since they are just + # used for statically linked wmake utilities, but left in anyhow. + + # rpath for installed OpenFOAM libraries + rpath = '{0}{1}'.format( + foam_pkg.compiler.cxx_rpath_arg, + join_path(foam_pkg.projectdir, foam_pkg.archlib)) + + user_mpi = mplib_content(foam_pkg.spec) + rule_dir = self._rule_directory(projdir) + + with working_dir(rule_dir): + # Compiler: copy existing cOpt,c++Opt and modify '*DBUG' value + for lang in ['c', 'c++']: + src = '{0}Opt'.format(lang) + dst = '{0}{1}'.format(lang, self.compile_option) + with open(src, 'r') as infile: + with open(dst, 'w') as outfile: + for line in infile: + line = line.rstrip() + outfile.write(line) + if re.match(r'^\S+DBUG\s*=', line): + outfile.write(' ') + outfile.write(rpath) + outfile.write('\n') + + # MPI rules + for mplib in ['mplibUSER', 'mplibUSERMPI']: + with open(mplib, 'w') as out: + out.write("""# Use mpi from spack ({name})\n +PFLAGS = {FLAGS} +PINC = {PINC} +PLIBS = {PLIBS} +""".format(**user_mpi)) + # ----------------------------------------------------------------------------- diff --git a/var/spack/repos/builtin/packages/openfoam-org/assets/bin/foamEtcFile b/var/spack/repos/builtin/packages/openfoam-org/assets/bin/foamEtcFile new file mode 100755 index 00000000000..294cc265054 --- /dev/null +++ b/var/spack/repos/builtin/packages/openfoam-org/assets/bin/foamEtcFile @@ -0,0 +1,417 @@ +#!/bin/sh +#------------------------------------------------------------------------------ +# ========= | +# \\ / F ield | OpenFOAM: The Open Source CFD Toolbox +# \\ / O peration | +# \\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation +# \\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd. +#------------------------------------------------------------------------------- +# License +# This file is part of OpenFOAM. +# +# OpenFOAM is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# OpenFOAM is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with OpenFOAM. If not, see . +# +# Script +# foamEtcFile +# +# Description +# Locate user/group/other files with semantics similar to the +# ~OpenFOAM/fileName expansion. +# +# The -mode option can be used to allow chaining from +# personal settings to site-wide settings. +# +# For example, within the user ~/.OpenFOAM//prefs.sh: +# \code +# eval $(foamEtcFile -sh -mode=go prefs.sh) +# \endcode +# +# Environment +# - WM_PROJECT: (unset defaults to OpenFOAM) +# - WM_PROJECT_SITE: (unset defaults to PREFIX/site) +# - WM_PROJECT_VERSION: (unset defaults to detect from path) +# +# Note +# This script must exist in one of these locations: +# - $WM_PROJECT_INST_DIR/OpenFOAM-/bin +# - $WM_PROJECT_INST_DIR/openfoam-/bin +# - $WM_PROJECT_INST_DIR/OpenFOAM+/bin +# - $WM_PROJECT_INST_DIR/openfoam+/bin +# - $WM_PROJECT_INST_DIR/openfoam/bin (debian version) +# +#------------------------------------------------------------------------------- +unset optQuiet optSilent +usage() { + [ "${optQuiet:-$optSilent}" = true ] && exit 1 + exec 1>&2 + while [ "$#" -ge 1 ]; do echo "$1"; shift; done + cat<&2 + echo + echo "Error encountered:" + while [ "$#" -ge 1 ]; do echo " $1"; shift; done + echo + echo "See 'foamEtcFile -help' for usage" + echo + exit 1 +} + +#------------------------------------------------------------------------------- +binDir="${0%/*}" # The bin dir +projectDir="${binDir%/bin}" # The project dir +prefixDir="${projectDir%/*}" # The prefix dir (same as $WM_PROJECT_INST_DIR) + +# Could not resolve projectDir, prefixDir? (eg, called as ./bin/foamEtcFile) +if [ "$prefixDir" = "$projectDir" ] +then + binDir="$(cd $binDir && pwd -L)" + projectDir="${binDir%/bin}" + prefixDir="${projectDir%/*}" +fi +projectDirName="${projectDir##*/}" # The project directory name + +projectVersion="$WM_PROJECT_VERSION" # Empty? - will be treated later +userDir="$HOME/.OpenFOAM" # Hard-coded as per foamVersion.H + +#------------------------------------------------------------------------------- + +# Guess project version or simply get the stem part of the projectDirName. +# Handle standard and debian naming conventions. +# +# - projectVersion: update unless already set +# +# Helper variables: +# - dirBase (for reassembling name) == projectDirName without the version +# - versionNum (debian packaging) +unset dirBase versionNum +guessVersion() +{ + local version + + case "$projectDirName" in + (OpenFOAM-* | openfoam-*) + # Standard naming: OpenFOAM- or openfoam- + dirBase="${projectDirName%%-*}-" + version="${projectDirName#*-}" + version="${version%%*-}" # Extra safety, eg openfoam-version-packager + ;; + + (OpenFOAM+* | openfoam+*) + # Alternative naming: OpenFOAM+ or openfoam+ + dirBase="${projectDirName%%+*}+" + version="${projectDirName#*+}" + version="${version%%*-}" # Extra safety, eg openfoam-version-packager + ;; + + (openfoam[0-9]*) + # Debian naming: openfoam + dirBase="openfoam" + version="${projectDirName#openfoam}" + versionNum="$version" + + # Convert digits version number to decimal delineated + case "${#versionNum}" in (2|3|4) + version=$(echo "$versionNum" | sed -e 's@\([0-9]\)@\1.@g') + version="${version%.}" + ;; + esac + + # Ignore special treatment if no decimals were inserted. + [ "${#version}" -gt "${#versionNum}" ] || unset versionNum + ;; + + (*) + die "unknown/unsupported naming convention for '$projectDirName'" + ;; + esac + + # Set projectVersion if required + : ${projectVersion:=$version} +} + + +# Set projectVersion and update versionNum, projectDirName accordingly +setVersion() +{ + projectVersion="$1" + + # Need dirBase when reassembling projectDirName + [ -n "$dirBase" ] || guessVersion + + # Debian: update x.y.z -> xyz version + if [ -n "$versionNum" ] + then + versionNum=$(echo "$projectVersion" | sed -e 's@\.@@g') + fi + + projectDirName="$dirBase${versionNum:-$projectVersion}" +} + + +optMode=ugo # Default mode is always 'ugo' +unset optAll optList optShell optVersion + +# Parse options +while [ "$#" -gt 0 ] +do + case "$1" in + -h | -help) + usage + ;; + -a | -all) + optAll=true + unset optShell + ;; + -l | -list) + optList=true + unset optShell + ;; + -list-test) + optList='test' + unset optShell + ;; + -csh | -sh | -csh-verbose | -sh-verbose) + optShell="${1#-}" + unset optAll + ;; + -mode=[ugo]*) + optMode="${1#*=}" + ;; + -prefix=/*) + prefixDir="${1#*=}" + prefixDir="${prefixDir%/}" + ;; + -version=*) + optVersion="${1#*=}" + ;; + -m | -mode) + optMode="$2" + shift + # Sanity check. Handles missing argument too. + case "$optMode" in + ([ugo]*) + ;; + (*) + die "invalid mode '$optMode'" + ;; + esac + ;; + -p | -prefix) + [ "$#" -ge 2 ] || die "'$1' option requires an argument" + prefixDir="${2%/}" + shift + ;; + -q | -quiet) + optQuiet=true + ;; + -s | -silent) + optSilent=true + ;; + -v | -version) + [ "$#" -ge 2 ] || die "'$1' option requires an argument" + optVersion="$2" + shift + ;; + --) + shift + break + ;; + -*) + die "unknown option: '$1'" + ;; + *) + break + ;; + esac + shift +done + + +#------------------------------------------------------------------------------- + +if [ -n "$optVersion" ] +then + setVersion $optVersion +elif [ -z "$projectVersion" ] +then + guessVersion +fi + +# Updates: +# - projectDir for changes via -prefix or -version +# - groupDir for changes via -prefix +projectDir="$prefixDir/$projectDirName" +groupDir="${WM_PROJECT_SITE:-$prefixDir/site}" + + +# Debugging: +# echo "Installed locations:" 1>&2 +# for i in projectDir prefixDir projectDirName projectVersion +# do +# eval echo "$i=\$$i" 1>&2 +# done + + +# Save the essential bits of information +# silently remove leading ~OpenFOAM/ (used in Foam::findEtcFile) +nArgs=$# +fileName="${1#~OpenFOAM/}" + +# Define the various places to be searched: +unset dirList +case "$optMode" in (*u*) # (U)ser + dirList="$dirList $userDir/$projectVersion $userDir" + ;; +esac + +case "$optMode" in (*g*) # (G)roup == site + dirList="$dirList $groupDir/$projectVersion $groupDir" + ;; +esac + +case "$optMode" in (*o*) # (O)ther == shipped + dirList="$dirList $projectDir/etc" + ;; +esac +set -- $dirList + + +# +# The main routine +# + +exitCode=0 +if [ -n "$optList" ] +then + + # List directories, or potential file locations + [ "$nArgs" -le 1 ] || \ + die "-list expects 0 or 1 filename, but $nArgs provided" + + # A silly combination, but -quiet does have precedence + [ -n "$optQuiet" ] && exit 0 + + # Test for directory or file too? + if [ "$optList" = "test" ] + then + exitCode=2 # Fallback to a general error (file not found) + + if [ "$nArgs" -eq 1 ] + then + for dir + do + resolved="$dir/$fileName" + if [ -f "$resolved" ] + then + echo "$resolved" + exitCode=0 # OK + fi + done + else + for dir + do + if [ -d "$dir" ] + then + echo "$dir" + exitCode=0 # OK + fi + done + fi + else + for dir + do + echo "$dir${fileName:+/}$fileName" + done + fi + +else + + [ "$nArgs" -eq 1 ] || die "One filename expected - $nArgs provided" + + exitCode=2 # Fallback to a general error (file not found) + + for dir + do + if [ -f "$dir/$fileName" ] + then + exitCode=0 + [ -n "$optQuiet" ] && break + + case "$optShell" in + (*verbose) + echo "Using: $dir/$fileName" 1>&2 + ;; + esac + + case "$optShell" in + csh*) + echo "source $dir/$fileName" + break + ;; + sh*) + echo ". $dir/$fileName" + break + ;; + *) + echo "$dir/$fileName" + [ -n "$optAll" ] || break + ;; + esac + fi + done + +fi + +exit $exitCode + +#------------------------------------------------------------------------------ diff --git a/var/spack/repos/builtin/packages/openfoam-org/openfoam-site.patch b/var/spack/repos/builtin/packages/openfoam-org/openfoam-site-41.patch similarity index 86% rename from var/spack/repos/builtin/packages/openfoam-org/openfoam-site.patch rename to var/spack/repos/builtin/packages/openfoam-org/openfoam-site-41.patch index 66310257885..d988c2f9b85 100644 --- a/var/spack/repos/builtin/packages/openfoam-org/openfoam-site.patch +++ b/var/spack/repos/builtin/packages/openfoam-org/openfoam-site-41.patch @@ -6,7 +6,7 @@ diff -uw OpenFOAM-v1612+.orig/etc/config.sh/settings OpenFOAM-v1612+/etc/config. # Location of the jobControl directory -export FOAM_JOB_DIR=$WM_PROJECT_INST_DIR/jobControl -+export FOAM_JOB_DIR=$HOME/$WM_PROJECT/jobControl #SPACK: non-central location ++export FOAM_JOB_DIR=$HOME/.OpenFOAM/jobControl #SPACK: non-central location # wmake configuration export WM_DIR=$WM_PROJECT_DIR/wmake @@ -15,7 +15,7 @@ diff -uw OpenFOAM-v1612+.orig/etc/config.sh/settings OpenFOAM-v1612+/etc/config. # Site-specific directory -siteDir="${WM_PROJECT_SITE:-$WM_PROJECT_INST_DIR/site}" -+siteDir="${WM_PROJECT_SITE:-$WM_PROJECT/site}" #SPACK: not in parent directory ++siteDir="${WM_PROJECT_SITE:-$WM_PROJECT_DIR/site}" #SPACK: not in parent directory # Shared site executables/libraries # Similar naming convention as ~OpenFOAM expansion @@ -27,7 +27,7 @@ diff -uw OpenFOAM-v1612+.orig/etc/config.csh/settings OpenFOAM-v1612+/etc/config # Location of the jobControl directory -setenv FOAM_JOB_DIR $WM_PROJECT_INST_DIR/jobControl -+setenv FOAM_JOB_DIR=$HOME/$WM_PROJECT/jobControl #SPACK: non-central location ++setenv FOAM_JOB_DIR=$HOME/.OpenFOAM/jobControl #SPACK: non-central location # wmake configuration setenv WM_DIR $WM_PROJECT_DIR/wmake diff --git a/var/spack/repos/builtin/packages/openfoam-org/package.py b/var/spack/repos/builtin/packages/openfoam-org/package.py index 53be5f63378..02c27a0db5b 100644 --- a/var/spack/repos/builtin/packages/openfoam-org/package.py +++ b/var/spack/repos/builtin/packages/openfoam-org/package.py @@ -44,22 +44,23 @@ # entirely clear and thus untested. # - Resolution of flex, zlib needs more attention (within OpenFOAM) # -# - mpi handling: WM_MPLIB=SYSTEMMPI and use spack to populate the prefs.sh -# for it. -# Also provide wmake rules for special purpose 'USER' and 'USERMPI' +# - mpi handling: WM_MPLIB=SYSTEMMPI and use spack to populate prefs.sh for it. +# Provide wmake rules for special purpose 'USER' and 'USERMPI' # mpi implementations, in case these are required. # +# Known issues +# - Combining +zoltan with +int64 has not been tested, but probably won't work. +# - Combining +mgridgen with +int64 or +float32 probably won't work. +# ############################################################################## from spack import * from spack.environment import * import llnl.util.tty as tty -import multiprocessing import glob import re import shutil import os -from os.path import isdir, isfile from spack.pkg.builtin.openfoam_com import * @@ -78,19 +79,15 @@ class OpenfoamOrg(Package): version('4.1', '318a446c4ae6366c7296b61184acd37c', url=baseurl + '/OpenFOAM-4.x/archive/version-4.1.tar.gz') + version('dev', git='https://github.com/OpenFOAM/OpenFOAM-dev.git') variant('int64', default=False, - description='Compile with 64-bit labels') + description='Compile with 64-bit label') variant('float32', default=False, description='Compile with 32-bit scalar (single-precision)') - variant('source', default=True, description='Install library/application sources and tutorials') - #: Map spack compiler names to OpenFOAM compiler names - # By default, simply capitalize the first letter - compiler_mapping = {'intel': 'icc'} - provides('openfoam') depends_on('mpi') depends_on('zlib') @@ -98,31 +95,26 @@ class OpenfoamOrg(Package): depends_on('cmake', type='build') # Require scotch with ptscotch - corresponds to standard OpenFOAM setup - depends_on('scotch~int64+mpi', when='~int64') - depends_on('scotch+int64+mpi', when='+int64') + depends_on('scotch~metis+mpi~int64', when='~int64') + depends_on('scotch~metis+mpi+int64', when='+int64') - # General patches - patch('openfoam-site.patch') + # General patches - foamEtcFile as per openfoam.com (robuster) + common = ['spack-Allwmake', 'README-spack'] + assets = ['bin/foamEtcFile'] # Version-specific patches - patch('openfoam-etc-41.patch') + patch('openfoam-etc-41.patch', when='@4.1') + patch('openfoam-site-41.patch', when='@4.1') - # Some user settings, to be adjusted manually or via variants - foam_cfg = { - 'WM_COMPILER': 'Gcc', # <- %compiler - 'WM_ARCH_OPTION': '64', # (32/64-bit on x86_64) - 'WM_LABEL_SIZE': '32', # <- +int64 - 'WM_PRECISION_OPTION': 'DP', # <- +float32 - 'WM_COMPILE_OPTION': 'SPACKOpt', # Do not change - 'WM_MPLIB': 'SYSTEMMPI', # Use system mpi for spack + # Some user config settings + config = { + 'mplib': 'SYSTEMMPI', # Use system mpi for spack + # Add links into bin/, lib/ (eg, for other applications) + 'link': False } - # The system description is frequently needed - foam_sys = { - 'WM_ARCH': None, - 'WM_COMPILER': None, - 'WM_OPTIONS': None, - } + # The openfoam architecture, compiler information etc + _foam_arch = None # Content for etc/prefs.{csh,sh} etc_prefs = {} @@ -130,236 +122,111 @@ class OpenfoamOrg(Package): # Content for etc/config.{csh,sh}/ files etc_config = {} - build_script = './spack-Allwmake' # <- Generated by patch() method. - # phases = ['configure', 'build', 'install'] - # build_system_class = 'OpenfoamCom' + phases = ['configure', 'build', 'install'] + build_script = './spack-Allwmake' # <- Added by patch() method. - # Add symlinks into bin/, lib/ (eg, for other applications) - extra_symlinks = False + # + # - End of definitions / setup - + # def setup_environment(self, spack_env, run_env): + run_env.set('FOAM_PROJECT_DIR', self.projectdir) run_env.set('WM_PROJECT_DIR', self.projectdir) + for d in ['wmake', self.archbin]: # bin already added automatically + run_env.prepend_path('PATH', join_path(self.projectdir, d)) + run_env.set('MPI_BUFFER_SIZE', "20000000") - @property - def _canonical(self): - """Canonical name for this package and version""" - return 'OpenFOAM-{0}'.format(self.version) + def setup_dependent_environment(self, spack_env, run_env, dependent_spec): + """Provide location of the OpenFOAM project. + This is identical to the WM_PROJECT_DIR value, but we avoid that + variable since it would mask the normal OpenFOAM cleanup of + previous versions. + """ + spack_env.set('FOAM_PROJECT_DIR', self.projectdir) @property def projectdir(self): """Absolute location of project directory: WM_PROJECT_DIR/""" - return join_path(self.prefix, self._canonical) # <- prefix/canonical + return self.prefix # <- install directly under prefix @property - def etc(self): - """Absolute location of the OpenFOAM etc/ directory""" - return join_path(self.projectdir, 'etc') + def foam_arch(self): + if not self._foam_arch: + self._foam_arch = OpenfoamArch(self.spec, **self.config) + return self._foam_arch @property def archbin(self): """Relative location of architecture-specific executables""" - return join_path('platforms', self.wm_options, 'bin') + return join_path('platforms', self.foam_arch, 'bin') @property def archlib(self): """Relative location of architecture-specific libraries""" - return join_path('platforms', self.wm_options, 'lib') + return join_path('platforms', self.foam_arch, 'lib') - @property - def wm_options(self): - """The architecture+compiler+options for OpenFOAM""" - opts = self.set_openfoam() - return opts - - @property - def rpath_info(self): - """Define 'SPACKOpt' compiler optimization file to have wmake - use spack information with minimum modifications to OpenFOAM + def rename_source(self): + """This is fairly horrible. + The github tarfiles have weird names that do not correspond to the + canonical name. We need to rename these, but leave a symlink for + spack to work with. """ - build_libpath = join_path(self.stage.source_path, self.archlib) - install_libpath = join_path(self.projectdir, self.archlib) - - # 'DBUG': rpaths - return '{0}{1} {2}{3}'.format( - self.compiler.cxx_rpath_arg, install_libpath, - self.compiler.cxx_rpath_arg, build_libpath) - - def openfoam_arch(self): - """Return an architecture value similar to what OpenFOAM does in - etc/config.sh/settings, but slightly more generous. - Uses and may adjust foam_cfg[WM_ARCH_OPTION] as a side-effect - """ - # spec.architecture.platform is like `uname -s`, but lower-case - platform = self.spec.architecture.platform - - # spec.architecture.target is like `uname -m` - target = self.spec.architecture.target - - if platform == 'linux': - if target == 'i686': - self.foam_cfg['WM_ARCH_OPTION'] = '32' # Force consistency - elif target == 'x86_64': - if self.foam_cfg['WM_ARCH_OPTION'] == '64': - platform += '64' - elif target == 'ia64': - platform += 'ia64' - elif target == 'armv7l': - platform += 'ARM7' - elif target == ppc64: - platform += 'PPC64' - elif target == ppc64le: - platform += 'PPC64le' - elif platform == 'darwin': - if target == 'x86_64': - platform += 'Intel' - if self.foam_cfg['WM_ARCH_OPTION'] == '64': - platform += '64' - # ... and others? - return platform - - def openfoam_compiler(self): - """Capitalized version of the compiler name, which usually corresponds - to how OpenFOAM will camel-case things. - Use compiler_mapping to handing special cases. - Also handle special compiler options (eg, KNL) - """ - comp = self.compiler.name - if comp in self.compiler_mapping: - comp = self.compiler_mapping[comp] - comp = comp.capitalize() - - if '+knl' in self.spec: - comp += 'KNL' - return comp - - def set_openfoam(self): - """Populate foam_cfg, foam_sys according to - variants, architecture, compiler. - Returns WM_OPTIONS. - """ - # Run once - opts = self.foam_sys['WM_OPTIONS'] - if opts: - return opts - - wm_arch = self.openfoam_arch() - wm_compiler = self.openfoam_compiler() - compileOpt = self.foam_cfg['WM_COMPILE_OPTION'] - - # Insist on a wmake rule for this architecture/compiler combination - archCompiler = wm_arch + wm_compiler - compiler_rule = join_path( - self.stage.source_path, 'wmake', 'rules', archCompiler) - - if not isdir(compiler_rule): - raise RuntimeError( - 'No wmake rule for {0}'.format(archCompiler)) - if not re.match(r'.+Opt$', compileOpt): - raise RuntimeError( - "WM_COMPILE_OPTION={0} is not type '*Opt'".format(compileOpt)) - - # Adjust for variants - self.foam_cfg['WM_LABEL_SIZE'] = ( - '64' if '+int64' in self.spec else '32' - ) - self.foam_cfg['WM_PRECISION_OPTION'] = ( - 'SP' if '+float32' in self.spec else 'DP' - ) - - # ---- - # WM_LABEL_OPTION=Int$WM_LABEL_SIZE - # WM_OPTIONS=$WM_ARCH$WM_COMPILER$WM_PRECISION_OPTION$WM_LABEL_OPTION$WM_COMPILE_OPTION - # ---- - self.foam_sys['WM_ARCH'] = wm_arch - self.foam_sys['WM_COMPILER'] = wm_compiler - self.foam_cfg['WM_COMPILER'] = wm_compiler # For bashrc,cshrc too - self.foam_sys['WM_OPTIONS'] = ''.join([ - wm_arch, - wm_compiler, - self.foam_cfg['WM_PRECISION_OPTION'], - 'Int', self.foam_cfg['WM_LABEL_SIZE'], # Int32/Int64 - compileOpt - ]) - return self.foam_sys['WM_OPTIONS'] - - def patch(self): - """Adjust OpenFOAM build for spack. Where needed, apply filter as an - alternative to normal patching. - """ - self.set_openfoam() # May need foam_cfg/foam_sys information - - # This is fairly horrible. - # The github tarfiles have weird names that do not correspond to the - # canonical name. We need to rename these, but leave a symlink for - # spack to work with. - # - # Note that this particular OpenFOAM release requires absolute - # directories to build correctly! + # Note that this particular OpenFOAM requires absolute directories + # to build correctly! parent = os.path.dirname(self.stage.source_path) original = os.path.basename(self.stage.source_path) - target = self._canonical + target = 'OpenFOAM-{0}'.format(self.version) + # Could also grep through etc/bashrc for WM_PROJECT_VERSION with working_dir(parent): if original != target and not os.path.lexists(target): os.rename(original, target) os.symlink(target, original) tty.info('renamed {0} -> {1}'.format(original, target)) + def patch(self): + """Adjust OpenFOAM build for spack. + Where needed, apply filter as an alternative to normal patching.""" + self.rename_source() + add_extra_files(self, self.common, self.assets) + # Avoid WM_PROJECT_INST_DIR for ThirdParty, site or jobControl. # Use openfoam-site.patch to handle jobControl, site. # - # Filter (not patch) bashrc,cshrc for additional flexibility - wm_setting = { + # Filtering: bashrc,cshrc (using a patch is less flexible) + edits = { 'WM_THIRD_PARTY_DIR': r'$WM_PROJECT_DIR/ThirdParty #SPACK: No separate third-party', 'WM_VERSION': self.version, # consistency 'FOAMY_HEX_MESH': '', # This is horrible (unset variable?) } - rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc - wm_setting, + edits, posix=join_path('etc', 'bashrc'), cshell=join_path('etc', 'cshrc')) - # Build wrapper script - with open(self.build_script, 'w') as out: - out.write( - """#!/bin/bash -. $PWD/etc/bashrc '' # No arguments -mkdir -p $FOAM_APPBIN $FOAM_LIBBIN 2>/dev/null # Allow interrupt -echo Build openfoam with SPACK -echo WM_PROJECT_DIR = $WM_PROJECT_DIR -./Allwmake $@ -# -""") - set_executable(self.build_script) - self.configure(self.spec, self.prefix) # Should be a separate phase - def configure(self, spec, prefix): """Make adjustments to the OpenFOAM configuration files in their various locations: etc/bashrc, etc/config.sh/FEATURE and customizations that don't properly fit get placed in the etc/prefs.sh file (similiarly for csh). """ - self.set_openfoam() # Need foam_cfg/foam_sys information - - # Some settings for filtering bashrc, cshrc - wm_setting = {} - wm_setting.update(self.foam_cfg) - + # Filtering bashrc, cshrc + edits = {} + edits.update(self.foam_arch.foam_dict()) rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc - wm_setting, + edits, posix=join_path('etc', 'bashrc'), cshell=join_path('etc', 'cshrc')) # MPI content, with absolute paths - content = mplib_content(spec) + user_mpi = mplib_content(spec) # Content for etc/prefs.{csh,sh} self.etc_prefs = { r'MPI_ROOT': spec['mpi'].prefix, # Absolute - r'MPI_ARCH_FLAGS': '"%s"' % content['FLAGS'], - r'MPI_ARCH_INC': '"%s"' % content['PINC'], - r'MPI_ARCH_LIBS': '"%s"' % content['PLIBS'], + r'MPI_ARCH_FLAGS': '"%s"' % user_mpi['FLAGS'], + r'MPI_ARCH_INC': '"%s"' % user_mpi['PINC'], + r'MPI_ARCH_LIBS': '"%s"' % user_mpi['PLIBS'], } # Content for etc/config.{csh,sh}/ files @@ -368,6 +235,7 @@ def configure(self, spec, prefix): 'scotch': {}, 'metis': {}, 'paraview': [], + 'gperftools': [], # Currently unused } if True: @@ -392,45 +260,30 @@ def configure(self, spec, prefix): posix=join_path('etc', 'config.sh', component), cshell=join_path('etc', 'config.csh', component)) - archCompiler = self.foam_sys['WM_ARCH'] + self.foam_sys['WM_COMPILER'] - compileOpt = self.foam_cfg['WM_COMPILE_OPTION'] - general_rule = join_path('wmake', 'rules', 'General') - compiler_rule = join_path('wmake', 'rules', archCompiler) - generate_mplib_rules(general_rule, self.spec) - generate_compiler_rules(compiler_rule, compileOpt, self.rpath_info) - # Record the spack spec information - with open("log.spack-spec", 'w') as outfile: - outfile.write(spec.tree()) - def build(self, spec, prefix): """Build using the OpenFOAM Allwmake script, with a wrapper to source its environment first. + Only build if the compiler is known to be supported. """ - self.set_openfoam() # Force proper population of foam_cfg/foam_sys + self.foam_arch.has_rule(self.stage.source_path) + self.foam_arch.create_rules(self.stage.source_path, self) + args = [] if self.parallel: # Build in parallel? - pass via the environment - os.environ['WM_NCOMPPROCS'] = str(self.make_jobs) \ - if self.make_jobs else str(multiprocessing.cpu_count()) + os.environ['WM_NCOMPPROCS'] = str(make_jobs) builder = Executable(self.build_script) builder(*args) def install(self, spec, prefix): - """Install under the projectdir (== prefix/name-version)""" - self.build(spec, prefix) # Should be a separate phase - opts = self.wm_options - + """Install under the projectdir""" mkdirp(self.projectdir) projdir = os.path.basename(self.projectdir) - wm_setting = { + # Filtering: bashrc, cshrc + edits = { 'WM_PROJECT_INST_DIR': os.path.dirname(self.projectdir), 'WM_PROJECT_DIR': join_path('$WM_PROJECT_INST_DIR', projdir), } - # Retain build log file - out = "spack-build.out" - if isfile(out): - install(out, join_path(self.projectdir, "log." + opts)) - # All top-level files, except spack build info and possibly Allwmake if '+source' in spec: ignored = re.compile(r'^spack-.*') @@ -438,20 +291,23 @@ def install(self, spec, prefix): ignored = re.compile(r'^(Allwmake|spack-).*') files = [ - f for f in glob.glob("*") if isfile(f) and not ignored.search(f) + f for f in glob.glob("*") + if os.path.isfile(f) and not ignored.search(f) ] for f in files: install(f, self.projectdir) - # Having wmake without sources is actually somewhat pointless... - dirs = ['bin', 'etc', 'wmake'] + # Having wmake and ~source is actually somewhat pointless... + # Install 'etc' before 'bin' (for symlinks) + dirs = ['etc', 'bin', 'wmake'] if '+source' in spec: dirs.extend(['applications', 'src', 'tutorials']) for d in dirs: install_tree( d, - join_path(self.projectdir, d)) + join_path(self.projectdir, d), + symlinks=True) dirs = ['platforms'] if '+source' in spec: @@ -463,29 +319,37 @@ def install(self, spec, prefix): install_tree( d, join_path(self.projectdir, d), - ignore=shutil.ignore_patterns(*ignored)) + ignore=shutil.ignore_patterns(*ignored), + symlinks=True) + etc_dir = join_path(self.projectdir, 'etc') rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc - wm_setting, - posix=join_path(self.etc, 'bashrc'), - cshell=join_path(self.etc, 'cshrc')) + edits, + posix=join_path(etc_dir, 'bashrc'), + cshell=join_path(etc_dir, 'cshrc')) self.install_links() def install_links(self): """Add symlinks into bin/, lib/ (eg, for other applications)""" - if not self.extra_symlinks: + # Make build log visible - it contains OpenFOAM-specific information + with working_dir(self.projectdir): + os.symlink( + join_path('.spack', 'build.out'), + join_path('log.' + str(self.foam_arch))) + + if not self.config['link']: return # ln -s platforms/linux64GccXXX/lib lib with working_dir(self.projectdir): - if isdir(self.archlib): + if os.path.isdir(self.archlib): os.symlink(self.archlib, 'lib') # (cd bin && ln -s ../platforms/linux64GccXXX/bin/* .) with working_dir(join_path(self.projectdir, 'bin')): for f in [ f for f in glob.glob(join_path('..', self.archbin, "*")) - if isfile(f) + if os.path.isfile(f) ]: os.symlink(f, os.path.basename(f))