From e000a3cdc59f7a4e9cfaad9d75fa7195b0f25547 Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Mon, 20 Apr 2020 20:18:56 +0200
Subject: [PATCH] CONFIG: additional packaging helpers, tutorial test helper

- bin/tools/create-mpi-config to query/write values for system openmpi.
  In some cases this can be used to avoid an mpicc requirement at runtime.

- adjust openfoam session to latest version,
  including -test-tutorial forwarding.

- adjust foamConfigurePaths to latest version

- removal of gperftools default config, as per develop
---
 Allwmake                     |  29 ++-
 META-INFO/api-info           |   2 +-
 bin/foamEtcFile              | 108 ++++-----
 bin/tools/create-mpi-config  | 272 ++++++++++++++++++++++
 bin/tools/foamConfigurePaths | 439 ++++++++++++++++++++++++-----------
 bin/tools/openfoam           | 193 ---------------
 bin/tools/openfoam.in        |  19 ++
 doc/modules/README           |   1 +
 doc/openfoam.1.in            |  70 ++++++
 etc/config.sh/gperftools     |   7 +-
 etc/config.sh/setup          |   1 -
 etc/openfoam                 | 301 ++++++++++++++++++++++++
 tutorials/AutoTest           | 199 ++++++++++++++++
 tutorials/modules/README     |   1 +
 wmake/scripts/sysFunctions   |  74 +++++-
 15 files changed, 1308 insertions(+), 408 deletions(-)
 create mode 100755 bin/tools/create-mpi-config
 delete mode 100755 bin/tools/openfoam
 create mode 100644 bin/tools/openfoam.in
 create mode 100644 doc/modules/README
 create mode 100644 doc/openfoam.1.in
 create mode 100755 etc/openfoam
 create mode 100755 tutorials/AutoTest
 create mode 100644 tutorials/modules/README

diff --git a/Allwmake b/Allwmake
index c4544892a4f..aa2914453ac 100755
--- a/Allwmake
+++ b/Allwmake
@@ -25,7 +25,7 @@ command -v mpirun 2>/dev/null || true
 echo "========================================"
 date "+%Y-%m-%d %H:%M:%S %z" 2>/dev/null || echo "date is unknown"
 echo "Starting compile ${WM_PROJECT_DIR##*/} ${0##*/}"
-echo "  $WM_COMPILER $WM_COMPILER_TYPE compiler"
+echo "  $WM_COMPILER ${WM_COMPILER_TYPE:-system} compiler"
 echo "  ${WM_OPTIONS}, with ${WM_MPLIB} ${FOAM_MPI}"
 echo "========================================"
 echo
@@ -36,9 +36,18 @@ echo
 # Compile ThirdParty libraries and applications
 if [ -d "$WM_THIRD_PARTY_DIR" ]
 then
-    $WM_THIRD_PARTY_DIR/Allwmake
+    if [ -e "$WM_THIRD_PARTY_DIR"/Allwmake.override ]
+    then
+        if [ -x "$WM_THIRD_PARTY_DIR"/Allwmake.override ]
+        then    "$WM_THIRD_PARTY_DIR"/Allwmake.override
+        fi
+    elif [ -x "$WM_THIRD_PARTY_DIR"/Allwmake ]
+    then      "$WM_THIRD_PARTY_DIR"/Allwmake
+    else
+        echo "Skip ThirdParty (no Allwmake* files)"
+    fi
 else
-    echo "No ThirdParty directory found - skipping"
+    echo "Skip ThirdParty (no directory)"
 fi
 
 echo "========================================"
@@ -57,13 +66,13 @@ then
     echo "========================================"
     echo "Compile OpenFOAM modules"
     echo
-    (cd $WM_PROJECT_DIR/modules 2>/dev/null && wmake -all)
+    (cd "$WM_PROJECT_DIR/modules" 2>/dev/null && wmake -all)
 fi
 
 # Count files in given directory. Ignore "Test-*" binaries.
 _foamCountDirEntries()
 {
-    (cd "$1" 2>/dev/null && find -mindepth 1 -maxdepth 1 -type f 2>/dev/null) |\
+    (cd "$1" 2>/dev/null && find . -mindepth 1 -maxdepth 1 -type f 2>/dev/null) |\
         sed -e '\@/Test-@d' | wc -l
 }
 
@@ -72,13 +81,13 @@ echo
 date "+%Y-%m-%d %H:%M:%S %z" 2>/dev/null || echo "date is unknown"
 echo "========================================"
 echo "  ${WM_PROJECT_DIR##*/}"
-echo "  $WM_COMPILER $WM_COMPILER_TYPE compiler"
+echo "  $WM_COMPILER ${WM_COMPILER_TYPE:-system} compiler"
 echo "  ${WM_OPTIONS}, with ${WM_MPLIB} ${FOAM_MPI}"
 echo
-echo "  api   = $(foamEtcFile -show-api 2>/dev/null)"
-echo "  patch = $(foamEtcFile -show-patch 2>/dev/null)"
-echo "  bin   = $(_foamCountDirEntries $FOAM_APPBIN) entries"
-echo "  lib   = $(_foamCountDirEntries $FOAM_LIBBIN) entries"
+echo "  api   = $(etc/openfoam -show-api 2>/dev/null)"
+echo "  patch = $(etc/openfoam -show-patch 2>/dev/null)"
+echo "  bin   = $(_foamCountDirEntries "$FOAM_APPBIN") entries"
+echo "  lib   = $(_foamCountDirEntries "$FOAM_LIBBIN") entries"
 echo
 echo "========================================"
 
diff --git a/META-INFO/api-info b/META-INFO/api-info
index 5942011d139..bd5f06ab8b5 100644
--- a/META-INFO/api-info
+++ b/META-INFO/api-info
@@ -1,2 +1,2 @@
 api=1906
-patch=200312
+patch=200417
diff --git a/bin/foamEtcFile b/bin/foamEtcFile
index 024c16a33b6..fc8cc57bf53 100755
--- a/bin/foamEtcFile
+++ b/bin/foamEtcFile
@@ -7,14 +7,13 @@
 #    \\/     M anipulation  |
 #------------------------------------------------------------------------------
 #     Copyright (C) 2011-2016 OpenFOAM Foundation
-#     Copyright (C) 2017-2018 OpenCFD Ltd.
+#     Copyright (C) 2017-2020 OpenCFD Ltd.
 #------------------------------------------------------------------------------
 # License
-#     This file is part of OpenFOAM, licensed under GNU General Public License
-#     <http://www.gnu.org/licenses/>.
+#     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
 #
 # Script
-#     foamEtcFile
+#     bin/foamEtcFile
 #
 # Description
 #     Locate user/group/other file as per '#includeEtc'.
@@ -33,7 +32,13 @@
 #     \endcode
 #
 # Environment
-#     - WM_PROJECT_SITE         (unset defaults to PROJECT/site)
+#     FOAM_CONFIG_ETC
+#         Alternative etc directory for shipped files
+#
+#     FOAM_CONFIG_MODE
+#         Fallback search mode for etc files. Unset is the same as "ugo".
+#
+#     WM_PROJECT_SITE         (unset defaults to PROJECT/site)
 #
 # Note
 #     This script must exist in the project 'bin' directory
@@ -46,8 +51,8 @@
 printHelp() {
     cat<<USAGE
 
-Usage: foamEtcFile [OPTION] fileName [-- args]
-       foamEtcFile [OPTION] [-list|-list-test] [fileName]
+Usage: ${0##*/} [OPTION] fileName [-- args]
+       ${0##*/} [OPTION] [-list|-list-test] [fileName]
 
 options:
   -all (-a)         Return all files (otherwise stop after the first match)
@@ -61,8 +66,8 @@ options:
   -config           Add config directory prefix for shell type:
                         with -csh* for a config.csh/ prefix
                         with -sh*  for a config.sh/ prefix
-  -show-api         Print api value from wmake/rules, or meta-info and exit
-  -show-patch       Print patch value from meta-info and exit
+  -show-api         Print META-INFO api value and exit
+  -show-patch       Print META-INFO patch value and exit
   -with-api=NUM     Specify alternative api value to search with
   -quiet (-q)       Suppress all normal output
   -silent (-s)      Suppress stderr, except -csh-verbose, -sh-verbose output
@@ -106,64 +111,40 @@ projectDir="$(\cd $(dirname $binDir) && \pwd -L)"   # Project dir
 
 userDir="$HOME/.OpenFOAM"                           # As per foamVersion.H
 groupDir="${WM_PROJECT_SITE:-$projectDir/site}"     # As per foamVersion.H
+optMode=ugo                                         # Default search = 'ugo'
 
-#-------------------------------------------------------------------------------
-
-# The API locations. See wmake/wmakeBuildInfo
-rulesFile="$projectDir/wmake/rules/General/general"
-metaInfoDir="$projectDir/META-INFO"
-
-# Get api from rules/General/general
-#
-# Failure modes:
-# - No api information (can't find file etc).
-#   -> Fatal for building, but could be OK for a stripped down version
-#
-# Fallback. Get from api-info
-#
-getApi()
-{
-    local value
-
-    value="$(sed -ne '/^ *#/!{ /WM_VERSION.*OPENFOAM=/{ s@^.*OPENFOAM= *\([0-9][0-9]*\).*@\1@p; q }}' $rulesFile 2>/dev/null)"
-    if [ -z "$value" ] && [ -f "$metaInfoDir/api-info" ]
-    then
-        # Fallback. Get from api-info
-        value="$(sed -ne 's@^ *api *= *\([0-9][0-9]*\).*@\1@p' $metaInfoDir/api-info 2>/dev/null)"
-    fi
+# Environment overrides
+case "$FOAM_CONFIG_MODE" in ([ugo]*) optMode="$FOAM_CONFIG_MODE" ;; esac
 
-    if [ -n "$value" ]
+# Verify validity of FOAM_CONFIG_ETC
+if [ -n "$FOAM_CONFIG_ETC" ]
+then
+    if [ ! -d "$FOAM_CONFIG_ETC" ] || [ "$FOAM_CONFIG_ETC" = "$projectDir/etc" ]
     then
-        echo "$value"
-    else
-        return 1
+        # Bad directory or redundant value
+        unset FOAM_CONFIG_ETC
     fi
-}
+fi
 
+#-------------------------------------------------------------------------------
 
-# Get patch from meta-info / api-info
-#
-# Failure modes:
-# - No patch information (can't find file etc).
-#
-getPatchLevel()
+# Get a value from META-INFO/api-info
+# $1 : keyword
+getApiInfo()
 {
-    local value
-
-    # Fallback. Get from api-info
-    value="$(sed -ne 's@^ *patch *= *\([0-9][0-9]*\).*@\1@p' $metaInfoDir/api-info 2>/dev/null)"
+    value="$(sed -ne 's@^'"$1"' *= *\([0-9][0-9]*\).*@\1@p' "$projectDir"/META-INFO/api-info 2>/dev/null)"
 
     if [ -n "$value" ]
     then
         echo "$value"
     else
+        echo "Could not determine OPENFOAM '$1' value" 1>&2
         return 1
     fi
 }
 
 
 #-------------------------------------------------------------------------------
-optMode=ugo         # Default mode is always 'ugo'
 unset shellOutput verboseOutput
 unset optAll optConfig optList projectApi
 
@@ -174,14 +155,12 @@ do
     -h | -help*)
         printHelp
         ;;
-    -show-api)
-        # Show API and exit
-        getApi
+    -show-api)  # Show API and exit
+        getApiInfo api
         exit $?
         ;;
