Add ability to specify substitutions as key-value pairs

This commit is contained in:
Boris Kolpackov 2022-09-02 10:45:23 +02:00
parent 48fb7e2cc9
commit ed653f0cc2
7 changed files with 103 additions and 21 deletions

View File

@ -55,8 +55,8 @@ h{config}: in{config}
``` ```
Besides the built-in configuration options, custom substitutions can be Besides the built-in configuration options, custom substitutions can be
specified as `buildfile` variables in the same way as with the specified as `buildfile` variables or key-value pairs in the same way as with
[`in`][module-in] module. For example: the [`in`][module-in] module. For example, as `buildfile` variables:
``` ```
/* config.h.in */ /* config.h.in */
@ -76,7 +76,35 @@ h{config}: in{config}
} }
``` ```
This mechanism can also be used to override the built-in checks, for example: As key-value pairs in the `autoconf.substitutions` map (which is an alias for
the `in.substitutions` variable; see the [`in`][module-in] module for
details):
```
/* config.h.in */
#undef _GNU_SOURCE
#undef _POSIX_SOURCE
```
```
gnu_source = ($c.stdlib == 'glibc')
posix_source = ($c.target.class != 'windows' && !$gnu_source)
h{config}: in{config}
{
autoconf.substitutions = _GNU_SOURCE@$gnu_source
autoconf.substitutions += _POSIX_SOURCE@$posix_source
}
```
In particular, the `autoconf.substitutions` mechanism is the only way to have
substitutions that cannot be specified as `buildfile` variables because they
start with an underscore (and thus are reserved, as in the above example) or
refer to one of the predefined variables.
The custom substitutions can also be used to override the built-in checks, for
example:
``` ```
h{config}: in{config} h{config}: in{config}

View File

@ -7,5 +7,5 @@ license: MIT ; MIT License.
description-file: README.md description-file: README.md
url: https://github.com/build2/libbuild2-autoconf url: https://github.com/build2/libbuild2-autoconf
email: users@build2.org email: users@build2.org
depends: * build2 >= 0.15.0- depends: * build2 >= 0.16.0-
depends: * bpkg >= 0.15.0- depends: * bpkg >= 0.16.0-

View File

@ -401,3 +401,26 @@ cat config.h >>EOO
# define PREFIX_zzz_TEST_DUMMY5_H PREFIX_zzz_TEST_DUMMY4_H # define PREFIX_zzz_TEST_DUMMY5_H PREFIX_zzz_TEST_DUMMY4_H
#endif /*zzz_TEST_DUMMY3_H*/ #endif /*zzz_TEST_DUMMY3_H*/
EOO EOO
: substitution-map
:
mkdir build;
ln -s ../../bootstrap.build ../../root.build build/;
cat <<EOI >=config.h.in;
#undef _GNU_SOURCE
#undef _POSIX_SOURCE
#undef FOO
EOI
$* <<EOI &config.h &config.h.d;
gnu = false
./: h{config}: in{config}
{
autoconf.substitutions = _GNU_SOURCE@$gnu _POSIX_SOURCE@true
FOO = true
}
EOI
cat config.h >>EOO
#undef _GNU_SOURCE
#define _POSIX_SOURCE 1
#define FOO 1
EOO

View File

@ -43,6 +43,11 @@ namespace build2
// Built-in checks prefix. // Built-in checks prefix.
// //
vp.insert<string> ("autoconf.prefix"); vp.insert<string> ("autoconf.prefix");
// Substitution map (an alias for in.substitutions).
//
vp.insert_alias (*vp.find ("in.substitutions"),
"autoconf.substitutions");
} }
// Register the rule. // Register the rule.

View File

