add full spectrum config var configurations

Sat, 29 Nov 2025 17:31:03 +0100

author
Mike Becker <universe@uap-core.de>
date
Sat, 29 Nov 2025 17:31:03 +0100
changeset 165
f4f11f755ee7
parent 164
099448bcc943
child 166
9bb4b40d61b7

add full spectrum config var configurations

resolves #680
resolves #740
resolves #741
resolves #742

src/main/java/de/unixwork/uwproj/AbstractOption.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/Config.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/ConfigVar.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/Dependency.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/Feature.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/Main.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/Option.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/Project.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/Util.java file | annotate | diff | comparison | revisions
src/main/resources/make/configure.vm file | annotate | diff | comparison | revisions
src/main/resources/make/uwproj.xsd file | annotate | diff | comparison | revisions
test/configure file | annotate | diff | comparison | revisions
test/configure2 file | annotate | diff | comparison | revisions
test/make/configure.vm file | annotate | diff | comparison | revisions
test/make/project.xml file | annotate | diff | comparison | revisions
test/make/project2.xml file | annotate | diff | comparison | revisions
test/make/uwproj.xsd file | annotate | diff | comparison | revisions
--- a/src/main/java/de/unixwork/uwproj/AbstractOption.java	Sat Nov 29 13:50:15 2025 +0100
+++ b/src/main/java/de/unixwork/uwproj/AbstractOption.java	Sat Nov 29 17:31:03 2025 +0100
@@ -1,11 +1,19 @@
 package de.unixwork.uwproj;
 
 public abstract class AbstractOption {
-    protected final String arg;
+    protected String arg = "";
     protected String desc = "";
 
-    public AbstractOption(String arg) {
-        this.arg = arg;
+    public AbstractOption() {
+    }
+
+    /**
+     * Indicates whether the option can be overridden by command line arguments.
+     *
+     * @return {@code true} if the option can be overridden, {@code false} otherwise
+     */
+    public final boolean isOverridable() {
+        return !arg.isEmpty();
     }
 
     /**
@@ -14,7 +22,9 @@
      * @return the argument name
      * @see #getHelpTextArg()
      */
-    public abstract String getArg();
+    public final String getArg() {
+        return arg;
+    }
 
     /**
      * The display text for the argument.
@@ -34,7 +44,9 @@
      * @return the description without any formatting
      * @see #getHelpText()
      */
-    public abstract String getDesc();
+    public final String getDesc() {
+        return desc;
+    }
 
     /**
      * The internal variable name for the option.
--- a/src/main/java/de/unixwork/uwproj/Config.java	Sat Nov 29 13:50:15 2025 +0100
+++ b/src/main/java/de/unixwork/uwproj/Config.java	Sat Nov 29 17:31:03 2025 +0100
@@ -18,11 +18,21 @@
         platform = element.getAttribute("platform");
         not = element.getAttribute("not");
 
-        Util.getChildElements(element).forEach(elm -> {
-            if (elm.getNodeName().equals("var")) {
-                vars.add(new ConfigVar(elm));
+        Util.getChildElements(element).forEach(elm ->
+            vars.add(new ConfigVar(elm))
+        );
+
+        // special case: prefix is requested, but exec_prefix is not
+        // insert exec_prefix default directly after the prefix
+        if (vars.stream().noneMatch(v -> v.getVarName().equals("exec_prefix"))) {
+            for (var iter = vars.listIterator(); iter.hasNext();) {
+                final var v = iter.next();
+                if (v.getVarName().equals("prefix")) {
+                    iter.add(new ConfigVar("exec_prefix"));
+                    break;
+                }
             }
-        });
+        }
     }
 
 
--- a/src/main/java/de/unixwork/uwproj/ConfigVar.java	Sat Nov 29 13:50:15 2025 +0100
+++ b/src/main/java/de/unixwork/uwproj/ConfigVar.java	Sat Nov 29 17:31:03 2025 +0100
@@ -2,34 +2,115 @@
 
 import org.w3c.dom.Element;
 
-public final class ConfigVar {
+public final class ConfigVar extends AbstractOption {
     private final String varName;
     private final String value;
     private final boolean exec;
 
+    public ConfigVar(String varName) {
+        this.varName = varName;
+        desc = getDefaultHelpText(varName);
+        arg = varName.toLowerCase().replace('_', '-');
+        value = "";
+        exec = false;
+    }
+
     public ConfigVar(Element e) {
-        this(e, false);
+        this(e, e.getNodeName().replace('-', '_'));
     }
 
-    public ConfigVar(Element e, boolean varNameIsElemName) {
-        if (varNameIsElemName) {
-            // take the node name literally and don't apply shId()
-            varName = e.getNodeName().toUpperCase();
+    public ConfigVar(Element e, String defaultVarName) {
+        super();
+        varName = Util.getAttrOrDefault(e, "name", defaultVarName);
+        desc = Util.getAttrOrDefault(e, "option-help", getDefaultHelpText(varName));
+        if (desc.isEmpty()) {
+            // no help text, add an option only when requested
+            arg = e.getAttribute("option");
         } else {
-            varName = e.getAttribute("name");
+            // there is a help text, generate an option if none is specified
+            arg = Util.getAttrOrDefault(e, "option", varName.toLowerCase().replace('_', '-'));
         }
-        value = Util.getContent(e);
+
+        if (e.hasChildNodes()) {
+            value = Util.getContent(e);
+        } else if (arg.equals("prefix")) {
+            // special treatment for prefix
+            value = "/usr";
+        } else {
+            value = "";
+        }
         exec = Boolean.parseBoolean(e.getAttribute("exec"));
+
+        if (exec) {
+            desc = desc.replace("%default", String.format("{{%s}}", value));
+        } else {
+            desc = desc.replace("%default", value);
+        }
     }
 
+    /**
+     * A set of default help texts for standard config variables.
+     * <p>
+     * Returns an empty string for custom config variables.
+     *
+     * @param varName the variable name
+     * @return the default help text
+     */
+    private static String getDefaultHelpText(String varName) {
+        return switch (varName) {
+            case "prefix" -> "path prefix for architecture-independent files [%default]";
+            case "exec_prefix" -> "path prefix for architecture-dependent files [PREFIX]";
+            case "bindir" -> "user executables [EPREFIX/bin]";
+            case "sbindir" -> "system admin executables [EPREFIX/sbin]";
+            case "libexecdir" -> "program executables [EPREFIX/libexec]";
+            case "sysconfdir" -> "system configuration files [PREFIX/etc]";
+            case "sharedstatedir" -> "modifiable architecture-independent data [PREFIX/com]";
+            case "localstatedir" -> "modifiable single-machine data [PREFIX/var]";
+            case "runstatedir" -> "run-time variable data [LOCALSTATEDIR/run]";
+            case "libdir" -> "object code libraries [EPREFIX/lib]";
+            case "includedir" -> "C header files [PREFIX/include]";
+            case "datarootdir" -> "read-only architecture-independent data root [PREFIX/share]";
+            case "datadir" -> "read-only architecture-independent data [DATAROOTDIR]";
+            case "infodir" -> "info documentation [DATAROOTDIR/info]";
+            case "mandir" -> "man documentation [DATAROOTDIR/man]";
+            case "localedir" -> "locale-dependent data [DATAROOTDIR/locale]";
+            default -> "";
+        };
+    }
+
+    /**
+     * The name of the variable where the value will be stored.
+     * <p>
+     * This is also the name of the variable that shall be added to the make config.
+     *
+     * @return the variable name
+     */
+    @Override
     public String getVarName() {
         return varName;
     }
 
+    @Override
+    public String getHelpTextArg() {
+        return "--" + arg;
+    }
+
+    /**
+     * The value with which this variable shall be initialized.
+     * <p>
+     * If {@link #isExec()} returns {@code true}, this value is used as the command to execute.
+     *
+     * @return the initial value for this variable
+     */
     public String getValue() {
         return value;
     }
 
+    /**
+     * Indicates whether the value is a command to execute.
+     *
+     * @return {@code true} if the value is a command, {@code false} otherwise.
+     */
     public boolean isExec() {
         return exec;
     }
--- a/src/main/java/de/unixwork/uwproj/Dependency.java	Sat Nov 29 13:50:15 2025 +0100
+++ b/src/main/java/de/unixwork/uwproj/Dependency.java	Sat Nov 29 17:31:03 2025 +0100
@@ -31,7 +31,8 @@
 
         Util.getChildElements(element).forEach(elm -> {
             switch (elm.getNodeName()) {
-                case "cflags", "cxxflags", "ldflags" -> flags.add(new ConfigVar(elm, true));
+                // TODO: instead of re-using ConfigVar, we should add a Flags type
+                case "cflags", "cxxflags", "ldflags" -> flags.add(new ConfigVar(elm, elm.getNodeName().toUpperCase()));
                 case "pkgconfig" -> pkgconfig.add(new PkgConfigPackage(elm));
                 case "test" -> tests.add(Util.getContent(elm));
                 case "make" -> make.add(Util.getContent(elm));
@@ -41,8 +42,8 @@
     }
 
     /**
-     * Returns the ID of this dependency, if it has a name.
-     * @return the ID that can be used for shell scripts - empty if dependency has not a name
+     * Returns the ID of this dependency if it has a name.
+     * @return the ID that can be used for shell scripts - empty if the dependency has not a name
      */
     public String getId() {
         return id;
--- a/src/main/java/de/unixwork/uwproj/Feature.java	Sat Nov 29 13:50:15 2025 +0100
+++ b/src/main/java/de/unixwork/uwproj/Feature.java	Sat Nov 29 17:31:03 2025 +0100
@@ -13,7 +13,7 @@
     private final TargetData disabled = new TargetData();
 
     public Feature(Element e) {
-        super(Util.getAttrOrDefault(e, "arg", e.getAttribute("name")));
+        arg = Util.getAttrOrDefault(e, "arg", e.getAttribute("name"));
         name = e.getAttribute("name");
         auto = Boolean.parseBoolean(e.getAttribute("default"));
         targetData = new TargetData(e);
@@ -54,14 +54,6 @@
         return name;
     }
 
-    public String getArg() {
-        return arg;
-    }
-
-    public String getDesc() {
-        return desc;
-    }
-
     public boolean isAuto() {
         return auto;
     }
--- a/src/main/java/de/unixwork/uwproj/Main.java	Sat Nov 29 13:50:15 2025 +0100
+++ b/src/main/java/de/unixwork/uwproj/Main.java	Sat Nov 29 17:31:03 2025 +0100
@@ -70,6 +70,7 @@
         context.put("features", project.getFeatures());
         context.put("project", project);
         context.put("config", project.getConfig());
+        context.put("vars", project.getVars());
         context.put("languages", project.getLang());
         new VelocityEngine().getTemplate(tplFileName).merge(context, out);
     }
--- a/src/main/java/de/unixwork/uwproj/Option.java	Sat Nov 29 13:50:15 2025 +0100
+++ b/src/main/java/de/unixwork/uwproj/Option.java	Sat Nov 29 17:31:03 2025 +0100
@@ -13,7 +13,7 @@
     private final LinkedList<OptionDefault> defaults = new LinkedList<>();
 
     public Option(Element element) {
-        super(element.getAttribute("arg"));
+        arg = element.getAttribute("arg");
         Util.getChildElements(element).forEach(elm -> {
             switch (elm.getNodeName()) {
                 case "desc" -> desc = Util.getContent(elm);
@@ -28,16 +28,6 @@
     }
 
     @Override
-    public String getDesc() {
-        return desc;
-    }
-
-    @Override
-    public String getArg() {
-        return arg;
-    }
-
-    @Override
     public String getHelpTextArg() {
         return "--" + arg + "=" + getValuesString();
     }
--- a/src/main/java/de/unixwork/uwproj/Project.java	Sat Nov 29 13:50:15 2025 +0100
+++ b/src/main/java/de/unixwork/uwproj/Project.java	Sat Nov 29 17:31:03 2025 +0100
@@ -12,6 +12,8 @@
     private final List<Feature> features = new LinkedList<>();
 
     private final List<Config> configList = new LinkedList<>();
+    private final Set<String> configOptions = new HashSet<>();
+    private final List<ConfigVar> vars = new LinkedList<>();
     
     private final Set<String> lang = new HashSet<>();
 
@@ -45,6 +47,15 @@
         // check if some targets want all named dependencies
         targets.stream().filter(Target::wantsAllDependencies)
                 .forEach(t -> t.replaceAllDependencies(namedDependencies.keySet()));
+
+        // collect and de-duplicate config options
+        configList.forEach(config -> {
+            config.getVars().forEach(configVar -> {
+                if (configOptions.add(configVar.getArg())) {
+                    vars.add(configVar);
+                }
+            });
+        });
     }
 
     public List<NamedDependency> getNamedDependencies() {
@@ -74,6 +85,10 @@
     public List<Config> getConfig() {
         return configList;
     }
+
+    public List<ConfigVar> getVars() {
+        return vars;
+    }
     
     public Collection<String> getLang() {
         return lang;
--- a/src/main/java/de/unixwork/uwproj/Util.java	Sat Nov 29 13:50:15 2025 +0100
+++ b/src/main/java/de/unixwork/uwproj/Util.java	Sat Nov 29 17:31:03 2025 +0100
@@ -31,7 +31,7 @@
      */
     public static String getAttrOrDefault(Element elm, String attr, String def) {
         final var v = elm.getAttribute(attr);
-        return v.isBlank() ? def : v;
+        return v.isBlank() ? def : v.trim();
     }
 
     /**
--- a/src/main/resources/make/configure.vm	Sat Nov 29 13:50:15 2025 +0100
+++ b/src/main/resources/make/configure.vm	Sat Nov 29 17:31:03 2025 +0100
@@ -86,27 +86,30 @@
 printhelp()
 {
     echo "Usage: $0 [OPTIONS]..."
-    cat << __EOF__
-Installation directories:
-  --prefix=PREFIX         path prefix for architecture-independent files
-                          [${D}prefix]
-  --exec-prefix=EPREFIX   path prefix for architecture-dependent files
-                          [PREFIX]
-
-  --bindir=DIR            user executables [EPREFIX/bin]
-  --sbindir=DIR           system admin executables [EPREFIX/sbin]
-  --libexecdir=DIR        program executables [EPREFIX/libexec]
-  --sysconfdir=DIR        system configuration files [PREFIX/etc]
-  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
-  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
-  --runstatedir=DIR       run-time variable data [LOCALSTATEDIR/run]
-  --libdir=DIR            object code libraries [EPREFIX/lib]
-  --includedir=DIR        C header files [PREFIX/include]
-  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
-  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
-  --infodir=DIR           info documentation [DATAROOTDIR/info]
-  --mandir=DIR            man documentation [DATAROOTDIR/man]
-  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+    echo 'Configuration:'
+#foreach( $cfg in $config )
+if true \
+#if( $cfg.platform )
+    && isplatform "${cfg.platform}" \
+#end
+#foreach( $np in $cfg.notList )
+      && notisplatform "${np}" \
+#end
+      ; then
+    :
+    #foreach( $var in $cfg.vars )
+    #if( $var.overridable )
+    if test -z "${D}${var.varName}__described__"; then
+        ${var.varName}__described__=1
+        cat << '__EOF__'
+${var.helpText}
+__EOF__
+    fi
+    #end
+    #end
+fi
+#end
+    cat << '__EOF__'
 
 Build Types:
   --debug                 add extra compile flags for debug builds
@@ -127,6 +130,7 @@
 #end
 
 __EOF__
+    abort_configure
 }
 
 # create temporary directory
@@ -142,26 +146,7 @@
 touch "$TEMP_DIR/options"
 touch "$TEMP_DIR/features"
 
-# define standard variables
-# also define standard prefix (this is where we will search for config.site)
-prefix=/usr
-exec_prefix=
-bindir=
-sbindir=
-libdir=
-libexecdir=
-datarootdir=
-datadir=
-sysconfdir=
-sharedstatedir=
-localstatedir=
-runstatedir=
-includedir=
-infodir=
-localedir=
-mandir=
-
-# custom variables
+# config variables
 #foreach( $cfg in $config )
 if true \
 #if( $cfg.platform )
@@ -171,11 +156,17 @@
       && notisplatform "${np}" \
 #end
       ; then
+    :
     #foreach( $var in $cfg.vars )
-    #if( $var.exec )
-    ${var.varName}=`${var.value}`
-    #else
-    ${var.varName}="${var.value}"
+    #if( $var.overridable )
+    if test -z "${D}${var.varName}__initialized__"; then
+        ${var.varName}__initialized__=1
+        #if( $var.exec )
+        ${var.varName}=`${var.value}`
+        #else
+        ${var.varName}="${var.value}"
+        #end
+    fi
     #end
     #end
 fi
@@ -195,28 +186,17 @@
 for ARG in "$@"
 do
     case "$ARG" in
-        "--prefix="*)         prefix=${D}{ARG#--prefix=} ;;
-        "--exec-prefix="*)    exec_prefix=${D}{ARG#--exec-prefix=} ;;
-        "--bindir="*)         bindir=${D}{ARG#----bindir=} ;;
-        "--sbindir="*)        sbindir=${D}{ARG#--sbindir=} ;;
-        "--libdir="*)         libdir=${D}{ARG#--libdir=} ;;
-        "--libexecdir="*)     libexecdir=${D}{ARG#--libexecdir=} ;;
-        "--datarootdir="*)    datarootdir=${D}{ARG#--datarootdir=} ;;
-        "--datadir="*)        datadir=${D}{ARG#--datadir=} ;;
-        "--sysconfdir="*)     sysconfdir=${D}{ARG#--sysconfdir=} ;;
-        "--sharedstatedir="*) sharedstatedir=${D}{ARG#--sharedstatedir=} ;;
-        "--localstatedir="*)  localstatedir=${D}{ARG#--localstatedir=} ;;
-        "--runstatedir="*)    runstatedir=${D}{ARG#--runstatedir=} ;;
-        "--includedir="*)     includedir=${D}{ARG#--includedir=} ;;
-        "--infodir="*)        infodir=${D}{ARG#--infodir=} ;;
-        "--mandir"*)          mandir=${D}{ARG#--mandir} ;;
-        "--localedir"*)       localedir=${D}{ARG#--localedir} ;;
-        "--help"*)            printhelp; abort_configure ;;
-        "--debug")            BUILD_TYPE="debug" ;;
-        "--release")          BUILD_TYPE="release" ;;
+    #foreach( $var in $vars )
+    #if ($var.overridable)
+        "--${var.arg}="*) ${var.varName}=${D}{ARG#--${var.arg}=} ;;
+    #end
+    #end
+        "--help"*) printhelp ;;
+        "--debug") BUILD_TYPE="debug" ;;
+        "--release") BUILD_TYPE="release" ;;
     #foreach( $opt in $options )
         "--${opt.arg}="*) ${opt.varName}=${D}{ARG#--${opt.arg}=} ;;
-        "--${opt.arg}")  echo "option '$ARG' needs a value:"; echo "  $ARG=${opt.valuesString}"; abort_configure ;;
+        "--${opt.arg}") echo "option '$ARG' needs a value:"; echo "  $ARG=${opt.valuesString}"; abort_configure ;;
     #end
     #foreach( $feature in $features )
         "--enable-${feature.arg}") ${feature.varName}=on ;;
@@ -264,22 +244,6 @@
 : ${mandir:='${datarootdir}/man'}
 : ${localedir:='${datarootdir}/locale'}
 
-# remember the above values and compare them later
-orig_bindir="$bindir"
-orig_sbindir="$sbindir"
-orig_libdir="$libdir"
-orig_libexecdir="$libexecdir"
-orig_datarootdir="$datarootdir"
-orig_datadir="$datadir"
-orig_sysconfdir="$sysconfdir"
-orig_sharedstatedir="$sharedstatedir"
-orig_localstatedir="$localstatedir"
-orig_runstatedir="$runstatedir"
-orig_includedir="$includedir"
-orig_infodir="$infodir"
-orig_mandir="$mandir"
-orig_localedir="$localedir"
-
 # check if a config.site exists and load it
 if [ -n "$CONFIG_SITE" ]; then
     # CONFIG_SITE may contain space separated file names
@@ -324,22 +288,6 @@
 
 # generate vars.mk
 cat > "$TEMP_DIR/vars.mk" << __EOF__
-prefix=$prefix
-exec_prefix=$exec_prefix
-bindir=$bindir
-sbindir=$sbindir
-libdir=$libdir
-libexecdir=$libexecdir
-datarootdir=$datarootdir
-datadir=$datadir
-sysconfdir=$sysconfdir
-sharedstatedir=$sharedstatedir
-localstatedir=$localstatedir
-runstatedir=$runstatedir
-includedir=$includedir
-infodir=$infodir
-mandir=$mandir
-localedir=$localedir
 #foreach( $var in $vars )
 ${var.varName}=${D}${var.varName}
 #end
@@ -744,7 +692,7 @@
 
 echo "configure finished"
 echo
-echo "Toolchain"
+echo "Toolchain:"
 echo "  name:           $TOOLCHAIN_NAME"
 if [ -n "$TOOLCHAIN_CC" ]; then
     echo "  cc:             $TOOLCHAIN_CC"
@@ -759,51 +707,13 @@
     echo "  default C std:  $TOOLCHAIN_CSTD"
 fi
 echo
-echo "Build Config:"
-echo "  prefix:         $prefix"
-echo "  exec_prefix:    $exec_prefix"
-if [ "$orig_bindir" != "$bindir" ]; then
-    echo "  bindir:      $bindir"
-fi
-if [ "$orig_sbindir" != "$sbindir" ]; then
-    echo "  sbindir:     $sbindir"
-fi
-if [ "$orig_libdir" != "$libdir" ]; then
-    echo "  libdir:         $libdir"
-fi
-if [ "$orig_libexecdir" != "$libexecdir" ]; then
-    echo "  libexecdir:     $libexecdir"
-fi
-if [ "$orig_datarootdir" != "$datarootdir" ]; then
-    echo "  datarootdir:    $datarootdir"
-fi
-if [ "$orig_datadir" != "$datadir" ]; then
-    echo "  datadir:        $datadir"
-fi
-if [ "$orig_sysconfdir" != "$sysconfdir" ]; then
-    echo "  sysconfdir:     $sysconfdir"
-fi
-if [ "$orig_sharedstatedir" != "$sharedstatedir" ]; then
-    echo "  sharedstatedir: $sharedstatedir"
-fi
-if [ "$orig_localstatedir" != "$localstatedir" ]; then
-    echo "  localstatedir:  $localstatedir"
-fi
-if [ "$orig_runstatedir" != "$runstatedir" ]; then
-    echo "  runstatedir:    $runstatedir"
-fi
-if [ "$orig_includedir" != "$includedir" ]; then
-    echo "  includedir:     $includedir"
-fi
-if [ "$orig_infodir" != "$infodir" ]; then
-    echo "  infodir:        $infodir"
-fi
-if [ "$orig_mandir" != "$mandir" ]; then
-    echo "  mandir:         $mandir"
-fi
-if [ "$orig_localedir" != "$localedir" ]; then
-    echo "  localedir:      $localedir"
-fi
+echo "Config:"
+#foreach( $var in $vars )
+#if ($var.overridable)
+    printf '  %-16s' '${var.arg}:'
+    echo "${D}${var.varName}"
+#end
+#end
 #if ( $options.size() > 0 )
 echo
 echo "Options:"
@@ -813,10 +723,11 @@
 echo
 echo "Features:"
 #foreach( $feature in $features )
+printf '  %-16s' '$feature.name:'
 if [ -n "${D}${feature.varName}" ]; then
-echo "  $feature.name: on"
+    echo 'on'
 else
-echo "  $feature.name: off"
+    echo 'off'
 fi
 #end
 #end
--- a/src/main/resources/make/uwproj.xsd	Sat Nov 29 13:50:15 2025 +0100
+++ b/src/main/resources/make/uwproj.xsd	Sat Nov 29 17:31:03 2025 +0100
@@ -29,23 +29,61 @@
             <xs:documentation>
                 <p>
                     The configuration section.
-                    Consists of an arbitrary number of <code>var</code> elements.
+                    Consists of an arbitrary number of <code>var</code> elements and pre-defined elements for
+                    standard installation directories. If you want to use standard installation directories, you
+                    must list the wanted variables here.
                 </p>
                 <p>
                     The optional <code>platform</code> attribute may specify a <em>single</em> platform identifier and
                     the optional <code>not</code> attribute may specify a comma-separated list of platform identifiers.
                     The configure script shall skip this config declaration if the detected platform is not matching
                     the filter specification of these attributes.
+                    When multiple config sections have a matching filter, and declare the same variables, the settings
+                    of the first matching config section will be used for the affected variables.
                 </p>
             </xs:documentation>
         </xs:annotation>
         <xs:sequence>
+            <xs:element name="prefix" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="exec-prefix" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="bindir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="sbindir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="libdir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="libexecdir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="datarootdir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="datadir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="sysconfdir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="sharedstatedir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="localstatedir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="runstatedir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="includedir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="infodir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="localedir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="mandir" type="StandardConfigVarType" minOccurs="0"/>
             <xs:element name="var" type="ConfigVarType" minOccurs="0" maxOccurs="unbounded"/>
         </xs:sequence>
         <xs:attribute name="platform" type="xs:string"/>
         <xs:attribute name="not" type="xs:string"/>
     </xs:complexType>
 
+    <xs:complexType name="StandardConfigVarType">
+        <xs:annotation>
+            <xs:documentation>
+                The definition of a standard configuration variable.
+                <p>
+                    You may customize the value and the help text,
+                    but the variable name and the option name are pre-defined.
+                </p>
+            </xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="option-help" type="xs:string"/>
+                <xs:attribute name="exec" type="xs:boolean" default="false"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
     <xs:complexType name="ConfigVarType">
         <xs:annotation>
             <xs:documentation>
@@ -55,14 +93,23 @@
                     written to the resulting config file (in contrast to make variables, which are only
                     written to the config file).
                     The <code>name</code> attribute is mandatory, the value is defined by the text body of the element.
-                    The optional Boolean <code>exec</code> attribute (false by default) controls, whether the entire
-                    definition is automatically executed under command substitution.
+                    The optional Boolean <code>exec</code> attribute (false by default) controls, whether value denotes
+                    a command which shall be executed at configuration time to produce the value.
+                    With <code>option</code> and <code>option-help</code> you can control how the variable can be
+                    overridden on the command line. When you don't specify either of those attributes, no command
+                    line option will be generated. When you provide a <code>option-help</code>, but do not specify the
+                    <code>option</code> name, a name is generated.
+                    You can use the string <code>%default</code> in your help text when you want to show the default
+                    value in the text. When <code>exec</code> is used, the default will not be resolved in the help
+                    text and instead the command is shown (to avoid breaking the formatting).
                 </p>
             </xs:documentation>
         </xs:annotation>
         <xs:simpleContent>
             <xs:extension base="xs:string">
                 <xs:attribute name="name" type="xs:string" use="required"/>
+                <xs:attribute name="option" type="xs:string"/>
+                <xs:attribute name="option-help" type="xs:string"/>
                 <xs:attribute name="exec" type="xs:boolean" default="false"/>
             </xs:extension>
         </xs:simpleContent>
--- a/test/configure	Sat Nov 29 13:50:15 2025 +0100
+++ b/test/configure	Sat Nov 29 17:31:03 2025 +0100
@@ -85,27 +85,40 @@
 printhelp()
 {
     echo "Usage: $0 [OPTIONS]..."
-    cat << __EOF__
-Installation directories:
-  --prefix=PREFIX         path prefix for architecture-independent files
-                          [$prefix]
-  --exec-prefix=EPREFIX   path prefix for architecture-dependent files
-                          [PREFIX]
-
-  --bindir=DIR            user executables [EPREFIX/bin]
-  --sbindir=DIR           system admin executables [EPREFIX/sbin]
-  --libexecdir=DIR        program executables [EPREFIX/libexec]
-  --sysconfdir=DIR        system configuration files [PREFIX/etc]
-  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
-  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
-  --runstatedir=DIR       run-time variable data [LOCALSTATEDIR/run]
-  --libdir=DIR            object code libraries [EPREFIX/lib]
-  --includedir=DIR        C header files [PREFIX/include]
-  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
-  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
-  --infodir=DIR           info documentation [DATAROOTDIR/info]
-  --mandir=DIR            man documentation [DATAROOTDIR/man]
-  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+    echo 'Configuration:'
+if true \
+      ; then
+    :
+    if test -z "$prefix__described__"; then
+        prefix__described__=1
+        cat << '__EOF__'
+  --prefix                path prefix for architecture-independent files [/usr]
+__EOF__
+    fi
+    if test -z "$exec_prefix__described__"; then
+        exec_prefix__described__=1
+        cat << '__EOF__'
+  --exec-prefix           path prefix for architecture-dependent files [PREFIX]
+__EOF__
+    fi
+    if test -z "$libdir__described__"; then
+        libdir__described__=1
+        cat << '__EOF__'
+  --libdir                object code libraries [EPREFIX/lib]
+__EOF__
+    fi
+fi
+if true \
+      && notisplatform "mingw" \
+      ; then
+    :
+fi
+if true \
+    && isplatform "mingw" \
+      ; then
+    :
+fi
+    cat << '__EOF__'
 
 Build Types:
   --debug                 add extra compile flags for debug builds
@@ -115,6 +128,7 @@
   --disable-pg
 
 __EOF__
+    abort_configure
 }
 
 # create temporary directory
@@ -130,39 +144,32 @@
 touch "$TEMP_DIR/options"
 touch "$TEMP_DIR/features"
 
-# define standard variables
-# also define standard prefix (this is where we will search for config.site)
-prefix=/usr
-exec_prefix=
-bindir=
-sbindir=
-libdir=
-libexecdir=
-datarootdir=
-datadir=
-sysconfdir=
-sharedstatedir=
-localstatedir=
-runstatedir=
-includedir=
-infodir=
-localedir=
-mandir=
-
-# custom variables
+# config variables
+if true \
+      ; then
+    :
+    if test -z "$prefix__initialized__"; then
+        prefix__initialized__=1
+        prefix="/usr"
+    fi
+    if test -z "$exec_prefix__initialized__"; then
+        exec_prefix__initialized__=1
+        exec_prefix=""
+    fi
+    if test -z "$libdir__initialized__"; then
+        libdir__initialized__=1
+        libdir=""
+    fi
+fi
 if true \
       && notisplatform "mingw" \
       ; then
-    PWD="pwd"
+    :
 fi
 if true \
     && isplatform "mingw" \
       ; then
-    PWD="pwd -W"
-fi
-if true \
-      ; then
-    HOST=`uname -n`
+    :
 fi
 
 # features
@@ -175,25 +182,12 @@
 for ARG in "$@"
 do
     case "$ARG" in
-        "--prefix="*)         prefix=${ARG#--prefix=} ;;
-        "--exec-prefix="*)    exec_prefix=${ARG#--exec-prefix=} ;;
-        "--bindir="*)         bindir=${ARG#----bindir=} ;;
-        "--sbindir="*)        sbindir=${ARG#--sbindir=} ;;
-        "--libdir="*)         libdir=${ARG#--libdir=} ;;
-        "--libexecdir="*)     libexecdir=${ARG#--libexecdir=} ;;
-        "--datarootdir="*)    datarootdir=${ARG#--datarootdir=} ;;
-        "--datadir="*)        datadir=${ARG#--datadir=} ;;
-        "--sysconfdir="*)     sysconfdir=${ARG#--sysconfdir=} ;;
-        "--sharedstatedir="*) sharedstatedir=${ARG#--sharedstatedir=} ;;
-        "--localstatedir="*)  localstatedir=${ARG#--localstatedir=} ;;
-        "--runstatedir="*)    runstatedir=${ARG#--runstatedir=} ;;
-        "--includedir="*)     includedir=${ARG#--includedir=} ;;
-        "--infodir="*)        infodir=${ARG#--infodir=} ;;
-        "--mandir"*)          mandir=${ARG#--mandir} ;;
-        "--localedir"*)       localedir=${ARG#--localedir} ;;
-        "--help"*)            printhelp; abort_configure ;;
-        "--debug")            BUILD_TYPE="debug" ;;
-        "--release")          BUILD_TYPE="release" ;;
+        "--prefix="*) prefix=${ARG#--prefix=} ;;
+        "--exec-prefix="*) exec_prefix=${ARG#--exec-prefix=} ;;
+        "--libdir="*) libdir=${ARG#--libdir=} ;;
+        "--help"*) printhelp ;;
+        "--debug") BUILD_TYPE="debug" ;;
+        "--release") BUILD_TYPE="release" ;;
         "--enable-pg") FEATURE_PG=on ;;
         "--disable-pg") unset FEATURE_PG ;;
         "-"*) echo "unknown option: $ARG"; abort_configure ;;
@@ -237,22 +231,6 @@
 : ${mandir:='${datarootdir}/man'}
 : ${localedir:='${datarootdir}/locale'}
 
-# remember the above values and compare them later
-orig_bindir="$bindir"
-orig_sbindir="$sbindir"
-orig_libdir="$libdir"
-orig_libexecdir="$libexecdir"
-orig_datarootdir="$datarootdir"
-orig_datadir="$datadir"
-orig_sysconfdir="$sysconfdir"
-orig_sharedstatedir="$sharedstatedir"
-orig_localstatedir="$localstatedir"
-orig_runstatedir="$runstatedir"
-orig_includedir="$includedir"
-orig_infodir="$infodir"
-orig_mandir="$mandir"
-orig_localedir="$localedir"
-
 # check if a config.site exists and load it
 if [ -n "$CONFIG_SITE" ]; then
     # CONFIG_SITE may contain space separated file names
@@ -298,20 +276,8 @@
 cat > "$TEMP_DIR/vars.mk" << __EOF__
 prefix=$prefix
 exec_prefix=$exec_prefix
-bindir=$bindir
-sbindir=$sbindir
 libdir=$libdir
-libexecdir=$libexecdir
-datarootdir=$datarootdir
-datadir=$datadir
-sysconfdir=$sysconfdir
-sharedstatedir=$sharedstatedir
-localstatedir=$localstatedir
-runstatedir=$runstatedir
-includedir=$includedir
-infodir=$infodir
-mandir=$mandir
-localedir=$localedir
+HOST=$HOST
 __EOF__
 
 # toolchain detection utilities
@@ -681,7 +647,7 @@
 
 echo "configure finished"
 echo
-echo "Toolchain"
+echo "Toolchain:"
 echo "  name:           $TOOLCHAIN_NAME"
 if [ -n "$TOOLCHAIN_CC" ]; then
     echo "  cc:             $TOOLCHAIN_CC"
@@ -696,57 +662,20 @@
     echo "  default C std:  $TOOLCHAIN_CSTD"
 fi
 echo
-echo "Build Config:"
-echo "  prefix:         $prefix"
-echo "  exec_prefix:    $exec_prefix"
-if [ "$orig_bindir" != "$bindir" ]; then
-    echo "  bindir:      $bindir"
-fi
-if [ "$orig_sbindir" != "$sbindir" ]; then
-    echo "  sbindir:     $sbindir"
-fi
-if [ "$orig_libdir" != "$libdir" ]; then
-    echo "  libdir:         $libdir"
-fi
-if [ "$orig_libexecdir" != "$libexecdir" ]; then
-    echo "  libexecdir:     $libexecdir"
-fi
-if [ "$orig_datarootdir" != "$datarootdir" ]; then
-    echo "  datarootdir:    $datarootdir"
-fi
-if [ "$orig_datadir" != "$datadir" ]; then
-    echo "  datadir:        $datadir"
-fi
-if [ "$orig_sysconfdir" != "$sysconfdir" ]; then
-    echo "  sysconfdir:     $sysconfdir"
-fi
-if [ "$orig_sharedstatedir" != "$sharedstatedir" ]; then
-    echo "  sharedstatedir: $sharedstatedir"
-fi
-if [ "$orig_localstatedir" != "$localstatedir" ]; then
-    echo "  localstatedir:  $localstatedir"
-fi
-if [ "$orig_runstatedir" != "$runstatedir" ]; then
-    echo "  runstatedir:    $runstatedir"
-fi
-if [ "$orig_includedir" != "$includedir" ]; then
-    echo "  includedir:     $includedir"
-fi
-if [ "$orig_infodir" != "$infodir" ]; then
-    echo "  infodir:        $infodir"
-fi
-if [ "$orig_mandir" != "$mandir" ]; then
-    echo "  mandir:         $mandir"
-fi
-if [ "$orig_localedir" != "$localedir" ]; then
-    echo "  localedir:      $localedir"
-fi
+echo "Config:"
+    printf '  %-16s' 'prefix:'
+    echo "$prefix"
+    printf '  %-16s' 'exec-prefix:'
+    echo "$exec_prefix"
+    printf '  %-16s' 'libdir:'
+    echo "$libdir"
 echo
 echo "Features:"
+printf '  %-16s' 'pg:'
 if [ -n "$FEATURE_PG" ]; then
-echo "  pg: on"
+    echo 'on'
 else
-echo "  pg: off"
+    echo 'off'
 fi
 echo
 
--- a/test/configure2	Sat Nov 29 13:50:15 2025 +0100
+++ b/test/configure2	Sat Nov 29 17:31:03 2025 +0100
@@ -85,27 +85,56 @@
 printhelp()
 {
     echo "Usage: $0 [OPTIONS]..."
-    cat << __EOF__
-Installation directories:
-  --prefix=PREFIX         path prefix for architecture-independent files
-                          [$prefix]
-  --exec-prefix=EPREFIX   path prefix for architecture-dependent files
-                          [PREFIX]
-
-  --bindir=DIR            user executables [EPREFIX/bin]
-  --sbindir=DIR           system admin executables [EPREFIX/sbin]
-  --libexecdir=DIR        program executables [EPREFIX/libexec]
-  --sysconfdir=DIR        system configuration files [PREFIX/etc]
-  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
-  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
-  --runstatedir=DIR       run-time variable data [LOCALSTATEDIR/run]
-  --libdir=DIR            object code libraries [EPREFIX/lib]
-  --includedir=DIR        C header files [PREFIX/include]
-  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
-  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
-  --infodir=DIR           info documentation [DATAROOTDIR/info]
-  --mandir=DIR            man documentation [DATAROOTDIR/man]
-  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+    echo 'Configuration:'
+if true \
+      ; then
+    :
+    if test -z "$prefix__described__"; then
+        prefix__described__=1
+        cat << '__EOF__'
+  --prefix                path prefix for architecture-independent files 
+                          [`pwd`/work]
+__EOF__
+    fi
+    if test -z "$exec_prefix__described__"; then
+        exec_prefix__described__=1
+        cat << '__EOF__'
+  --exec-prefix           path prefix for architecture-dependent files [PREFIX]
+__EOF__
+    fi
+    if test -z "$libdir__described__"; then
+        libdir__described__=1
+        cat << '__EOF__'
+  --libdir                object code libraries [EPREFIX/lib]
+__EOF__
+    fi
+    if test -z "$datarootdir__described__"; then
+        datarootdir__described__=1
+        cat << '__EOF__'
+  --datarootdir           read-only architecture-independent data root 
+                          [PREFIX/share]
+__EOF__
+    fi
+    if test -z "$localstatedir__described__"; then
+        localstatedir__described__=1
+        cat << '__EOF__'
+  --localstatedir         modifiable single-machine data [PREFIX/var]
+__EOF__
+    fi
+    if test -z "$libdatadir__described__"; then
+        libdatadir__described__=1
+        cat << '__EOF__'
+  --libdatadir            miscellaneous files for libraries [PREFIX/libdata]
+__EOF__
+    fi
+    if test -z "$TOOLKIT_HOME__described__"; then
+        TOOLKIT_HOME__described__=1
+        cat << '__EOF__'
+  --toolkit-home          the location of the toolkit installation [/usr]
+__EOF__
+    fi
+fi
+    cat << '__EOF__'
 
 Build Types:
   --debug                 add extra compile flags for debug builds
@@ -124,6 +153,7 @@
   --enable-gui
 
 __EOF__
+    abort_configure
 }
 
 # create temporary directory
@@ -139,26 +169,39 @@
 touch "$TEMP_DIR/options"
 touch "$TEMP_DIR/features"
 
-# define standard variables
-# also define standard prefix (this is where we will search for config.site)
-prefix=/usr
-exec_prefix=
-bindir=
-sbindir=
-libdir=
-libexecdir=
-datarootdir=
-datadir=
-sysconfdir=
-sharedstatedir=
-localstatedir=
-runstatedir=
-includedir=
-infodir=
-localedir=
-mandir=
-
-# custom variables
+# config variables
+if true \
+      ; then
+    :
+    if test -z "$prefix__initialized__"; then
+        prefix__initialized__=1
+        prefix="`pwd`/work"
+    fi
+    if test -z "$exec_prefix__initialized__"; then
+        exec_prefix__initialized__=1
+        exec_prefix=""
+    fi
+    if test -z "$libdir__initialized__"; then
+        libdir__initialized__=1
+        libdir=""
+    fi
+    if test -z "$datarootdir__initialized__"; then
+        datarootdir__initialized__=1
+        datarootdir=""
+    fi
+    if test -z "$localstatedir__initialized__"; then
+        localstatedir__initialized__=1
+        localstatedir="/var"
+    fi
+    if test -z "$libdatadir__initialized__"; then
+        libdatadir__initialized__=1
+        libdatadir="$prefix/libdata"
+    fi
+    if test -z "$TOOLKIT_HOME__initialized__"; then
+        TOOLKIT_HOME__initialized__=1
+        TOOLKIT_HOME="/usr"
+    fi
+fi
 
 # features
 FEATURE_DB=auto
@@ -170,27 +213,18 @@
 for ARG in "$@"
 do
     case "$ARG" in
-        "--prefix="*)         prefix=${ARG#--prefix=} ;;
-        "--exec-prefix="*)    exec_prefix=${ARG#--exec-prefix=} ;;
-        "--bindir="*)         bindir=${ARG#----bindir=} ;;
-        "--sbindir="*)        sbindir=${ARG#--sbindir=} ;;
-        "--libdir="*)         libdir=${ARG#--libdir=} ;;
-        "--libexecdir="*)     libexecdir=${ARG#--libexecdir=} ;;
-        "--datarootdir="*)    datarootdir=${ARG#--datarootdir=} ;;
-        "--datadir="*)        datadir=${ARG#--datadir=} ;;
-        "--sysconfdir="*)     sysconfdir=${ARG#--sysconfdir=} ;;
-        "--sharedstatedir="*) sharedstatedir=${ARG#--sharedstatedir=} ;;
-        "--localstatedir="*)  localstatedir=${ARG#--localstatedir=} ;;
-        "--runstatedir="*)    runstatedir=${ARG#--runstatedir=} ;;
-        "--includedir="*)     includedir=${ARG#--includedir=} ;;
-        "--infodir="*)        infodir=${ARG#--infodir=} ;;
-        "--mandir"*)          mandir=${ARG#--mandir} ;;
-        "--localedir"*)       localedir=${ARG#--localedir} ;;
-        "--help"*)            printhelp; abort_configure ;;
-        "--debug")            BUILD_TYPE="debug" ;;
-        "--release")          BUILD_TYPE="release" ;;
+        "--prefix="*) prefix=${ARG#--prefix=} ;;
+        "--exec-prefix="*) exec_prefix=${ARG#--exec-prefix=} ;;
+        "--libdir="*) libdir=${ARG#--libdir=} ;;
+        "--datarootdir="*) datarootdir=${ARG#--datarootdir=} ;;
+        "--localstatedir="*) localstatedir=${ARG#--localstatedir=} ;;
+        "--libdatadir="*) libdatadir=${ARG#--libdatadir=} ;;
+        "--toolkit-home="*) TOOLKIT_HOME=${ARG#--toolkit-home=} ;;
+        "--help"*) printhelp ;;
+        "--debug") BUILD_TYPE="debug" ;;
+        "--release") BUILD_TYPE="release" ;;
         "--toolkit="*) OPT_TOOLKIT=${ARG#--toolkit=} ;;
-        "--toolkit")  echo "option '$ARG' needs a value:"; echo "  $ARG=(gtk3|cli|gtk2|wpf)"; abort_configure ;;
+        "--toolkit") echo "option '$ARG' needs a value:"; echo "  $ARG=(gtk3|cli|gtk2|wpf)"; abort_configure ;;
         "--enable-db") FEATURE_DB=on ;;
         "--disable-db") unset FEATURE_DB ;;
         "--enable-gui") FEATURE_GUI=on ;;
@@ -236,22 +270,6 @@
 : ${mandir:='${datarootdir}/man'}
 : ${localedir:='${datarootdir}/locale'}
 
-# remember the above values and compare them later
-orig_bindir="$bindir"
-orig_sbindir="$sbindir"
-orig_libdir="$libdir"
-orig_libexecdir="$libexecdir"
-orig_datarootdir="$datarootdir"
-orig_datadir="$datadir"
-orig_sysconfdir="$sysconfdir"
-orig_sharedstatedir="$sharedstatedir"
-orig_localstatedir="$localstatedir"
-orig_runstatedir="$runstatedir"
-orig_includedir="$includedir"
-orig_infodir="$infodir"
-orig_mandir="$mandir"
-orig_localedir="$localedir"
-
 # check if a config.site exists and load it
 if [ -n "$CONFIG_SITE" ]; then
     # CONFIG_SITE may contain space separated file names
@@ -297,20 +315,12 @@
 cat > "$TEMP_DIR/vars.mk" << __EOF__
 prefix=$prefix
 exec_prefix=$exec_prefix
-bindir=$bindir
-sbindir=$sbindir
 libdir=$libdir
-libexecdir=$libexecdir
 datarootdir=$datarootdir
-datadir=$datadir
-sysconfdir=$sysconfdir
-sharedstatedir=$sharedstatedir
 localstatedir=$localstatedir
-runstatedir=$runstatedir
-includedir=$includedir
-infodir=$infodir
-mandir=$mandir
-localedir=$localedir
+libdatadir=$libdatadir
+SRCDIR=$SRCDIR
+TOOLKIT_HOME=$TOOLKIT_HOME
 __EOF__
 
 # toolchain detection utilities
@@ -877,7 +887,7 @@
 
 echo "configure finished"
 echo
-echo "Toolchain"
+echo "Toolchain:"
 echo "  name:           $TOOLCHAIN_NAME"
 if [ -n "$TOOLCHAIN_CC" ]; then
     echo "  cc:             $TOOLCHAIN_CC"
@@ -892,65 +902,37 @@
     echo "  default C std:  $TOOLCHAIN_CSTD"
 fi
 echo
-echo "Build Config:"
-echo "  prefix:         $prefix"
-echo "  exec_prefix:    $exec_prefix"
-if [ "$orig_bindir" != "$bindir" ]; then
-    echo "  bindir:      $bindir"
-fi
-if [ "$orig_sbindir" != "$sbindir" ]; then
-    echo "  sbindir:     $sbindir"
-fi
-if [ "$orig_libdir" != "$libdir" ]; then
-    echo "  libdir:         $libdir"
-fi
-if [ "$orig_libexecdir" != "$libexecdir" ]; then
-    echo "  libexecdir:     $libexecdir"
-fi
-if [ "$orig_datarootdir" != "$datarootdir" ]; then
-    echo "  datarootdir:    $datarootdir"
-fi
-if [ "$orig_datadir" != "$datadir" ]; then
-    echo "  datadir:        $datadir"
-fi
-if [ "$orig_sysconfdir" != "$sysconfdir" ]; then
-    echo "  sysconfdir:     $sysconfdir"
-fi
-if [ "$orig_sharedstatedir" != "$sharedstatedir" ]; then
-    echo "  sharedstatedir: $sharedstatedir"
-fi
-if [ "$orig_localstatedir" != "$localstatedir" ]; then
-    echo "  localstatedir:  $localstatedir"
-fi
-if [ "$orig_runstatedir" != "$runstatedir" ]; then
-    echo "  runstatedir:    $runstatedir"
-fi
-if [ "$orig_includedir" != "$includedir" ]; then
-    echo "  includedir:     $includedir"
-fi
-if [ "$orig_infodir" != "$infodir" ]; then
-    echo "  infodir:        $infodir"
-fi
-if [ "$orig_mandir" != "$mandir" ]; then
-    echo "  mandir:         $mandir"
-fi
-if [ "$orig_localedir" != "$localedir" ]; then
-    echo "  localedir:      $localedir"
-fi
+echo "Config:"
+    printf '  %-16s' 'prefix:'
+    echo "$prefix"
+    printf '  %-16s' 'exec-prefix:'
+    echo "$exec_prefix"
+    printf '  %-16s' 'libdir:'
+    echo "$libdir"
+    printf '  %-16s' 'datarootdir:'
+    echo "$datarootdir"
+    printf '  %-16s' 'localstatedir:'
+    echo "$localstatedir"
+    printf '  %-16s' 'libdatadir:'
+    echo "$libdatadir"
+    printf '  %-16s' 'toolkit-home:'
+    echo "$TOOLKIT_HOME"
 echo
 echo "Options:"
 cat "$TEMP_DIR/options"
 echo
 echo "Features:"
+printf '  %-16s' 'db:'
 if [ -n "$FEATURE_DB" ]; then
-echo "  db: on"
+    echo 'on'
 else
-echo "  db: off"
+    echo 'off'
 fi
+printf '  %-16s' 'gui:'
 if [ -n "$FEATURE_GUI" ]; then
-echo "  gui: on"
+    echo 'on'
 else
-echo "  gui: off"
+    echo 'off'
 fi
 echo
 
--- a/test/make/configure.vm	Sat Nov 29 13:50:15 2025 +0100
+++ b/test/make/configure.vm	Sat Nov 29 17:31:03 2025 +0100
@@ -86,27 +86,30 @@
 printhelp()
 {
     echo "Usage: $0 [OPTIONS]..."
-    cat << __EOF__
-Installation directories:
-  --prefix=PREFIX         path prefix for architecture-independent files
-                          [${D}prefix]
-  --exec-prefix=EPREFIX   path prefix for architecture-dependent files
-                          [PREFIX]
-
-  --bindir=DIR            user executables [EPREFIX/bin]
-  --sbindir=DIR           system admin executables [EPREFIX/sbin]
-  --libexecdir=DIR        program executables [EPREFIX/libexec]
-  --sysconfdir=DIR        system configuration files [PREFIX/etc]
-  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
-  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
-  --runstatedir=DIR       run-time variable data [LOCALSTATEDIR/run]
-  --libdir=DIR            object code libraries [EPREFIX/lib]
-  --includedir=DIR        C header files [PREFIX/include]
-  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
-  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
-  --infodir=DIR           info documentation [DATAROOTDIR/info]
-  --mandir=DIR            man documentation [DATAROOTDIR/man]
-  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+    echo 'Configuration:'
+#foreach( $cfg in $config )
+if true \
+#if( $cfg.platform )
+    && isplatform "${cfg.platform}" \
+#end
+#foreach( $np in $cfg.notList )
+      && notisplatform "${np}" \
+#end
+      ; then
+    :
+    #foreach( $var in $cfg.vars )
+    #if( $var.overridable )
+    if test -z "${D}${var.varName}__described__"; then
+        ${var.varName}__described__=1
+        cat << '__EOF__'
+${var.helpText}
+__EOF__
+    fi
+    #end
+    #end
+fi
+#end
+    cat << '__EOF__'
 
 Build Types:
   --debug                 add extra compile flags for debug builds
@@ -127,6 +130,7 @@
 #end
 
 __EOF__
+    abort_configure
 }
 
 # create temporary directory
@@ -142,26 +146,7 @@
 touch "$TEMP_DIR/options"
 touch "$TEMP_DIR/features"
 
-# define standard variables
-# also define standard prefix (this is where we will search for config.site)
-prefix=/usr
-exec_prefix=
-bindir=
-sbindir=
-libdir=
-libexecdir=
-datarootdir=
-datadir=
-sysconfdir=
-sharedstatedir=
-localstatedir=
-runstatedir=
-includedir=
-infodir=
-localedir=
-mandir=
-
-# custom variables
+# config variables
 #foreach( $cfg in $config )
 if true \
 #if( $cfg.platform )
@@ -171,11 +156,17 @@
       && notisplatform "${np}" \
 #end
       ; then
+    :
     #foreach( $var in $cfg.vars )
-    #if( $var.exec )
-    ${var.varName}=`${var.value}`
-    #else
-    ${var.varName}="${var.value}"
+    #if( $var.overridable )
+    if test -z "${D}${var.varName}__initialized__"; then
+        ${var.varName}__initialized__=1
+        #if( $var.exec )
+        ${var.varName}=`${var.value}`
+        #else
+        ${var.varName}="${var.value}"
+        #end
+    fi
     #end
     #end
 fi
@@ -195,28 +186,17 @@
 for ARG in "$@"
 do
     case "$ARG" in
-        "--prefix="*)         prefix=${D}{ARG#--prefix=} ;;
-        "--exec-prefix="*)    exec_prefix=${D}{ARG#--exec-prefix=} ;;
-        "--bindir="*)         bindir=${D}{ARG#----bindir=} ;;
-        "--sbindir="*)        sbindir=${D}{ARG#--sbindir=} ;;
-        "--libdir="*)         libdir=${D}{ARG#--libdir=} ;;
-        "--libexecdir="*)     libexecdir=${D}{ARG#--libexecdir=} ;;
-        "--datarootdir="*)    datarootdir=${D}{ARG#--datarootdir=} ;;
-        "--datadir="*)        datadir=${D}{ARG#--datadir=} ;;
-        "--sysconfdir="*)     sysconfdir=${D}{ARG#--sysconfdir=} ;;
-        "--sharedstatedir="*) sharedstatedir=${D}{ARG#--sharedstatedir=} ;;
-        "--localstatedir="*)  localstatedir=${D}{ARG#--localstatedir=} ;;
-        "--runstatedir="*)    runstatedir=${D}{ARG#--runstatedir=} ;;
-        "--includedir="*)     includedir=${D}{ARG#--includedir=} ;;
-        "--infodir="*)        infodir=${D}{ARG#--infodir=} ;;
-        "--mandir"*)          mandir=${D}{ARG#--mandir} ;;
-        "--localedir"*)       localedir=${D}{ARG#--localedir} ;;
-        "--help"*)            printhelp; abort_configure ;;
-        "--debug")            BUILD_TYPE="debug" ;;
-        "--release")          BUILD_TYPE="release" ;;
+    #foreach( $var in $vars )
+    #if ($var.overridable)
+        "--${var.arg}="*) ${var.varName}=${D}{ARG#--${var.arg}=} ;;
+    #end
+    #end
+        "--help"*) printhelp ;;
+        "--debug") BUILD_TYPE="debug" ;;
+        "--release") BUILD_TYPE="release" ;;
     #foreach( $opt in $options )
         "--${opt.arg}="*) ${opt.varName}=${D}{ARG#--${opt.arg}=} ;;
-        "--${opt.arg}")  echo "option '$ARG' needs a value:"; echo "  $ARG=${opt.valuesString}"; abort_configure ;;
+        "--${opt.arg}") echo "option '$ARG' needs a value:"; echo "  $ARG=${opt.valuesString}"; abort_configure ;;
     #end
     #foreach( $feature in $features )
         "--enable-${feature.arg}") ${feature.varName}=on ;;
@@ -264,22 +244,6 @@
 : ${mandir:='${datarootdir}/man'}
 : ${localedir:='${datarootdir}/locale'}
 
-# remember the above values and compare them later
-orig_bindir="$bindir"
-orig_sbindir="$sbindir"
-orig_libdir="$libdir"
-orig_libexecdir="$libexecdir"
-orig_datarootdir="$datarootdir"
-orig_datadir="$datadir"
-orig_sysconfdir="$sysconfdir"
-orig_sharedstatedir="$sharedstatedir"
-orig_localstatedir="$localstatedir"
-orig_runstatedir="$runstatedir"
-orig_includedir="$includedir"
-orig_infodir="$infodir"
-orig_mandir="$mandir"
-orig_localedir="$localedir"
-
 # check if a config.site exists and load it
 if [ -n "$CONFIG_SITE" ]; then
     # CONFIG_SITE may contain space separated file names
@@ -324,22 +288,6 @@
 
 # generate vars.mk
 cat > "$TEMP_DIR/vars.mk" << __EOF__
-prefix=$prefix
-exec_prefix=$exec_prefix
-bindir=$bindir
-sbindir=$sbindir
-libdir=$libdir
-libexecdir=$libexecdir
-datarootdir=$datarootdir
-datadir=$datadir
-sysconfdir=$sysconfdir
-sharedstatedir=$sharedstatedir
-localstatedir=$localstatedir
-runstatedir=$runstatedir
-includedir=$includedir
-infodir=$infodir
-mandir=$mandir
-localedir=$localedir
 #foreach( $var in $vars )
 ${var.varName}=${D}${var.varName}
 #end
@@ -744,7 +692,7 @@
 
 echo "configure finished"
 echo
-echo "Toolchain"
+echo "Toolchain:"
 echo "  name:           $TOOLCHAIN_NAME"
 if [ -n "$TOOLCHAIN_CC" ]; then
     echo "  cc:             $TOOLCHAIN_CC"
@@ -759,51 +707,13 @@
     echo "  default C std:  $TOOLCHAIN_CSTD"
 fi
 echo
-echo "Build Config:"
-echo "  prefix:         $prefix"
-echo "  exec_prefix:    $exec_prefix"
-if [ "$orig_bindir" != "$bindir" ]; then
-    echo "  bindir:      $bindir"
-fi
-if [ "$orig_sbindir" != "$sbindir" ]; then
-    echo "  sbindir:     $sbindir"
-fi
-if [ "$orig_libdir" != "$libdir" ]; then
-    echo "  libdir:         $libdir"
-fi
-if [ "$orig_libexecdir" != "$libexecdir" ]; then
-    echo "  libexecdir:     $libexecdir"
-fi
-if [ "$orig_datarootdir" != "$datarootdir" ]; then
-    echo "  datarootdir:    $datarootdir"
-fi
-if [ "$orig_datadir" != "$datadir" ]; then
-    echo "  datadir:        $datadir"
-fi
-if [ "$orig_sysconfdir" != "$sysconfdir" ]; then
-    echo "  sysconfdir:     $sysconfdir"
-fi
-if [ "$orig_sharedstatedir" != "$sharedstatedir" ]; then
-    echo "  sharedstatedir: $sharedstatedir"
-fi
-if [ "$orig_localstatedir" != "$localstatedir" ]; then
-    echo "  localstatedir:  $localstatedir"
-fi
-if [ "$orig_runstatedir" != "$runstatedir" ]; then
-    echo "  runstatedir:    $runstatedir"
-fi
-if [ "$orig_includedir" != "$includedir" ]; then
-    echo "  includedir:     $includedir"
-fi
-if [ "$orig_infodir" != "$infodir" ]; then
-    echo "  infodir:        $infodir"
-fi
-if [ "$orig_mandir" != "$mandir" ]; then
-    echo "  mandir:         $mandir"
-fi
-if [ "$orig_localedir" != "$localedir" ]; then
-    echo "  localedir:      $localedir"
-fi
+echo "Config:"
+#foreach( $var in $vars )
+#if ($var.overridable)
+    printf '  %-16s' '${var.arg}:'
+    echo "${D}${var.varName}"
+#end
+#end
 #if ( $options.size() > 0 )
 echo
 echo "Options:"
@@ -813,10 +723,11 @@
 echo
 echo "Features:"
 #foreach( $feature in $features )
+printf '  %-16s' '$feature.name:'
 if [ -n "${D}${feature.varName}" ]; then
-echo "  $feature.name: on"
+    echo 'on'
 else
-echo "  $feature.name: off"
+    echo 'off'
 fi
 #end
 #end
--- a/test/make/project.xml	Sat Nov 29 13:50:15 2025 +0100
+++ b/test/make/project.xml	Sat Nov 29 17:31:03 2025 +0100
@@ -1,15 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="0.4" xmlns="http://unixwork.de/uwproj">
 	<!-- makefile config -->
+    <config>
+        <prefix/>
+        <libdir/>
+        <var name="HOST" exec="true">uname -n</var>
+    </config>
 	<config not="mingw">
 		<var name="PWD">pwd</var>
 	</config>
 	<config platform="mingw">
 		<var name="PWD">pwd -W</var>
 	</config>
-	<config>
-		<var name="HOST" exec="true">uname -n</var>
-	</config>
 	
 	<dependency>
 		<lang>c</lang>
--- a/test/make/project2.xml	Sat Nov 29 13:50:15 2025 +0100
+++ b/test/make/project2.xml	Sat Nov 29 17:31:03 2025 +0100
@@ -1,6 +1,16 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="0.4" xmlns="http://unixwork.de/uwproj">
-	<dependency name="curl" platform="windows">
+    <config>
+        <prefix>`pwd`/work</prefix>
+        <libdir/>
+        <datarootdir/>
+        <localstatedir>/var</localstatedir>
+        <var name="libdatadir" option-help="miscellaneous files for libraries [PREFIX/libdata]">$prefix/libdata</var>
+        <var name="SRCDIR" exec="true">pwd</var>
+        <var name="TOOLKIT_HOME" option-help="the location of the toolkit installation [%default]">/usr</var>
+    </config>
+
+    <dependency name="curl" platform="windows">
 		<cflags>-I/mingw/include</cflags>
 		<ldflags>-lcurl</ldflags>
 	</dependency>
--- a/test/make/uwproj.xsd	Sat Nov 29 13:50:15 2025 +0100
+++ b/test/make/uwproj.xsd	Sat Nov 29 17:31:03 2025 +0100
@@ -29,23 +29,61 @@
             <xs:documentation>
                 <p>
                     The configuration section.
-                    Consists of an arbitrary number of <code>var</code> elements.
+                    Consists of an arbitrary number of <code>var</code> elements and pre-defined elements for
+                    standard installation directories. If you want to use standard installation directories, you
+                    must list the wanted variables here.
                 </p>
                 <p>
                     The optional <code>platform</code> attribute may specify a <em>single</em> platform identifier and
                     the optional <code>not</code> attribute may specify a comma-separated list of platform identifiers.
                     The configure script shall skip this config declaration if the detected platform is not matching
                     the filter specification of these attributes.
+                    When multiple config sections have a matching filter, and declare the same variables, the settings
+                    of the first matching config section will be used for the affected variables.
                 </p>
             </xs:documentation>
         </xs:annotation>
         <xs:sequence>
+            <xs:element name="prefix" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="exec-prefix" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="bindir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="sbindir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="libdir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="libexecdir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="datarootdir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="datadir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="sysconfdir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="sharedstatedir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="localstatedir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="runstatedir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="includedir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="infodir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="localedir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="mandir" type="StandardConfigVarType" minOccurs="0"/>
             <xs:element name="var" type="ConfigVarType" minOccurs="0" maxOccurs="unbounded"/>
         </xs:sequence>
         <xs:attribute name="platform" type="xs:string"/>
         <xs:attribute name="not" type="xs:string"/>
     </xs:complexType>
 
+    <xs:complexType name="StandardConfigVarType">
+        <xs:annotation>
+            <xs:documentation>
+                The definition of a standard configuration variable.
+                <p>
+                    You may customize the value and the help text,
+                    but the variable name and the option name are pre-defined.
+                </p>
+            </xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="option-help" type="xs:string"/>
+                <xs:attribute name="exec" type="xs:boolean" default="false"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
     <xs:complexType name="ConfigVarType">
         <xs:annotation>
             <xs:documentation>
@@ -55,14 +93,23 @@
                     written to the resulting config file (in contrast to make variables, which are only
                     written to the config file).
                     The <code>name</code> attribute is mandatory, the value is defined by the text body of the element.
-                    The optional Boolean <code>exec</code> attribute (false by default) controls, whether the entire
-                    definition is automatically executed under command substitution.
+                    The optional Boolean <code>exec</code> attribute (false by default) controls, whether value denotes
+                    a command which shall be executed at configuration time to produce the value.
+                    With <code>option</code> and <code>option-help</code> you can control how the variable can be
+                    overridden on the command line. When you don't specify either of those attributes, no command
+                    line option will be generated. When you provide a <code>option-help</code>, but do not specify the
+                    <code>option</code> name, a name is generated.
+                    You can use the string <code>%default</code> in your help text when you want to show the default
+                    value in the text. When <code>exec</code> is used, the default will not be resolved in the help
+                    text and instead the command is shown (to avoid breaking the formatting).
                 </p>
             </xs:documentation>
         </xs:annotation>
         <xs:simpleContent>
             <xs:extension base="xs:string">
                 <xs:attribute name="name" type="xs:string" use="required"/>
+                <xs:attribute name="option" type="xs:string"/>
+                <xs:attribute name="option-help" type="xs:string"/>
                 <xs:attribute name="exec" type="xs:boolean" default="false"/>
             </xs:extension>
         </xs:simpleContent>

mercurial