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]
mpi: [openmpi, mpich]
opencl: [pocl]
openfoam: [foam-extend]
openfoam: [openfoam-com, openfoam-org, foam-extend]
pil: [py-pillow]
scalapack: [netlib-scalapack]

View File

@ -48,16 +48,17 @@
# - reworked to mirror the openfoam-com package.
# If changes are needed here, consider if they need applying there too.
#
# Known issues
# - Combining +parmgridgen with +float32 probably won't work.
#
##############################################################################
from spack import *
from spack.environment import *
import multiprocessing
import glob
import re
import shutil
import os
from os.path import isdir, isfile
from spack.pkg.builtin.openfoam_com import *
@ -77,10 +78,9 @@ class FoamExtend(Package):
version('3.0', git='http://git.code.sf.net/p/foam-extend/foam-extend-3.0')
# variant('int64', default=False,
# description='Compile with 64-bit labels')
# description='Compile with 64-bit label')
variant('float32', default=False,
description='Compile with 32-bit scalar (single-precision)')
variant('paraview', default=False,
description='Build paraview plugins (eg, paraFoam)')
variant('scotch', default=True,
@ -96,10 +96,6 @@ class FoamExtend(Package):
variant('source', default=True,
description='Install library/application sources and tutorials')
#: Map spack compiler names to OpenFOAM compiler names
# By default, simply capitalize the first letter
compiler_mapping = {'intel': 'icc'}
provides('openfoam')
depends_on('mpi')
depends_on('python')
@ -111,25 +107,22 @@ class FoamExtend(Package):
depends_on('scotch~metis+mpi', when='+ptscotch')
depends_on('metis@5:', when='+metis')
depends_on('parmetis', when='+parmetis')
depends_on('parmgridgen', when='+parmgridgen')
# mgridgen is statically linked
depends_on('parmgridgen', when='+parmgridgen', type='build')
depends_on('paraview@:5.0.1', when='+paraview')
# Some user settings, to be adjusted manually or via variants
foam_cfg = {
'WM_COMPILER': 'Gcc', # <- %compiler
'WM_ARCH_OPTION': '64', # (32/64-bit on x86_64)
# FUTURE? 'WM_LABEL_SIZE': '32', # <- +int64
'WM_PRECISION_OPTION': 'DP', # <- +float32
'WM_COMPILE_OPTION': 'SPACKOpt', # Do not change
'WM_MPLIB': 'USER', # USER | USERMPI
# General patches
common = ['spack-Allwmake', 'README-spack']
assets = []
# Some user config settings
config = {
'label-size': False, # <- No int32/int64 support
'mplib': 'USERMPI', # USER | USERMPI
}
# The system description is frequently needed
foam_sys = {
'WM_ARCH': None,
'WM_COMPILER': None,
'WM_OPTIONS': None,
}
# The openfoam architecture, compiler information etc
_foam_arch = None
# Content for etc/prefs.{csh,sh}
etc_prefs = {}
@ -137,163 +130,54 @@ class FoamExtend(Package):
# Content for etc/config.{csh,sh}/ files
etc_config = {}
build_script = './spack-Allwmake' # <- Generated by patch() method.
# phases = ['configure', 'build', 'install']
# build_system_class = 'OpenfoamCom'
phases = ['configure', 'build', 'install']
build_script = './spack-Allwmake' # <- Added by patch() method.
#
# - End of definitions / setup -
#
def setup_environment(self, spack_env, run_env):
run_env.set('FOAM_INST_DIR', self.prefix)
run_env.set('FOAM_INST_DIR', os.path.dirname(self.projectdir)),
run_env.set('FOAM_PROJECT_DIR', self.projectdir)
run_env.set('WM_PROJECT_DIR', self.projectdir)
for d in ['wmake', self.archbin]: # bin already added automatically
run_env.prepend_path('PATH', join_path(self.projectdir, d))
run_env.set('MPI_BUFFER_SIZE', "20000000")
@property
def _canonical(self):
"""Canonical name for this package and version"""
return 'foam-extend-{0}'.format(self.version.up_to(2))
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
"""Provide location of the OpenFOAM project.
This is identical to the WM_PROJECT_DIR value, but we avoid that
variable since it would mask the normal OpenFOAM cleanup of
previous versions.
"""
spack_env.set('FOAM_PROJECT_DIR', self.projectdir)
@property
def projectdir(self):
"""Absolute location of project directory: WM_PROJECT_DIR/"""
return join_path(self.prefix, self._canonical) # <- prefix/canonical
return self.prefix # <- install directly under prefix
@property
def etc(self):
"""Absolute location of the OpenFOAM etc/ directory"""
return join_path(self.projectdir, 'etc')
def foam_arch(self):
if not self._foam_arch:
self._foam_arch = OpenfoamArch(self.spec, **self.config)
return self._foam_arch
@property
def archbin(self):
"""Relative location of architecture-specific executables"""
wm_options = self.set_openfoam()
return join_path('applications', 'bin', wm_options)
return join_path('applications', 'bin', self.foam_arch)
@property
def archlib(self):
"""Relative location of architecture-specific libraries"""
wm_options = self.set_openfoam()
return join_path('lib', wm_options)
@property
def wm_options(self):
"""The architecture+compiler+options for OpenFOAM"""
opts = self.set_openfoam()
return opts
@property
def rpath_info(self):
"""Define 'SPACKOpt' compiler optimization file to have wmake
use spack information with minimum modifications to OpenFOAM
"""
build_libpath = join_path(self.stage.source_path, self.archlib)
install_libpath = join_path(self.projectdir, self.archlib)
# 'DBUG': rpaths
return '{0}{1} {2}{3}'.format(
self.compiler.cxx_rpath_arg, install_libpath,
self.compiler.cxx_rpath_arg, build_libpath)
def openfoam_arch(self):
"""Return an architecture value similar to what OpenFOAM does in
etc/config.sh/settings, but slightly more generous.
Uses and may adjust foam_cfg[WM_ARCH_OPTION] as a side-effect
"""
# spec.architecture.platform is like `uname -s`, but lower-case
platform = self.spec.architecture.platform
# spec.architecture.target is like `uname -m`
target = self.spec.architecture.target
if platform == 'linux':
if target == 'i686':
self.foam_cfg['WM_ARCH_OPTION'] = '32' # Force consistency
elif target == 'x86_64':
if self.foam_cfg['WM_ARCH_OPTION'] == '64':
platform += '64'
elif target == 'ia64':
platform += 'ia64'
elif target == 'armv7l':
platform += 'ARM7'
elif target == ppc64:
platform += 'PPC64'
elif target == ppc64le:
platform += 'PPC64le'
elif platform == 'darwin':
if target == 'x86_64':
platform += 'Intel'
if self.foam_cfg['WM_ARCH_OPTION'] == '64':
platform += '64'
# ... and others?
return platform
def openfoam_compiler(self):
"""Capitalized version of the compiler name, which usually corresponds
to how OpenFOAM will camel-case things.
Use compiler_mapping to handing special cases.
Also handle special compiler options (eg, KNL)
"""
comp = self.compiler.name
if comp in self.compiler_mapping:
comp = self.compiler_mapping[comp]
comp = comp.capitalize()
if '+knl' in self.spec:
comp += 'KNL'
return comp
# For foam-extend: does not yet support +int64
def set_openfoam(self):
"""Populate foam_cfg, foam_sys according to
variants, architecture, compiler.
Returns WM_OPTIONS.
"""
# Run once
opts = self.foam_sys['WM_OPTIONS']
if opts:
return opts
wm_arch = self.openfoam_arch()
wm_compiler = self.openfoam_compiler()
compileOpt = self.foam_cfg['WM_COMPILE_OPTION']
# Insist on a wmake rule for this architecture/compiler combination
archCompiler = wm_arch + wm_compiler
compiler_rule = join_path(
self.stage.source_path, 'wmake', 'rules', archCompiler)
if not isdir(compiler_rule):
raise RuntimeError(
'No wmake rule for {0}'.format(archCompiler))
if not re.match(r'.+Opt$', compileOpt):
raise RuntimeError(
"WM_COMPILE_OPTION={0} is not type '*Opt'".format(compileOpt))
# Adjust for variants
# FUTURE? self.foam_cfg['WM_LABEL_SIZE'] = (
# FUTURE? '64' if '+int64' in self.spec else '32'
# FUTURE? )
self.foam_cfg['WM_PRECISION_OPTION'] = (
'SP' if '+float32' in self.spec else 'DP'
)
# ----
# WM_OPTIONS=$WM_ARCH$WM_COMPILER$WM_PRECISION_OPTION$WM_COMPILE_OPTION
# ----
self.foam_sys['WM_ARCH'] = wm_arch
self.foam_sys['WM_COMPILER'] = wm_compiler
self.foam_cfg['WM_COMPILER'] = wm_compiler # For bashrc,cshrc too
self.foam_sys['WM_OPTIONS'] = ''.join([
wm_arch,
wm_compiler,
self.foam_cfg['WM_PRECISION_OPTION'],
# FUTURE? 'Int', self.foam_cfg['WM_LABEL_SIZE'], # Int32/Int64
compileOpt
])
return self.foam_sys['WM_OPTIONS']
return join_path('lib', self.foam_arch)
def patch(self):
"""Adjust OpenFOAM build for spack. Where needed, apply filter as an
alternative to normal patching.
"""
self.set_openfoam() # May need foam_cfg/foam_sys information
"""Adjust OpenFOAM build for spack.
Where needed, apply filter as an alternative to normal patching."""
add_extra_files(self, self.common, self.assets)
# Adjust ParMGridGen - this is still a mess
files = [
@ -319,23 +203,7 @@ def patch(self):
filter_file(
r'#if YY_FLEX_SUBMINOR_VERSION < 34',
r'#if YY_FLEX_MAJOR_VERSION <= 2 && YY_FLEX_MINOR_VERSION <= 5 && YY_FLEX_SUBMINOR_VERSION < 34', # noqa: E501
f, backup=False
)
# Build wrapper script
with open(self.build_script, 'w') as out:
out.write(
"""#!/bin/bash
export FOAM_INST_DIR=$(cd .. && pwd -L)
. $PWD/etc/bashrc '' # No arguments
mkdir -p $FOAM_APPBIN $FOAM_LIBBIN 2>/dev/null # Allow interrupt
echo Build openfoam with SPACK
echo WM_PROJECT_DIR = $WM_PROJECT_DIR
./Allwmake # No arguments
#
""")
set_executable(self.build_script)
self.configure(self.spec, self.prefix) # Should be a separate phase
f, backup=False)
def configure(self, spec, prefix):
"""Make adjustments to the OpenFOAM configuration files in their various
@ -343,8 +211,6 @@ def configure(self, spec, prefix):
don't properly fit get placed in the etc/prefs.sh file (similiarly for
csh).
"""
self.set_openfoam() # Need foam_cfg/foam_sys information
# Content for etc/prefs.{csh,sh}
self.etc_prefs = {
'000': { # Sort first
@ -373,7 +239,7 @@ def configure(self, spec, prefix):
},
}
# Adjust configuration via prefs - sort second
self.etc_prefs['001'].update(self.foam_cfg)
self.etc_prefs['001'].update(self.foam_arch.foam_dict())
if '+scotch' in spec or '+ptscotch' in spec:
pkg = spec['scotch'].prefix
@ -434,41 +300,33 @@ def configure(self, spec, prefix):
posix=join_path('etc', 'prefs.sh'),
cshell=join_path('etc', 'prefs.csh'))
archCompiler = self.foam_sys['WM_ARCH'] + self.foam_sys['WM_COMPILER']
compileOpt = self.foam_cfg['WM_COMPILE_OPTION']
# general_rule = join_path('wmake', 'rules', 'General')
compiler_rule = join_path('wmake', 'rules', archCompiler)
generate_mplib_rules(compiler_rule, self.spec)
generate_compiler_rules(compiler_rule, compileOpt, self.rpath_info)
# Record the spack spec information
with open("log.spack-spec", 'w') as outfile:
outfile.write(spec.tree())
def build(self, spec, prefix):
"""Build using the OpenFOAM Allwmake script, with a wrapper to source
its environment first.
Only build if the compiler is known to be supported.
"""
self.set_openfoam() # Force proper population of foam_cfg/foam_sys
self.foam_arch.has_rule(self.stage.source_path)
self.foam_arch.create_rules(self.stage.source_path, self)
args = []
if self.parallel: # Build in parallel? - pass via the environment
os.environ['WM_NCOMPPROCS'] = str(self.make_jobs) \
if self.make_jobs else str(multiprocessing.cpu_count())
os.environ['WM_NCOMPPROCS'] = str(make_jobs)
builder = Executable(self.build_script)
builder(*args)
def install(self, spec, prefix):
"""Install under the projectdir (== prefix/name-version)"""
self.build(spec, prefix) # Should be a separate phase
opts = self.wm_options
"""Install under the projectdir"""
opts = str(self.foam_arch)
# Fairly ugly since intermediate targets are scattered inside sources
appdir = 'applications'
projdir = os.path.basename(self.projectdir)
mkdirp(self.projectdir, join_path(self.projectdir, appdir))
# Retain build log file
out = "spack-build.out"
if isfile(out):
install(out, join_path(self.projectdir, "log." + opts))
# Filtering: bashrc, cshrc
edits = {
'WM_PROJECT_INST_DIR': os.path.dirname(self.projectdir),
'WM_PROJECT_DIR': join_path('$WM_PROJECT_INST_DIR', projdir),
}
# All top-level files, except spack build info and possibly Allwmake
if '+source' in spec:
@ -477,36 +335,52 @@ def install(self, spec, prefix):
ignored = re.compile(r'^(Allclean|Allwmake|spack-).*')
files = [
f for f in glob.glob("*") if isfile(f) and not ignored.search(f)
f for f in glob.glob("*")
if os.path.isfile(f) and not ignored.search(f)
]
for f in files:
install(f, self.projectdir)
# Install directories. install applications/bin directly
for d in ['bin', 'etc', 'wmake', 'lib', join_path(appdir, 'bin')]:
# Install 'etc' before 'bin' (for symlinks)
for d in ['etc', 'bin', 'wmake', 'lib', join_path(appdir, 'bin')]:
install_tree(
d,
join_path(self.projectdir, d))
join_path(self.projectdir, d),
symlinks=True)
if '+source' in spec:
subitem = join_path(appdir, 'Allwmake')
install(subitem, join_path(self.projectdir, subitem))
ignored = [opts] # Intermediate targets
ignored = [opts] # Ignore intermediate targets
for d in ['src', 'tutorials']:
install_tree(
d,
join_path(self.projectdir, d),
ignore=shutil.ignore_patterns(*ignored))
ignore=shutil.ignore_patterns(*ignored),
symlinks=True)
for d in ['solvers', 'utilities']:
install_tree(
join_path(appdir, d),
join_path(self.projectdir, appdir, d),
ignore=shutil.ignore_patterns(*ignored))
ignore=shutil.ignore_patterns(*ignored),
symlinks=True)
etc_dir = join_path(self.projectdir, 'etc')
rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc
edits,
posix=join_path(etc_dir, 'bashrc'),
cshell=join_path(etc_dir, 'cshrc'))
self.install_links()
def install_links(self):
"""Add symlinks into bin/, lib/ (eg, for other applications)"""
return
# Make build log visible - it contains OpenFOAM-specific information
with working_dir(self.projectdir):
os.symlink(
join_path('.spack', 'build.out'),
join_path('log.' + str(self.foam_arch)))
# -----------------------------------------------------------------------------

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

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
# in ~/.spack/packages.yaml
#
# Known issues
# - Combining +zoltan with +int64 has not been tested, but probably won't work.
# - Combining +mgridgen with +int64 or +float32 probably won't work.
#
##############################################################################
from spack import *
from spack.environment import *
import llnl.util.tty as tty
import glob
import re
import shutil
import os
from os.path import isdir, isfile
# Not the nice way of doing things, but is a start for refactoring
__all__ = [
'format_export',
'format_setenv',
'add_extra_files',
'write_environ',
'rewrite_environ_files',
'mplib_content',
'generate_mplib_rules',
'generate_compiler_rules',
'foamAddPath',
'foamAddLib',
'OpenfoamArch',
]
def add_extra_files(foam_pkg, common, local, **kwargs):
"""Copy additional common and local files into the stage.source_path
from the openfoam-com/common and the package/assets directories,
respectively
"""
outdir = foam_pkg.stage.source_path
indir = join_path(os.path.dirname(__file__), 'common')
for f in common:
tty.info('Added file {0}'.format(f))
install(join_path(indir, f), join_path(outdir, f))
indir = join_path(foam_pkg.package_dir, 'assets')
for f in local:
tty.info('Added file {0}'.format(f))
install(join_path(indir, f), join_path(outdir, f))
def format_export(key, value):
"""Format key,value pair as 'export' with newline for POSIX shell."""
return 'export {0}={1}\n'.format(key, value)
"""Format key,value pair as 'export' with newline for POSIX shell.
A leading '#' for key adds a comment character to the entire line.
A value of 'None' corresponds to 'unset'.
"""
if key.startswith('#'):
return '## export {0}={1}\n'.format(re.sub(r'^#+\s*', '', key), value)
elif value is None:
return 'unset {0}\n'.format(key)
else:
return 'export {0}={1}\n'.format(key, value)
def format_setenv(key, value):
"""Format key,value pair as 'setenv' with newline for C-shell."""
return 'setenv {0} {1}\n'.format(key, value)
"""Format key,value pair as 'setenv' with newline for C-shell.
A leading '#' for key adds a comment character to the entire line.
A value of 'None' corresponds to 'unsetenv'.
"""
if key.startswith('#'):
return '## setenv {0} {1}\n'.format(re.sub(r'^#+\s*', '', key), value)
elif value is None:
return 'unsetenv {0}\n'.format(key)
else:
return 'setenv {0} {1}\n'.format(key, value)
def _write_environ_entries(outfile, environ, formatter):
@ -139,7 +175,7 @@ def rewrite_environ_files(environ, **kwargs):
cshell[=None] If set, the name of the C-shell file to rewrite.
"""
posix = kwargs.get('posix', None)
if posix and isfile(posix):
if posix and os.path.isfile(posix):
for k, v in environ.items():
filter_file(
r'^(\s*export\s+%s)=.*$' % k,
@ -147,7 +183,7 @@ def rewrite_environ_files(environ, **kwargs):
posix,
backup=False)
cshell = kwargs.get('cshell', None)
if cshell and isfile(cshell):
if cshell and os.path.isfile(cshell):
for k, v in environ.items():
filter_file(
r'^(\s*setenv\s+%s)\s+.*$' % k,
@ -156,19 +192,35 @@ def rewrite_environ_files(environ, **kwargs):
backup=False)
def pkglib(package):
"""Get lib64 or lib from package prefix"""
def foamAddPath(*args):
"""A string with args prepended to 'PATH'"""
return '"' + ':'.join(args) + ':${PATH}"'
def foamAddLib(*args):
"""A string with args prepended to 'LD_LIBRARY_PATH'"""
return '"' + ':'.join(args) + ':${LD_LIBRARY_PATH}"'
def pkglib(package, pre=None):
"""Get lib64 or lib from package prefix.
Optional parameter 'pre' to provide alternative prefix
"""
libdir = package.prefix.lib64
if isdir(libdir):
if not os.path.isdir(libdir):
libdir = package.prefix.lib
if pre:
return join_path(pre, os.path.basename(libdir))
else:
return libdir
return package.prefix.lib
def mplib_content(spec, pre=None):
"""The mpi settings to have wmake
use spack information with minimum modifications to OpenFOAM.
Optional parameter 'pre' to provid alternative prefix
Optional parameter 'pre' to provide alternative prefix
"""
mpi_spec = spec['mpi']
bin = mpi_spec.prefix.bin
@ -194,36 +246,7 @@ def mplib_content(spec, pre=None):
return info
def generate_mplib_rules(directory, spec):
""" Create mplibUSER,mplibUSERMPI rules in the specified directory"""
content = mplib_content(spec)
with working_dir(directory):
for mplib in ['mplibUSER', 'mplibUSERMPI']:
with open(mplib, 'w') as out:
out.write("""# Use mpi from spack ({name})\n
PFLAGS = {FLAGS}
PINC = {PINC}
PLIBS = {PLIBS}
""".format(**content))
def generate_compiler_rules(directory, compOpt, value):
""" Create cSPACKOpt,c++SPACKOpt rules in the specified directory.
The file content is copied and filtered from the corresponding
cOpt,c++Opt rules"""
# Compiler options for SPACK - eg, wmake/rules/linux64Gcc/
# Copy from existing cOpt, c++Opt and modify DBUG value
with working_dir(directory):
for lang in ['c', 'c++']:
src = '{0}Opt'.format(lang)
dst = '{0}{1}'.format(lang, compOpt)
shutil.copyfile(src, dst) # src -> dst
filter_file(
r'^(\S+DBUG\s*)=.*$',
r'\1= %s' % value,
dst,
backup=False)
# -----------------------------------------------------------------------------
class OpenfoamCom(Package):
"""OpenFOAM is a GPL-opensource C++ CFD-toolbox.
@ -239,31 +262,28 @@ class OpenfoamCom(Package):
version('1612', 'ca02c491369150ab127cbb88ec60fbdf',
url=baseurl + '/v1612+/OpenFOAM-v1612+.tgz')
version('plus', branch='develop', # Note: needs user credentials
git='https://develop.openfoam.com/Development/OpenFOAM-plus.git')
variant('int64', default=False,
description='Compile with 64-bit labels')
description='Compile with 64-bit label')
variant('float32', default=False,
description='Compile with 32-bit scalar (single-precision)')
variant('knl', default=False,
description='Use KNL compiler settings')
variant('scotch', default=True,
description='With scotch/ptscotch for decomposition')
variant('metis', default=False,
description='With metis for decomposition')
variant('zoltan', default=False,
description='With zoltan renumbering')
# TODO?# variant('parmgridgen', default=True,
# TODO?# description='With parmgridgen support')
variant('source', default=True,
description='Install library/application sources and tutorials')
# TODO?# variant('scalasca', default=False,
# TODO?# description='With scalasca profiling')
variant('mgridgen', default=False, description='With mgridgen support')
variant('paraview', default=True,
description='Build paraview plugins and runtime post-processing')
#: Map spack compiler names to OpenFOAM compiler names
# By default, simply capitalize the first letter
compiler_mapping = {'intel': 'icc'}
variant('source', default=True,
description='Install library/application sources and tutorials')
provides('openfoam')
depends_on('mpi')
@ -275,12 +295,14 @@ class OpenfoamCom(Package):
depends_on('cmake', type='build')
# Require scotch with ptscotch - corresponds to standard OpenFOAM setup
depends_on('scotch~int64+mpi', when='+scotch~int64')
depends_on('scotch+int64+mpi', when='+scotch+int64')
depends_on('scotch~metis+mpi~int64', when='+scotch~int64')
depends_on('scotch~metis+mpi+int64', when='+scotch+int64')
depends_on('metis@5:', when='+metis')
depends_on('metis+int64', when='+metis+int64')
depends_on('parmgridgen', when='+parmgridgen')
# mgridgen is statically linked
depends_on('parmgridgen', when='+mgridgen', type='build')
depends_on('zoltan', when='+zoltan')
# TODO?# depends_on('scalasca', when='+scalasca')
# For OpenFOAM plugins and run-time post-processing this should just be
# 'paraview+plugins' but that resolves poorly.
@ -289,36 +311,36 @@ class OpenfoamCom(Package):
# 1612 plugins need older paraview
# The native reader in paraview 5.2 is broken, so start after that
depends_on('paraview@:5.0.1', when='@:1612+paraview')
depends_on('paraview@:5.0.1', when='@1612+paraview')
depends_on('paraview@5.3:', when='@1706:+paraview')
depends_on('paraview@5.3:', when='@plus+paraview')
# General patches
patch('openfoam-site.patch')
common = ['spack-Allwmake', 'README-spack']
assets = []
# Version-specific patches
patch('openfoam-bin-1612.patch', when='@1612')
patch('openfoam-etc-1612.patch', when='@1612')
patch('openfoam-site-1612.patch', when='@1612')
patch('openfoam-mpi-1612.patch', when='@1612')
patch('openfoam-build-1612.patch', when='@1612')
patch('mgridgen-lib-1612.patch', when='@1612')
patch('scotch-metis-lib-1612.patch', when='@1612')
patch('zoltan-lib-1612.patch', when='@1612')
# Some user settings, to be adjusted manually or via variants
foam_cfg = {
'WM_COMPILER': 'Gcc', # <- %compiler
'WM_ARCH_OPTION': '64', # (32/64-bit on x86_64)
'WM_LABEL_SIZE': '32', # <- +int64
'WM_PRECISION_OPTION': 'DP', # <- +float32
'WM_COMPILE_OPTION': 'SPACKOpt', # Do not change
'WM_MPLIB': 'USERMPI', # Use user mpi for spack
patch('openfoam-site-plus.patch', when='@plus')
# Some user config settings
# default: 'compile-option': 'RpathOpt',
# default: 'mplib': 'USERMPI', # Use user mpi for spack
config = {
# Add links into bin/, lib/ (eg, for other applications)
'link': False
}
# The system description is frequently needed
foam_sys = {
'WM_ARCH': None,
'WM_COMPILER': None,
'WM_OPTIONS': None,
}
# The openfoam architecture, compiler information etc
_foam_arch = None
# Content for etc/prefs.{csh,sh}
etc_prefs = {}
@ -326,23 +348,27 @@ class OpenfoamCom(Package):
# Content for etc/config.{csh,sh}/ files
etc_config = {}
build_script = './spack-Allwmake' # <- Generated by patch() method.
# phases = ['configure', 'build', 'install']
# build_system_class = 'OpenfoamCom'
phases = ['configure', 'build', 'install']
build_script = './spack-Allwmake' # <- Added by patch() method.
# Add symlinks into bin/, lib/ (eg, for other applications)
extra_symlinks = False
# Quickly enable/disable testing with the current develop branch
if False:
version(
'plus',
branch='develop',
git='file://{0}/{1}'
.format(os.path.expanduser("~"), 'openfoam/OpenFOAM-plus/.git'))
#
# - End of definitions / setup -
#
def setup_environment(self, spack_env, run_env):
run_env.set('FOAM_PROJECT_DIR', self.projectdir)
run_env.set('WM_PROJECT_DIR', self.projectdir)
for d in ['wmake', self.archbin]: # bin already added automatically
run_env.prepend_path('PATH', join_path(self.projectdir, d))
run_env.set('MPI_BUFFER_SIZE', "20000000")
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
"""Provide location of the OpenFOAM project.
This is identical to the WM_PROJECT_DIR value, but we avoid that
variable since it would mask the normal OpenFOAM cleanup of
previous versions.
"""
spack_env.set('FOAM_PROJECT_DIR', self.projectdir)
@property
def projectdir(self):
@ -350,195 +376,50 @@ def projectdir(self):
return self.prefix # <- install directly under prefix
@property
def etc(self):
"""Absolute location of the OpenFOAM etc/ directory"""
return join_path(self.projectdir, 'etc')
def foam_arch(self):
if not self._foam_arch:
self._foam_arch = OpenfoamArch(self.spec, **self.config)
return self._foam_arch
@property
def archbin(self):
"""Relative location of architecture-specific executables"""
return join_path('platforms', self.wm_options, 'bin')
return join_path('platforms', self.foam_arch, 'bin')
@property
def archlib(self):
"""Relative location of architecture-specific libraries"""
return join_path('platforms', self.wm_options, 'lib')
@property
def wm_options(self):
"""The architecture+compiler+options for OpenFOAM"""
opts = self.set_openfoam()
return opts
@property
def rpath_info(self):
"""Define 'SPACKOpt' compiler optimization file to have wmake
use spack information with minimum modifications to OpenFOAM
"""
build_libpath = join_path(self.stage.source_path, self.archlib)
install_libpath = join_path(self.projectdir, self.archlib)
# 'DBUG': rpaths
return '{0}{1} {2}{3}'.format(
self.compiler.cxx_rpath_arg, install_libpath,
self.compiler.cxx_rpath_arg, build_libpath)
def openfoam_arch(self):
"""Return an architecture value similar to what OpenFOAM does in
etc/config.sh/settings, but slightly more generous.
Uses and may adjust foam_cfg[WM_ARCH_OPTION] as a side-effect
"""
# spec.architecture.platform is like `uname -s`, but lower-case
platform = self.spec.architecture.platform
# spec.architecture.target is like `uname -m`
target = self.spec.architecture.target
if platform == 'linux':
if target == 'i686':
self.foam_cfg['WM_ARCH_OPTION'] = '32' # Force consistency
elif target == 'x86_64':
if self.foam_cfg['WM_ARCH_OPTION'] == '64':
platform += '64'
elif target == 'ia64':
platform += 'ia64'
elif target == 'armv7l':
platform += 'ARM7'
elif target == ppc64:
platform += 'PPC64'
elif target == ppc64le:
platform += 'PPC64le'
elif platform == 'darwin':
if target == 'x86_64':
platform += 'Intel'
if self.foam_cfg['WM_ARCH_OPTION'] == '64':
platform += '64'
# ... and others?
return platform
def openfoam_compiler(self):
"""Capitalized version of the compiler name, which usually corresponds
to how OpenFOAM will camel-case things.
Use compiler_mapping to handing special cases.
Also handle special compiler options (eg, KNL)
"""
comp = self.compiler.name
if comp in self.compiler_mapping:
comp = self.compiler_mapping[comp]
comp = comp.capitalize()
if '+knl' in self.spec:
comp += 'KNL'
return comp
def set_openfoam(self):
"""Populate foam_cfg, foam_sys according to
variants, architecture, compiler.
Returns WM_OPTIONS.
"""
# Run once
opts = self.foam_sys['WM_OPTIONS']
if opts:
return opts
wm_arch = self.openfoam_arch()
wm_compiler = self.openfoam_compiler()
compileOpt = self.foam_cfg['WM_COMPILE_OPTION']
# Insist on a wmake rule for this architecture/compiler combination
archCompiler = wm_arch + wm_compiler
compiler_rule = join_path(
self.stage.source_path, 'wmake', 'rules', archCompiler)
if not isdir(compiler_rule):
raise RuntimeError(
'No wmake rule for {0}'.format(archCompiler))
if not re.match(r'.+Opt$', compileOpt):
raise RuntimeError(
"WM_COMPILE_OPTION={0} is not type '*Opt'".format(compileOpt))
# Adjust for variants
self.foam_cfg['WM_LABEL_SIZE'] = (
'64' if '+int64' in self.spec else '32'
)
self.foam_cfg['WM_PRECISION_OPTION'] = (
'SP' if '+float32' in self.spec else 'DP'
)
# ----
# WM_LABEL_OPTION=Int$WM_LABEL_SIZE
# WM_OPTIONS=$WM_ARCH$WM_COMPILER$WM_PRECISION_OPTION$WM_LABEL_OPTION$WM_COMPILE_OPTION
# ----
self.foam_sys['WM_ARCH'] = wm_arch
self.foam_sys['WM_COMPILER'] = wm_compiler
self.foam_cfg['WM_COMPILER'] = wm_compiler # For bashrc,cshrc too
self.foam_sys['WM_OPTIONS'] = ''.join([
wm_arch,
wm_compiler,
self.foam_cfg['WM_PRECISION_OPTION'],
'Int', self.foam_cfg['WM_LABEL_SIZE'], # Int32/Int64
compileOpt
])
return self.foam_sys['WM_OPTIONS']
return join_path('platforms', self.foam_arch, 'lib')
def patch(self):
"""Adjust OpenFOAM build for spack. Where needed, apply filter as an
alternative to normal patching.
"""
self.set_openfoam() # May need foam_cfg/foam_sys information
"""Adjust OpenFOAM build for spack.
Where needed, apply filter as an alternative to normal patching."""
add_extra_files(self, self.common, self.assets)
# Avoid WM_PROJECT_INST_DIR for ThirdParty, site or jobControl.
# Use openfoam-site.patch to handle jobControl, site.
#
# Filter (not patch) bashrc,cshrc for additional flexibility
wm_setting = {
# Filtering: bashrc,cshrc (using a patch is less flexible)
edits = {
'WM_THIRD_PARTY_DIR':
r'$WM_PROJECT_DIR/ThirdParty #SPACK: No separate third-party',
}
rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc
wm_setting,
edits,
posix=join_path('etc', 'bashrc'),
cshell=join_path('etc', 'cshrc'))
# Adjust ParMGridGen - this is still a mess.
# We also have no assurances about sizes (int/long, float/double) etc.
#
# Need to adjust src/fvAgglomerationMethods/Allwmake
# "export ParMGridGen=%s" % spec['parmgridgen'].prefix
#
# and src/fvAgglomerationMethods/MGridGenGamgAgglomeration/Make/options
# "-I=%s" % spec['parmgridgen'].include
# "-L=%s -lmgrid" % spec['parmgridgen'].lib
# Build wrapper script
with open(self.build_script, 'w') as out:
out.write(
"""#!/bin/bash
. $PWD/etc/bashrc '' # No arguments
mkdir -p $FOAM_APPBIN $FOAM_LIBBIN 2>/dev/null # Allow interrupt
echo Build openfoam with SPACK
echo WM_PROJECT_DIR = $WM_PROJECT_DIR
./Allwmake $@
#
""")
set_executable(self.build_script)
self.configure(self.spec, self.prefix) # Should be a separate phase
def configure(self, spec, prefix):
"""Make adjustments to the OpenFOAM configuration files in their various
locations: etc/bashrc, etc/config.sh/FEATURE and customizations that
don't properly fit get placed in the etc/prefs.sh file (similiarly for
csh).
"""
self.set_openfoam() # Need foam_cfg/foam_sys information
# Some settings for filtering bashrc, cshrc
wm_setting = {}
wm_setting.update(self.foam_cfg)
# Filtering bashrc, cshrc
edits = {}
edits.update(self.foam_arch.foam_dict())
rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc
wm_setting,
edits,
posix=join_path('etc', 'bashrc'),
cshell=join_path('etc', 'cshrc'))
@ -551,27 +432,34 @@ def configure(self, spec, prefix):
}
# MPI content, using MPI_ARCH_PATH
content = mplib_content(spec, '${MPI_ARCH_PATH}')
user_mpi = mplib_content(spec, '${MPI_ARCH_PATH}')
# Content for etc/config.{csh,sh}/ files
self.etc_config = {
'CGAL': {
'BOOST_ARCH_PATH': spec['boost'].prefix,
'CGAL_ARCH_PATH': spec['cgal'].prefix,
},
'FFTW': {
'FFTW_ARCH_PATH': spec['fftw'].prefix,
},
'CGAL': [
('BOOST_ARCH_PATH', spec['boost'].prefix),
('CGAL_ARCH_PATH', spec['cgal'].prefix),
('LD_LIBRARY_PATH',
foamAddLib(
pkglib(spec['boost'], '${BOOST_ARCH_PATH}'),
pkglib(spec['cgal'], '${CGAL_ARCH_PATH}'))),
],
'FFTW': [
('FFTW_ARCH_PATH', spec['fftw'].prefix), # Absolute
('LD_LIBRARY_PATH',
foamAddLib(
pkglib(spec['fftw'], '${BOOST_ARCH_PATH}'))),
],
# User-defined MPI
'mpi-user': [
('MPI_ARCH_PATH', spec['mpi'].prefix), # Absolute
('LD_LIBRARY_PATH',
'"%s:${LD_LIBRARY_PATH}"' % content['libdir']),
('PATH', '"%s:${PATH}"' % content['bindir']),
('LD_LIBRARY_PATH', foamAddLib(user_mpi['libdir'])),
('PATH', foamAddPath(user_mpi['bindir'])),
],
'scotch': {},
'metis': {},
'paraview': [],
'gperftools': [], # Currently unused
}
if '+scotch' in spec:
@ -590,15 +478,15 @@ def configure(self, spec, prefix):
pvMajor = 'paraview-{0}'.format(spec['paraview'].version.up_to(2))
self.etc_config['paraview'] = [
('ParaView_DIR', spec['paraview'].prefix),
('ParaView_INCLUDE_DIR', '$ParaView_DIR/include/' + pvMajor),
('ParaView_INCLUDE_DIR', '${ParaView_DIR}/include/' + pvMajor),
('PV_PLUGIN_PATH', '$FOAM_LIBBIN/' + pvMajor),
('PATH', '"${ParaView_DIR}/bin:${PATH}"'),
('PATH', foamAddPath('${ParaView_DIR}/bin')),
]
# Not normally included as etc/config file
if '+parmgridgen' in spec:
self.etc_config['parmgridgen'] = {
'PARMGRIDGEN_ARCH_PATH': spec['parmgridgen'].prefix
# Optional
if '+mgridgen' in spec:
self.etc_config['mgridgen'] = {
'MGRIDGEN_ARCH_PATH': spec['parmgridgen'].prefix
}
# Optional
@ -622,45 +510,30 @@ def configure(self, spec, prefix):
posix=join_path('etc', 'config.sh', component),
cshell=join_path('etc', 'config.csh', component))
archCompiler = self.foam_sys['WM_ARCH'] + self.foam_sys['WM_COMPILER']
compileOpt = self.foam_cfg['WM_COMPILE_OPTION']
general_rule = join_path('wmake', 'rules', 'General')
compiler_rule = join_path('wmake', 'rules', archCompiler)
generate_mplib_rules(general_rule, self.spec)
generate_compiler_rules(compiler_rule, compileOpt, self.rpath_info)
# Record the spack spec information
with open("log.spack-spec", 'w') as outfile:
outfile.write(spec.tree())
def build(self, spec, prefix):
"""Build using the OpenFOAM Allwmake script, with a wrapper to source
its environment first.
Only build if the compiler is known to be supported.
"""
self.set_openfoam() # Force proper population of foam_cfg/foam_sys
self.foam_arch.has_rule(self.stage.source_path)
self.foam_arch.create_rules(self.stage.source_path, self)
args = ['-silent']
if self.parallel: # Build in parallel? - pass as an argument
args.append(
'-j{0}'.format(str(self.make_jobs) if self.make_jobs else ''))
args.append('-j{0}'.format(make_jobs))
builder = Executable(self.build_script)
builder(*args)
def install(self, spec, prefix):
"""Install under the projectdir (== prefix)"""
self.build(spec, prefix) # Should be a separate phase
opts = self.wm_options
"""Install under the projectdir"""
mkdirp(self.projectdir)
projdir = os.path.basename(self.projectdir)
wm_setting = {
# Filtering: bashrc, cshrc
edits = {
'WM_PROJECT_INST_DIR': os.path.dirname(self.projectdir),
'WM_PROJECT_DIR': join_path('$WM_PROJECT_INST_DIR', projdir),
}
# Retain build log file
out = "spack-build.out"
if isfile(out):
install(out, join_path(self.projectdir, "log." + opts))
# All top-level files, except spack build info and possibly Allwmake
if '+source' in spec:
ignored = re.compile(r'^spack-.*')
@ -668,20 +541,23 @@ def install(self, spec, prefix):
ignored = re.compile(r'^(Allwmake|spack-).*')
files = [
f for f in glob.glob("*") if isfile(f) and not ignored.search(f)
f for f in glob.glob("*")
if os.path.isfile(f) and not ignored.search(f)
]
for f in files:
install(f, self.projectdir)
# Having wmake without sources is actually somewhat pointless...
dirs = ['bin', 'etc', 'wmake']
# Having wmake and ~source is actually somewhat pointless...
# Install 'etc' before 'bin' (for symlinks)
dirs = ['etc', 'bin', 'wmake']
if '+source' in spec:
dirs.extend(['applications', 'src', 'tutorials'])
for d in dirs:
install_tree(
d,
join_path(self.projectdir, d))
join_path(self.projectdir, d),
symlinks=True)
dirs = ['platforms']
if '+source' in spec:
@ -693,30 +569,229 @@ def install(self, spec, prefix):
install_tree(
d,
join_path(self.projectdir, d),
ignore=shutil.ignore_patterns(*ignored))
ignore=shutil.ignore_patterns(*ignored),
symlinks=True)
etc_dir = join_path(self.projectdir, 'etc')
rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc
wm_setting,
posix=join_path(self.etc, 'bashrc'),
cshell=join_path(self.etc, 'cshrc'))
edits,
posix=join_path(etc_dir, 'bashrc'),
cshell=join_path(etc_dir, 'cshrc'))
self.install_links()
def install_links(self):
"""Add symlinks into bin/, lib/ (eg, for other applications)"""
if not self.extra_symlinks:
# Make build log visible - it contains OpenFOAM-specific information
with working_dir(self.projectdir):
os.symlink(
join_path('.spack', 'build.out'),
join_path('log.' + str(self.foam_arch)))
if not self.config['link']:
return
# ln -s platforms/linux64GccXXX/lib lib
with working_dir(self.projectdir):
if isdir(self.archlib):
if os.path.isdir(self.archlib):
os.symlink(self.archlib, 'lib')
# (cd bin && ln -s ../platforms/linux64GccXXX/bin/* .)
with working_dir(join_path(self.projectdir, 'bin')):
for f in [
f for f in glob.glob(join_path('..', self.archbin, "*"))
if isfile(f)
if os.path.isfile(f)
]:
os.symlink(f, os.path.basename(f))
def openfoam_run_environment(self, projdir):
# This seems to bomb out with an ImportError 'site'!
# mods = EnvironmentModifications.from_sourcing_files(
# join_path(projdir, 'etc/bashrc'))
pass
# -----------------------------------------------------------------------------
class OpenfoamArch(object):
"""OpenfoamArch represents architecture/compiler settings for OpenFOAM.
The string representation is WM_OPTIONS.
Keywords
label-size=[True] supports int32/int64
compile-option[=RpathOpt]
mplib[=USERMPI]
"""
#: Map spack compiler names to OpenFOAM compiler names
# By default, simply capitalize the first letter
compiler_mapping = {'intel': 'icc'}
def __init__(self, spec, **kwargs):
# Some user settings, to be adjusted manually or via variants
self.compiler = None # <- %compiler
self.arch_option = '64' # (32/64-bit on x86_64)
self.label_size = None # <- +int64
self.precision_option = 'DP' # <- +float32
self.compile_option = kwargs.get('compile-option', 'RpathOpt')
self.arch = None
self.options = None
self.rule = None
self.mplib = kwargs.get('mplib', 'USERMPI')
# Normally support WM_LABEL_OPTION, but not yet for foam-extend
if '+int64' in spec:
self.label_size = '64'
elif kwargs.get('label-size', True):
self.label_size = '32'
if '+float32' in spec:
self.precision_option = 'SP'
# spec.architecture.platform is like `uname -s`, but lower-case
platform = spec.architecture.platform
# spec.architecture.target is like `uname -m`
target = spec.architecture.target
if platform == 'linux':
if target == 'i686':
self.arch_option = '32' # Force consistency
elif target == 'x86_64':
if self.arch_option == '64':
platform += '64'
elif target == 'ia64':
platform += 'ia64'
elif target == 'armv7l':
platform += 'ARM7'
elif target == ppc64:
platform += 'PPC64'
elif target == ppc64le:
platform += 'PPC64le'
elif platform == 'darwin':
if target == 'x86_64':
platform += 'Intel'
if self.arch_option == '64':
platform += '64'
# ... and others?
self.arch = platform
# Capitalized version of the compiler name, which usually corresponds
# to how OpenFOAM will camel-case things.
# Use compiler_mapping to handing special cases.
# Also handle special compiler options (eg, KNL)
comp = spec.compiler.name
if comp in self.compiler_mapping:
comp = self.compiler_mapping[comp]
comp = comp.capitalize()
if '+knl' in spec:
comp += 'KNL'
self.compiler = comp
self.rule = self.arch + self.compiler
# Build WM_OPTIONS
# ----
# WM_LABEL_OPTION=Int$WM_LABEL_SIZE
# WM_OPTIONS=$WM_ARCH$WM_COMPILER$WM_PRECISION_OPTION$WM_LABEL_OPTION$WM_COMPILE_OPTION
# or
# WM_OPTIONS=$WM_ARCH$WM_COMPILER$WM_PRECISION_OPTION$WM_COMPILE_OPTION
# ----
self.options = ''.join([
self.rule,
self.precision_option,
('Int' + self.label_size if self.label_size else ''),
self.compile_option])
def __str__(self):
return self.options
def __repr__(self):
return str(self)
def foam_dict(self):
"""Returns a dictionary for OpenFOAM prefs, bashrc, cshrc."""
return dict([
('WM_COMPILER', self.compiler),
('WM_ARCH_OPTION', self.arch_option),
('WM_LABEL_SIZE', self.label_size),
('WM_PRECISION_OPTION', self.precision_option),
('WM_COMPILE_OPTION', self.compile_option),
('WM_MPLIB', self.mplib),
])
def _rule_directory(self, projdir=None, general=False):
"""The wmake/rules/ compiler directory"""
if general:
relative = os.path.join('wmake', 'rules', 'General')
else:
relative = os.path.join('wmake', 'rules', self.rule)
if projdir:
return os.path.join(projdir, relative)
else:
return relative
def has_rule(self, projdir):
"""Verify that a wmake/rules/ compiler rule exists in the project
directory.
"""
# Insist on a wmake rule for this architecture/compiler combination
rule_dir = self._rule_directory(projdir)
if not os.path.isdir(rule_dir):
raise InstallError(
'No wmake rule for {0}'.format(self.rule))
if not re.match(r'.+Opt$', self.compile_option):
raise InstallError(
"WM_COMPILE_OPTION={0} is not type '*Opt'"
.format(self.compile_option))
return True
def create_rules(self, projdir, foam_pkg):
""" Create cRpathOpt,c++RpathOpt and mplibUSER,mplibUSERMPI
rules in the specified project directory.
The compiler rules are based on the respective cOpt,c++Opt rules
but with additional rpath information for the OpenFOAM libraries.
The rpath rules allow wmake to use spack information with minimal
modification to OpenFOAM.
The rpath is used for the installed libpath (continue to use
LD_LIBRARY_PATH for values during the build).
"""
# Note: the 'c' rules normally don't need rpath, since they are just
# used for statically linked wmake utilities, but left in anyhow.
# rpath for installed OpenFOAM libraries
rpath = '{0}{1}'.format(
foam_pkg.compiler.cxx_rpath_arg,
join_path(foam_pkg.projectdir, foam_pkg.archlib))
user_mpi = mplib_content(foam_pkg.spec)
rule_dir = self._rule_directory(projdir)
with working_dir(rule_dir):
# Compiler: copy existing cOpt,c++Opt and modify '*DBUG' value
for lang in ['c', 'c++']:
src = '{0}Opt'.format(lang)
dst = '{0}{1}'.format(lang, self.compile_option)
with open(src, 'r') as infile:
with open(dst, 'w') as outfile:
for line in infile:
line = line.rstrip()
outfile.write(line)
if re.match(r'^\S+DBUG\s*=', line):
outfile.write(' ')
outfile.write(rpath)
outfile.write('\n')
# MPI rules
for mplib in ['mplibUSER', 'mplibUSERMPI']:
with open(mplib, 'w') as out:
out.write("""# Use mpi from spack ({name})\n
PFLAGS = {FLAGS}
PINC = {PINC}
PLIBS = {PLIBS}
""".format(**user_mpi))
# -----------------------------------------------------------------------------

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

