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
This commit is contained in:
Mark Olesen 2017-06-21 17:35:31 +01:00 committed by Adam J. Stewart
parent b1fceb75d0
commit 1f2e56e1f3
15 changed files with 1313 additions and 754 deletions

View File

@ -28,6 +28,6 @@ packages:
mpe: [mpe2] mpe: [mpe2]
mpi: [openmpi, mpich] mpi: [openmpi, mpich]
opencl: [pocl] opencl: [pocl]
openfoam: [foam-extend] openfoam: [openfoam-com, openfoam-org, foam-extend]
pil: [py-pillow] pil: [py-pillow]
scalapack: [netlib-scalapack] scalapack: [netlib-scalapack]

View File

@ -48,16 +48,17 @@
# - reworked to mirror the openfoam-com package. # - reworked to mirror the openfoam-com package.
# If changes are needed here, consider if they need applying there too. # 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 import *
from spack.environment import * from spack.environment import *
import multiprocessing
import glob import glob
import re import re
import shutil import shutil
import os import os
from os.path import isdir, isfile
from spack.pkg.builtin.openfoam_com import * 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') version('3.0', git='http://git.code.sf.net/p/foam-extend/foam-extend-3.0')
# variant('int64', default=False, # variant('int64', default=False,
# description='Compile with 64-bit labels') # description='Compile with 64-bit label')
variant('float32', default=False, variant('float32', default=False,
description='Compile with 32-bit scalar (single-precision)') description='Compile with 32-bit scalar (single-precision)')
variant('paraview', default=False, variant('paraview', default=False,
description='Build paraview plugins (eg, paraFoam)') description='Build paraview plugins (eg, paraFoam)')
variant('scotch', default=True, variant('scotch', default=True,
@ -96,10 +96,6 @@ class FoamExtend(Package):
variant('source', default=True, variant('source', default=True,
description='Install library/application sources and tutorials') 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') provides('openfoam')
depends_on('mpi') depends_on('mpi')
depends_on('python') depends_on('python')
@ -111,25 +107,22 @@ class FoamExtend(Package):
depends_on('scotch~metis+mpi', when='+ptscotch') depends_on('scotch~metis+mpi', when='+ptscotch')
depends_on('metis@5:', when='+metis') depends_on('metis@5:', when='+metis')
depends_on('parmetis', when='+parmetis') 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') depends_on('paraview@:5.0.1', when='+paraview')
# Some user settings, to be adjusted manually or via variants # General patches
foam_cfg = { common = ['spack-Allwmake', 'README-spack']
'WM_COMPILER': 'Gcc', # <- %compiler assets = []
'WM_ARCH_OPTION': '64', # (32/64-bit on x86_64)
# FUTURE? 'WM_LABEL_SIZE': '32', # <- +int64 # Some user config settings
'WM_PRECISION_OPTION': 'DP', # <- +float32 config = {
'WM_COMPILE_OPTION': 'SPACKOpt', # Do not change 'label-size': False, # <- No int32/int64 support
'WM_MPLIB': 'USER', # USER | USERMPI 'mplib': 'USERMPI', # USER | USERMPI
} }
# The system description is frequently needed # The openfoam architecture, compiler information etc
foam_sys = { _foam_arch = None
'WM_ARCH': None,
'WM_COMPILER': None,
'WM_OPTIONS': None,
}
# Content for etc/prefs.{csh,sh} # Content for etc/prefs.{csh,sh}
etc_prefs = {} etc_prefs = {}
@ -137,163 +130,54 @@ class FoamExtend(Package):
# Content for etc/config.{csh,sh}/ files # Content for etc/config.{csh,sh}/ files
etc_config = {} etc_config = {}
build_script = './spack-Allwmake' # <- Generated by patch() method. phases = ['configure', 'build', 'install']
# phases = ['configure', 'build', 'install'] build_script = './spack-Allwmake' # <- Added by patch() method.
# build_system_class = 'OpenfoamCom'
#
# - End of definitions / setup -
#
def setup_environment(self, spack_env, run_env): 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) 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 setup_dependent_environment(self, spack_env, run_env, dependent_spec):
def _canonical(self): """Provide location of the OpenFOAM project.
"""Canonical name for this package and version""" This is identical to the WM_PROJECT_DIR value, but we avoid that
return 'foam-extend-{0}'.format(self.version.up_to(2)) variable since it would mask the normal OpenFOAM cleanup of
previous versions.
"""
spack_env.set('FOAM_PROJECT_DIR', self.projectdir)
@property @property
def projectdir(self): def projectdir(self):
"""Absolute location of project directory: WM_PROJECT_DIR/""" """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 @property
def etc(self): def foam_arch(self):
"""Absolute location of the OpenFOAM etc/ directory""" if not self._foam_arch:
return join_path(self.projectdir, 'etc') self._foam_arch = OpenfoamArch(self.spec, **self.config)
return self._foam_arch
@property @property
def archbin(self): def archbin(self):
"""Relative location of architecture-specific executables""" """Relative location of architecture-specific executables"""
wm_options = self.set_openfoam() return join_path('applications', 'bin', self.foam_arch)
return join_path('applications', 'bin', wm_options)
@property @property
def archlib(self): def archlib(self):
"""Relative location of architecture-specific libraries""" """Relative location of architecture-specific libraries"""
wm_options = self.set_openfoam() return join_path('lib', self.foam_arch)
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']
def patch(self): def patch(self):
"""Adjust OpenFOAM build for spack. Where needed, apply filter as an """Adjust OpenFOAM build for spack.
alternative to normal patching. Where needed, apply filter as an alternative to normal patching."""
""" add_extra_files(self, self.common, self.assets)
self.set_openfoam() # May need foam_cfg/foam_sys information
# Adjust ParMGridGen - this is still a mess # Adjust ParMGridGen - this is still a mess
files = [ files = [
@ -319,23 +203,7 @@ def patch(self):
filter_file( filter_file(
r'#if YY_FLEX_SUBMINOR_VERSION < 34', 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 r'#if YY_FLEX_MAJOR_VERSION <= 2 && YY_FLEX_MINOR_VERSION <= 5 && YY_FLEX_SUBMINOR_VERSION < 34', # noqa: E501
f, backup=False 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
def configure(self, spec, prefix): def configure(self, spec, prefix):
"""Make adjustments to the OpenFOAM configuration files in their various """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 don't properly fit get placed in the etc/prefs.sh file (similiarly for
csh). csh).
""" """
self.set_openfoam() # Need foam_cfg/foam_sys information
# Content for etc/prefs.{csh,sh} # Content for etc/prefs.{csh,sh}
self.etc_prefs = { self.etc_prefs = {
'000': { # Sort first '000': { # Sort first
@ -373,7 +239,7 @@ def configure(self, spec, prefix):
}, },
} }
# Adjust configuration via prefs - sort second # 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: if '+scotch' in spec or '+ptscotch' in spec:
pkg = spec['scotch'].prefix pkg = spec['scotch'].prefix
@ -434,41 +300,33 @@ def configure(self, spec, prefix):
posix=join_path('etc', 'prefs.sh'), posix=join_path('etc', 'prefs.sh'),
cshell=join_path('etc', 'prefs.csh')) 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): def build(self, spec, prefix):
"""Build using the OpenFOAM Allwmake script, with a wrapper to source """Build using the OpenFOAM Allwmake script, with a wrapper to source
its environment first. 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 = [] args = []
if self.parallel: # Build in parallel? - pass via the environment if self.parallel: # Build in parallel? - pass via the environment
os.environ['WM_NCOMPPROCS'] = str(self.make_jobs) \ os.environ['WM_NCOMPPROCS'] = str(make_jobs)
if self.make_jobs else str(multiprocessing.cpu_count())
builder = Executable(self.build_script) builder = Executable(self.build_script)
builder(*args) builder(*args)
def install(self, spec, prefix): def install(self, spec, prefix):
"""Install under the projectdir (== prefix/name-version)""" """Install under the projectdir"""
self.build(spec, prefix) # Should be a separate phase opts = str(self.foam_arch)
opts = self.wm_options
# Fairly ugly since intermediate targets are scattered inside sources # Fairly ugly since intermediate targets are scattered inside sources
appdir = 'applications' appdir = 'applications'
projdir = os.path.basename(self.projectdir)
mkdirp(self.projectdir, join_path(self.projectdir, appdir)) mkdirp(self.projectdir, join_path(self.projectdir, appdir))
# Filtering: bashrc, cshrc
# Retain build log file edits = {
out = "spack-build.out" 'WM_PROJECT_INST_DIR': os.path.dirname(self.projectdir),
if isfile(out): 'WM_PROJECT_DIR': join_path('$WM_PROJECT_INST_DIR', projdir),
install(out, join_path(self.projectdir, "log." + opts)) }
# All top-level files, except spack build info and possibly Allwmake # All top-level files, except spack build info and possibly Allwmake
if '+source' in spec: if '+source' in spec:
@ -477,36 +335,52 @@ def install(self, spec, prefix):
ignored = re.compile(r'^(Allclean|Allwmake|spack-).*') ignored = re.compile(r'^(Allclean|Allwmake|spack-).*')
files = [ 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: for f in files:
install(f, self.projectdir) install(f, self.projectdir)
# Install directories. install applications/bin directly # 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( install_tree(
d, d,
join_path(self.projectdir, d)) join_path(self.projectdir, d),
symlinks=True)
if '+source' in spec: if '+source' in spec:
subitem = join_path(appdir, 'Allwmake') subitem = join_path(appdir, 'Allwmake')
install(subitem, join_path(self.projectdir, subitem)) install(subitem, join_path(self.projectdir, subitem))
ignored = [opts] # Intermediate targets ignored = [opts] # Ignore intermediate targets
for d in ['src', 'tutorials']: for d in ['src', 'tutorials']:
install_tree( install_tree(
d, d,
join_path(self.projectdir, d), join_path(self.projectdir, d),
ignore=shutil.ignore_patterns(*ignored)) ignore=shutil.ignore_patterns(*ignored),
symlinks=True)
for d in ['solvers', 'utilities']: for d in ['solvers', 'utilities']:
install_tree( install_tree(
join_path(appdir, d), join_path(appdir, d),
join_path(self.projectdir, 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): def install_links(self):
"""Add symlinks into bin/, lib/ (eg, for other applications)""" """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)))
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------

