From ed653f0cc2b0b5dc05286538f0411d3bf3212efd Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 2 Sep 2022 10:45:23 +0200 Subject: [PATCH] Add ability to specify substitutions as key-value pairs --- README.md | 34 ++++++++++-- libbuild2-autoconf-tests/manifest | 4 +- libbuild2-autoconf-tests/module/testscript | 23 ++++++++ .../libbuild2/autoconf/init.cxx | 5 ++ .../libbuild2/autoconf/rule.cxx | 52 ++++++++++++++----- .../libbuild2/autoconf/rule.hxx | 2 + libbuild2-autoconf/manifest | 4 +- 7 files changed, 103 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 1dad088..8659cf4 100644 --- a/README.md +++ b/README.md @@ -55,8 +55,8 @@ h{config}: in{config} ``` Besides the built-in configuration options, custom substitutions can be -specified as `buildfile` variables in the same way as with the -[`in`][module-in] module. For example: +specified as `buildfile` variables or key-value pairs in the same way as with +the [`in`][module-in] module. For example, as `buildfile` variables: ``` /* 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} diff --git a/libbuild2-autoconf-tests/manifest b/libbuild2-autoconf-tests/manifest index cca66a4..39b051a 100644 --- a/libbuild2-autoconf-tests/manifest +++ b/libbuild2-autoconf-tests/manifest @@ -7,5 +7,5 @@ license: MIT ; MIT License. description-file: README.md url: https://github.com/build2/libbuild2-autoconf email: users@build2.org -depends: * build2 >= 0.15.0- -depends: * bpkg >= 0.15.0- +depends: * build2 >= 0.16.0- +depends: * bpkg >= 0.16.0- diff --git a/libbuild2-autoconf-tests/module/testscript b/libbuild2-autoconf-tests/module/testscript index 63d1089..6e2af25 100644 --- a/libbuild2-autoconf-tests/module/testscript +++ b/libbuild2-autoconf-tests/module/testscript @@ -401,3 +401,26 @@ cat config.h >>EOO # define PREFIX_zzz_TEST_DUMMY5_H PREFIX_zzz_TEST_DUMMY4_H #endif /*zzz_TEST_DUMMY3_H*/ EOO + +: substitution-map +: +mkdir build; +ln -s ../../bootstrap.build ../../root.build build/; +cat <=config.h.in; + #undef _GNU_SOURCE + #undef _POSIX_SOURCE + #undef FOO + EOI +$* <>EOO + #undef _GNU_SOURCE + #define _POSIX_SOURCE 1 + #define FOO 1 + EOO diff --git a/libbuild2-autoconf/libbuild2/autoconf/init.cxx b/libbuild2-autoconf/libbuild2/autoconf/init.cxx index 1fd487b..6ccd7b0 100644 --- a/libbuild2-autoconf/libbuild2/autoconf/init.cxx +++ b/libbuild2-autoconf/libbuild2/autoconf/init.cxx @@ -43,6 +43,11 @@ namespace build2 // Built-in checks prefix. // vp.insert ("autoconf.prefix"); + + // Substitution map (an alias for in.substitutions). + // + vp.insert_alias (*vp.find ("in.substitutions"), + "autoconf.substitutions"); } // Register the rule. diff --git a/libbuild2-autoconf/libbuild2/autoconf/rule.cxx b/libbuild2-autoconf/libbuild2/autoconf/rule.cxx index 8e08dc4..ded2244 100644 --- a/libbuild2-autoconf/libbuild2/autoconf/rule.cxx +++ b/libbuild2-autoconf/libbuild2/autoconf/rule.cxx @@ -144,6 +144,7 @@ namespace build2 const char* nl, char sym, bool strict, + const substitution_map* smap, const optional& null) const { auto ws = [] (char c) @@ -182,7 +183,7 @@ namespace build2 &l, a, &t, &dd, &dd_skip, - nl, strict, &null, + nl, strict, smap, &null, &s] (const string& name, bool value = true) -> optional { @@ -195,7 +196,7 @@ namespace build2 a, t, dd, dd_skip, name, 1 /* flags */, - strict, null)); + strict, smap, null)); assert (ov); // C identifier is a valid variable name. 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:: @@ -478,6 +480,7 @@ namespace build2 action a, const target& t, const string& n, optional flags, + const substitution_map* smap, const optional& null) const { if (flags) @@ -508,7 +511,7 @@ namespace build2 // variable is unlikely, something like const or volatile is // possible. Since there is no way to undefine a buildfile variable // (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 // 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; }; - // 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 (t[n]); + }; + + // Note: original name in the custom substitution lookup. // 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 // duplicates) followed by the main check while prefixing all the @@ -616,11 +639,12 @@ namespace build2 // Buildscript). // auto base = [this, - &l, &t, a, &null, + &l, &t, a, smap, &null, &md, &p, &ns, - &find, &append, &prefix] (const string& n, - const char* bs, - const auto& base) -> void + &find, &custom, + &append, &prefix] (const string& n, + const char* bs, + const auto& base) -> void { auto df = make_diag_frame ( [&n] (const diag_record& dr) @@ -666,9 +690,9 @@ namespace build2 md.checks.emplace (pn, n); - if (t[n]) - append ( - this->in::rule::lookup (l, a, t, n, nullopt, null).c_str ()); + if (custom (n)) + append (this->in::rule::lookup ( + l, a, t, n, nullopt, smap, null).c_str ()); else { 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); } } } diff --git a/libbuild2-autoconf/libbuild2/autoconf/rule.hxx b/libbuild2-autoconf/libbuild2/autoconf/rule.hxx index d9b30a9..ed86020 100644 --- a/libbuild2-autoconf/libbuild2/autoconf/rule.hxx +++ b/libbuild2-autoconf/libbuild2/autoconf/rule.hxx @@ -39,6 +39,7 @@ namespace build2 const char*, char, bool, + const substitution_map*, const optional&) const override; virtual string @@ -46,6 +47,7 @@ namespace build2 action, const target&, const string&, optional, + const substitution_map*, const optional&) const override; }; } diff --git a/libbuild2-autoconf/manifest b/libbuild2-autoconf/manifest index 2d882b1..7fbe965 100644 --- a/libbuild2-autoconf/manifest +++ b/libbuild2-autoconf/manifest @@ -9,6 +9,6 @@ url: https://github.com/build2/libbuild2-autoconf email: users@build2.org build-warning-email: builds@build2.org builds: all -depends: * build2 >= 0.15.0- -depends: * bpkg >= 0.15.0- +depends: * build2 >= 0.16.0- +depends: * bpkg >= 0.16.0- tests: * libbuild2-autoconf-tests == $