-    -show-patch)
-        # Show patch level and exit
-        getPatchLevel
+    -show-patch)  # Show patch level and exit
+        getApiInfo patch
         exit $?
         ;;
     -with-api=*)
@@ -208,7 +187,7 @@ do
     -config)
         optConfig=true
         ;;
-    -mode=[ugoa]*)
+    -mode=[ugo]*)
         optMode="${1#*=}"
         ;;
     -m | -mode)
@@ -216,7 +195,7 @@ do
         shift
         # Sanity check. Handles missing argument too.
         case "$optMode" in
-        ([ugoa]*)
+        ([ugo]*)
             ;;
         (*)
             die "invalid mode '$optMode'"
@@ -257,8 +236,7 @@ done
 #-------------------------------------------------------------------------------
 
 # Establish the API value
-[ -n "$projectApi" ] || projectApi=$(getApi)
-
+[ -n "$projectApi" ] || projectApi=$(getApiInfo api)
 
 # Split arguments into filename (for searching) and trailing bits for shell eval
 # Silently remove leading ~OpenFOAM/ (as per Foam::findEtcFile)
@@ -293,23 +271,23 @@ fi
 
 # Define the various places to be searched:
 unset dirList
-case "$optMode" in (*[au]*) # (A)ll or (U)ser
+case "$optMode" in (*[u]*) # (U)ser
     dirList="$dirList $userDir/$projectApi $userDir"
     ;;
 esac
 
-case "$optMode" in (*[ag]*) # (A)ll or (G)roup == site
+case "$optMode" in (*[g]*) # (G)roup == site
     dirList="$dirList $groupDir/$projectApi/etc $groupDir/etc"
     ;;
 esac
 
-case "$optMode" in (*[ao]*) # (A)ll or (O)ther == shipped
-    dirList="$dirList $projectDir/etc"
+case "$optMode" in (*[o]*) # (O)ther == shipped
+    dirList="$dirList $FOAM_CONFIG_ETC $projectDir/etc"
     ;;
 esac
 set -- $dirList
 
-[ "$#" -ge 1 ] || die "No directories to scan. Programming error?"
+[ "$#" -ge 1 ] || die "No directories to scan. Programming or user error?"
 exitCode=2  # Fallback is a FileNotFound error
 
 
@@ -318,7 +296,7 @@ exitCode=2  # Fallback is a FileNotFound error
 #
 
 # Special handling of config.sh/ , config.csh/ directories
-if [ -n "$optConfig" -a -n "$shellOutput" -a -n "$fileName" ]
+if [ -n "$optConfig" ] && [ -n "$shellOutput" ] && [ -n "$fileName" ]
 then
     case "$shellOutput" in
     csh*)
diff --git a/bin/tools/create-mpi-config b/bin/tools/create-mpi-config
new file mode 100755
index 00000000000..561923f59d5
--- /dev/null
+++ b/bin/tools/create-mpi-config
@@ -0,0 +1,272 @@
+#!/bin/sh
+#------------------------------------------------------------------------------
+# =========                 |
+# \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+#  \\    /   O peration     |
+#   \\  /    A nd           | www.openfoam.com
+#    \\/     M anipulation  |
+#------------------------------------------------------------------------------
+#     Copyright (C) 2020 OpenCFD Ltd.
+#------------------------------------------------------------------------------
+# License
+#     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
+#
+# Script
+#     bin/tools/create-mpi-config
+#
+# Description
+#     Define hard-coded packaging settings for MPI flavours,
+#     primarily for system openmpi.
+#     This eliminates a runtime dependency on mpicc, for example.
+#
+#     Instead of querying/parsing 'mpicc --showme:link' each time,
+#     it is done once during packaging.
+#
+# Environment
+#     FOAM_MPI, MPI_ARCH_PATH, DEB_TARGET_MULTIARCH
+#
+# Possible Dependencies
+#     - dpkg-architecture
+#     - mpicc
+#
+# Notes
+#     Run from top-level directory when creating config files
+#
+#------------------------------------------------------------------------------
+printHelp() {
+    exec 1>&2
+    while [ "$#" -ge 1 ]; do echo "$1"; shift; done
+    cat<<USAGE
+
+usage: ${0##*/} options
+
+options:
+  -dry-run          Report but do not write config files
+  -no-mpicc         Bypass any use of mpicc
+  -query-openmpi    Report installation directory for system openmpi
+  -write-openmpi    Query system openmpi and write config files
+  -write            Write config files using FOAM_MPI, MPI_ARCH_PATH
+
+Define hard-coded packaging settings for MPI flavours.
+
+Equivalent options:
+  -write-system-openmpi | -write-openmpi
+  -query-system-openmpi | -query-openmpi
+
+USAGE
+    exit 0  # A clean exit
+}
+
+
+# Report error and exit
+die()
+{
+    exec 1>&2
+    echo
+    echo "Error encountered:"
+    while [ "$#" -ge 1 ]; do echo "    $1"; shift; done
+    echo
+    echo "See '${0##*/} -help' for usage"
+    echo
+    exit 1
+}
+
+
+#------------------------------------------------------------------------------
+# Options
+unset optDryRun
+useMpicc=true
+
+# Get installation directory for system openmpi
+# - from "mpicc --showme:link"
+# - manual fallback
+#
+# The mpicc content looks like this:
+# ----
+# -pthread -L/usr/lib64/mpi/gcc/openmpi/lib64 -lmpi
+# ----
+
+query_system_openmpi()
+{
+    unset arch_path
+
+    if [ "$useMpicc" = true ]
+    then
+        arch_path=$(mpicc --showme:link 2>/dev/null | sed -e 's#^.*-L\([^ ]*\).*#\1#')
+        arch_path="${arch_path%/*}"
+
+        if [ -n "$arch_path" ]
+        then
+            echo "$arch_path"
+            return 0  # Clean exit
+        fi
+
+        echo "No mpicc found. Attempt manually" 1>&2
+    fi
+
+
+    # Manual discovery
+    if [ -z "$DEB_TARGET_MULTIARCH" ]
+    then
+        DEB_TARGET_MULTIARCH=$(dpkg-architecture -qDEB_TARGET_MULTIARCH 2>/dev/null || true)
+    fi
+
+    # Include is under /usr/lib...  (eg, debian, openSUSE)
+    for testdir in \
+        /usr/lib/"${DEB_TARGET_MULTIARCH:+${DEB_TARGET_MULTIARCH}/}"openmpi/include \
+        /usr/lib64/mpi/gcc/openmpi/include \
+    ;
+    do
+        if [ -e "$testdir/mpi.h" ]
+        then
+            echo "${testdir%/*}"
+            return 0  # Clean exit
+        fi
+    done
+
+    # Include is under /usr/include (eg, RedHat)
+    for testdir in \
+        /usr/include/openmpi-"$(uname -m)" \
+        /usr/include/openmpi \
+    ;
+    do
+        if [ -e "$testdir/mpi.h" ]
+        then
+            echo "/usr"
+            return 0  # Clean exit
+        fi
+    done
+
+    # Failed (should not happen)
+    # - report '/usr', but with error code 2
+    echo "/usr"
+    return 2
+}
+
+
+# Generate etc/config.{csh,sh}/MPI-TYPE files
+# based on the values for FOAM_MPI and MPI_ARCH_PATH
+
+create_files()
+{
+    [ -n "$FOAM_MPI" ] || die "FOAM_MPI not set"
+
+    if [ -d "$MPI_ARCH_PATH" ]
+    then
+        echo "Define $FOAM_MPI with $MPI_ARCH_PATH" 1>&2
+
+        case "$FOAM_MPI" in
+        (openmpi-system)
+            configDir="etc/config.sh"
+            if [ "$optDryRun" = true ]
+            then
+                cat << CONTENT 1>&2
+dry-run: $configDir/$FOAM_MPI
+#
+# Packaging configured value for $FOAM_MPI
+export MPI_ARCH_PATH="$MPI_ARCH_PATH"
+
+CONTENT
+            elif [ -d "$configDir" ]
+            then
+                echo "Write $configDir/$FOAM_MPI" 1>&2
+                cat << CONTENT > "$configDir/$FOAM_MPI"
+# $configDir/$FOAM_MPI
+#
+# Packaging configured value for $FOAM_MPI
+
+export MPI_ARCH_PATH="$MPI_ARCH_PATH"
+#----
+CONTENT
+            else
+                echo "Cannot write $configDir/$FOAM_MPI - no directory" 1>&2
+            fi
+
+            configDir="etc/config.csh"
+            if [ "$optDryRun" = true ]
+            then
+                cat << CONTENT 1>&2
+dry-run: $configDir/$FOAM_MPI
+#
+# Packaging configured value for $FOAM_MPI
+setenv MPI_ARCH_PATH "$MPI_ARCH_PATH"
+
+CONTENT
+            elif [ -d "$configDir" ]
+            then
+                echo "Write $configDir/$FOAM_MPI" 1>&2
+                cat << CONTENT > "$configDir/$FOAM_MPI"
+# $configDir/$FOAM_MPI
+#
+# Packaging configured value for $FOAM_MPI
+
+setenv MPI_ARCH_PATH "$MPI_ARCH_PATH"
+#----
+CONTENT
+            else
+                echo "Cannot write $configDir/$FOAM_MPI - no directory" 1>&2
+            fi
+            ;;
+        esac
+    else
+        echo "Warning: $FOAM_MPI with bad MPI_ARCH_PATH: $MPI_ARCH_PATH" 1>&2
+        # TBD - remove old/bad entries?
+        #
+        # for file in "etc/config.sh/$FOAM_MPI" "etc/config.csh/$FOAM_MPI"
+        # do
+        #     [ -f "$file" ] && rm -f "$file"
+        # done
+    fi
+}
+
+
+#------------------------------------------------------------------------------
+
+# Parse options
+while [ "$#" -gt 0 ]
+do
+    case "$1" in
+    -h | -help* | --help*)
+        printHelp
+        ;;
+    '')
+        # Discard empty arguments
+        ;;
+
+    -dry-run)
+        optDryRun=true
+        ;;
+
+    -no-mpicc)
+        unset useMpicc
+        ;;
+
+    -query-openmpi | -query-system-openmpi)
+        query_system_openmpi
+        exit $?
+        ;;
+
+    -write-openmpi | -write-system-openmpi)
+        if MPI_ARCH_PATH=$(query_system_openmpi)
+        then
+            FOAM_MPI="openmpi-system"
+            create_files
+        else
+            die "Failed query for system openmpi"
+        fi
+        ;;
+
+    -write)
+        create_files
+        ;;
+
+    *)
+        echo "Ignore unknown option/argument: '$1'" 1>&2
+        ;;
+    esac
+    shift
+done
+
+exit 0 # A clean exit, if we get this far
+
+# -----------------------------------------------------------------------------
diff --git a/bin/tools/foamConfigurePaths b/bin/tools/foamConfigurePaths
index 7243e1bfdf4..12ea3d36bcb 100755
--- a/bin/tools/foamConfigurePaths
+++ b/bin/tools/foamConfigurePaths
@@ -19,30 +19,68 @@
 #     Adjust hardcoded installation versions and paths
 #     in etc/{bashrc,cshrc} and etc/config.{sh,csh}/
 #