View File

@ -0,0 +1,2 @@
Some helper tools for packaging applications/libraries dependent on an
openfoam provider.

View File

@ -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

View File

@ -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
#------------------------------------------------------------------------------

View File

@ -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
#------------------------------------------------------------------------------

View File

@ -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
# -----------------------------------------------------------------------------

View File

@ -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
# -----------------------------------------------------------------------------

View File

@ -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

View File

@ -6,7 +6,7 @@ diff -uw OpenFOAM-v1612+.orig/etc/config.sh/settings OpenFOAM-v1612+/etc/config.
# Location of the jobControl directory # Location of the jobControl directory
-export FOAM_JOB_DIR=$WM_PROJECT_INST_DIR/jobControl -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 # wmake configuration
export WM_DIR=$WM_PROJECT_DIR/wmake 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 # Site-specific directory
-siteDir="${WM_PROJECT_SITE:-$WM_PROJECT_INST_DIR/site}" -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 # Shared site executables/libraries
# Similar naming convention as ~OpenFOAM expansion # 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 # Location of the jobControl directory
-setenv FOAM_JOB_DIR $WM_PROJECT_INST_DIR/jobControl -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 # wmake configuration
setenv WM_DIR $WM_PROJECT_DIR/wmake setenv WM_DIR $WM_PROJECT_DIR/wmake

