From 3a816006dc7b75c6ca4a1f611495f37d13a2694b Mon Sep 17 00:00:00 2001 From: Mark Olesen Date: Tue, 3 Dec 2019 12:34:24 +0100 Subject: [PATCH] COMP: support m4 include directories for wrap-lemon Set the m4 -I include accordingly to have the folllowing: - the directory of the parser. - include/ in the top-level source tree of the current target (eg, src/finiteVolume/include-m4/ when compiling libfiniteVolume) - include/ from OpenFOAM Additional -dry-run option for makeParser, wrap-lemon for expanding m4 only. Extend m4 wrapping support to include bison as well. --- wmake/rules/General/bison | 12 +- wmake/rules/General/lemon | 5 +- wmake/scripts/makeParser | 122 +++++++++++++------ wmake/scripts/wrap-bison | 250 +++++++++++++++++++++++++++++++------- wmake/scripts/wrap-lemon | 167 ++++++++++++++++++------- 5 files changed, 434 insertions(+), 122 deletions(-) diff --git a/wmake/rules/General/bison b/wmake/rules/General/bison index 3e17290499..9b3862a075 100644 --- a/wmake/rules/General/bison +++ b/wmake/rules/General/bison @@ -1,4 +1,4 @@ -SUFFIXES += .Y .y .yy +SUFFIXES += .Y .y .yy .yy-m4 ytoo = $E $(call QUIET_MESSAGE,bison,$(/dev/null + if test -f "$1" && rm -f "$1" then - echo "Removed generated $2 file" + echo "Removed generated $2 file" 1>&2 else - echo "No generated $2 file to remove" + echo "No generated $2 file to remove" 1>&2 fi } @@ -86,44 +84,100 @@ case "$scanner" in input="${prefix}${scanner}" output="${prefix}${scanner%.*}.cc" - if [ "$optRemove" = true ] + if [ "$optRemoveFile" = true ] then removeFile "$output" "ragel scanner" elif command -v ragel >/dev/null then - echo "Generating ragel scanner" + echo "Generating ragel scanner" 1>&2 ragel -G2 -o "$output" "$input" else - echo "No ragel, leaving scanner intact" + echo "No ragel, leaving scanner intact" 1>&2 fi echo ;; esac +# The output code extension is .c (default) or .cc, but also possibly .C +# - mapping here consistent with wmake/rules/General/{bison,lemon} + +extCode=c case "$parser" in -(*.ly | *.lyy | *.ly*m4) - extCode=cc + (*.Y) extCode=C ;; + (*.yy | *.yy-m4 | *.lyy | *.lyy-m4) extCode=cc ;; +esac + +# Detect m4, any additional messages (eg, using m4 etc) +unset usingM4 message +case "$parser" in +(*m4) + usingM4=true + message=", using m4 filtering" + ;; +esac + +case "$parser" in +(*.ly | *.lyy | *.ly-m4 | *.lyy-m4) # Lemon input="${prefix}${parser}" output="${parser%.*}.h" - # Pass -with-debug to wrap-lemon - [ -n "$optDebug" ] && optDebug="-with-debug" - - # Additional message (eg, using m4 etc) - unset message - case "$parser" in (*m4) message=", using m4 filtering" ;; esac - - if [ "$optRemove" = true ] + if [ "$optRemoveFile" = true ] then removeFile "$output" "lemon header" - elif [ "$optCode" = true ] - then - echo "Generating lemon parser code ($extCode)$message" - "${WM_PROJECT_DIR:?}/wmake/scripts/wrap-lemon" $optDebug -e"$extCode" -s "$input" else - echo "Generating lemon parser header$message" - "${WM_PROJECT_DIR:?}/wmake/scripts/wrap-lemon" $optDebug -header -s "$input" + + # Touch parser file time when using m4. + # This ensures that we have a better correspondence between + # generated and compiled versions since changes to the m4 macros + # may otherwise not be noticed. + + if [ "$usingM4" = true ] && [ -f "$input" ] + then + message="$message (touching input file time)" + touch "$input" + fi + + if [ "$optHeader" = false ] + then + echo "Generating lemon parser code ($extCode)$message" 1>&2 + "${WM_PROJECT_DIR:?}/wmake/scripts/wrap-lemon" \ + $optDryRun $optRemoveTmp -e"$extCode" -p -s "$input" + else + echo "Generating lemon parser header$message" 1>&2 + "${WM_PROJECT_DIR:?}/wmake/scripts/wrap-lemon" \ + $optDryRun $optRemoveTmp -header -p -s "$input" + fi + fi + echo + ;; + +(*.[Yy] | *.yy | *.y-m4 | *.yy-m4) # Bison + input="${prefix}${parser}" + + if [ "$optRemoveFile" = true ] + then + echo "File removal not yet supported for bison" 1>&2 + else + # Touch parser file time when using m4. + # This ensures that we have a better correspondence between + # generated and compiled versions since changes to the m4 macros + # may otherwise not be noticed. + + if [ "$usingM4" = true ] && [ -f "$input" ] + then + message="$message (touching input file time)" + touch "$input" + fi + + if [ -n "$optDryRun" ] + then + echo "Generating bison parser code ($extCode)$message" 1>&2 + "${WM_PROJECT_DIR:?}/wmake/scripts/wrap-bison" \ + $optDryRun $optRemoveTmp "$input" + else + echo "Currently only -dry-run is supported for bison" 1>&2 + fi fi echo ;; diff --git a/wmake/scripts/wrap-bison b/wmake/scripts/wrap-bison index 740ad0f851..c68dce1c88 100755 --- a/wmake/scripts/wrap-bison +++ b/wmake/scripts/wrap-bison @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash #------------------------------------------------------------------------------ # ========= | # \\ / F ield | OpenFOAM: The Open Source CFD Toolbox @@ -14,7 +14,7 @@ # wrap-bison # # Usage -# wrap-bison -input=*.yy -output=*.cc [bison-options] +# wrap-bison -output=*.cc [bison options/args] # # Description # A wrapper to handle renaming/relocation of bison-generated files. @@ -41,6 +41,13 @@ # - place generated *.hh files directly into lnInclude/ # - place generated *.cc file into the build/ directory # +# When called with m4 wrapping, it sets the m4 -I include to have +# the following: +# - the directory of the parser. +# - include/ in the top-level source tree of the current target +# (eg, src/finiteVolume/include/ when compiling libfiniteVolume) +# - include/ from OpenFOAM +# # Note # General idea lifted from swak #------------------------------------------------------------------------------ @@ -52,8 +59,9 @@ usage() { Usage: ${0##*/} [options] [bison args/options] options: - -input=NAME Perform the renaming actions - -output=NAME Perform the renaming actions + -dry-run Process m4 only (output on stdout) + -no-tmp Do not retain temporary m4 processed files + -output=NAME Request renaming actions -h, -help Print the usage A bison wrapper with renaming of skeleton files @@ -62,7 +70,7 @@ USAGE exit 1 } -# File extensions used +# File extensions used (may need adjustment) extCode="cc" extHead="hh" @@ -70,71 +78,151 @@ extHead="hh" # Parse arguments and options #------------------------------------------------------------------------------ -# wrap-bison -input=... -output=... -unset inputFile outputFile +# wrap-bison -output=... +unset outputFile optDryRun optRemoveTmp m4Flags while [ "$#" -gt 0 ] do case "$1" in (-h | -help*) usage ;; - (-input=*) inputFile="${1#*=}" ;; - (-output=*) outputFile="${1#*=}" ;; + (-dry-run) optDryRun=true ;; + (-no-tmp) optRemoveTmp=true ;; + (-output=*) outputFile="${1#*=}" ;; (*) break ;; esac shift done -# No rename action supplied? Juet execute bison directly. -if [ -z "$inputFile" ] +#------------------------------------------------------------------------------ +# Additional m4Flags (for includes etc) +# +# $1 : path-qualified name of the parser +# +# Set includes accordingly to +# - the directory containing the parser +# - include/ in the top-level source tree of the current target +# - include/ from OpenFOAM + +defineM4Flags() +{ + # Always include the directory containing the parser file + m4Flags="$m4Flags${m4Flags:+ }-I$(dirname ${1:-.})" + + local proj="$WM_PROJECT_DIR/src/${WM_PROJECT:-OpenFOAM}" + local curr="$PWD" + + # Called from the Makefile (PWD contains the parser source) + # or from elsewhere (eg, createCode)? + if [ ! -f "$curr/Make/options" ] + then + # No Make/options (eg createCode) - discover with "wmake -pwd" + curr="$(wmake -pwd 2>/dev/null)" + fi + + # Avoid examining twice + [ "$curr" != "$proj" ] || unset curr + + if [ -n "$curr" ] && [ -d "$curr/include" ] + then + m4Flags="$m4Flags -I$curr/include" + fi + + if [ -n "$proj" ] && [ -d "$proj/include" ] + then + m4Flags="$m4Flags -I$proj/include" + fi +} + + +#------------------------------------------------------------------------------ +# Get some information based on the bison options +# The last argument is the input file + +unset parser +findBisonOptions() +{ + parser="${@: -1}" +} + +findBisonOptions "$@" + +unset parserFlags extParser usingM4 + +# Detect m4 use (defines parser macro too) and get extension without m4 +case "$parser" in +(*.*m4) + usingM4=true + parserFlags="-Dm4" + defineM4Flags "$parser" + + extParser=".${parser##*.}" # The extension (with dot) + extParser="${extParser%m4}" # Without trailing m4 + extParser="${extParser/%[-_]/}" # Without - or _ separators + ;; +esac + +# No rename action requested? Just execute bison directly. +if [ -z "$outputFile" ] && [ "$usingM4" != true ] then bison $* exit $? fi -#------------------------------------------------------------------------------ -# Renaming requested -# Need lnInclude/ directory -[ -d lnInclude ] || mkdir lnInclude 2>/dev/null || { +exitCode=0 # No failures + + +#------------------------------------------------------------------------------ +# Dry-run + +if [ "$optDryRun" = true ] +then + if [ "$usingM4" = true ] + then + echo "m4 flags: $m4Flags" 1>&2 + m4 $m4Flags "$parser"; exitCode=$? + else + echo "Nothing to do - not using m4" 2>/dev/null + fi + [ "$exitCode" -eq 0 ] || echo "m4 failed" 2>/dev/null + exit "$exitCode" # Done +fi + + +#------------------------------------------------------------------------------ + +# Called from the Makefile (PWD contains the parser source) +# or from elsewhere (eg, createCode)? +curr="$PWD" +if [ ! -f "$curr/Make/options" ] +then + # No Make/options (eg createCode) - discover with "wmake -pwd" + curr="$(wmake -pwd 2>/dev/null)" +fi + +# Will most likely need a lnInclude/ directory +[ -d "$curr/lnInclude" ] || mkdir "$curr/lnInclude" 2>/dev/null || { echo "Cannot continue without an lnInclude directory" 1>&2 - pwd -L + (cd "$curr" && pwd -L) exit 1 } # Get a baseName (stem) for the output -baseName="${inputFile##*/}" +baseName="${parser##*/}" baseName="${baseName%.*}" # Fallback for output if [ -z "$outputFile" ] then - outputFile="$(dirname ${inputFile})/${baseName}.$extCode" + outputFile="$(dirname ${parser})/${baseName}.$extCode" fi -# Execute in a temporary directory (keeps files together) -cwd="$(pwd -L)" -tmpDir="Make/bisonWrapper-$baseName" -rm -rf "$tmpDir" 2>/dev/null -mkdir "$tmpDir" 2>/dev/null +outputDir="$(dirname $outputFile)" -cd "$tmpDir" || exit -rc=1 - -# DO WE WANT THIS? -# trap 'cd $cwd; rm -f $tmpDir 2>/dev/null; exit $rc' EXIT TERM INT - -bison "$@" "../../$inputFile" -rc=$? - -cd "../.." || exit - -if [ "$rc" -ne 0 ] -then - rm -rf "$tmpDir" 2>/dev/null - exit "$rc" # Exit with bison return code -fi +#------------------------------------------------------------------------------ +# Renaming, filter code # Check for/remove .tab. tag? unset untabFilter @@ -146,7 +234,7 @@ hasTab="${hasTab%.*}" if [ "$hasTab" = "${hasTab%.tab}" ] then - untab='/^#.*".*\.tab\./s/\.tab\././' + untabFilter='/^#.*".*\.tab\./s/\.tab\././' fi # Filter include names to generate new files @@ -160,12 +248,80 @@ filterRename() -e '/include *"location/s/"/"'"${baseName}."'/;' \ -e '/include *"position/s/"/"'"${baseName}."'/;' \ -e '/include *"stack/s/"/"'"${baseName}."'/;' \ - -e "$untab;" \ + -e "$untabFilter;" \ "$1" >| "$2" fi } +#------------------------------------------------------------------------------ + +# This gets slightly complicated with temporary files/dirs. +# +# - a tmp FILE for the m4-filtered parser (optional). +# - a tmp DIR for storing the bison generated files so that we can +# properly edit and rename them. + +unset tmpFile tmpDir parserInput + +if [ "$usingM4" = true ] +then + # Drop last argument (the parser input file) + set -- "${@:1:${#}-1}" + + # Filter via m4 + + # The outputDir is always defined. Make absolute + tmpFile="$(cd ${outputDir:?} && pwd -L)/${parser##*/}" + tmpFile="${tmpFile%.*}$extParser" # Eg, from .lyy-m4 -> .lyy + + # We may want this: + # trap 'rm -f $tmpFile 2>/dev/null; exit $exitCode' EXIT TERM INT + + if m4 $m4Flags "$parser" > "$tmpFile" && [ -f "$tmpFile" ] + then + parserInput="$tmpFile" + exitCode=0 + else + echo "m4 stage failed on $parser" 2>/dev/null + rm -f "$tmpFile" 2>/dev/null + exit 1 + fi + +else + # No special (m4) handling + + # Make parser input name absolute + parserInput="$(cd $(dirname $parser) && pwd -L)/${parser##*/}" + +fi + +#------------ +# Execute bison in a temporary directory to keeps all files together +cwd="$(pwd -L)" +tmpDir="Make/wrap-bison-$baseName" +rm -rf "$tmpDir" 2>/dev/null +mkdir "$tmpDir" 2>/dev/null + +# We may want this: +# trap 'cd $cwd; rm -f $tmpDir 2>/dev/null; exit $exitCode' EXIT TERM INT + +cd "$tmpDir" || exit + +# Execute bison +bison "$@" "$parserInput" +exitCode=$? + +cd "../.." || exit + +if [ "$exitCode" -ne 0 ] +then + rm -rf "$tmpDir" 2>/dev/null + exit "$exitCode" # Exit with bison return code +fi + +#------------ + # Boilerplate -> lnInclude/ directory with new name for file in position location stack do @@ -185,7 +341,17 @@ filterRename \ "${outputFile}" +if [ -n "$tmpFile" ] +then + if [ -n "$optRemoveTmp" ] + then + rm -f "$tmpFile" 2>/dev/null + else + echo "Retaining intermediate: $tmpFile" 2>/dev/null + fi +fi + rm -rf "$tmpDir" 2>/dev/null -exit "$rc" # Exit with bison return code +exit "$exitCode" # Exit with bison return code #------------------------------------------------------------------------------ diff --git a/wmake/scripts/wrap-lemon b/wmake/scripts/wrap-lemon index 18eb53ebb6..36ac29ed34 100755 --- a/wmake/scripts/wrap-lemon +++ b/wmake/scripts/wrap-lemon @@ -14,12 +14,19 @@ # wrap-lemon # # Usage -# wrap-lemon [options] [lemon args/options] +# wrap-lemon [options] [lemon options/args] # # Description # A wrapper to use lemon compiled with OpenFOAM with the appropriate # parser template. # +# When called with m4 wrapping, it sets the m4 -I include to have +# the following: +# - the directory of the parser. +# - include/ in the top-level source tree of the current target +# (eg, src/finiteVolume/include/ when compiling libfiniteVolume) +# - include/ from OpenFOAM +# #------------------------------------------------------------------------------ binDir="${WMAKE_BIN:-$WM_PROJECT_DIR/wmake/platforms/$WM_ARCH$WM_COMPILER}" @@ -38,7 +45,8 @@ Usage: ${0##*/} [options] [lemon args/options] options: -header Generate header only, suppressing other output - -with-debug Retain intermediate files (eg, m4 output) + -dry-run Process m4 only (output on stdout) + -no-tmp Do not retain temporary m4 processed files -h, -help Print the usage A lemon wrapper using predefined executable and skeleton locations. @@ -54,21 +62,65 @@ USAGE # Parse arguments and options #------------------------------------------------------------------------------ -# wrap-lemon -header -unset optHeader optDebug +# Eg, wrap-lemon -header +unset optHeader optDryRun optRemoveTmp m4Flags while [ "$#" -gt 0 ] do case "$1" in (-h | -help*) usage ;; (-head*) optHeader=true ;; - (-with-debug) optDebug=true ;; + (-dry-run) optDryRun=true ;; + (-no-tmp) optRemoveTmp=true ;; (*) break ;; esac shift done + +#------------------------------------------------------------------------------ + +# Additional m4Flags (for includes etc) +# +# $1 : path-qualified name of the parser +# +# Set includes accordingly to +# - the directory containing the parser +# - include/ in the top-level source tree of the current target +# - include/ from OpenFOAM + +defineM4Flags() +{ + # Always include the directory containing the parser file + m4Flags="$m4Flags${m4Flags:+ }-I$(dirname ${1:-.})" + + local proj="$WM_PROJECT_DIR/src/${WM_PROJECT:-OpenFOAM}" + local curr="$PWD" + + # Called from the Makefile (PWD contains the parser source) + # or from elsewhere (eg, createCode)? + if [ ! -f "$curr/Make/options" ] + then + # No Make/options (eg createCode) - discover with "wmake -pwd" + curr="$(wmake -pwd 2>/dev/null)" + fi + + # Avoid examining twice + [ "$curr" != "$proj" ] || unset curr + + if [ -n "$curr" ] && [ -d "$curr/include" ] + then + m4Flags="$m4Flags -I$curr/include" + fi + + if [ -n "$proj" ] && [ -d "$proj/include" ] + then + m4Flags="$m4Flags -I$proj/include" + fi +} + + #------------------------------------------------------------------------------ # Get some information based on the lemon options # * '-dXX' for the output directory @@ -95,19 +147,43 @@ findLemonOptions() findLemonOptions "$@" -# Detect m4 use (defines lemon macro too) and get extension without m4 -unset extLemon usingMacros +unset parserFlags extParser usingM4 + +# Detect m4 use (defines parser macro too) and get extension without m4 case "$parser" in (*.*m4) - extLemon=".${parser##*.}" # The extension (with dot) - extLemon="${extLemon%m4}" # Without trailing m4 - extLemon="${extLemon/%[-_]/}" # Without - or _ separators - usingMacros="-Dm4" + usingM4=true + parserFlags="-Dm4" + defineM4Flags "$parser" + + extParser=".${parser##*.}" # The extension (with dot) + extParser="${extParser%m4}" # Without trailing m4 + extParser="${extParser/%[-_]/}" # Without - or _ separators ;; esac -rc=1 # Assume some failure +exitCode=0 # No failures +#------------------------------------------------------------------------------ +# Dry-run + +if [ "$optDryRun" = true ] +then + if [ "$usingM4" = true ] + then + echo "m4 flags: $m4Flags" 1>&2 + m4 $m4Flags "$parser"; exitCode=$? + else + echo "Nothing to do - not using m4" 2>/dev/null + fi + [ "$exitCode" -eq 0 ] || echo "m4 failed" 2>/dev/null + exit "$exitCode" # Done +fi + + +#------------------------------------------------------------------------------ + +unset tmpFile tmpDir if [ -n "$optHeader" ] then @@ -119,41 +195,49 @@ then rm -rf "$tmpDir" 2>/dev/null mkdir "$tmpDir" 2>/dev/null - if [ -n "$usingMacros" ] + # We may want this: + # trap 'rm -f $tmpDir 2>/dev/null; exit $exitCode' EXIT TERM INT + + if [ "$usingM4" = true ] then # Using m4 - redirect to a temporary file tmpFile="$tmpDir/${parser##*/}" - tmpFile="${tmpFile%.*}$extLemon" # Eg, from .lyy-m4 -> .lyy + tmpFile="${tmpFile%.*}$extParser" # Eg, from .lyy-m4 -> .lyy - if m4 "$parser" > "$tmpFile" && [ -f "$tmpFile" ] + if m4 $m4Flags "$parser" > "$tmpFile" && [ -f "$tmpFile" ] then parser="$tmpFile" else echo "m4 stage failed on $parser" 2>/dev/null + exitCode=1 fi fi - # DO WE WANT THIS? - # trap 'rm -f $tmpDir 2>/dev/null; exit $rc' EXIT TERM INT - "$lemon" "$skel" "-d$tmpDir" "$@" $usingMacros "$parser" - rc=$? + if [ "$exitCode" -eq 0 ] + then + "$lemon" "$skel" "-d$tmpDir" "$@" $parserFlags "$parser" + exitCode=$? + fi - for src in "$tmpDir"/*.h - do - dst="${src##*/}" - if [ -f "$src" ] - then - if ! cmp "$src" "$dst" 2>/dev/null + if [ "$exitCode" -eq 0 ] + then + for src in "$tmpDir"/*.h + do + dst="${src##*/}" + if [ -f "$src" ] then - mv "$src" "$dst" - echo "Updating $dst" 1>&2 + if ! cmp "$src" "$dst" 2>/dev/null + then + mv "$src" "$dst" + echo "Updating $dst" 1>&2 + fi fi - fi - done + done + fi rm -rf "$tmpDir" 2>/dev/null -elif [ -n "$usingMacros" ] +elif [ "$usingM4" = true ] then # Drop last argument (the parser input file) set -- "${@:1:${#}-1}" @@ -165,24 +249,25 @@ then else tmpFile="${parser}" fi - tmpFile="${tmpFile%.*}$extLemon" # Eg, from .lyy-m4 -> .lyy + tmpFile="${tmpFile%.*}$extParser" # Eg, from .lyy-m4 -> .lyy - # DO WE WANT THIS? - # trap 'rm -f $tmpFile 2>/dev/null; exit $rc' EXIT TERM INT + # We may want this: + # trap 'rm -f $tmpFile 2>/dev/null; exit $exitCode' EXIT TERM INT - if m4 "$parser" > "$tmpFile" && [ -f "$tmpFile" ] + if m4 $m4Flags "$parser" > "$tmpFile" && [ -f "$tmpFile" ] then - "$lemon" "$skel" "$@" $usingMacros "$tmpFile" - rc=$? + "$lemon" "$skel" "$@" $parserFlags "$tmpFile" + exitCode=$? else echo "m4 stage failed on $parser" 2>/dev/null + exitCode=1 fi - if [ -n "$optDebug" ] + if [ -n "$optRemoveTmp" ] then - echo "Retaining intermediate: $tmpFile" 2>/dev/null - else rm -f "$tmpFile" 2>/dev/null + else + echo "Retaining intermediate: $tmpFile" 2>/dev/null fi else @@ -190,10 +275,10 @@ else # No special handling "$lemon" "$skel" "$@" - rc=$? + exitCode=$? fi -exit "$rc" # Exit with lemon return code +exit "$exitCode" # Exit with lemon return code #------------------------------------------------------------------------------