Add support for custom prefix in built-in checks
This commit is contained in:
parent
d1dc8180d4
commit
f0715ced26
59
README.md
59
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 `<NAME>` 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 `<NAME>` with its
|
||||
prefixed version if the `autoconf.prefix` functionality is in use (see above).
|
||||
This is done by textually substituting every occurrence of `<NAME>` that is
|
||||
separated on both left and right hand sides (that is, both characters
|
||||
immediately before and after `<NAME>` 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/
|
||||
|
@ -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 <<EOI >=config.h.in;
|
||||
#undef PREFIX_zzz_TEST_DUMMY1_H
|
||||
#undef PREFIX_zzz_TEST_DUMMY2_H
|
||||
EOI
|
||||
$* <<EOI &config.h &config.h.d;
|
||||
./: h{config}: in{config}
|
||||
{
|
||||
autoconf.prefix = PREFIX_
|
||||
|
||||
PREFIX_zzz_TEST_DUMMY2_H = '#define PREFIX_zzz_TEST_DUMMY2_H 2'
|
||||
}
|
||||
EOI
|
||||
cat config.h >>EOO
|
||||
#define PREFIX_zzz_TEST_DUMMY1_H 1
|
||||
#define PREFIX_zzz_TEST_DUMMY2_H 2
|
||||
EOO
|
||||
|
@ -39,6 +39,10 @@ namespace build2
|
||||
// `cmake`, and `meson`.
|
||||
//
|
||||
vp.insert<string> ("autoconf.flavor");
|
||||
|
||||
// Built-in checks prefix.
|
||||
//
|
||||
vp.insert<string> ("autoconf.prefix");
|
||||
}
|
||||
|
||||
// Register the rule.
|
||||
|
@ -1,5 +1,8 @@
|
||||
#include <libbuild2/autoconf/rule.hxx>
|
||||
|
||||
#include <cstring> // strcmp()
|
||||
|
||||
#include <libbuild2/depdb.hxx>
|
||||
#include <libbuild2/target.hxx>
|
||||
#include <libbuild2/algorithm.hxx>
|
||||
#include <libbuild2/diagnostics.hxx>
|
||||
@ -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<string> (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<match_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<match_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);
|
||||
|
@ -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&,
|
||||
|
Loading…
Reference in New Issue
Block a user