diff --git a/README.md b/README.md index 76744b5..fa30bd0 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,16 @@ 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: +``` +/* config.h.in */ + +#define PACKAGE_NAME @PACKAGE_NAME@ +#define PACKAGE_VERSION @PACKAGE_VERSION@ + +#undef HAVE_STRLCPY +#undef HAVE_STRLCAT +``` + ``` h{config}: in{config} { @@ -73,6 +83,40 @@ h{config}: in{config} } ``` +The build-in checks can be prefixed in order to avoid clashes with similarly +named macros in other headers. This is an especially good idea if the +resulting header is public. To enable this, we specify the prefix with +the `autoconf.prefix` variable and then use the prefixed versions of +the options in the `config.h.in` file. For example: + +``` +/* config.h.in */ + +#undef LIBFOO_HAVE_STRLCPY +#undef LIBFOO_HAVE_STRLCAT +``` + +``` +h{config}: in{config} +{ + autoconf.prefix = LIBFOO_ +} +``` + +Note that `autoconf.prefix` only affects the lookup of the built-in checks. +Custom substitutions and overrides of build-in checks must include the +prefix. For example: + +``` +h{config}: in{config} +{ + autoconf.prefix = LIBFOO_ + + LIBFOO_HAVE_STRLCPY = true +} +``` + + ## Adding new checks To add a check for a new configuration option `` simply create the @@ -92,14 +136,21 @@ there should be no double-quotes or backslashes except for line continuations. For example: ``` -// HAVE_FOO -#ifndef _WIN32 -# define HAVE_FOO 1 +// HAVE_BAR +#if !defined(_WIN32) || \ + defined(__MINGW32__) +# define HAVE_BAR 1 #else -# undef HAVE_FOO /* No foo on Windows. */ +# undef HAVE_BAR /* No bar on Windows except with MinGW. */ #endif ``` +Note also that the module implementation may need to replace `` with its +prefixed version if the `autoconf.prefix` functionality is in use (see above). +This is done by textually substituting every occurrence of `` that is +separated on both left and right hand sides (that is, both characters +immediately before and after `` are not `[A-Za-z0-9_]`). + [module-in]: https://build2.org/build2/doc/build2-build-system-manual.xhtml#module-in [proj-config]: https://build2.org/build2/doc/build2-build-system-manual.xhtml#proj-config [checks]: https://github.com/build2/libbuild2-autoconf/tree/master/libbuild2-autoconf/libbuild2/autoconf/checks/ diff --git a/libbuild2-autoconf-tests/basics/testscript b/libbuild2-autoconf-tests/basics/testscript index 0e7612d..f19f3fd 100644 --- a/libbuild2-autoconf-tests/basics/testscript +++ b/libbuild2-autoconf-tests/basics/testscript @@ -228,3 +228,24 @@ cat config.h >>EOO #define zzz_TEST_DUMMY1_H 1 #define zzz_TEST_DUMMY2_H 2 EOO + +: prefix +: +mkdir build; +ln -s ../../bootstrap.build ../../root.build build/; +cat <=config.h.in; + #undef PREFIX_zzz_TEST_DUMMY1_H + #undef PREFIX_zzz_TEST_DUMMY2_H + EOI +$* <>EOO + #define PREFIX_zzz_TEST_DUMMY1_H 1 + #define PREFIX_zzz_TEST_DUMMY2_H 2 + EOO diff --git a/libbuild2-autoconf/libbuild2/autoconf/init.cxx b/libbuild2-autoconf/libbuild2/autoconf/init.cxx index b466c4a..1fd487b 100644 --- a/libbuild2-autoconf/libbuild2/autoconf/init.cxx +++ b/libbuild2-autoconf/libbuild2/autoconf/init.cxx @@ -39,6 +39,10 @@ namespace build2 // `cmake`, and `meson`. // vp.insert ("autoconf.flavor"); + + // Built-in checks prefix. + // + vp.insert ("autoconf.prefix"); } // Register the rule. diff --git a/libbuild2-autoconf/libbuild2/autoconf/rule.cxx b/libbuild2-autoconf/libbuild2/autoconf/rule.cxx index 82d863c..4698c42 100644 --- a/libbuild2-autoconf/libbuild2/autoconf/rule.cxx +++ b/libbuild2-autoconf/libbuild2/autoconf/rule.cxx @@ -1,5 +1,8 @@ #include +#include // strcmp() + +#include #include #include #include @@ -19,11 +22,9 @@ namespace build2 struct match_data { autoconf::flavor flavor; + string prefix; }; - static_assert (sizeof (match_data) <= target::data_size, - "insufficient space"); - rule:: rule () : in::rule ("autoconf.in 1", @@ -31,6 +32,8 @@ namespace build2 '@' /* symbol */, false /* strict */) { + static_assert (sizeof (match_data) <= target::data_size, + "insufficient space"); } recipe rule:: @@ -71,11 +74,41 @@ namespace build2 } } - t.data (match_data {f}); + // Get the prefix if any. + // + string p (cast_empty (t["autoconf.prefix"])); + + t.data (match_data {f, move (p)}); return r; } + void rule:: + perform_update_depdb (action, const target& t, depdb& dd) const + { + tracer trace ("autoconf::rule::perform_update_depdb"); + + const match_data& md (t.data ()); + + // Then the flavor. + // + if (dd.expect (md.flavor == flavor::autoconf ? "autoconf" : + md.flavor == flavor::cmake ? "cmake" : + "meson") != nullptr) + l4 ([&]{trace << "flavor mismatch forcing update of" << t;}); + + // Then the prefix. + // + if (dd.expect (md.prefix) != nullptr) + l4 ([&]{trace << "prefix mismatch forcing update of" << t;}); + + // Note that at first it may seem necessary to add something like the + // full module version in lieu of the built-in checks database hash. + // Note, however, that any changes will be automatically taken care of + // (and with better precision) as part of the substituted variable value + // checks by in::rule. + } + void rule:: process (const location& l, action a, const target& t, @@ -424,21 +457,63 @@ namespace build2 // 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. - // While this clashes with the in.null semantics, it'ss 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. // // 3. Return the build-in value form the catalog. // - const check* e (checks + sizeof (checks) / sizeof (*checks)); - const check* i (lower_bound (checks, e, - n, - [] (const check& c, const string& n) - { - return n.compare (c.name) > 0; - })); + const char* pn (nullptr); // Prefix-less name. - if (i != e && n == i->name && !t[n]) - return i->value; + const string& p (t.data ().prefix); + if (!p.empty ()) + { + // Note that if there is no prefix, then we don't look for a + // built-in check. + // + if (n.size () > p.size () && n.compare (0, p.size (), p) == 0) + pn = n.c_str () + p.size (); + } + else + pn = n.c_str (); + + if (pn != nullptr) + { + const check* e (checks + sizeof (checks) / sizeof (*checks)); + const check* i (lower_bound (checks, e, + pn, + [] (const check& c, const char* pn) + { + return strcmp (c.name, pn) < 0; + })); + + // Note: original name in lookup. + // + if (i != e && strcmp (i->name, pn) == 0 && !t[n]) + { + string r (i->value); + + // Add "back" the prefix. + // + if (!p.empty ()) + { + auto sep = [] (char c) { return !alnum (c) && c != '_'; }; + + size_t m (n.size () - p.size ()); // Prefix-less name length. + + for (size_t i (0); (i = r.find (pn, i)) != string::npos; i += m) + { + if ((i == 0 || sep (r[i - 1])) && + (i + m == r.size () || sep (r[i + m]))) + { + r.insert (i, p); + i += p.size (); + } + } + } + + return r; + } + } } return in::rule::lookup (l, a, t, n, nullopt, null); diff --git a/libbuild2-autoconf/libbuild2/autoconf/rule.hxx b/libbuild2-autoconf/libbuild2/autoconf/rule.hxx index 626e991..5d6fdb2 100644 --- a/libbuild2-autoconf/libbuild2/autoconf/rule.hxx +++ b/libbuild2-autoconf/libbuild2/autoconf/rule.hxx @@ -24,6 +24,9 @@ namespace build2 virtual recipe apply (action, target&) const override; + virtual void + perform_update_depdb (action, const target&, depdb&) const override; + virtual void process (const location&, action, const target&,