+# Requires
+#     - sed
+#     - bin/foamEtcFile
+#
+# Environment
+#     FOAM_CONFIG_ETC
+#         Alternative etc directory for shipped files
+#
 #------------------------------------------------------------------------------
-usage() {
-    exec 1>&2
-    while [ "$#" -ge 1 ]; do echo "$1"; shift; done
-    cat<<USAGE
+printHelp() {
 
-usage: ${0##*/} options
+    case "$1" in
+    (*compat*)
+        cat<<HELP_COMPAT
+Obsolete options:
+  -foamInstall DIR    [obsolete]
+  -projectName NAME   [obsolete]
+  -sigfpe|-no-sigfpe  [obsolete - now under etc/controlDict]
+  -archOption 32|64   [obsolete setting of 'WM_ARCH_OPTION' - edit manually]
+
+Equivalent options:
+  -version -foamVersion --projectVersion
+  -archOption           --archOption
+  -third                -ThirdParty
+  -paraview             --paraviewVersion | -paraviewVersion
+  -paraview-path        --paraviewInstall | -paraviewInstall
+  -scotch               --scotchVersion | -scotchVersion
+  -scotch-path          --scotchArchPath | -scotchArchPath
+  -system-compiler      -system
+  -third-compiler       -third
+
+HELP_COMPAT
+        exit 0 # A clean exit
+        ;;
+    esac
+
+    cat<<HELP_HEAD
+
+usage: $0 options
+
+Options
+  -h | -help          Display short help and exit
+  -help-compat        Display compatibility options and exit
+  -help-full          Display full help and exit
 
 Basic
+  -etc=DIR            set FOAM_CONFIG_ETC for alternative project files
   -project-path DIR   specify 'WM_PROJECT_DIR' (eg, /opt/openfoam1806-patch1)
   -version VER        specify project version (eg, v1806)
-  -SP | -float32      single precision (WM_PRECISION_OPTION)
-  -DP | -float64      double precision (WM_PRECISION_OPTION)
-  -SPDP               mixed single/double precision
-  -int32 | -int64     the 'WM_LABEL_SIZE'
+  -sp | -SP | -float32 single precision (WM_PRECISION_OPTION)
+  -dp | -DP | -float64 double precision (WM_PRECISION_OPTION)
+  -spdp | -SPDP       mixed precision (WM_PRECISION_OPTION)
+  -int32 | -int64     label-size (WM_LABEL_SIZE)
 
 Compiler
-  -system NAME        specify 'system' compiler to use (eg, Gcc, Icc,...)
-  -third  NAME        specify 'ThirdParty' compiler to use (eg, Clang40,...)
-  -gcc VER            specify 'default_gcc_version' for ThirdParty Gcc
-  -clang VER          specify 'default_clang_version' for ThirdParty Clang
-  gmp-VERSION         for ThirdParty gcc (gmp-system for system library)
-  mpfr-VERSION        for ThirdParty gcc (mpfr-system for system library)
-  mpc-VERSION         for ThirdParty gcc (mpc-system for system library)
+  -system-compiler NAME The 'system' compiler to use (eg, Gcc, Clang, Icc,...)
+  -third-compiler NAME  The 'ThirdParty' compiler to use (eg, Clang40,...)
+  -gcc VER            The 'default_gcc_version' for ThirdParty Gcc
+  -clang VER          The 'default_clang_version' for ThirdParty Clang
+  gmp-VERSION         For ThirdParty gcc (gmp-system for system library)
+  mpfr-VERSION        For ThirdParty gcc (mpfr-system for system library)
+  mpc-VERSION         For ThirdParty gcc (mpc-system for system library)
 
 MPI
   -mpi NAME           specify 'WM_MPLIB' type (eg, INTELMPI, etc)
@@ -50,51 +88,55 @@ MPI
   -openmpi-system     use system openmpi
   -openmpi-third      use ThirdParty openmpi (using default version)
 
-Components
+Components versions (ThirdParty)
+  -adios VER          specify 'adios2_version'
   -boost VER          specify 'boost_version'
-  -boost-path DIR     specify 'BOOST_ARCH_PATH'
-  -cgal ver           specify 'cgal_version'
-  -cgal-path DIR      specify 'CGAL_ARCH_PATH'
+  -cgal VER           specify 'cgal_version'
   -cmake VER          specify 'cmake_version'
   -fftw VER           specify 'fffw_version'
-  -fftw-path DIR      specify 'FFTW_ARCH_PATH'
   -kahip VER          specify 'KAHIP_VERSION'
-  -kahip-path DIR     specify 'KAHIP_ARCH_PATH'
-  -metis ver          specify 'METIS_VERSION'
-  -metis-path DIR     specify 'METIS_ARCH_PATH'
+  -metis VER          specify 'METIS_VERSION'
   -scotch VER         specify 'SCOTCH_VERSION' (eg, scotch_6.0.4)
-  -scotch-path DIR    specify 'SCOTCH_ARCH_PATH' (eg, /opt/scotch_6.0.4)
+
+HELP_HEAD
+
+    case "$1" in
+    (*full*)
+        cat<<HELP_FULL
+Components specified by absolute path
+  -adios-path DIR     Path for 'ADIOS2_ARCH_PATH' (overrides -adios)
+  -boost-path DIR     Path for 'BOOST_ARCH_PATH'  (overrides -boost)
+  -cgal-path DIR      Path for 'CGAL_ARCH_PATH'   (overrides -cgal)
+  -fftw-path DIR      Path for 'FFTW_ARCH_PATH'   (overrides -fftw)
+  -kahip-path DIR     Path for 'KAHIP_ARCH_PATH'  (overrides -kahip)
+  -metis-path DIR     Path for 'METIS_ARCH_PATH'  (overrides -metis)
+  -scotch-path DIR    Path for 'SCOTCH_ARCH_PATH' (overrides -scotch)
 
 Graphics
   -paraview VER       specify 'ParaView_VERSION' (eg, 5.4.1 or system)
   -paraview-qt VER    specify 'ParaView_QT' (eg, qt-system)
   -paraview-path DIR  specify 'ParaView_DIR' (eg, /opt/ParaView-5.4.1)
-  -vtk  VER           specify 'vtk_version' (eg, VTK-7.1.0)
+  -llvm VER           specify 'mesa_llvm'
   -mesa VER           specify 'mesa_version' (eg, mesa-13.0.1)
+  -vtk  VER           specify 'vtk_version' (eg, VTK-7.1.0)
+  -llvm-path DIR      Path for 'LLVM_ARCH_PATH'   (overrides -llvm)
+  -mesa-path DIR      Path for 'MESA_ARCH_PATH'   (overrides -mesa)
+  -vtk-path DIR       Path for 'VTK_DIR'          (overrides -vtk)
 
-Misc
-  -foamInstall DIR    [obsolete]
-  -projectName NAME   [obsolete]
-  -sigfpe|-no-sigfpe  [obsolete - now under etc/controlDict]
-  -archOption 32|64   [obsolete setting of 'WM_ARCH_OPTION' - edit manually]
-
+HELP_FULL
+        ;;
+    esac
 
-Adjusts hardcoded versions and installation paths (POSIX and C-shell).
+    cat<<HELP_TAIL_COMMON
+Adjusts hardcoded versions and installation paths (POSIX and C-shell)
+for OpenFOAM.
 
+HELP_TAIL_COMMON
 
-Equivalent options:
-  -version -foamVersion --projectVersion
-  -archOption           --archOption
-  -third                -ThirdParty
-  -paraview             --paraviewVersion | -paraviewVersion
-  -paraview-path        --paraviewInstall | -paraviewInstall
-  -scotch               --scotchVersion | -scotchVersion
-  -scotch-path          --scotchArchPath | -scotchArchPath
-
-USAGE
-    exit 1
+    exit 0 # A clean exit
 }
 
+
 # Report error and exit
 die()
 {
@@ -103,16 +145,32 @@ die()
     echo "Error encountered:"
     while [ "$#" -ge 1 ]; do echo "    $1"; shift; done
     echo
-    echo "See '${0##*/} -help' for usage"
+    echo "See '$0 -help' for usage"
     echo
     exit 1
 }
 
 # -----------------------------------------------------------------------------
+projectDir="$(\pwd -L)"     # Project dir
 
 # Check that it appears to be an OpenFOAM installation
-[ -f etc/bashrc -a -d etc/config.sh ] || \
-    usage "Please run from top-level directory of installation"
+if [ -f etc/bashrc ] && [ -d "META-INFO" ]
+then
+    echo "Configuring OpenFOAM ($projectDir)" 1>&2
+else
+    die "Please run from the OpenFOAM top-level installation directory" \
+        "No etc/bashrc or META-INFO/ found"
+fi
+
+# Use foamEtcFile to locate files, but only edit shipped files
+if [ -x bin/foamEtcFile ]
+then
+    _foamEtc() {
+        ./bin/foamEtcFile -mode=o "$@"
+    }
+else
+    die "No bin/foamEtcFile found in installation"
+fi
 
 
 # Check if argument matches the expected input. Respects case.
@@ -143,18 +201,22 @@ _inlineSed()
     local replacement="$3"
     local msg="$4"
     local cmd='/^[^#]/s@'"$regexp"'@'"$replacement"'@'
+    local localFile
 
     [ -f "$file" ] || {
         echo "Missing file: $file"
         exit 2 # Fatal
     }
 
+    # Local filename (for reporting)
+    localFile="$(echo "$file" | sed -e "s#^$projectDir/##")"
+
     grep -q "$regexp" "$file" && sed -i -e "$cmd" "$file" || { \
-        echo "Failed: ${msg:-replacement} in $file"
+        echo "Failed: ${msg:-replacement} in $localFile"
         return 1
     }
 
-    [ -n "$msg" ] && echo "    $msg  ($file)"
+    [ -n "$msg" ] && echo "    $msg  ($localFile)"
 
     return 0
 }
@@ -180,7 +242,7 @@ replace()
             "$file"  \
             "$key=.*" \
             "$key=$val" \
-            "Replaced $key setting by '$val'"
+            "Replaced $key by '$val'"
     done
 }
 