View File

@ -44,22 +44,23 @@
# entirely clear and thus untested.
# - Resolution of flex, zlib needs more attention (within OpenFOAM)
#
# - mpi handling: WM_MPLIB=SYSTEMMPI and use spack to populate the prefs.sh
# for it.
# Also provide wmake rules for special purpose 'USER' and 'USERMPI'
# - mpi handling: WM_MPLIB=SYSTEMMPI and use spack to populate prefs.sh for it.
# Provide wmake rules for special purpose 'USER' and 'USERMPI'
# mpi implementations, in case these are required.
#
# Known issues
# - Combining +zoltan with +int64 has not been tested, but probably won't work.
# - Combining +mgridgen with +int64 or +float32 probably won't work.
#
##############################################################################
from spack import *
from spack.environment import *
import llnl.util.tty as tty
import multiprocessing
import glob
import re
import shutil
import os
from os.path import isdir, isfile
from spack.pkg.builtin.openfoam_com import *
@ -78,19 +79,15 @@ class OpenfoamOrg(Package):
version('4.1', '318a446c4ae6366c7296b61184acd37c',
url=baseurl + '/OpenFOAM-4.x/archive/version-4.1.tar.gz')
version('dev', git='https://github.com/OpenFOAM/OpenFOAM-dev.git')
variant('int64', default=False,
description='Compile with 64-bit labels')
description='Compile with 64-bit label')
variant('float32', default=False,
description='Compile with 32-bit scalar (single-precision)')
variant('source', default=True,
description='Install library/application sources and tutorials')
#: Map spack compiler names to OpenFOAM compiler names
# By default, simply capitalize the first letter
compiler_mapping = {'intel': 'icc'}
provides('openfoam')
depends_on('mpi')
depends_on('zlib')
@ -98,31 +95,26 @@ class OpenfoamOrg(Package):
depends_on('cmake', type='build')
# Require scotch with ptscotch - corresponds to standard OpenFOAM setup
depends_on('scotch~int64+mpi', when='~int64')
depends_on('scotch+int64+mpi', when='+int64')
depends_on('scotch~metis+mpi~int64', when='~int64')
depends_on('scotch~metis+mpi+int64', when='+int64')
# General patches
patch('openfoam-site.patch')
# General patches - foamEtcFile as per openfoam.com (robuster)
common = ['spack-Allwmake', 'README-spack']
assets = ['bin/foamEtcFile']
# Version-specific patches
patch('openfoam-etc-41.patch')
patch('openfoam-etc-41.patch', when='@4.1')
patch('openfoam-site-41.patch', when='@4.1')
# Some user settings, to be adjusted manually or via variants
foam_cfg = {
'WM_COMPILER': 'Gcc', # <- %compiler
'WM_ARCH_OPTION': '64', # (32/64-bit on x86_64)
'WM_LABEL_SIZE': '32', # <- +int64
'WM_PRECISION_OPTION': 'DP', # <- +float32
'WM_COMPILE_OPTION': 'SPACKOpt', # Do not change
'WM_MPLIB': 'SYSTEMMPI', # Use system mpi for spack
# Some user config settings
config = {
'mplib': 'SYSTEMMPI', # Use system mpi for spack
# Add links into bin/, lib/ (eg, for other applications)
'link': False
}
# The system description is frequently needed
foam_sys = {
'WM_ARCH': None,
'WM_COMPILER': None,
'WM_OPTIONS': None,
}
# The openfoam architecture, compiler information etc
_foam_arch = None
# Content for etc/prefs.{csh,sh}
etc_prefs = {}
@ -130,236 +122,111 @@ class OpenfoamOrg(Package):
# Content for etc/config.{csh,sh}/ files
etc_config = {}
build_script = './spack-Allwmake' # <- Generated by patch() method.
# phases = ['configure', 'build', 'install']
# build_system_class = 'OpenfoamCom'
phases = ['configure', 'build', 'install']
build_script = './spack-Allwmake' # <- Added by patch() method.
# Add symlinks into bin/, lib/ (eg, for other applications)
extra_symlinks = False
#
# - End of definitions / setup -
#
def setup_environment(self, spack_env, run_env):
run_env.set('FOAM_PROJECT_DIR', self.projectdir)
run_env.set('WM_PROJECT_DIR', self.projectdir)
for d in ['wmake', self.archbin]: # bin already added automatically
run_env.prepend_path('PATH', join_path(self.projectdir, d))
run_env.set('MPI_BUFFER_SIZE', "20000000")
@property
def _canonical(self):
"""Canonical name for this package and version"""
return 'OpenFOAM-{0}'.format(self.version)
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
"""Provide location of the OpenFOAM project.
This is identical to the WM_PROJECT_DIR value, but we avoid that
variable since it would mask the normal OpenFOAM cleanup of
previous versions.
"""
spack_env.set('FOAM_PROJECT_DIR', self.projectdir)
@property
def projectdir(self):
"""Absolute location of project directory: WM_PROJECT_DIR/"""
return join_path(self.prefix, self._canonical) # <- prefix/canonical
return self.prefix # <- install directly under prefix
@property
def etc(self):
"""Absolute location of the OpenFOAM etc/ directory"""
return join_path(self.projectdir, 'etc')
def foam_arch(self):
if not self._foam_arch:
self._foam_arch = OpenfoamArch(self.spec, **self.config)
return self._foam_arch
@property
def archbin(self):
"""Relative location of architecture-specific executables"""
return join_path('platforms', self.wm_options, 'bin')
return join_path('platforms', self.foam_arch, 'bin')
@property
def archlib(self):
"""Relative location of architecture-specific libraries"""
return join_path('platforms', self.wm_options, 'lib')
return join_path('platforms', self.foam_arch, 'lib')
@property
def wm_options(self):
"""The architecture+compiler+options for OpenFOAM"""
opts = self.set_openfoam()
return opts
@property
def rpath_info(self):
"""Define 'SPACKOpt' compiler optimization file to have wmake
use spack information with minimum modifications to OpenFOAM
def rename_source(self):
"""This is fairly horrible.
The github tarfiles have weird names that do not correspond to the
canonical name. We need to rename these, but leave a symlink for
spack to work with.
"""
build_libpath = join_path(self.stage.source_path, self.archlib)
install_libpath = join_path(self.projectdir, self.archlib)
# 'DBUG': rpaths
return '{0}{1} {2}{3}'.format(
self.compiler.cxx_rpath_arg, install_libpath,
self.compiler.cxx_rpath_arg, build_libpath)
def openfoam_arch(self):
"""Return an architecture value similar to what OpenFOAM does in
etc/config.sh/settings, but slightly more generous.
Uses and may adjust foam_cfg[WM_ARCH_OPTION] as a side-effect
"""
# spec.architecture.platform is like `uname -s`, but lower-case
platform = self.spec.architecture.platform
# spec.architecture.target is like `uname -m`
target = self.spec.architecture.target
if platform == 'linux':
if target == 'i686':
self.foam_cfg['WM_ARCH_OPTION'] = '32' # Force consistency
elif target == 'x86_64':
if self.foam_cfg['WM_ARCH_OPTION'] == '64':
platform += '64'
elif target == 'ia64':
platform += 'ia64'
elif target == 'armv7l':
platform += 'ARM7'
elif target == ppc64:
platform += 'PPC64'
elif target == ppc64le:
platform += 'PPC64le'
elif platform == 'darwin':
if target == 'x86_64':
platform += 'Intel'
if self.foam_cfg['WM_ARCH_OPTION'] == '64':
platform += '64'
# ... and others?
return platform
def openfoam_compiler(self):
"""Capitalized version of the compiler name, which usually corresponds
to how OpenFOAM will camel-case things.
Use compiler_mapping to handing special cases.
Also handle special compiler options (eg, KNL)
"""
comp = self.compiler.name
if comp in self.compiler_mapping:
comp = self.compiler_mapping[comp]
comp = comp.capitalize()
if '+knl' in self.spec:
comp += 'KNL'
return comp
def set_openfoam(self):
"""Populate foam_cfg, foam_sys according to
variants, architecture, compiler.
Returns WM_OPTIONS.
"""
# Run once
opts = self.foam_sys['WM_OPTIONS']
if opts:
return opts
wm_arch = self.openfoam_arch()
wm_compiler = self.openfoam_compiler()
compileOpt = self.foam_cfg['WM_COMPILE_OPTION']
# Insist on a wmake rule for this architecture/compiler combination
archCompiler = wm_arch + wm_compiler
compiler_rule = join_path(
self.stage.source_path, 'wmake', 'rules', archCompiler)
if not isdir(compiler_rule):
raise RuntimeError(
'No wmake rule for {0}'.format(archCompiler))
if not re.match(r'.+Opt$', compileOpt):
raise RuntimeError(
"WM_COMPILE_OPTION={0} is not type '*Opt'".format(compileOpt))
# Adjust for variants
self.foam_cfg['WM_LABEL_SIZE'] = (
'64' if '+int64' in self.spec else '32'
)
self.foam_cfg['WM_PRECISION_OPTION'] = (
'SP' if '+float32' in self.spec else 'DP'
)
# ----
# WM_LABEL_OPTION=Int$WM_LABEL_SIZE
# WM_OPTIONS=$WM_ARCH$WM_COMPILER$WM_PRECISION_OPTION$WM_LABEL_OPTION$WM_COMPILE_OPTION
# ----
self.foam_sys['WM_ARCH'] = wm_arch
self.foam_sys['WM_COMPILER'] = wm_compiler
self.foam_cfg['WM_COMPILER'] = wm_compiler # For bashrc,cshrc too
self.foam_sys['WM_OPTIONS'] = ''.join([
wm_arch,
wm_compiler,
self.foam_cfg['WM_PRECISION_OPTION'],
'Int', self.foam_cfg['WM_LABEL_SIZE'], # Int32/Int64
compileOpt
])
return self.foam_sys['WM_OPTIONS']
def patch(self):
"""Adjust OpenFOAM build for spack. Where needed, apply filter as an
alternative to normal patching.
"""
self.set_openfoam() # May need foam_cfg/foam_sys information
# This is fairly horrible.
# The github tarfiles have weird names that do not correspond to the
# canonical name. We need to rename these, but leave a symlink for
# spack to work with.
#
# Note that this particular OpenFOAM release requires absolute
# directories to build correctly!
# Note that this particular OpenFOAM requires absolute directories
# to build correctly!
parent = os.path.dirname(self.stage.source_path)
original = os.path.basename(self.stage.source_path)
target = self._canonical
target = 'OpenFOAM-{0}'.format(self.version)
# Could also grep through etc/bashrc for WM_PROJECT_VERSION
with working_dir(parent):
if original != target and not os.path.lexists(target):
os.rename(original, target)
os.symlink(target, original)
tty.info('renamed {0} -> {1}'.format(original, target))
def patch(self):
"""Adjust OpenFOAM build for spack.
Where needed, apply filter as an alternative to normal patching."""
self.rename_source()
add_extra_files(self, self.common, self.assets)
# Avoid WM_PROJECT_INST_DIR for ThirdParty, site or jobControl.
# Use openfoam-site.patch to handle jobControl, site.
#
# Filter (not patch) bashrc,cshrc for additional flexibility
wm_setting = {
# Filtering: bashrc,cshrc (using a patch is less flexible)
edits = {
'WM_THIRD_PARTY_DIR':
r'$WM_PROJECT_DIR/ThirdParty #SPACK: No separate third-party',
'WM_VERSION': self.version, # consistency
'FOAMY_HEX_MESH': '', # This is horrible (unset variable?)
}
rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc
wm_setting,
edits,
posix=join_path('etc', 'bashrc'),
cshell=join_path('etc', 'cshrc'))
# Build wrapper script
with open(self.build_script, 'w') as out:
out.write(
"""#!/bin/bash
. $PWD/etc/bashrc '' # No arguments
mkdir -p $FOAM_APPBIN $FOAM_LIBBIN 2>/dev/null # Allow interrupt
echo Build openfoam with SPACK
echo WM_PROJECT_DIR = $WM_PROJECT_DIR
./Allwmake $@
#
""")
set_executable(self.build_script)
self.configure(self.spec, self.prefix) # Should be a separate phase
def configure(self, spec, prefix):
"""Make adjustments to the OpenFOAM configuration files in their various
locations: etc/bashrc, etc/config.sh/FEATURE and customizations that
don't properly fit get placed in the etc/prefs.sh file (similiarly for
csh).
"""
self.set_openfoam() # Need foam_cfg/foam_sys information
# Some settings for filtering bashrc, cshrc
wm_setting = {}
wm_setting.update(self.foam_cfg)
# Filtering bashrc, cshrc
edits = {}
edits.update(self.foam_arch.foam_dict())
rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc
wm_setting,
edits,
posix=join_path('etc', 'bashrc'),
cshell=join_path('etc', 'cshrc'))
# MPI content, with absolute paths
content = mplib_content(spec)
user_mpi = mplib_content(spec)
# Content for etc/prefs.{csh,sh}
self.etc_prefs = {
r'MPI_ROOT': spec['mpi'].prefix, # Absolute
r'MPI_ARCH_FLAGS': '"%s"' % content['FLAGS'],
r'MPI_ARCH_INC': '"%s"' % content['PINC'],
r'MPI_ARCH_LIBS': '"%s"' % content['PLIBS'],
r'MPI_ARCH_FLAGS': '"%s"' % user_mpi['FLAGS'],
r'MPI_ARCH_INC': '"%s"' % user_mpi['PINC'],
r'MPI_ARCH_LIBS': '"%s"' % user_mpi['PLIBS'],
}
# Content for etc/config.{csh,sh}/ files
@ -368,6 +235,7 @@ def configure(self, spec, prefix):
'scotch': {},
'metis': {},
'paraview': [],
'gperftools': [], # Currently unused
}
if True:
@ -392,45 +260,30 @@ def configure(self, spec, prefix):
posix=join_path('etc', 'config.sh', component),
cshell=join_path('etc', 'config.csh', component))
archCompiler = self.foam_sys['WM_ARCH'] + self.foam_sys['WM_COMPILER']
compileOpt = self.foam_cfg['WM_COMPILE_OPTION']
general_rule = join_path('wmake', 'rules', 'General')
compiler_rule = join_path('wmake', 'rules', archCompiler)
generate_mplib_rules(general_rule, self.spec)
generate_compiler_rules(compiler_rule, compileOpt, self.rpath_info)
# Record the spack spec information
with open("log.spack-spec", 'w') as outfile:
outfile.write(spec.tree())
def build(self, spec, prefix):
"""Build using the OpenFOAM Allwmake script, with a wrapper to source
its environment first.
Only build if the compiler is known to be supported.
"""
self.set_openfoam() # Force proper population of foam_cfg/foam_sys
self.foam_arch.has_rule(self.stage.source_path)
self.foam_arch.create_rules(self.stage.source_path, self)
args = []
if self.parallel: # Build in parallel? - pass via the environment
os.environ['WM_NCOMPPROCS'] = str(self.make_jobs) \
if self.make_jobs else str(multiprocessing.cpu_count())
os.environ['WM_NCOMPPROCS'] = str(make_jobs)
builder = Executable(self.build_script)
builder(*args)
def install(self, spec, prefix):
"""Install under the projectdir (== prefix/name-version)"""
self.build(spec, prefix) # Should be a separate phase
opts = self.wm_options
"""Install under the projectdir"""
mkdirp(self.projectdir)
projdir = os.path.basename(self.projectdir)
wm_setting = {
# Filtering: bashrc, cshrc
edits = {
'WM_PROJECT_INST_DIR': os.path.dirname(self.projectdir),
'WM_PROJECT_DIR': join_path('$WM_PROJECT_INST_DIR', projdir),
}
# Retain build log file
out = "spack-build.out"
if isfile(out):
install(out, join_path(self.projectdir, "log." + opts))
# All top-level files, except spack build info and possibly Allwmake
if '+source' in spec:
ignored = re.compile(r'^spack-.*')
@ -438,20 +291,23 @@ def install(self, spec, prefix):
ignored = re.compile(r'^(Allwmake|spack-).*')
files = [
f for f in glob.glob("*") if isfile(f) and not ignored.search(f)
f for f in glob.glob("*")
if os.path.isfile(f) and not ignored.search(f)
]
for f in files:
install(f, self.projectdir)
# Having wmake without sources is actually somewhat pointless...
dirs = ['bin', 'etc', 'wmake']
# Having wmake and ~source is actually somewhat pointless...
# Install 'etc' before 'bin' (for symlinks)
dirs = ['etc', 'bin', 'wmake']
if '+source' in spec:
dirs.extend(['applications', 'src', 'tutorials'])
for d in dirs:
install_tree(
d,
join_path(self.projectdir, d))
join_path(self.projectdir, d),
symlinks=True)
dirs = ['platforms']
if '+source' in spec:
@ -463,29 +319,37 @@ def install(self, spec, prefix):
install_tree(
d,
join_path(self.projectdir, d),
ignore=shutil.ignore_patterns(*ignored))
ignore=shutil.ignore_patterns(*ignored),
symlinks=True)
etc_dir = join_path(self.projectdir, 'etc')
rewrite_environ_files( # Adjust etc/bashrc and etc/cshrc
wm_setting,
posix=join_path(self.etc, 'bashrc'),
cshell=join_path(self.etc, 'cshrc'))
edits,
posix=join_path(etc_dir, 'bashrc'),
cshell=join_path(etc_dir, 'cshrc'))
self.install_links()
def install_links(self):
"""Add symlinks into bin/, lib/ (eg, for other applications)"""
if not self.extra_symlinks:
# Make build log visible - it contains OpenFOAM-specific information
with working_dir(self.projectdir):
os.symlink(
join_path('.spack', 'build.out'),
join_path('log.' + str(self.foam_arch)))
if not self.config['link']:
return
# ln -s platforms/linux64GccXXX/lib lib
with working_dir(self.projectdir):
if isdir(self.archlib):
if os.path.isdir(self.archlib):
os.symlink(self.archlib, 'lib')
# (cd bin && ln -s ../platforms/linux64GccXXX/bin/* .)
with working_dir(join_path(self.projectdir, 'bin')):
for f in [
f for f in glob.glob(join_path('..', self.archbin, "*"))
if isfile(f)
if os.path.isfile(f)
]:
os.symlink(f, os.path.basename(f))