View File

@ -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

View File

@ -50,38 +50,74 @@
# variants: +plugins +qt # variants: +plugins +qt
# in ~/.spack/packages.yaml # in ~/.spack/packages.yaml
# #
# Known issues
# - Combining +zoltan with +int64 has not been tested, but probably won't work. # - 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 import *
from spack.environment import * from spack.environment import *
import llnl.util.tty as tty
import glob import glob
import re import re
import shutil import shutil
import os import os
from os.path import isdir, isfile
# Not the nice way of doing things, but is a start for refactoring # Not the nice way of doing things, but is a start for refactoring
__all__ = [ __all__ = [
'format_export', 'add_extra_files',
'format_setenv',
'write_environ', 'write_environ',
'rewrite_environ_files', 'rewrite_environ_files',
'mplib_content', 'mplib_content',
'generate_mplib_rules', 'foamAddPath',
'generate_compiler_rules', '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): def format_export(key, value):
"""Format key,value pair as 'export' with newline for POSIX shell.""" """Format key,value pair as 'export' with newline for POSIX shell.
return 'export {0}={1}\n'.format(key, value) 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): def format_setenv(key, value):
"""Format key,value pair as 'setenv' with newline for C-shell.""" """Format key,value pair as 'setenv' with newline for C-shell.
return 'setenv {0} {1}\n'.format(key, value) 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): 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. cshell[=None] If set, the name of the C-shell file to rewrite.
""" """
posix = kwargs.get('posix', None) posix = kwargs.get('posix', None)
if posix and isfile(posix): if posix and os.path.isfile(posix):
for k, v in environ.items(): for k, v in environ.items():
filter_file( filter_file(
r'^(\s*export\s+%s)=.*$' % k, r'^(\s*export\s+%s)=.*$' % k,
@ -147,7 +183,7 @@ def rewrite_environ_files(environ, **kwargs):
posix, posix,
backup=False) backup=False)
cshell = kwargs.get('cshell', None) cshell = kwargs.get('cshell', None)
if cshell and isfile(cshell): if cshell and os.path.isfile(cshell):
for k, v in environ.items(): for k, v in environ.items():
filter_file( filter_file(
r'^(\s*setenv\s+%s)\s+.*$' % k, r'^(\s*setenv\s+%s)\s+.*$' % k,
@ -156,19 +192,35 @@ def rewrite_environ_files(environ, **kwargs):
backup=False) backup=False)
def pkglib(package): def foamAddPath(*args):
"""Get lib64 or lib from package prefix""" """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 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 libdir
return package.prefix.lib
def mplib_content(spec, pre=None): def mplib_content(spec, pre=None):
"""The mpi settings to have wmake """The mpi settings to have wmake
use spack information with minimum modifications to OpenFOAM. 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'] mpi_spec = spec['mpi']
bin = mpi_spec.prefix.bin bin = mpi_spec.prefix.bin
@ -194,36 +246,7 @@ def mplib_content(spec, pre=None):
return info 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): class OpenfoamCom(Package):
"""OpenFOAM is a GPL-opensource C++ CFD-toolbox. """OpenFOAM is a GPL-opensource C++ CFD-toolbox.
@ -239,31 +262,28 @@ class OpenfoamCom(Package):
version('1612', 'ca02c491369150ab127cbb88ec60fbdf', version('1612', 'ca02c491369150ab127cbb88ec60fbdf',
url=baseurl + '/v1612+/OpenFOAM-v1612+.tgz') 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, variant('int64', default=False,
description='Compile with 64-bit labels') description='Compile with 64-bit label')
variant('float32', default=False, variant('float32', default=False,
description='Compile with 32-bit scalar (single-precision)') description='Compile with 32-bit scalar (single-precision)')
variant('knl', default=False, variant('knl', default=False,
description='Use KNL compiler settings') description='Use KNL compiler settings')
variant('scotch', default=True, variant('scotch', default=True,
description='With scotch/ptscotch for decomposition') description='With scotch/ptscotch for decomposition')
variant('metis', default=False, variant('metis', default=False,
description='With metis for decomposition') description='With metis for decomposition')
variant('zoltan', default=False, variant('zoltan', default=False,
description='With zoltan renumbering') description='With zoltan renumbering')
# TODO?# variant('parmgridgen', default=True, # TODO?# variant('scalasca', default=False,
# TODO?# description='With parmgridgen support') # TODO?# description='With scalasca profiling')
variant('source', default=True, variant('mgridgen', default=False, description='With mgridgen support')
description='Install library/application sources and tutorials')
variant('paraview', default=True, variant('paraview', default=True,
description='Build paraview plugins and runtime post-processing') description='Build paraview plugins and runtime post-processing')
variant('source', default=True,
#: Map spack compiler names to OpenFOAM compiler names description='Install library/application sources and tutorials')
# By default, simply capitalize the first letter
compiler_mapping = {'intel': 'icc'}
provides('openfoam') provides('openfoam')
depends_on('mpi') depends_on('mpi')
@ -275,12 +295,14 @@ class OpenfoamCom(Package):
depends_on('cmake', type='build') depends_on('cmake', type='build')
# Require scotch with ptscotch - corresponds to standard OpenFOAM setup # Require scotch with ptscotch - corresponds to standard OpenFOAM setup
depends_on('scotch~int64+mpi', when='+scotch~int64') depends_on('scotch~metis+mpi~int64', when='+scotch~int64')
depends_on('scotch+int64+mpi', when='+scotch+int64') depends_on('scotch~metis+mpi+int64', when='+scotch+int64')
depends_on('metis@5:', when='+metis') depends_on('metis@5:', when='+metis')
depends_on('metis+int64', when='+metis+int64') 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') depends_on('zoltan', when='+zoltan')
# TODO?# depends_on('scalasca', when='+scalasca')
# For OpenFOAM plugins and run-time post-processing this should just be # For OpenFOAM plugins and run-time post-processing this should just be
# 'paraview+plugins' but that resolves poorly. # 'paraview+plugins' but that resolves poorly.
@ -289,36 +311,36 @@ class OpenfoamCom(Package):
# 1612 plugins need older paraview # 1612 plugins need older paraview
# The native reader in paraview 5.2 is broken, so start after that # 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='@1706:+paraview')
depends_on('paraview@5.3:', when='@plus+paraview')
# General patches # General patches
patch('openfoam-site.patch') common = ['spack-Allwmake', 'README-spack']
assets = []
# Version-specific patches # Version-specific patches
patch('openfoam-bin-1612.patch', when='@1612') patch('openfoam-bin-1612.patch', when='@1612')
patch('openfoam-etc-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-mpi-1612.patch', when='@1612')
patch('openfoam-build-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('scotch-metis-lib-1612.patch', when='@1612')
patch('zoltan-lib-1612.patch', when='@1612') patch('zoltan-lib-1612.patch', when='@1612')
# Some user settings, to be adjusted manually or via variants patch('openfoam-site-plus.patch', when='@plus')
foam_cfg = {
'WM_COMPILER': 'Gcc', # <- %compiler # Some user config settings
'WM_ARCH_OPTION': '64', # (32/64-bit on x86_64) # default: 'compile-option': 'RpathOpt',
'WM_LABEL_SIZE': '32', # <- +int64 # default: 'mplib': 'USERMPI', # Use user mpi for spack
'WM_PRECISION_OPTION': 'DP', # <- +float32 config = {
'WM_COMPILE_OPTION': 'SPACKOpt', # Do not change # Add links into bin/, lib/ (eg, for other applications)
'WM_MPLIB': 'USERMPI', # Use user mpi for spack 'link': False
} }
# The system description is frequently needed # The openfoam architecture, compiler information etc
foam_sys = { _foam_arch = None
'WM_ARCH': None,
'WM_COMPILER': None,
'WM_OPTIONS': None,
}
# Content for etc/prefs.{csh,sh} # Content for etc/prefs.{csh,sh}
etc_prefs = {} etc_prefs = {}
@ -326,23 +348,27 @@ class OpenfoamCom(Package):
# Content for etc/config.{csh,sh}/ files # Content for etc/config.{csh,sh}/ files
etc_config = {} etc_config = {}
build_script = './spack-Allwmake' # <- Generated by patch() method. phases = ['configure', 'build', 'install']
# phases = ['configure', 'build', 'install'] build_script = './spack-Allwmake' # <- Added by patch() method.
# build_system_class = 'OpenfoamCom'
# Add symlinks into bin/, lib/ (eg, for other applications) #
extra_symlinks = False # - End of definitions / setup -
#
# 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'))
def setup_environment(self, spack_env, run_env): def setup_environment(self, spack_env, run_env):
run_env.set('FOAM_PROJECT_DIR', self.projectdir)
run_env.set('WM_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 @property
def projectdir(self): def projectdir(self):
@ -350,195 +376,50 @@ def projectdir(self):
return self.prefix # <- install directly under prefix return self.prefix # <- install directly under prefix
@property @property
def etc(self): def foam_arch(self):
"""Absolute location of the OpenFOAM etc/ directory""" if not self._foam_arch:
return join_path(self.projectdir, 'etc') self._foam_arch = OpenfoamArch(self.spec, **self.config)
return self._foam_arch
@property @property
def archbin(self): def archbin(self):
"""Relative location of architecture-specific executables""" """Relative location of architecture-specific executables"""
return join_path('platforms', self.wm_options, 'bin') return join_path('platforms', self.foam_arch, 'bin')
@property @property
def archlib(self): def archlib(self):
"""Relative location of architecture-specific libraries""" """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
"""
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): def patch(self):
"""Adjust OpenFOAM build for spack. Where needed, apply filter as an """Adjust OpenFOAM build for spack.
alternative to normal patching. Where needed, apply filter as an alternative to normal patching."""
""" add_extra_files(self, self.common, self.assets)
self.set_openfoam() # May need foam_cfg/foam_sys information
# Avoid WM_PROJECT_INST_DIR for ThirdParty, site or jobControl. # Avoid WM_PROJECT_INST_DIR for ThirdParty, site or jobControl.
# Use openfoam-site.patch to handle jobControl, site. # Use openfoam-site.patch to handle jobControl, site.
# #
# Filter (not patch) bashrc,cshrc for additional flexibility # Filtering: bashrc,cshrc (using a patch is less flexible)
wm_setting = { edits = {
'WM_THIRD_PARTY_DIR': 'WM_THIRD_PARTY_DIR':
r'$WM_PROJECT_DIR/ThirdParty #SPACK: No separate third-party', r'$WM_PROJECT_DIR/ThirdParty #SPACK: No separate third-party',
} }
rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc
wm_setting, edits,
posix=join_path('etc', 'bashrc'), posix=join_path('etc', 'bashrc'),
cshell=join_path('etc', 'cshrc')) 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): def configure(self, spec, prefix):
"""Make adjustments to the OpenFOAM configuration files in their various """Make adjustments to the OpenFOAM configuration files in their various
locations: etc/bashrc, etc/config.sh/FEATURE and customizations that locations: etc/bashrc, etc/config.sh/FEATURE and customizations that
don't properly fit get placed in the etc/prefs.sh file (similiarly for don't properly fit get placed in the etc/prefs.sh file (similiarly for
csh). csh).
""" """
self.set_openfoam() # Need foam_cfg/foam_sys information # Filtering bashrc, cshrc
edits = {}
# Some settings for filtering bashrc, cshrc edits.update(self.foam_arch.foam_dict())
wm_setting = {}
wm_setting.update(self.foam_cfg)
rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc
wm_setting, edits,
posix=join_path('etc', 'bashrc'), posix=join_path('etc', 'bashrc'),
cshell=join_path('etc', 'cshrc')) cshell=join_path('etc', 'cshrc'))
@ -551,27 +432,34 @@ def configure(self, spec, prefix):
} }
# MPI content, using MPI_ARCH_PATH # 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 # Content for etc/config.{csh,sh}/ files
self.etc_config = { self.etc_config = {
'CGAL': { 'CGAL': [
'BOOST_ARCH_PATH': spec['boost'].prefix, ('BOOST_ARCH_PATH', spec['boost'].prefix),
'CGAL_ARCH_PATH': spec['cgal'].prefix, ('CGAL_ARCH_PATH', spec['cgal'].prefix),
}, ('LD_LIBRARY_PATH',
'FFTW': { foamAddLib(
'FFTW_ARCH_PATH': spec['fftw'].prefix, 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 # User-defined MPI
'mpi-user': [ 'mpi-user': [
('MPI_ARCH_PATH', spec['mpi'].prefix), # Absolute ('MPI_ARCH_PATH', spec['mpi'].prefix), # Absolute
('LD_LIBRARY_PATH', ('LD_LIBRARY_PATH', foamAddLib(user_mpi['libdir'])),
'"%s:${LD_LIBRARY_PATH}"' % content['libdir']), ('PATH', foamAddPath(user_mpi['bindir'])),
('PATH', '"%s:${PATH}"' % content['bindir']),
], ],
'scotch': {}, 'scotch': {},
'metis': {}, 'metis': {},
'paraview': [], 'paraview': [],
'gperftools': [], # Currently unused
} }
if '+scotch' in spec: if '+scotch' in spec:
@ -590,15 +478,15 @@ def configure(self, spec, prefix):
pvMajor = 'paraview-{0}'.format(spec['paraview'].version.up_to(2)) pvMajor = 'paraview-{0}'.format(spec['paraview'].version.up_to(2))
self.etc_config['paraview'] = [ self.etc_config['paraview'] = [
('ParaView_DIR', spec['paraview'].prefix), ('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), ('PV_PLUGIN_PATH', '$FOAM_LIBBIN/' + pvMajor),
('PATH', '"${ParaView_DIR}/bin:${PATH}"'), ('PATH', foamAddPath('${ParaView_DIR}/bin')),
] ]
# Not normally included as etc/config file # Optional
if '+parmgridgen' in spec: if '+mgridgen' in spec:
self.etc_config['parmgridgen'] = { self.etc_config['mgridgen'] = {
'PARMGRIDGEN_ARCH_PATH': spec['parmgridgen'].prefix 'MGRIDGEN_ARCH_PATH': spec['parmgridgen'].prefix
} }
# Optional # Optional
@ -622,45 +510,30 @@ def configure(self, spec, prefix):
posix=join_path('etc', 'config.sh', component), posix=join_path('etc', 'config.sh', component),
cshell=join_path('etc', 'config.csh', 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): def build(self, spec, prefix):
"""Build using the OpenFOAM Allwmake script, with a wrapper to source """Build using the OpenFOAM Allwmake script, with a wrapper to source
its environment first. 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'] args = ['-silent']
if self.parallel: # Build in parallel? - pass as an argument if self.parallel: # Build in parallel? - pass as an argument
args.append( args.append('-j{0}'.format(make_jobs))
'-j{0}'.format(str(self.make_jobs) if self.make_jobs else ''))
builder = Executable(self.build_script) builder = Executable(self.build_script)
builder(*args) builder(*args)
def install(self, spec, prefix): def install(self, spec, prefix):
"""Install under the projectdir (== prefix)""" """Install under the projectdir"""
self.build(spec, prefix) # Should be a separate phase
opts = self.wm_options
mkdirp(self.projectdir) mkdirp(self.projectdir)
projdir = os.path.basename(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_INST_DIR': os.path.dirname(self.projectdir),
'WM_PROJECT_DIR': join_path('$WM_PROJECT_INST_DIR', projdir), '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 # All top-level files, except spack build info and possibly Allwmake
if '+source' in spec: if '+source' in spec:
ignored = re.compile(r'^spack-.*') ignored = re.compile(r'^spack-.*')
@ -668,20 +541,23 @@ def install(self, spec, prefix):
ignored = re.compile(r'^(Allwmake|spack-).*') ignored = re.compile(r'^(Allwmake|spack-).*')
files = [ 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: for f in files:
install(f, self.projectdir) install(f, self.projectdir)
# Having wmake without sources is actually somewhat pointless... # Having wmake and ~source is actually somewhat pointless...
dirs = ['bin', 'etc', 'wmake'] # Install 'etc' before 'bin' (for symlinks)
dirs = ['etc', 'bin', 'wmake']
if '+source' in spec: if '+source' in spec:
dirs.extend(['applications', 'src', 'tutorials']) dirs.extend(['applications', 'src', 'tutorials'])
for d in dirs: for d in dirs:
install_tree( install_tree(
d, d,
join_path(self.projectdir, d)) join_path(self.projectdir, d),
symlinks=True)
dirs = ['platforms'] dirs = ['platforms']
if '+source' in spec: if '+source' in spec:
@ -693,30 +569,229 @@ def install(self, spec, prefix):
install_tree( install_tree(
d, d,
join_path(self.projectdir, 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 rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc
wm_setting, edits,
posix=join_path(self.etc, 'bashrc'), posix=join_path(etc_dir, 'bashrc'),
cshell=join_path(self.etc, 'cshrc')) cshell=join_path(etc_dir, 'cshrc'))
self.install_links() self.install_links()
def install_links(self): def install_links(self):
"""Add symlinks into bin/, lib/ (eg, for other applications)""" """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 return
# ln -s platforms/linux64GccXXX/lib lib # ln -s platforms/linux64GccXXX/lib lib
with working_dir(self.projectdir): with working_dir(self.projectdir):
if isdir(self.archlib): if os.path.isdir(self.archlib):
os.symlink(self.archlib, 'lib') os.symlink(self.archlib, 'lib')
# (cd bin && ln -s ../platforms/linux64GccXXX/bin/* .) # (cd bin && ln -s ../platforms/linux64GccXXX/bin/* .)
with working_dir(join_path(self.projectdir, 'bin')): with working_dir(join_path(self.projectdir, 'bin')):
for f in [ for f in [
f for f in glob.glob(join_path('..', self.archbin, "*")) 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)) 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))
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------