@@ -203,12 +265,34 @@ replaceCsh()
 
         _inlineSed \
             "$file"  \
-            "setenv  *$key [^ #]*" \
+            "setenv [ ]*$key [^ #]*" \
             "setenv $key $val" \
-            "Replaced $key setenv by '$val'"
+            "Replaced $key by '$val'"
     done
 }
 
+# Locate file with foamEtcFile -mode=o and forward to replace()
+replaceEtc()
+{
+    local file="$1"
+    shift
+
+    file=$(_foamEtc "$file")
+    replace $file "$@"
+}
+
+
+# Locate file with foamEtcFile -mode=o and forward to replaceCsh()
+replaceEtcCsh()
+{
+    local file="$1"
+    shift
+
+    file=$(_foamEtc "$file")
+    replaceCsh $file "$@"
+}
+
+
 # Get the option's value (argument), or die on missing or empty argument
 # $1 option
 # $2 value
@@ -272,23 +356,62 @@ unset adjusted optMpi
 while [ "$#" -gt 0 ]
 do
     case "$1" in
-    -h | -help* | --help*)
-        usage
+    -help-c*)   # Compat help
+        printHelp -compat
+        ;;
+    -help-f*)   # Full help
+        printHelp -full
+        ;;
+    -h | -help*) # Short help
+        printHelp
         ;;
     '')
         # Discard empty arguments
         ;;
 
+    -debug-list)
+        # Undocumented (experimental)
+        # TDB: List files that can be edited by this script
+        cat << CONFIG_SH
+etc/bashrc
+etc/config.sh/adios2
+etc/config.sh/compiler
+etc/config.sh/paraview
+etc/config.sh/vtk
+etc/config.sh/CGAL
+etc/config.sh/FFTW
+etc/config.sh/metis
+etc/config.sh/kahip
+etc/config.sh/scotch
+CONFIG_SH
+
+        cat << CONFIG_CSH
+etc/cshrc
+etc/config.csh/adios2
+etc/config.csh/compiler
+etc/config.csh/paraview
+etc/config.csh/vtk
+etc/config.csh/CGAL
+etc/config.csh/FFTW
+CONFIG_CSH
+        exit 0
+        ;;
+
 ## Basic ##
 
+   -etc=*)
+        # Define FOAM_CONFIG_ETC for finding files
+        export FOAM_CONFIG_ETC="${1#*=}"
+        ;;
+
    -project-path)
         # Replace WM_PROJECT_DIR=...
         optionValue=$(getOptionValue "$@")
-        replace    etc/bashrc  WM_PROJECT_DIR "\"$optionValue\""
-        replaceCsh etc/cshrc   WM_PROJECT_DIR "\"$optionValue\""
+        replaceEtc     bashrc  WM_PROJECT_DIR "\"$optionValue\""
+        replaceEtcCsh  cshrc   WM_PROJECT_DIR "\"$optionValue\""
 
-        removeBashMagic etc/bashrc
-        removeCshMagic  etc/cshrc
+        removeBashMagic $(_foamEtc bashrc)
+        removeCshMagic  $(_foamEtc cshrc)
 
         adjusted=true
         shift
@@ -297,8 +420,8 @@ do
    -version | -foamVersion | --projectVersion)
         # Replace WM_PROJECT_VERSION=...
         optionValue=$(getOptionValue "$@")
-        replace    etc/bashrc  WM_PROJECT_VERSION "$optionValue"
-        replaceCsh etc/cshrc   WM_PROJECT_VERSION "$optionValue"
+        replaceEtc     bashrc  WM_PROJECT_VERSION "$optionValue"
+        replaceEtcCsh  cshrc   WM_PROJECT_VERSION "$optionValue"
         adjusted=true
         shift
         ;;
@@ -310,32 +433,32 @@ do
         shift
         ;;
 
-    -SP | -float32)
+    -sp | -SP | -float32)
         # Replace WM_PRECISION_OPTION=...
-        replace    etc/bashrc  WM_PRECISION_OPTION "SP"
-        replaceCsh etc/cshrc   WM_PRECISION_OPTION "SP"
+        replaceEtc     bashrc  WM_PRECISION_OPTION "SP"
+        replaceEtcCsh  cshrc   WM_PRECISION_OPTION "SP"
         adjusted=true
         ;;
 
-    -DP | -float64)
+    -dp | -DP | -float64)
         # Replace WM_PRECISION_OPTION=...
-        replace    etc/bashrc  WM_PRECISION_OPTION "DP"
-        replaceCsh etc/cshrc   WM_PRECISION_OPTION "DP"
+        replaceEtc     bashrc  WM_PRECISION_OPTION "DP"
+        replaceEtcCsh  cshrc   WM_PRECISION_OPTION "DP"
         adjusted=true
         ;;
 
-    -SPDP)
+    -spdp | -SPDP)
         # Replace WM_PRECISION_OPTION=...
-        replace    etc/bashrc  WM_PRECISION_OPTION "SPDP"
-        replaceCsh etc/cshrc   WM_PRECISION_OPTION "SPDP"
+        replaceEtc     bashrc  WM_PRECISION_OPTION "SPDP"
+        replaceEtcCsh  cshrc   WM_PRECISION_OPTION "SPDP"
         adjusted=true
         ;;
 
     -int32 | -int64)
         # Replace WM_LABEL_SIZE=...
         optionValue="${1#-int}"
-        replace    etc/bashrc  WM_LABEL_SIZE "$optionValue"
-        replaceCsh etc/cshrc   WM_LABEL_SIZE "$optionValue"
+        replaceEtc     bashrc  WM_LABEL_SIZE "$optionValue"
+        replaceEtcCsh  cshrc   WM_LABEL_SIZE "$optionValue"
         adjusted=true
         ;;
 
@@ -345,8 +468,8 @@ do
     -clang)
         # Replace default_clang_version=...
         optionValue=$(getOptionValue "$@")
-        replace etc/config.sh/compiler   default_clang_version "$optionValue"
-        replace etc/config.csh/compiler  default_clang_version "$optionValue"
+        replaceEtc  config.sh/compiler   default_clang_version "$optionValue"
+        replaceEtc  config.csh/compiler  default_clang_version "$optionValue"
         adjusted=true
         shift
         ;;
@@ -354,32 +477,32 @@ do
     -gcc)
         # Replace default_gcc_version=...
         optionValue=$(getOptionValue "$@")
-        replace etc/config.sh/compiler   default_gcc_version "$optionValue"
-        replace etc/config.csh/compiler  default_gcc_version "$optionValue"
+        replaceEtc  config.sh/compiler   default_gcc_version "$optionValue"
+        replaceEtc  config.csh/compiler  default_gcc_version "$optionValue"
         adjusted=true
         shift
         ;;
 
-    -system)
+    -system-compiler | -system)
         # Replace WM_COMPILER_TYPE=... and WM_COMPILER=...
         optionValue=$(getOptionValue "$@")
-        replace etc/bashrc  \
+        replaceEtc  bashrc  \
             WM_COMPILER_TYPE system \
             WM_COMPILER "$optionValue"
-        replaceCsh etc/cshrc \
+        replaceEtcCsh  cshrc \
             WM_COMPILER_TYPE system \
             WM_COMPILER "$optionValue"
         adjusted=true
         shift
         ;;
 
-    -third | -ThirdParty)
+    -third-compiler | -third | -ThirdParty)
         # Replace WM_COMPILER_TYPE=... and WM_COMPILER=...
         optionValue=$(getOptionValue "$@")
-        replace etc/bashrc  \
+        replaceEtc  bashrc  \
             WM_COMPILER_TYPE ThirdParty \
             WM_COMPILER "$optionValue"
-        replaceCsh etc/cshrc  \
+        replaceEtcCsh  cshrc  \
             WM_COMPILER_TYPE ThirdParty \
             WM_COMPILER "$optionValue"
         adjusted=true
@@ -388,22 +511,22 @@ do
 
     gmp-[4-9]* | gmp-system)
         # gcc-related package
-        replace etc/config.sh/compiler   default_gmp_version "$1"
-        replace etc/config.csh/compiler  default_gmp_version "$1"
+        replaceEtc  config.sh/compiler   default_gmp_version "$1"
+        replaceEtc  config.csh/compiler  default_gmp_version "$1"
         adjusted=true
         ;;
 
     mpfr-[2-9]* | mpfr-system)
         # gcc-related package
-        replace etc/config.sh/compiler   default_mpfr_version "$1"
-        replace etc/config.csh/compiler  default_mpfr_version "$1"
+        replaceEtc  config.sh/compiler   default_mpfr_version "$1"
+        replaceEtc  config.csh/compiler  default_mpfr_version "$1"
         adjusted=true
         ;;
 
     mpc-[0-9]* | mpc-system)
         # gcc-related package
-        replace etc/config.sh/compiler   default_mpc_version "$1"
-        replace etc/config.csh/compiler  default_mpc_version "$1"
+        replaceEtc  config.sh/compiler   default_mpc_version "$1"
+        replaceEtc  config.csh/compiler  default_mpc_version "$1"
         adjusted=true
         ;;
 
@@ -413,8 +536,8 @@ do
     -mpi)
         # Explicitly set WM_MPLIB=...
         optionValue=$(getOptionValue "$@")
-        replace    etc/bashrc  WM_MPLIB "$optionValue"
-        replaceCsh etc/bashrc  WM_MPLIB "$optionValue"
+        replaceEtc     bashrc  WM_MPLIB "$optionValue"
+        replaceEtcCsh  cshrc   WM_MPLIB "$optionValue"
         optMpi=system
         adjusted=true
         shift
@@ -429,34 +552,34 @@ do
         _matches "$optMpi" "$expected" || \
             die "'$1' has bad value: '$optMpi'"
 
-        _inlineSed etc/config.sh/mpi \
+        _inlineSed  $(_foamEtc config.sh/mpi) \
             "FOAM_MPI=$expected" \
             "FOAM_MPI=$optMpi" \
-            "Replaced 'FOAM_MPI=$expected' setting by 'FOAM_MPI=$optMpi'"
+            "Replaced 'FOAM_MPI=$expected' by 'FOAM_MPI=$optMpi'"
 
-        _inlineSed etc/config.csh/mpi \
+        _inlineSed  $(_foamEtc config.csh/mpi) \
             "FOAM_MPI $expected" \
             "FOAM_MPI $optMpi" \
-            "Replaced 'FOAM_MPI $expected' setting by 'FOAM_MPI $optMpi'"
+            "Replaced 'FOAM_MPI $expected' by 'FOAM_MPI $optMpi'"
 