@ -144,6 +144,7 @@ namespace build2
const char* nl, const char* nl,
char sym, char sym,
bool strict, bool strict,
const substitution_map* smap,
const optional<string>& null) const const optional<string>& null) const
{ {
auto ws = [] (char c) auto ws = [] (char c)
@ -182,7 +183,7 @@ namespace build2
&l, &l,
a, &t, a, &t,
&dd, &dd_skip, &dd, &dd_skip,
nl, strict, &null, nl, strict, smap, &null,
&s] (const string& name, &s] (const string& name,
bool value = true) -> optional<bool> bool value = true) -> optional<bool>
{ {
@ -195,7 +196,7 @@ namespace build2
a, t, a, t,
dd, dd_skip, dd, dd_skip,
name, 1 /* flags */, name, 1 /* flags */,
strict, null)); strict, smap, null));
assert (ov); // C identifier is a valid variable name. assert (ov); // C identifier is a valid variable name.
string& v (*ov); string& v (*ov);
@ -470,7 +471,8 @@ namespace build2
} }
} }
in::rule::process (l, a, t, dd, dd_skip, s, b, nl, sym, strict, null); in::rule::process (
l, a, t, dd, dd_skip, s, b, nl, sym, strict, smap, null);
} }
string rule:: string rule::
@ -478,6 +480,7 @@ namespace build2
action a, const target& t, action a, const target& t,
const string& n, const string& n,
optional<uint64_t> flags, optional<uint64_t> flags,
const substitution_map* smap,
const optional<string>& null) const const optional<string>& null) const
{ {
if (flags) if (flags)
@ -508,7 +511,7 @@ namespace build2
// variable is unlikely, something like const or volatile is // variable is unlikely, something like const or volatile is
// possible. Since there is no way to undefine a buildfile variable // possible. Since there is no way to undefine a buildfile variable
// (becasue we could always see a value from the outer scope), we // (becasue we could always see a value from the outer scope), we
// will treat null as an indication to use the built-in check. // will treat null as an instruction to use the built-in check.
// While this clashes with the in.null semantics, it's just as // While this clashes with the in.null semantics, it's just as
// easy to set the variable to the real default value as to null. // easy to set the variable to the real default value as to null.
// //
@ -554,11 +557,31 @@ namespace build2
(!up || strchr (i->modifier, '!') != nullptr)) ? i : nullptr; (!up || strchr (i->modifier, '!') != nullptr)) ? i : nullptr;
}; };
// Note: original name in variable lookup. // Return true if there is a custom substitution for the name.
//
// Note: see above on the special NULL semantics.
//
auto custom = [&t, smap] (const string& n) -> bool
{
if (smap != nullptr)
{
auto i (smap->find (n));
// Note that we treat NULL as the "use built-in check" instruction
// (see above). So it's a return, not fall through.
//
if (i != smap->end ())
return i->second.has_value ();
}
return static_cast<bool> (t[n]);
};
// Note: original name in the custom substitution lookup.
// //
const check* c (find (en, pn == nullptr)); const check* c (find (en, pn == nullptr));
if (c != nullptr && !t[n]) if (c != nullptr && !custom (n))
{ {
// The plan is as follows: keep adding base checks (suppressing // The plan is as follows: keep adding base checks (suppressing
// duplicates) followed by the main check while prefixing all the // duplicates) followed by the main check while prefixing all the
@ -616,9 +639,10 @@ namespace build2
// Buildscript). // Buildscript).
// //
auto base = [this, auto base = [this,
&l, &t, a, &null, &l, &t, a, smap, &null,
&md, &p, &ns, &md, &p, &ns,
&find, &append, &prefix] (const string& n, &find, &custom,
&append, &prefix] (const string& n,
const char* bs, const char* bs,
const auto& base) -> void const auto& base) -> void
{ {
@ -666,9 +690,9 @@ namespace build2
md.checks.emplace (pn, n); md.checks.emplace (pn, n);
if (t[n]) if (custom (n))
append ( append (this->in::rule::lookup (
this->in::rule::lookup (l, a, t, n, nullopt, null).c_str ()); l, a, t, n, nullopt, smap, null).c_str ());
else else
{ {
if (*c->base != '\0') if (*c->base != '\0')
@ -706,7 +730,7 @@ namespace build2
} }
} }
return in::rule::lookup (l, a, t, n, nullopt, null); return in::rule::lookup (l, a, t, n, nullopt, smap, null);
} }
} }
} }

View File

@ -39,6 +39,7 @@ namespace build2
const char*, const char*,
char, char,
bool, bool,
const substitution_map*,
const optional<string>&) const override; const optional<string>&) const override;
virtual string virtual string
@ -46,6 +47,7 @@ namespace build2
action, const target&, action, const target&,
const string&, const string&,
optional<uint64_t>, optional<uint64_t>,
const substitution_map*,
const optional<string>&) const override; const optional<string>&) const override;
}; };
} }

View File

@ -9,6 +9,6 @@ url: https://github.com/build2/libbuild2-autoconf
email: users@build2.org email: users@build2.org
build-warning-email: builds@build2.org build-warning-email: builds@build2.org
builds: all builds: all
depends: * build2 >= 0.15.0- depends: * build2 >= 0.16.0-
depends: * bpkg >= 0.15.0- depends: * bpkg >= 0.16.0-
tests: * libbuild2-autoconf-tests == $ tests: * libbuild2-autoconf-tests == $