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
|
specified as `buildfile` variables in the same way as with the
|
||||||
[`in`][module-in] module. For example:
|
[`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}
|
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
|
## Adding new checks
|
||||||
|
|
||||||
To add a check for a new configuration option `<NAME>` simply create the
|
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:
|
continuations. For example:
|
||||||
|
|
||||||
```
|
```
|
||||||
// HAVE_FOO
|
// HAVE_BAR
|
||||||
#ifndef _WIN32
|
#if !defined(_WIN32) || \
|
||||||
# define HAVE_FOO 1
|
defined(__MINGW32__)
|
||||||
|
# define HAVE_BAR 1
|
||||||
#else
|
#else
|
||||||
# undef HAVE_FOO /* No foo on Windows. */
|
# undef HAVE_BAR /* No bar on Windows except with MinGW. */
|
||||||
#endif
|
#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
|
[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
|
[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/
|
[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_DUMMY1_H 1
|
||||||
#define zzz_TEST_DUMMY2_H 2
|
#define zzz_TEST_DUMMY2_H 2
|
||||||
EOO
|
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`.
|
// `cmake`, and `meson`.
|
||||||
//
|
//
|
||||||
vp.insert<string> ("autoconf.flavor");
|
vp.insert<string> ("autoconf.flavor");
|
||||||
|
|
||||||
|
// Built-in checks prefix.
|
||||||
|
//
|
||||||
|
vp.insert<string> ("autoconf.prefix");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the rule.
|
// Register the rule.
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
#include <libbuild2/autoconf/rule.hxx>
|
#include <libbuild2/autoconf/rule.hxx>
|
||||||
|
|
||||||
|
#include <cstring> // strcmp()
|
||||||
|
|
||||||
|
#include <libbuild2/depdb.hxx>
|
||||||
#include <libbuild2/target.hxx>
|
#include <libbuild2/target.hxx>
|
||||||
#include <libbuild2/algorithm.hxx>
|
#include <libbuild2/algorithm.hxx>
|
||||||
#include <libbuild2/diagnostics.hxx>
|
#include <libbuild2/diagnostics.hxx>
|
||||||
@ -19,11 +22,9 @@ namespace build2
|
|||||||
struct match_data
|
struct match_data
|
||||||
{
|
{
|
||||||
autoconf::flavor flavor;
|
autoconf::flavor flavor;
|
||||||
|
string prefix;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert (sizeof (match_data) <= target::data_size,
|
|
||||||
"insufficient space");
|
|
||||||
|
|
||||||
rule::
|
rule::
|
||||||
rule ()
|
rule ()
|
||||||
: in::rule ("autoconf.in 1",
|
: in::rule ("autoconf.in 1",
|
||||||
@ -31,6 +32,8 @@ namespace build2
|
|||||||
'@' /* symbol */,
|
'@' /* symbol */,
|
||||||
false /* strict */)
|
false /* strict */)
|
||||||
{
|
{
|
||||||
|
static_assert (sizeof (match_data) <= target::data_size,
|
||||||
|
"insufficient space");
|
||||||
}
|
}
|
||||||
|
|
||||||
recipe rule::
|
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;
|
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::
|
void rule::
|
||||||
process (const location& l,
|
process (const location& l,
|
||||||
action a, const target& t,
|
action a, const target& t,
|
||||||
@ -424,21 +457,63 @@ namespace build2
|
|||||||
// 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 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.
|
// easy to set the variable to the real default value as to null.
|
||||||
//
|
//
|
||||||
// 3. Return the build-in value form the catalog.
|
// 3. Return the build-in value form the catalog.
|
||||||
//
|
//
|
||||||
const check* e (checks + sizeof (checks) / sizeof (*checks));
|
const char* pn (nullptr); // Prefix-less name.
|
||||||
const check* i (lower_bound (checks, e,
|
|
||||||
n,
|
|
||||||
[] (const check& c, const string& n)
|
|
||||||
{
|
|
||||||
return n.compare (c.name) > 0;
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (i != e && n == i->name && !t[n])
|
const string& p (t.data<match_data> ().prefix);
|
||||||
return i->value;
|
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);
|
return in::rule::lookup (l, a, t, n, nullopt, null);
|
||||||
|
@ -24,6 +24,9 @@ namespace build2
|
|||||||
virtual recipe
|
virtual recipe
|
||||||
apply (action, target&) const override;
|
apply (action, target&) const override;
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
perform_update_depdb (action, const target&, depdb&) const override;
|
||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
process (const location&,
|
process (const location&,
|
||||||
action, const target&,
|
action, const target&,
|
||||||
|
Loading…
Reference in New Issue
Block a user