-        replace    etc/bashrc  WM_MPLIB OPENMPI
-        replaceCsh etc/cshrc   WM_MPLIB OPENMPI
+        replaceEtc     bashrc  WM_MPLIB OPENMPI
+        replaceEtcCsh  cshrc   WM_MPLIB OPENMPI
         adjusted=true
         shift
         ;;
 
     -openmpi-system)
         # Explicitly set WM_MPLIB=SYSTEMOPENMPI
-        replace    etc/bashrc  WM_MPLIB SYSTEMOPENMPI
-        replaceCsh etc/cshrc   WM_MPLIB SYSTEMOPENMPI
+        replaceEtc     bashrc  WM_MPLIB SYSTEMOPENMPI
+        replaceEtcCsh  cshrc   WM_MPLIB SYSTEMOPENMPI
         optMpi=system
         adjusted=true
         ;;
 
     -openmpi-third)
         # Explicitly set WM_MPLIB=OPENMPI, using default setting for openmpi
-        replace    etc/bashrc  WM_MPLIB OPENMPI
-        replaceCsh etc/cshrc   WM_MPLIB OPENMPI
+        replaceEtc     bashrc  WM_MPLIB OPENMPI
+        replaceEtcCsh  cshrc   WM_MPLIB OPENMPI
         optMpi=third
         adjusted=true
         ;;
@@ -464,11 +587,29 @@ do
 
 ## Components ##
 
+    -adios | -adios2)
+        # Replace adios2_version=...
+        optionValue=$(getOptionValue "$@")
+        replaceEtc  config.sh/adios2   adios2_version "$optionValue"
+        replaceEtc  config.csh/adios2  adios2_version "$optionValue"
+        adjusted=true
+        shift
+        ;;
+
+    -adios-path | -adios2-path)
+        # Replace ADIOS2_ARCH_PATH=...
+        optionValue=$(getOptionValue "$@")
+        replaceEtc     config.sh/adios2   ADIOS2_ARCH_PATH "\"$optionValue\""
+        replaceEtcCsh  config.csh/adios2  ADIOS2_ARCH_PATH "\"$optionValue\""
+        adjusted=true
+        shift
+        ;;
+
     -boost)
         # Replace boost_version=...
         optionValue=$(getOptionValue "$@")
-        replace etc/config.sh/CGAL   boost_version "$optionValue"
-        replace etc/config.csh/CGAL  boost_version "$optionValue"
+        replaceEtc  config.sh/CGAL   boost_version "$optionValue"
+        replaceEtc  config.csh/CGAL  boost_version "$optionValue"
         adjusted=true
         shift
         ;;
@@ -476,8 +617,8 @@ do
     -boost-path)
         # Replace BOOST_ARCH_PATH=...
         optionValue=$(getOptionValue "$@")
-        replace    etc/config.sh/CGAL   BOOST_ARCH_PATH "\"$optionValue\""
-        replaceCsh etc/config.csh/CGAL  BOOST_ARCH_PATH "\"$optionValue\""
+        replaceEtc     config.sh/CGAL   BOOST_ARCH_PATH "\"$optionValue\""
+        replaceEtcCsh  config.csh/CGAL  BOOST_ARCH_PATH "\"$optionValue\""
         adjusted=true
         shift
         ;;
@@ -485,8 +626,8 @@ do
     -cgal)
         # Replace cgal_version=...
         optionValue=$(getOptionValue "$@")
-        replace etc/config.sh/CGAL   cgal_version "$optionValue"
-        replace etc/config.csh/CGAL  cgal_version "$optionValue"
+        replaceEtc  config.sh/CGAL   cgal_version "$optionValue"
+        replaceEtc  config.csh/CGAL  cgal_version "$optionValue"
         adjusted=true
         shift
         ;;
@@ -494,8 +635,8 @@ do
     -cgal-path)
         # Replace CGAL_ARCH_PATH=...
         optionValue=$(getOptionValue "$@")
-        replace    etc/config.sh/CGAL   CGAL_ARCH_PATH "$optionValue"
-        replaceCsh etc/config.csh/CGAL  CGAL_ARCH_PATH "$optionValue"
+        replaceEtc     config.sh/CGAL   CGAL_ARCH_PATH "$optionValue"
+        replaceEtcCsh  config.csh/CGAL  CGAL_ARCH_PATH "$optionValue"
         adjusted=true
         shift
         ;;
@@ -503,8 +644,8 @@ do
     -fftw)
         # Replace fftw_version=...
         optionValue=$(getOptionValue "$@")
-        replace etc/config.sh/FFTW   fftw_version "$optionValue"
-        replace etc/config.csh/FFTW  fftw_version "$optionValue"
+        replaceEtc  config.sh/FFTW   fftw_version "$optionValue"
+        replaceEtc  config.csh/FFTW  fftw_version "$optionValue"
         adjusted=true
         shift
         ;;
@@ -512,8 +653,8 @@ do
     -fftw-path)
         # Replace FFTW_ARCH_PATH=...
         optionValue=$(getOptionValue "$@")
-        replace    etc/config.sh/FFTW   FFTW_ARCH_PATH "\"$optionValue\""
-        replaceCsh etc/config.csh/FFTW  FFTW_ARCH_PATH "\"$optionValue\""
+        replaceEtc     config.sh/FFTW   FFTW_ARCH_PATH "\"$optionValue\""
+        replaceEtcCsh  config.csh/FFTW  FFTW_ARCH_PATH "\"$optionValue\""
         adjusted=true
         shift
         ;;
@@ -521,8 +662,8 @@ do
     -cmake)
         # Replace cmake_version=...
         optionValue=$(getOptionValue "$@")
-        replace etc/config.sh/paraview   cmake_version "$optionValue"
-        replace etc/config.csh/paraview  cmake_version "$optionValue"
+        replaceEtc  config.sh/paraview   cmake_version "$optionValue"
+        replaceEtc  config.csh/paraview  cmake_version "$optionValue"
         adjusted=true
         shift
         ;;
@@ -530,7 +671,7 @@ do
     -kahip)
         # Replace KAHIP_VERSION=...
         optionValue=$(getOptionValue "$@")
-        replace etc/config.sh/kahip  KAHIP_VERSION "$optionValue"
+        replaceEtc  config.sh/kahip  KAHIP_VERSION "$optionValue"
         adjusted=true
         shift
         ;;
@@ -538,7 +679,7 @@ do
     -kahip-path)
         # Replace KAHIP_ARCH_PATH=...
         optionValue=$(getOptionValue "$@")
-        replace etc/config.sh/kahip  KAHIP_ARCH_PATH "\"$optionValue\""
+        replaceEtc  config.sh/kahip  KAHIP_ARCH_PATH "\"$optionValue\""
         adjusted=true
         shift
         ;;
@@ -546,7 +687,7 @@ do
     -metis)
         # Replace METIS_VERSION=...
         optionValue=$(getOptionValue "$@")
-        replace etc/config.sh/metis  METIS_VERSION "$optionValue"
+        replaceEtc  config.sh/metis  METIS_VERSION "$optionValue"
         adjusted=true
         shift
         ;;
@@ -554,7 +695,7 @@ do
     -metis-path)
         # Replace METIS_ARCH_PATH=...
         optionValue=$(getOptionValue "$@")
-        replace etc/config.sh/metis  METIS_ARCH_PATH "\"$optionValue\""
+        replaceEtc  config.sh/metis  METIS_ARCH_PATH "\"$optionValue\""
         adjusted=true
         shift
         ;;
@@ -562,7 +703,7 @@ do
     -scotch | -scotchVersion | --scotchVersion)
         # Replace SCOTCH_VERSION=...
         optionValue=$(getOptionValue "$@")
-        replace etc/config.sh/scotch  SCOTCH_VERSION "$optionValue"
+        replaceEtc  config.sh/scotch  SCOTCH_VERSION "$optionValue"
         adjusted=true
         shift
         ;;
@@ -570,7 +711,7 @@ do
     -scotch-path | -scotchArchPath | --scotchArchPath)
         # Replace SCOTCH_ARCH_PATH=...
         optionValue=$(getOptionValue "$@")
-        replace etc/config.sh/scotch  SCOTCH_ARCH_PATH "\"$optionValue\""
+        replaceEtc  config.sh/scotch  SCOTCH_ARCH_PATH "\"$optionValue\""
         adjusted=true
         shift
         ;;
@@ -585,8 +726,8 @@ do
         _matches "$optionValue" "$expected" || \
             [ "$optionValue" != "${optionValue%system}" ] || \
             die "'$1' has bad value: '$optionValue'"
-        replace etc/config.sh/paraview   ParaView_VERSION "$optionValue"
-        replace etc/config.csh/paraview  ParaView_VERSION "$optionValue"
+        replaceEtc  config.sh/paraview   ParaView_VERSION "$optionValue"
+        replaceEtc  config.csh/paraview  ParaView_VERSION "$optionValue"
         adjusted=true
         shift
         ;;
@@ -594,8 +735,8 @@ do
     -paraview-qt)
         # Replace ParaView_QT=...
         optionValue=$(getOptionValue "$@")
-        replace etc/config.sh/paraview   ParaView_QT "$optionValue"
-        replace etc/config.csh/paraview  ParaView_QT "$optionValue"
+        replaceEtc  config.sh/paraview   ParaView_QT "$optionValue"
+        replaceEtc  config.csh/paraview  ParaView_QT "$optionValue"
         adjusted=true
         shift
         ;;
@@ -603,17 +744,17 @@ do
     -paraview-path | -paraviewInstall | --paraviewInstall)
         # Replace ParaView_DIR=...
         optionValue=$(getOptionValue "$@")
-        replace    etc/config.sh/paraview   ParaView_DIR \""$optionValue\""
-        replaceCsh etc/config.csh/paraview  ParaView_DIR \""$optionValue\""
+        replaceEtc     config.sh/paraview   ParaView_DIR \""$optionValue\""
+        replaceEtcCsh  config.csh/paraview  ParaView_DIR \""$optionValue\""
         adjusted=true
         shift
         ;;
 
-    -vtk)
-        # Replace vtk_version=...
+    -llvm)
+        # Replace mesa_llvm=...
         optionValue=$(getOptionValue "$@")
-        replace etc/config.sh/vtk   vtk_version "$optionValue"
-        replace etc/config.csh/vtk  vtk_version "$optionValue"
+        replaceEtc  config.sh/vtk   mesa_llvm "$optionValue"
+        replaceEtc  config.csh/vtk  mesa_llvm "$optionValue"
         adjusted=true
         shift
         ;;
@@ -621,8 +762,44 @@ do
     -mesa)
         # Replace mesa_version=...
         optionValue=$(getOptionValue "$@")
