diff options
author | Mark Olesen <Mark.Olesen@gmx.net> | 2017-06-21 17:35:31 +0100 |
---|---|---|
committer | Adam J. Stewart <ajstewart426@gmail.com> | 2017-06-21 11:35:31 -0500 |
commit | 1f2e56e1f3452fdc9b6dde349a67efc217292b04 (patch) | |
tree | 17e5d58bd4eae61a387f9298346b1ee8f2e30a3b | |
parent | b1fceb75d0f7b999c5f2a4edc686a1a947b60a95 (diff) | |
download | spack-1f2e56e1f3452fdc9b6dde349a67efc217292b04.tar.gz spack-1f2e56e1f3452fdc9b6dde349a67efc217292b04.tar.bz2 spack-1f2e56e1f3452fdc9b6dde349a67efc217292b04.tar.xz spack-1f2e56e1f3452fdc9b6dde349a67efc217292b04.zip |
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
15 files changed, 1316 insertions, 757 deletions
diff --git a/etc/spack/defaults/packages.yaml b/etc/spack/defaults/packages.yaml index 0cafab28e9..d04ce76e6b 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 c68e570c0f..d417ef8cf3 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,189 +107,77 @@ 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 = [] - # The system description is frequently needed - foam_sys = { - 'WM_ARCH': None, - 'WM_COMPILER': None, - 'WM_OPTIONS': None, + # Some user config settings + config = { + 'label-size': False, # <- No int32/int64 support + 'mplib': 'USERMPI', # USER | USERMPI } + # The openfoam architecture, compiler information etc + _foam_arch = None + # Content for etc/prefs.{csh,sh} etc_prefs = {} # 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) - - @property - def _canonical(self): - """Canonical name for this package and version""" - return 'foam-extend-{0}'.format(self.version.up_to(2)) + 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): """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 @@ class FoamExtend(Package): 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 @@ echo WM_PROJECT_DIR = $WM_PROJECT_DIR 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 @@ echo WM_PROJECT_DIR = $WM_PROJECT_DIR }, } # 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 @@ echo WM_PROJECT_DIR = $WM_PROJECT_DIR 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 @@ echo WM_PROJECT_DIR = $WM_PROJECT_DIR 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 0000000000..d116bbaa23 --- /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 0000000000..83b606dda1 --- /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 0000000000..61d9c3ea8b --- /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 <http://www.gnu.org/licenses/>. +# +# 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 0000000000..d126fcfe5d --- /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 <http://www.gnu.org/licenses/>. +# +# 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 0000000000..cff22daf10 --- /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 0000000000..407ad734e8 --- /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 0000000000..8dc0b995ff --- /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 index 6631025788..d988c2f9b8 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 0000000000..a1f5d8a08a --- /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 15c4f8fdd4..c6dd6dbe9a 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,60 +311,64 @@ 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') - # The system description is frequently needed - foam_sys = { - 'WM_ARCH': None, - 'WM_COMPILER': None, - 'WM_OPTIONS': None, + # 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 openfoam architecture, compiler information etc + _foam_arch = None + # Content for etc/prefs.{csh,sh} etc_prefs = {} # 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 @@ class OpenfoamCom(Package): 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 @@ echo WM_PROJECT_DIR = $WM_PROJECT_DIR } # 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 @@ echo WM_PROJECT_DIR = $WM_PROJECT_DIR 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 @@ echo WM_PROJECT_DIR = $WM_PROJECT_DIR 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 @@ echo WM_PROJECT_DIR = $WM_PROJECT_DIR 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 @@ echo WM_PROJECT_DIR = $WM_PROJECT_DIR 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 0000000000..294cc26505 --- /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 <http://www.gnu.org/licenses/>. +# +# 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/<VER>/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-<VERSION>/bin +# - $WM_PROJECT_INST_DIR/openfoam-<VERSION>/bin +# - $WM_PROJECT_INST_DIR/OpenFOAM+<VERSION>/bin +# - $WM_PROJECT_INST_DIR/openfoam+<VERSION>/bin +# - $WM_PROJECT_INST_DIR/openfoam<VERSION>/bin (debian version) +# +#------------------------------------------------------------------------------- +unset optQuiet optSilent +usage() { + [ "${optQuiet:-$optSilent}" = true ] && exit 1 + exec 1>&2 + while [ "$#" -ge 1 ]; do echo "$1"; shift; done + cat<<USAGE + +Usage: foamEtcFile [OPTION] fileName + foamEtcFile [OPTION] [-list|-list-test] [fileName] + +options: + -a, -all Return all files (otherwise stop after the first match) + -l, -list List directories or files to be checked + -list-test List (existing) directories or files to be checked + -mode=MODE Any combination of u(user), g(group), o(other) + -prefix=DIR Specify an alternative installation prefix + -version=VER Specify alternative OpenFOAM version (eg, 3.0, 1612, ...) + -csh | -sh Produce output suitable for a csh or sh 'eval' + -csh-verbose | -sh-verbose + As per -csh | -sh, with additional verbosity + -q, -quiet Suppress all normal output + -s, -silent Suppress stderr, except -csh-verbose, -sh-verbose output + -help Print the usage + +Locate user/group/other file with semantics similar to the +~OpenFOAM/fileName expansion. + +Single character options must not be grouped. Equivalent options: + -mode=MODE, -mode MODE, -m MODE + -prefix=DIR, -prefix DIR, -p DIR + -version=VER, -version VER, -v VER + +Exit status + 0 when the file is found. Print resolved path to stdout. + 1 for miscellaneous errors. + 2 when the file is not found. + +USAGE + exit 1 +} + +# Report error and exit +die() +{ + [ "${optQuiet:-$optSilent}" = true ] && exit 1 + exec 1>&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-<VERSION> or openfoam-<VERSION> + dirBase="${projectDirName%%-*}-" + version="${projectDirName#*-}" + version="${version%%*-}" # Extra safety, eg openfoam-version-packager + ;; + + (OpenFOAM+* | openfoam+*) + # Alternative naming: OpenFOAM+<VERSION> or openfoam+<VERSION> + dirBase="${projectDirName%%+*}+" + version="${projectDirName#*+}" + version="${version%%*-}" # Extra safety, eg openfoam-version-packager + ;; + + (openfoam[0-9]*) + # Debian naming: openfoam<VERSION> + 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 index 6631025788..d988c2f9b8 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 53be5f6337..02c27a0db5 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') - - # 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 + patch('openfoam-etc-41.patch', when='@4.1') + patch('openfoam-site-41.patch', when='@4.1') + + # 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) - - @property - def _canonical(self): - """Canonical name for this package and version""" - return 'OpenFOAM-{0}'.format(self.version) + 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): """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') - - @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. + 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. """ - 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 @@ echo WM_PROJECT_DIR = $WM_PROJECT_DIR 'scotch': {}, 'metis': {}, 'paraview': [], + 'gperftools': [], # Currently unused } if True: @@ -392,45 +260,30 @@ echo WM_PROJECT_DIR = $WM_PROJECT_DIR 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 @@ echo WM_PROJECT_DIR = $WM_PROJECT_DIR 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 @@ echo WM_PROJECT_DIR = $WM_PROJECT_DIR 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)) |