View File

@ -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
#------------------------------------------------------------------------------

View File

@ -6,7 +6,7 @@ diff -uw OpenFOAM-v1612+.orig/etc/config.sh/settings OpenFOAM-v1612+/etc/config.
# Location of the jobControl directory # Location of the jobControl directory
-export FOAM_JOB_DIR=$WM_PROJECT_INST_DIR/jobControl -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 # wmake configuration
export WM_DIR=$WM_PROJECT_DIR/wmake 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 # Site-specific directory
-siteDir="${WM_PROJECT_SITE:-$WM_PROJECT_INST_DIR/site}" -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 # Shared site executables/libraries
# Similar naming convention as ~OpenFOAM expansion # 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 # Location of the jobControl directory
-setenv FOAM_JOB_DIR $WM_PROJECT_INST_DIR/jobControl -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 # wmake configuration
setenv WM_DIR $WM_PROJECT_DIR/wmake setenv WM_DIR $WM_PROJECT_DIR/wmake

View File

@ -44,22 +44,23 @@
# entirely clear and thus untested. # entirely clear and thus untested.
# - Resolution of flex, zlib needs more attention (within OpenFOAM) # - Resolution of flex, zlib needs more attention (within OpenFOAM)
# #
# - mpi handling: WM_MPLIB=SYSTEMMPI and use spack to populate the prefs.sh # - mpi handling: WM_MPLIB=SYSTEMMPI and use spack to populate prefs.sh for it.
# for it. # Provide wmake rules for special purpose 'USER' and 'USERMPI'
# Also provide wmake rules for special purpose 'USER' and 'USERMPI'
# mpi implementations, in case these are required. # 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 import *
from spack.environment import * from spack.environment import *
import llnl.util.tty as tty import llnl.util.tty as tty
import multiprocessing
import glob import glob
import re import re
import shutil import shutil
import os import os
from os.path import isdir, isfile
from spack.pkg.builtin.openfoam_com import * from spack.pkg.builtin.openfoam_com import *
@ -78,19 +79,15 @@ class OpenfoamOrg(Package):
version('4.1', '318a446c4ae6366c7296b61184acd37c', version('4.1', '318a446c4ae6366c7296b61184acd37c',
url=baseurl + '/OpenFOAM-4.x/archive/version-4.1.tar.gz') 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, variant('int64', default=False,
description='Compile with 64-bit labels') description='Compile with 64-bit label')
variant('float32', default=False, variant('float32', default=False,
description='Compile with 32-bit scalar (single-precision)') description='Compile with 32-bit scalar (single-precision)')
variant('source', default=True, variant('source', default=True,
description='Install library/application sources and tutorials') 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') provides('openfoam')
depends_on('mpi') depends_on('mpi')
depends_on('zlib') depends_on('zlib')
@ -98,31 +95,26 @@ class OpenfoamOrg(Package):
depends_on('cmake', type='build') depends_on('cmake', type='build')
# Require scotch with ptscotch - corresponds to standard OpenFOAM setup # Require scotch with ptscotch - corresponds to standard OpenFOAM setup
depends_on('scotch~int64+mpi', when='~int64') depends_on('scotch~metis+mpi~int64', when='~int64')
depends_on('scotch+int64+mpi', when='+int64') depends_on('scotch~metis+mpi+int64', when='+int64')
# General patches # General patches - foamEtcFile as per openfoam.com (robuster)
patch('openfoam-site.patch') common = ['spack-Allwmake', 'README-spack']
assets = ['bin/foamEtcFile']
# Version-specific patches # 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 # Some user config settings
foam_cfg = { config = {
'WM_COMPILER': 'Gcc', # <- %compiler 'mplib': 'SYSTEMMPI', # Use system mpi for spack
'WM_ARCH_OPTION': '64', # (32/64-bit on x86_64) # Add links into bin/, lib/ (eg, for other applications)
'WM_LABEL_SIZE': '32', # <- +int64 'link': False
'WM_PRECISION_OPTION': 'DP', # <- +float32
'WM_COMPILE_OPTION': 'SPACKOpt', # Do not change
'WM_MPLIB': 'SYSTEMMPI', # Use system mpi for spack
} }
# The system description is frequently needed # The openfoam architecture, compiler information etc
foam_sys = { _foam_arch = None
'WM_ARCH': None,
'WM_COMPILER': None,
'WM_OPTIONS': None,
}
# Content for etc/prefs.{csh,sh} # Content for etc/prefs.{csh,sh}
etc_prefs = {} etc_prefs = {}
@ -130,236 +122,111 @@ class OpenfoamOrg(Package):
# Content for etc/config.{csh,sh}/ files # Content for etc/config.{csh,sh}/ files
etc_config = {} etc_config = {}
build_script = './spack-Allwmake' # <- Generated by patch() method. phases = ['configure', 'build', 'install']
# phases = ['configure', 'build', 'install'] build_script = './spack-Allwmake' # <- Added by patch() method.
# build_system_class = 'OpenfoamCom'
# Add symlinks into bin/, lib/ (eg, for other applications) #
extra_symlinks = False # - End of definitions / setup -
#
def setup_environment(self, spack_env, run_env): def setup_environment(self, spack_env, run_env):
run_env.set('FOAM_PROJECT_DIR', self.projectdir)
run_env.set('WM_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 setup_dependent_environment(self, spack_env, run_env, dependent_spec):
def _canonical(self): """Provide location of the OpenFOAM project.
"""Canonical name for this package and version""" This is identical to the WM_PROJECT_DIR value, but we avoid that
return 'OpenFOAM-{0}'.format(self.version) variable since it would mask the normal OpenFOAM cleanup of
previous versions.
"""
spack_env.set('FOAM_PROJECT_DIR', self.projectdir)
@property @property
def projectdir(self): def projectdir(self):
"""Absolute location of project directory: WM_PROJECT_DIR/""" """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 @property
def etc(self): def foam_arch(self):
"""Absolute location of the OpenFOAM etc/ directory""" if not self._foam_arch:
return join_path(self.projectdir, 'etc') self._foam_arch = OpenfoamArch(self.spec, **self.config)
return self._foam_arch
@property @property
def archbin(self): def archbin(self):
"""Relative location of architecture-specific executables""" """Relative location of architecture-specific executables"""
return join_path('platforms', self.wm_options, 'bin') return join_path('platforms', self.foam_arch, 'bin')
@property @property
def archlib(self): def archlib(self):
"""Relative location of architecture-specific libraries""" """Relative location of architecture-specific libraries"""
return join_path('platforms', self.wm_options, 'lib') return join_path('platforms', self.foam_arch, 'lib')
@property def rename_source(self):
def wm_options(self): """This is fairly horrible.
"""The architecture+compiler+options for OpenFOAM""" The github tarfiles have weird names that do not correspond to the
opts = self.set_openfoam() canonical name. We need to rename these, but leave a symlink for
return opts spack to work with.
@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) # Note that this particular OpenFOAM requires absolute directories
install_libpath = join_path(self.projectdir, self.archlib) # to build correctly!
# '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!
parent = os.path.dirname(self.stage.source_path) parent = os.path.dirname(self.stage.source_path)
original = os.path.basename(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): with working_dir(parent):
if original != target and not os.path.lexists(target): if original != target and not os.path.lexists(target):
os.rename(original, target) os.rename(original, target)
os.symlink(target, original) os.symlink(target, original)
tty.info('renamed {0} -> {1}'.format(original, target)) 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. # Avoid WM_PROJECT_INST_DIR for ThirdParty, site or jobControl.
# Use openfoam-site.patch to handle jobControl, site. # Use openfoam-site.patch to handle jobControl, site.
# #
# Filter (not patch) bashrc,cshrc for additional flexibility # Filtering: bashrc,cshrc (using a patch is less flexible)
wm_setting = { edits = {
'WM_THIRD_PARTY_DIR': 'WM_THIRD_PARTY_DIR':
r'$WM_PROJECT_DIR/ThirdParty #SPACK: No separate third-party', r'$WM_PROJECT_DIR/ThirdParty #SPACK: No separate third-party',
'WM_VERSION': self.version, # consistency 'WM_VERSION': self.version, # consistency
'FOAMY_HEX_MESH': '', # This is horrible (unset variable?) 'FOAMY_HEX_MESH': '', # This is horrible (unset variable?)
} }
rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc
wm_setting, edits,
posix=join_path('etc', 'bashrc'), posix=join_path('etc', 'bashrc'),
cshell=join_path('etc', 'cshrc')) 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): def configure(self, spec, prefix):
"""Make adjustments to the OpenFOAM configuration files in their various """Make adjustments to the OpenFOAM configuration files in their various
locations: etc/bashrc, etc/config.sh/FEATURE and customizations that locations: etc/bashrc, etc/config.sh/FEATURE and customizations that
don't properly fit get placed in the etc/prefs.sh file (similiarly for don't properly fit get placed in the etc/prefs.sh file (similiarly for
csh). csh).
""" """
self.set_openfoam() # Need foam_cfg/foam_sys information # Filtering bashrc, cshrc
edits = {}
# Some settings for filtering bashrc, cshrc edits.update(self.foam_arch.foam_dict())
wm_setting = {}
wm_setting.update(self.foam_cfg)
rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc
wm_setting, edits,
posix=join_path('etc', 'bashrc'), posix=join_path('etc', 'bashrc'),
cshell=join_path('etc', 'cshrc')) cshell=join_path('etc', 'cshrc'))
# MPI content, with absolute paths # MPI content, with absolute paths
content = mplib_content(spec) user_mpi = mplib_content(spec)
# Content for etc/prefs.{csh,sh} # Content for etc/prefs.{csh,sh}
self.etc_prefs = { self.etc_prefs = {
r'MPI_ROOT': spec['mpi'].prefix, # Absolute r'MPI_ROOT': spec['mpi'].prefix, # Absolute
r'MPI_ARCH_FLAGS': '"%s"' % content['FLAGS'], r'MPI_ARCH_FLAGS': '"%s"' % user_mpi['FLAGS'],
r'MPI_ARCH_INC': '"%s"' % content['PINC'], r'MPI_ARCH_INC': '"%s"' % user_mpi['PINC'],
r'MPI_ARCH_LIBS': '"%s"' % content['PLIBS'], r'MPI_ARCH_LIBS': '"%s"' % user_mpi['PLIBS'],
} }
# Content for etc/config.{csh,sh}/ files # Content for etc/config.{csh,sh}/ files
@ -368,6 +235,7 @@ def configure(self, spec, prefix):
'scotch': {}, 'scotch': {},
'metis': {}, 'metis': {},
'paraview': [], 'paraview': [],
'gperftools': [], # Currently unused
} }
if True: if True:
@ -392,45 +260,30 @@ def configure(self, spec, prefix):
posix=join_path('etc', 'config.sh', component), posix=join_path('etc', 'config.sh', component),
cshell=join_path('etc', 'config.csh', 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): def build(self, spec, prefix):
"""Build using the OpenFOAM Allwmake script, with a wrapper to source """Build using the OpenFOAM Allwmake script, with a wrapper to source
its environment first. 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 = [] args = []
if self.parallel: # Build in parallel? - pass via the environment if self.parallel: # Build in parallel? - pass via the environment
os.environ['WM_NCOMPPROCS'] = str(self.make_jobs) \ os.environ['WM_NCOMPPROCS'] = str(make_jobs)
if self.make_jobs else str(multiprocessing.cpu_count())
builder = Executable(self.build_script) builder = Executable(self.build_script)
builder(*args) builder(*args)
def install(self, spec, prefix): def install(self, spec, prefix):
"""Install under the projectdir (== prefix/name-version)""" """Install under the projectdir"""
self.build(spec, prefix) # Should be a separate phase
opts = self.wm_options
mkdirp(self.projectdir) mkdirp(self.projectdir)
projdir = os.path.basename(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_INST_DIR': os.path.dirname(self.projectdir),
'WM_PROJECT_DIR': join_path('$WM_PROJECT_INST_DIR', projdir), '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 # All top-level files, except spack build info and possibly Allwmake
if '+source' in spec: if '+source' in spec:
ignored = re.compile(r'^spack-.*') ignored = re.compile(r'^spack-.*')
@ -438,20 +291,23 @@ def install(self, spec, prefix):
ignored = re.compile(r'^(Allwmake|spack-).*') ignored = re.compile(r'^(Allwmake|spack-).*')
files = [ 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: for f in files:
install(f, self.projectdir) install(f, self.projectdir)
# Having wmake without sources is actually somewhat pointless... # Having wmake and ~source is actually somewhat pointless...
dirs = ['bin', 'etc', 'wmake'] # Install 'etc' before 'bin' (for symlinks)
dirs = ['etc', 'bin', 'wmake']
if '+source' in spec: if '+source' in spec:
dirs.extend(['applications', 'src', 'tutorials']) dirs.extend(['applications', 'src', 'tutorials'])
for d in dirs: for d in dirs:
install_tree( install_tree(
d, d,
join_path(self.projectdir, d)) join_path(self.projectdir, d),
symlinks=True)
dirs = ['platforms'] dirs = ['platforms']
if '+source' in spec: if '+source' in spec:
@ -463,29 +319,37 @@ def install(self, spec, prefix):
install_tree( install_tree(
d, d,
join_path(self.projectdir, 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 rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc
wm_setting, edits,
posix=join_path(self.etc, 'bashrc'), posix=join_path(etc_dir, 'bashrc'),
cshell=join_path(self.etc, 'cshrc')) cshell=join_path(etc_dir, 'cshrc'))
self.install_links() self.install_links()
def install_links(self): def install_links(self):
"""Add symlinks into bin/, lib/ (eg, for other applications)""" """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 return
# ln -s platforms/linux64GccXXX/lib lib # ln -s platforms/linux64GccXXX/lib lib
with working_dir(self.projectdir): with working_dir(self.projectdir):
if isdir(self.archlib): if os.path.isdir(self.archlib):
os.symlink(self.archlib, 'lib') os.symlink(self.archlib, 'lib')
# (cd bin && ln -s ../platforms/linux64GccXXX/bin/* .) # (cd bin && ln -s ../platforms/linux64GccXXX/bin/* .)
with working_dir(join_path(self.projectdir, 'bin')): with working_dir(join_path(self.projectdir, 'bin')):
for f in [ for f in [
f for f in glob.glob(join_path('..', self.archbin, "*")) 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)) os.symlink(f, os.path.basename(f))