-        replace etc/config.sh/vtk   mesa_version "$optionValue"
-        replace etc/config.csh/vtk  mesa_version "$optionValue"
+        replaceEtc  config.sh/vtk   mesa_version "$optionValue"
+        replaceEtc  config.csh/vtk  mesa_version "$optionValue"
+        adjusted=true
+        shift
+        ;;
+
+    -vtk)
+        # Replace vtk_version=...
+        optionValue=$(getOptionValue "$@")
+        replaceEtc  config.sh/vtk   vtk_version "$optionValue"
+        replaceEtc  config.csh/vtk  vtk_version "$optionValue"
+        adjusted=true
+        shift
+        ;;
+
+    -llvm-path)
+        # Replace LLVM_ARCH_PATH=...
+        optionValue=$(getOptionValue "$@")
+        replaceEtc     config.sh/vtk   LLVM_ARCH_PATH \""$optionValue\""
+        replaceEtcCsh  config.csh/vtk  LLVM_ARCH_PATH \""$optionValue\""
+        adjusted=true
+        shift
+        ;;
+
+    -mesa-path)
+        # Replace MESA_ARCH_PATH...
+        optionValue=$(getOptionValue "$@")
+        replaceEtc     config.sh/vtk   MESA_ARCH_PATH \""$optionValue\""
+        replaceEtcCsh  config.csh/vtk  MESA_ARCH_PATH \""$optionValue\""
+        adjusted=true
+        shift
+        ;;
+
+    -vtk-path)
+        # Replace VTK_DIR...
+        optionValue=$(getOptionValue "$@")
+        replaceEtc     config.sh/vtk   VTK_DIR \""$optionValue\""
+        replaceEtcCsh  config.csh/vtk  VTK_DIR \""$optionValue\""
         adjusted=true
         shift
         ;;
diff --git a/bin/tools/openfoam b/bin/tools/openfoam
deleted file mode 100755
index bae80e12afc..00000000000
--- a/bin/tools/openfoam
+++ /dev/null
@@ -1,193 +0,0 @@
-#!/bin/bash
-#------------------------------------------------------------------------------
-# =========                 |
-# \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-#  \\    /   O peration     |
-#   \\  /    A nd           | www.openfoam.com
-#    \\/     M anipulation  |
-#------------------------------------------------------------------------------
-#     Copyright (C) 2019 OpenCFD Ltd.
-#------------------------------------------------------------------------------
-# License
-#     This file is part of OpenFOAM, licensed under GNU General Public License
-#     <http://www.gnu.org/licenses/>.
-#
-# Script
-#     openfoam [args]
-#
-# Description
-#     Open an interactive bash session with an OpenFOAM environment,
-#     or run an OpenFOAM application (with arguments) after first sourcing
-#     the OpenFOAM etc/bashrc file from the project directory.
-#
-#     This script normally exists in $WM_PROJECT_DIR/bin/tools but can also
-#     be modified to use a hard-coded PROJECT_DIR entry and placed elsewhere
-#     in the filesystem (eg, /usr/bin).
-#
-#------------------------------------------------------------------------------
-# Hard-coded value (eg, with autoconfig)
-projectDir="@PROJECT_DIR@"
-
-if [ -z "$projectDir" ] || [ "${projectDir#@}" != "$projectDir" ]
-then
-    # Auto-detect from location
-    toolsDir="${0%/*}"                              # The bin/tools dir
-    projectDir="${toolsDir%/bin/tools}"             # Project dir
-
-    case "$projectDir" in
-        (/bin | /usr/bin | /usr/local/bin)
-        # This shouldn't happen.
-        # If copied to a system dir, should also be using hard-coded values!
-        echo "Warning: suspicious looking project dir: $projectDir" 1>&2
-        ;;
-
-        ("$toolsDir")
-        # Eg, called as ./openfoam etc - need to try harder
-        projectDir="$(\cd $(dirname $0)/../.. && \pwd -L)" || unset projectDir
-        ;;
-    esac
-fi
-
-#------------------------------------------------------------------------------
-usage() {
-    exec 1>&2
-    while [ "$#" -ge 1 ]; do echo "$1"; shift; done
-    cat<<USAGE
-
-Usage: ${0##*/} [OPTION] [application ...]
-
-options:
-  -prefix=DIR       Specify alternative OpenFOAM directory
-  -sp               Single precision
-  -dp               Double precision
-  -spdp             Mixed single/double precision
-  -int32 | -int64   The label-size
-  -help             Print the usage
-
-Open an interactive bash session with an OpenFOAM environment,
-or run an OpenFOAM application (with arguments) after first sourcing
-the OpenFOAM etc/bashrc file from the project directory:
-($projectDir)
-
-For more information: www.OpenFOAM.com
-
-USAGE
-    exit 1
-}
-
-
-#-------------------------------------------------------------------------------
-
-# Only preserve settings for non-interactive?
-
-if [ "$#" -eq 0 ]
-then
-    unset _foamSettings FOAM_SETTINGS
-else
-    _foamSettings="$FOAM_SETTINGS"
-fi
-
-
-# Parse options
-while [ "$#" -gt 0 ]
-do
-    case "$1" in
-    -h | -help*)
-        usage
-        ;;
-    -prefix=* | -foam=*)
-        projectDir="${1#*=}"
-        ;;
-
-    -sp | -SP)
-        # WM_PRECISION_OPTION=...
-        _foamSettings="$_foamSettings${_foamSettings:+ }WM_PRECISION_OPTION=SP"
-        ;;
-
-    -dp | -DP)
-        # WM_PRECISION_OPTION=...
-        _foamSettings="$_foamSettings${_foamSettings:+ }WM_PRECISION_OPTION=DP"
-        ;;
-
-    -spdp | -SPDP)
-        # WM_PRECISION_OPTION=...
-        _foamSettings="$_foamSettings${_foamSettings:+ }WM_PRECISION_OPTION=SPDP"
-        ;;
-
-    -int32 | -int64)
-        # WM_LABEL_SIZE=...
-        _foamSettings="$_foamSettings${_foamSettings:+ }WM_LABEL_SIZE=${1#-int}"
-        ;;
-
-    --)
-        shift
-        break
-        ;;
-    -*)
-        echo "Error: unknown option: '$1'" 1>&2
-        exit 1
-        ;;
-    *)
-        break
-        ;;
-    esac
-    shift
-done
-
-#-------------------------------------------------------------------------------
-
-# Remove current OpenFOAM environment
-if [ -d "$WM_PROJECT_DIR" ] && [ -f "$WM_PROJECT_DIR/etc/config.sh/unset" ]
-then
-    . "$WM_PROJECT_DIR/etc/config.sh/unset"
-fi
-
-[ -d "$projectDir" ] || {
-    echo "Error: no project dir: $projectDir" 1>&2
-    exit 2
-}
-
-_foamSourceBashEnv="$projectDir/etc/bashrc"
-
-if [ "$#" -eq 0 ]
-then
-    # Interactive shell
-    _foamSourceBashEnv="$projectDir/bin/tools/source-bashrc"
-fi
-
-[ -f "$_foamSourceBashEnv" ] || {
-    echo "Error: file not found: $_foamSourceBashEnv" 1>&2
-    exit 2
-}
-
-if [ "$#" -eq 0 ]
-then
-    # Source user ~/.bashrc and OpenFOAM etc/bashrc.
-    # 1) Can either use a tmp file, or 2) chain off to a dedicated file
-    # We use a dedicated file.
-
-    if [ -n "$_foamSettings" ]
-    then
-        export FOAM_SETTINGS="$_foamSettings"
-    fi
-
-    ## echo "Source with $_foamSourceBashEnv with '$FOAM_SETTINGS'" 1>&2
-
-    # Interactive shell (newer bash can use --init-file instead of --rcfile)
-    exec bash --rcfile "$_foamSourceBashEnv" -i
-
-else
-    # Non-interactive
-
-    # Source bashrc within a function to preserve command-line arguments
-    # - this will not have aliases, but working non-interactively anyhow
-    sourceBashrc()
-    {
-        . "$_foamSourceBashEnv" $_foamSettings
-    }
-
-    sourceBashrc
-    exec "$@"
-fi
-
-#------------------------------------------------------------------------------
diff --git a/bin/tools/openfoam.in b/bin/tools/openfoam.in
new file mode 100644
index 00000000000..d712512d0c7
--- /dev/null
+++ b/bin/tools/openfoam.in
@@ -0,0 +1,19 @@
+#!/bin/sh
+exec "@PROJECT_DIR@"/etc/openfoam "$@"
+#------------------------------------------------------------------------------
+# =========                 |
+# \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+#  \\    /   O peration     |
+#   \\  /    A nd           | www.openfoam.com
+#    \\/     M anipulation  |
+#------------------------------------------------------------------------------
+#     Copyright (C) 2020 OpenCFD Ltd.
+#------------------------------------------------------------------------------
+# License
+#     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
+#
+# Description
+#     Forwarding to OpenFOAM etc/openfoam bash session script.
+#     Uses a hard-code directory path (eg, generated with autoconfig).
+#
+#------------------------------------------------------------------------------
diff --git a/doc/modules/README b/doc/modules/README
new file mode 100644
index 00000000000..0d4c4030615
--- /dev/null
+++ b/doc/modules/README
@@ -0,0 +1 @@
+Modules-related documents when collated for an installation package.
diff --git a/doc/openfoam.1.in b/doc/openfoam.1.in
new file mode 100644
index 00000000000..2dbdac04bb6
--- /dev/null
+++ b/doc/openfoam.1.in
@@ -0,0 +1,70 @@
+.TH "OPENFOAM" 1 "OpenFOAM-version" "www.openfoam.com" "OpenFOAM Commands Manual"
+
+.SH NAME
+openfoam \- OpenFOAM bash(1) session
+
+.SH SYNOPSIS
+\fBopenfoam\fR [\fIOPTIONS\fR] [\fIapplication ...\fR]
+
+.SH DESCRIPTION
+Activate an \fBOpenFOAM\fR environment in an interactive or
+non-interactive bash(1) session.
+
+If no application is given, an interactive bash session will be used.
+If an application (optionally with arguments) is provided, the
+OpenFOAM \fIetc/bashrc\fR file will be sourced from the project directory
+prior to running the application.
+
+.SH OPTIONS
+.TP
+\fB\-c\fR \fIcommand\fR
+Execute shell commands with OpenFOAM environment
+.TP
+\fB\-D\fR\fIkey=[value]\fR
+Define key/value to pass as a preference
+.TP
+\fB\-sp\fR
+Use single precision for scalar-size
+.TP
+\fB\-dp\fR
+Use double precision for scalar-size
+.TP
+\fB\-spdp\fR
+Use single precision for scalar-size, double for solve-scalar size
+.TP
+\fB\-int32\fR
+Use 32-bit label-size
+.TP
+\fB\-int64\fR
+Use 64-bit label-size
+.TP
+\fB\-prefix=DIR\fR
+Specify alternative OpenFOAM project directory
+.TP
+\fB\-show-api\fR | \fB\-version\fR
+Print META-INFO api value and exit
+.TP
+\fB\-show-patch\fR
+Print META-INFO patch value and exit
+.TP
+\fB\-show-prefix\fR
+Print project directory and exit
+.TP
+\fB\-help\fR
+Print the usage
+
+.SH ARGUMENTS
+
+If arguments remain after option processing, the first argument is
+assumed to be an application with options and arguments.
+
+.SH FILES
+
+The \fIetc/bashrc\fR file from the OpenFOAM project directory supplies
+the environment settings.
+
+.SH "SEE ALSO"
+Online documentation https://www.openfoam.com/documentation/
+
+.SH COPYRIGHT
+Copyright \(co 2020 OpenCFD Ltd.
diff --git a/etc/config.sh/gperftools b/etc/config.sh/gperftools
index bf8ca42bb11..ea58dc58eab 100644
--- a/etc/config.sh/gperftools
+++ b/etc/config.sh/gperftools
@@ -9,12 +9,11 @@
 #     Copyright (C) 2016-2018 OpenCFD Ltd.
 #------------------------------------------------------------------------------
 # License
-#     This file is part of OpenFOAM, licensed under GNU General Public License
-#     <http://www.gnu.org/licenses/>.
+#     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
 #
 # File
 #     etc/config.sh/gperftools
-#     - sourced by OpenFOAM-*/etc/bashrc
+#     Not normally sourced by OpenFOAM-*/etc/bashrc
 #
 # Description
 #     Setup file for GPERFTOOLS binaries/libraries.
@@ -48,7 +47,7 @@ then
     echo "Using gperftools ($gperftools_version)  ->  $GPERFTOOLS_ARCH_PATH" 1>&2
 fi
 
-if command -v _foamAddLib > /dev/null 2>&1      # Normal sourcing
+if command -v _foamAddLib >/dev/null  # Normal sourcing
 then
 
     # If GPERFTOOLS_ARCH_PATH does not end with '-system' or '-none',
diff --git a/etc/config.sh/setup b/etc/config.sh/setup
index 79e8ff6fcfd..debd396ac2d 100644
--- a/etc/config.sh/setup
+++ b/etc/config.sh/setup
@@ -121,7 +121,6 @@ _foamEtc -config  settings
 _foamEtc -config  mpi
 _foamEtc -config  paraview -- "$@"  # Pass through for evaluation
 _foamEtc -config  vtk
-_foamEtc -config  gperftools
 ## _foamEtc -config  ADIOS
 ## _foamEtc -config  ADIOS2
 _foamEtc -config  CGAL
diff --git a/etc/openfoam b/etc/openfoam
new file mode 100755
index 00000000000..6db02bc6883
--- /dev/null
+++ b/etc/openfoam
@@ -0,0 +1,301 @@
+#!/bin/bash
+#------------------------------------------------------------------------------
+# =========                 |
+# \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+#  \\    /   O peration     |
+#   \\  /    A nd           | www.openfoam.com
+#    \\/     M anipulation  |
+#------------------------------------------------------------------------------
+#     Copyright (C) 2019-2020 OpenCFD Ltd.
+#------------------------------------------------------------------------------
+# License
+#     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
+#
+# Script
+#     openfoam [options] [args]
+#
+# Description
+#     Open an interactive bash session with an OpenFOAM environment,
+#     or run an OpenFOAM application (with arguments) after first sourcing
+#     the OpenFOAM etc/bashrc file from the project directory.
+#
+# Note
+#     This script normally exists in the $WM_PROJECT_DIR/etc/ directory.
+#     Do not copy/move/link to other locations. Use instead an edited copy of
+#     `bin/tools/openfoam.in` with a hard-coded projectDir entry.
+#
+#     See OpenFOAM etc/bashrc for (command-line) preferences.
+#     Some equivalent settings:
+#       -sp     | -DWM_PRECISION_OPTION=SP
+#       -dp     | -DWM_PRECISION_OPTION=DP
+#       -int32  | -DWM_LABEL_SIZE=32
+#       -int64  | -DWM_LABEL_SIZE=64
+#
+#     However, the '-D' options grant more flexibility. For example,
+#         etc/openfoam -DWM_COMPILER=Clang
+#
+#------------------------------------------------------------------------------
+# Auto-detect from location. Do not call from within the etc/directory itself!
+projectDir="$(\cd "$(dirname "${0%/*}")" && \pwd -L)"
+
+#------------------------------------------------------------------------------
+printHelp() {
+    cat<<USAGE
+
+Usage: ${0##*/} [OPTION] [application ...]
+
+options:
+  -c command            Execute shell commands with OpenFOAM environment
+  -Dkey[=value]         Define key/value to pass as a preference
+  -sp                   Single precision
+  -dp                   Double precision
+  -spdp                 Mixed single/double precision
+  -int32 | -int64       The label-size
+  -etc=DIR              Additional project etc/ directory
+  -prefix=DIR           Alternative OpenFOAM project directory
+  -show-api | -version  Print META-INFO api value and exit
+  -show-patch           Print META-INFO patch value and exit
+  -show-prefix          Print project directory and exit
+  -test-tutorial        Forward arguments to tutorials/AutoTest
+  -verbose              Set FOAM_VERBOSE=true (interactive only)
+  -help                 Print the usage
+
+Open an interactive bash session with an OpenFOAM environment,
+or run an OpenFOAM application (with arguments) after first sourcing
+the OpenFOAM etc/bashrc file from the project directory:
+($projectDir)
+
+For more information: www.openfoam.com
+
+USAGE
+    exit 0 # A clean exit
+}
+
+
+#-------------------------------------------------------------------------------
+
+# Get a value from META-INFO/api-info
+# $1 : keyword
+getApiInfo()
+{
+    value="$(sed -ne 's@^'"$1"' *= *\([0-9][0-9]*\).*@\1@p' "$projectDir"/META-INFO/api-info 2>/dev/null)"
+
+    if [ -n "$value" ]
+    then
+        echo "$value"
+    else
+        echo "Could not determine OPENFOAM '$1' value" 1>&2
+        return 1
+    fi
+}
+
+#-------------------------------------------------------------------------------
+
+# No inheritance of FOAM_SETTINGS
+unset FOAM_SETTINGS
+unset _foamEtcDir _foamSettings _foamScriptCommand
+unset optTestTut
+
+# Parse options
+while [ "$#" -gt 0 ]
+do
+    case "$1" in
+    -h | -help* | --help*)
+        printHelp
+        ;;
+    -show-api | -version | --version)  # Show API and exit
+        getApiInfo api
+        exit $?
+        ;;
+    -show-patch)  # Show patch level and exit
+        getApiInfo patch
+        exit $?
+        ;;
+    -show-prefix)  # Show project directory and exit
+        echo "$projectDir"
+        exit $?
+        ;;
+
+    -test-tutorial)  # Run tutorials/AutoTest
+        optTestTut=true
+        ;;
+
+    -c)  # Shell command
+        _foamScriptCommand="$2"
+        [ -n "$_foamScriptCommand" ] || {
+            echo "$0: missing or bad command argument: $2" 1>&2
+            exit 1
+        }
+        shift 2
+        break
+        ;;
+
+    -D*)  # Define key/value to pass as preference
+        setting="${1#-D}"
+        if [ -n "$setting" ]
+        then
+            _foamSettings="$_foamSettings${_foamSettings:+ }$setting"
+        fi
+        ;;
+
+    -sp | -dp | -spdp )
+        # WM_PRECISION_OPTION=(SP|DP|SPDP)
+        setting=$(echo "${1#-}" | sed -e 's/-//g;y/sdp/SDP/')
+        _foamSettings="$_foamSettings${_foamSettings:+ }WM_PRECISION_OPTION=$setting"
+        ;;
+
+    -int32 | -int64)
+        # WM_LABEL_SIZE=...
+        _foamSettings="$_foamSettings${_foamSettings:+ }WM_LABEL_SIZE=${1#-int}"
+        ;;
+
+    -etc=*)
+        # Define FOAM_CONFIG_ETC for finding files
+        _foamEtcDir="${1#*=}"
+        ;;
+
+    -prefix=*)
+        projectDir="${1#*=}"
+        ;;
+
+    -verbose)
+        export FOAM_VERBOSE=true
+        ;;
+
+    --)
+        shift
+        break
+        ;;
+    -*)
+        echo "$0: unknown option: '$1'" 1>&2
+        exit 1
+        ;;
+    *)
+        break
+        ;;
+    esac
+    shift
+done
+
+#-------------------------------------------------------------------------------
+
+# Sanity check (installed under /bin, /usr/bin, /usr/local/bin)
+# This should not happen.
+# If copied to a system dir, should also be using hard-coded values!
+
+if [ "${projectDir%/bin}" != "$projectDir" ]
+then
+    echo "Warning: suspicious project dir: $projectDir" 1>&2
+fi
+
+[ -d "$projectDir/META-INFO" ] || {
+    echo "Warning: missing META-INFO in OpenFOAM directory:" 1>&2
+    echo "    $projectDir" 1>&2
+}
+
+
+# Remove current OpenFOAM environment
+if [ -d "$WM_PROJECT_DIR" ] && [ -f "$WM_PROJECT_DIR/etc/config.sh/unset" ]
+then
+    . "$WM_PROJECT_DIR/etc/config.sh/unset" || true
+fi
+
+unset interactive
+
+if [ "$#" -eq 0 ] && [ -z "$_foamScriptCommand" ] && [ -z "$optTestTut" ]
+then
+    # Interactive shell, chain off via a file
+    interactive=true
+    _foamSourceBashEnv="$projectDir/bin/tools/source-bashrc"
+else
+    # Non-interactive shell, use the OPENFOAM etc/bashrc
+    _foamSourceBashEnv="$projectDir/etc/bashrc"
+fi
+
+[ -f "$_foamSourceBashEnv" ] || {
+    echo "Error: file not found: $_foamSourceBashEnv" 1>&2
+    exit 2
+}
+
+if [ -n "$_foamEtcDir" ] && [ -d "$_foamEtcDir" ]
+then
+    # Additional etc directory
+    export FOAM_CONFIG_ETC="$_foamEtcDir"
+else
+    unset FOAM_CONFIG_ETC
+fi
+
+if [ -n "$interactive" ]
+then
+    # Interactive shell
+    # -----------------
+
+    # Source ~/.bashrc and OpenFOAM etc/bashrc in one of two ways:
+    #   1) Generate and use a tmp file
+    #   2) Chain off to a dedicated file  [This is what we use]
+
+    if [ -n "$_foamSettings" ]
+    then
+        # Pass preferences via the FOAM_SETTINGS mechanism
+        export FOAM_SETTINGS="$_foamSettings"
+    fi
+
+    ## echo "Source with $_foamSourceBashEnv with '$FOAM_SETTINGS'" 1>&2
+
+    # Newer bash can use --init-file instead of --rcfile
+    exec bash --rcfile "$_foamSourceBashEnv" -i
+    exit $? # Safety
+fi
+
+
+# Non-interactive shell
+# ---------------------
+
+# Source bashrc within a function to preserve command-line arguments
+# Suppresses aliases as a side-effect, but non-interactive anyhow.
+sourceBashrc()
+{
+    . "$_foamSourceBashEnv" $_foamSettings
+}
+
+
+if [ -n "$_foamScriptCommand" ]
+then
+    # A shell command
+
+    sourceBashrc
+    exec bash -c "$_foamScriptCommand" "$@"
+    exit $? # Safety
+fi
+
+
+if [ -n "$optTestTut" ]
+then
+
+    sourceBashrc
+    exec "$WM_PROJECT_DIR/tutorials/AutoTest" "$@"
+    exit $? # Safety
+fi
+
+
+# An application or a shell script
+
+# It may actually be a script with a '#!/project-path/bin/openfoam',
+# so we need to catch this to avoid infinite recursion.
+if [ -f "$1" ] \
+&& [ -n "$(sed -ne '1{/^#!.*\/openfoam$/p; q}' "$1" 2>/dev/null)" ]
+then
+    # A shell script
+
+    sourceBashrc
+    exec bash "$@"
+
+else
+    # An application
+
+    sourceBashrc
+    exec "$@"
+
+fi
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/AutoTest b/tutorials/AutoTest
new file mode 100755
index 00000000000..3a3f41b66a6
--- /dev/null
+++ b/tutorials/AutoTest
@@ -0,0 +1,199 @@
+#!/bin/sh
+#------------------------------------------------------------------------------
+# =========                 |
+# \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+#  \\    /   O peration     |
+#   \\  /    A nd           | www.openfoam.com
+#    \\/     M anipulation  |
+#------------------------------------------------------------------------------
+#     Copyright (C) 2020 OpenCFD Ltd.
+#------------------------------------------------------------------------------
+# License
+#     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
+#
+# Script
+#     tutorials/AutoTest dir [.. dirN]
+#
+# Description
+#     Run foamRunTutorials with specified tutorial directories
+#     Creates/destroys a temporary directory for each test.
+#
+# Environment
+#     Requires an initialized OpenFOAM environment.
+#
+# Note
+#     Potentially useful for debian autopkgtest
+#
+#------------------------------------------------------------------------------
+# Auto-detect from location
+#Unused# projectDir="$(\cd "$(dirname "${0%/*}")" && \pwd -L)"
+
+#------------------------------------------------------------------------------
+printHelp() {
+    cat<<USAGE
+
+usage: ${0##*/} [OPTION] dir [.. dirN]
+
+options:
+  -1            Modify case controlDict to run only one time step (default)
+  -full         Do not modify controlDict (run tutorial to completion)
+  -debian       Any modifications when running with autopkgtest
+  -help         Print the usage
+
+Run foamRunTutorials with specified tutorial directories.
+Creates/destroys a temporary directory for each.
+
+USAGE
+    exit 0 # A clean exit
+}
+
+# Report error and exit
+die()
+{
+    exec 1>&2
+    echo
+    echo "Error encountered:"
+    while [ "$#" -ge 1 ]; do echo "    $1"; shift; done
+    echo
+    echo "See '${0##*/} -help' for usage"
+    echo
+    exit 1
+}
+
+#------------------------------------------------------------------------------
+
+unset optDebian optVerbose
+optRunLimit=1
+
+# Parse options
+while [ "$#" -gt 0 ]
+do
+    case "$1" in
+    -h*)
+        printHelp
+        ;;
+
+    -1)
+        optRunLimit="${1#-}"
+        ;;
+
+    -full)
+        unset optRunLimit
+        ;;
+
+    -debian)
+        # Redirect stderr to stdout, if autopkgtest (tests/control)
+        # does NOT use "Restrictions: allow-stderr"
+        exec 2>&1
+        ;;
+
+    --)
+        break
+        ;;
+
+    -*)
+        die "unknown option $1"
+        ;;
+
+    *)
+        break
+        ;;
+    esac
+    shift
+done
+
+
+#------------------------------------------------------------------------------
+# Basic sanity checks
+
+[ -n "$FOAM_TUTORIALS" ] || export FOAM_TUTORIALS="$WM_PROJECT_DIR"/tutorials
+
+[ -d "${WM_PROJECT_DIR:?}" ] || die "No OpenFOAM environment: $WM_PROJECT_DIR"
+[ -d "$FOAM_TUTORIALS" ] || die "No OpenFOAM tutorials : $FOAM_TUTORIALS"
+
+
+#------------------------------------------------------------------------------
+
+#
+# Modify case controlDicts to run only one time step
+#
+modifyCaseControlDict()
+{
+    for dict in $(find . -name "controlDict*" -type f)
+    do
+        cp -f "${dict}" "${dict}.orig"
+        sed \
+            -e 's/\(startFrom[ \t]*\)\([A-Za-z]*\);/\1 latestTime;/' \
+            -e 's/\(stopAt[ \t]*\)\([A-Za-z]*\);/\1 nextWrite;/' \
+            -e 's/\(writeControl[ \t]*\)\([A-Za-z]*\);/\1 timeStep;/' \
+            -e 's/\(writeInterval[ \t]*\)\([-.0-9A-Za-z]*\);/\1 '"$optRunLimit"';/' \
+            "${dict}.orig" > "${dict}"
+    done
+}
+
+
+#------------------------------------------------------------------------------
+
+nTests="$#"
+nPassed=0
+
+for testdir in "$@"
+do
+    testdir="${testdir#tutorials/}"
+    testdir="$(echo "$testdir" | sed -e 's@^//*@@; s@//*$@@;')"
+    suffix="$(echo "$testdir" | sed -e 's@//*@_@g')"
+
+    if [ -n "$testdir" ] && [ -d "$FOAM_TUTORIALS/$testdir" ]
+    then
+    (
+        echo "Run test: $testdir"
+        set -e
+
+        TESTDIR="$(mktemp --directory --suffix=".$suffix")"
+        trap 'rm -rf $TESTDIR' 0 INT QUIT ABRT PIPE TERM
+
+        cp -r "$FOAM_TUTORIALS/$testdir"/* "$TESTDIR"/
+        cd "$TESTDIR"
+
+        if [ -n "$optRunLimit" ]
+        then
+            set +e
+            modifyCaseControlDict
+            set -e
+        fi
+
+        nInput="$(ls | wc -l)"
+        foamRunTutorials
+        nOutput="$(ls | wc -l)"
+
+        if [ "$nInput" = 0 ]
+        then
+            echo "No input for $testdir" 1>&2
+            exit 1
+        elif [ "$nOutput" = "$nInput" ]
+        then
+            echo "Run failure for $testdir" 1>&2
+            exit 1
+        else
+            echo "run: OK"
+        fi
+    ) && nPassed=$((nPassed + 1))
+
+    else
+        echo "No tutorial: $testdir" 1>&2
+    fi
+done
+
+
+if [ "$nTests" = 0 ]
+then
+    die "No tests specified"
+elif [ "$nPassed" = "$nTests" ]
+then
+    echo "Passed all $nTests tests"
+else
+    echo "Passed $nPassed/$nTests tests" 1>&2
+    exit 1
+fi
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/modules/README b/tutorials/modules/README
new file mode 100644
index 00000000000..00e3d745906
--- /dev/null
+++ b/tutorials/modules/README
@@ -0,0 +1 @@
+Modules-related tutorials when collated for an installation package.
diff --git a/wmake/scripts/sysFunctions b/wmake/scripts/sysFunctions
index 606d9589662..4e8590841a0 100644
--- a/wmake/scripts/sysFunctions
+++ b/wmake/scripts/sysFunctions
@@ -5,11 +5,10 @@
 #   \\  /    A nd           | www.openfoam.com
 #    \\/     M anipulation  |
 #------------------------------------------------------------------------------
-#     Copyright (C) 2018-2019 OpenCFD Ltd.
+#     Copyright (C) 2018-2020 OpenCFD Ltd.
 #------------------------------------------------------------------------------
 # License
-#     This file is part of OpenFOAM, licensed under GNU General Public License
-#     <http://www.gnu.org/licenses/>.
+#     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
 #
 # Script
 #     sysFunctions
@@ -23,6 +22,7 @@
 #     findFirstFile
 #     findLibrary
 #     findExtLib
+#     versionCompare
 #
 # Internal variables used
 #     extLibraries
@@ -175,6 +175,74 @@ then
 
         return 2
     }
+
+
+    # Compare version tuples with syntax similar to POSIX shell,
+    # but respecting dot separators.
+    #
+    # arg1 OP arg2
+    #   OP is one of -eq, -ne, -lt, -le, -gt, or -ge.
+    #   Returns true for a successful comparison.
+    #   Arg1 and arg2 normally comprise positive integers, but leading content
+    #   before a '-' is stripped.
+    #   Missing digits are treated as '0'.
+    #
+    # Eg,
+    #    versionCompare "software-1.2.3" -gt 1.1 && echo True
+    #
+    # Ad hoc handling of "git" version as always newest.
+    #    "git" -gt "1.2.3" : True
+    #    "1.2.3" -lt "git" : True
+    versionCompare()
+    {
+        [ "$#" -eq 3 ] || {
+            echo "Compare needs 3 arguments (was given $#)" 1>&2
+            return 2
+        }
+
+        local arg1="${1#*-}"    # Strip leading prefix-
+        local op="${2}"
+        local arg2="${3#*-}"    # Strip leading prefix-
+        local result=''         # Empty represents 'equal'
+
+        arg1="${arg1:-0}."
+        arg2="${arg2:-0}."
+
+        if   [ "$arg1" = "$arg2" ];        then unset arg1 arg2 # Identical
+        elif [ "${arg1#git}" != "$arg1" ]; then result='more'   # (git > arg2)
+        elif [ "${arg2#git}" != "$arg2" ]; then result='less'   # (arg1 < git)
+        fi
+
+        while [ -z "$result" ] && [ -n "${arg1}${arg2}" ]
+        do
+            local digits1="${arg1%%.*}"
+            local digits2="${arg2%%.*}"
+
+            arg1="${arg1#*.}"
+            arg2="${arg2#*.}"
+
+            : "${digits1:=0}"
+            : "${digits2:=0}"
+
+            # Other handling of non-integer values?
+            if   [ "$digits1" -lt "$digits2" ]; then result='less'
+            elif [ "$digits1" -gt "$digits2" ]; then result='more'
+            fi
+        done
+
+        case "$op" in
+        (-eq | eq)  [ -z "$result" ] ;;
+        (-ne | ne)  [ -n "$result" ] ;;
+        (-lt | lt)  [ 'less' = "$result" ] ;;
+        (-gt | gt)  [ 'more' = "$result" ] ;;
+        (-le | le)  [ 'less' = "${result:-less}" ] ;;
+        (-ge | ge)  [ 'more' = "${result:-more}" ] ;;
+        (*)
+            echo "Unknown operator: '$op'" 1>&2
+            return 2
+            ;;
+        esac
+    }
 fi
 
 
-- 
GitLab