aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/cc
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/cc')
-rw-r--r--libbuild2/cc/buildfile16
-rw-r--r--libbuild2/cc/common.cxx241
-rw-r--r--libbuild2/cc/common.hxx63
-rw-r--r--libbuild2/cc/common.txx15
-rw-r--r--libbuild2/cc/compile-rule.cxx1375
-rw-r--r--libbuild2/cc/compile-rule.hxx5
-rw-r--r--libbuild2/cc/functions.cxx4
-rw-r--r--libbuild2/cc/gcc.cxx177
-rw-r--r--libbuild2/cc/guess.cxx125
-rw-r--r--libbuild2/cc/init.cxx29
-rw-r--r--libbuild2/cc/install-rule.cxx524
-rw-r--r--libbuild2/cc/install-rule.hxx45
-rw-r--r--libbuild2/cc/lexer+comment.test.testscript5
-rw-r--r--libbuild2/cc/lexer+raw-string-literal.test.testscript2
-rw-r--r--libbuild2/cc/lexer.cxx34
-rw-r--r--libbuild2/cc/lexer.hxx30
-rw-r--r--libbuild2/cc/lexer.test.cxx2
-rw-r--r--libbuild2/cc/link-rule.cxx215
-rw-r--r--libbuild2/cc/module.cxx149
-rw-r--r--libbuild2/cc/module.hxx15
-rw-r--r--libbuild2/cc/msvc.cxx129
-rw-r--r--libbuild2/cc/parser.cxx24
-rw-r--r--libbuild2/cc/parser.hxx11
-rw-r--r--libbuild2/cc/parser.test.cxx2
-rw-r--r--libbuild2/cc/pkgconfig-libpkgconf.cxx7
-rw-r--r--libbuild2/cc/pkgconfig.cxx440
-rw-r--r--libbuild2/cc/pkgconfig.hxx8
-rw-r--r--libbuild2/cc/predefs-rule.cxx379
-rw-r--r--libbuild2/cc/predefs-rule.hxx45
-rw-r--r--libbuild2/cc/std.compat.cppm996
-rw-r--r--libbuild2/cc/std.cppm6795
-rw-r--r--libbuild2/cc/target.cxx27
-rw-r--r--libbuild2/cc/target.hxx35
-rw-r--r--libbuild2/cc/types.cxx15
-rw-r--r--libbuild2/cc/windows-rpath.cxx23
35 files changed, 11075 insertions, 932 deletions
diff --git a/libbuild2/cc/buildfile b/libbuild2/cc/buildfile
index e090e76..05e4c8c 100644
--- a/libbuild2/cc/buildfile
+++ b/libbuild2/cc/buildfile
@@ -11,19 +11,29 @@ libpkgconf = $config.build2.libpkgconf
if $libpkgconf
import impl_libs += libpkgconf%lib{pkgconf}
else
- import impl_libs += libpkg-config%lib{pkg-config}
+ import impl_libs += libbutl%lib{butl-pkg-config}
include ../bin/
intf_libs = ../bin/lib{build2-bin}
./: lib{build2-cc}: libul{build2-cc}: \
{hxx ixx txx cxx}{** -pkgconfig-lib* -**.test...} \
- h{msvc-setup} \
- $intf_libs $impl_libs
+ h{msvc-setup}
libul{build2-cc}: cxx{pkgconfig-libpkgconf}: include = $libpkgconf
libul{build2-cc}: cxx{pkgconfig-libpkg-config}: include = (!$libpkgconf)
+libul{build2-cc}: $intf_libs $impl_libs
+
+# libc++ std module interface translation units.
+#
+# Hopefully temporary, see llvm-project GH issues #73089.
+#
+# @@ TMP: make sure sync'ed with upstream before release (keep this note).
+#
+lib{build2-cc}: file{std.cppm std.compat.cppm}
+file{std.cppm}@./ file{std.compat.cppm}@./: install = data/libbuild2/cc/
+
# Unit tests.
#
exe{*.test}:
diff --git a/libbuild2/cc/common.cxx b/libbuild2/cc/common.cxx
index 2d344f1..9a4a07c 100644
--- a/libbuild2/cc/common.cxx
+++ b/libbuild2/cc/common.cxx
@@ -162,7 +162,12 @@ namespace build2
// Add the library to the chain.
//
if (self && proc_lib)
+ {
+ if (find (chain->begin (), chain->end (), &l) != chain->end ())
+ fail << "dependency cycle detected involving library " << l;
+
chain->push_back (&l);
+ }
// We only lookup public variables so go straight for the public
// variable pool.
@@ -382,9 +387,10 @@ namespace build2
for (const prerequisite_target& pt: l.prerequisite_targets[a])
{
// Note: adhoc prerequisites are not part of the library metadata
- // protocol (and we should check for adhoc first to avoid races).
+ // protocol (and we should check for adhoc first to avoid races
+ // during execute).
//
- if (pt == nullptr || pt.adhoc ())
+ if (pt.adhoc () || pt == nullptr)
continue;
if (marked (pt))
@@ -408,7 +414,7 @@ namespace build2
if (!li) find_linfo ();
process_libraries_impl (a, bs, *li, *sysd,
- g, *f, la, pt.data,
+ g, *f, la, pt.data /* lflags */,
proc_impl, proc_lib, proc_opt,
true /* self */, proc_opt_group,
cache, chain, nullptr);
@@ -642,18 +648,36 @@ namespace build2
<< " dependency " << *t << " is " << w <<
info << "mentioned in *.export." << (impl ? "impl_" : "")
<< "libs of target " << l <<
- info << "is it a prerequisite of " << l << "?";
+ info << "is it a prerequisite of " << l << "?" << endf;
}
// Process it recursively.
//
- // @@ Where can we get the link flags? Should we try to find
- // them in the library's prerequisites? What about
- // installed stuff?
+ bool u;
+ bool la ((u = t->is_a<libux> ()) || t->is_a<liba> ());
+ lflags lf (0);
+
+ // If this is a static library, see if we need to link it
+ // whole.
//
+ if (la && proc_lib)
+ {
+ // Note: go straight for the public variable pool.
+ //
+ const variable& var (t->ctx.var_pool["bin.whole"]);
+
+ // See the link rule for the lookup semantics.
+ //
+ lookup l (
+ t->lookup_original (var, true /* target_only */).first);
+
+ if (l ? cast<bool> (*l) : u)
+ lf |= lflag_whole;
+ }
+
process_libraries_impl (
a, bs, *li, *sysd,
- g, *t, t->is_a<liba> () || t->is_a<libux> (), 0,
+ g, *t, la, lf,
proc_impl, proc_lib, proc_opt,
true /* self */, proc_opt_group,
cache, chain, dedup);
@@ -804,6 +828,8 @@ namespace build2
// always a file. The second half of the returned pair is the group, if
// the member was picked.
//
+ // Note: paths in sysd/usrd are expected to be absolute and normalized.
+ //
// Note: may throw non_existent_library.
//
pair<const mtime_target&, const target*> common::
@@ -911,6 +937,8 @@ namespace build2
// Action should be absent if called during the load phase. Note that pk's
// scope should not be NULL (even if dir is absolute).
//
+ // Note: paths in sysd/usrd are expected to be absolute and normalized.
+ //
// Note: see similar logic in find_system_library().
//
target* common::
@@ -1039,6 +1067,21 @@ namespace build2
{
context& ctx (p.scope->ctx);
+ // Whether to look for a binless variant using the common .pc file
+ // (see below).
+ //
+ // Normally we look for a binless version if the binful one was not
+ // found. However, sometimes we may find what looks like a binful
+ // library but on a closer examination realize that there is something
+ // wrong with it (for example, it's not a Windows import library). In
+ // such cases we want to omit looking for a binless library using the
+ // common .pc file since it most likely corresponds to the binful
+ // library (and we may end up in a infinite loop trying to resolve
+ // itself).
+ //
+ bool ba (true);
+ bool bs (true);
+
timestamp mt;
// libs
@@ -1110,6 +1153,31 @@ namespace build2
s->path_mtime (move (f), mt);
}
}
+ else if (!ext && tsys == "darwin")
+ {
+ // Besides .dylib, Mac OS now also has "text-based stub libraries"
+ // that use the .tbd extension. They appear to be similar to
+ // Windows import libraries and contain information such as the
+ // location of the .dylib library, its symbols, etc. For example,
+ // there is /Library/.../MacOSX13.3.sdk/usr/lib/libsqlite3.tbd
+ // which points to /usr/lib/libsqlite3.dylib (but which itself is
+ // invisible/inaccessible, presumably for security).
+ //
+ // Note that for now we are treating the .tbd library as the
+ // shared library but could probably do the more elaborate dance
+ // with ad hoc members like on Windows if really necessary.
+ //
+ se = string ("tbd");
+ f = f.base (); // Remove .dylib.
+ f += ".tbd";
+ mt = mtime (f);
+
+ if (mt != timestamp_nonexistent)
+ {
+ insert_library (ctx, s, name, d, ld, se, exist, trace);
+ s->path_mtime (move (f), mt);
+ }
+ }
}
// liba
@@ -1139,10 +1207,24 @@ namespace build2
if (tsys == "win32-msvc")
{
if (s == nullptr && !sn.empty ())
- s = msvc_search_shared (ld, d, p, exist);
+ {
+ pair<libs*, bool> r (msvc_search_shared (ld, d, p, exist));
+
+ if (r.first != nullptr)
+ s = r.first;
+ else if (!r.second)
+ bs = false;
+ }
if (a == nullptr && !an.empty ())
- a = msvc_search_static (ld, d, p, exist);
+ {
+ pair<liba*, bool> r (msvc_search_static (ld, d, p, exist));
+
+ if (r.first != nullptr)
+ a = r.first;
+ else if (!r.second)
+ ba = false;
+ }
}
// Look for binary-less libraries via pkg-config .pc files. Note that
@@ -1159,7 +1241,10 @@ namespace build2
// is no binful variant.
//
pair<path, path> r (
- pkgconfig_search (d, p.proj, name, na && ns /* common */));
+ pkgconfig_search (d,
+ p.proj,
+ name,
+ na && ns && ba && bs /* common */));
if (na && !r.first.empty ())
{
@@ -1212,6 +1297,8 @@ namespace build2
// making it the only one to allow things to be overriden (e.g.,
// if build2 was moved or some such).
//
+ // Note: build_install_lib is already normalized.
+ //
usrd->insert (usrd->begin (), build_install_lib);
}
}
@@ -1269,7 +1356,7 @@ namespace build2
// idea is that in .pc files that we generate, we copy those macros (or
// custom ones) from *.export.poptions.
//
- // @@ Should we add .pc files as ad hoc members so pkconfig_save() can
+ // @@ Should we add .pc files as ad hoc members so pkgconfig_save() can
// use their names when deriving -l-names (this would be especially
// helpful for binless libraries to get hold of prefix/suffix, etc).
//
@@ -1390,7 +1477,7 @@ namespace build2
// @@ TODO: we currently always reload pkgconfig for lt (and below).
//
mark_cc (*lt);
- lt->mtime (mt);
+ lt->mtime (mt); // Note: problematic, see below for details.
// We can only load metadata from here since we can only do this
// during the load phase. But it's also possible that a racing match
@@ -1441,6 +1528,9 @@ namespace build2
return l;
};
+ target_lock al (lock (a));
+ target_lock sl (lock (s));
+
target_lock ll (lock (lt));
// Set lib{} group members to indicate what's available. Note that we
@@ -1468,9 +1558,6 @@ namespace build2
ll.unlock ();
}
- target_lock al (lock (a));
- target_lock sl (lock (s));
-
if (!al) a = nullptr;
if (!sl) s = nullptr;
@@ -1504,6 +1591,34 @@ namespace build2
if (s != nullptr) match_rule (sl, file_rule::rule_match);
if (ll)
{
+ // @@ Turns out this has a problem: file_rule won't match/execute
+ // group members. So what happens is that if we have two installed
+ // libraries, say lib{build2} that depends on lib{butl}, then
+ // lib{build2} will have lib{butl} as a prerequisite and file_rule
+ // that matches lib{build2} will update lib{butl} (also matched by
+ // file_rule), but not its members. Later, someone (for example,
+ // the newer() call in append_libraries()) will pick one of the
+ // members assuming it is executed and things will go sideways.
+ //
+ // For now we hacked around the issue but the long term solution is
+ // probably to add to the bin module a special rule that is
+ // registered on the global scope and matches the installed lib{}
+ // targets. This rule will have to both update prerequisites like
+ // the file_rule and group members like the lib_rule (or maybe it
+ // can skip prerequisites since one of the member will do that; in
+ // which case maybe we will be able to reuse lib_rule maybe with
+ // the "all members" flag or some such). A few additional
+ // notes/thoughts:
+ //
+ // - Will be able to stop inheriting lib{} from mtime_target.
+ //
+ // - Will need to register for perform_update/clean like in context
+ // as well as for configure as in the config module (feels like
+ // shouldn't need to register for dist).
+ //
+ // - Will need to test batches, immediate import thoroughly (this
+ // stuff is notoriously tricky to get right in all situations).
+ //
match_rule (ll, file_rule::rule_match);
// Also bless the library group with a "trust me it exists" timestamp.
@@ -1512,6 +1627,8 @@ namespace build2
// won't match.
//
lt->mtime (mt);
+
+ ll.unlock (); // Unlock group before members, for good measure.
}
return r;
@@ -1553,5 +1670,97 @@ namespace build2
return r;
}
+
+ void common::
+ append_diag_color_options (cstrings& args) const
+ {
+ switch (cclass)
+ {
+ case compiler_class::msvc:
+ {
+ // MSVC has the /diagnostics: option which has an undocumented value
+ // `color`. It's unclear from which version of MSVC this value is
+ // supported, but it works in 17.0, so let's start from there.
+ //
+ // Note that there is currently no way to disable color in the MSVC
+ // diagnostics specifically (the /diagnostics:* option values are
+ // cumulative and there doesn't seem to be a `color-` value). This
+ // is probably not a big deal since one can just disable the color
+ // globally (--no-diag-color).
+ //
+ // Note that clang-cl appears to use -fansi-escape-codes. See GH
+ // issue #312 for background.
+ //
+ // Note that MSVC ignores /diagnostics:color if diagnostics is
+ // written to a pipe. See GH issue #312 for details and a link to
+ // the MSVC bug report.
+ //
+ if (show_diag_color ())
+ {
+ if (cvariant.empty () &&
+ (cmaj > 19 || (cmaj == 19 && cmin >= 30)))
+ {
+ // Check for the prefix in case /diagnostics:color- gets added
+ // eventually.
+ //
+ if (!find_option_prefixes ({"/diagnostics:color",
+ "-diagnostics:color"}, args))
+ {
+ args.push_back ("/diagnostics:color");
+ }
+ }
+ }
+
+ break;
+ }
+ case compiler_class::gcc:
+ {
+ // Enable/disable diagnostics color unless a custom option is
+ // specified.
+ //
+ // Supported from GCC 4.9 (8.1 on Windows) and (at least) from Clang
+ // 3.5. Clang supports -f[no]color-diagnostics in addition to the
+ // GCC's spelling. Note that to enable color on Windows Clang also
+ // needs -fansi-escape-codes.
+ //
+ if (
+#ifndef _WIN32
+ ctype == compiler_type::gcc ? cmaj > 4 || (cmaj == 4 && cmin >= 9) :
+#else
+ ctype == compiler_type::gcc ? cmaj > 8 || (cmaj == 8 && cmin >= 1) :
+#endif
+ ctype == compiler_type::clang ? cmaj > 3 || (cmaj == 3 && cmin >= 5) :
+ false)
+ {
+ if (!(find_option_prefix ("-fdiagnostics-color", args) ||
+ find_option ("-fno-diagnostics-color", args) ||
+ find_option ("-fdiagnostics-plain-output", args) ||
+ (ctype == compiler_type::clang &&
+ (find_option ("-fcolor-diagnostics", args) ||
+ find_option ("-fno-color-diagnostics", args)))))
+ {
+ // Omit -fno-diagnostics-color if stderr is not a terminal (we
+ // know there will be no color in this case and the option will
+ // just add noise, for example, in build logs).
+ //
+ if (const char* o = (
+ show_diag_color () ? "-fdiagnostics-color" :
+ stderr_term ? "-fno-diagnostics-color" :
+ nullptr))
+ {
+ args.push_back (o);
+
+#ifdef _WIN32
+ if (ctype == compiler_type::clang && o[2] != 'n')
+ args.push_back ("-fansi-escape-codes");
+#endif
+ }
+ }
+ }
+
+ break;
+ }
+ }
+ }
}
}
diff --git a/libbuild2/cc/common.hxx b/libbuild2/cc/common.hxx
index 4ad0e22..cb85632 100644
--- a/libbuild2/cc/common.hxx
+++ b/libbuild2/cc/common.hxx
@@ -117,6 +117,7 @@ namespace build2
const variable& c_module_name; // cc.module_name
const variable& c_importable; // cc.importable
const variable& c_reprocess; // cc.reprocess
+ const variable& c_serialize; // cc.serialize
const variable& x_preprocessed; // x.preprocessed
const variable* x_symexport; // x.features.symexport
@@ -165,6 +166,7 @@ namespace build2
// Cached values for some commonly-used variables/values.
//
+ const compiler_id& cid; // x.id
compiler_type ctype; // x.id.type
const string& cvariant; // x.id.variant
compiler_class cclass; // x.class
@@ -198,26 +200,34 @@ namespace build2
build2::cc::importable_headers* importable_headers;
// The order of sys_*_dirs is the mode entries first, followed by the
- // compiler built-in entries, and finished off with any extra entries
- // (e.g., fallback directories such as /usr/local/*).
+ // extra entries (e.g., /usr/local/*), followed by the compiler built-in
+ // entries.
+ //
+ // Note that even if we wanted to, we wouldn't be able to support extra
+ // trailing (after built-in) directories since we would need a portable
+ // equivalent of -idirafter for both headers and libraries.
//
const dir_paths& sys_lib_dirs; // x.sys_lib_dirs
const dir_paths& sys_hdr_dirs; // x.sys_hdr_dirs
const dir_paths* sys_mod_dirs; // compiler_info::sys_mod_dirs
- size_t sys_lib_dirs_mode; // Number of leading mode entries (0 if none).
+ size_t sys_lib_dirs_mode; // Number of mode entries (0 if none).
size_t sys_hdr_dirs_mode;
size_t sys_mod_dirs_mode;
- size_t sys_lib_dirs_extra; // First trailing extra entry (size if none).
+ size_t sys_lib_dirs_extra; // Number of extra entries (0 if none).
size_t sys_hdr_dirs_extra;
// Note that x_obj is patched in by the x.objx module. So it stays NULL
- // if Objective-X compilation is not enabled.
+ // if Objective-X compilation is not enabled. Similarly for x_asp except
+ // here we don't have duality and it's purely to signal (by the c.as-cpp
+ // module) that it's enabled.
//
const target_type& x_src; // Source target type (c{}, cxx{}).
const target_type* x_mod; // Module target type (mxx{}), if any.
+ const target_type& x_inc; // Includable base target type (e.g., c_inc{}).
const target_type* x_obj; // Objective-X target type (m{}, mm{}).
+ const target_type* x_asp; // Assembler with CPP target type (S{}).
// Check if an object (target, prerequisite, etc) is an Objective-X
// source.
@@ -229,11 +239,21 @@ namespace build2
return x_obj != nullptr && t.is_a (*x_obj);
}
+ // Check if an object (target, prerequisite, etc) is an Assembler with
+ // C preprocessor source.
+ //
+ template <typename T>
+ bool
+ x_assembler_cpp (const T& t) const
+ {
+ return x_asp != nullptr && t.is_a (*x_asp);
+ }
+
// Array of target types that are considered the X-language headers
// (excluding h{} except for C). Keep them in the most likely to appear
// order with the "real header" first and terminated with NULL.
//
- const target_type* const* x_hdr;
+ const target_type* const* x_hdrs;
// Check if an object (target, prerequisite, etc) is a header.
//
@@ -241,7 +261,7 @@ namespace build2
bool
x_header (const T& t, bool c_hdr = true) const
{
- for (const target_type* const* ht (x_hdr); *ht != nullptr; ++ht)
+ for (const target_type* const* ht (x_hdrs); *ht != nullptr; ++ht)
if (t.is_a (**ht))
return true;
@@ -252,7 +272,7 @@ namespace build2
// extensions to target types. Keep them in the most likely to appear
// order and terminate with NULL.
//
- const target_type* const* x_inc;
+ const target_type* const* x_incs;
// Aggregate-like constructor with from-base support.
//
@@ -260,8 +280,7 @@ namespace build2
const char* compile,
const char* link,
const char* install,
- compiler_type ct,
- const string& cv,
+ const compiler_id& ci,
compiler_class cl,
uint64_t mj, uint64_t mi,
uint64_t vmj, uint64_t vmi,
@@ -280,13 +299,14 @@ namespace build2
size_t sle, size_t she,
const target_type& src,
const target_type* mod,
- const target_type* const* hdr,
- const target_type* const* inc)
+ const target_type& inc,
+ const target_type* const* hdrs,
+ const target_type* const* incs)
: config_data (cd),
x_compile (compile),
x_link (link),
x_install (install),
- ctype (ct), cvariant (cv), cclass (cl),
+ cid (ci), ctype (ci.type), cvariant (ci.variant), cclass (cl),
cmaj (mj), cmin (mi),
cvmaj (vmj), cvmin (vmi),
cpath (path), cmode (mode),
@@ -301,8 +321,9 @@ namespace build2
sys_lib_dirs_mode (slm), sys_hdr_dirs_mode (shm),
sys_mod_dirs_mode (smm),
sys_lib_dirs_extra (sle), sys_hdr_dirs_extra (she),
- x_src (src), x_mod (mod), x_obj (nullptr),
- x_hdr (hdr), x_inc (inc) {}
+ x_src (src), x_mod (mod), x_inc (inc),
+ x_obj (nullptr), x_asp (nullptr),
+ x_hdrs (hdrs), x_incs (incs) {}
};
class LIBBUILD2_CC_SYMEXPORT common: public data
@@ -440,13 +461,16 @@ namespace build2
// Alternative search logic for VC (msvc.cxx).
//
- bin::liba*
+ // The second half is false if we should poison the binless search via
+ // the common .pc file.
+ //
+ pair<bin::liba*, bool>
msvc_search_static (const process_path&,
const dir_path&,
const prerequisite_key&,
bool existing) const;
- bin::libs*
+ pair<bin::libs*, bool>
msvc_search_shared (const process_path&,
const dir_path&,
const prerequisite_key&,
@@ -483,6 +507,11 @@ namespace build2
const dir_paths&,
const dir_paths&,
pair<bool, bool>) const;
+
+ // Append compiler-specific diagnostics color options as necessary.
+ //
+ void
+ append_diag_color_options (cstrings&) const;
};
}
}
diff --git a/libbuild2/cc/common.txx b/libbuild2/cc/common.txx
index f55072c..8c80686 100644
--- a/libbuild2/cc/common.txx
+++ b/libbuild2/cc/common.txx
@@ -19,13 +19,14 @@ namespace build2
bool exist,
tracer& trace)
{
- auto p (ctx.targets.insert_locked (T::static_type,
- move (dir),
- path_cast<dir_path> (out.effect),
- name,
- move (ext),
- target_decl::implied,
- trace));
+ auto p (ctx.targets.insert_locked (
+ T::static_type,
+ move (dir),
+ dir_path (out.effect_string ()).normalize (),
+ name,
+ move (ext),
+ target_decl::implied,
+ trace));
if (exist && p.second)
throw non_existent_library {p.first.template as<mtime_target> ()};
diff --git a/libbuild2/cc/compile-rule.cxx b/libbuild2/cc/compile-rule.cxx
index 51d9b4d..7629ed5 100644
--- a/libbuild2/cc/compile-rule.cxx
+++ b/libbuild2/cc/compile-rule.cxx
@@ -295,24 +295,25 @@ namespace build2
void compile_rule::
append_sys_hdr_options (T& args) const
{
- assert (sys_hdr_dirs_extra <= sys_hdr_dirs.size ());
+ assert (sys_hdr_dirs_mode + sys_hdr_dirs_extra <= sys_hdr_dirs.size ());
// Note that the mode options are added as part of cmode.
//
auto b (sys_hdr_dirs.begin () + sys_hdr_dirs_mode);
- auto m (sys_hdr_dirs.begin () + sys_hdr_dirs_extra);
- auto e (sys_hdr_dirs.end ());
+ auto x (b + sys_hdr_dirs_extra);
+ // Add extras.
+ //
// Note: starting from 16.10, MSVC gained /external:I option though it
// doesn't seem to affect the order, only "system-ness".
//
append_option_values (
args,
- cclass == compiler_class::gcc ? "-idirafter" :
+ cclass == compiler_class::gcc ? "-isystem" :
cclass == compiler_class::msvc ? (isystem (*this)
? "/external:I"
: "/I") : "-I",
- m, e,
+ b, x,
[] (const dir_path& d) {return d.string ().c_str ();});
// For MSVC if we have no INCLUDE environment variable set, then we
@@ -328,7 +329,7 @@ namespace build2
{
append_option_values (
args, "/I",
- b, m,
+ x, sys_hdr_dirs.end (),
[] (const dir_path& d) {return d.string ().c_str ();});
}
}
@@ -353,6 +354,35 @@ namespace build2
case lang::c: o1 = "/TC"; break;
case lang::cxx: o1 = "/TP"; break;
}
+
+ // Note: /interface and /internalPartition are in addition to /TP.
+ //
+ switch (md.type)
+ {
+ case unit_type::non_modular:
+ case unit_type::module_impl:
+ {
+ break;
+ }
+ case unit_type::module_intf:
+ case unit_type::module_intf_part:
+ {
+ o2 = "/interface";
+ break;
+ }
+ case unit_type::module_impl_part:
+ {
+ o2 = "/internalPartition";
+ break;
+ }
+ case unit_type::module_header:
+ {
+ //@@ MODHDR TODO: /exportHeader
+ assert (false);
+ break;
+ }
+ }
+
break;
}
case compiler_class::gcc:
@@ -370,14 +400,21 @@ namespace build2
case unit_type::non_modular:
case unit_type::module_impl:
{
- bool obj (x_objective (md.src));
-
o1 = "-x";
- switch (x_lang)
+
+ if (x_assembler_cpp (md.src))
+ o2 = "assembler-with-cpp";
+ else
{
- case lang::c: o2 = obj ? "objective-c" : "c"; break;
- case lang::cxx: o2 = obj ? "objective-c++" : "c++"; break;
+ bool obj (x_objective (md.src));
+
+ switch (x_lang)
+ {
+ case lang::c: o2 = obj ? "objective-c" : "c"; break;
+ case lang::cxx: o2 = obj ? "objective-c++" : "c++"; break;
+ }
}
+
break;
}
case unit_type::module_intf:
@@ -417,9 +454,11 @@ namespace build2
default:
assert (false);
}
+
break;
}
}
+
break;
}
}
@@ -476,9 +515,11 @@ namespace build2
// For a header unit we check the "real header" plus the C header.
//
- if (ut == unit_type::module_header ? p.is_a (**x_hdr) || p.is_a<h> () :
- ut == unit_type::module_intf ? p.is_a (*x_mod) :
- p.is_a (x_src) || (x_obj != nullptr && p.is_a (*x_obj)))
+ if (ut == unit_type::module_header ? p.is_a (**x_hdrs) || p.is_a<h> () :
+ ut == unit_type::module_intf ? p.is_a (*x_mod) :
+ p.is_a (x_src) ||
+ (x_asp != nullptr && p.is_a (*x_asp)) ||
+ (x_obj != nullptr && p.is_a (*x_obj)))
{
// Save in the target's auxiliary storage.
//
@@ -937,7 +978,9 @@ namespace build2
//
// Note: ut is still unrefined.
//
- if (ut == unit_type::module_intf && cast_true<bool> (t[b_binless]))
+ if ((ut == unit_type::module_intf ||
+ ut == unit_type::module_intf_part ||
+ ut == unit_type::module_impl_part) && cast_true<bool> (t[b_binless]))
{
// The module interface unit can be the same as an implementation
// (e.g., foo.mxx and foo.cxx) which means obj*{} targets could
@@ -998,6 +1041,12 @@ namespace build2
// to match it if we may need its modules or importable headers
// (see search_modules(), make_header_sidebuild() for details).
//
+ // Well, that was the case until we've added support for immediate
+ // importation of libraries, which happens during the load phase
+ // and natually leaves the library unmatched. While we could have
+ // returned from search_library() an indication of whether the
+ // library has been matched, this doesn't seem worth the trouble.
+ //
if (p.proj ())
{
pt = search_library (a,
@@ -1005,8 +1054,10 @@ namespace build2
usr_lib_dirs,
p.prerequisite);
+#if 0
if (pt != nullptr && !modules)
continue;
+#endif
}
if (pt == nullptr)
@@ -1034,7 +1085,8 @@ namespace build2
{
pt = &p.search (t);
- if (a.operation () == clean_id && !pt->dir.sub (rs.out_path ()))
+ if (pt == dir ||
+ (a.operation () == clean_id && !pt->dir.sub (rs.out_path ())))
continue;
}
@@ -1126,12 +1178,14 @@ namespace build2
// this can very well be happening in parallel. But that's not a
// problem since fsdir{}'s update is idempotent.
//
- fsdir_rule::perform_update_direct (a, t);
+ fsdir_rule::perform_update_direct (a, *dir);
}
// Note: the leading '@' is reserved for the module map prefix (see
// extract_modules()) and no other line must start with it.
//
+ // NOTE: see also the predefs rule if changing anything here.
+ //
depdb dd (tp + ".d");
// First should come the rule name/version.
@@ -1351,6 +1405,10 @@ namespace build2
//
if (mt != timestamp_nonexistent)
{
+ // Appended to by to_module_info() below.
+ //
+ tu.module_info.imports.clear ();
+
u = false;
md.touch = true;
}
@@ -1435,24 +1493,6 @@ namespace build2
extract_modules (a, bs, t, li,
tts, src,
md, move (tu.module_info), dd, u);
-
- // Currently in VC module interface units must be compiled from
- // the original source (something to do with having to detect and
- // store header boundaries in the .ifc files).
- //
- // @@ MODHDR MSVC: should we do the same for header units? I guess
- // we will figure it out when MSVC supports header units.
- //
- // @@ TMP: probably outdated. Probably the same for partitions.
- //
- // @@ See also similar check in extract_headers(), existing entry
- // case.
- //
- if (ctype == compiler_type::msvc)
- {
- if (ut == unit_type::module_intf)
- psrc.second = false;
- }
}
}
@@ -1471,7 +1511,7 @@ namespace build2
// to keep re-validating the file on every subsequent dry-run as well
// on the real run).
//
- if (u && dd.reading () && !ctx.dry_run)
+ if (u && dd.reading () && !ctx.dry_run_option)
dd.touch = timestamp_unknown;
dd.close (false /* mtime_check */);
@@ -1926,23 +1966,211 @@ namespace build2
for (size_t i (0); i != batch_n; ++i)
{
string& r (batch[i]);
+ size_t rn (r.size ());
+
+ // The protocol uses a peculiar quoting/escaping scheme that can be
+ // summarized as follows (see the libcody documentation for details):
+ //
+ // - Words are seperated with spaces and/or tabs.
+ //
+ // - Words need not be quoted if they only containing characters from
+ // the [-+_/%.A-Za-z0-9] set.
+ //
+ // - Otherwise words need to be single-quoted.
+ //
+ // - Inside single-quoted words, the \n \t \' and \\ escape sequences
+ // are recognized.
+ //
+ // Note that we currently don't treat abutted quotes (as in a' 'b) as
+ // a single word (it doesn't seem plausible that we will ever receive
+ // something like this).
+ //
+ size_t b (0), e (0), n; bool q; // Next word.
+
+ auto next = [&r, rn, &b, &e, &n, &q] () -> size_t
+ {
+ if (b != e)
+ b = e;
+
+ // Skip leading whitespaces.
+ //
+ for (; b != rn && (r[b] == ' ' || r[b] == '\t'); ++b) ;
+
+ if (b != rn)
+ {
+ q = (r[b] == '\'');
+
+ // Find first trailing whitespace or closing quote.
+ //
+ for (e = b + 1; e != rn; ++e)
+ {
+ // Note that we deal with invalid quoting/escaping in unquote().
+ //
+ switch (r[e])
+ {
+ case ' ':
+ case '\t':
+ if (q)
+ continue;
+ else
+ break;
+ case '\'':
+ if (q)
+ {
+ ++e; // Include closing quote (hopefully).
+ break;
+ }
+ else
+ {
+ assert (false); // Abutted quote.
+ break;
+ }
+ case '\\':
+ if (++e != rn) // Skip next character (hopefully).
+ continue;
+ else
+ break;
+ default:
+ continue;
+ }
+
+ break;
+ }
+
+ n = e - b;
+ }
+ else
+ {
+ q = false;
+ e = rn;
+ n = 0;
+ }
+
+ return n;
+ };
+
+ // Unquote into tmp the current word returning false if malformed.
+ //
+ auto unquote = [&r, &b, &n, &q, &tmp] (bool clear = true) -> bool
+ {
+ if (q && n > 1)
+ {
+ size_t e (b + n - 1);
- // @@ TODO: quoting and escaping.
+ if (r[b] == '\'' && r[e] == '\'')
+ {
+ if (clear)
+ tmp.clear ();
+
+ size_t i (b + 1);
+ for (; i != e; ++i)
+ {
+ char c (r[i]);
+ if (c == '\\')
+ {
+ if (++i == e)
+ {
+ i = 0;
+ break;
+ }
+
+ c = r[i];
+ if (c == 'n') c = '\n';
+ else if (c == 't') c = '\t';
+ }
+ tmp += c;
+ }
+
+ if (i == e)
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+#if 0
+#define UNQUOTE(x, y) \
+ r = x; rn = r.size (); b = e = 0; \
+ assert (next () && unquote () && tmp == y)
+
+ UNQUOTE ("'foo bar'", "foo bar");
+ UNQUOTE (" 'foo bar' ", "foo bar");
+ UNQUOTE ("'foo\\\\bar'", "foo\\bar");
+ UNQUOTE ("'\\'foo bar'", "'foo bar");
+ UNQUOTE ("'foo bar\\''", "foo bar'");
+ UNQUOTE ("'\\'foo\\\\bar\\''", "'foo\\bar'");
+
+ fail << "all good";
+#endif
+
+ // Escape if necessary the specified string and append to r.
//
- size_t b (0), e (0), n; // Next word.
+ auto escape = [&r] (const string& s)
+ {
+ size_t b (0), e, n (s.size ());
+ while (b != n && (e = s.find_first_of ("\\'\n\t", b)) != string::npos)
+ {
+ r.append (s, b, e - b); // Preceding chunk.
+
+ char c (s[e]);
+ r += '\\';
+ r += (c == '\n' ? 'n' : c == '\t' ? 't' : c);
+ b = e + 1;
+ }
+
+ if (b != n)
+ r.append (s, b, e); // Final chunk.
+ };
- auto next = [&r, &b, &e, &n] () -> size_t
+ // Quote and escape if necessary the specified string and append to r.
+ //
+ auto quote = [&r, &escape] (const string& s)
{
- return (n = next_word (r, b, e, ' ', '\t'));
+ if (find_if (s.begin (), s.end (),
+ [] (char c)
+ {
+ return !((c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') ||
+ (c >= 'A' && c <= 'Z') ||
+ c == '-' || c == '_' || c == '/' ||
+ c == '.' || c == '+' || c == '%');
+ }) == s.end ())
+ {
+ r += s;
+ }
+ else
+ {
+ r += '\'';
+ escape (s);
+ r += '\'';
+ }
};
+#if 0
+#define QUOTE(x, y) \
+ r.clear (); quote (x); \
+ assert (r == y)
+
+ QUOTE ("foo/Bar-7.h", "foo/Bar-7.h");
+
+ QUOTE ("foo bar", "'foo bar'");
+ QUOTE ("foo\\bar", "'foo\\\\bar'");
+ QUOTE ("'foo bar", "'\\'foo bar'");
+ QUOTE ("foo bar'", "'foo bar\\''");
+ QUOTE ("'foo\\bar'", "'\\'foo\\\\bar\\''");
+
+ fail << "all good";
+#endif
+
next (); // Request name.
- auto name = [&r, b, n] (const char* c) -> bool
+ auto name = [&r, b, n, q] (const char* c) -> bool
{
// We can reasonably assume a command will never be quoted.
//
- return (r.compare (b, n, c) == 0 &&
+ return (!q &&
+ r.compare (b, n, c) == 0 &&
(r[n] == ' ' || r[n] == '\t' || r[n] == '\0'));
};
@@ -1991,7 +2219,17 @@ namespace build2
if (next ())
{
- path f (r, b, n);
+ path f;
+ if (!q)
+ f = path (r, b, n);
+ else if (unquote ())
+ f = path (tmp);
+ else
+ {
+ r = "ERROR 'malformed quoting/escaping in request'";
+ continue;
+ }
+
bool exists (true);
// The TU path we pass to the compiler is always absolute so any
@@ -2002,8 +2240,9 @@ namespace build2
//
if (exists && f.relative ())
{
- tmp.assign (r, b, n);
- r = "ERROR 'relative header path "; r += tmp; r += '\'';
+ r = "ERROR 'relative header path ";
+ escape (f.string ());
+ r += '\'';
continue;
}
@@ -2111,7 +2350,7 @@ namespace build2
// Note: if ht is NULL, f is still valid.
//
r = "ERROR 'unable to update header ";
- r += (ht != nullptr ? ht->path () : f).string ();
+ escape ((ht != nullptr ? ht->path () : f).string ());
r += '\'';
continue;
}
@@ -2246,17 +2485,27 @@ namespace build2
// original (which we may need to normalize when we read
// this mapping in extract_headers()).
//
- tmp = "@ "; tmp.append (r, b, n); tmp += ' '; tmp += bp;
+ // @@ This still breaks if the header path contains spaces.
+ // GCC bug 110153.
+ //
+ tmp = "@ ";
+ if (!q) tmp.append (r, b, n);
+ else unquote (false /* clear */); // Can't fail.
+ tmp += ' ';
+ tmp += bp;
+
dd.expect (tmp);
st.header_units++;
}
- r = "PATHNAME "; r += bp;
+ r = "PATHNAME ";
+ quote (bp);
}
catch (const failed&)
{
r = "ERROR 'unable to update header unit for ";
- r += hs; r += '\'';
+ escape (hs);
+ r += '\'';
continue;
}
}
@@ -2282,7 +2531,7 @@ namespace build2
// Truncate the response batch and terminate the communication (see
// also libcody issue #22).
//
- tmp.assign (r, b, n);
+ tmp.assign (r, b, n); // Request name (unquoted).
r = "ERROR '"; r += w; r += ' '; r += tmp; r += '\'';
batch_n = i + 1;
term = true;
@@ -2865,7 +3114,7 @@ namespace build2
// single "version" of a header. Seems reasonable.
//
// Note also that while it would have been nice to have a unified cc
- // cache, the map_extension() call is passed x_inc which is module-
+ // cache, the map_extension() call is passed x_incs which is module-
// specific. In other words, we may end up mapping the same header to
// two different targets depending on whether it is included from, say,
// C or C++ translation unit. We could have used a unified cache for
@@ -2929,7 +3178,7 @@ namespace build2
fp, cache, norm,
[this] (const scope& bs, const string& n, const string& e)
{
- return map_extension (bs, n, e, x_inc);
+ return map_extension (bs, n, e, x_incs);
},
h::static_type,
[this, &d] (action a, const scope& bs, const target& t)
@@ -3020,11 +3269,14 @@ namespace build2
// Preprocessed file extension.
//
- const char* pext (x_objective (src) ? x_obj_pext : x_pext);
+ const char* pext (x_assembler_cpp (src) ? ".Si" :
+ x_objective (src) ? x_obj_pext :
+ x_pext);
// Preprocesor mode that preserves as much information as possible while
// still performing inclusions. Also serves as a flag indicating whether
- // this compiler uses the separate preprocess and compile setup.
+ // this (non-MSVC) compiler uses the separate preprocess and compile
+ // setup.
//
const char* pp (nullptr);
@@ -3035,7 +3287,16 @@ namespace build2
// -fdirectives-only is available since GCC 4.3.0.
//
if (cmaj > 4 || (cmaj == 4 && cmin >= 3))
- pp = "-fdirectives-only";
+ {
+ // Note that for assembler-with-cpp GCC currently forces full
+ // preprocessing in (what appears to be) an attempt to paper over
+ // a deeper issue (see GCC bug 109534). If/when that bug gets
+ // fixed, we can enable this on our side. Note that Clang's
+ // -frewrite-includes also has issues (see below).
+ //
+ if (!x_assembler_cpp (src))
+ pp = "-fdirectives-only";
+ }
break;
}
@@ -3044,7 +3305,16 @@ namespace build2
// -frewrite-includes is available since Clang 3.2.0.
//
if (cmaj > 3 || (cmaj == 3 && cmin >= 2))
- pp = "-frewrite-includes";
+ {
+ // While Clang's -frewrite-includes appears to work, there are
+ // some issues with correctly tracking location information
+ // (manifests itself as wrong line numbers in debug info, for
+ // example). The result also appears to reference the .Si file
+ // instead of the original source file for some reason.
+ //
+ if (!x_assembler_cpp (src))
+ pp = "-frewrite-includes";
+ }
break;
}
@@ -3214,8 +3484,8 @@ namespace build2
// The gen argument to init_args() is in/out. The caller signals whether
// to force the generated header support and on return it signals
- // whether this support is enabled. The first call to init_args is
- // expected to have gen false.
+ // whether this support is enabled. If gen is false, then stderr is
+ // expected to be either discarded or merged with sdtout.
//
// Return NULL if the dependency information goes to stdout and a
// pointer to the temporary file path otherwise.
@@ -3366,16 +3636,6 @@ namespace build2
// Some compile options (e.g., -std, -m) affect the preprocessor.
//
- // Currently Clang supports importing "header modules" even when in
- // the TS mode. And "header modules" support macros which means
- // imports have to be resolved during preprocessing. Which poses a
- // bit of a chicken and egg problem for us. For now, the workaround
- // is to remove the -fmodules-ts option when preprocessing. Hopefully
- // there will be a "pure modules" mode at some point.
- //
- // @@ MODHDR Clang: should be solved with the dynamic module mapper
- // if/when Clang supports it?
- //
// Don't treat warnings as errors.
//
@@ -3404,8 +3664,13 @@ namespace build2
append_options (args, cmode);
append_sys_hdr_options (args); // Extra system header dirs (last).
+ // Note that for MSVC stderr is merged with stdout and is then
+ // parsed, so no append_diag_color_options() call.
+
// See perform_update() for details on the choice of options.
//
+ // NOTE: see also the predefs rule if adding anything here.
+ //
{
bool sc (find_option_prefixes (
{"/source-charset:", "-source-charset:"}, args));
@@ -3435,6 +3700,8 @@ namespace build2
!find_option_prefixes ({"/EH", "-EH"}, args))
args.push_back ("/EHsc");
+ // NOTE: see similar code in search_modules().
+ //
if (!find_option_prefixes ({"/MD", "/MT", "-MD", "-MT"}, args))
args.push_back ("/MD");
@@ -3446,7 +3713,7 @@ namespace build2
msvc_sanitize_cl (args);
- psrc = ctx.fcache.create (t.path () + pext, !modules);
+ psrc = ctx.fcache->create (t.path () + pext, !modules);
if (fc)
{
@@ -3465,12 +3732,18 @@ namespace build2
}
case compiler_class::gcc:
{
- append_options (args, cmode,
- cmode.size () - (modules && clang ? 1 : 0));
+ append_options (args, cmode);
append_sys_hdr_options (args); // Extra system header dirs (last).
+ // If not gen, then stderr is discarded.
+ //
+ if (gen)
+ append_diag_color_options (args);
+
// See perform_update() for details on the choice of options.
//
+ // NOTE: see also the predefs rule if adding anything here.
+ //
if (!find_option_prefix ("-finput-charset=", args))
args.push_back ("-finput-charset=UTF-8");
@@ -3482,8 +3755,7 @@ namespace build2
if (ctype == compiler_type::clang && tsys == "win32-msvc")
{
- initializer_list<const char*> os {"-nostdlib", "-nostartfiles"};
- if (!find_options (os, cmode) && !find_options (os, args))
+ if (!find_options ({"-nostdlib", "-nostartfiles"}, args))
{
args.push_back ("-D_MT");
args.push_back ("-D_DLL");
@@ -3593,7 +3865,7 @@ namespace build2
// Preprocessor output.
//
- psrc = ctx.fcache.create (t.path () + pext, !modules);
+ psrc = ctx.fcache->create (t.path () + pext, !modules);
args.push_back ("-o");
args.push_back (psrc.path ().string ().c_str ());
}
@@ -3883,12 +4155,9 @@ namespace build2
// If modules are enabled, then we keep the preprocessed output
// around (see apply() for details).
//
- // See apply() for details on the extra MSVC check.
- //
- if (modules && (ctype != compiler_type::msvc ||
- md.type != unit_type::module_intf))
+ if (modules)
{
- result.first = ctx.fcache.create_existing (t.path () + pext);
+ result.first = ctx.fcache->create_existing (t.path () + pext);
result.second = true;
}
@@ -4835,6 +5104,18 @@ namespace build2
{
tracer trace (x, "compile_rule::parse_unit");
+ // Scanning .S files with our parser is hazardous since such files
+ // sometimes use `#`-style comments. Presumably real compilers just
+ // ignore them in some way, but it doesn't seem worth it to bother in
+ // our case. Also, the checksum calculation over assembler tokens feels
+ // iffy.
+ //
+ if (x_assembler_cpp (src))
+ {
+ tu.type = unit_type::non_modular;
+ return "";
+ }
+
otype ot (li.type);
// If things go wrong give the user a bit extra context. Let's call it
@@ -4913,8 +5194,6 @@ namespace build2
case compiler_class::msvc: werror = "/WX"; break;
}
- bool clang (ctype == compiler_type::clang);
-
append_options (args, t, c_coptions, werror);
append_options (args, t, x_coptions, werror);
@@ -4929,6 +5208,9 @@ namespace build2
append_options (args, cmode);
append_sys_hdr_options (args);
+ // Note: no append_diag_color_options() call since the
+ // diagnostics is discarded.
+
// See perform_update() for details on the choice of options.
//
{
@@ -4974,10 +5256,12 @@ namespace build2
}
case compiler_class::gcc:
{
- append_options (args, cmode,
- cmode.size () - (modules && clang ? 1 : 0));
+ append_options (args, cmode);
append_sys_hdr_options (args);
+ // Note: no append_diag_color_options() call since the
+ // diagnostics is discarded.
+
// See perform_update() for details on the choice of options.
//
if (!find_option_prefix ("-finput-charset=", args))
@@ -4991,8 +5275,7 @@ namespace build2
if (ctype == compiler_type::clang && tsys == "win32-msvc")
{
- initializer_list<const char*> os {"-nostdlib", "-nostartfiles"};
- if (!find_options (os, cmode) && !find_options (os, args))
+ if (!find_options ({"-nostdlib", "-nostartfiles"}, args))
{
args.push_back ("-D_MT");
args.push_back ("-D_DLL");
@@ -5019,12 +5302,36 @@ namespace build2
//
if (ps)
{
- if (ctype == compiler_type::gcc)
+ switch (ctype)
{
- // Note that only these two *plus* -x do the trick.
- //
- args.push_back ("-fpreprocessed");
- args.push_back ("-fdirectives-only");
+ case compiler_type::gcc:
+ {
+ // Note that only these two *plus* -x do the trick.
+ //
+ args.push_back ("-fpreprocessed");
+ args.push_back ("-fdirectives-only");
+ break;
+ }
+ case compiler_type::clang:
+ {
+ // See below for details.
+ //
+ if (ctype == compiler_type::clang &&
+ cmaj >= (cvariant != "apple" ? 15 : 16))
+ {
+ if (find_options ({"-pedantic", "-pedantic-errors",
+ "-Wpedantic", "-Werror=pedantic"},
+ args))
+ {
+ args.push_back ("-Wno-gnu-line-marker");
+ }
+ }
+
+ break;
+ }
+ case compiler_type::msvc:
+ case compiler_type::icc:
+ assert (false);
}
}
@@ -5093,7 +5400,7 @@ namespace build2
fdstream_mode::binary | fdstream_mode::skip);
parser p;
- p.parse (is, path_name (*sp), tu);
+ p.parse (is, path_name (*sp), tu, cid);
is.close ();
@@ -5108,7 +5415,9 @@ namespace build2
if (!modules)
{
if (ut != unit_type::non_modular || !mi.imports.empty ())
- fail << "modules support required by " << src;
+ fail << "modules support required by " << src <<
+ info << "consider enabling modules with "
+ << x << ".features.modules=true in root.build";
}
else
{
@@ -5133,18 +5442,6 @@ namespace build2
ut = md.type;
mi.name = src.path ().string ();
}
-
- // Prior to 15.5 (19.12) VC was not using the 'export module M;'
- // syntax so we use the preprequisite type to distinguish
- // between interface and implementation units.
- //
- // @@ TMP: probably outdated.
- //
- if (ctype == compiler_type::msvc && cmaj == 19 && cmin <= 11)
- {
- if (ut == unit_type::module_impl && src.is_a (*x_mod))
- ut = unit_type::module_intf;
- }
}
// If we were forced to reprocess, assume the checksum is not
@@ -5359,6 +5656,9 @@ namespace build2
{
tracer trace (x, "compile_rule::search_modules");
+ context& ctx (bs.ctx);
+ const scope& rs (*bs.root_scope ());
+
// NOTE: currently we don't see header unit imports (they are handled by
// extract_headers() and are not in imports).
@@ -5394,7 +5694,7 @@ namespace build2
// So, the fuzzy match: the idea is that each match gets a score, the
// number of characters in the module name that got matched. A match
// with the highest score is used. And we use the (length + 1) for a
- // match against an actual module name.
+ // match against an actual (extracted) module name.
//
// Actually, the scoring system is a bit more elaborate than that.
// Consider module name core.window and two files, window.mxx and
@@ -5422,10 +5722,10 @@ namespace build2
// module (or partition) component. Failed that, we will match `format`
// to `print` because the last character (`t`) is the same.
//
- // For std.* modules we only accept non-fuzzy matches (think std.core vs
- // some core.mxx). And if such a module is unresolved, then we assume it
- // is pre-built and will be found by some other means (e.g., VC's
- // IFCPATH).
+ // For std.* modules we only accept non-fuzzy matches (think std.compat
+ // vs some compat.mxx). And if such a module is unresolved, then we
+ // assume it is pre-built and will be found by some other means (e.g.,
+ // VC's IFCPATH).
//
// Note also that we handle module partitions the same as submodules. In
// other words, for matching, `.` and `:` are treated the same.
@@ -5438,7 +5738,7 @@ namespace build2
// PPPPABBBB
//
// Where PPPP is the primary score, A is the A) score, and BBBB is
- // the B) scope described above. Zero signifies no match.
+ // the B) score described above. Zero signifies no match.
//
// We use decimal instead of binary packing to make it easier for the
// human to separate fields in the trace messages, during debugging,
@@ -5544,6 +5844,31 @@ namespace build2
if (!match)
return 0;
+ // Here is another corner case, the module is async_simple:IOExecutor
+ // and the file names are:
+ //
+ // IOExecutor.mxx
+ // SimpleIOExecutor.mxx
+ //
+ // The above implementation treats the latter as better because
+ // `Simple` in SimpleIOExecutor matches `simple` in async_simple. It's
+ // unclear what we can do about it without potentially breaking other
+ // legitimate cases (think Boost_Simple:IOExecutor). Maybe we could
+ // boost the exact partition name match score, similar to the exact
+ // module match, as some sort of a heuristics? Let's try.
+ //
+ if (fi == 0 && mi != 0 && m[mi - 1] == ':')
+ {
+ // Pretend we matched one short of the next module component. This
+ // way AsyncSimpleIOExecutor.mxx would still be a better match.
+ //
+ while (--mi != 0 && m[mi - 1] != '.')
+ ;
+
+ msep = (mi != 0); // For uncount logic below.
+ mi++; // One short.
+ }
+
// "Uncount" real separators.
//
if (fsep) fi++;
@@ -5572,6 +5897,20 @@ namespace build2
return ps * 100000 + as * 10000 + bs;
};
+#if 0
+ assert (match ("IOExecutor", "async_simple:IOExecutor") >
+ match ("SimpleIOExecutor", "async_simple:IOExecutor"));
+
+ assert (match ("IOExecutor", "async_simple:IOExecutor") <
+ match ("AsyncSimpleIOExecutor", "async_simple:IOExecutor"));
+
+ assert (match ("IOExecutor", "x.async_simple:IOExecutor") >
+ match ("SimpleIOExecutor", "x.async_simple:IOExecutor"));
+
+ assert (match ("IOExecutor", "x.async_simple:IOExecutor") <
+ match ("AsyncSimpleIOExecutor", "x.async_simple:IOExecutor"));
+#endif
+
auto& pts (t.prerequisite_targets[a]);
size_t start (pts.size ()); // Index of the first to be added.
@@ -5586,7 +5925,7 @@ namespace build2
// promise. It has to do with module re-exporting (export import M;).
// In this case (currently) all implementations simply treat it as a
// shallow (from the BMI's point of view) reference to the module (or an
- // implicit import, if you will). Do you see where it's going? Nowever
+ // implicit import, if you will). Do you see where it's going? Nowhere
// good, that's right. This shallow reference means that the compiler
// should be able to find BMIs for all the re-exported modules,
// recursively. The good news is we are actually in a pretty good shape
@@ -5632,6 +5971,7 @@ namespace build2
// so we actually don't need to pass any extra options (unless things
// get moved) but they still need access to the BMIs (and things will
// most likely have to be done differenly for distributed compilation).
+ // @@ Note: no longer the case for Clang either.
//
// So the revised plan: on the off chance that some implementation will
// do it differently we will continue maintaing the imported/re-exported
@@ -5725,6 +6065,8 @@ namespace build2
continue; // Scan the rest to detect if all done.
}
}
+ else
+ assert (name != m.name); // No duplicates.
done = false;
}
@@ -5752,10 +6094,18 @@ namespace build2
//
if (pt->is_a<bmix> ())
{
- const string& n (cast<string> (pt->state[a].vars[c_module_name]));
-
- if (const target** p = check_exact (n))
- *p = pt;
+ // If the extraction of the module information for this BMI failed
+ // and we have deferred failure to compiler diagnostics, then
+ // there will be no module name assigned. It would have been
+ // better to make sure that's the cause, but that won't be easy.
+ //
+ const string* n (cast_null<string> (
+ pt->state[a].vars[c_module_name]));
+ if (n != nullptr)
+ {
+ if (const target** p = check_exact (*n))
+ *p = pt;
+ }
}
else if (pt->is_a (*x_mod))
{
@@ -5764,7 +6114,8 @@ namespace build2
// rule puts them into prerequisite_targets for us).
//
// The module names should be specified but if not assume
- // something else is going on and ignore.
+ // something else is going on (like a deferred failure) and
+ // ignore.
//
// Note also that besides modules, prerequisite_targets may
// contain libraries which are interface dependencies of this
@@ -5777,7 +6128,15 @@ namespace build2
continue;
if (const target** p = check_exact (*n))
- *p = &this->make_module_sidebuild (a, bs, l, *pt, *n); // GCC 4.9
+ {
+ // It seems natural to build a BMI type that corresponds to the
+ // library type. After all, this is where the object file part
+ // of the BMI is going to come from (unless it's a module
+ // interface-only library).
+ //
+ *p = &this->make_module_sidebuild (
+ a, bs, &l, link_type (l).type, *pt, *n).first; // GCC 4.9
+ }
}
// Note that in prerequisite targets we will have the libux{}
// members, not the group.
@@ -5792,112 +6151,300 @@ namespace build2
}
};
- for (prerequisite_member p: group_prerequisite_members (a, t))
- {
- if (include (a, t, p) != include_type::normal) // Excluded/ad hoc.
- continue;
+ // Pre-resolve standard library modules (std and std.compat) in an ad
+ // hoc way.
+ //
- const target* pt (p.load ()); // Should be cached for libraries.
+ // Similar logic to check_exact() above.
+ //
+ done = true;
- if (pt != nullptr)
- {
- const file* lt (nullptr);
+ for (size_t i (0); i != n; ++i)
+ {
+ module_import& m (imports[i]);
- if (const libx* l = pt->is_a<libx> ())
- lt = link_member (*l, a, li);
- else if (pt->is_a<liba> () || pt->is_a<libs> () || pt->is_a<libux> ())
- lt = &pt->as<file> ();
+ if (m.name == "std" || m.name == "std.compat")
+ {
+ otype ot (otype::e);
+ const target* mt (nullptr);
- // If this is a library, check its bmi{}s and mxx{}s.
- //
- if (lt != nullptr)
+ switch (ctype)
{
- find (*lt, find);
+ case compiler_type::clang:
+ {
+ // @@ TODO: cache x_stdlib value.
+ //
+ if (cast<string> (rs[x_stdlib]) != "libc++")
+ fail << "standard library module '" << m.name << "' is "
+ << "currently only supported in libc++" <<
+ info << "try adding -stdlib=libc++ as compiler mode option";
+
+ if (cmaj < 18)
+ fail << "standard library module '" << m.name << "' is "
+ << "only supported in Clang 18 or later";
+
+ // Find or insert std*.cppm (similar code to pkgconfig.cxx).
+ //
+ // Note: build_install_data is absolute and normalized.
+ //
+ mt = &ctx.targets.insert_locked (
+ *x_mod,
+ (dir_path (build_install_data) /= "libbuild2") /= "cc",
+ dir_path (),
+ m.name,
+ string ("cppm"), // For C++14 during bootstrap.
+ target_decl::implied,
+ trace).first;
+
+ // Which output type should we use, static or shared? The
+ // correct way would be to detect whether static or shared
+ // version of libc++ is to be linked and use the corresponding
+ // type. And we could do that by looking for -static-libstdc++
+ // in loption (and no, it's not -static-libc++).
+ //
+ // But, looking at the object file produced from std*.cppm, they
+ // only contain one symbol, the static object initializer. And
+ // this is unlikely to change since all other non-inline or
+ // template symbols should be in libc++. So feels like it's not
+ // worth the trouble and one variant should be good enough for
+ // both cases. Let's use the shared one for less surprising
+ // diagnostics (as in, "why are you linking obje{} to a shared
+ // library?")
+ //
+ // (Of course, theoretically, std*.cppm could detect via a macro
+ // whether they are being compiled with -fPIC or not and do
+ // things differently, but this seems far-fetched).
+ //
+ ot = otype::s;
- if (done)
break;
+ }
+ case compiler_type::msvc:
+ {
+ // For MSVC, the source files std.ixx and std.compat.ixx are
+ // found in the modules/ subdirectory which is a sibling of
+ // include/ in the MSVC toolset (and "that is a contract with
+ // customers" to quote one of the developers).
+ //
+ // The problem of course is that there are multiple system
+ // header search directories (for example, as specified in the
+ // INCLUDE environment variable) and which one of them is for
+ // the MSVC toolset is not specified. So what we are going to do
+ // is search for one of the well-known standard C++ headers and
+ // assume that the directory where we found it is the one we are
+ // looking for. Or we could look for something MSVC-specific
+ // like vcruntime.h.
+ //
+ dir_path modules;
+ if (optional<path> p = find_system_header (path ("vcruntime.h")))
+ {
+ p->make_directory (); // Strip vcruntime.h.
+ if (p->leaf () == path ("include")) // Sanity check.
+ {
+ modules = path_cast<dir_path> (move (p->make_directory ()));
+ modules /= "modules";
+ }
+ }
- continue;
+ if (modules.empty ())
+ fail << "unable to locate MSVC standard modules directory";
+
+ mt = &ctx.targets.insert_locked (
+ *x_mod,
+ move (modules),
+ dir_path (),
+ m.name,
+ string ("ixx"), // For C++14 during bootstrap.
+ target_decl::implied,
+ trace).first;
+
+ // For MSVC it's easier to detect the runtime being used since
+ // it's specified with the compile options (/MT[d], /MD[d]).
+ //
+ // Similar semantics as in extract_headers() except here we use
+ // options visible from the root scope. Note that
+ // find_option_prefixes() looks in reverse, so look in the
+ // cmode, x_coptions, c_coptions order.
+ //
+ initializer_list<const char*> os {"/MD", "/MT", "-MD", "-MT"};
+
+ const string* o;
+ if ((o = find_option_prefixes (os, cmode)) != nullptr ||
+ (o = find_option_prefixes (os, rs, x_coptions)) != nullptr ||
+ (o = find_option_prefixes (os, rs, c_coptions)) != nullptr)
+ {
+ ot = (*o)[2] == 'D' ? otype::s : otype::a;
+ }
+ else
+ ot = otype::s; // The default is /MD.
+
+ break;
+ }
+ case compiler_type::gcc:
+ case compiler_type::icc:
+ {
+ fail << "standard library module '" << m.name << "' is "
+ << "not yet supported in this compiler";
+ }
+ };
+
+ pair<target&, ulock> tl (
+ this->make_module_sidebuild ( // GCC 4.9
+ a, bs, nullptr, ot, *mt, m.name));
+
+ if (tl.second.owns_lock ())
+ {
+ // Special compile options for the std modules.
+ //
+ if (ctype == compiler_type::clang)
+ {
+ value& v (tl.first.append_locked (x_coptions));
+
+ if (v.null)
+ v = strings {};
+
+ strings& cops (v.as<strings> ());
+
+ switch (ctype)
+ {
+ case compiler_type::clang:
+ {
+ cops.push_back ("-Wno-reserved-module-identifier");
+ break;
+ }
+ case compiler_type::msvc:
+ // It appears nothing special is needed to compile MSVC
+ // standard modules.
+ case compiler_type::gcc:
+ case compiler_type::icc:
+ assert (false);
+ };
+ }
+
+ tl.second.unlock ();
}
- // Fall through.
+ pts[start + i].target = &tl.first;
+ m.score = match_max (m.name) + 1;
+ continue; // Scan the rest to detect if all done.
}
- // While it would have been even better not to search for a target, we
- // need to get hold of the corresponding mxx{} (unlikely but possible
- // for bmi{} to have a different name).
- //
- // While we want to use group_prerequisite_members() below, we cannot
- // call resolve_group() since we will be doing it "speculatively" for
- // modules that we may use but also for modules that may use us. This
- // quickly leads to deadlocks. So instead we are going to perform an
- // ad hoc group resolution.
- //
- const target* pg;
- if (p.is_a<bmi> ())
- {
- pg = pt != nullptr ? pt : &p.search (t);
- pt = &search (t, btt, p.key ()); // Same logic as in picking obj*{}.
- }
- else if (p.is_a (btt))
- {
- pg = &search (t, bmi::static_type, p.key ());
- if (pt == nullptr) pt = &p.search (t);
- }
- else
- continue;
+ done = false;
+ }
- // Find the mxx{} prerequisite and extract its "file name" for the
- // fuzzy match unless the user specified the module name explicitly.
- //
- for (prerequisite_member p:
- prerequisite_members (a, t, group_prerequisites (*pt, pg)))
+ // Go over prerequisites and try to resolve imported modules with them.
+ //
+ if (!done)
+ {
+ for (prerequisite_member p: group_prerequisite_members (a, t))
{
if (include (a, t, p) != include_type::normal) // Excluded/ad hoc.
continue;
- if (p.is_a (*x_mod))
+ const target* pt (p.load ()); // Should be cached for libraries.
+
+ if (pt != nullptr)
{
- // Check for an explicit module name. Only look for an existing
- // target (which means the name can only be specified on the
- // target itself, not target type/pattern-spec).
+ const file* lt (nullptr);
+
+ if (const libx* l = pt->is_a<libx> ())
+ lt = link_member (*l, a, li);
+ else if (pt->is_a<liba> () ||
+ pt->is_a<libs> () ||
+ pt->is_a<libux> ())
+ lt = &pt->as<file> ();
+
+ // If this is a library, check its bmi{}s and mxx{}s.
//
- const target* t (p.search_existing ());
- const string* n (t != nullptr
- ? cast_null<string> (t->vars[c_module_name])
- : nullptr);
- if (n != nullptr)
+ if (lt != nullptr)
{
- if (const target** p = check_exact (*n))
- *p = pt;
+ find (*lt, find);
+
+ if (done)
+ break;
+
+ continue;
}
- else
+
+ // Fall through.
+ }
+
+ // While it would have been even better not to search for a target,
+ // we need to get hold of the corresponding mxx{} (unlikely but
+ // possible for bmi{} to have a different name).
+ //
+ // While we want to use group_prerequisite_members() below, we
+ // cannot call resolve_group() since we will be doing it
+ // "speculatively" for modules that we may use but also for modules
+ // that may use us. This quickly leads to deadlocks. So instead we
+ // are going to perform an ad hoc group resolution.
+ //
+ const target* pg;
+ if (p.is_a<bmi> ())
+ {
+ pg = pt != nullptr ? pt : &p.search (t);
+ pt = &search (t, btt, p.key ()); // Same logic as in picking obj*{}.
+ }
+ else if (p.is_a (btt))
+ {
+ pg = &search (t, bmi::static_type, p.key ());
+ if (pt == nullptr) pt = &p.search (t);
+ }
+ else
+ continue;
+
+ // Find the mxx{} prerequisite and extract its "file name" for the
+ // fuzzy match unless the user specified the module name explicitly.
+ //
+ for (prerequisite_member p:
+ prerequisite_members (a, t, group_prerequisites (*pt, pg)))
+ {
+ if (include (a, t, p) != include_type::normal) // Excluded/ad hoc.
+ continue;
+
+ if (p.is_a (*x_mod))
{
- // Fuzzy match.
+ // Check for an explicit module name. Only look for an existing
+ // target (which means the name can only be specified on the
+ // target itself, not target type/pattern-spec).
//
- string f;
+ const target* mt (p.search_existing ());
+ const string* n (mt != nullptr
+ ? cast_null<string> (mt->vars[c_module_name])
+ : nullptr);
+ if (n != nullptr)
+ {
+ if (const target** p = check_exact (*n))
+ *p = pt;
+ }
+ else
+ {
+ // Fuzzy match.
+ //
+ string f;
- // Add the directory part if it is relative. The idea is to
- // include it into the module match, say hello.core vs
- // hello/mxx{core}.
- //
- // @@ MOD: Why not for absolute? Good question. What if it
- // contains special components, say, ../mxx{core}?
- //
- const dir_path& d (p.dir ());
+ // Add the directory part if it is relative. The idea is to
+ // include it into the module match, say hello.core vs
+ // hello/mxx{core}.
+ //
+ // @@ MOD: Why not for absolute? Good question. What if it
+ // contains special components, say, ../mxx{core}?
+ //
+ const dir_path& d (p.dir ());
- if (!d.empty () && d.relative ())
- f = d.representation (); // Includes trailing slash.
+ if (!d.empty () && d.relative ())
+ f = d.representation (); // Includes trailing slash.
- f += p.name ();
- check_fuzzy (pt, f);
+ f += p.name ();
+ check_fuzzy (pt, f);
+ }
+ break;
}
- break;
}
- }
- if (done)
- break;
+ if (done)
+ break;
+ }
}
// Diagnose unresolved modules.
@@ -5967,9 +6514,12 @@ namespace build2
if (m.score <= match_max (in))
{
- const string& mn (cast<string> (bt->state[a].vars[c_module_name]));
+ // As above (deffered failure).
+ //
+ const string* mn (
+ cast_null<string> (bt->state[a].vars[c_module_name]));
- if (in != mn)
+ if (mn != nullptr && in != *mn)
{
// Note: matched, so the group should be resolved.
//
@@ -5983,7 +6533,7 @@ namespace build2
fail (relative (src))
<< "failed to correctly guess module name from " << p <<
info << "guessed: " << in <<
- info << "actual: " << mn <<
+ info << "actual: " << *mn <<
info << "consider adjusting module interface file names or" <<
info << "consider specifying module name with " << x
<< ".module_name";
@@ -6011,12 +6561,15 @@ namespace build2
if (et == nullptr)
continue; // Unresolved (std.*).
- const string& mn (cast<string> (et->state[a].vars[c_module_name]));
+ // As above (deferred failure).
+ //
+ const string* mn (cast_null<string> (et->state[a].vars[c_module_name]));
- if (find_if (imports.begin (), imports.end (),
- [&mn] (const module_import& i)
+ if (mn != nullptr &&
+ find_if (imports.begin (), imports.end (),
+ [mn] (const module_import& i)
{
- return i.name == mn;
+ return i.name == *mn;
}) == imports.end ())
{
pts.push_back (et);
@@ -6027,10 +6580,10 @@ namespace build2
// but it's probably not worth it if we have a small string
// optimization.
//
- import_type t (mn.find (':') != string::npos
+ import_type t (mn->find (':') != string::npos
? import_type::module_part
: import_type::module_intf);
- imports.push_back (module_import {t, mn, true, 0});
+ imports.push_back (module_import {t, *mn, true, 0});
}
}
}
@@ -6050,6 +6603,10 @@ namespace build2
// Find or create a modules sidebuild subproject returning its root
// directory.
//
+ // @@ Could we omit creating a subproject if the sidebuild scope is the
+ // project scope itself? This would speed up simple examples (and
+ // potentially direct compilation that we may support).
+ //
pair<dir_path, const scope&> compile_rule::
find_modules_sidebuild (const scope& rs) const
{
@@ -6120,6 +6677,15 @@ namespace build2
//
string extra;
+ // @@ What happens if different projects used different standards?
+ // Specifically, how do we detect this and what can the user do
+ // about it? For the latter question, forcing the same standard
+ // with config.cxx.std seems like the only sensible option. For
+ // the former, we could read the value of cxx.std using our
+ // buildfile first-line peeking mechanism. But doing that for
+ // every module interface feels inefficient so we will probably
+ // need to cache it on the per-project basis. Maybe/later.
+ //
if (const string* std = cast_null<string> (rs[x_std]))
extra += string (x) + ".std = " + *std + '\n';
@@ -6154,13 +6720,18 @@ namespace build2
return pair<dir_path, const scope&> (move (pd), *as);
}
- // Synthesize a dependency for building a module binary interface on
- // the side.
+ // Synthesize a dependency for building a module binary interface of a
+ // library on the side. If library is missing, then assume it's some
+ // ad hoc/system library case (in which case we assume it's binless,
+ // for now).
//
- const file& compile_rule::
+ // The return value semantics is as in target_set::insert_locked().
+ //
+ pair<target&, ulock> compile_rule::
make_module_sidebuild (action a,
const scope& bs,
- const file& lt,
+ const file* lt,
+ otype ot,
const target& mt,
const string& mn) const
{
@@ -6181,24 +6752,20 @@ namespace build2
back_inserter (mf),
[] (char c) {return c == '.' ? '-' : c == ':' ? '+' : c;});
- // It seems natural to build a BMI type that corresponds to the library
- // type. After all, this is where the object file part of the BMI is
- // going to come from (unless it's a module interface-only library).
- //
- const target_type& tt (compile_types (link_type (lt).type).bmi);
+ const target_type& tt (compile_types (ot).bmi);
// Store the BMI target in the subproject root. If the target already
// exists then we assume all this is already done (otherwise why would
// someone have created such a target).
//
- if (const file* bt = bs.ctx.targets.find<file> (
+ if (const target* bt = bs.ctx.targets.find (
tt,
pd,
dir_path (), // Always in the out tree.
mf,
nullopt, // Use default extension.
trace))
- return *bt;
+ return pair<target&, ulock> (const_cast<target&> (*bt), ulock ());
prerequisites ps;
ps.push_back (prerequisite (mt));
@@ -6211,19 +6778,22 @@ namespace build2
//
// Note: lt is matched and so the group is resolved.
//
- ps.push_back (prerequisite (lt));
- for (prerequisite_member p: group_prerequisite_members (a, lt))
+ if (lt != nullptr)
{
- // Ignore update=match.
- //
- lookup l;
- if (include (a, lt, p, &l) != include_type::normal) // Excluded/ad hoc.
- continue;
-
- if (p.is_a<libx> () ||
- p.is_a<liba> () || p.is_a<libs> () || p.is_a<libux> ())
+ ps.push_back (prerequisite (*lt));
+ for (prerequisite_member p: group_prerequisite_members (a, *lt))
{
- ps.push_back (p.as_prerequisite ());
+ // Ignore update=match.
+ //
+ lookup l;
+ if (include (a, *lt, p, &l) != include_type::normal) // Excluded/ad hoc.
+ continue;
+
+ if (p.is_a<libx> () ||
+ p.is_a<liba> () || p.is_a<libs> () || p.is_a<libux> ())
+ {
+ ps.push_back (p.as_prerequisite ());
+ }
}
}
@@ -6236,22 +6806,22 @@ namespace build2
target_decl::implied,
trace,
true /* skip_find */));
- file& bt (p.first.as<file> ());
// Note that this is racy and someone might have created this target
// while we were preparing the prerequisite list.
//
if (p.second)
{
- bt.prerequisites (move (ps));
+ p.first.prerequisites (move (ps));
// Unless this is a binless library, we don't need the object file
// (see config_data::b_binless for details).
//
- bt.vars.assign (b_binless) = (lt.mtime () == timestamp_unreal);
+ p.first.vars.assign (b_binless) = (lt == nullptr ||
+ lt->mtime () == timestamp_unreal);
}
- return bt;
+ return p;
}
// Synthesize a dependency for building a header unit binary interface on
@@ -6566,7 +7136,7 @@ namespace build2
// options).
//
void compile_rule::
- append_module_options (environment& env,
+ append_module_options (environment&,
cstrings& args,
small_vector<string, 2>& stor,
action a,
@@ -6577,8 +7147,6 @@ namespace build2
unit_type ut (md.type);
const module_positions& ms (md.modules);
- dir_path stdifc; // See the VC case below.
-
switch (ctype)
{
case compiler_type::gcc:
@@ -6607,15 +7175,12 @@ namespace build2
if (ms.start == 0)
return;
- // Clang embeds module file references so we only need to specify
- // our direct imports.
- //
- // If/when we get the ability to specify the mapping in a file, we
- // will pass the whole list.
+ // If/when we get the ability to specify the mapping in a file.
//
#if 0
// In Clang the module implementation's unit .pcm is special and
- // must be "loaded".
+ // must be "loaded". Note: not anymore, not from Clang 16 and is
+ // deprecated in 17.
//
if (ut == unit_type::module_impl)
{
@@ -6632,10 +7197,7 @@ namespace build2
stor.push_back (move (s));
#else
auto& pts (t.prerequisite_targets[a]);
- for (size_t i (ms.start),
- n (ms.copied != 0 ? ms.copied : pts.size ());
- i != n;
- ++i)
+ for (size_t i (ms.start), n (pts.size ()); i != n; ++i)
{
const target* pt (pts[i]);
@@ -6648,17 +7210,9 @@ namespace build2
const file& f (pt->as<file> ());
string s (relative (f.path ()).string ());
- // In Clang the module implementation's unit .pcm is special and
- // must be "loaded".
- //
- if (ut == unit_type::module_impl && i == ms.start)
- s.insert (0, "-fmodule-file=");
- else
- {
- s.insert (0, 1, '=');
- s.insert (0, cast<string> (f.state[a].vars[c_module_name]));
- s.insert (0, "-fmodule-file=");
- }
+ s.insert (0, 1, '=');
+ s.insert (0, cast<string> (f.state[a].vars[c_module_name]));
+ s.insert (0, "-fmodule-file=");
stor.push_back (move (s));
}
@@ -6670,10 +7224,11 @@ namespace build2
if (ms.start == 0)
return;
+ // MSVC requires a transitive set of interfaces, including
+ // implementation partitions.
+ //
auto& pts (t.prerequisite_targets[a]);
- for (size_t i (ms.start), n (pts.size ());
- i != n;
- ++i)
+ for (size_t i (ms.start), n (pts.size ()); i != n; ++i)
{
const target* pt (pts[i]);
@@ -6684,34 +7239,14 @@ namespace build2
// of these are bmi's.
//
const file& f (pt->as<file> ());
+ string s (relative (f.path ()).string ());
- // In VC std.* modules can only come from a single directory
- // specified with the IFCPATH environment variable or the
- // /module:stdIfcDir option.
- //
- if (std_module (cast<string> (f.state[a].vars[c_module_name])))
- {
- dir_path d (f.path ().directory ());
+ s.insert (0, 1, '=');
+ s.insert (0, cast<string> (f.state[a].vars[c_module_name]));
- if (stdifc.empty ())
- {
- // Go one directory up since /module:stdIfcDir will look in
- // either Release or Debug subdirectories. Keeping the result
- // absolute feels right.
- //
- stor.push_back ("/module:stdIfcDir");
- stor.push_back (d.directory ().string ());
- stdifc = move (d);
- }
- else if (d != stdifc) // Absolute and normalized.
- fail << "multiple std.* modules in different directories";
- }
- else
- {
- stor.push_back ("/module:reference");
- stor.push_back (relative (f.path ()).string ());
- }
+ stor.push_back (move (s));
}
+
break;
}
case compiler_type::icc:
@@ -6722,25 +7257,11 @@ namespace build2
// into storage? Because of potential reallocations.
//
for (const string& a: stor)
- args.push_back (a.c_str ());
-
- if (getenv ("IFCPATH"))
- {
- // VC's IFCPATH takes precedence over /module:stdIfcDir so unset it if
- // we are using our own std modules. Note: IFCPATH saved in guess.cxx.
- //
- if (!stdifc.empty ())
- env.push_back ("IFCPATH");
- }
- else if (stdifc.empty ())
{
- // Add the VC's default directory (should be only one).
- //
- if (sys_mod_dirs != nullptr && !sys_mod_dirs->empty ())
- {
- args.push_back ("/module:stdIfcDir");
- args.push_back (sys_mod_dirs->front ().string ().c_str ());
- }
+ if (ctype == compiler_type::msvc)
+ args.push_back ("/reference");
+
+ args.push_back (a.c_str ());
}
}
@@ -6813,7 +7334,8 @@ namespace build2
// If we are building a module interface or partition, then the target
// is bmi*{} and it may have an ad hoc obj*{} member. For header units
// there is no obj*{} (see the corresponding add_adhoc_member() call in
- // apply()).
+ // apply()). For named modules there may be no obj*{} if this is a
+ // sidebuild (obj*{} is already in the library binary).
//
path relm;
path relo;
@@ -6861,9 +7383,6 @@ namespace build2
small_vector<string, 2> header_args; // Header unit options storage.
small_vector<string, 2> module_args; // Module options storage.
- size_t out_i (0); // Index of the -o option.
- //size_t lang_n (0); // Number of lang options. @@ TMP
-
switch (cclass)
{
case compiler_class::msvc:
@@ -6883,6 +7402,10 @@ namespace build2
if (md.pp != preprocessed::all)
append_sys_hdr_options (args); // Extra system header dirs (last).
+ // Note: could be overridden in mode.
+ //
+ append_diag_color_options (args);
+
// Set source/execution charsets to UTF-8 unless a custom charset
// is specified.
//
@@ -6973,9 +7496,8 @@ namespace build2
// Note also that what we are doing here appears to be incompatible
// with PCH (/Y* options) and /Gm (minimal rebuild).
//
- // @@ MOD: TODO deal with absent relo.
- //
- if (find_options ({"/Zi", "/ZI", "-Zi", "-ZI"}, args))
+ if (!relo.empty () &&
+ find_options ({"/Zi", "/ZI", "-Zi", "-ZI"}, args))
{
if (fc)
args.push_back ("/Fd:");
@@ -6988,27 +7510,38 @@ namespace build2
args.push_back (out1.c_str ());
}
- if (fc)
- {
- args.push_back ("/Fo:");
- args.push_back (relo.string ().c_str ());
- }
- else
+ if (ut == unit_type::module_intf ||
+ ut == unit_type::module_intf_part ||
+ ut == unit_type::module_impl_part ||
+ ut == unit_type::module_header)
{
- out = "/Fo" + relo.string ();
- args.push_back (out.c_str ());
- }
+ assert (ut != unit_type::module_header); // @@ MODHDR
- // @@ MODHDR MSVC
- // @@ MODPART MSVC
- //
- if (ut == unit_type::module_intf)
- {
relm = relative (tp);
- args.push_back ("/module:interface");
- args.push_back ("/module:output");
+ args.push_back ("/ifcOutput");
args.push_back (relm.string ().c_str ());
+
+ if (relo.empty ())
+ args.push_back ("/ifcOnly");
+ else
+ {
+ args.push_back ("/Fo:");
+ args.push_back (relo.string ().c_str ());
+ }
+ }
+ else
+ {
+ if (fc)
+ {
+ args.push_back ("/Fo:");
+ args.push_back (relo.string ().c_str ());
+ }
+ else
+ {
+ out = "/Fo" + relo.string ();
+ args.push_back (out.c_str ());
+ }
}
// Note: no way to indicate that the source if already preprocessed.
@@ -7023,9 +7556,53 @@ namespace build2
{
append_options (args, cmode);
+ // Clang 15 introduced the unqualified-std-cast-call warning which
+ // warns about unqualified calls to std::move() and std::forward()
+ // (because they can be "hijacked" via ADL). Surprisingly, this
+ // warning is enabled by default, as opposed to with -Wextra or at
+ // least -Wall. It has also proven to be quite disruptive, causing a
+ // large number of warnings in a large number of packages. So we are
+ // going to "remap" it to -Wextra for now and in the future may
+ // "relax" it to -Wall and potentially to being enabled by default.
+ // See GitHub issue #259 for background and details.
+ //
+ if (x_lang == lang::cxx &&
+ ctype == compiler_type::clang &&
+ cmaj >= 15)
+ {
+ bool w (false); // Seen -W[no-]unqualified-std-cast-call
+ optional<bool> extra; // Seen -W[no-]extra
+
+ for (const char* s: reverse_iterate (args))
+ {
+ if (s != nullptr)
+ {
+ if (strcmp (s, "-Wunqualified-std-cast-call") == 0 ||
+ strcmp (s, "-Wno-unqualified-std-cast-call") == 0)
+ {
+ w = true;
+ break;
+ }
+
+ if (!extra) // Last seen option wins.
+ {
+ if (strcmp (s, "-Wextra") == 0) extra = true;
+ else if (strcmp (s, "-Wno-extra") == 0) extra = false;
+ }
+ }
+ }
+
+ if (!w && (!extra || !*extra))
+ args.push_back ("-Wno-unqualified-std-cast-call");
+ }
+
if (md.pp != preprocessed::all)
append_sys_hdr_options (args); // Extra system header dirs (last).
+ // Note: could be overridden in mode.
+ //
+ append_diag_color_options (args);
+
// Set the input charset to UTF-8 unless a custom one is specified.
//
// Note that the execution charset (-fexec-charset) is UTF-8 by
@@ -7079,8 +7656,7 @@ namespace build2
// either -nostdlib or -nostartfiles is specified. Let's do
// the same.
//
- initializer_list<const char*> os {"-nostdlib", "-nostartfiles"};
- if (!find_options (os, cmode) && !find_options (os, args))
+ if (!find_options ({"-nostdlib", "-nostartfiles"}, args))
{
args.push_back ("-D_MT");
args.push_back ("-D_DLL");
@@ -7142,10 +7718,6 @@ namespace build2
append_header_options (env, args, header_args, a, t, md, md.dd);
append_module_options (env, args, module_args, a, t, md, md.dd);
- // Note: the order of the following options is relied upon below.
- //
- out_i = args.size (); // Index of the -o option.
-
if (ut == unit_type::module_intf ||
ut == unit_type::module_intf_part ||
ut == unit_type::module_impl_part ||
@@ -7184,21 +7756,35 @@ namespace build2
}
case compiler_type::clang:
{
- // @@ MOD TODO: deal with absent relo.
+ assert (ut != unit_type::module_header); // @@ MODHDR
relm = relative (tp);
- args.push_back ("-o");
- args.push_back (relm.string ().c_str ());
- args.push_back ("--precompile");
-
// Without this option Clang's .pcm will reference source
- // files. In our case this file may be transient (.ii). Plus,
+ // files. In our case this file may be transient (.ii). Plus,
// it won't play nice with distributed compilation.
//
+ // Note that this sort of appears to be the default from Clang
+ // 17, but not quite, see llvm-project issued #72383.
+ //
args.push_back ("-Xclang");
args.push_back ("-fmodules-embed-all-files");
+ if (relo.empty ())
+ {
+ args.push_back ("-o");
+ args.push_back (relm.string ().c_str ());
+ args.push_back ("--precompile");
+ }
+ else
+ {
+ out1 = "-fmodule-output=" + relm.string ();
+ args.push_back (out1.c_str ());
+ args.push_back ("-o");
+ args.push_back (relo.string ().c_str ());
+ args.push_back ("-c");
+ }
+
break;
}
case compiler_type::msvc:
@@ -7213,7 +7799,7 @@ namespace build2
args.push_back ("-c");
}
- /*lang_n = */append_lang_options (args, md); // @@ TMP
+ append_lang_options (args, md);
if (md.pp == preprocessed::all)
{
@@ -7258,6 +7844,14 @@ namespace build2
if (!env.empty ())
env.push_back (nullptr);
+ // We have no choice but to serialize early if we want the command line
+ // printed shortly before actually executing the compiler. Failed that,
+ // it may look like we are still executing in parallel.
+ //
+ scheduler::alloc_guard jobs_ag;
+ if (!ctx.dry_run && cast_false<bool> (t[c_serialize]))
+ jobs_ag = scheduler::alloc_guard (*ctx.sched, phase_unlock (nullptr));
+
// With verbosity level 2 print the command line as if we are compiling
// the source file, not its preprocessed version (so that it's easy to
// copy and re-run, etc). Only at level 3 and above print the real deal.
@@ -7265,7 +7859,13 @@ namespace build2
// @@ TODO: why don't we print env (here and/or below)? Also link rule.
//
if (verb == 1)
- print_diag (x_objective (s) ? x_obj_name : x_name, s, t);
+ {
+ const char* name (x_assembler_cpp (s) ? "as-cpp" :
+ x_objective (s) ? x_obj_name :
+ x_name);
+
+ print_diag (name, s, t);
+ }
else if (verb == 2)
print_process (args);
@@ -7273,7 +7873,7 @@ namespace build2
//
// But we remember the original source/position to restore later.
//
- bool psrc (md.psrc);
+ bool psrc (md.psrc); // Note: false if cc.reprocess.
bool ptmp (psrc && md.psrc.temporary);
pair<size_t, const char*> osrc;
if (psrc)
@@ -7291,36 +7891,40 @@ namespace build2
{
case compiler_type::gcc:
{
- // @@ TMP
-#if 0
- // The -fpreprocessed is implied by .i/.ii. But not when compiling
- // a header unit (there is no .hi/.hii).
- //
- if (ut == unit_type::module_header)
- args.push_back ("-fpreprocessed");
- else
- // Pop -x since it takes precedence over the extension.
- //
- // @@ I wonder why bother and not just add -fpreprocessed? Are
- // we trying to save an option or does something break?
- //
- for (; lang_n != 0; --lang_n)
- args.pop_back ();
-#else
// -fpreprocessed is implied by .i/.ii unless compiling a header
// unit (there is no .hi/.hii). Also, we would need to pop -x
// since it takes precedence over the extension, which would mess
// up our osrc logic. So in the end it feels like always passing
// explicit -fpreprocessed is the way to go.
//
+ // Also note that similarly there is no .Si for .S files.
+ //
args.push_back ("-fpreprocessed");
-#endif
-
args.push_back ("-fdirectives-only");
break;
}
case compiler_type::clang:
{
+ // Clang 15 and later with -pedantic warns about GNU-style line
+ // markers that it wrote itself in the -frewrite-includes output
+ // (llvm-project issue 63284). So we suppress this warning unless
+ // compiling from source.
+ //
+ // In Apple Clang this warning/option are absent in 14.0.3 (which
+ // is said to be based on vanilla Clang 15.0.5) for some reason
+ // (let's hope it's because they patched it out rather than due to
+ // a misleading _LIBCPP_VERSION value).
+ //
+ if (ctype == compiler_type::clang &&
+ cmaj >= (cvariant != "apple" ? 15 : 16))
+ {
+ if (find_options ({"-pedantic", "-pedantic-errors",
+ "-Wpedantic", "-Werror=pedantic"}, args))
+ {
+ args.push_back ("-Wno-gnu-line-marker");
+ }
+ }
+
// Note that without -x Clang will treat .i/.ii as fully
// preprocessed.
//
@@ -7412,6 +8016,8 @@ namespace build2
throw failed ();
}
+ jobs_ag.deallocate ();
+
if (md.deferred_failure)
fail << "expected error exit status from " << x_lang << " compiler";
}
@@ -7421,59 +8027,6 @@ namespace build2
if (ptmp && verb >= 3)
md.psrc.temporary = true;
- // Clang's module compilation requires two separate compiler
- // invocations.
- //
- // @@ MODPART: Clang (all of this is probably outdated).
- //
- if (ctype == compiler_type::clang && ut == unit_type::module_intf)
- {
- // Adjust the command line. First discard everything after -o then
- // build the new "tail".
- //
- args.resize (out_i + 1);
- args.push_back (relo.string ().c_str ()); // Produce .o.
- args.push_back ("-c"); // By compiling .pcm.
- args.push_back ("-Wno-unused-command-line-argument");
- args.push_back (relm.string ().c_str ());
- args.push_back (nullptr);
-
- if (verb >= 2)
- print_process (args);
-
- if (!ctx.dry_run)
- {
- // Remove the target file if this fails. If we don't do that, we
- // will end up with a broken build that is up-to-date.
- //
- auto_rmfile rm (relm);
-
- try
- {
- process pr (cpath,
- args,
- 0, 2, diag_buffer::pipe (ctx),
- nullptr, // CWD
- env.empty () ? nullptr : env.data ());
-
- diag_buffer dbuf (ctx, args[0], pr);
- dbuf.read ();
- run_finish (dbuf, args, pr, 1 /* verbosity */);
- }
- catch (const process_error& e)
- {
- error << "unable to execute " << args[0] << ": " << e;
-
- if (e.child)
- exit (1);
-
- throw failed ();
- }
-
- rm.cancel ();
- }
- }
-
timestamp now (system_clock::now ());
if (!ctx.dry_run)
@@ -7495,11 +8048,13 @@ namespace build2
// Preprocessed file extension.
//
- const char* pext (x_objective (srct) ? x_obj_pext : x_pext);
+ const char* pext (x_assembler_cpp (srct) ? ".Si" :
+ x_objective (srct) ? x_obj_pext :
+ x_pext);
// Compressed preprocessed file extension.
//
- string cpext (t.ctx.fcache.compressed_extension (pext));
+ string cpext (t.ctx.fcache->compressed_extension (pext));
clean_extras extras;
switch (ctype)
diff --git a/libbuild2/cc/compile-rule.hxx b/libbuild2/cc/compile-rule.hxx
index a9a22c4..0886b4b 100644
--- a/libbuild2/cc/compile-rule.hxx
+++ b/libbuild2/cc/compile-rule.hxx
@@ -156,8 +156,9 @@ namespace build2
pair<dir_path, const scope&>
find_modules_sidebuild (const scope&) const;
- const file&
- make_module_sidebuild (action, const scope&, const file&,
+ pair<target&, ulock>
+ make_module_sidebuild (action, const scope&,
+ const file*, otype,
const target&, const string&) const;
const file&
diff --git a/libbuild2/cc/functions.cxx b/libbuild2/cc/functions.cxx
index 94900ee..9d408af 100644
--- a/libbuild2/cc/functions.cxx
+++ b/libbuild2/cc/functions.cxx
@@ -52,7 +52,7 @@ namespace build2
//
if (bs->ctx.phase != run_phase::match &&
bs->ctx.phase != run_phase::execute)
- fail << f.name << " can only be called during execution";
+ fail << f.name << " can only be called from recipe";
const module* m (rs->find_module<module> (d.x));
@@ -131,7 +131,7 @@ namespace build2
if (bs->ctx.phase != run_phase::match && // See above.
bs->ctx.phase != run_phase::execute)
- fail << f.name << " can only be called during execution";
+ fail << f.name << " can only be called from recipe";
const module* m (rs->find_module<module> (d.x));
diff --git a/libbuild2/cc/gcc.cxx b/libbuild2/cc/gcc.cxx
index 755b0d8..286ba10 100644
--- a/libbuild2/cc/gcc.cxx
+++ b/libbuild2/cc/gcc.cxx
@@ -45,6 +45,13 @@ namespace build2
d = dir_path (o, 2, string::npos);
else
continue;
+
+ // Ignore relative paths. Or maybe we should warn?
+ //
+ if (d.relative ())
+ continue;
+
+ d.normalize ();
}
catch (const invalid_path& e)
{
@@ -52,10 +59,7 @@ namespace build2
<< o << "'";
}
- // Ignore relative paths. Or maybe we should warn?
- //
- if (!d.relative ())
- r.push_back (move (d));
+ r.push_back (move (d));
}
}
@@ -78,6 +82,71 @@ namespace build2
}
#endif
+ // Parse color/semicolon-separated list of search directories (from
+ // -print-search-dirs output, environment variables).
+ //
+ static void
+ parse_search_dirs (const string& v, dir_paths& r,
+ const char* what, const char* what2 = "")
+ {
+ // Now the fun part: figuring out which delimiter is used. Normally it
+ // is ':' but on Windows it is ';' (or can be; who knows for sure). Also
+ // note that these paths are absolute (or should be). So here is what we
+ // are going to do: first look for ';'. If found, then that's the
+ // delimiter. If not found, then there are two cases: it is either a
+ // single Windows path or the delimiter is ':'. To distinguish these two
+ // cases we check if the path starts with a Windows drive.
+ //
+ char d (';');
+ string::size_type e (v.find (d));
+
+ if (e == string::npos &&
+ (v.size () < 2 || v[0] == '/' || v[1] != ':'))
+ {
+ d = ':';
+ e = v.find (d);
+ }
+
+ // Now chop it up. We already have the position of the first delimiter
+ // (if any).
+ //
+ for (string::size_type b (0);; e = v.find (d, (b = e + 1)))
+ {
+ dir_path d;
+ try
+ {
+ string ds (v, b, (e != string::npos ? e - b : e));
+
+ // Skip empty entries (sometimes found in random MinGW toolchains).
+ //
+ if (!ds.empty ())
+ {
+#ifdef _WIN32
+ if (path_traits::is_separator (ds[0]))
+ add_current_drive (ds);
+#endif
+ d = dir_path (move (ds));
+
+ if (d.relative ())
+ throw invalid_path (move (d).string ());
+
+ d.normalize ();
+ }
+ }
+ catch (const invalid_path& e)
+ {
+ fail << "invalid directory '" << e.path << "'" << " in "
+ << what << what2;
+ }
+
+ if (!d.empty () && find (r.begin (), r.end (), d) == r.end ())
+ r.push_back (move (d));
+
+ if (e == string::npos)
+ break;
+ }
+ }
+
// Extract system header search paths from GCC (gcc/g++) or compatible
// (Clang, Intel) using the `-v -E </dev/null` method.
//
@@ -88,14 +157,15 @@ namespace build2
// do this is to run the compiler twice.
//
pair<dir_paths, size_t> config_module::
- gcc_header_search_dirs (const process_path& xc, scope& rs) const
+ gcc_header_search_dirs (const compiler_info& xi, scope& rs) const
{
dir_paths r;
// Note also that any -I and similar that we may specify on the command
- // line are factored into the output.
+ // line are factored into the output. As well as the CPATH, etc.,
+ // environment variable values.
//
- cstrings args {xc.recall_string ()};
+ cstrings args {xi.path.recall_string ()};
append_options (args, rs, x_mode);
// Compile as.
@@ -119,7 +189,7 @@ namespace build2
args.push_back ("-");
args.push_back (nullptr);
- process_env env (xc);
+ process_env env (xi.path);
// For now let's assume that all the platforms other than Windows
// recognize LC_ALL.
@@ -132,6 +202,9 @@ namespace build2
if (verb >= 3)
print_process (env, args);
+ bool found_q (false); // Found `#include "..." ...` marker.
+ bool found_b (false); // Found `#include <...> ...` marker.
+
// Open pipe to stderr, redirect stdin and stdout to /dev/null.
//
process pr (run_start (
@@ -152,7 +225,7 @@ namespace build2
// End of search list.
//
// The exact text depends on the current locale. What we can rely on
- // is the presence of the "#include <...>" substring in the "opening"
+ // is the presence of the "#include <...>" marker in the "opening"
// line and the fact that the paths are indented with a single space
// character, unlike the "closing" line.
//
@@ -166,11 +239,15 @@ namespace build2
// which we fail to normalize or stat. @@ Maybe this is a bit too
// loose, especially compared to gcc_library_search_dirs()?
//
- string s;
- for (bool found (false); getline (is, s); )
+ // Note that when there are no paths (e.g., because of -nostdinc),
+ // then GCC prints both #include markers while Clang -- only "...".
+ //
+ for (string s; getline (is, s); )
{
- if (!found)
- found = s.find ("#include <...>") != string::npos;
+ if (!found_q)
+ found_q = s.find ("#include \"...\"") != string::npos;
+ else if (!found_b)
+ found_b = s.find ("#include <...>") != string::npos;
else
{
if (s[0] != ' ')
@@ -222,10 +299,12 @@ namespace build2
fail << "error reading " << x_lang << " compiler -v -E output";
}
- // It's highly unlikely not to have any system directories. More likely
- // we misinterpreted the compiler output.
+ // Note that it's possible that we will have no system directories, for
+ // example, if the user specified -nostdinc. But we must have still seen
+ // at least one marker. Failed that we assume we misinterpreted the
+ // compiler output.
//
- if (r.empty ())
+ if (!found_b && !found_q)
fail << "unable to extract " << x_lang << " compiler system header "
<< "search paths";
@@ -236,7 +315,7 @@ namespace build2
// (Clang, Intel) using the -print-search-dirs option.
//
pair<dir_paths, size_t> config_module::
- gcc_library_search_dirs (const process_path& xc, scope& rs) const
+ gcc_library_search_dirs (const compiler_info& xi, scope& rs) const
{
// The output of -print-search-dirs are a bunch of lines that start with
// "<name>: =" where name can be "install", "programs", or "libraries".
@@ -263,12 +342,12 @@ namespace build2
gcc_extract_library_search_dirs (cast<strings> (rs[x_mode]), r);
size_t rn (r.size ());
- cstrings args {xc.recall_string ()};
+ cstrings args {xi.path.recall_string ()};
append_options (args, rs, x_mode);
args.push_back ("-print-search-dirs");
args.push_back (nullptr);
- process_env env (xc);
+ process_env env (xi.path);
// For now let's assume that all the platforms other than Windows
// recognize LC_ALL.
@@ -326,62 +405,16 @@ namespace build2
fail << "unable to extract " << x_lang << " compiler system library "
<< "search paths";
- // Now the fun part: figuring out which delimiter is used. Normally it
- // is ':' but on Windows it is ';' (or can be; who knows for sure). Also
- // note that these paths are absolute (or should be). So here is what we
- // are going to do: first look for ';'. If found, then that's the
- // delimiter. If not found, then there are two cases: it is either a
- // single Windows path or the delimiter is ':'. To distinguish these two
- // cases we check if the path starts with a Windows drive.
- //
- char d (';');
- string::size_type e (l.find (d));
+ parse_search_dirs (l, r, args[0], " -print-search-dirs output");
- if (e == string::npos &&
- (l.size () < 2 || l[0] == '/' || l[1] != ':'))
- {
- d = ':';
- e = l.find (d);
- }
-
- // Now chop it up. We already have the position of the first delimiter
- // (if any).
+ // While GCC incorporates the LIBRARY_PATH environment variable value
+ // into the -print-search-dirs output, Clang does not. Also, unlike GCC,
+ // it appears to consider such paths last.
//
- for (string::size_type b (0);; e = l.find (d, (b = e + 1)))
+ if (xi.id.type == compiler_type::clang)
{
- dir_path d;
- try
- {
- string ds (l, b, (e != string::npos ? e - b : e));
-
- // Skip empty entries (sometimes found in random MinGW toolchains).
- //
- if (!ds.empty ())
- {
-#ifdef _WIN32
- if (path_traits::is_separator (ds[0]))
- add_current_drive (ds);
-#endif
-
- d = dir_path (move (ds));
-
- if (d.relative ())
- throw invalid_path (move (d).string ());
-
- d.normalize ();
- }
- }
- catch (const invalid_path& e)
- {
- fail << "invalid directory '" << e.path << "'" << " in "
- << args[0] << " -print-search-dirs output";
- }
-
- if (!d.empty () && find (r.begin (), r.end (), d) == r.end ())
- r.emplace_back (move (d));
-
- if (e == string::npos)
- break;
+ if (optional<string> v = getenv ("LIBRARY_PATH"))
+ parse_search_dirs (*v, r, "LIBRARY_PATH environment variable");
}
return make_pair (move (r), rn);
diff --git a/libbuild2/cc/guess.cxx b/libbuild2/cc/guess.cxx
index 7a2ede9..d7e9c63 100644
--- a/libbuild2/cc/guess.cxx
+++ b/libbuild2/cc/guess.cxx
@@ -412,6 +412,8 @@ namespace build2
//
// Note that Visual Studio versions prior to 15.0 are not supported.
//
+ // Note also the directories are absolute and normalized.
+ //
struct msvc_info
{
dir_path msvc_dir; // VC tools directory (...\Tools\MSVC\<ver>\).
@@ -759,7 +761,7 @@ namespace build2
//
for (const dir_entry& de:
dir_iterator (r.psdk_dir / dir_path ("Include"),
- false /* ignore_dangling */))
+ dir_iterator::no_follow))
{
if (de.type () == entry_type::directory)
{
@@ -777,6 +779,16 @@ namespace build2
return nullopt;
}
+ try
+ {
+ r.msvc_dir.normalize ();
+ r.psdk_dir.normalize ();
+ }
+ catch (const invalid_path&)
+ {
+ return nullopt;
+ }
+
return r;
}
#endif
@@ -1537,6 +1549,8 @@ namespace build2
msvc_extract_header_search_dirs (mo, r);
size_t rn (r.size ());
+ // Note: the resulting directories are normalized by construction.
+ //
r.push_back (dir_path (mi.msvc_dir) /= "include");
// This path structure only appeared in Platform SDK 10 (if anyone wants
@@ -1586,6 +1600,8 @@ namespace build2
msvc_extract_library_search_dirs (mo, r);
size_t rn (r.size ());
+ // Note: the resulting directories are normalized by construction.
+ //
r.push_back ((dir_path (mi.msvc_dir) /= "lib") /= cpu);
// This path structure only appeared in Platform SDK 10 (if anyone wants
@@ -2349,17 +2365,20 @@ namespace build2
// These are derived from gcc_* plus the sparse documentation (clang(1))
// and source code.
//
+ // Note that for now for Clang targeting MSVC we use msvc_env but should
+ // probably use a combined list.
+ //
// See also the note on environment and caching below if adding any new
// variables.
//
static const char* clang_c_env[] = {
- "CPATH", "C_INCLUDE_PATH",
+ "CPATH", "C_INCLUDE_PATH", "CCC_OVERRIDE_OPTIONS",
"LIBRARY_PATH", "LD_RUN_PATH",
"COMPILER_PATH",
nullptr};
static const char* clang_cxx_env[] = {
- "CPATH", "CPLUS_INCLUDE_PATH",
+ "CPATH", "CPLUS_INCLUDE_PATH", "CCC_OVERRIDE_OPTIONS",
"LIBRARY_PATH", "LD_RUN_PATH",
"COMPILER_PATH",
nullptr};
@@ -2405,6 +2424,12 @@ namespace build2
//
// emcc (...) 2.0.8
//
+ // Pre-releases of the vanilla Clang append `rc` or `git` to the
+ // version, unfortunately without a separator. So we will handle these
+ // ad hoc. For example:
+ //
+ // FreeBSD clang version 18.1.0rc (https://github.com/llvm/llvm-project.git llvmorg-18-init-18361-g22683463740e)
+ //
auto extract_version = [] (const string& s, bool patch, const char* what)
-> compiler_version
{
@@ -2419,8 +2444,28 @@ namespace build2
// end of the word position (first space). In fact, we can just
// check if it is >= e.
//
- if (s.find_first_not_of ("1234567890.", b, 11) >= e)
+ size_t p (s.find_first_not_of ("1234567890.", b, 11));
+ if (p >= e)
break;
+
+ // Handle the unseparated `rc` and `git` suffixes.
+ //
+ if (p != string::npos)
+ {
+ if (p + 2 == e && (e - b) > 2 &&
+ s[p] == 'r' && s[p + 1] == 'c')
+ {
+ e -= 2;
+ break;
+ }
+
+ if (p + 3 == e && (e - b) > 3 &&
+ s[p] == 'g' && s[p + 1] == 'i' && s[p + 2] == 't')
+ {
+ e -= 3;
+ break;
+ }
+ }
}
if (b == e)
@@ -2456,7 +2501,14 @@ namespace build2
ver.patch = next ("patch", patch);
if (e != s.size ())
- ver.build.assign (s, e + 1, string::npos);
+ {
+ // Skip the separator (it could also be unseparated `rc` or `git`).
+ //
+ if (s[e] == ' ' || s[e] == '-')
+ e++;
+
+ ver.build.assign (s, e, string::npos);
+ }
return ver;
};
@@ -2480,7 +2532,10 @@ namespace build2
// Some overrides for testing.
//
+ //string s (xv != nullptr ? *xv : "");
+ //
//s = "clang version 3.7.0 (tags/RELEASE_370/final)";
+ //s = "FreeBSD clang version 18.1.0rc (https://github.com/llvm/llvm-project.git llvmorg-18-init-18361-g22683463740e)";
//
//gr.id.variant = "apple";
//s = "Apple LLVM version 7.3.0 (clang-703.0.16.1)";
@@ -2508,10 +2563,21 @@ namespace build2
//
// Specifically, we now look in the libc++'s __config file for the
// _LIBCPP_VERSION and use the previous version as a conservative
- // estimate (NOTE that there could be multiple __config files with
+ // estimate (NOTE: that there could be multiple __config files with
// potentially different versions so compile with -v to see which one
// gets picked up).
//
+ // Also, lately, we started seeing _LIBCPP_VERSION values like 15.0.6
+ // or 16.0.2 which would suggest the base is 15.0.5 or 16.0.1. But
+ // that assumption did not check out with the actual usage. For
+ // example, vanilla Clang 16 should no longer require -fmodules-ts but
+ // the Apple's version (that is presumably based on it) still does. So
+ // the theory here is that Apple upgrades to newer libc++ while
+ // keeping the old compiler. Which means we must be more conservative
+ // and assume something like 15.0.6 is still 14-based. But then you
+ // get -Wunqualified-std-cast-call in 14, which was supposedly only
+ // introduced in Clang 15. So maybe not.
+ //
// Note that this is Apple Clang version and not XCode version.
//
// 4.2 -> 3.2svn
@@ -2532,35 +2598,40 @@ namespace build2
// 12.0.5 -> 10.0 (yes, seriously!)
// 13.0.0 -> 11.0
// 13.1.6 -> 12.0
+ // 14.0.0 -> 12.0 (_LIBCPP_VERSION=130000)
+ // 14.0.3 -> 15.0 (_LIBCPP_VERSION=150006)
+ // 15.0.0 -> 16.0 (_LIBCPP_VERSION=160002)
//
uint64_t mj (var_ver->major);
uint64_t mi (var_ver->minor);
uint64_t pa (var_ver->patch);
- if (mj > 13 || (mj == 13 && mi >= 1)) {mj = 12; mi = 0;}
- else if (mj == 13) {mj = 11; mi = 0;}
- else if (mj == 12 && (mi > 0 || pa >= 5)) {mj = 10; mi = 0;}
- else if (mj == 12) {mj = 9; mi = 0;}
- else if (mj == 11 && (mi > 0 || pa >= 3)) {mj = 8; mi = 0;}
- else if (mj == 11) {mj = 7; mi = 0;}
- else if (mj == 10) {mj = 6; mi = 0;}
- else if (mj == 9 && mi >= 1) {mj = 5; mi = 0;}
- else if (mj == 9) {mj = 4; mi = 0;}
- else if (mj == 8) {mj = 3; mi = 9;}
- else if (mj == 7 && mi >= 3) {mj = 3; mi = 8;}
- else if (mj == 7) {mj = 3; mi = 7;}
- else if (mj == 6 && mi >= 1) {mj = 3; mi = 5;}
- else if (mj == 6) {mj = 3; mi = 4;}
- else if (mj == 5 && mi >= 1) {mj = 3; mi = 3;}
- else if (mj == 5) {mj = 3; mi = 2;}
- else if (mj == 4 && mi >= 2) {mj = 3; mi = 1;}
- else {mj = 3; mi = 0;}
+ if (mj >= 15) {mj = 16; mi = 0; pa = 0;}
+ else if (mj == 14 && (mi > 0 || pa >= 3)) {mj = 15; mi = 0; pa = 0;}
+ else if (mj == 14 || (mj == 13 && mi >= 1)) {mj = 12; mi = 0; pa = 0;}
+ else if (mj == 13) {mj = 11; mi = 0; pa = 0;}
+ else if (mj == 12 && (mi > 0 || pa >= 5)) {mj = 10; mi = 0; pa = 0;}
+ else if (mj == 12) {mj = 9; mi = 0; pa = 0;}
+ else if (mj == 11 && (mi > 0 || pa >= 3)) {mj = 8; mi = 0; pa = 0;}
+ else if (mj == 11) {mj = 7; mi = 0; pa = 0;}
+ else if (mj == 10) {mj = 6; mi = 0; pa = 0;}
+ else if (mj == 9 && mi >= 1) {mj = 5; mi = 0; pa = 0;}
+ else if (mj == 9) {mj = 4; mi = 0; pa = 0;}
+ else if (mj == 8) {mj = 3; mi = 9; pa = 0;}
+ else if (mj == 7 && mi >= 3) {mj = 3; mi = 8; pa = 0;}
+ else if (mj == 7) {mj = 3; mi = 7; pa = 0;}
+ else if (mj == 6 && mi >= 1) {mj = 3; mi = 5; pa = 0;}
+ else if (mj == 6) {mj = 3; mi = 4; pa = 0;}
+ else if (mj == 5 && mi >= 1) {mj = 3; mi = 3; pa = 0;}
+ else if (mj == 5) {mj = 3; mi = 2; pa = 0;}
+ else if (mj == 4 && mi >= 2) {mj = 3; mi = 1; pa = 0;}
+ else {mj = 3; mi = 0; pa = 0;}
ver = compiler_version {
- to_string (mj) + '.' + to_string (mi) + ".0",
+ to_string (mj) + '.' + to_string (mi) + '.' + to_string (pa),
mj,
mi,
- 0,
+ pa,
""};
}
else if (emscr)
@@ -2673,7 +2744,7 @@ namespace build2
const char* cpu (msvc_cpu (tt.cpu));
// Come up with the system library search paths. Ideally we would want
- // to extract this from Clang and -print-search-paths would have been
+ // to extract this from Clang and -print-search-dirs would have been
// the natural way for Clang to report it. But no luck.
//
lib_dirs = msvc_lib (mi, x_mo, cpu);
diff --git a/libbuild2/cc/init.cxx b/libbuild2/cc/init.cxx
index 33a1133..e124450 100644
--- a/libbuild2/cc/init.cxx
+++ b/libbuild2/cc/init.cxx
@@ -100,13 +100,19 @@ namespace build2
vp.insert<strings> ("config.cc.loptions");
vp.insert<strings> ("config.cc.aoptions");
vp.insert<strings> ("config.cc.libs");
- vp.insert<string> ("config.cc.internal.scope");
+
+ vp.insert<string> ("config.cc.internal.scope");
+
+ vp.insert<bool> ("config.cc.reprocess"); // See cc.preprocess below.
+
+ vp.insert<abs_dir_path> ("config.cc.pkgconfig.sysroot");
vp.insert<strings> ("cc.poptions");
vp.insert<strings> ("cc.coptions");
vp.insert<strings> ("cc.loptions");
vp.insert<strings> ("cc.aoptions");
vp.insert<strings> ("cc.libs");
+
vp.insert<string> ("cc.internal.scope");
vp.insert<strings> ("cc.internal.libs");
@@ -120,8 +126,8 @@ namespace build2
// files instead of the default install.{include,lib}. Relative paths
// are resolved as install paths.
//
- vp.insert<dir_paths> ("cc.pkconfig.include");
- vp.insert<dir_paths> ("cc.pkconfig.lib");
+ vp.insert<dir_paths> ("cc.pkgconfig.include");
+ vp.insert<dir_paths> ("cc.pkgconfig.lib");
// Hint variables (not overridable).
//
@@ -177,9 +183,15 @@ namespace build2
// Ability to disable using preprocessed output for compilation.
//
- vp.insert<bool> ("config.cc.reprocess");
vp.insert<bool> ("cc.reprocess");
+ // Execute serially with regards to any other recipe. This is primarily
+ // useful when compiling large translation units or linking large
+ // binaries that require so much memory that doing that in parallel with
+ // other compilation/linking jobs is likely to summon the OOM killer.
+ //
+ vp.insert<bool> ("cc.serialize");
+
// Register scope operation callback.
//
// It feels natural to clean up sidebuilds as a post operation but that
@@ -337,6 +349,15 @@ namespace build2
if (lookup l = lookup_config (rs, "config.cc.reprocess"))
rs.assign ("cc.reprocess") = *l;
+ // config.cc.pkgconfig.sysroot
+ //
+ // Let's look it up instead of just marking for saving to make sure the
+ // path is valid.
+ //
+ // Note: save omitted.
+ //
+ lookup_config (rs, "config.cc.pkgconfig.sysroot");
+
// Load the bin.config module.
//
if (!cast_false<bool> (rs["bin.config.loaded"]))
diff --git a/libbuild2/cc/install-rule.cxx b/libbuild2/cc/install-rule.cxx
index 640612c..6758e03 100644
--- a/libbuild2/cc/install-rule.cxx
+++ b/libbuild2/cc/install-rule.cxx
@@ -18,20 +18,67 @@ namespace build2
{
using namespace bin;
+ using posthoc_prerequisite_target =
+ context::posthoc_target::prerequisite_target;
+
// install_rule
//
install_rule::
install_rule (data&& d, const link_rule& l)
: common (move (d)), link_ (l) {}
- const target* install_rule::
+ // Wrap the file_rule's recipe into a data-carrying recipe.
+ //
+ struct install_match_data
+ {
+ build2::recipe recipe;
+ uint64_t options; // Match options.
+ link_rule::libs_paths libs_paths;
+
+ target_state
+ operator() (action a, const target& t)
+ {
+ return recipe (a, t);
+ }
+ };
+
+ bool install_rule::
+ filter (action a, const target& t, const target& m) const
+ {
+ if (!t.is_a<exe> ())
+ {
+ // If runtime-only, filter out all known buildtime target types.
+ //
+ const auto& md (t.data<install_match_data> (a));
+
+ if ((md.options & lib::option_install_buildtime) == 0)
+ {
+ if (m.is_a<liba> () || // Staic library.
+ m.is_a<pc> () || // pkg-config file.
+ m.is_a<libi> ()) // Import library.
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ pair<const target*, uint64_t> install_rule::
filter (const scope* is,
- action a, const target& t, prerequisite_iterator& i) const
+ action a, const target& t, prerequisite_iterator& i,
+ match_extra& me) const
{
// NOTE: see libux_install_rule::filter() if changing anything here.
const prerequisite& p (i->prerequisite);
+ uint64_t options (match_extra::all_options);
+
+ otype ot (link_type (t).type);
+
+ // @@ TMP: drop eventually.
+ //
+#if 0
// If this is a shared library prerequisite, install it as long as it is
// in the installation scope.
//
@@ -43,10 +90,14 @@ namespace build2
//
// Note: we install ad hoc prerequisites by default.
//
- otype ot (link_type (t).type);
+ // Note: at least one must be true since we only register this rule for
+ // exe{}, and lib[as]{} (this makes sure the following if-condition will
+ // always be true for libx{}).
+ //
bool st (t.is_a<exe> () || t.is_a<libs> ()); // Target needs shared.
bool at (t.is_a<liba> () || t.is_a<libs> ()); // Target needs static.
+ assert (st || at);
if ((st && (p.is_a<libx> () || p.is_a<libs> ())) ||
(at && (p.is_a<libx> () || p.is_a<liba> ())))
@@ -59,26 +110,115 @@ namespace build2
if (const libx* l = pt->is_a<libx> ())
pt = link_member (*l, a, link_info (t.base_scope (), ot));
- // Note: not redundant since we are returning a member.
+ // Note: not redundant since we could be returning a member.
//
if ((st && pt->is_a<libs> ()) || (at && pt->is_a<liba> ()))
- return is == nullptr || pt->in (*is) ? pt : nullptr;
+ {
+ // Adjust match options.
+ //
+ if (a.operation () != update_id)
+ {
+ if (t.is_a<exe> ())
+ options = lib::option_install_runtime;
+ else
+ {
+ // This is a library prerequisite of a library target and
+ // runtime-only begets runtime-only.
+ //
+ if (me.cur_options == lib::option_install_runtime)
+ options = lib::option_install_runtime;
+ }
+ }
+
+ return make_pair (is == nullptr || pt->in (*is) ? pt : nullptr,
+ options);
+ }
// See through to libu*{} members. Note that we are always in the same
// project (and thus amalgamation).
//
if (pt->is_a<libux> ())
- return pt;
+ {
+ // Adjust match options (similar to above).
+ //
+ if (a.operation () != update_id && !pt->is_a<libue> ())
+ {
+ if (t.is_a<exe> ())
+ options = lib::option_install_runtime;
+ else
+ {
+ if (me.cur_options == lib::option_install_runtime)
+ options = lib::option_install_runtime;
+ }
+ }
+
+ return make_pair (pt, options);
+ }
}
+#else
+ // Note that at first it may seem like we don't need to install static
+ // library prerequisites of executables. But such libraries may still
+ // have prerequisites that are needed at runtime (say, some data files).
+ // So we install all libraries as long as they are in the installation
+ // scope and deal with runtime vs buildtime distiction using match
+ // options.
+ //
+ // Note: for now we assume these prerequisites never come from see-
+ // through groups.
+ //
+ // Note: we install ad hoc prerequisites by default.
+ //
+ if (p.is_a<libx> () || p.is_a<libs> () || p.is_a<liba> ())
+ {
+ const target* pt (&search (t, p));
+
+ // If this is the lib{}/libu*{} group, pick a member which we would
+ // link. For libu*{} we want the "see through" logic.
+ //
+ if (const libx* l = pt->is_a<libx> ())
+ pt = link_member (*l, a, link_info (t.base_scope (), ot));
+
+ // Adjust match options.
+ //
+ if (a.operation () != update_id)
+ {
+ if (t.is_a<exe> ())
+ options = lib::option_install_runtime;
+ else
+ {
+ // This is a library prerequisite of a library target and
+ // runtime-only begets runtime-only.
+ //
+ if (me.cur_options == lib::option_install_runtime)
+ options = lib::option_install_runtime;
+ }
+ }
+
+ // Note: not redundant since we could be returning a member.
+ //
+ if (pt->is_a<libs> () || pt->is_a<liba> ())
+ {
+ return make_pair (is == nullptr || pt->in (*is) ? pt : nullptr,
+ options);
+ }
+ else // libua{} or libus{}
+ {
+ // See through to libu*{} members. Note that we are always in the
+ // same project (and thus amalgamation).
+ //
+ return make_pair (pt, options);
+ }
+ }
+#endif
// The rest of the tests only succeed if the base filter() succeeds.
//
- const target* pt (file_rule::filter (is, a, t, p));
+ const target* pt (file_rule::filter (is, a, t, p, me).first);
if (pt == nullptr)
- return pt;
+ return make_pair (pt, options);
- // Don't install executable's prerequisite headers and module
- // interfaces.
+ // Don't install executable's or runtime-only library's prerequisite
+ // headers and module interfaces.
//
// Note that if they come from a group, then we assume the entire
// group is not to be installed.
@@ -88,13 +228,18 @@ namespace build2
//
auto header_source = [this] (const auto& p)
{
- return (x_header (p) ||
- p.is_a (x_src) ||
- (x_mod != nullptr && p.is_a (*x_mod)) ||
- (x_obj != nullptr && p.is_a (*x_obj)));
+ return (x_header (p) ||
+ p.is_a (x_src) ||
+ p.is_a (c::static_type) ||
+ p.is_a (S::static_type) ||
+ (x_mod != nullptr && p.is_a (*x_mod)) ||
+ (x_obj != nullptr && (p.is_a (*x_obj) ||
+ p.is_a (m::static_type))));
};
- if (t.is_a<exe> ())
+ if (t.is_a<exe> () ||
+ (a.operation () != update_id &&
+ me.cur_options == lib::option_install_runtime))
{
if (header_source (p))
pt = nullptr;
@@ -109,7 +254,7 @@ namespace build2
}
if (pt == nullptr)
- return pt;
+ return make_pair (pt, options);
}
// Here is a problem: if the user spells the obj*/bmi*{} targets
@@ -139,16 +284,16 @@ namespace build2
{
pt = t.is_a<exe> ()
? nullptr
- : file_rule::filter (is, a, *pt, pm.prerequisite);
+ : file_rule::filter (is, a, *pt, pm.prerequisite, me).first;
break;
}
}
if (pt == nullptr)
- return pt;
+ return make_pair (pt, options);
}
- return pt;
+ return make_pair (pt, options);
}
bool install_rule::
@@ -161,27 +306,34 @@ namespace build2
file_rule::match (a, t);
}
- // Wrap the file_rule's recipe into a data-carrying recipe.
- //
- struct install_match_data
+ recipe install_rule::
+ apply (action a, target& t, match_extra& me) const
{
- build2::recipe recipe;
- link_rule::libs_paths libs_paths;
-
- target_state
- operator() (action a, const target& t)
+ // Handle match options.
+ //
+ // Do it before calling apply_impl() since we need this information
+ // in the filter() callbacks.
+ //
+ if (a.operation () != update_id)
{
- return recipe (a, t);
+ if (!t.is_a<exe> ())
+ {
+ if (me.new_options == 0)
+ me.new_options = lib::option_install_runtime; // Minimum we can do.
+
+ me.cur_options = me.new_options;
+ }
}
- };
- recipe install_rule::
- apply (action a, target& t) const
- {
- recipe r (file_rule::apply_impl (a, t));
+ recipe r (file_rule::apply_impl (
+ a, t, me,
+ me.cur_options != match_extra::all_options /* reapply */));
if (r == nullptr)
+ {
+ me.cur_options = match_extra::all_options; // Noop for all options.
return noop_recipe;
+ }
if (a.operation () == update_id)
{
@@ -203,29 +355,109 @@ namespace build2
}
else // install or uninstall
{
- // Derive shared library paths and cache them in the target's aux
- // storage if we are un/installing (used in the *_extra() functions
- // below).
- //
- if (file* f = t.is_a<libs> ())
+ file* ls;
+ if ((ls = t.is_a<libs> ()) || t.is_a<liba> ())
{
- if (!f->path ().empty ()) // Not binless.
+ // Derive shared library paths and cache them in the target's aux
+ // storage if we are un/installing (used in the *_extra() functions
+ // below).
+ //
+ link_rule::libs_paths lsp;
+ if (ls != nullptr && !ls->path ().empty ()) // Not binless.
{
const string* p (cast_null<string> (t["bin.lib.prefix"]));
const string* s (cast_null<string> (t["bin.lib.suffix"]));
- return install_match_data {
- move (r),
- link_.derive_libs_paths (*f,
- p != nullptr ? p->c_str (): nullptr,
- s != nullptr ? s->c_str (): nullptr)};
+ lsp = link_.derive_libs_paths (*ls,
+ p != nullptr ? p->c_str (): nullptr,
+ s != nullptr ? s->c_str (): nullptr);
}
+
+ return install_match_data {move (r), me.cur_options, move (lsp)};
}
}
return r;
}
+ void install_rule::
+ apply_posthoc (action a, target& t, match_extra& me) const
+ {
+ // Similar semantics to filter() above for shared libraries specified as
+ // post hoc prerequisites (e.g., plugins).
+ //
+ if (a.operation () != update_id)
+ {
+ for (posthoc_prerequisite_target& p: *me.posthoc_prerequisite_targets)
+ {
+ if (p.target != nullptr && p.target->is_a<libs> ())
+ {
+ if (t.is_a<exe> ())
+ p.match_options = lib::option_install_runtime;
+ else
+ {
+ if (me.cur_options == lib::option_install_runtime)
+ p.match_options = lib::option_install_runtime;
+ }
+ }
+ }
+ }
+ }
+
+ void install_rule::
+ reapply (action a, target& t, match_extra& me) const
+ {
+ tracer trace ("cc::install_rule::reapply");
+
+ assert (a.operation () != update_id && !t.is_a<exe> ());
+
+ l6 ([&]{trace << "rematching " << t
+ << ", current options " << me.cur_options
+ << ", new options " << me.new_options;});
+
+ me.cur_options |= me.new_options;
+
+ // We also need to update options in install_match_data.
+ //
+ t.data<install_match_data> (a).options = me.cur_options;
+
+ if ((me.new_options & lib::option_install_buildtime) != 0)
+ {
+ // If we are rematched with the buildtime option, propagate it to our
+ // prerequisite libraries.
+ //
+ for (const target* pt: t.prerequisite_targets[a])
+ {
+ if (pt != nullptr && (pt->is_a<liba> () || pt->is_a<libs> () ||
+ pt->is_a<libua> () || pt->is_a<libus> ()))
+ {
+ // Go for all options instead of just install_buildtime to avoid
+ // any further relocking/reapply (we only support runtime-only or
+ // everything).
+ //
+ rematch_sync (a, *pt, match_extra::all_options);
+ }
+ }
+
+ // Also to post hoc.
+ //
+ if (me.posthoc_prerequisite_targets != nullptr)
+ {
+ for (posthoc_prerequisite_target& p: *me.posthoc_prerequisite_targets)
+ {
+ if (p.target != nullptr && p.target->is_a<libs> ())
+ {
+ p.match_options = match_extra::all_options;
+ }
+ }
+ }
+
+ // Also match any additional prerequisites (e.g., headers).
+ //
+ file_rule::reapply_impl (a, t, me);
+ }
+ }
+
bool install_rule::
install_extra (const file& t, const install_dir& id) const
{
@@ -233,14 +465,19 @@ namespace build2
if (t.is_a<libs> ())
{
+ const auto& md (t.data<install_match_data> (perform_install_id));
+
// Here we may have a bunch of symlinks that we need to install.
//
+ // Note that for runtime-only install we only omit the name that is
+ // used for linking (e.g., libfoo.so).
+ //
const scope& rs (t.root_scope ());
- auto& lp (t.data<install_match_data> (perform_install_id).libs_paths);
+ const link_rule::libs_paths& lp (md.libs_paths);
- auto ln = [&rs, &id] (const path& f, const path& l)
+ auto ln = [&t, &rs, &id] (const path& f, const path& l)
{
- install_l (rs, id, f.leaf (), l.leaf (), 2 /* verbosity */);
+ install_l (rs, id, l.leaf (), t, f.leaf (), 2 /* verbosity */);
return true;
};
@@ -254,7 +491,10 @@ namespace build2
if (!in.empty ()) {r = ln (*f, in) || r; f = &in;}
if (!so.empty ()) {r = ln (*f, so) || r; f = &so;}
if (!ld.empty ()) {r = ln (*f, ld) || r; f = &ld;}
- if (!lk.empty ()) {r = ln (*f, lk) || r; }
+ if ((md.options & lib::option_install_buildtime) != 0)
+ {
+ if (!lk.empty ()) {r = ln (*f, lk) || r;}
+ }
}
return r;
@@ -267,14 +507,16 @@ namespace build2
if (t.is_a<libs> ())
{
+ const auto& md (t.data<install_match_data> (perform_uninstall_id));
+
// Here we may have a bunch of symlinks that we need to uninstall.
//
const scope& rs (t.root_scope ());
- auto& lp (t.data<install_match_data> (perform_uninstall_id).libs_paths);
+ const link_rule::libs_paths& lp (md.libs_paths);
auto rm = [&rs, &id] (const path& f, const path& l)
{
- return uninstall_l (rs, id, f.leaf (), l.leaf (), 2 /* verbosity */);
+ return uninstall_l (rs, id, l.leaf (), f.leaf (), 2 /* verbosity */);
};
const path& lk (lp.link);
@@ -287,7 +529,10 @@ namespace build2
if (!in.empty ()) {r = rm (*f, in) || r; f = &in;}
if (!so.empty ()) {r = rm (*f, so) || r; f = &so;}
if (!ld.empty ()) {r = rm (*f, ld) || r; f = &ld;}
- if (!lk.empty ()) {r = rm (*f, lk) || r; }
+ if ((md.options & lib::option_install_buildtime) != 0)
+ {
+ if (!lk.empty ()) {r = rm (*f, lk) || r;}
+ }
}
return r;
@@ -299,22 +544,30 @@ namespace build2
libux_install_rule (data&& d, const link_rule& l)
: common (move (d)), link_ (l) {}
- const target* libux_install_rule::
+ pair<const target*, uint64_t> libux_install_rule::
filter (const scope* is,
- action a, const target& t, prerequisite_iterator& i) const
+ action a, const target& t, prerequisite_iterator& i,
+ match_extra& me) const
{
using file_rule = install::file_rule;
const prerequisite& p (i->prerequisite);
+ uint64_t options (match_extra::all_options);
+
+ otype ot (link_type (t).type);
+
// The "see through" semantics that should be parallel to install_rule
// above. In particular, here we use libue/libua/libus{} as proxies for
// exe/liba/libs{} there.
//
- otype ot (link_type (t).type);
+ // @@ TMP: drop eventually.
+ //
+#if 0
bool st (t.is_a<libue> () || t.is_a<libus> ()); // Target needs shared.
bool at (t.is_a<libua> () || t.is_a<libus> ()); // Target needs static.
+ assert (st || at);
if ((st && (p.is_a<libx> () || p.is_a<libs> ())) ||
(at && (p.is_a<libx> () || p.is_a<liba> ())))
@@ -325,25 +578,85 @@ namespace build2
pt = link_member (*l, a, link_info (t.base_scope (), ot));
if ((st && pt->is_a<libs> ()) || (at && pt->is_a<liba> ()))
- return is == nullptr || pt->in (*is) ? pt : nullptr;
+ {
+ if (a.operation () != update_id)
+ {
+ if (t.is_a<libue> ())
+ options = lib::option_install_runtime;
+ else
+ {
+ if (me.cur_options == lib::option_install_runtime)
+ options = lib::option_install_runtime;
+ }
+ }
+
+ return make_pair (is == nullptr || pt->in (*is) ? pt : nullptr,
+ options);
+ }
if (pt->is_a<libux> ())
- return pt;
+ {
+ if (a.operation () != update_id && !pt->is_a<libue> ())
+ {
+ if (t.is_a<libue> ())
+ options = lib::option_install_runtime;
+ else
+ {
+ if (me.cur_options == lib::option_install_runtime)
+ options = lib::option_install_runtime;
+ }
+ }
+
+ return make_pair (pt, options);
+ }
}
+#else
+ if (p.is_a<libx> () || p.is_a<libs> () || p.is_a<liba> ())
+ {
+ const target* pt (&search (t, p));
- const target* pt (file_rule::instance.filter (is, a, t, p));
+ if (const libx* l = pt->is_a<libx> ())
+ pt = link_member (*l, a, link_info (t.base_scope (), ot));
+
+ if (a.operation () != update_id)
+ {
+ if (t.is_a<libue> ())
+ options = lib::option_install_runtime;
+ else
+ {
+ if (me.cur_options == lib::option_install_runtime)
+ options = lib::option_install_runtime;
+ }
+ }
+
+ if (pt->is_a<libs> () || pt->is_a<liba> ())
+ {
+ return make_pair (is == nullptr || pt->in (*is) ? pt : nullptr,
+ options);
+ }
+ else
+ return make_pair (pt, options);
+ }
+#endif
+
+ const target* pt (file_rule::instance.filter (is, a, t, p, me).first);
if (pt == nullptr)
- return pt;
+ return make_pair (pt, options);
auto header_source = [this] (const auto& p)
{
- return (x_header (p) ||
- p.is_a (x_src) ||
- (x_mod != nullptr && p.is_a (*x_mod)) ||
- (x_obj != nullptr && p.is_a (*x_obj)));
+ return (x_header (p) ||
+ p.is_a (x_src) ||
+ p.is_a (c::static_type) ||
+ p.is_a (S::static_type) ||
+ (x_mod != nullptr && p.is_a (*x_mod)) ||
+ (x_obj != nullptr && (p.is_a (*x_obj) ||
+ p.is_a (m::static_type))));
};
- if (t.is_a<libue> ())
+ if (t.is_a<libue> () ||
+ (a.operation () != update_id &&
+ me.cur_options == lib::option_install_runtime))
{
if (header_source (p))
pt = nullptr;
@@ -358,7 +671,7 @@ namespace build2
}
if (pt == nullptr)
- return pt;
+ return make_pair (pt, options);
}
bool g (false);
@@ -374,16 +687,17 @@ namespace build2
{
pt = t.is_a<libue> ()
? nullptr
- : file_rule::instance.filter (is, a, *pt, pm.prerequisite);
+ : file_rule::instance.filter (
+ is, a, *pt, pm.prerequisite, me).first;
break;
}
}
if (pt == nullptr)
- return pt;
+ return make_pair (pt, options);
}
- return pt;
+ return make_pair (pt, options);
}
bool libux_install_rule::
@@ -395,5 +709,81 @@ namespace build2
return link_.sub_match (x_link, update_id, a, t, me) &&
alias_rule::match (a, t);
}
+
+ recipe libux_install_rule::
+ apply (action a, target& t, match_extra& me) const
+ {
+ if (a.operation () != update_id)
+ {
+ if (!t.is_a<libue> ())
+ {
+ if (me.new_options == 0)
+ me.new_options = lib::option_install_runtime;
+
+ me.cur_options = me.new_options;
+ }
+ }
+
+ return alias_rule::apply_impl (
+ a, t, me, me.cur_options != match_extra::all_options /* reapply */);
+ }
+
+ void libux_install_rule::
+ apply_posthoc (action a, target& t, match_extra& me) const
+ {
+ if (a.operation () != update_id)
+ {
+ for (posthoc_prerequisite_target& p: *me.posthoc_prerequisite_targets)
+ {
+ if (p.target != nullptr && p.target->is_a<libs> ())
+ {
+ if (t.is_a<libue> ())
+ p.match_options = lib::option_install_runtime;
+ else
+ {
+ if (me.cur_options == lib::option_install_runtime)
+ p.match_options = lib::option_install_runtime;
+ }
+ }
+ }
+ }
+ }
+
+ void libux_install_rule::
+ reapply (action a, target& t, match_extra& me) const
+ {
+ tracer trace ("cc::linux_install_rule::reapply");
+
+ assert (a.operation () != update_id && !t.is_a<libue> ());
+
+ l6 ([&]{trace << "rematching " << t
+ << ", current options " << me.cur_options
+ << ", new options " << me.new_options;});
+
+ me.cur_options |= me.new_options;
+
+ if ((me.new_options & lib::option_install_buildtime) != 0)
+ {
+ for (const target* pt: t.prerequisite_targets[a])
+ {
+ if (pt != nullptr && (pt->is_a<liba> () || pt->is_a<libs> () ||
+ pt->is_a<libua> () || pt->is_a<libus> ()))
+ rematch_sync (a, *pt, match_extra::all_options);
+ }
+
+ if (me.posthoc_prerequisite_targets != nullptr)
+ {
+ for (posthoc_prerequisite_target& p: *me.posthoc_prerequisite_targets)
+ {
+ if (p.target != nullptr && p.target->is_a<libs> ())
+ {
+ p.match_options = match_extra::all_options;
+ }
+ }
+ }
+
+ alias_rule::reapply_impl (a, t, me);
+ }
+ }
}
}
diff --git a/libbuild2/cc/install-rule.hxx b/libbuild2/cc/install-rule.hxx
index 6998d63..771c33b 100644
--- a/libbuild2/cc/install-rule.hxx
+++ b/libbuild2/cc/install-rule.hxx
@@ -20,7 +20,7 @@ namespace build2
{
class link_rule;
- // Installation rule for exe{} and lib*{}. Here we do:
+ // Installation rule for exe{} and lib[as]{}. Here we do:
//
// 1. Signal to the link rule that this is update for install.
//
@@ -28,17 +28,23 @@ namespace build2
//
// 3. Extra un/installation (e.g., libs{} symlinks).
//
+ // 4. Handling runtime/buildtime match options for lib[as]{}.
+ //
class LIBBUILD2_CC_SYMEXPORT install_rule: public install::file_rule,
virtual common
{
public:
install_rule (data&&, const link_rule&);
- virtual const target*
+ virtual bool
+ filter (action, const target&, const target&) const override;
+
+ virtual pair<const target*, uint64_t>
filter (const scope*,
- action, const target&, prerequisite_iterator&) const override;
+ action, const target&, prerequisite_iterator&,
+ match_extra&) const override;
- // Note: rule::match() override.
+ // Note: rule::match() override (with hint and match_extra).
//
virtual bool
match (action, target&, const string&, match_extra&) const override;
@@ -46,7 +52,13 @@ namespace build2
using file_rule::match; // Make Clang happy.
virtual recipe
- apply (action, target&) const override;
+ apply (action, target&, match_extra&) const override;
+
+ virtual void
+ apply_posthoc (action, target&, match_extra&) const override;
+
+ virtual void
+ reapply (action, target&, match_extra&) const override;
virtual bool
install_extra (const file&, const install_dir&) const override;
@@ -58,22 +70,24 @@ namespace build2
const link_rule& link_;
};
- // Installation rule for libu*{}.
+ // Installation rule for libu[eas]{}.
//
// While libu*{} members themselves are not installable, we need to see
// through them in case they depend on stuff that we need to install
// (e.g., headers). Note that we use the alias_rule as a base.
//
- class LIBBUILD2_CC_SYMEXPORT libux_install_rule:
- public install::alias_rule,
- virtual common
+ class LIBBUILD2_CC_SYMEXPORT libux_install_rule: public install::alias_rule,
+ virtual common
{
public:
libux_install_rule (data&&, const link_rule&);
- virtual const target*
+ // Note: utility libraries currently have no ad hoc members.
+
+ virtual pair<const target*, uint64_t>
filter (const scope*,
- action, const target&, prerequisite_iterator&) const override;
+ action, const target&, prerequisite_iterator&,
+ match_extra&) const override;
// Note: rule::match() override.
//
@@ -82,6 +96,15 @@ namespace build2
using alias_rule::match; // Make Clang happy.
+ virtual recipe
+ apply (action, target&, match_extra&) const override;
+
+ virtual void
+ apply_posthoc (action, target&, match_extra&) const override;
+
+ virtual void
+ reapply (action, target&, match_extra&) const override;
+
private:
const link_rule& link_;
};
diff --git a/libbuild2/cc/lexer+comment.test.testscript b/libbuild2/cc/lexer+comment.test.testscript
index 358865c..381e479 100644
--- a/libbuild2/cc/lexer+comment.test.testscript
+++ b/libbuild2/cc/lexer+comment.test.testscript
@@ -16,6 +16,11 @@ four
/**
six /*
*/
+/* */
+/*
+
+*/
+/**/
EOI
: cxx-comment
diff --git a/libbuild2/cc/lexer+raw-string-literal.test.testscript b/libbuild2/cc/lexer+raw-string-literal.test.testscript
index bca489a..a6455eb 100644
--- a/libbuild2/cc/lexer+raw-string-literal.test.testscript
+++ b/libbuild2/cc/lexer+raw-string-literal.test.testscript
@@ -16,6 +16,7 @@ R"X(a
b)X"
R"X(a\
b)X"
+R""(a)""
EOI
<string literal>
<string literal>
@@ -24,6 +25,7 @@ EOI
<string literal>
<string literal>
<string literal>
+<string literal>
EOO
: prefix
diff --git a/libbuild2/cc/lexer.cxx b/libbuild2/cc/lexer.cxx
index beeb970..d20e0dc 100644
--- a/libbuild2/cc/lexer.cxx
+++ b/libbuild2/cc/lexer.cxx
@@ -214,7 +214,7 @@ namespace build2
// #line <integer> [<string literal>] ...
// # <integer> [<string literal>] ...
//
- // Also diagnose #include while at it.
+ // Also diagnose #include while at it if preprocessed.
//
if (!(c >= '0' && c <= '9'))
{
@@ -222,10 +222,13 @@ namespace build2
if (t.type == type::identifier)
{
- if (t.value == "include")
- fail (l) << "unexpected #include directive";
- else if (t.value != "line")
+ if (t.value != "line")
+ {
+ if (preprocessed_ && t.value == "include")
+ fail (l) << "unexpected #include directive";
+
continue;
+ }
}
else
continue;
@@ -734,8 +737,8 @@ namespace build2
// R"<delimiter>(<raw_characters>)<delimiter>"
//
// Where <delimiter> is a potentially-empty character sequence made of
- // any source character but parentheses, backslash and spaces. It can be
- // at most 16 characters long.
+ // any source character but parentheses, backslash, and spaces (in
+ // particular, it can be `"`). It can be at most 16 characters long.
//
// Note that the <raw_characters> are not processed in any way, not even
// for line continuations.
@@ -750,7 +753,7 @@ namespace build2
{
c = geth ();
- if (eos (c) || c == '\"' || c == ')' || c == '\\' || c == ' ')
+ if (eos (c) || c == ')' || c == '\\' || c == ' ')
fail (l) << "invalid raw string literal";
if (c == '(')
@@ -1108,21 +1111,18 @@ namespace build2
if (eos (c))
fail (p) << "unterminated comment";
- if (c == '*' && (c = peek ()) == '/')
+ if (c == '*')
{
- get (c);
- break;
+ if ((c = peek ()) == '/')
+ {
+ get (c);
+ break;
+ }
}
-
- if (c != '*' && c != '\\')
+ else
{
// Direct buffer scan.
//
- // Note that we should call get() prior to the direct buffer
- // scan (see butl::char_scanner for details).
- //
- get (c);
-
const char* b (gptr_);
const char* e (egptr_);
const char* p (b);
diff --git a/libbuild2/cc/lexer.hxx b/libbuild2/cc/lexer.hxx
index 81e0d97..17d706b 100644
--- a/libbuild2/cc/lexer.hxx
+++ b/libbuild2/cc/lexer.hxx
@@ -12,6 +12,8 @@
#include <libbuild2/diagnostics.hxx>
+#include <libbuild2/cc/export.hxx>
+
namespace build2
{
namespace cc
@@ -20,13 +22,15 @@ namespace build2
// sequence of tokens returned is similar to what a real C/C++ compiler
// would see from its preprocessor.
//
- // The input is a (partially-)preprocessed translation unit that may still
- // contain comments, line continuations, and preprocessor directives such
- // as #line, #pragma, but not #include (which is diagnosed). Currently,
- // all preprocessor directives except #line are ignored and no values are
- // saved from literals. The #line directive (and its shorthand notation)
- // is recognized to provide the logical token location. Note that the
- // modules-related pseudo-directives are not recognized or handled.
+ // The input is a potentially (partially-)preprocessed translation unit
+ // that may still contain comments, line continuations, and preprocessor
+ // directives such as #line and #pragma. If the input is said to be
+ // (partially-)preprocessed then #include directives are diagnosed.
+ // Currently, all preprocessor directives except #line are ignored and no
+ // values are saved from literals. The #line directive (and its shorthand
+ // notation) is recognized to provide the logical token location. Note
+ // that the modules-related pseudo-directives are not recognized or
+ // handled.
//
// While at it we also calculate the checksum of the input ignoring
// comments, whitespaces, etc. This is used to detect changes that do not
@@ -80,15 +84,19 @@ namespace build2
// Output the token value in a format suitable for diagnostics.
//
- ostream&
+ LIBBUILD2_CC_SYMEXPORT ostream&
operator<< (ostream&, const token&);
- class lexer: protected butl::char_scanner<>
+ class LIBBUILD2_CC_SYMEXPORT lexer: protected butl::char_scanner<>
{
public:
- lexer (ifdstream& is, const path_name& name)
+ // If preprocessed is true, then assume the input is at least partially
+ // preprocessed and therefore should not contain #include directives.
+ //
+ lexer (ifdstream& is, const path_name& name, bool preprocessed)
: char_scanner (is, false /* crlf */),
name_ (name),
+ preprocessed_ (preprocessed),
fail ("error", &name_),
log_file_ (name)
{
@@ -173,6 +181,8 @@ namespace build2
private:
const path_name& name_;
+ bool preprocessed_;
+
const fail_mark fail;
// Logical file and line as set by the #line directives. Note that the
diff --git a/libbuild2/cc/lexer.test.cxx b/libbuild2/cc/lexer.test.cxx
index 39e4279..82163fe 100644
--- a/libbuild2/cc/lexer.test.cxx
+++ b/libbuild2/cc/lexer.test.cxx
@@ -65,7 +65,7 @@ namespace build2
is.open (fddup (stdin_fd ()));
}
- lexer l (is, in);
+ lexer l (is, in, true /* preprocessed */);
// No use printing eos since we will either get it or loop forever.
//
diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx
index 4588ce1..08a60b9 100644
--- a/libbuild2/cc/link-rule.cxx
+++ b/libbuild2/cc/link-rule.cxx
@@ -20,6 +20,8 @@
#include <libbuild2/bin/target.hxx>
#include <libbuild2/bin/utility.hxx>
+#include <libbuild2/install/utility.hxx>
+
#include <libbuild2/cc/target.hxx> // c, pc*
#include <libbuild2/cc/utility.hxx>
@@ -94,7 +96,7 @@ namespace build2
return false;
}
- if (const target* t = search_existing (n, bs, dir_path () /* out */))
+ if (const target* t = search_existing (n, bs))
{
// The same logic as in process_libraries().
//
@@ -290,13 +292,14 @@ namespace build2
if (p.is_a (x_src) ||
(x_mod != nullptr && p.is_a (*x_mod)) ||
+ (x_asp != nullptr && p.is_a (*x_asp)) ||
(x_obj != nullptr && p.is_a (*x_obj)) ||
// Header-only X library (or library with C source and X header).
(library && x_header (p, false /* c_hdr */)))
{
r.seen_x = true;
}
- else if (p.is_a<c> () ||
+ else if (p.is_a<c> () || p.is_a<S> () ||
(x_obj != nullptr && p.is_a<m> ()) ||
// Header-only C library.
(library && p.is_a<h> ()))
@@ -433,9 +436,12 @@ namespace build2
r.seen_lib = true;
}
// Some other c-common header/source (say C++ in a C rule) other than
- // a C header (we assume everyone can hanle that).
+ // a C header (we assume everyone can hanle that) or some other
+ // #include'able target.
//
- else if (p.is_a<cc> () && !(x_header (p, true /* c_hdr */)))
+ else if (p.is_a<cc> () &&
+ !(x_header (p, true /* c_hdr */)) &&
+ !p.is_a (x_inc) && !p.is_a<c_inc> ())
{
r.seen_cc = true;
break;
@@ -842,6 +848,9 @@ namespace build2
// If not, then we may need the same in recursive-binless logic.
//
#if 0
+ // @@ TMP hm, this hasn't actually been enabled. So may actually
+ // enable and see if it trips up (do git-blame for good measure).
+ //
assert (false); // @@ TMP (remove before 0.16.0 release)
#endif
ux = &link_member (*ul, a, li)->as<libux> ();
@@ -903,7 +912,7 @@ namespace build2
// for binless libraries since there could be other output (e.g., .pc
// files).
//
- inject_fsdir (a, t);
+ const fsdir* dir (inject_fsdir (a, t));
// Process prerequisites, pass 1: search and match prerequisite
// libraries, search obj/bmi{} targets, and search targets we do rule
@@ -999,7 +1008,7 @@ namespace build2
//
#if 1
if (!um)
- um = (p.is_a (x_src) || p.is_a<c> () ||
+ um = (p.is_a (x_src) || p.is_a<c> () || p.is_a<S> () ||
(x_mod != nullptr && p.is_a (*x_mod)) ||
(x_obj != nullptr && (p.is_a (*x_obj) || p.is_a<m> ())) ||
x_header (p, true));
@@ -1030,8 +1039,8 @@ namespace build2
bool mod (x_mod != nullptr && p.is_a (*x_mod));
bool hdr (false);
- if (mod ||
- p.is_a (x_src) || p.is_a<c> () ||
+ if (mod ||
+ p.is_a (x_src) || p.is_a<c> () || p.is_a<S> () ||
(x_obj != nullptr && (p.is_a (*x_obj) || p.is_a<m> ())))
{
binless = binless && (mod ? user_binless : false);
@@ -1192,6 +1201,12 @@ namespace build2
}
pt = &p.search (t);
+
+ if (pt == dir)
+ {
+ pt = nullptr;
+ continue;
+ }
}
if (skip (*pt))
@@ -1686,7 +1701,8 @@ namespace build2
fsdir::static_type,
path_cast<dir_path> (t.path () + ".dlls"),
t.out,
- string () /* name */));
+ string () /* name */,
+ nullopt /* ext */));
// By default our backlinking logic will try to symlink the
// directory and it can even be done on Windows using junctions.
@@ -1900,7 +1916,7 @@ namespace build2
//
if (mod
? p1.is_a (*x_mod)
- : (p1.is_a (x_src) || p1.is_a<c> () ||
+ : (p1.is_a (x_src) || p1.is_a<c> () || p1.is_a<S> () ||
(x_obj != nullptr && (p1.is_a (*x_obj) || p1.is_a<m> ()))))
{
src = true;
@@ -1914,10 +1930,11 @@ namespace build2
p1.is_a<libx> () ||
p1.is_a<liba> () || p1.is_a<libs> () || p1.is_a<libux> () ||
p1.is_a<bmi> () || p1.is_a<bmix> () ||
- ((mod ||
- p.is_a (x_src) ||
+ ((mod ||
+ p.is_a (x_src) ||
+ (x_asp != nullptr && p.is_a (*x_asp)) ||
(x_obj != nullptr && p.is_a (*x_obj))) && x_header (p1)) ||
- ((p.is_a<c> () ||
+ ((p.is_a<c> () || p.is_a<S> () ||
(x_obj != nullptr && p.is_a<m> ())) && p1.is_a<h> ()))
continue;
@@ -1931,7 +1948,7 @@ namespace build2
if (!src)
fail << "synthesized dependency for prerequisite " << p
<< " would be incompatible with existing target " << *pt <<
- info << "no existing c/" << x_lang << " source prerequisite" <<
+ info << "no existing C/" << x_lang << " source prerequisite" <<
info << "specify corresponding " << rtt.name << "{} "
<< "dependency explicitly";
@@ -2060,7 +2077,7 @@ namespace build2
{
if (mod
? p1.is_a (*x_mod)
- : (p1.is_a (x_src) || p1.is_a<c> () ||
+ : (p1.is_a (x_src) || p1.is_a<c> () || p1.is_a<S> () ||
(x_obj != nullptr && (p1.is_a (*x_obj) || p1.is_a<m> ()))))
{
// Searching our own prerequisite is ok, p1 must already be
@@ -2244,17 +2261,47 @@ namespace build2
*type != "cc" &&
type->compare (0, 3, "cc,") != 0)
{
- auto& md (l->data<link_rule::match_data> (d.a));
- assert (md.for_install); // Must have been executed.
+ auto* md (l->try_data<link_rule::match_data> (d.a));
+
+ if (md == nullptr)
+ fail << "library " << *l << " is not built with cc module-based "
+ << "link rule" <<
+ info << "mark it as generic with cc.type=cc target-specific "
+ << "variable";
+
+ assert (md->for_install); // Must have been executed.
// The user will get the target name from the context info.
//
- if (*md.for_install != *d.for_install)
+ if (*md->for_install != *d.for_install)
fail << "incompatible " << *l << " build" <<
- info << "library is built " << (*md.for_install ? "" : "not ")
+ info << "library is built " << (*md->for_install ? "" : "not ")
<< "for install";
}
+ auto newer = [&d, l] ()
+ {
+ // @@ Work around the unexecuted member for installed libraries
+ // issue (see search_library() for details).
+ //
+ // Note that the member may not even be matched, let alone
+ // executed, so we have to go through the group to detect this
+ // case (if the group is not matched, then the member got to be).
+ //
+#if 0
+ return l->newer (d.mt);
+#else
+ const target* g (l->group);
+ target_state s (g != nullptr &&
+ g->matched (d.a, memory_order_acquire) &&
+ g->state[d.a].rule == &file_rule::rule_match
+ ? target_state::unchanged
+ : l->executed_state (d.a));
+
+ return l->newer (d.mt, s);
+#endif
+ };
+
if (d.li.type == otype::a)
{
// Linking a utility library to a static library.
@@ -2282,7 +2329,7 @@ namespace build2
// Check if this library renders us out of date.
//
if (d.update != nullptr)
- *d.update = *d.update || l->newer (d.mt);
+ *d.update = *d.update || newer ();
for (const target* pt: l->prerequisite_targets[d.a])
{
@@ -2321,7 +2368,7 @@ namespace build2
// Check if this library renders us out of date.
//
if (d.update != nullptr)
- *d.update = *d.update || l->newer (d.mt);
+ *d.update = *d.update || newer ();
// On Windows a shared library is a DLL with the import library as
// an ad hoc group member. MinGW though can link directly to DLLs
@@ -2817,7 +2864,7 @@ namespace build2
// (Re)generate pkg-config's .pc file. While the target itself might be
// up-to-date from a previous run, there is no guarantee that .pc exists
// or also up-to-date. So to keep things simple we just regenerate it
- // unconditionally (and avoid doing so on uninstall; see pkconfig_save()
+ // unconditionally (and avoid doing so on uninstall; see pkgconfig_save()
// for details).
//
// Also, if you are wondering why don't we just always produce this .pc,
@@ -2827,7 +2874,7 @@ namespace build2
// There is a further complication: we may have no intention of
// installing the library but still need to update it for install (see
// install_scope() for background). In which case we may still not have
- // the installation directories. We handle this in pkconfig_save() by
+ // the installation directories. We handle this in pkgconfig_save() by
// skipping the generation of .pc files (and letting the install rule
// complain if we do end up trying to install them).
//
@@ -3264,10 +3311,72 @@ namespace build2
rpath_libraries (sargs, bs, a, t, li, for_install /* link */);
lookup l;
-
if ((l = t["bin.rpath"]) && !l->empty ())
+ {
+ // See if we need to make the specified paths relative using the
+ // $ORIGIN (Linux, BSD) or @loader_path (Mac OS) mechanisms.
+ //
+ optional<dir_path> origin;
+ if (for_install && cast_false<bool> (rs["install.relocatable"]))
+ {
+ // Note that both $ORIGIN and @loader_path will be expanded to
+ // the path of the binary that we are building (executable or
+ // shared library) as opposed to top-level executable.
+ //
+ path p (install::resolve_file (t));
+
+ // If the file is not installable then the install.relocatable
+ // semantics does not apply, naturally.
+ //
+ if (!p.empty ())
+ origin = p.directory ();
+ }
+
+ bool origin_used (false);
for (const dir_path& p: cast<dir_paths> (l))
- sargs.push_back ("-Wl,-rpath," + p.string ());
+ {
+ string o ("-Wl,-rpath,");
+
+ // Note that we only rewrite absolute paths so if the user
+ // specified $ORIGIN or @loader_path manually, we will pass it
+ // through as is.
+ //
+ if (origin && p.absolute ())
+ {
+ dir_path l;
+ try
+ {
+ l = p.relative (*origin);
+ }
+ catch (const invalid_path&)
+ {
+ fail << "unable to make rpath " << p << " relative to "
+ << *origin <<
+ info << "required for relocatable installation";
+ }
+
+ o += (tclass == "macos" ? "@loader_path" : "$ORIGIN");
+
+ if (!l.empty ())
+ {
+ o += path_traits::directory_separator;
+ o += l.string ();
+ }
+
+ origin_used = true;
+ }
+ else
+ o += p.string ();
+
+ sargs.push_back (move (o));
+ }
+
+ // According to the Internet, `-Wl,-z,origin` is not needed except
+ // potentially for older BSDs.
+ //
+ if (origin_used && tclass == "bsd")
+ sargs.push_back ("-Wl,-z,origin");
+ }
if ((l = t["bin.rpath_link"]) && !l->empty ())
{
@@ -3301,25 +3410,24 @@ namespace build2
// Extra system library dirs (last).
//
- assert (sys_lib_dirs_extra <= sys_lib_dirs.size ());
+ assert (sys_lib_dirs_mode + sys_lib_dirs_extra <= sys_lib_dirs.size ());
+
+ // Note that the mode options are added as part of cmode.
+ //
+ auto b (sys_lib_dirs.begin () + sys_lib_dirs_mode);
+ auto x (b + sys_lib_dirs_extra);
if (tsys == "win32-msvc")
{
// If we have no LIB environment variable set, then we add all of
// them. But we want extras to come first.
//
- // Note that the mode options are added as part of cmode.
- //
- auto b (sys_lib_dirs.begin () + sys_lib_dirs_mode);
- auto m (sys_lib_dirs.begin () + sys_lib_dirs_extra);
- auto e (sys_lib_dirs.end ());
-
- for (auto i (m); i != e; ++i)
+ for (auto i (b); i != x; ++i)
sargs1.push_back ("/LIBPATH:" + i->string ());
if (!getenv ("LIB"))
{
- for (auto i (b); i != m; ++i)
+ for (auto i (x), e (sys_lib_dirs.end ()); i != e; ++i)
sargs1.push_back ("/LIBPATH:" + i->string ());
}
@@ -3330,7 +3438,7 @@ namespace build2
append_option_values (
args,
"-L",
- sys_lib_dirs.begin () + sys_lib_dirs_extra, sys_lib_dirs.end (),
+ b, x,
[] (const dir_path& d) {return d.string ().c_str ();});
}
}
@@ -3426,7 +3534,7 @@ namespace build2
&cs, &update, mt,
bs, a, *f, la, p.data, li,
for_install, true, true, &lc);
- f = nullptr; // Timestamp checked by hash_libraries().
+ f = nullptr; // Timestamp checked by append_libraries().
}
else
{
@@ -3687,6 +3795,8 @@ namespace build2
{
ld = &cpath;
+ append_diag_color_options (args);
+
// Add the option that triggers building a shared library and
// take care of any extras (e.g., import library).
//
@@ -3859,6 +3969,14 @@ namespace build2
try_rmfile (relt, true);
}
+ // We have no choice but to serialize early if we want the command line
+ // printed shortly before actually executing the linker. Failed that, it
+ // may look like we are still executing in parallel.
+ //
+ scheduler::alloc_guard jobs_ag;
+ if (!ctx.dry_run && cast_false<bool> (t[c_serialize]))
+ jobs_ag = scheduler::alloc_guard (*ctx.sched, phase_unlock (nullptr));
+
if (verb == 1)
print_diag (lt.static_library () ? "ar" : "ld", t);
else if (verb == 2)
@@ -3879,10 +3997,15 @@ namespace build2
//
// Note that we are not going to bother with oargs for this.
//
+ // Note also that we now have scheduler::serialize() which allows us to
+ // block until full parallelism is available (this mode can currently
+ // be forced with cc.serialize=true; maybe we should invent something
+ // like config.cc.link_serialize or some such which can be used when
+ // LTO is enabled).
+ //
string jobs_arg;
- scheduler::alloc_guard jobs_extra;
- if (!lt.static_library ())
+ if (!ctx.dry_run && !lt.static_library ())
{
switch (ctype)
{
@@ -3898,8 +4021,10 @@ namespace build2
auto i (find_option_prefix ("-flto", args.rbegin (), args.rend ()));
if (i != args.rend () && strcmp (*i, "-flto=auto") == 0)
{
- jobs_extra = scheduler::alloc_guard (ctx.sched, 0);
- jobs_arg = "-flto=" + to_string (1 + jobs_extra.n);
+ if (jobs_ag.n == 0) // Might already have (see above).
+ jobs_ag = scheduler::alloc_guard (*ctx.sched, 0);
+
+ jobs_arg = "-flto=" + to_string (1 + jobs_ag.n);
*i = jobs_arg.c_str ();
}
break;
@@ -3917,8 +4042,10 @@ namespace build2
strcmp (*i, "-flto=thin") == 0 &&
!find_option_prefix ("-flto-jobs=", args))
{
- jobs_extra = scheduler::alloc_guard (ctx.sched, 0);
- jobs_arg = "-flto-jobs=" + to_string (1 + jobs_extra.n);
+ if (jobs_ag.n == 0) // Might already have (see above).
+ jobs_ag = scheduler::alloc_guard (*ctx.sched, 0);
+
+ jobs_arg = "-flto-jobs=" + to_string (1 + jobs_ag.n);
args.insert (i.base (), jobs_arg.c_str ()); // After -flto=thin.
}
break;
@@ -4090,8 +4217,6 @@ namespace build2
if (!e)
throw failed ();
}
-
- jobs_extra.deallocate ();
}
catch (const process_error& e)
{
@@ -4171,6 +4296,8 @@ namespace build2
}
}
+ jobs_ag.deallocate ();
+
// For Windows generate (or clean up) rpath-emulating assembly.
//
if (tclass == "windows")
diff --git a/libbuild2/cc/module.cxx b/libbuild2/cc/module.cxx
index aa9a526..cf6c6e4 100644
--- a/libbuild2/cc/module.cxx
+++ b/libbuild2/cc/module.cxx
@@ -11,10 +11,7 @@
#include <libbuild2/bin/target.hxx>
-#include <libbuild2/cc/target.hxx> // pc*
-
#include <libbuild2/config/utility.hxx>
-#include <libbuild2/install/utility.hxx>
#include <libbuild2/cc/guess.hxx>
@@ -60,7 +57,7 @@ namespace build2
// config.x
//
- strings mode;
+ strings omode; // Original mode.
{
// Normally we will have a persistent configuration and computing the
// default value every time will be a waste. So try without a default
@@ -144,19 +141,31 @@ namespace build2
fail << "invalid path '" << s << "' in " << config_x;
}
- mode.assign (++v.begin (), v.end ());
+ omode.assign (++v.begin (), v.end ());
// Save original path/mode in *.config.path/mode.
//
rs.assign (x_c_path) = xc;
- rs.assign (x_c_mode) = mode;
+ rs.assign (x_c_mode) = omode;
+
+ // Merge the configured mode options into user-specified (which must
+ // be done before loading the *.guess module).
+ //
+ // In particular, this ability to specify the compiler mode in a
+ // buildfile is useful in embedded development where the project may
+ // need to hardcode things like -target, -nostdinc, etc.
+ //
+ const strings& mode (cast<strings> (rs.assign (x_mode) += omode));
// Figure out which compiler we are dealing with, its target, etc.
//
// Note that we could allow guess() to modify mode to support
// imaginary options (such as /MACHINE for cl.exe). Though it's not
// clear what cc.mode would contain (original or modified). Note that
- // we are now folding *.std options into mode options.
+ // we are now adding *.std options into mode options.
+ //
+ // @@ But can't the language standard options alter things like search
+ // directories?
//
x_info = &build2::cc::guess (
ctx,
@@ -225,9 +234,10 @@ namespace build2
// Assign values to variables that describe the compiler.
//
+ // Note: x_mode is dealt with above.
+ //
rs.assign (x_path) = process_path_ex (
xi.path, x_name, xi.checksum, env_checksum);
- const strings& xm (cast<strings> (rs.assign (x_mode) = move (mode)));
rs.assign (x_id) = xi.id.string ();
rs.assign (x_id_type) = to_string (xi.id.type);
@@ -285,8 +295,8 @@ namespace build2
if (!xi.pattern.empty ())
h.assign ("config.cc.pattern") = xi.pattern;
- if (!xm.empty ())
- h.assign ("config.cc.mode") = xm;
+ if (!omode.empty ())
+ h.assign ("config.cc.mode") = move (omode);
h.assign (c_runtime) = xi.runtime;
h.assign (c_stdlib) = xi.c_stdlib;
@@ -357,6 +367,8 @@ namespace build2
# ifdef __APPLE__
static const dir_path a_usr_inc (
"/Library/Developer/CommandLineTools/SDKs/MacOSX*.sdk/usr/include");
+ static const dir_path a_usr_lib (
+ "/Library/Developer/CommandLineTools/SDKs/MacOSX*.sdk/usr/lib");
# endif
#endif
@@ -611,10 +623,10 @@ namespace build2
switch (xi.class_)
{
case compiler_class::gcc:
- lib_dirs = gcc_library_search_dirs (xi.path, rs);
+ lib_dirs = gcc_library_search_dirs (xi, rs);
break;
case compiler_class::msvc:
- lib_dirs = msvc_library_search_dirs (xi.path, rs);
+ lib_dirs = msvc_library_search_dirs (xi, rs);
break;
}
}
@@ -628,10 +640,10 @@ namespace build2
switch (xi.class_)
{
case compiler_class::gcc:
- hdr_dirs = gcc_header_search_dirs (xi.path, rs);
+ hdr_dirs = gcc_header_search_dirs (xi, rs);
break;
case compiler_class::msvc:
- hdr_dirs = msvc_header_search_dirs (xi.path, rs);
+ hdr_dirs = msvc_header_search_dirs (xi, rs);
break;
}
}
@@ -649,8 +661,8 @@ namespace build2
sys_hdr_dirs_mode = hdr_dirs.second;
sys_mod_dirs_mode = mod_dirs ? mod_dirs->second : 0;
- sys_lib_dirs_extra = lib_dirs.first.size ();
- sys_hdr_dirs_extra = hdr_dirs.first.size ();
+ sys_lib_dirs_extra = 0;
+ sys_hdr_dirs_extra = 0;
#ifndef _WIN32
// Add /usr/local/{include,lib}. We definitely shouldn't do this if we
@@ -666,11 +678,11 @@ namespace build2
// on the next invocation.
//
{
- auto& is (hdr_dirs.first);
+ auto& hs (hdr_dirs.first);
auto& ls (lib_dirs.first);
- bool ui (find (is.begin (), is.end (), usr_inc) != is.end ());
- bool uli (find (is.begin (), is.end (), usr_loc_inc) != is.end ());
+ bool ui (find (hs.begin (), hs.end (), usr_inc) != hs.end ());
+ bool uli (find (hs.begin (), hs.end (), usr_loc_inc) != hs.end ());
#ifdef __APPLE__
// On Mac OS starting from 10.14 there is no longer /usr/include.
@@ -693,15 +705,28 @@ namespace build2
//
// Is Apple's /usr/include.
//
- if (!ui && !uli)
+ // Also, it appears neither Clang nor GCC report MacOSX*.sdk/usr/lib
+ // with -print-search-dirs but they do search in there. So we add it
+ // to our list if we see MacOSX*.sdk/usr/include.
+ //
+ auto aui (find_if (hs.begin (), hs.end (),
+ [] (const dir_path& d)
+ {
+ return path_match (d, a_usr_inc);
+ }));
+
+ if (aui != hs.end ())
{
- for (const dir_path& d: is)
+ if (!ui)
+ ui = true;
+
+ if (find_if (ls.begin (), ls.end (),
+ [] (const dir_path& d)
+ {
+ return path_match (d, a_usr_lib);
+ }) == ls.end ())
{
- if (path_match (d, a_usr_inc))
- {
- ui = true;
- break;
- }
+ ls.push_back (aui->directory () /= "lib");
}
}
#endif
@@ -709,18 +734,29 @@ namespace build2
{
bool ull (find (ls.begin (), ls.end (), usr_loc_lib) != ls.end ());
- // Many platforms don't search in /usr/local/lib by default (but do
- // for headers in /usr/local/include). So add it as the last option.
+ // Many platforms don't search in /usr/local/lib by default but do
+ // for headers in /usr/local/include.
+ //
+ // Note that customarily /usr/local/include is searched before
+ // /usr/include so we add /usr/local/lib before built-in entries
+ // (there isn't really a way to add it after since all we can do is
+ // specify it with -L).
//
if (!ull && exists (usr_loc_lib, true /* ignore_error */))
- ls.push_back (usr_loc_lib);
+ {
+ ls.insert (ls.begin () + sys_lib_dirs_mode, usr_loc_lib);
+ ++sys_lib_dirs_extra;
+ }
// FreeBSD is at least consistent: it searches in neither. Quoting
// its wiki: "FreeBSD can't even find libraries that it installed."
// So let's help it a bit.
//
if (!uli && exists (usr_loc_inc, true /* ignore_error */))
- is.push_back (usr_loc_inc);
+ {
+ hs.insert (hs.begin () + sys_hdr_dirs_mode, usr_loc_inc);
+ ++sys_hdr_dirs_extra;
+ }
}
}
#endif
@@ -824,8 +860,11 @@ namespace build2
dr << "\n hdr dirs";
for (size_t i (0); i != incs.size (); ++i)
{
- if (i == sys_hdr_dirs_extra)
+ if ((sys_hdr_dirs_mode != 0 && i == sys_hdr_dirs_mode) ||
+ (sys_hdr_dirs_extra != 0 &&
+ i == sys_hdr_dirs_extra + sys_hdr_dirs_mode))
dr << "\n --";
+
dr << "\n " << incs[i];
}
}
@@ -835,8 +874,11 @@ namespace build2
dr << "\n lib dirs";
for (size_t i (0); i != libs.size (); ++i)
{
- if (i == sys_lib_dirs_extra)
+ if ((sys_lib_dirs_mode != 0 && i == sys_lib_dirs_mode) ||
+ (sys_lib_dirs_extra != 0 &&
+ i == sys_lib_dirs_extra + sys_lib_dirs_mode))
dr << "\n --";
+
dr << "\n " << libs[i];
}
}
@@ -957,43 +999,7 @@ namespace build2
// Register target types and configure their "installability".
//
- bool install_loaded (cast_false<bool> (rs["install.loaded"]));
-
- {
- using namespace install;
-
- // Note: not registering x_obj (it's registered seperately by the
- // x.objx module).
- //
- rs.insert_target_type (x_src);
-
- auto insert_hdr = [&rs, install_loaded] (const target_type& tt)
- {
- rs.insert_target_type (tt);
-
- // Install headers into install.include.
- //
- if (install_loaded)
- install_path (rs, tt, dir_path ("include"));
- };
-
- // Note: module (x_mod) is in x_hdr.
- //
- for (const target_type* const* ht (x_hdr); *ht != nullptr; ++ht)
- insert_hdr (**ht);
-
- // Also register the C header for C-derived languages.
- //
- if (*x_hdr != &h::static_type)
- insert_hdr (h::static_type);
-
- rs.insert_target_type<pc> ();
- rs.insert_target_type<pca> ();
- rs.insert_target_type<pcs> ();
-
- if (install_loaded)
- install_path<pc> (rs, dir_path ("pkgconfig"));
- }
+ load_module (rs, rs, (string (x) += ".types"), loc);
// Register rules.
//
@@ -1091,8 +1097,11 @@ namespace build2
// them in case they depend on stuff that we need to install (see the
// install rule implementations for details).
//
- if (install_loaded)
+ if (cast_false<bool> (rs["install.loaded"]))
{
+ // Note: we rely quite heavily in these rule implementations that
+ // these are the only target types they are registered for.
+
const install_rule& ir (*this);
r.insert<exe> (perform_install_id, x_install, ir);
diff --git a/libbuild2/cc/module.hxx b/libbuild2/cc/module.hxx
index 2a8611b..4213516 100644
--- a/libbuild2/cc/module.hxx
+++ b/libbuild2/cc/module.hxx
@@ -17,6 +17,7 @@
#include <libbuild2/cc/compile-rule.hxx>
#include <libbuild2/cc/link-rule.hxx>
#include <libbuild2/cc/install-rule.hxx>
+#include <libbuild2/cc/predefs-rule.hxx>
#include <libbuild2/cc/export.hxx>
@@ -115,18 +116,18 @@ namespace build2
// Defined in gcc.cxx.
//
pair<dir_paths, size_t>
- gcc_header_search_dirs (const process_path&, scope&) const;
+ gcc_header_search_dirs (const compiler_info&, scope&) const;
pair<dir_paths, size_t>
- gcc_library_search_dirs (const process_path&, scope&) const;
+ gcc_library_search_dirs (const compiler_info&, scope&) const;
// Defined in msvc.cxx.
//
pair<dir_paths, size_t>
- msvc_header_search_dirs (const process_path&, scope&) const;
+ msvc_header_search_dirs (const compiler_info&, scope&) const;
pair<dir_paths, size_t>
- msvc_library_search_dirs (const process_path&, scope&) const;
+ msvc_library_search_dirs (const compiler_info&, scope&) const;
};
class LIBBUILD2_CC_SYMEXPORT module: public build2::module,
@@ -134,7 +135,8 @@ namespace build2
public link_rule,
public compile_rule,
public install_rule,
- public libux_install_rule
+ public libux_install_rule,
+ public predefs_rule
{
public:
explicit
@@ -143,7 +145,8 @@ namespace build2
link_rule (move (d)),
compile_rule (move (d), rs),
install_rule (move (d), *this),
- libux_install_rule (move (d), *this) {}
+ libux_install_rule (move (d), *this),
+ predefs_rule (move (d)) {}
void
init (scope&,
diff --git a/libbuild2/cc/msvc.cxx b/libbuild2/cc/msvc.cxx
index 8fcbb0b..d21969c 100644
--- a/libbuild2/cc/msvc.cxx
+++ b/libbuild2/cc/msvc.cxx
@@ -264,6 +264,13 @@ namespace build2
}
else
continue;
+
+ // Ignore relative paths. Or maybe we should warn?
+ //
+ if (d.relative ())
+ continue;
+
+ d.normalize ();
}
catch (const invalid_path& e)
{
@@ -271,10 +278,7 @@ namespace build2
<< o << "'";
}
- // Ignore relative paths. Or maybe we should warn?
- //
- if (!d.relative ())
- r.push_back (move (d));
+ r.push_back (move (d));
}
}
@@ -295,6 +299,13 @@ namespace build2
d = dir_path (o, 9, string::npos);
else
continue;
+
+ // Ignore relative paths. Or maybe we should warn?
+ //
+ if (d.relative ())
+ continue;
+
+ d.normalize ();
}
catch (const invalid_path& e)
{
@@ -302,10 +313,7 @@ namespace build2
<< o << "'";
}
- // Ignore relative paths. Or maybe we should warn?
- //
- if (!d.relative ())
- r.push_back (move (d));
+ r.push_back (move (d));
}
}
@@ -324,7 +332,7 @@ namespace build2
{
try
{
- r.push_back (dir_path (move (d)));
+ r.push_back (dir_path (move (d)).normalize ());
}
catch (const invalid_path&)
{
@@ -337,7 +345,7 @@ namespace build2
// Extract system header search paths from MSVC.
//
pair<dir_paths, size_t> config_module::
- msvc_header_search_dirs (const process_path&, scope& rs) const
+ msvc_header_search_dirs (const compiler_info&, scope& rs) const
{
// MSVC doesn't have any built-in paths and all of them either come from
// the INCLUDE environment variable or are specified explicitly on the
@@ -365,7 +373,7 @@ namespace build2
// Extract system library search paths from MSVC.
//
pair<dir_paths, size_t> config_module::
- msvc_library_search_dirs (const process_path&, scope& rs) const
+ msvc_library_search_dirs (const compiler_info&, scope& rs) const
{
// MSVC doesn't seem to have any built-in paths and all of them either
// come from the LIB environment variable or are specified explicitly on
@@ -390,9 +398,22 @@ namespace build2
// Inspect the file and determine if it is static or import library.
// Return otype::e if it is neither (which we quietly ignore).
//
+ static global_cache<otype> library_type_cache;
+
static otype
library_type (const process_path& ld, const path& l)
{
+ string key;
+ {
+ sha256 cs;
+ cs.append (ld.effect_string ());
+ cs.append (l.string ());
+ key = cs.string ();
+
+ if (const otype* r = library_type_cache.find (key))
+ return *r;
+ }
+
// The are several reasonably reliable methods to tell whether it is a
// static or import library. One is lib.exe /LIST -- if there aren't any
// .obj members, then it is most likely an import library (it can also
@@ -458,14 +479,11 @@ namespace build2
// libhello\hello.lib.obj
// hello-0.1.0-a.0.19700101000000.dll
//
- // Archive member name at 746: [...]hello.dll[/][ ]*
- // Archive member name at 8C70: [...]hello.lib.obj[/][ ]*
- //
size_t n (s.size ());
for (; n != 0 && s[n - 1] == ' '; --n) ; // Skip trailing spaces.
- if (n >= 7) // At least ": X.obj" or ": X.dll".
+ if (n >= 5) // At least "X.obj" or "X.dll".
{
n -= 4; // Beginning of extension.
@@ -500,23 +518,25 @@ namespace build2
return otype::e;
}
- if (obj && dll)
+ otype r;
+ if (obj != dll)
+ r = obj ? otype::a : otype::s;
+ else
{
- warn << l << " looks like hybrid static/import library, ignoring";
- return otype::e;
- }
+ if (obj && dll)
+ warn << l << " looks like hybrid static/import library, ignoring";
- if (!obj && !dll)
- {
- warn << l << " looks like empty static or import library, ignoring";
- return otype::e;
+ if (!obj && !dll)
+ warn << l << " looks like empty static or import library, ignoring";
+
+ r = otype::e;
}
- return obj ? otype::a : otype::s;
+ return library_type_cache.insert (move (key), r);
}
template <typename T>
- static T*
+ static pair<T*, bool>
msvc_search_library (const process_path& ld,
const dir_path& d,
const prerequisite_key& p,
@@ -562,20 +582,26 @@ namespace build2
//
timestamp mt (mtime (f));
- if (mt != timestamp_nonexistent && library_type (ld, f) == lt)
+ pair<T*, bool> r (nullptr, true);
+
+ if (mt != timestamp_nonexistent)
{
- // Enter the target.
- //
- T* t;
- common::insert_library (p.scope->ctx, t, name, d, ld, e, exist, trace);
- t->path_mtime (move (f), mt);
- return t;
+ if (library_type (ld, f) == lt)
+ {
+ // Enter the target.
+ //
+ common::insert_library (
+ p.scope->ctx, r.first, name, d, ld, e, exist, trace);
+ r.first->path_mtime (move (f), mt);
+ }
+ else
+ r.second = false; // Don't search for binless.
}
- return nullptr;
+ return r;
}
- liba* common::
+ pair<bin::liba*, bool> common::
msvc_search_static (const process_path& ld,
const dir_path& d,
const prerequisite_key& p,
@@ -583,14 +609,21 @@ namespace build2
{
tracer trace (x, "msvc_search_static");
- liba* r (nullptr);
+ liba* a (nullptr);
+ bool b (true);
- auto search = [&r, &ld, &d, &p, exist, &trace] (
+ auto search = [&a, &b, &ld, &d, &p, exist, &trace] (
const char* pf, const char* sf) -> bool
{
- r = msvc_search_library<liba> (
- ld, d, p, otype::a, pf, sf, exist, trace);
- return r != nullptr;
+ pair<liba*, bool> r (msvc_search_library<liba> (
+ ld, d, p, otype::a, pf, sf, exist, trace));
+
+ if (r.first != nullptr)
+ a = r.first;
+ else if (!r.second)
+ b = false;
+
+ return a != nullptr;
};
// Try:
@@ -603,10 +636,10 @@ namespace build2
search ("", "") ||
search ("lib", "") ||
search ("", "lib") ||
- search ("", "_static") ? r : nullptr;
+ search ("", "_static") ? make_pair (a, true) : make_pair (nullptr, b);
}
- libs* common::
+ pair<bin::libs*, bool> common::
msvc_search_shared (const process_path& ld,
const dir_path& d,
const prerequisite_key& pk,
@@ -617,12 +650,14 @@ namespace build2
assert (pk.scope != nullptr);
libs* s (nullptr);
+ bool b (true);
- auto search = [&s, &ld, &d, &pk, exist, &trace] (
+ auto search = [&s, &b, &ld, &d, &pk, exist, &trace] (
const char* pf, const char* sf) -> bool
{
- if (libi* i = msvc_search_library<libi> (
- ld, d, pk, otype::s, pf, sf, exist, trace))
+ pair<libi*, bool> r (msvc_search_library<libi> (
+ ld, d, pk, otype::s, pf, sf, exist, trace));
+ if (r.first != nullptr)
{
ulock l (
insert_library (
@@ -630,6 +665,8 @@ namespace build2
if (!exist)
{
+ libi* i (r.first);
+
if (l.owns_lock ())
{
s->adhoc_member = i; // We are first.
@@ -643,6 +680,8 @@ namespace build2
s->path_mtime (path (), i->mtime ());
}
}
+ else if (!r.second)
+ b = false;
return s != nullptr;
};
@@ -655,7 +694,7 @@ namespace build2
return
search ("", "") ||
search ("lib", "") ||
- search ("", "dll") ? s : nullptr;
+ search ("", "dll") ? make_pair (s, true) : make_pair (nullptr, b);
}
}
}
diff --git a/libbuild2/cc/parser.cxx b/libbuild2/cc/parser.cxx
index dc5093f..f62847e 100644
--- a/libbuild2/cc/parser.cxx
+++ b/libbuild2/cc/parser.cxx
@@ -15,9 +15,11 @@ namespace build2
using type = token_type;
void parser::
- parse (ifdstream& is, const path_name& in, unit& u)
+ parse (ifdstream& is, const path_name& in, unit& u, const compiler_id& cid)
{
- lexer l (is, in);
+ cid_ = &cid;
+
+ lexer l (is, in, true /* preprocessed */);
l_ = &l;
u_ = &u;
@@ -82,6 +84,12 @@ namespace build2
// to call it __import) or it can have a special attribute (GCC
// currently marks it with [[__translated]]).
//
+ // Similarly, MSVC drops the `module;` marker and replaces all
+ // other `module` keywords with `__preprocessed_module`.
+ //
+ // Clang doesn't appear to rewrite anything, at least as of
+ // version 18.
+ //
if (bb == 0 && t.first)
{
const string& id (t.value); // Note: tracks t.
@@ -102,7 +110,9 @@ namespace build2
// Fall through.
}
- if (id == "module")
+ if (id == "module" ||
+ (cid_->type == compiler_type::msvc &&
+ id == "__preprocessed_module"))
{
location_value l (get_location (t));
l_->next (t);
@@ -113,7 +123,9 @@ namespace build2
else
n = false;
}
- else if (id == "import" /*|| id == "__import"*/)
+ else if (id == "import" /* ||
+ (cid_->type == compiler_type::gcc &&
+ id == "__import")*/)
{
l_->next (t);
@@ -181,7 +193,7 @@ namespace build2
//
pair<string, bool> np (parse_module_name (t, true /* partition */));
- // Should be {}-balanced.
+ // Skip attributes (should be {}-balanced).
//
for (;
t.type != type::eos && t.type != type::semi && !t.first;
@@ -262,7 +274,7 @@ namespace build2
return;
}
- // Should be {}-balanced.
+ // Skip attributes (should be {}-balanced).
//
for (;
t.type != type::eos && t.type != type::semi && !t.first;
diff --git a/libbuild2/cc/parser.hxx b/libbuild2/cc/parser.hxx
index 1fbf1a3..0c2eb2d 100644
--- a/libbuild2/cc/parser.hxx
+++ b/libbuild2/cc/parser.hxx
@@ -10,6 +10,7 @@
#include <libbuild2/diagnostics.hxx>
#include <libbuild2/cc/types.hxx>
+#include <libbuild2/cc/guess.hxx> // compiler_id
namespace build2
{
@@ -23,16 +24,19 @@ namespace build2
class parser
{
public:
+ // The compiler_id argument should identify the compiler that has done
+ // the preprocessing.
+ //
unit
- parse (ifdstream& is, const path_name& n)
+ parse (ifdstream& is, const path_name& n, const compiler_id& cid)
{
unit r;
- parse (is, n, r);
+ parse (is, n, r, cid);
return r;
}
void
- parse (ifdstream&, const path_name&, unit&);
+ parse (ifdstream&, const path_name&, unit&, const compiler_id&);
private:
void
@@ -54,6 +58,7 @@ namespace build2
string checksum; // Translation unit checksum.
private:
+ const compiler_id* cid_;
lexer* l_;
unit* u_;
diff --git a/libbuild2/cc/parser.test.cxx b/libbuild2/cc/parser.test.cxx
index 1d5930a..2270d32 100644
--- a/libbuild2/cc/parser.test.cxx
+++ b/libbuild2/cc/parser.test.cxx
@@ -44,7 +44,7 @@ namespace build2
}
parser p;
- unit u (p.parse (is, in));
+ unit u (p.parse (is, in, compiler_id (compiler_type::gcc, "")));
switch (u.type)
{
diff --git a/libbuild2/cc/pkgconfig-libpkgconf.cxx b/libbuild2/cc/pkgconfig-libpkgconf.cxx
index 81a96c3..f3754d3 100644
--- a/libbuild2/cc/pkgconfig-libpkgconf.cxx
+++ b/libbuild2/cc/pkgconfig-libpkgconf.cxx
@@ -81,10 +81,17 @@ namespace build2
#endif
;
+#if defined(LIBPKGCONF_VERSION) && LIBPKGCONF_VERSION >= 10900
+ static bool
+ pkgconf_error_handler (const char* msg,
+ const pkgconf_client_t*,
+ void*)
+#else
static bool
pkgconf_error_handler (const char* msg,
const pkgconf_client_t*,
const void*)
+#endif
{
error << runtime_error (msg); // Sanitize the message (trailing dot).
return true;
diff --git a/libbuild2/cc/pkgconfig.cxx b/libbuild2/cc/pkgconfig.cxx
index eae328e..046fbc8 100644
--- a/libbuild2/cc/pkgconfig.cxx
+++ b/libbuild2/cc/pkgconfig.cxx
@@ -34,6 +34,9 @@ namespace build2
//
// @@ TODO: handle empty values (save as ''?)
//
+ // Note: may contain variable expansions (e.g, ${pcfiledir}) so unclear
+ // if can use quoting.
+ //
static string
escape (const string& s)
{
@@ -313,23 +316,120 @@ namespace build2
assert (!ap.empty () || !sp.empty ());
- // Extract --cflags and set them as lib?{}:export.poptions..
+ const scope& rs (*s.root_scope ());
+
+ const dir_path* sysroot (
+ cast_null<abs_dir_path> (rs["config.cc.pkgconfig.sysroot"]));
+
+ // Append -I<dir> or -L<dir> option suppressing duplicates. Also handle
+ // the sysroot rewrite.
+ //
+ auto append_dir = [sysroot] (strings& ops, string&& o)
+ {
+ char c (o[1]);
+
+ // @@ Should we normalize the path for good measure? But on the other
+ // hand, most of the time when it's not normalized, it will likely
+ // be "consistently-relative", e.g., something like
+ // ${prefix}/lib/../include. I guess let's wait and see for some
+ // real-world examples.
+ //
+ // Well, we now support generating relocatable .pc files that have
+ // a bunch of -I${pcfiledir}/../../include and -L${pcfiledir}/.. .
+ //
+ // On the other hand, there could be symlinks involved and just
+ // normalize() may not be correct.
+ //
+ // Note that we do normalize -L paths in the usrd logic later
+ // (but not when setting as *.export.loptions).
+
+ if (sysroot != nullptr)
+ {
+ // Notes:
+ //
+ // - The path might not be absolute (we only rewrite absolute ones).
+ //
+ // - Do this before duplicate suppression since options in ops
+ // already have the sysroot rewritten.
+ //
+ // - Check if the path already starts with sysroot since some .pc
+ // files might already be in a good shape (e.g., because they use
+ // ${pcfiledir} to support relocation properly).
+ //
+ const char* op (o.c_str () + 2);
+ size_t on (o.size () - 2);
+
+ if (path_traits::absolute (op, on))
+ {
+ const string& s (sysroot->string ());
+
+ const char* sp (s.c_str ());
+ size_t sn (s.size ());
+
+ if (!path_traits::sub (op, on, sp, sn)) // Already in sysroot.
+ {
+ // Find the first directory seperator that seperates the root
+ // component from the rest of the path (think /usr/include,
+ // c:\install\include). We need to replace the root component
+ // with sysroot. If there is no separator (say, -Ic:) or the
+ // path after the separator is empty (say, -I/), then we replace
+ // the entire path.
+ //
+ size_t p (path_traits::find_separator (o, 2));
+ if (p == string::npos || p + 1 == o.size ())
+ p = o.size ();
+
+ o.replace (2, p - 2, s);
+ }
+ }
+ }
+
+ for (const string& x: ops)
+ {
+ if (x.size () > 2 && x[0] == '-' && x[1] == c)
+ {
+ if (path_traits::compare (x.c_str () + 2, x.size () - 2,
+ o.c_str () + 2, o.size () - 2) == 0)
+ return; // Duplicate.
+ }
+ }
+
+ ops.push_back (move (o));
+ };
+
+ // Extract --cflags and set them as lib?{}:export.poptions returing the
+ // pointer to the set value. If [as]pops are not NULL, then only keep
+ // options that are present in both.
//
- auto parse_cflags = [&trace, this] (target& t,
- const pkgconfig& pc,
- bool la)
+ auto parse_cflags =[&trace,
+ this,
+ &append_dir] (target& t,
+ const pkgconfig& pc,
+ bool la,
+ const strings* apops = nullptr,
+ const strings* spops = nullptr)
+ -> const strings*
{
+ // Note that we normalize `-[IDU] <arg>` to `-[IDU]<arg>`.
+ //
strings pops;
- bool arg (false);
- for (auto& o: pc.cflags (la))
+ char arg ('\0'); // Option with pending argument.
+ for (string& o: pc.cflags (la))
{
if (arg)
{
// Can only be an argument for -I, -D, -U options.
//
- pops.push_back (move (o));
- arg = false;
+ o.insert (0, 1, arg);
+ o.insert (0, 1, '-');
+
+ if (arg == 'I')
+ append_dir (pops, move (o));
+ else
+ pops.push_back (move (o));
+
+ arg = '\0';
continue;
}
@@ -340,8 +440,15 @@ namespace build2
if (n >= 2 &&
o[0] == '-' && (o[1] == 'I' || o[1] == 'D' || o[1] == 'U'))
{
- pops.push_back (move (o));
- arg = (n == 2);
+ if (n > 2)
+ {
+ if (o[1] == 'I')
+ append_dir (pops, move (o));
+ else
+ pops.push_back (move (o));
+ }
+ else
+ arg = o[1];
continue;
}
@@ -350,7 +457,7 @@ namespace build2
}
if (arg)
- fail << "argument expected after " << pops.back () <<
+ fail << "argument expected after -" << arg <<
info << "while parsing pkg-config --cflags " << pc.path;
if (!pops.empty ())
@@ -363,19 +470,45 @@ namespace build2
// export stub and we shouldn't touch them.
//
if (p.second)
+ {
+ // If required, only keep common stuff. While removing the entries
+ // is not the most efficient way, it is simple.
+ //
+ if (apops != nullptr || spops != nullptr)
+ {
+ for (auto i (pops.begin ()); i != pops.end (); )
+ {
+ if ((apops != nullptr && find (
+ apops->begin (), apops->end (), *i) == apops->end ()) ||
+ (spops != nullptr && find (
+ spops->begin (), spops->end (), *i) == spops->end ()))
+ i = pops.erase (i);
+ else
+ ++i;
+ }
+ }
+
p.first = move (pops);
+ return &p.first.as<strings> ();
+ }
}
+
+ return nullptr;
};
// Parse --libs into loptions/libs (interface and implementation). If
// ps is not NULL, add each resolved library target as a prerequisite.
//
- auto parse_libs = [this, act, &s, top_sysd] (target& t,
- bool binless,
- const pkgconfig& pc,
- bool la,
- prerequisites* ps)
+ auto parse_libs = [this,
+ &append_dir,
+ act, &s, top_sysd] (target& t,
+ bool binless,
+ const pkgconfig& pc,
+ bool la,
+ prerequisites* ps)
{
+ // Note that we normalize `-L <arg>` to `-L<arg>`.
+ //
strings lops;
vector<name> libs;
@@ -392,15 +525,21 @@ namespace build2
// library. What we do at the moment is stop recognizing just library
// names (without -l) after seeing an unknown option.
//
- bool arg (false), first (true), known (true), have_L;
- for (auto& o: pc.libs (la))
+ bool first (true), known (true), have_L (false);
+
+ string self; // The library itself (-l of just name/path).
+
+ char arg ('\0'); // Option with pending argument.
+ for (string& o: pc.libs (la))
{
if (arg)
{
- // Can only be an argument for an loption.
+ // Can only be an argument for an -L option.
//
- lops.push_back (move (o));
- arg = false;
+ o.insert (0, 1, arg);
+ o.insert (0, 1, '-');
+ append_dir (lops, move (o));
+ arg = '\0';
continue;
}
@@ -410,15 +549,17 @@ namespace build2
//
if (n >= 2 && o[0] == '-' && o[1] == 'L')
{
+ if (n > 2)
+ append_dir (lops, move (o));
+ else
+ arg = o[1];
have_L = true;
- lops.push_back (move (o));
- arg = (n == 2);
continue;
}
// See if that's -l, -pthread, or just the library name/path.
//
- if ((known && o[0] != '-') ||
+ if ((known && n != 0 && o[0] != '-') ||
(n > 2 && o[0] == '-' && (o[1] == 'l' || o == "-pthread")))
{
// Unless binless, the first one is the library itself, which we
@@ -426,19 +567,11 @@ namespace build2
// be some other library, but we haven't encountered such a beast
// yet.
//
- if (first)
- {
- first = false;
-
- if (!binless)
- continue;
- }
-
- // @@ If for some reason this is the library itself (doesn't go
- // first or libpkg-config parsed libs in some bizarre way) we
- // will have a dependency cycle by trying to lock its target
- // inside search_library() as by now it is already locked. To
- // be safe we probably shouldn't rely on the position and
+ // What we have enountered (e.g., in the Magick++ library) is the
+ // library itself repeated in Libs.private. So now we save it and
+ // filter all its subsequent occurences.
+ //
+ // @@ To be safe we probably shouldn't rely on the position and
// filter out all occurrences of the library itself (by name?)
// and complain if none were encountered.
//
@@ -448,6 +581,22 @@ namespace build2
// frame around the call to search_library() to help diagnose
// such situations.
//
+ if (first)
+ {
+ first = false;
+
+ if (!binless)
+ {
+ self = move (o);
+ continue;
+ }
+ }
+ else
+ {
+ if (!binless && o == self)
+ continue;
+ }
+
libs.push_back (name (move (o)));
continue;
}
@@ -459,7 +608,7 @@ namespace build2
}
if (arg)
- fail << "argument expected after " << lops.back () <<
+ fail << "argument expected after -" << arg <<
info << "while parsing pkg-config --libs " << pc.path;
// Space-separated list of escaped library flags.
@@ -467,7 +616,7 @@ namespace build2
auto lflags = [&pc, la] () -> string
{
string r;
- for (const auto& o: pc.libs (la))
+ for (const string& o: pc.libs (la))
{
if (!r.empty ())
r += ' ';
@@ -476,7 +625,7 @@ namespace build2
return r;
};
- if (first && !binless)
+ if (!binless && self.empty ())
fail << "library expected in '" << lflags () << "'" <<
info << "while parsing pkg-config --libs " << pc.path;
@@ -517,12 +666,15 @@ namespace build2
if (l[0] != '-') // e.g., just shell32.lib
continue;
else if (cmp ("advapi32") ||
+ cmp ("authz") ||
cmp ("bcrypt") ||
+ cmp ("comdlg32") ||
cmp ("crypt32") ||
- cmp ("dbgeng") ||
- cmp ("dbghelp") ||
cmp ("d2d1") ||
cmp ("d3d", 3) || // d3d*
+ cmp ("dbgeng") ||
+ cmp ("dbghelp") ||
+ cmp ("dnsapi") ||
cmp ("dwmapi") ||
cmp ("dwrite") ||
cmp ("dxgi") ||
@@ -535,6 +687,7 @@ namespace build2
cmp ("kernel32") ||
cmp ("mincore") ||
cmp ("mpr") ||
+ cmp ("msimg32") ||
cmp ("mswsock") ||
cmp ("msxml", 5) || // msxml*
cmp ("netapi32") ||
@@ -547,6 +700,7 @@ namespace build2
cmp ("psapi") ||
cmp ("rpcrt4") ||
cmp ("secur32") ||
+ cmp ("setupapi") ||
cmp ("shell32") ||
cmp ("shlwapi") ||
cmp ("synchronization") ||
@@ -554,6 +708,7 @@ namespace build2
cmp ("userenv") ||
cmp ("uuid") ||
cmp ("version") ||
+ cmp ("windowscodecs") ||
cmp ("winhttp") ||
cmp ("winmm") ||
cmp ("winspool") ||
@@ -604,7 +759,11 @@ namespace build2
}
else if (tclass == "macos")
{
- if (l == "-lSystem")
+ // Note that Mac OS has libiconv in /usr/lib/ which only comes
+ // in the shared variant. So we treat it as system.
+ //
+ if (l == "-lSystem" ||
+ l == "-liconv")
continue;
}
else if (tclass == "bsd")
@@ -621,18 +780,13 @@ namespace build2
{
usrd = dir_paths ();
- for (auto i (lops.begin ()); i != lops.end (); ++i)
+ for (const string& o: lops)
{
- const string& o (*i);
-
- if (o.size () >= 2 && o[0] == '-' && o[1] == 'L')
+ // Note: always in the -L<dir> form (see above).
+ //
+ if (o.size () > 2 && o[0] == '-' && o[1] == 'L')
{
- string p;
-
- if (o.size () == 2)
- p = *++i; // We've verified it's there.
- else
- p = string (o, 2);
+ string p (o, 2);
try
{
@@ -643,6 +797,7 @@ namespace build2
<< lflags () << "'" <<
info << "while parsing pkg-config --libs " << pc.path;
+ d.normalize ();
usrd->push_back (move (d));
}
catch (const invalid_path& e)
@@ -722,24 +877,16 @@ namespace build2
{
// Translate -L to /LIBPATH.
//
- for (auto i (lops.begin ()); i != lops.end (); )
+ for (string& o: lops)
{
- string& o (*i);
size_t n (o.size ());
- if (n >= 2 && o[0] == '-' && o[1] == 'L')
+ // Note: always in the -L<dir> form (see above).
+ //
+ if (n > 2 && o[0] == '-' && o[1] == 'L')
{
o.replace (0, 2, "/LIBPATH:");
-
- if (n == 2)
- {
- o += *++i; // We've verified it's there.
- i = lops.erase (i);
- continue;
- }
}
-
- ++i;
}
}
@@ -933,6 +1080,14 @@ namespace build2
string mn (m, 0, p);
path mp (m, p + 1, string::npos);
+
+ // Must be absolute but may not be normalized due to a relocatable
+ // .pc file. We assume there are no symlink shenanigans that would
+ // require realize().
+ //
+ if (!mp.normalized ())
+ mp.normalize ();
+
path mf (mp.leaf ());
// Extract module properties, if any.
@@ -957,7 +1112,7 @@ namespace build2
target_decl::implied,
trace));
- target& mt (tl.first);
+ file& mt (tl.first.as<file> ());
// If the target already exists, then setting its variables is not
// MT-safe. So currently we only do it if we have the lock (and thus
@@ -975,6 +1130,7 @@ namespace build2
//
if (tl.second.owns_lock ())
{
+ mt.path (move (mp));
mt.vars.assign (c_module_name) = move (mn);
// Set module properties. Note that if unspecified we should still
@@ -1025,6 +1181,14 @@ namespace build2
for (size_t b (0), e (0); !(h = next (*val, b, e)).empty (); )
{
path hp (move (h));
+
+ // Must be absolute but may not be normalized due to a relocatable
+ // .pc file. We assume there are no symlink shenanigans that would
+ // require realize().
+ //
+ if (!hp.normalized ())
+ hp.normalize ();
+
path hf (hp.leaf ());
auto tl (
@@ -1037,7 +1201,7 @@ namespace build2
target_decl::implied,
trace));
- target& ht (tl.first);
+ file& ht (tl.first.as<file> ());
// If the target already exists, then setting its variables is not
// MT-safe. So currently we only do it if we have the lock (and thus
@@ -1046,6 +1210,7 @@ namespace build2
//
if (tl.second.owns_lock ())
{
+ ht.path (move (hp));
ht.vars.assign (c_importable) = true;
tl.second.unlock ();
}
@@ -1209,14 +1374,26 @@ namespace build2
false,
&prs);
+ const strings* apops (nullptr);
if (pa)
{
- parse_cflags (*at, apc, true);
+ apops = parse_cflags (*at, apc, true);
parse_libs (*at, at->path ().empty (), apc, true, nullptr);
}
+ const strings* spops (nullptr);
if (ps)
- parse_cflags (*st, spc, false);
+ spops = parse_cflags (*st, spc, false);
+
+ // Also set common poptions for the group. In particular, this makes
+ // sure $lib_poptions() in the "common interface" mode works for the
+ // installed libraries.
+ //
+ // Note that if there are no poptions set for either, then we cannot
+ // possibly have a common subset.
+ //
+ if (apops != nullptr || spops != nullptr)
+ parse_cflags (lt, ipc, false, apops, spops);
// @@ TODO: we can now load cc.type if there is metadata (but need to
// return this rather than set, see search_library() for
@@ -1248,7 +1425,7 @@ namespace build2
// We treat headers outside of any project as C headers (see
// enter_header() for details).
//
- parse_headers (ipc, h::static_type /* **x_hdr */, x, prs);
+ parse_headers (ipc, h::static_type /* **x_hdrs */, x, prs);
parse_headers (ipc, h::static_type, "c", prs);
}
@@ -1368,7 +1545,7 @@ namespace build2
{
bool f (ldirs.empty ());
- ldirs.push_back (resolve_dir (g, d, !f /* fail_unknown */));
+ ldirs.push_back (resolve_dir (g, d, {}, !f /* fail_unknown */));
if (f && ldirs.back ().empty ())
break;
@@ -1377,6 +1554,7 @@ namespace build2
else
ldirs.push_back (resolve_dir (g,
cast<dir_path> (g["install.lib"]),
+ {},
false /* fail_unknown */));
if (!ldirs.empty () && ldirs.front ().empty ())
@@ -1407,6 +1585,71 @@ namespace build2
if (ctx.dry_run)
return;
+ // See if we should be generating a relocatable .pc file and if so get
+ // its installation location. The plan is to make all absolute paths
+ // that we write relative to this location and prefix them with the
+ // built-in ${pcfiledir} variable (which supported by everybody: the
+ // original pkg-config, pkgconf, and our libpkg-config library).
+ //
+ dir_path rel_base;
+ if (cast_false<bool> (rs["install.relocatable"]))
+ {
+ path f (install::resolve_file (*t));
+ if (!f.empty ()) // Shouldn't happen but who knows.
+ rel_base = f.directory ();
+ }
+
+ // Note: reloc_*path() expect absolute and normalized paths.
+ //
+ // Note also that reloc_path() can be used on dir_path to get the path
+ // without the trailing slash.
+ //
+ auto reloc_path = [&rel_base,
+ s = string ()] (const path& p,
+ const char* what) mutable
+ -> const string&
+ {
+ if (rel_base.empty ())
+ return p.string ();
+
+ try
+ {
+ s = p.relative (rel_base).string ();
+ }
+ catch (const invalid_path&)
+ {
+ fail << "unable to make " << what << " path " << p << " relative to "
+ << rel_base;
+ }
+
+ if (!s.empty ()) s.insert (0, 1, path_traits::directory_separator);
+ s.insert (0, "${pcfiledir}");
+ return s;
+ };
+
+ auto reloc_dir_path = [&rel_base,
+ s = string ()] (const dir_path& p,
+ const char* what) mutable
+ -> const string&
+ {
+ if (rel_base.empty ())
+ return (s = p.representation ());
+
+ try
+ {
+ s = p.relative (rel_base).representation ();
+ }
+ catch (const invalid_path&)
+ {
+ fail << "unable to make " << what << " path " << p << " relative to "
+ << rel_base;
+ }
+
+ if (!s.empty ()) s.insert (0, 1, path_traits::directory_separator);
+ s.insert (0, "${pcfiledir}");
+ return s;
+ };
+
auto_rmfile arm (p);
try
@@ -1558,7 +1801,7 @@ namespace build2
//
os << "Cflags:";
for (const dir_path& d: idirs)
- os << " -I" << escape (d.string ());
+ os << " -I" << escape (reloc_path (d, "header search"));
save_poptions (x_export_poptions);
save_poptions (c_export_poptions);
os << endl;
@@ -1578,7 +1821,7 @@ namespace build2
// necessary to resolve its binful dependencies.
//
for (const dir_path& d: ldirs)
- os << " -L" << escape (d.string ());
+ os << " -L" << escape (reloc_path (d, "library search"));
// Now process ourselves as if we were being linked to something (so
// pretty similar to link_rule::append_libraries()). We also reuse
@@ -1671,7 +1914,7 @@ namespace build2
//@@ TODO: should we filter -L similar to -I?
//@@ TODO: how will the Libs/Libs.private work?
- //@@ TODO: remember to use escape()
+ //@@ TODO: remember to use reloc_*() and escape().
if (d.pls != nullptr && d.pls->find (l) != nullptr)
return true;
@@ -1765,7 +2008,8 @@ namespace build2
}
catch (const invalid_argument& e)
{
- fail << "invalid metadata version in library " << g << ": " << e;
+ fail << "invalid metadata version in library " << g << ": " << e
+ << endf;
}
if (ver != 1)
@@ -1923,16 +2167,43 @@ namespace build2
const value& val (*b.val);
names ns;
- names_view nv (reverse (val, ns));
+ names_view nv (reverse (val, ns, true /* reduce */));
os << *b.name << " =";
- auto append = [&l, &var, &s] (const name& v)
+ auto append = [&rel_base,
+ &reloc_path,
+ &reloc_dir_path,
+ &l, &var, &val, &s] (const name& v)
{
+ // If this is absolute path or dir_path, then attempt to
+ // relocate. Without that the result will not be relocatable.
+ //
if (v.simple ())
- s += v.value;
+ {
+ path p;
+ if (!rel_base.empty () &&
+ val.type != nullptr &&
+ (val.type->is_a<path> () || val.type->is_a<paths> ()) &&
+ (p = path (v.value)).absolute ())
+ {
+ p.normalize ();
+ s += reloc_path (p, var.name.c_str ());
+ }
+ else
+ s += v.value;
+ }
else if (v.directory ())
- s += v.dir.representation ();
+ {
+ if (!rel_base.empty () && v.dir.absolute ())
+ {
+ dir_path p (v.dir);
+ p.normalize ();
+ s += reloc_dir_path (p, var.name.c_str ());
+ }
+ else
+ s += v.dir.representation ();
+ }
else
// It seems like we shouldn't end up here due to the type
// check but let's keep it for good measure.
@@ -2090,7 +2361,7 @@ namespace build2
move (pp),
symexport});
}
- else if (pt->is_a (**x_hdr) || pt->is_a<h> ())
+ else if (pt->is_a (**this->x_hdrs) || pt->is_a<h> ())
{
if (cast_false<bool> ((*pt)[c_importable]))
{
@@ -2133,7 +2404,8 @@ namespace build2
// Module names shouldn't require escaping.
//
os << (n != 1 ? " \\\n" : " ")
- << m.name << '=' << escape (m.file.string ());
+ << m.name << '='
+ << escape (reloc_path (m.file, "module interface"));
}
os << endl;
@@ -2159,7 +2431,8 @@ namespace build2
<< "c.importable_headers =";
for (const path& h: c_hdrs)
- os << (n != 1 ? " \\\n" : " ") << escape (h.string ());
+ os << (n != 1 ? " \\\n" : " ")
+ << escape (reloc_path (h, "header unit"));
os << endl;
}
@@ -2170,7 +2443,8 @@ namespace build2
<< x << ".importable_headers =";
for (const path& h: x_hdrs)
- os << (n != 1 ? " \\\n" : " ") << escape (h.string ());
+ os << (n != 1 ? " \\\n" : " ")
+ << escape (reloc_path (h, "header unit"));
os << endl;
}
diff --git a/libbuild2/cc/pkgconfig.hxx b/libbuild2/cc/pkgconfig.hxx
index 7959da1..a1bcdee 100644
--- a/libbuild2/cc/pkgconfig.hxx
+++ b/libbuild2/cc/pkgconfig.hxx
@@ -56,8 +56,8 @@ namespace build2
// Movable-only type.
//
- pkgconfig (pkgconfig&&);
- pkgconfig& operator= (pkgconfig&&);
+ pkgconfig (pkgconfig&&) noexcept;
+ pkgconfig& operator= (pkgconfig&&) noexcept;
pkgconfig (const pkgconfig&) = delete;
pkgconfig& operator= (const pkgconfig&) = delete;
@@ -95,7 +95,7 @@ namespace build2
}
inline pkgconfig::
- pkgconfig (pkgconfig&& p)
+ pkgconfig (pkgconfig&& p) noexcept
: path (move (p.path)),
client_ (p.client_),
pkg_ (p.pkg_)
@@ -105,7 +105,7 @@ namespace build2
}
inline pkgconfig& pkgconfig::
- operator= (pkgconfig&& p)
+ operator= (pkgconfig&& p) noexcept
{
if (this != &p)
{
diff --git a/libbuild2/cc/predefs-rule.cxx b/libbuild2/cc/predefs-rule.cxx
new file mode 100644
index 0000000..606db06
--- /dev/null
+++ b/libbuild2/cc/predefs-rule.cxx
@@ -0,0 +1,379 @@
+// file : libbuild2/cc/predefs-rule.cxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#include <libbuild2/cc/predefs-rule.hxx>
+
+#include <libbuild2/depdb.hxx>
+#include <libbuild2/target.hxx>
+#include <libbuild2/context.hxx>
+#include <libbuild2/algorithm.hxx>
+#include <libbuild2/filesystem.hxx>
+#include <libbuild2/diagnostics.hxx>
+
+namespace build2
+{
+ namespace cc
+ {
+ predefs_rule::
+ predefs_rule (data&& d)
+ : common (move (d)),
+ rule_name (string (x) += ".predefs"),
+ rule_id (rule_name + " 1")
+ {
+ }
+
+ bool predefs_rule::
+ match (action, target&, const string& hint, match_extra&) const
+ {
+ tracer trace (x, "predefs_rule::match");
+
+ // We only match with an explicit hint (failed that, we will turn every
+ // header into predefs).
+ //
+ if (hint == rule_name)
+ {
+ // Don't match if unsupported compiler. In particular, this allows the
+ // user to provide a fallback rule.
+ //
+ switch (cclass)
+ {
+ case compiler_class::gcc: return true;
+ case compiler_class::msvc:
+ {
+ // Only MSVC 19.20 or later. Not tested with clang-cl.
+ //
+ if (cvariant.empty () && (cmaj > 19 || (cmaj == 19 && cmin >= 20)))
+ return true;
+
+ l4 ([&]{trace << "unsupported compiler/version";});
+ break;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ recipe predefs_rule::
+ apply (action a, target& xt, match_extra&) const
+ {
+ file& t (xt.as<file> ());
+ t.derive_path ();
+
+ // Inject dependency on the output directory.
+ //
+ inject_fsdir (a, t);
+
+ if (a == perform_update_id)
+ {
+ return [this] (action a, const target& xt)
+ {
+ return perform_update (a, xt);
+ };
+ }
+ else if (a == perform_clean_id)
+ {
+ return [] (action a, const target& t)
+ {
+ // Also remove the temporary input source file in case it wasn't
+ // removed at the end of the update.
+ //
+ return perform_clean_extra (a, t.as<file> (), {".d", ".t"});
+ };
+ }
+ else
+ return noop_recipe; // Configure update.
+ }
+
+ // Filter noise, sanitize options (msvc.cxx).
+ //
+ void
+ msvc_filter_cl (diag_buffer&, const path& src);
+
+ void
+ msvc_sanitize_cl (cstrings&);
+
+ target_state predefs_rule::
+ perform_update (action a, const target& xt) const
+ {
+ tracer trace (x, "predefs_rule::perform_update");
+
+ const file& t (xt.as<file> ());
+ const path& tp (t.path ());
+
+ context& ctx (t.ctx);
+
+ const scope& rs (t.root_scope ());
+
+ // Execute prerequisites (the output directory being the only one thus
+ // not mtime checking).
+ //
+ execute_prerequisites (a, t);
+
+ // Use depdb to track changes to options, compiler, etc (similar to
+ // the compile_rule).
+ //
+ depdb dd (tp + ".d");
+ {
+ // First should come the rule name/version.
+ //
+ if (dd.expect (rule_id) != nullptr)
+ l4 ([&]{trace << "rule mismatch forcing update of " << t;});
+
+ // Then the compiler checksum.
+ //
+ if (dd.expect (cast<string> (rs[x_checksum])) != nullptr)
+ l4 ([&]{trace << "compiler mismatch forcing update of " << t;});
+
+ // Then the compiler environment checksum.
+ //
+ if (dd.expect (env_checksum) != nullptr)
+ l4 ([&]{trace << "environment mismatch forcing update of " << t;});
+
+ // Finally the options checksum (as below).
+ //
+ {
+ sha256 cs;
+ append_options (cs, t, c_coptions);
+ append_options (cs, t, x_coptions);
+ append_options (cs, cmode);
+
+ if (dd.expect (cs.string ()) != nullptr)
+ l4 ([&]{trace << "options mismatch forcing update of " << t;});
+ }
+ }
+
+ // Update if depdb mismatch.
+ //
+ bool update (dd.writing () || dd.mtime > t.load_mtime ());
+
+ dd.close ();
+
+ if (!update)
+ return target_state::unchanged; // No mtime-based prerequisites.
+
+ // Prepare the compiler command-line.
+ //
+ cstrings args {cpath.recall_string ()};
+
+ // Append compile options.
+ //
+ // Note that any command line macros that we specify with -D will end up
+ // in the predefs, which is something we don't want. So no poptions.
+ //
+ append_options (args, t, c_coptions);
+ append_options (args, t, x_coptions);
+ append_options (args, cmode);
+
+ // The output and input paths, relative to the working directory for
+ // easier to read diagnostics.
+ //
+ path relo (relative (tp));
+ path reli;
+
+ // Add compiler-specific command-line arguments.
+ //
+ switch (cclass)
+ {
+ case compiler_class::gcc:
+ {
+ // Add implied options which may affect predefs, similar to the
+ // compile rule.
+ //
+ if (!find_option_prefix ("-finput-charset=", args))
+ args.push_back ("-finput-charset=UTF-8");
+
+ if (ctype == compiler_type::clang && tsys == "win32-msvc")
+ {
+ if (!find_options ({"-nostdlib", "-nostartfiles"}, args))
+ {
+ args.push_back ("-D_MT");
+ args.push_back ("-D_DLL");
+ }
+ }
+
+ if (ctype == compiler_type::clang && cvariant == "emscripten")
+ {
+ if (x_lang == lang::cxx)
+ {
+ if (!find_option_prefix ("DISABLE_EXCEPTION_CATCHING=", args))
+ {
+ args.push_back ("-s");
+ args.push_back ("DISABLE_EXCEPTION_CATCHING=0");
+ }
+ }
+ }
+
+ args.push_back ("-E"); // Stop after the preprocessing stage.
+ args.push_back ("-dM"); // Generate #define directives.
+
+ // Output.
+ //
+ args.push_back ("-o");
+ args.push_back (relo.string ().c_str ());
+
+ // Input.
+ //
+ args.push_back ("-x");
+ switch (x_lang)
+ {
+ case lang::c: args.push_back ("c"); break;
+ case lang::cxx: args.push_back ("c++"); break;
+ }
+
+ // With GCC and Clang we can compile /dev/null as stdin by
+ // specifying `-` and thus omitting the temporary file.
+ //
+ args.push_back ("-");
+
+ break;
+ }
+ case compiler_class::msvc:
+ {
+ // Add implied options which may affect predefs, similar to the
+ // compile rule.
+ //
+ {
+ // Note: these affect the _MSVC_EXECUTION_CHARACTER_SET, _UTF8
+ // macros.
+ //
+ bool sc (find_option_prefixes (
+ {"/source-charset:", "-source-charset:"}, args));
+ bool ec (find_option_prefixes (
+ {"/execution-charset:", "-execution-charset:"}, args));
+
+ if (!sc && !ec)
+ args.push_back ("/utf-8");
+ else
+ {
+ if (!sc)
+ args.push_back ("/source-charset:UTF-8");
+
+ if (!ec)
+ args.push_back ("/execution-charset:UTF-8");
+ }
+ }
+
+ if (x_lang == lang::cxx)
+ {
+ if (!find_option_prefixes ({"/EH", "-EH"}, args))
+ args.push_back ("/EHsc");
+ }
+
+ if (!find_option_prefixes ({"/MD", "/MT", "-MD", "-MT"}, args))
+ args.push_back ("/MD");
+
+ msvc_sanitize_cl (args);
+
+ args.push_back ("/nologo");
+
+ // /EP may seem like it contradicts /P but it's the recommended
+ // way to suppress `#line`s from the output of the /P option (see
+ // /P in the "MSVC Compiler Options" documentation).
+ //
+ args.push_back ("/P"); // Write preprocessor output to a file.
+ args.push_back ("/EP"); // Preprocess to stdout without `#line`s.
+
+ args.push_back ("/PD"); // Print all macro definitions.
+ args.push_back ("/Zc:preprocessor"); // Preproc. conformance mode.
+
+ // Output (note that while the /Fi: variant is only availbale
+ // starting with VS2013, /Zc:preprocessor is only available
+ // starting from VS2019).
+ //
+ args.push_back ("/Fi:");
+ args.push_back (relo.string ().c_str ());
+
+ // Input.
+ //
+ switch (x_lang)
+ {
+ case lang::c: args.push_back ("/TC"); break;
+ case lang::cxx: args.push_back ("/TP"); break;
+ }
+
+ // Input path.
+ //
+ // Note that with MSVC we have to use a temporary file. In
+ // particular compiling `nul` does not work.
+ //
+ reli = relo + ".t";
+ args.push_back (reli.string ().c_str ());
+
+ break;
+ }
+ }
+
+ args.push_back (nullptr);
+
+ // Run the compiler.
+ //
+ if (verb >= 2)
+ print_process (args);
+ else if (verb)
+ print_diag ((string (x_name) + "-predefs").c_str (), t);
+
+ if (!ctx.dry_run)
+ {
+ // Create an empty temporary input source file, if necessary.
+ //
+ auto_rmfile rmi;
+ if (!reli.empty ())
+ {
+ rmi = auto_rmfile (reli);
+
+ if (exists (reli, false /* follow_symlinks */))
+ rmfile (ctx, reli, 3 /* verbosity */);
+
+ touch (ctx, reli, true /* create */, 3 /* verbosity */);
+ }
+
+ try
+ {
+ // VC cl.exe sends diagnostics to stdout. It also prints the file
+ // name being compiled as the first line. So for cl.exe we filter
+ // that noise out.
+ //
+ // For other compilers also redirect stdout to stderr, in case any
+ // of them tries to pull off something similar. For sane compilers
+ // this should be harmless.
+ //
+ // We also redirect stdin to /dev/null in case that's used instead
+ // of the temporary file.
+ //
+ // Note: similar logic as in compile_rule.
+ //
+ bool filter (ctype == compiler_type::msvc);
+
+ process pr (cpath,
+ args,
+ -2, /* stdin */
+ 2, /* stdout */
+ diag_buffer::pipe (ctx, filter /* force */) /* stderr */);
+
+ diag_buffer dbuf (ctx, args[0], pr);
+
+ if (filter)
+ msvc_filter_cl (dbuf, reli);
+
+ dbuf.read ();
+
+ run_finish (dbuf, args, pr, 1 /* verbosity */);
+ dd.check_mtime (tp);
+ }
+ catch (const process_error& e)
+ {
+ error << "unable to execute " << args[0] << ": " << e;
+
+ if (e.child)
+ exit (1);
+
+ throw failed ();
+ }
+ }
+
+ t.mtime (system_clock::now ());
+ return target_state::changed;
+ }
+ }
+}
diff --git a/libbuild2/cc/predefs-rule.hxx b/libbuild2/cc/predefs-rule.hxx
new file mode 100644
index 0000000..60aa063
--- /dev/null
+++ b/libbuild2/cc/predefs-rule.hxx
@@ -0,0 +1,45 @@
+// file : libbuild2/cc/predefs-rule.hxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#ifndef LIBBUILD2_CC_PREDEFS_RULE_HXX
+#define LIBBUILD2_CC_PREDEFS_RULE_HXX
+
+#include <libbuild2/types.hxx>
+#include <libbuild2/utility.hxx>
+
+#include <libbuild2/rule.hxx>
+
+#include <libbuild2/cc/types.hxx>
+#include <libbuild2/cc/common.hxx>
+
+#include <libbuild2/cc/export.hxx>
+
+namespace build2
+{
+ namespace cc
+ {
+ class LIBBUILD2_CC_SYMEXPORT predefs_rule: public rule,
+ virtual common
+ {
+ public:
+ const string rule_name;
+
+ explicit
+ predefs_rule (data&&);
+
+ virtual bool
+ match (action, target&, const string&, match_extra&) const override;
+
+ virtual recipe
+ apply (action, target&, match_extra&) const override;
+
+ target_state
+ perform_update (action, const target&) const;
+
+ private:
+ const string rule_id;
+ };
+ }
+}
+
+#endif // LIBBUILD2_CC_PREDEFS_RULE_HXX
diff --git a/libbuild2/cc/std.compat.cppm b/libbuild2/cc/std.compat.cppm
new file mode 100644
index 0000000..2668b30
--- /dev/null
+++ b/libbuild2/cc/std.compat.cppm
@@ -0,0 +1,996 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// WARNING, this entire header is generated by
+// utils/generate_libcxx_cppm_in.py
+// DO NOT MODIFY!
+
+module;
+
+#include <__config>
+
+#if _LIBCPP_VERSION < 180000
+#error libc++ version 18.0.0 or later required
+#endif
+
+// The headers of Table 24: C++ library headers [tab:headers.cpp]
+// and the headers of Table 25: C++ headers for C library facilities [tab:headers.cpp.c]
+#include <cassert>
+#include <cctype>
+#include <cerrno>
+#include <cfenv>
+#include <cfloat>
+#include <cinttypes>
+#include <climits>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <clocale>
+#endif
+#include <cmath>
+#include <csetjmp>
+#include <csignal>
+#include <cstdarg>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <cuchar>
+#if !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)
+# include <cwchar>
+#endif
+#if !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)
+# include <cwctype>
+#endif
+
+#if 0
+// *** Headers not yet available ***
+#if __has_include(<debugging>)
+# error "please update the header information for <debugging> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<debugging>)
+#if __has_include(<flat_map>)
+# error "please update the header information for <flat_map> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<flat_map>)
+#if __has_include(<flat_set>)
+# error "please update the header information for <flat_set> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<flat_set>)
+#if __has_include(<generator>)
+# error "please update the header information for <generator> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<generator>)
+#if __has_include(<hazard_pointer>)
+# error "please update the header information for <hazard_pointer> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<hazard_pointer>)
+#if __has_include(<linalg>)
+# error "please update the header information for <linalg> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<linalg>)
+#if __has_include(<rcu>)
+# error "please update the header information for <rcu> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<rcu>)
+#if __has_include(<spanstream>)
+# error "please update the header information for <spanstream> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<spanstream>)
+#if __has_include(<stacktrace>)
+# error "please update the header information for <stacktrace> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<stacktrace>)
+#if __has_include(<stdfloat>)
+# error "please update the header information for <stdfloat> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<stdfloat>)
+#if __has_include(<text_encoding>)
+# error "please update the header information for <text_encoding> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<text_encoding>)
+#endif
+
+export module std.compat;
+export import std;
+
+// cassert.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ // This module exports nothing.
+} // export
+
+// cctype.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::isalnum;
+ using ::isalpha;
+ using ::isblank;
+ using ::iscntrl;
+ using ::isdigit;
+ using ::isgraph;
+ using ::islower;
+ using ::isprint;
+ using ::ispunct;
+ using ::isspace;
+ using ::isupper;
+ using ::isxdigit;
+ using ::tolower;
+ using ::toupper;
+} // export
+
+// cerrno.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ // This module exports nothing.
+} // export
+
+// cfenv.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ // types
+ using ::fenv_t;
+ using ::fexcept_t;
+
+ // functions
+ using ::feclearexcept;
+ using ::fegetexceptflag;
+ using ::feraiseexcept;
+ using ::fesetexceptflag;
+ using ::fetestexcept;
+
+ using ::fegetround;
+ using ::fesetround;
+
+ using ::fegetenv;
+ using ::feholdexcept;
+ using ::fesetenv;
+ using ::feupdateenv;
+} // export
+
+// cfloat.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ // This module exports nothing.
+} // export
+
+// cinttypes.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::imaxdiv_t;
+
+ using ::imaxabs;
+ using ::imaxdiv;
+ using ::strtoimax;
+ using ::strtoumax;
+ using ::wcstoimax;
+ using ::wcstoumax;
+
+ // abs is conditionally here, but always present in cmath.cppm. To avoid
+ // conflicing declarations omit the using here.
+
+ // div is conditionally here, but always present in cstdlib.cppm. To avoid
+ // conflicing declarations omit the using here.
+} // export
+
+// climits.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ // This module exports nothing.
+} // export
+
+// clocale.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ using ::lconv;
+
+ using ::localeconv;
+ using ::setlocale;
+#endif // _LIBCPP_HAS_NO_LOCALIZATION
+} // export
+
+// cmath.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::double_t;
+ using ::float_t;
+
+ using ::acos;
+ using ::acosf;
+ using ::acosl;
+
+ using ::asin;
+ using ::asinf;
+ using ::asinl;
+
+ using ::atan;
+ using ::atanf;
+ using ::atanl;
+
+ using ::atan2;
+ using ::atan2f;
+ using ::atan2l;
+
+ using ::cos;
+ using ::cosf;
+ using ::cosl;
+
+ using ::sin;
+ using ::sinf;
+ using ::sinl;
+
+ using ::tan;
+ using ::tanf;
+ using ::tanl;
+
+ using ::acosh;
+ using ::acoshf;
+ using ::acoshl;
+
+ using ::asinh;
+ using ::asinhf;
+ using ::asinhl;
+
+ using ::atanh;
+ using ::atanhf;
+ using ::atanhl;
+
+ using ::cosh;
+ using ::coshf;
+ using ::coshl;
+
+ using ::sinh;
+ using ::sinhf;
+ using ::sinhl;
+
+ using ::tanh;
+ using ::tanhf;
+ using ::tanhl;
+
+ using ::exp;
+ using ::expf;
+ using ::expl;
+
+ using ::exp2;
+ using ::exp2f;
+ using ::exp2l;
+
+ using ::expm1;
+ using ::expm1f;
+ using ::expm1l;
+
+ using ::frexp;
+ using ::frexpf;
+ using ::frexpl;
+
+ using ::ilogb;
+ using ::ilogbf;
+ using ::ilogbl;
+
+ using ::ldexp;
+ using ::ldexpf;
+ using ::ldexpl;
+
+ using ::log;
+ using ::logf;
+ using ::logl;
+
+ using ::log10;
+ using ::log10f;
+ using ::log10l;
+
+ using ::log1p;
+ using ::log1pf;
+ using ::log1pl;
+
+ using ::log2;
+ using ::log2f;
+ using ::log2l;
+
+ using ::logb;
+ using ::logbf;
+ using ::logbl;
+
+ using ::modf;
+ using ::modff;
+ using ::modfl;
+
+ using ::scalbn;
+ using ::scalbnf;
+ using ::scalbnl;
+
+ using ::scalbln;
+ using ::scalblnf;
+ using ::scalblnl;
+
+ using ::cbrt;
+ using ::cbrtf;
+ using ::cbrtl;
+
+ // [c.math.abs], absolute values
+ using ::abs;
+
+ using ::fabs;
+ using ::fabsf;
+ using ::fabsl;
+
+ using ::hypot;
+ using ::hypotf;
+ using ::hypotl;
+
+ // [c.math.hypot3], three-dimensional hypotenuse
+
+ using ::pow;
+ using ::powf;
+ using ::powl;
+
+ using ::sqrt;
+ using ::sqrtf;
+ using ::sqrtl;
+
+ using ::erf;
+ using ::erff;
+ using ::erfl;
+
+ using ::erfc;
+ using ::erfcf;
+ using ::erfcl;
+
+ using ::lgamma;
+ using ::lgammaf;
+ using ::lgammal;
+
+ using ::tgamma;
+ using ::tgammaf;
+ using ::tgammal;
+
+ using ::ceil;
+ using ::ceilf;
+ using ::ceill;
+
+ using ::floor;
+ using ::floorf;
+ using ::floorl;
+
+ using ::nearbyint;
+ using ::nearbyintf;
+ using ::nearbyintl;
+
+ using ::rint;
+ using ::rintf;
+ using ::rintl;
+
+ using ::lrint;
+ using ::lrintf;
+ using ::lrintl;
+
+ using ::llrint;
+ using ::llrintf;
+ using ::llrintl;
+
+ using ::round;
+ using ::roundf;
+ using ::roundl;
+
+ using ::lround;
+ using ::lroundf;
+ using ::lroundl;
+
+ using ::llround;
+ using ::llroundf;
+ using ::llroundl;
+
+ using ::trunc;
+ using ::truncf;
+ using ::truncl;
+
+ using ::fmod;
+ using ::fmodf;
+ using ::fmodl;
+
+ using ::remainder;
+ using ::remainderf;
+ using ::remainderl;
+
+ using ::remquo;
+ using ::remquof;
+ using ::remquol;
+
+ using ::copysign;
+ using ::copysignf;
+ using ::copysignl;
+
+ using ::nan;
+ using ::nanf;
+ using ::nanl;
+
+ using ::nextafter;
+ using ::nextafterf;
+ using ::nextafterl;
+
+ using ::nexttoward;
+ using ::nexttowardf;
+ using ::nexttowardl;
+
+ using ::fdim;
+ using ::fdimf;
+ using ::fdiml;
+
+ using ::fmax;
+ using ::fmaxf;
+ using ::fmaxl;
+
+ using ::fmin;
+ using ::fminf;
+ using ::fminl;
+
+ using ::fma;
+ using ::fmaf;
+ using ::fmal;
+
+ // [c.math.lerp], linear interpolation
+ // [support.c.headers.other]/1
+ // ... placed within the global namespace scope, except for the functions
+ // described in [sf.cmath], the std::lerp function overloads ([c.math.lerp])
+ // ...
+
+ // [c.math.fpclass], classification / comparison functions
+ using ::fpclassify;
+ using ::isfinite;
+ using ::isgreater;
+ using ::isgreaterequal;
+ using ::isinf;
+ using ::isless;
+ using ::islessequal;
+ using ::islessgreater;
+ using ::isnan;
+ using ::isnormal;
+ using ::isunordered;
+ using ::signbit;
+
+ // [sf.cmath], mathematical special functions
+} // export
+
+// csetjmp.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::jmp_buf;
+ using ::longjmp;
+} // export
+
+// csignal.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::sig_atomic_t;
+
+ // [support.signal], signal handlers
+ using ::signal;
+
+ using ::raise;
+} // export
+
+// cstdarg.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export { using ::va_list; } // export
+
+// cstddef.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::max_align_t;
+ using ::nullptr_t;
+ using ::ptrdiff_t;
+ using ::size_t;
+
+ // [support.c.headers]/1
+ // ... placed within the global namespace scope, except for ... the
+ // declaration of std::byte ([cstddef.syn]), and the functions and
+ // function templates described in [support.types.byteops]. ...
+
+ // [support.types.byteops], byte type operations
+} // export
+
+// cstdint.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ // signed
+ using ::int8_t _LIBCPP_USING_IF_EXISTS;
+ using ::int16_t _LIBCPP_USING_IF_EXISTS;
+ using ::int32_t _LIBCPP_USING_IF_EXISTS;
+ using ::int64_t _LIBCPP_USING_IF_EXISTS;
+
+ using ::int_fast16_t;
+ using ::int_fast32_t;
+ using ::int_fast64_t;
+ using ::int_fast8_t;
+
+ using ::int_least16_t;
+ using ::int_least32_t;
+ using ::int_least64_t;
+ using ::int_least8_t;
+
+ using ::intmax_t;
+
+ using ::intptr_t _LIBCPP_USING_IF_EXISTS;
+
+ // unsigned
+ using ::uint8_t _LIBCPP_USING_IF_EXISTS;
+ using ::uint16_t _LIBCPP_USING_IF_EXISTS;
+ using ::uint32_t _LIBCPP_USING_IF_EXISTS;
+ using ::uint64_t _LIBCPP_USING_IF_EXISTS;
+
+ using ::uint_fast16_t;
+ using ::uint_fast32_t;
+ using ::uint_fast64_t;
+ using ::uint_fast8_t;
+
+ using ::uint_least16_t;
+ using ::uint_least32_t;
+ using ::uint_least64_t;
+ using ::uint_least8_t;
+
+ using ::uintmax_t;
+
+ using ::uintptr_t _LIBCPP_USING_IF_EXISTS;
+} // export
+
+// cstdio.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::FILE;
+ using ::fpos_t;
+ using ::size_t;
+
+ using ::clearerr;
+ using ::fclose;
+ using ::feof;
+ using ::ferror;
+ using ::fflush;
+ using ::fgetc;
+ using ::fgetpos;
+ using ::fgets;
+ using ::fopen;
+ using ::fprintf;
+ using ::fputc;
+ using ::fputs;
+ using ::fread;
+ using ::freopen;
+ using ::fscanf;
+ using ::fseek;
+ using ::fsetpos;
+ using ::ftell;
+ using ::fwrite;
+ using ::getc;
+ using ::getchar;
+ using ::perror;
+ using ::printf;
+ using ::putc;
+ using ::putchar;
+ using ::puts;
+ using ::remove;
+ using ::rename;
+ using ::rewind;
+ using ::scanf;
+ using ::setbuf;
+ using ::setvbuf;
+ using ::snprintf;
+ using ::sprintf;
+ using ::sscanf;
+ using ::tmpfile;
+ using ::tmpnam;
+ using ::ungetc;
+ using ::vfprintf;
+ using ::vfscanf;
+ using ::vprintf;
+ using ::vscanf;
+ using ::vsnprintf;
+ using ::vsprintf;
+ using ::vsscanf;
+
+} // export
+
+// cstdlib.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::div_t;
+ using ::ldiv_t;
+ using ::lldiv_t;
+ using ::size_t;
+
+ // [support.start.term], start and termination
+ using ::_Exit;
+ using ::abort;
+ using ::at_quick_exit _LIBCPP_USING_IF_EXISTS;
+ using ::atexit;
+ using ::exit;
+ using ::quick_exit _LIBCPP_USING_IF_EXISTS;
+
+ using ::getenv;
+ using ::system;
+
+ // [c.malloc], C library memory allocation
+ using ::aligned_alloc _LIBCPP_USING_IF_EXISTS;
+ using ::calloc;
+ using ::free;
+ using ::malloc;
+ using ::realloc;
+
+ using ::atof;
+ using ::atoi;
+ using ::atol;
+ using ::atoll;
+ using ::strtod;
+ using ::strtof;
+ using ::strtol;
+ using ::strtold;
+ using ::strtoll;
+ using ::strtoul;
+ using ::strtoull;
+
+ // [c.mb.wcs], multibyte / wide string and character conversion functions
+ using ::mblen;
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using ::mbstowcs;
+ using ::mbtowc;
+ using ::wcstombs;
+ using ::wctomb;
+#endif
+ // [alg.c.library], C standard library algorithms
+ using ::bsearch;
+ using ::qsort;
+
+ // [c.math.rand], low-quality random number generation
+ using ::rand;
+ using ::srand;
+
+ // [c.math.abs], absolute values
+ using ::abs;
+
+ using ::labs;
+ using ::llabs;
+
+ using ::div;
+ using ::ldiv;
+ using ::lldiv;
+
+} // export
+
+// cstring.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::size_t;
+
+ using ::memchr;
+ using ::memcmp;
+ using ::memcpy;
+ using ::memmove;
+ using ::memset;
+ using ::strcat;
+ using ::strchr;
+ using ::strcmp;
+ using ::strcoll;
+ using ::strcpy;
+ using ::strcspn;
+ using ::strerror;
+ using ::strlen;
+ using ::strncat;
+ using ::strncmp;
+ using ::strncpy;
+ using ::strpbrk;
+ using ::strrchr;
+ using ::strspn;
+ using ::strstr;
+ using ::strtok;
+ using ::strxfrm;
+
+} // export
+
+// ctime.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::clock_t;
+ using ::size_t;
+ using ::time_t;
+
+ using ::timespec;
+ using ::tm;
+
+ using ::asctime;
+ using ::clock;
+ using ::ctime;
+ using ::difftime;
+ using ::gmtime;
+ using ::localtime;
+ using ::mktime;
+ using ::strftime;
+ using ::time;
+ using ::timespec_get _LIBCPP_USING_IF_EXISTS;
+} // export
+
+// cuchar.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ // Note the Standard does not mark these symbols optional, but libc++'s header
+ // does. So this seems strictly not to be conforming.
+
+ // mbstate_t is conditionally here, but always present in cwchar.cppm. To avoid
+ // conflicing declarations omit the using here.
+
+ // size_t is conditionally here, but always present in cstddef.cppm. To avoid
+ // conflicing declarations omit the using here.
+
+#if !defined(_LIBCPP_HAS_NO_C8RTOMB_MBRTOC8)
+ using ::mbrtoc8 _LIBCPP_USING_IF_EXISTS;
+ using ::c8rtomb _LIBCPP_USING_IF_EXISTS;
+#endif
+ using ::mbrtoc16 _LIBCPP_USING_IF_EXISTS;
+ using ::c16rtomb _LIBCPP_USING_IF_EXISTS;
+ using ::mbrtoc32 _LIBCPP_USING_IF_EXISTS;
+ using ::c32rtomb _LIBCPP_USING_IF_EXISTS;
+} // export
+
+// cwchar.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using ::mbstate_t;
+ using ::size_t;
+ using ::wint_t;
+
+ using ::tm;
+
+ using ::btowc;
+ using ::fgetwc;
+ using ::fgetws;
+ using ::fputwc;
+ using ::fputws;
+ using ::fwide;
+ using ::fwprintf;
+ using ::fwscanf;
+ using ::getwc;
+ using ::getwchar;
+ using ::putwc;
+ using ::putwchar;
+ using ::swprintf;
+ using ::swscanf;
+ using ::ungetwc;
+ using ::vfwprintf;
+ using ::vfwscanf;
+ using ::vswprintf;
+ using ::vswscanf;
+ using ::vwprintf;
+ using ::vwscanf;
+ using ::wcscat;
+ using ::wcschr;
+ using ::wcscmp;
+ using ::wcscoll;
+ using ::wcscpy;
+ using ::wcscspn;
+ using ::wcsftime;
+ using ::wcslen;
+ using ::wcsncat;
+ using ::wcsncmp;
+ using ::wcsncpy;
+ using ::wcspbrk;
+ using ::wcsrchr;
+ using ::wcsspn;
+ using ::wcsstr;
+ using ::wcstod;
+ using ::wcstof;
+ using ::wcstok;
+ using ::wcstol;
+ using ::wcstold;
+ using ::wcstoll;
+ using ::wcstoul;
+ using ::wcstoull;
+ using ::wcsxfrm;
+ using ::wctob;
+ using ::wmemchr;
+ using ::wmemcmp;
+ using ::wmemcpy;
+ using ::wmemmove;
+ using ::wmemset;
+ using ::wprintf;
+ using ::wscanf;
+
+ // [c.mb.wcs], multibyte / wide string and character conversion functions
+ using ::mbrlen;
+ using ::mbrtowc;
+ using ::mbsinit;
+ using ::mbsrtowcs;
+ using ::wcrtomb;
+ using ::wcsrtombs;
+#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
+} // export
+
+// cwctype.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using ::wctrans_t;
+ using ::wctype_t;
+ using ::wint_t;
+
+ using ::iswalnum;
+ using ::iswalpha;
+ using ::iswblank;
+ using ::iswcntrl;
+ using ::iswctype;
+ using ::iswdigit;
+ using ::iswgraph;
+ using ::iswlower;
+ using ::iswprint;
+ using ::iswpunct;
+ using ::iswspace;
+ using ::iswupper;
+ using ::iswxdigit;
+ using ::towctrans;
+ using ::towlower;
+ using ::towupper;
+ using ::wctrans;
+ using ::wctype;
+#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
+} // export
diff --git a/libbuild2/cc/std.cppm b/libbuild2/cc/std.cppm
new file mode 100644
index 0000000..575e6a4
--- /dev/null
+++ b/libbuild2/cc/std.cppm
@@ -0,0 +1,6795 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// WARNING, this entire header is generated by
+// utils/generate_libcxx_cppm_in.py
+// DO NOT MODIFY!
+
+module;
+
+#include <__config>
+
+#if _LIBCPP_VERSION < 180000
+#error libc++ version 18.0.0 or later required
+#endif
+
+// The headers of Table 24: C++ library headers [tab:headers.cpp]
+// and the headers of Table 25: C++ headers for C library facilities [tab:headers.cpp.c]
+#include <algorithm>
+#include <any>
+#include <array>
+#if !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER)
+# include <atomic>
+#endif
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+# include <barrier>
+#endif
+#include <bit>
+#include <bitset>
+#include <cassert>
+#include <cctype>
+#include <cerrno>
+#include <cfenv>
+#include <cfloat>
+#include <charconv>
+#include <chrono>
+#include <cinttypes>
+#include <climits>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <clocale>
+#endif
+#include <cmath>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <codecvt>
+#endif
+#include <compare>
+#include <complex>
+#include <concepts>
+#include <condition_variable>
+#include <coroutine>
+#include <csetjmp>
+#include <csignal>
+#include <cstdarg>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <cuchar>
+#if !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)
+# include <cwchar>
+#endif
+#if !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)
+# include <cwctype>
+#endif
+#include <deque>
+#include <exception>
+#include <execution>
+#include <expected>
+#include <filesystem>
+#include <format>
+#include <forward_list>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <fstream>
+#endif
+#include <functional>
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+# include <future>
+#endif
+#include <initializer_list>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <iomanip>
+#endif
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <ios>
+#endif
+#include <iosfwd>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <iostream>
+#endif
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <istream>
+#endif
+#include <iterator>
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+# include <latch>
+#endif
+#include <limits>
+#include <list>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <locale>
+#endif
+#include <map>
+#include <mdspan>
+#include <memory>
+#include <memory_resource>
+#include <mutex>
+#include <new>
+#include <numbers>
+#include <numeric>
+#include <optional>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <ostream>
+#endif
+#include <print>
+#include <queue>
+#include <random>
+#include <ranges>
+#include <ratio>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <regex>
+#endif
+#include <scoped_allocator>
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+# include <semaphore>
+#endif
+#include <set>
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+# include <shared_mutex>
+#endif
+#include <source_location>
+#include <span>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <sstream>
+#endif
+#include <stack>
+#include <stdexcept>
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+# include <stop_token>
+#endif
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <streambuf>
+#endif
+#include <string>
+#include <string_view>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <strstream>
+#endif
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <syncstream>
+#endif
+#include <system_error>
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+# include <thread>
+#endif
+#include <tuple>
+#include <type_traits>
+#include <typeindex>
+#include <typeinfo>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <valarray>
+#include <variant>
+#include <vector>
+#include <version>
+
+#if 0
+// *** Headers not yet available ***
+#if __has_include(<debugging>)
+# error "please update the header information for <debugging> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<debugging>)
+#if __has_include(<flat_map>)
+# error "please update the header information for <flat_map> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<flat_map>)
+#if __has_include(<flat_set>)
+# error "please update the header information for <flat_set> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<flat_set>)
+#if __has_include(<generator>)
+# error "please update the header information for <generator> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<generator>)
+#if __has_include(<hazard_pointer>)
+# error "please update the header information for <hazard_pointer> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<hazard_pointer>)
+#if __has_include(<linalg>)
+# error "please update the header information for <linalg> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<linalg>)
+#if __has_include(<rcu>)
+# error "please update the header information for <rcu> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<rcu>)
+#if __has_include(<spanstream>)
+# error "please update the header information for <spanstream> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<spanstream>)
+#if __has_include(<stacktrace>)
+# error "please update the header information for <stacktrace> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<stacktrace>)
+#if __has_include(<stdfloat>)
+# error "please update the header information for <stdfloat> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<stdfloat>)
+#if __has_include(<text_encoding>)
+# error "please update the header information for <text_encoding> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<text_encoding>)
+#endif
+
+export module std;
+
+// algorithm.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ namespace ranges {
+ // [algorithms.results], algorithm result types
+ using std::ranges::in_found_result;
+ using std::ranges::in_fun_result;
+ using std::ranges::in_in_out_result;
+ using std::ranges::in_in_result;
+ using std::ranges::in_out_out_result;
+ using std::ranges::in_out_result;
+#if _LIBCPP_STD_VER >= 23
+ using std::ranges::in_value_result;
+#endif
+ using std::ranges::min_max_result;
+ // using std::ranges::out_value_result;
+ } // namespace ranges
+
+ // [alg.nonmodifying], non-modifying sequence operations
+ // [alg.all.of], all of
+ using std::all_of;
+ namespace ranges {
+ using std::ranges::all_of;
+ }
+
+ // [alg.any.of], any of
+ using std::any_of;
+ namespace ranges {
+ using std::ranges::any_of;
+ }
+
+ // [alg.none.of], none of
+ using std::none_of;
+ namespace ranges {
+ using std::ranges::none_of;
+ }
+
+#if _LIBCPP_STD_VER >= 23
+ // [alg.contains], contains
+ namespace ranges {
+ using std::ranges::contains;
+#if 0
+ using std::ranges::contains_subrange;
+#endif
+ } // namespace ranges
+#endif // _LIBCPP_STD_VER >= 23
+
+ // [alg.foreach], for each
+ using std::for_each;
+
+ namespace ranges {
+ using std::ranges::for_each;
+ using std::ranges::for_each_result;
+ } // namespace ranges
+
+ using std::for_each_n;
+
+ namespace ranges {
+ using std::ranges::for_each_n_result;
+
+ using std::ranges::for_each_n;
+ } // namespace ranges
+
+ // [alg.find], find
+ using std::find;
+ using std::find_if;
+ using std::find_if_not;
+
+ namespace ranges {
+ using std::ranges::find;
+ using std::ranges::find_if;
+ using std::ranges::find_if_not;
+ } // namespace ranges
+
+ namespace ranges {
+#if 0
+ using std::ranges::find_last;
+ using std::ranges::find_last_if;
+ using std::ranges::find_last_if_not;
+#endif
+ } // namespace ranges
+
+ // [alg.find.end], find end
+ using std::find_end;
+
+ namespace ranges {
+ using std::ranges::find_end;
+ }
+
+ // [alg.find.first.of], find first
+ using std::find_first_of;
+
+ namespace ranges {
+ using std::ranges::find_first_of;
+ }
+
+ // [alg.adjacent.find], adjacent find
+ using std::adjacent_find;
+
+ namespace ranges {
+ using std::ranges::adjacent_find;
+ }
+
+ // [alg.count], count
+ using std::count;
+ using std::count_if;
+
+ namespace ranges {
+ using std::ranges::count;
+ using std::ranges::count_if;
+ } // namespace ranges
+
+ // [mismatch], mismatch
+ using std::mismatch;
+
+ namespace ranges {
+ using std::ranges::mismatch_result;
+
+ using std::ranges::mismatch;
+ } // namespace ranges
+
+ // [alg.equal], equal
+ using std::equal;
+
+ namespace ranges {
+ using std::ranges::equal;
+ }
+
+ // [alg.is.permutation], is permutation
+ using std::is_permutation;
+
+ namespace ranges {
+ using std::ranges::is_permutation;
+ }
+
+ // [alg.search], search
+ using std::search;
+
+ namespace ranges {
+ using std::ranges::search;
+ }
+
+ using std::search_n;
+
+ namespace ranges {
+ using std::ranges::search_n;
+ }
+
+ namespace ranges {
+#if _LIBCPP_STD_VER >= 23
+ // [alg.starts.with], starts with
+ using std::ranges::starts_with;
+
+ // [alg.ends.with], ends with
+ using std::ranges::ends_with;
+
+ // [alg.fold], fold
+ using std::ranges::fold_left;
+ using std::ranges::fold_left_with_iter;
+ using std::ranges::fold_left_with_iter_result;
+# if 0
+ using std::ranges::fold_left_first;
+ using std::ranges::fold_right;
+ using std::ranges::fold_right_last;
+ using std::ranges::fold_left_with_iter;
+ using std::ranges::fold_left_first_with_iter;
+ using std::ranges::fold_left_first_with_iter;
+# endif
+#endif // _LIBCPP_STD_VER >= 23
+ } // namespace ranges
+
+ // [alg.modifying.operations], mutating sequence operations
+ // [alg.copy], copy
+ using std::copy;
+
+ namespace ranges {
+ using std::ranges::copy;
+ using std::ranges::copy_result;
+ } // namespace ranges
+
+ using std::copy_n;
+
+ namespace ranges {
+ using std::ranges::copy_n;
+ using std::ranges::copy_n_result;
+ } // namespace ranges
+
+ using std::copy_if;
+
+ namespace ranges {
+ using std::ranges::copy_if;
+ using std::ranges::copy_if_result;
+ } // namespace ranges
+
+ using std::copy_backward;
+
+ namespace ranges {
+ using std::ranges::copy_backward;
+ using std::ranges::copy_backward_result;
+ } // namespace ranges
+
+ // [alg.move], move
+ using std::move;
+
+ namespace ranges {
+ using std::ranges::move;
+ using std::ranges::move_result;
+ } // namespace ranges
+
+ using std::move_backward;
+
+ namespace ranges {
+ using std::ranges::move_backward;
+ using std::ranges::move_backward_result;
+ } // namespace ranges
+
+ // [alg.swap], swap
+ using std::swap_ranges;
+
+ namespace ranges {
+ using std::ranges::swap_ranges;
+ using std::ranges::swap_ranges_result;
+ } // namespace ranges
+
+ using std::iter_swap;
+
+ // [alg.transform], transform
+ using std::transform;
+
+ namespace ranges {
+ using std::ranges::binary_transform_result;
+ using std::ranges::unary_transform_result;
+
+ using std::ranges::transform;
+
+ } // namespace ranges
+
+ using std::replace;
+ using std::replace_if;
+
+ namespace ranges {
+ using std::ranges::replace;
+ using std::ranges::replace_if;
+ } // namespace ranges
+
+ using std::replace_copy;
+ using std::replace_copy_if;
+
+ namespace ranges {
+ using std::ranges::replace_copy;
+ using std::ranges::replace_copy_if;
+ using std::ranges::replace_copy_if_result;
+ using std::ranges::replace_copy_result;
+ } // namespace ranges
+
+ // [alg.fill], fill
+ using std::fill;
+ using std::fill_n;
+
+ namespace ranges {
+ using std::ranges::fill;
+ using std::ranges::fill_n;
+ } // namespace ranges
+
+ // [alg.generate], generate
+ using std::generate;
+ using std::generate_n;
+
+ namespace ranges {
+ using std::ranges::generate;
+ using std::ranges::generate_n;
+ } // namespace ranges
+
+ // [alg.remove], remove
+ using std::remove;
+ using std::remove_if;
+
+ namespace ranges {
+ using std::ranges::remove;
+ using std::ranges::remove_if;
+ } // namespace ranges
+
+ using std::remove_copy;
+ using std::remove_copy_if;
+ namespace ranges {
+ using std::ranges::remove_copy;
+ using std::ranges::remove_copy_if;
+ using std::ranges::remove_copy_if_result;
+ using std::ranges::remove_copy_result;
+ } // namespace ranges
+
+ // [alg.unique], unique
+ using std::unique;
+
+ namespace ranges {
+ using std::ranges::unique;
+ }
+
+ using std::unique_copy;
+
+ namespace ranges {
+ using std::ranges::unique_copy;
+ using std::ranges::unique_copy_result;
+ } // namespace ranges
+
+ // [alg.reverse], reverse
+ using std::reverse;
+
+ namespace ranges {
+ using std::ranges::reverse;
+ }
+
+ using std::reverse_copy;
+
+ namespace ranges {
+ using std::ranges::reverse_copy;
+ using std::ranges::reverse_copy_result;
+ } // namespace ranges
+
+ // [alg.rotate], rotate
+ using std::rotate;
+
+ namespace ranges {
+ using std::ranges::rotate;
+ }
+
+ using std::rotate_copy;
+
+ namespace ranges {
+ using std::ranges::rotate_copy;
+ using std::ranges::rotate_copy_result;
+ } // namespace ranges
+
+ // [alg.random.sample], sample
+ using std::sample;
+
+ namespace ranges {
+ using std::ranges::sample;
+ }
+
+ // [alg.random.shuffle], shuffle
+ using std::shuffle;
+
+ namespace ranges {
+ using std::ranges::shuffle;
+ }
+
+ // [alg.shift], shift
+ using std::shift_left;
+
+ namespace ranges {
+ // using std::ranges::shift_left;
+ }
+
+ using std::shift_right;
+
+ namespace ranges {
+ // using std::ranges::shift_right;
+ }
+
+ // [alg.sorting], sorting and related operations
+ // [alg.sort], sorting
+ using std::sort;
+
+ namespace ranges {
+ using std::ranges::sort;
+ }
+
+ using std::stable_sort;
+
+ namespace ranges {
+ using std::ranges::stable_sort;
+ }
+
+ using std::partial_sort;
+
+ namespace ranges {
+ using std::ranges::partial_sort;
+ }
+ using std::partial_sort_copy;
+
+ namespace ranges {
+ using std::ranges::partial_sort_copy;
+ using std::ranges::partial_sort_copy_result;
+ } // namespace ranges
+
+ using std::is_sorted;
+ using std::is_sorted_until;
+
+ namespace ranges {
+ using std::ranges::is_sorted;
+ using std::ranges::is_sorted_until;
+ } // namespace ranges
+
+ // [alg.nth.element], Nth element
+ using std::nth_element;
+
+ namespace ranges {
+ using std::ranges::nth_element;
+ }
+
+ // [alg.binary.search], binary search
+ using std::lower_bound;
+
+ namespace ranges {
+ using std::ranges::lower_bound;
+ }
+
+ using std::upper_bound;
+
+ namespace ranges {
+ using std::ranges::upper_bound;
+ }
+
+ using std::equal_range;
+
+ namespace ranges {
+ using std::ranges::equal_range;
+ }
+
+ using std::binary_search;
+
+ namespace ranges {
+ using std::ranges::binary_search;
+ }
+
+ // [alg.partitions], partitions
+ using std::is_partitioned;
+
+ namespace ranges {
+ using std::ranges::is_partitioned;
+ }
+
+ using std::partition;
+
+ namespace ranges {
+ using std::ranges::partition;
+ }
+
+ using std::stable_partition;
+
+ namespace ranges {
+ using std::ranges::stable_partition;
+ }
+
+ using std::partition_copy;
+
+ namespace ranges {
+ using std::ranges::partition_copy;
+ using std::ranges::partition_copy_result;
+ } // namespace ranges
+
+ using std::partition_point;
+
+ namespace ranges {
+ using std::ranges::partition_point;
+ }
+ // [alg.merge], merge
+ using std::merge;
+ namespace ranges {
+ using std::ranges::merge;
+ using std::ranges::merge_result;
+ } // namespace ranges
+
+ using std::inplace_merge;
+
+ namespace ranges {
+ using std::ranges::inplace_merge;
+ }
+
+ // [alg.set.operations], set operations
+ using std::includes;
+ namespace ranges {
+ using std::ranges::includes;
+ }
+
+ using std::set_union;
+
+ namespace ranges {
+ using std::ranges::set_union;
+ using std::ranges::set_union_result;
+ } // namespace ranges
+
+ using std::set_intersection;
+ namespace ranges {
+ using std::ranges::set_intersection;
+ using std::ranges::set_intersection_result;
+ } // namespace ranges
+
+ using std::set_difference;
+
+ namespace ranges {
+ using std::ranges::set_difference;
+ using std::ranges::set_difference_result;
+ } // namespace ranges
+
+ using std::set_symmetric_difference;
+
+ namespace ranges {
+ using std::ranges::set_symmetric_difference_result;
+
+ using std::ranges::set_symmetric_difference;
+ } // namespace ranges
+
+ // [alg.heap.operations], heap operations
+ using std::push_heap;
+
+ namespace ranges {
+ using std::ranges::push_heap;
+ }
+
+ using std::pop_heap;
+
+ namespace ranges {
+ using std::ranges::pop_heap;
+ }
+
+ using std::make_heap;
+
+ namespace ranges {
+ using std::ranges::make_heap;
+ }
+
+ using std::sort_heap;
+
+ namespace ranges {
+ using std::ranges::sort_heap;
+ }
+
+ using std::is_heap;
+
+ namespace ranges {
+ using std::ranges::is_heap;
+ }
+
+ using std::is_heap_until;
+
+ namespace ranges {
+ using std::ranges::is_heap_until;
+ }
+
+ // [alg.min.max], minimum and maximum
+ using std::min;
+
+ namespace ranges {
+ using std::ranges::min;
+ }
+
+ using std::max;
+
+ namespace ranges {
+ using std::ranges::max;
+ }
+
+ using std::minmax;
+
+ namespace ranges {
+ using std::ranges::minmax_result;
+
+ using std::ranges::minmax;
+ } // namespace ranges
+
+ using std::min_element;
+
+ namespace ranges {
+ using std::ranges::min_element;
+ }
+
+ using std::max_element;
+
+ namespace ranges {
+ using std::ranges::max_element;
+ }
+
+ using std::minmax_element;
+
+ namespace ranges {
+ using std::ranges::minmax_element_result;
+
+ using std::ranges::minmax_element;
+ } // namespace ranges
+ // [alg.clamp], bounded value
+ using std::clamp;
+
+ namespace ranges {
+ using std::ranges::clamp;
+ }
+
+ // [alg.lex.comparison], lexicographical comparison
+ using std::lexicographical_compare;
+
+ namespace ranges {
+ using std::ranges::lexicographical_compare;
+ }
+
+ // [alg.three.way], three-way comparison algorithms
+ using std::lexicographical_compare_three_way;
+
+ // [alg.permutation.generators], permutations
+ using std::next_permutation;
+
+ namespace ranges {
+ using std::ranges::next_permutation_result;
+
+ using std::ranges::next_permutation;
+ } // namespace ranges
+
+ using std::prev_permutation;
+
+ namespace ranges {
+ using std::ranges::prev_permutation_result;
+
+ using std::ranges::prev_permutation;
+ } // namespace ranges
+
+} // namespace std
+
+// any.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+
+ // [any.bad.any.cast], class bad_any_cast
+ using std::bad_any_cast;
+
+ // [any.class], class any
+ using std::any;
+
+ // [any.nonmembers], non-member functions
+ using std::any_cast;
+ using std::make_any;
+ using std::swap;
+
+} // namespace std
+
+// array.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+
+ // [array], class template array
+ using std::array;
+
+ using std::operator==;
+ using std::operator<=>;
+
+ // [array.special], specialized algorithms
+ using std::swap;
+
+ // [array.creation], array creation functions
+ using std::to_array;
+
+ // [array.tuple], tuple interface
+ using std::get;
+ using std::tuple_element;
+ using std::tuple_size;
+
+} // namespace std
+
+// atomic.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+
+ // [atomics.order], order and consistency
+ using std::memory_order;
+ using std::memory_order_acq_rel;
+ using std::memory_order_acquire;
+ using std::memory_order_consume;
+ using std::memory_order_relaxed;
+ using std::memory_order_release;
+ using std::memory_order_seq_cst;
+
+ using std::kill_dependency;
+
+ // [atomics.ref.generic], class template atomic_ref
+ // [atomics.ref.pointer], partial specialization for pointers
+ // using std::atomic_ref;
+
+ // [atomics.types.generic], class template atomic
+ using std::atomic;
+
+ // [atomics.nonmembers], non-member functions
+ using std::atomic_compare_exchange_strong;
+ using std::atomic_compare_exchange_strong_explicit;
+ using std::atomic_compare_exchange_weak;
+ using std::atomic_compare_exchange_weak_explicit;
+ using std::atomic_exchange;
+ using std::atomic_exchange_explicit;
+ using std::atomic_is_lock_free;
+ using std::atomic_load;
+ using std::atomic_load_explicit;
+ using std::atomic_store;
+ using std::atomic_store_explicit;
+
+ using std::atomic_fetch_add;
+ using std::atomic_fetch_add_explicit;
+ using std::atomic_fetch_and;
+ using std::atomic_fetch_and_explicit;
+ using std::atomic_fetch_or;
+ using std::atomic_fetch_or_explicit;
+ using std::atomic_fetch_sub;
+ using std::atomic_fetch_sub_explicit;
+ using std::atomic_fetch_xor;
+ using std::atomic_fetch_xor_explicit;
+ using std::atomic_notify_all;
+ using std::atomic_notify_one;
+ using std::atomic_wait;
+ using std::atomic_wait_explicit;
+
+ // [atomics.alias], type aliases
+ using std::atomic_bool;
+ using std::atomic_char;
+ using std::atomic_char16_t;
+ using std::atomic_char32_t;
+#ifndef _LIBCPP_HAS_NO_CHAR8_T
+ using std::atomic_char8_t;
+#endif
+ using std::atomic_int;
+ using std::atomic_llong;
+ using std::atomic_long;
+ using std::atomic_schar;
+ using std::atomic_short;
+ using std::atomic_uchar;
+ using std::atomic_uint;
+ using std::atomic_ullong;
+ using std::atomic_ulong;
+ using std::atomic_ushort;
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::atomic_wchar_t;
+#endif
+
+ using std::atomic_int16_t;
+ using std::atomic_int32_t;
+ using std::atomic_int64_t;
+ using std::atomic_int8_t;
+ using std::atomic_uint16_t;
+ using std::atomic_uint32_t;
+ using std::atomic_uint64_t;
+ using std::atomic_uint8_t;
+
+ using std::atomic_int_least16_t;
+ using std::atomic_int_least32_t;
+ using std::atomic_int_least64_t;
+ using std::atomic_int_least8_t;
+ using std::atomic_uint_least16_t;
+ using std::atomic_uint_least32_t;
+ using std::atomic_uint_least64_t;
+ using std::atomic_uint_least8_t;
+
+ using std::atomic_int_fast16_t;
+ using std::atomic_int_fast32_t;
+ using std::atomic_int_fast64_t;
+ using std::atomic_int_fast8_t;
+ using std::atomic_uint_fast16_t;
+ using std::atomic_uint_fast32_t;
+ using std::atomic_uint_fast64_t;
+ using std::atomic_uint_fast8_t;
+
+ using std::atomic_intmax_t;
+ using std::atomic_intptr_t;
+ using std::atomic_ptrdiff_t;
+ using std::atomic_size_t;
+ using std::atomic_uintmax_t;
+ using std::atomic_uintptr_t;
+
+ using std::atomic_signed_lock_free;
+ using std::atomic_unsigned_lock_free;
+
+ // [atomics.flag], flag type and operations
+ using std::atomic_flag;
+
+ using std::atomic_flag_clear;
+ using std::atomic_flag_clear_explicit;
+ using std::atomic_flag_test;
+ using std::atomic_flag_test_and_set;
+ using std::atomic_flag_test_and_set_explicit;
+ using std::atomic_flag_test_explicit;
+
+ using std::atomic_flag_notify_all;
+ using std::atomic_flag_notify_one;
+ using std::atomic_flag_wait;
+ using std::atomic_flag_wait_explicit;
+
+ // [atomics.fences], fences
+ using std::atomic_signal_fence;
+ using std::atomic_thread_fence;
+
+ // [depr.atomics.nonmembers]
+ using std::atomic_init;
+
+} // namespace std
+
+// barrier.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_THREADS
+ using std::barrier;
+#endif // _LIBCPP_HAS_NO_THREADS
+} // namespace std
+
+// bit.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [bit.cast], bit_cast
+ using std::bit_cast;
+
+#if _LIBCPP_STD_VER >= 23
+ // [bit.byteswap], byteswap
+ using std::byteswap;
+#endif
+
+ // [bit.pow.two], integral powers of 2
+ using std::bit_ceil;
+ using std::bit_floor;
+ using std::bit_width;
+ using std::has_single_bit;
+
+ // [bit.rotate], rotating
+ using std::rotl;
+ using std::rotr;
+
+ // [bit.count], counting
+ using std::countl_one;
+ using std::countl_zero;
+ using std::countr_one;
+ using std::countr_zero;
+ using std::popcount;
+
+ // [bit.endian], endian
+ using std::endian;
+} // namespace std
+
+// bitset.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::bitset;
+
+ // [bitset.operators], bitset operators
+ using std::operator&;
+ using std::operator|;
+ using std::operator^;
+ using std::operator>>;
+ using std::operator<<;
+
+ // [bitset.hash], hash support
+ using std::hash;
+
+} // namespace std
+
+// cassert.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // This module exports nothing.
+} // namespace std
+
+// cctype.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::isalnum;
+ using std::isalpha;
+ using std::isblank;
+ using std::iscntrl;
+ using std::isdigit;
+ using std::isgraph;
+ using std::islower;
+ using std::isprint;
+ using std::ispunct;
+ using std::isspace;
+ using std::isupper;
+ using std::isxdigit;
+ using std::tolower;
+ using std::toupper;
+} // namespace std
+
+// cerrno.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // This module exports nothing.
+} // namespace std
+
+// cfenv.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // types
+ using std::fenv_t;
+ using std::fexcept_t;
+
+ // functions
+ using std::feclearexcept;
+ using std::fegetexceptflag;
+ using std::feraiseexcept;
+ using std::fesetexceptflag;
+ using std::fetestexcept;
+
+ using std::fegetround;
+ using std::fesetround;
+
+ using std::fegetenv;
+ using std::feholdexcept;
+ using std::fesetenv;
+ using std::feupdateenv;
+
+} // namespace std
+
+// cfloat.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // This module exports nothing.
+} // namespace std
+
+// charconv.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+
+ // floating-point format for primitive numerical conversion
+ using std::chars_format;
+
+ // chars_format is a bitmask type.
+ // [bitmask.types] specified operators
+ using std::operator&;
+ using std::operator&=;
+ using std::operator^;
+ using std::operator^=;
+ using std::operator|;
+ using std::operator|=;
+ using std::operator~;
+
+ // [charconv.to.chars], primitive numerical output conversion
+ using std::to_chars_result;
+
+ using std::to_chars;
+
+ // [charconv.from.chars], primitive numerical input conversion
+ using std::from_chars_result;
+
+ using std::from_chars;
+} // namespace std
+
+// chrono.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+
+ namespace chrono {
+ using std::chrono::duration;
+ using std::chrono::time_point;
+
+ } // namespace chrono
+
+ using std::common_type;
+
+ namespace chrono {
+
+ // [time.traits], customization traits
+ using std::chrono::treat_as_floating_point;
+ using std::chrono::treat_as_floating_point_v;
+
+ using std::chrono::duration_values;
+
+ // using std::chrono::is_clock;
+ // using std::chrono::is_clock_v;
+
+ // [time.duration.nonmember], duration arithmetic
+ using std::chrono::operator+;
+ using std::chrono::operator-;
+ using std::chrono::operator*;
+ using std::chrono::operator/;
+ using std::chrono::operator%;
+
+ // [time.duration.comparisons], duration comparisons
+ using std::chrono::operator==;
+ using std::chrono::operator!=;
+ using std::chrono::operator<;
+ using std::chrono::operator>;
+ using std::chrono::operator<=;
+ using std::chrono::operator>=;
+ using std::chrono::operator<=>;
+
+ // [time.duration.cast], conversions
+ using std::chrono::ceil;
+ using std::chrono::duration_cast;
+ using std::chrono::floor;
+ using std::chrono::round;
+
+ // [time.duration.io], duration I/O
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ using std::chrono::operator<<;
+#endif
+ // using std::chrono::from_stream;
+
+ // convenience typedefs
+ using std::chrono::days;
+ using std::chrono::hours;
+ using std::chrono::microseconds;
+ using std::chrono::milliseconds;
+ using std::chrono::minutes;
+ using std::chrono::months;
+ using std::chrono::nanoseconds;
+ using std::chrono::seconds;
+ using std::chrono::weeks;
+ using std::chrono::years;
+
+ // [time.point.nonmember], time_point arithmetic
+
+ // [time.point.comparisons], time_point comparisons
+
+ // [time.point.cast], conversions
+ using std::chrono::time_point_cast;
+
+ // [time.duration.alg], specialized algorithms
+ using std::chrono::abs;
+
+ // [time.clock.system], class system_clock
+ using std::chrono::system_clock;
+
+ using std::chrono::sys_days;
+ using std::chrono::sys_seconds;
+ using std::chrono::sys_time;
+
+#if 0
+ // [time.clock.utc], class utc_clock
+ using std::chrono::utc_clock;
+
+ using std::chrono::utc_seconds;
+ using std::chrono::utc_time;
+
+ using std::chrono::leap_second_info;
+
+ using std::chrono::get_leap_second_info;
+ // [time.clock.tai], class tai_clock
+ using std::chrono::tai_clock;
+
+ using std::chrono::tai_seconds;
+ using std::chrono::tai_time;
+
+ // [time.clock.gps], class gps_clock
+ using std::chrono::gps_clock;
+
+ using std::chrono::gps_seconds;
+ using std::chrono::gps_time;
+#endif
+ // [time.clock.file], type file_clock
+ using std::chrono::file_clock;
+
+ using std::chrono::file_time;
+
+#ifndef _LIBCPP_HAS_NO_MONOTONIC_CLOCK
+ // [time.clock.steady], class steady_clock
+ using std::chrono::steady_clock;
+#endif
+
+ // [time.clock.hires], class high_resolution_clock
+ using std::chrono::high_resolution_clock;
+
+ // [time.clock.local], local time
+ using std::chrono::local_days;
+ using std::chrono::local_seconds;
+ using std::chrono::local_t;
+ using std::chrono::local_time;
+
+ // [time.clock.cast], time_point conversions
+ // using std::chrono::clock_time_conversion;
+
+ // using std::chrono::clock_cast;
+
+ // [time.cal.last], class last_spec
+ using std::chrono::last_spec;
+
+ // [time.cal.day], class day
+ using std::chrono::day;
+
+ // [time.cal.month], class month
+ using std::chrono::month;
+
+ // [time.cal.year], class year
+ using std::chrono::year;
+
+ // [time.cal.wd], class weekday
+ using std::chrono::weekday;
+
+ // [time.cal.wdidx], class weekday_indexed
+ using std::chrono::weekday_indexed;
+
+ // [time.cal.wdlast], class weekday_last
+ using std::chrono::weekday_last;
+
+ // [time.cal.md], class month_day
+ using std::chrono::month_day;
+
+ // [time.cal.mdlast], class month_day_last
+ using std::chrono::month_day_last;
+
+ // [time.cal.mwd], class month_weekday
+ using std::chrono::month_weekday;
+
+ // [time.cal.mwdlast], class month_weekday_last
+ using std::chrono::month_weekday_last;
+
+ // [time.cal.ym], class year_month
+ using std::chrono::year_month;
+
+ // [time.cal.ymd], class year_month_day
+ using std::chrono::year_month_day;
+
+ // [time.cal.ymdlast], class year_month_day_last
+ using std::chrono::year_month_day_last;
+
+ // [time.cal.ymwd], class year_month_weekday
+ using std::chrono::year_month_weekday;
+
+ // [time.cal.ymwdlast], class year_month_weekday_last
+ using std::chrono::year_month_weekday_last;
+
+ // [time.cal.operators], civil calendar conventional syntax operators
+
+ // [time.hms], class template hh_mm_ss
+ using std::chrono::hh_mm_ss;
+
+ // [time.12], 12/24 hour functions
+ using std::chrono::is_am;
+ using std::chrono::is_pm;
+ using std::chrono::make12;
+ using std::chrono::make24;
+
+#if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \
+ !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+
+# ifdef _LIBCPP_ENABLE_EXPERIMENTAL
+ // [time.zone.db], time zone database
+ using std::chrono::tzdb;
+ using std::chrono::tzdb_list;
+
+ // [time.zone.db.access], time zone database access
+ // using std::chrono::current_zone;
+ using std::chrono::get_tzdb;
+ using std::chrono::get_tzdb_list;
+ // using std::chrono::locate_zone;
+
+ // [time.zone.db.remote], remote time zone database support
+ using std::chrono::reload_tzdb;
+ using std::chrono::remote_version;
+
+# endif // !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) &&
+ // !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+
+# if 0
+ // [time.zone.exception], exception classes
+ using std::chrono::ambiguous_local_time;
+ using std::chrono::nonexistent_local_time;
+
+ // [time.zone.info], information classes
+ using std::chrono::sys_info;
+
+ // [time.zone.timezone], class time_zone
+ using std::chrono::choose;
+ using std::chrono::time_zone;
+
+ // [time.zone.zonedtraits], class template zoned_traits
+ using std::chrono::zoned_traits;
+
+ // [time.zone.zonedtime], class template zoned_time
+ using std::chrono::zoned_time;
+
+ using std::chrono::zoned_seconds;
+
+ // [time.zone.leap], leap second support
+ using std::chrono::leap_second;
+
+ // [time.zone.link], class time_zone_link
+ using std::chrono::time_zone_link;
+
+ // [time.format], formatting
+ using std::chrono::local_time_format;
+# endif
+#endif // _LIBCPP_ENABLE_EXPERIMENTAL
+ } // namespace chrono
+
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ using std::formatter;
+#endif // _LIBCPP_HAS_NO_LOCALIZATION
+
+ namespace chrono {
+ // using std::chrono::parse;
+
+ // calendrical constants
+ using std::chrono::last;
+
+ using std::chrono::Friday;
+ using std::chrono::Monday;
+ using std::chrono::Saturday;
+ using std::chrono::Sunday;
+ using std::chrono::Thursday;
+ using std::chrono::Tuesday;
+ using std::chrono::Wednesday;
+
+ using std::chrono::April;
+ using std::chrono::August;
+ using std::chrono::December;
+ using std::chrono::February;
+ using std::chrono::January;
+ using std::chrono::July;
+ using std::chrono::June;
+ using std::chrono::March;
+ using std::chrono::May;
+ using std::chrono::November;
+ using std::chrono::October;
+ using std::chrono::September;
+
+ } // namespace chrono
+
+} // namespace std
+export namespace std::inline literals::inline chrono_literals {
+ // [time.duration.literals], suffixes for duration literals
+ using std::literals::chrono_literals::operator""h;
+ using std::literals::chrono_literals::operator""min;
+ using std::literals::chrono_literals::operator""s;
+ using std::literals::chrono_literals::operator""ms;
+ using std::literals::chrono_literals::operator""us;
+ using std::literals::chrono_literals::operator""ns;
+
+ // [using std::literals::chrono_literals::.cal.day.nonmembers], non-member functions
+ using std::literals::chrono_literals::operator""d;
+
+ // [using std::literals::chrono_literals::.cal.year.nonmembers], non-member functions
+ using std::literals::chrono_literals::operator""y;
+} // namespace std::inline literals::inline chrono_literals
+
+// cinttypes.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::imaxdiv_t;
+
+ using std::imaxabs;
+ using std::imaxdiv;
+ using std::strtoimax;
+ using std::strtoumax;
+ using std::wcstoimax;
+ using std::wcstoumax;
+
+ // abs is conditionally here, but always present in cmath.cppm. To avoid
+ // conflicing declarations omit the using here.
+
+ // div is conditionally here, but always present in cstdlib.cppm. To avoid
+ // conflicing declarations omit the using here.
+} // namespace std
+
+// climits.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // This module exports nothing.
+} // namespace std
+
+// clocale.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ using std::lconv;
+
+ using std::localeconv;
+ using std::setlocale;
+#endif // _LIBCPP_HAS_NO_LOCALIZATION
+} // namespace std
+
+// cmath.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+
+ using std::double_t;
+ using std::float_t;
+
+ using std::acos;
+ using std::acosf;
+ using std::acosl;
+
+ using std::asin;
+ using std::asinf;
+ using std::asinl;
+
+ using std::atan;
+ using std::atanf;
+ using std::atanl;
+
+ using std::atan2;
+ using std::atan2f;
+ using std::atan2l;
+
+ using std::cos;
+ using std::cosf;
+ using std::cosl;
+
+ using std::sin;
+ using std::sinf;
+ using std::sinl;
+
+ using std::tan;
+ using std::tanf;
+ using std::tanl;
+
+ using std::acosh;
+ using std::acoshf;
+ using std::acoshl;
+
+ using std::asinh;
+ using std::asinhf;
+ using std::asinhl;
+
+ using std::atanh;
+ using std::atanhf;
+ using std::atanhl;
+
+ using std::cosh;
+ using std::coshf;
+ using std::coshl;
+
+ using std::sinh;
+ using std::sinhf;
+ using std::sinhl;
+
+ using std::tanh;
+ using std::tanhf;
+ using std::tanhl;
+
+ using std::exp;
+ using std::expf;
+ using std::expl;
+
+ using std::exp2;
+ using std::exp2f;
+ using std::exp2l;
+
+ using std::expm1;
+ using std::expm1f;
+ using std::expm1l;
+
+ using std::frexp;
+ using std::frexpf;
+ using std::frexpl;
+
+ using std::ilogb;
+ using std::ilogbf;
+ using std::ilogbl;
+
+ using std::ldexp;
+ using std::ldexpf;
+ using std::ldexpl;
+
+ using std::log;
+ using std::logf;
+ using std::logl;
+
+ using std::log10;
+ using std::log10f;
+ using std::log10l;
+
+ using std::log1p;
+ using std::log1pf;
+ using std::log1pl;
+
+ using std::log2;
+ using std::log2f;
+ using std::log2l;
+
+ using std::logb;
+ using std::logbf;
+ using std::logbl;
+
+ using std::modf;
+ using std::modff;
+ using std::modfl;
+
+ using std::scalbn;
+ using std::scalbnf;
+ using std::scalbnl;
+
+ using std::scalbln;
+ using std::scalblnf;
+ using std::scalblnl;
+
+ using std::cbrt;
+ using std::cbrtf;
+ using std::cbrtl;
+
+ // [c.math.abs], absolute values
+ using std::abs;
+
+ using std::fabs;
+ using std::fabsf;
+ using std::fabsl;
+
+ using std::hypot;
+ using std::hypotf;
+ using std::hypotl;
+
+ // [c.math.hypot3], three-dimensional hypotenuse
+
+ using std::pow;
+ using std::powf;
+ using std::powl;
+
+ using std::sqrt;
+ using std::sqrtf;
+ using std::sqrtl;
+
+ using std::erf;
+ using std::erff;
+ using std::erfl;
+
+ using std::erfc;
+ using std::erfcf;
+ using std::erfcl;
+
+ using std::lgamma;
+ using std::lgammaf;
+ using std::lgammal;
+
+ using std::tgamma;
+ using std::tgammaf;
+ using std::tgammal;
+
+ using std::ceil;
+ using std::ceilf;
+ using std::ceill;
+
+ using std::floor;
+ using std::floorf;
+ using std::floorl;
+
+ using std::nearbyint;
+ using std::nearbyintf;
+ using std::nearbyintl;
+
+ using std::rint;
+ using std::rintf;
+ using std::rintl;
+
+ using std::lrint;
+ using std::lrintf;
+ using std::lrintl;
+
+ using std::llrint;
+ using std::llrintf;
+ using std::llrintl;
+
+ using std::round;
+ using std::roundf;
+ using std::roundl;
+
+ using std::lround;
+ using std::lroundf;
+ using std::lroundl;
+
+ using std::llround;
+ using std::llroundf;
+ using std::llroundl;
+
+ using std::trunc;
+ using std::truncf;
+ using std::truncl;
+
+ using std::fmod;
+ using std::fmodf;
+ using std::fmodl;
+
+ using std::remainder;
+ using std::remainderf;
+ using std::remainderl;
+
+ using std::remquo;
+ using std::remquof;
+ using std::remquol;
+
+ using std::copysign;
+ using std::copysignf;
+ using std::copysignl;
+
+ using std::nan;
+ using std::nanf;
+ using std::nanl;
+
+ using std::nextafter;
+ using std::nextafterf;
+ using std::nextafterl;
+
+ using std::nexttoward;
+ using std::nexttowardf;
+ using std::nexttowardl;
+
+ using std::fdim;
+ using std::fdimf;
+ using std::fdiml;
+
+ using std::fmax;
+ using std::fmaxf;
+ using std::fmaxl;
+
+ using std::fmin;
+ using std::fminf;
+ using std::fminl;
+
+ using std::fma;
+ using std::fmaf;
+ using std::fmal;
+
+ // [c.math.lerp], linear interpolation
+ using std::lerp;
+
+ // [c.math.fpclass], classification / comparison functions
+ using std::fpclassify;
+ using std::isfinite;
+ using std::isgreater;
+ using std::isgreaterequal;
+ using std::isinf;
+ using std::isless;
+ using std::islessequal;
+ using std::islessgreater;
+ using std::isnan;
+ using std::isnormal;
+ using std::isunordered;
+ using std::signbit;
+
+ // [sf.cmath], mathematical special functions
+#if 0
+ // [sf.cmath.assoc.laguerre], associated Laguerre polynomials
+ using std::assoc_laguerre;
+ using std::assoc_laguerref;
+ using std::assoc_laguerrel;
+
+ // [sf.cmath.assoc.legendre], associated Legendre functions
+ using std::assoc_legendre;
+ using std::assoc_legendref;
+ using std::assoc_legendrel;
+
+ // [sf.cmath.beta], beta function
+ using std::beta;
+ using std::betaf;
+ using std::betal;
+
+ // [sf.cmath.comp.ellint.1], complete elliptic integral of the first kind
+ using std::comp_ellint_1;
+ using std::comp_ellint_1f;
+ using std::comp_ellint_1l;
+
+ // [sf.cmath.comp.ellint.2], complete elliptic integral of the second kind
+ using std::comp_ellint_2;
+ using std::comp_ellint_2f;
+ using std::comp_ellint_2l;
+
+ // [sf.cmath.comp.ellint.3], complete elliptic integral of the third kind
+ using std::comp_ellint_3;
+ using std::comp_ellint_3f;
+ using std::comp_ellint_3l;
+
+ // [sf.cmath.cyl.bessel.i], regular modified cylindrical Bessel functions
+ using std::cyl_bessel_i;
+ using std::cyl_bessel_if;
+ using std::cyl_bessel_il;
+
+ // [sf.cmath.cyl.bessel.j], cylindrical Bessel functions of the first kind
+ using std::cyl_bessel_j;
+ using std::cyl_bessel_jf;
+ using std::cyl_bessel_jl;
+
+ // [sf.cmath.cyl.bessel.k], irregular modified cylindrical Bessel functions
+ using std::cyl_bessel_k;
+ using std::cyl_bessel_kf;
+ using std::cyl_bessel_kl;
+
+ // [sf.cmath.cyl.neumann], cylindrical Neumann functions
+ // cylindrical Bessel functions of the second kind
+ using std::cyl_neumann;
+ using std::cyl_neumannf;
+ using std::cyl_neumannl;
+
+ // [sf.cmath.ellint.1], incomplete elliptic integral of the first kind
+ using std::ellint_1;
+ using std::ellint_1f;
+ using std::ellint_1l;
+
+ // [sf.cmath.ellint.2], incomplete elliptic integral of the second kind
+ using std::ellint_2;
+ using std::ellint_2f;
+ using std::ellint_2l;
+
+ // [sf.cmath.ellint.3], incomplete elliptic integral of the third kind
+ using std::ellint_3;
+ using std::ellint_3f;
+ using std::ellint_3l;
+
+ // [sf.cmath.expint], exponential integral
+ using std::expint;
+ using std::expintf;
+ using std::expintl;
+
+ // [sf.cmath.hermite], Hermite polynomials
+ using std::hermite;
+ using std::hermitef;
+ using std::hermitel;
+
+ // [sf.cmath.laguerre], Laguerre polynomials
+ using std::laguerre;
+ using std::laguerref;
+ using std::laguerrel;
+
+ // [sf.cmath.legendre], Legendre polynomials
+ using std::legendre;
+ using std::legendref;
+ using std::legendrel;
+
+ // [sf.cmath.riemann.zeta], Riemann zeta function
+ using std::riemann_zeta;
+ using std::riemann_zetaf;
+ using std::riemann_zetal;
+
+ // [sf.cmath.sph.bessel], spherical Bessel functions of the first kind
+ using std::sph_bessel;
+ using std::sph_besself;
+ using std::sph_bessell;
+
+ // [sf.cmath.sph.legendre], spherical associated Legendre functions
+ using std::sph_legendre;
+ using std::sph_legendref;
+ using std::sph_legendrel;
+
+ // [sf.cmath.sph.neumann], spherical Neumann functions;
+ // spherical Bessel functions of the second kind
+ using std::sph_neumann;
+ using std::sph_neumannf;
+ using std::sph_neumannl;
+#endif
+} // namespace std
+
+// codecvt.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+# if _LIBCPP_STD_VER < 26 || defined(_LIBCPP_ENABLE_CXX26_REMOVED_CODECVT)
+ using std::codecvt_mode;
+
+ using std::codecvt_utf16;
+ using std::codecvt_utf8;
+ using std::codecvt_utf8_utf16;
+# endif // _LIBCPP_STD_VER < 26 || defined(_LIBCPP_ENABLE_CXX26_REMOVED_CODECVT)
+#endif // _LIBCPP_HAS_NO_LOCALIZATION
+} // namespace std
+
+// compare.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+
+ // [cmp.categories], comparison category types
+ using std::partial_ordering;
+ using std::strong_ordering;
+ using std::weak_ordering;
+
+ // named comparison functions
+ using std::is_eq;
+ using std::is_gt;
+ using std::is_gteq;
+ using std::is_lt;
+ using std::is_lteq;
+ using std::is_neq;
+
+ // [cmp.common], common comparison category type
+ using std::common_comparison_category;
+ using std::common_comparison_category_t;
+
+ // [cmp.concept], concept three_way_comparable
+ using std::three_way_comparable;
+ using std::three_way_comparable_with;
+
+ // [cmp.result], result of three-way comparison
+ using std::compare_three_way_result;
+
+ using std::compare_three_way_result_t;
+
+ // [comparisons.three.way], class compare_three_way
+ using std::compare_three_way;
+
+ // [cmp.alg], comparison algorithms
+ inline namespace __cpo {
+ using std::__cpo::compare_partial_order_fallback;
+ using std::__cpo::compare_strong_order_fallback;
+ using std::__cpo::compare_weak_order_fallback;
+ using std::__cpo::partial_order;
+ using std::__cpo::strong_order;
+ using std::__cpo::weak_order;
+ } // namespace __cpo
+
+} // namespace std
+
+// complex.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+
+ // [complex], class template complex
+ using std::complex;
+
+ // [complex.ops], operators
+ using std::operator+;
+ using std::operator-;
+ using std::operator*;
+ using std::operator/;
+
+ using std::operator==;
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ using std::operator>>;
+ using std::operator<<;
+#endif // _LIBCPP_HAS_NO_LOCALIZATION
+
+ // [complex.value.ops], values
+ using std::imag;
+ using std::real;
+
+ using std::abs;
+ using std::arg;
+ using std::norm;
+
+ using std::conj;
+ using std::polar;
+ using std::proj;
+
+ // [complex.transcendentals], transcendentals
+ using std::acos;
+ using std::asin;
+ using std::atan;
+
+ using std::acosh;
+ using std::asinh;
+ using std::atanh;
+
+ using std::cos;
+ using std::cosh;
+ using std::exp;
+ using std::log;
+ using std::log10;
+
+ using std::pow;
+
+ using std::sin;
+ using std::sinh;
+ using std::sqrt;
+ using std::tan;
+ using std::tanh;
+
+ // [complex.literals], complex literals
+ inline namespace literals {
+ inline namespace complex_literals {
+ using std::operator""il;
+ using std::operator""i;
+ using std::operator""if;
+ } // namespace complex_literals
+ } // namespace literals
+
+} // namespace std
+
+// concepts.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+
+ // [concepts.lang], language-related concepts
+ // [concept.same], concept same_as
+ using std::same_as;
+
+ // [concept.derived], concept derived_from
+ using std::derived_from;
+
+ // [concept.convertible], concept convertible_to
+ using std::convertible_to;
+
+ // [concept.commonref], concept common_reference_with
+ using std::common_reference_with;
+
+ // [concept.common], concept common_with
+ using std::common_with;
+
+ // [concepts.arithmetic], arithmetic concepts
+ using std::floating_point;
+ using std::integral;
+ using std::signed_integral;
+ using std::unsigned_integral;
+
+ // [concept.assignable], concept assignable_from
+ using std::assignable_from;
+
+ // [concept.swappable], concept swappable
+ namespace ranges {
+ inline namespace __cpo {
+ using std::ranges::__cpo::swap;
+ }
+ } // namespace ranges
+
+ using std::swappable;
+ using std::swappable_with;
+
+ // [concept.destructible], concept destructible
+ using std::destructible;
+
+ // [concept.constructible], concept constructible_from
+ using std::constructible_from;
+
+ // [concept.default.init], concept default_initializable
+ using std::default_initializable;
+
+ // [concept.moveconstructible], concept move_constructible
+ using std::move_constructible;
+
+ // [concept.copyconstructible], concept copy_constructible
+ using std::copy_constructible;
+
+ // [concepts.compare], comparison concepts
+ // [concept.equalitycomparable], concept equality_comparable
+ using std::equality_comparable;
+ using std::equality_comparable_with;
+
+ // [concept.totallyordered], concept totally_ordered
+ using std::totally_ordered;
+ using std::totally_ordered_with;
+
+ // [concepts.object], object concepts
+ using std::copyable;
+ using std::movable;
+ using std::regular;
+ using std::semiregular;
+
+ // [concepts.callable], callable concepts
+ // [concept.invocable], concept invocable
+ using std::invocable;
+
+ // [concept.regularinvocable], concept regular_invocable
+ using std::regular_invocable;
+
+ // [concept.predicate], concept predicate
+ using std::predicate;
+
+ // [concept.relation], concept relation
+ using std::relation;
+
+ // [concept.equiv], concept equivalence_relation
+ using std::equivalence_relation;
+
+ // [concept.strictweakorder], concept strict_weak_order
+ using std::strict_weak_order;
+
+} // namespace std
+
+// condition_variable.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_THREADS
+ // [thread.condition.condvar], class condition_variable
+ using std::condition_variable;
+ // [thread.condition.condvarany], class condition_variable_any
+ using std::condition_variable_any;
+
+ // [thread.condition.nonmember], non-member functions
+ using std::notify_all_at_thread_exit;
+
+ using std::cv_status;
+#endif // _LIBCPP_HAS_NO_THREADS
+} // namespace std
+
+// coroutine.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+
+ // [coroutine.traits], coroutine traits
+ using std::coroutine_traits;
+
+ // [coroutine.handle], coroutine handle
+ using std::coroutine_handle;
+
+ // [coroutine.handle.compare], comparison operators
+ using std::operator==;
+ using std::operator<=>;
+
+ // [coroutine.handle.hash], hash support
+ using std::hash;
+
+ // [coroutine.noop], no-op coroutines
+ using std::noop_coroutine;
+ using std::noop_coroutine_handle;
+ using std::noop_coroutine_promise;
+
+ // [coroutine.trivial.awaitables], trivial awaitables
+ using std::suspend_always;
+ using std::suspend_never;
+} // namespace std
+
+// csetjmp.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::jmp_buf;
+ using std::longjmp;
+} // namespace std
+
+// csignal.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::sig_atomic_t;
+
+ // [support.signal], signal handlers
+ using std::signal;
+
+ using std::raise;
+
+} // namespace std
+
+// cstdarg.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::va_list;
+} // namespace std
+
+// cstddef.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::max_align_t;
+ using std::nullptr_t;
+ using std::ptrdiff_t;
+ using std::size_t;
+
+ using std::byte;
+
+ // [support.types.byteops], byte type operations
+ using std::operator<<=;
+ using std::operator<<;
+ using std::operator>>=;
+ using std::operator>>;
+ using std::operator|=;
+ using std::operator|;
+ using std::operator&=;
+ using std::operator&;
+ using std::operator^=;
+ using std::operator^;
+ using std::operator~;
+ using std::to_integer;
+} // namespace std
+
+// cstdint.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // signed
+ using std::int8_t _LIBCPP_USING_IF_EXISTS;
+ using std::int16_t _LIBCPP_USING_IF_EXISTS;
+ using std::int32_t _LIBCPP_USING_IF_EXISTS;
+ using std::int64_t _LIBCPP_USING_IF_EXISTS;
+
+ using std::int_fast16_t;
+ using std::int_fast32_t;
+ using std::int_fast64_t;
+ using std::int_fast8_t;
+
+ using std::int_least16_t;
+ using std::int_least32_t;
+ using std::int_least64_t;
+ using std::int_least8_t;
+
+ using std::intmax_t;
+
+ using std::intptr_t _LIBCPP_USING_IF_EXISTS;
+
+ // unsigned
+ using std::uint8_t _LIBCPP_USING_IF_EXISTS;
+ using std::uint16_t _LIBCPP_USING_IF_EXISTS;
+ using std::uint32_t _LIBCPP_USING_IF_EXISTS;
+ using std::uint64_t _LIBCPP_USING_IF_EXISTS;
+
+ using std::uint_fast16_t;
+ using std::uint_fast32_t;
+ using std::uint_fast64_t;
+ using std::uint_fast8_t;
+
+ using std::uint_least16_t;
+ using std::uint_least32_t;
+ using std::uint_least64_t;
+ using std::uint_least8_t;
+
+ using std::uintmax_t;
+
+ using std::uintptr_t _LIBCPP_USING_IF_EXISTS;
+} // namespace std
+
+// cstdio.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::FILE;
+ using std::fpos_t;
+ using std::size_t;
+
+ using std::clearerr;
+ using std::fclose;
+ using std::feof;
+ using std::ferror;
+ using std::fflush;
+ using std::fgetc;
+ using std::fgetpos;
+ using std::fgets;
+ using std::fopen;
+ using std::fprintf;
+ using std::fputc;
+ using std::fputs;
+ using std::fread;
+ using std::freopen;
+ using std::fscanf;
+ using std::fseek;
+ using std::fsetpos;
+ using std::ftell;
+ using std::fwrite;
+ using std::getc;
+ using std::getchar;
+ using std::perror;
+ using std::printf;
+ using std::putc;
+ using std::putchar;
+ using std::puts;
+ using std::remove;
+ using std::rename;
+ using std::rewind;
+ using std::scanf;
+ using std::setbuf;
+ using std::setvbuf;
+ using std::snprintf;
+ using std::sprintf;
+ using std::sscanf;
+ using std::tmpfile;
+ using std::tmpnam;
+ using std::ungetc;
+ using std::vfprintf;
+ using std::vfscanf;
+ using std::vprintf;
+ using std::vscanf;
+ using std::vsnprintf;
+ using std::vsprintf;
+ using std::vsscanf;
+} // namespace std
+
+// cstdlib.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::div_t;
+ using std::ldiv_t;
+ using std::lldiv_t;
+ using std::size_t;
+
+ // [support.start.term], start and termination
+ using std::_Exit;
+ using std::abort;
+ using std::at_quick_exit;
+ using std::atexit;
+ using std::exit;
+ using std::quick_exit;
+
+ using std::getenv;
+ using std::system;
+
+ // [c.malloc], C library memory allocation
+ using std::aligned_alloc;
+ using std::calloc;
+ using std::free;
+ using std::malloc;
+ using std::realloc;
+
+ using std::atof;
+ using std::atoi;
+ using std::atol;
+ using std::atoll;
+ using std::strtod;
+ using std::strtof;
+ using std::strtol;
+ using std::strtold;
+ using std::strtoll;
+ using std::strtoul;
+ using std::strtoull;
+
+ // [c.mb.wcs], multibyte / wide string and character conversion functions
+ using std::mblen;
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::mbstowcs;
+ using std::mbtowc;
+ using std::wcstombs;
+ using std::wctomb;
+#endif
+ // [alg.c.library], C standard library algorithms
+ using std::bsearch;
+ using std::qsort;
+
+ // [c.math.rand], low-quality random number generation
+ using std::rand;
+ using std::srand;
+
+ // [c.math.abs], absolute values
+ using std::abs;
+
+ using std::labs;
+ using std::llabs;
+
+ using std::div;
+ using std::ldiv;
+ using std::lldiv;
+} // namespace std
+
+// cstring.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::size_t;
+
+ using std::memchr;
+ using std::memcmp;
+ using std::memcpy;
+ using std::memmove;
+ using std::memset;
+ using std::strcat;
+ using std::strchr;
+ using std::strcmp;
+ using std::strcoll;
+ using std::strcpy;
+ using std::strcspn;
+ using std::strerror;
+ using std::strlen;
+ using std::strncat;
+ using std::strncmp;
+ using std::strncpy;
+ using std::strpbrk;
+ using std::strrchr;
+ using std::strspn;
+ using std::strstr;
+ using std::strtok;
+ using std::strxfrm;
+} // namespace std
+
+// ctime.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::clock_t;
+ using std::size_t;
+ using std::time_t;
+
+ using std::timespec;
+ using std::tm;
+
+ using std::asctime;
+ using std::clock;
+ using std::ctime;
+ using std::difftime;
+ using std::gmtime;
+ using std::localtime;
+ using std::mktime;
+ using std::strftime;
+ using std::time;
+ using std::timespec_get _LIBCPP_USING_IF_EXISTS;
+} // namespace std
+
+// cuchar.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // Note the Standard does not mark these symbols optional, but libc++'s header
+ // does. So this seems strictly not to be conforming.
+
+ // mbstate_t is conditionally here, but always present in cwchar.cppm. To avoid
+ // conflicing declarations omit the using here.
+
+ // size_t is conditionally here, but always present in cstddef.cppm. To avoid
+ // conflicing declarations omit the using here.
+
+#if !defined(_LIBCPP_HAS_NO_C8RTOMB_MBRTOC8)
+ using std::mbrtoc8 _LIBCPP_USING_IF_EXISTS;
+ using std::c8rtomb _LIBCPP_USING_IF_EXISTS;
+#endif
+ using std::mbrtoc16 _LIBCPP_USING_IF_EXISTS;
+ using std::c16rtomb _LIBCPP_USING_IF_EXISTS;
+ using std::mbrtoc32 _LIBCPP_USING_IF_EXISTS;
+ using std::c32rtomb _LIBCPP_USING_IF_EXISTS;
+} // namespace std
+
+// cwchar.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::mbstate_t;
+ using std::size_t;
+ using std::wint_t;
+
+ using std::tm;
+
+ using std::btowc;
+ using std::fgetwc;
+ using std::fgetws;
+ using std::fputwc;
+ using std::fputws;
+ using std::fwide;
+ using std::fwprintf;
+ using std::fwscanf;
+ using std::getwc;
+ using std::getwchar;
+ using std::putwc;
+ using std::putwchar;
+ using std::swprintf;
+ using std::swscanf;
+ using std::ungetwc;
+ using std::vfwprintf;
+ using std::vfwscanf;
+ using std::vswprintf;
+ using std::vswscanf;
+ using std::vwprintf;
+ using std::vwscanf;
+ using std::wcscat;
+ using std::wcschr;
+ using std::wcscmp;
+ using std::wcscoll;
+ using std::wcscpy;
+ using std::wcscspn;
+ using std::wcsftime;
+ using std::wcslen;
+ using std::wcsncat;
+ using std::wcsncmp;
+ using std::wcsncpy;
+ using std::wcspbrk;
+ using std::wcsrchr;
+ using std::wcsspn;
+ using std::wcsstr;
+ using std::wcstod;
+ using std::wcstof;
+ using std::wcstok;
+ using std::wcstol;
+ using std::wcstold;
+ using std::wcstoll;
+ using std::wcstoul;
+ using std::wcstoull;
+ using std::wcsxfrm;
+ using std::wctob;
+ using std::wmemchr;
+ using std::wmemcmp;
+ using std::wmemcpy;
+ using std::wmemmove;
+ using std::wmemset;
+ using std::wprintf;
+ using std::wscanf;
+
+ // [c.mb.wcs], multibyte / wide string and character conversion functions
+ using std::mbrlen;
+ using std::mbrtowc;
+ using std::mbsinit;
+ using std::mbsrtowcs;
+ using std::wcrtomb;
+ using std::wcsrtombs;
+#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
+} // namespace std
+
+// cwctype.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wctrans_t;
+ using std::wctype_t;
+ using std::wint_t;
+
+ using std::iswalnum;
+ using std::iswalpha;
+ using std::iswblank;
+ using std::iswcntrl;
+ using std::iswctype;
+ using std::iswdigit;
+ using std::iswgraph;
+ using std::iswlower;
+ using std::iswprint;
+ using std::iswpunct;
+ using std::iswspace;
+ using std::iswupper;
+ using std::iswxdigit;
+ using std::towctrans;
+ using std::towlower;
+ using std::towupper;
+ using std::wctrans;
+ using std::wctype;
+#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
+} // namespace std
+
+// deque.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [deque], class template deque
+ using std::deque;
+
+ using std::operator==;
+ using std::operator<=>;
+
+ using std::swap;
+
+ // [deque.erasure], erasure
+ using std::erase;
+ using std::erase_if;
+
+ namespace pmr {
+ using std::pmr::deque;
+ }
+} // namespace std
+
+// exception.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::bad_exception;
+ using std::current_exception;
+ using std::exception;
+ using std::exception_ptr;
+ using std::get_terminate;
+ using std::make_exception_ptr;
+ using std::nested_exception;
+ using std::rethrow_exception;
+ using std::rethrow_if_nested;
+ using std::set_terminate;
+ using std::terminate;
+ using std::terminate_handler;
+ using std::throw_with_nested;
+ using std::uncaught_exception;
+ using std::uncaught_exceptions;
+} // namespace std
+
+// execution.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifdef _LIBCPP_ENABLE_EXPERIMENTAL
+export namespace std {
+ // [execpol.type], execution policy type trait
+ using std::is_execution_policy;
+ using std::is_execution_policy_v;
+} // namespace std
+
+export namespace std::execution {
+ // [execpol.seq], sequenced execution policy
+ using std::execution::sequenced_policy;
+
+ // [execpol.par], parallel execution policy
+ using std::execution::parallel_policy;
+
+ // [execpol.parunseq], parallel and unsequenced execution policy
+ using std::execution::parallel_unsequenced_policy;
+
+ // [execpol.unseq], unsequenced execution policy
+ using std::execution::unsequenced_policy;
+
+ // [execpol.objects], execution policy objects
+ using std::execution::par;
+ using std::execution::par_unseq;
+ using std::execution::seq;
+ using std::execution::unseq;
+} // namespace std::execution
+#endif // _LIBCPP_ENABLE_EXPERIMENTAL
+
+// expected.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#if _LIBCPP_STD_VER >= 23
+ // [expected.unexpected], class template unexpected
+ using std::unexpected;
+
+ // [expected.bad], class template bad_expected_access
+ using std::bad_expected_access;
+
+ // in-place construction of unexpected values
+ using std::unexpect;
+ using std::unexpect_t;
+
+ // [expected.expected], class template expected
+ using std::expected;
+#endif // _LIBCPP_STD_VER >= 23
+} // namespace std
+
+// filesystem.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std::filesystem {
+ // [fs.class.path], paths
+ using std::filesystem::path;
+
+ // [fs.path.nonmember], path non-member functions
+ using std::filesystem::hash_value;
+ using std::filesystem::swap;
+
+ // [fs.class.filesystem.error], filesystem errors
+ using std::filesystem::filesystem_error;
+
+#ifndef _LIBCPP_HAS_NO_FILESYSTEM
+ // [fs.class.directory.entry], directory entries
+ using std::filesystem::directory_entry;
+
+ // [fs.class.directory.iterator], directory iterators
+ using std::filesystem::directory_iterator;
+
+ // [fs.dir.itr.nonmembers], range access for directory iterators
+ using std::filesystem::begin;
+ using std::filesystem::end;
+
+ // [fs.class.rec.dir.itr], recursive directory iterators
+ using std::filesystem::recursive_directory_iterator;
+#endif // _LIBCPP_HAS_NO_FILESYSTEM
+
+ // [fs.rec.dir.itr.nonmembers], range access for recursive directory iterators
+
+ // [fs.class.file.status], file status
+ using std::filesystem::file_status;
+ using std::filesystem::space_info;
+
+ // [fs.enum], enumerations
+ using std::filesystem::copy_options;
+ using std::filesystem::directory_options;
+ using std::filesystem::file_type;
+ using std::filesystem::perm_options;
+ using std::filesystem::perms;
+
+ using std::filesystem::file_time_type;
+
+ // several of these enums are a bitmask type.
+ // [bitmask.types] specified operators
+ using std::filesystem::operator&;
+ using std::filesystem::operator&=;
+ using std::filesystem::operator^;
+ using std::filesystem::operator^=;
+ using std::filesystem::operator|;
+ using std::filesystem::operator|=;
+ using std::filesystem::operator~;
+
+#ifndef _LIBCPP_HAS_NO_FILESYSTEM
+ // [fs.op.funcs], filesystem operations
+ using std::filesystem::absolute;
+ using std::filesystem::canonical;
+ using std::filesystem::copy;
+ using std::filesystem::copy_file;
+ using std::filesystem::copy_symlink;
+ using std::filesystem::create_directories;
+ using std::filesystem::create_directory;
+ using std::filesystem::create_directory_symlink;
+ using std::filesystem::create_hard_link;
+ using std::filesystem::create_symlink;
+ using std::filesystem::current_path;
+ using std::filesystem::equivalent;
+ using std::filesystem::exists;
+ using std::filesystem::file_size;
+ using std::filesystem::hard_link_count;
+
+ using std::filesystem::is_block_file;
+ using std::filesystem::is_character_file;
+ using std::filesystem::is_directory;
+ using std::filesystem::is_empty;
+ using std::filesystem::is_fifo;
+ using std::filesystem::is_other;
+ using std::filesystem::is_regular_file;
+ using std::filesystem::is_socket;
+ using std::filesystem::is_symlink;
+
+ using std::filesystem::last_write_time;
+ using std::filesystem::permissions;
+ using std::filesystem::proximate;
+ using std::filesystem::read_symlink;
+ using std::filesystem::relative;
+ using std::filesystem::remove;
+
+ using std::filesystem::remove_all;
+ using std::filesystem::rename;
+ using std::filesystem::resize_file;
+ using std::filesystem::space;
+ using std::filesystem::status;
+ using std::filesystem::status_known;
+ using std::filesystem::symlink_status;
+ using std::filesystem::temp_directory_path;
+ using std::filesystem::weakly_canonical;
+#endif // _LIBCPP_HAS_NO_FILESYSTEM
+
+ // [depr.fs.path.factory]
+ using std::filesystem::u8path;
+} // namespace std::filesystem
+
+// [fs.path.hash], hash support
+export namespace std {
+ using std::hash;
+}
+
+export namespace std::ranges {
+#ifndef _LIBCPP_HAS_NO_FILESYSTEM
+ using std::ranges::enable_borrowed_range;
+ using std::ranges::enable_view;
+#endif // _LIBCPP_HAS_NO_FILESYSTEM
+} // namespace std::ranges
+
+// flat_map.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#if 0
+ // [flat.map], class template flat_­map
+ using std::flat_map;
+
+ using std::sorted_unique;
+ using std::sorted_unique_t;
+
+ using std::uses_allocator;
+
+ // [flat.map.erasure], erasure for flat_­map
+ using std::erase_if;
+
+ // [flat.multimap], class template flat_­multimap
+ using std::flat_multimap;
+
+ using std::sorted_equivalent;
+ using std::sorted_equivalent_t;
+
+ // [flat.multimap.erasure], erasure for flat_­multimap
+#endif
+} // namespace std
+
+// flat_set.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#if 0
+ // [flat.set], class template flat_­set
+ using std::flat_set;
+
+ using std::sorted_unique;
+ using std::sorted_unique_t;
+
+ using std::uses_allocator;
+
+ // [flat.set.erasure], erasure for flat_­set
+ using std::erase_if;
+
+ // [flat.multiset], class template flat_­multiset
+ using std::flat_multiset;
+
+ using std::sorted_equivalent;
+ using std::sorted_equivalent_t;
+#endif
+} // namespace std
+
+// format.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [format.context], class template basic_format_context
+ using std::basic_format_context;
+ using std::format_context;
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wformat_context;
+#endif
+
+ // [format.args], class template basic_format_args
+ using std::basic_format_args;
+ using std::format_args;
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wformat_args;
+#endif
+
+ // [format.fmt.string], class template basic_format_string
+ using std::basic_format_string;
+ using std::format_string;
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wformat_string;
+#endif
+#if _LIBCPP_STD_VER >= 26
+ using std::runtime_format;
+#endif //_LIBCPP_STD_VER >= 26
+
+ // [format.functions], formatting functions
+ using std::format;
+ using std::format_to;
+ using std::vformat;
+ using std::vformat_to;
+
+ using std::format_to_n;
+ using std::format_to_n_result;
+ using std::formatted_size;
+
+ // [format.formatter], formatter
+ using std::formatter;
+
+#if _LIBCPP_STD_VER >= 23
+ // [format.formattable], concept formattable
+ using std::formattable;
+#endif
+
+ // [format.parse.ctx], class template basic_format_parse_context
+ using std::basic_format_parse_context;
+ using std::format_parse_context;
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wformat_parse_context;
+#endif
+
+#if _LIBCPP_STD_VER >= 23
+ // [format.range], formatting of ranges
+ // [format.range.fmtkind], variable template format_kind
+ using std::format_kind;
+ using std::range_format;
+
+ // [format.range.formatter], class template range_formatter
+ using std::range_formatter;
+#endif // _LIBCPP_STD_VER >= 23
+
+ // [format.arg], class template basic_format_arg
+ using std::basic_format_arg;
+ using std::visit_format_arg;
+
+ // [format.arg.store], class template format-arg-store
+ using std::make_format_args;
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::make_wformat_args;
+#endif
+
+ // [format.error], class format_error
+ using std::format_error;
+} // namespace std
+
+// forward_list.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [forward.list], class template forward_list
+ using std::forward_list;
+
+ using std::operator==;
+ using std::operator<=>;
+
+ using std::swap;
+
+ // [forward.list.erasure], erasure
+ using std::erase;
+ using std::erase_if;
+
+ namespace pmr {
+ using std::pmr::forward_list;
+ }
+} // namespace std
+
+// fstream.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ using std::basic_filebuf;
+
+# ifndef _LIBCPP_HAS_NO_FILESYSTEM
+ using std::swap;
+# endif
+
+ using std::filebuf;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wfilebuf;
+# endif
+
+ using std::basic_ifstream;
+
+ using std::ifstream;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wifstream;
+# endif
+
+ using std::basic_ofstream;
+
+ using std::ofstream;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wofstream;
+# endif
+
+ using std::basic_fstream;
+
+ using std::fstream;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wfstream;
+# endif
+#endif // _LIBCPP_HAS_NO_LOCALIZATION
+} // namespace std
+
+// functional.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [func.invoke], invoke
+ using std::invoke;
+#if _LIBCPP_STD_VER >= 23
+ using std::invoke_r;
+#endif
+
+ // [refwrap], reference_wrapper
+ using std::reference_wrapper;
+
+ using std::cref;
+ using std::ref;
+
+ // [arithmetic.operations], arithmetic operations
+ using std::divides;
+ using std::minus;
+ using std::modulus;
+ using std::multiplies;
+ using std::negate;
+ using std::plus;
+ // [comparisons], comparisons
+ using std::equal_to;
+ using std::greater;
+ using std::greater_equal;
+ using std::less;
+ using std::less_equal;
+ using std::not_equal_to;
+
+ // [comparisons.three.way], class compare_three_way
+ using std::compare_three_way;
+
+ // [logical.operations], logical operations
+ using std::logical_and;
+ using std::logical_not;
+ using std::logical_or;
+
+ // [bitwise.operations], bitwise operations
+ using std::bit_and;
+ using std::bit_not;
+ using std::bit_or;
+ using std::bit_xor;
+
+ // [func.identity], identity
+ using std::identity;
+
+ // [func.not.fn], function template not_fn
+ using std::not_fn;
+
+ // [func.bind.partial], function templates bind_front and bind_back
+ // using std::bind_back;
+ using std::bind_front;
+
+ // [func.bind], bind
+ using std::is_bind_expression;
+ using std::is_bind_expression_v;
+ using std::is_placeholder;
+ using std::is_placeholder_v;
+
+ using std::bind;
+
+ namespace placeholders {
+ // M is the implementation-defined number of placeholders
+ using std::placeholders::_1;
+ using std::placeholders::_10;
+ using std::placeholders::_2;
+ using std::placeholders::_3;
+ using std::placeholders::_4;
+ using std::placeholders::_5;
+ using std::placeholders::_6;
+ using std::placeholders::_7;
+ using std::placeholders::_8;
+ using std::placeholders::_9;
+ } // namespace placeholders
+
+ // [func.memfn], member function adaptors
+ using std::mem_fn;
+
+ // [func.wrap], polymorphic function wrappers
+ using std::bad_function_call;
+
+ using std::function;
+
+ using std::swap;
+
+ using std::operator==;
+
+ // [func.wrap.move], move only wrapper
+ // using std::move_only_function;
+
+ // [func.search], searchers
+ using std::default_searcher;
+
+ using std::boyer_moore_searcher;
+
+ using std::boyer_moore_horspool_searcher;
+
+ // [unord.hash], class template hash
+ using std::hash;
+
+ namespace ranges {
+ // [range.cmp], concept-constrained comparisons
+ using std::ranges::equal_to;
+ using std::ranges::greater;
+ using std::ranges::greater_equal;
+ using std::ranges::less;
+ using std::ranges::less_equal;
+ using std::ranges::not_equal_to;
+ } // namespace ranges
+} // namespace std
+
+// future.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_THREADS
+ using std::future_errc;
+ using std::future_status;
+ using std::launch;
+
+ // launch is a bitmask type.
+ // [bitmask.types] specified operators
+ using std::operator&;
+ using std::operator&=;
+ using std::operator^;
+ using std::operator^=;
+ using std::operator|;
+ using std::operator|=;
+ using std::operator~;
+
+ // [futures.errors], error handling
+ using std::is_error_code_enum;
+ using std::make_error_code;
+ using std::make_error_condition;
+
+ using std::future_category;
+
+ // [futures.future.error], class future_error
+ using std::future_error;
+
+ // [futures.promise], class template promise
+ using std::promise;
+
+ using std::swap;
+
+ using std::uses_allocator;
+
+ // [futures.unique.future], class template future
+ using std::future;
+
+ // [futures.shared.future], class template shared_future
+ using std::shared_future;
+
+ // [futures.task], class template packaged_task
+ using std::packaged_task;
+
+ // [futures.async], function template async
+ using std::async;
+#endif // _LIBCPP_HAS_NO_THREADS
+} // namespace std
+
+// generator.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#if 0
+ using std::generator;
+#endif
+} // namespace std
+
+// hazard_pointer.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#if 0
+# if _LIBCPP_STD_VER >= 23
+ // 4.1.3, class template hazard_pointer_obj_base
+ using std::hazard_pointer_obj_base;
+ // 4.1.4, class hazard_pointer
+ using std::hazard_pointer;
+ // 4.1.5, Construct non-empty hazard_pointer
+ using std::make_hazard_pointer;
+ // 4.1.6, Hazard pointer swap
+ using std::swap;
+# endif // _LIBCPP_STD_VER >= 23
+#endif
+} // namespace std
+
+// initializer_list.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::initializer_list;
+
+ // [support.initlist.range], initializer list range access
+ using std::begin;
+ using std::end;
+} // namespace std
+
+// iomanip.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ using std::get_money;
+ using std::get_time;
+ using std::put_money;
+ using std::put_time;
+ using std::resetiosflags;
+ using std::setbase;
+ using std::setfill;
+ using std::setiosflags;
+ using std::setprecision;
+ using std::setw;
+
+ using std::quoted;
+#endif // _LIBCPP_HAS_NO_LOCALIZATION
+} // namespace std
+
+// ios.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ using std::fpos;
+ // based on [tab:fpos.operations]
+ using std::operator!=; // Note not affected by P1614, seems like a bug.
+ using std::operator-;
+ using std::operator==;
+
+ using std::streamoff;
+ using std::streamsize;
+
+ using std::basic_ios;
+ using std::ios_base;
+
+ // [std.ios.manip], manipulators
+ using std::boolalpha;
+ using std::noboolalpha;
+
+ using std::noshowbase;
+ using std::showbase;
+
+ using std::noshowpoint;
+ using std::showpoint;
+
+ using std::noshowpos;
+ using std::showpos;
+
+ using std::noskipws;
+ using std::skipws;
+
+ using std::nouppercase;
+ using std::uppercase;
+
+ using std::nounitbuf;
+ using std::unitbuf;
+
+ // [adjustfield.manip], adjustfield
+ using std::internal;
+ using std::left;
+ using std::right;
+
+ // [basefield.manip], basefield
+ using std::dec;
+ using std::hex;
+ using std::oct;
+
+ // [floatfield.manip], floatfield
+ using std::defaultfloat;
+ using std::fixed;
+ using std::hexfloat;
+ using std::scientific;
+
+ // [error.reporting], error reporting
+ using std::io_errc;
+
+ using std::iostream_category;
+ using std::is_error_code_enum;
+ using std::make_error_code;
+ using std::make_error_condition;
+
+ // [iosfwd.syn]
+ using std::ios;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wios;
+# endif
+#endif // _LIBCPP_HAS_NO_LOCALIZATION
+} // namespace std
+
+// iosfwd.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::streampos;
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wstreampos;
+#endif
+ using std::u16streampos;
+ using std::u32streampos;
+#ifndef _LIBCPP_HAS_NO_CHAR8_T
+ using std::u8streampos;
+#endif
+
+#ifndef _LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM
+ using std::basic_osyncstream;
+ using std::basic_syncbuf;
+#endif
+
+ using std::istreambuf_iterator;
+ using std::ostreambuf_iterator;
+
+#ifndef _LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM
+ using std::osyncstream;
+ using std::syncbuf;
+
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wosyncstream;
+ using std::wsyncbuf;
+#endif
+#endif
+
+ using std::fpos;
+} // namespace std
+
+// iostream.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ using std::cerr;
+ using std::cin;
+ using std::clog;
+ using std::cout;
+
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wcerr;
+ using std::wcin;
+ using std::wclog;
+ using std::wcout;
+# endif
+#endif // _LIBCPP_HAS_NO_LOCALIZATION
+} // namespace std
+
+// istream.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ using std::basic_istream;
+
+ using std::istream;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wistream;
+# endif
+
+ using std::basic_iostream;
+
+ using std::iostream;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wiostream;
+# endif
+
+ using std::ws;
+
+ using std::operator>>;
+#endif // _LIBCPP_HAS_NO_LOCALIZATION
+} // namespace std
+
+// iterator.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [iterator.assoc.types], associated types
+ // [incrementable.traits], incrementable traits
+ using std::incrementable_traits;
+ using std::iter_difference_t;
+
+ using std::indirectly_readable_traits;
+ using std::iter_value_t;
+
+ // [iterator.traits], iterator traits
+ using std::iterator_traits;
+
+ using std::iter_reference_t;
+
+ namespace ranges {
+ // [iterator.cust], customization point objects
+ inline namespace __cpo {
+ // [iterator.cust.move], ranges::iter_move
+ using std::ranges::__cpo::iter_move;
+
+ // [iterator.cust.swap], ranges::iter_swap
+ using std::ranges::__cpo::iter_swap;
+ } // namespace __cpo
+ } // namespace ranges
+
+ using std::iter_rvalue_reference_t;
+
+ // [iterator.concepts], iterator concepts
+ // [iterator.concept.readable], concept indirectly_readable
+ using std::indirectly_readable;
+
+ using std::iter_common_reference_t;
+
+ // [iterator.concept.writable], concept indirectly_writable
+ using std::indirectly_writable;
+
+ // [iterator.concept.winc], concept weakly_incrementable
+ using std::weakly_incrementable;
+
+ // [iterator.concept.inc], concept incrementable
+ using std::incrementable;
+
+ // [iterator.concept.iterator], concept input_or_output_iterator
+ using std::input_or_output_iterator;
+
+ // [iterator.concept.sentinel], concept sentinel_for
+ using std::sentinel_for;
+
+ // [iterator.concept.sizedsentinel], concept sized_sentinel_for
+ using std::disable_sized_sentinel_for;
+
+ using std::sized_sentinel_for;
+
+ // [iterator.concept.input], concept input_iterator
+ using std::input_iterator;
+
+ // [iterator.concept.output], concept output_iterator
+ using std::output_iterator;
+
+ // [iterator.concept.forward], concept forward_iterator
+ using std::forward_iterator;
+
+ // [iterator.concept.bidir], concept bidirectional_iterator
+ using std::bidirectional_iterator;
+
+ // [iterator.concept.random.access], concept random_access_iterator
+ using std::random_access_iterator;
+
+ // [iterator.concept.contiguous], concept contiguous_iterator
+ using std::contiguous_iterator;
+
+ // [indirectcallable], indirect callable requirements
+ // [indirectcallable.indirectinvocable], indirect callables
+ using std::indirectly_unary_invocable;
+
+ using std::indirectly_regular_unary_invocable;
+
+ using std::indirect_unary_predicate;
+
+ using std::indirect_binary_predicate;
+
+ using std::indirect_equivalence_relation;
+
+ using std::indirect_strict_weak_order;
+
+ using std::indirect_result_t;
+
+ // [projected], projected
+ using std::projected;
+
+ // [alg.req], common algorithm requirements
+ // [alg.req.ind.move], concept indirectly_movable
+ using std::indirectly_movable;
+
+ using std::indirectly_movable_storable;
+
+ // [alg.req.ind.copy], concept indirectly_copyable
+ using std::indirectly_copyable;
+
+ using std::indirectly_copyable_storable;
+
+ // [alg.req.ind.swap], concept indirectly_swappable
+ using std::indirectly_swappable;
+
+ // [alg.req.ind.cmp], concept indirectly_comparable
+ using std::indirectly_comparable;
+
+ // [alg.req.permutable], concept permutable
+ using std::permutable;
+
+ // [alg.req.mergeable], concept mergeable
+ using std::mergeable;
+
+ // [alg.req.sortable], concept sortable
+ using std::sortable;
+
+ // [iterator.primitives], primitives
+ // [std.iterator.tags], iterator tags
+ using std::bidirectional_iterator_tag;
+ using std::contiguous_iterator_tag;
+ using std::forward_iterator_tag;
+ using std::input_iterator_tag;
+ using std::output_iterator_tag;
+ using std::random_access_iterator_tag;
+
+ // [iterator.operations], iterator operations
+ using std::advance;
+ using std::distance;
+ using std::next;
+ using std::prev;
+
+ // [range.iter.ops], range iterator operations
+ namespace ranges {
+ // [range.iter.op.advance], ranges​::​advance
+ using std::ranges::advance;
+
+ // [range.iter.op.distance], ranges​::​distance
+ using std::ranges::distance;
+
+ // [range.iter.op.next], ranges​::​next
+ using std::ranges::next;
+
+ // [range.iter.op.prev], ranges​::​prev
+ using std::ranges::prev;
+ } // namespace ranges
+
+ // [predef.iterators], predefined iterators and sentinels
+ // [reverse.iterators], reverse iterators
+ using std::reverse_iterator;
+
+ using std::operator==;
+ using std::operator!=;
+ using std::operator<;
+ using std::operator>;
+ using std::operator<=;
+ using std::operator>=;
+ using std::operator<=>;
+
+ using std::operator-;
+ using std::operator+;
+
+ using std::make_reverse_iterator;
+
+ // using std::disable_sized_sentinel_for;
+
+ // [insert.iterators], insert iterators
+ using std::back_insert_iterator;
+ using std::back_inserter;
+
+ using std::front_insert_iterator;
+ using std::front_inserter;
+
+ using std::insert_iterator;
+ using std::inserter;
+
+ // [const.iterators], constant iterators and sentinels
+ // [const.iterators.alias], alias templates
+ // using std::const_iterator;
+ // using std::const_sentinel;
+ // using std::iter_const_reference_t;
+
+ // [const.iterators.iterator], class template basic_const_iterator
+ // using std::basic_const_iterator;
+
+ // using std::common_type;
+
+ // using std::make_const_iterator;
+
+ // [move.iterators], move iterators and sentinels
+ using std::move_iterator;
+
+ using std::make_move_iterator;
+
+ using std::move_sentinel;
+
+ using std::common_iterator;
+
+ // [default.sentinel], default sentinel
+ using std::default_sentinel;
+ using std::default_sentinel_t;
+
+ // [iterators.counted], counted iterators
+ using std::counted_iterator;
+
+ // [unreachable.sentinel], unreachable sentinel
+ using std::unreachable_sentinel;
+ using std::unreachable_sentinel_t;
+
+ // [stream.iterators], stream iterators
+ using std::istream_iterator;
+
+ using std::ostream_iterator;
+
+ using std::istreambuf_iterator;
+ using std::ostreambuf_iterator;
+
+ // [iterator.range], range access
+ using std::begin;
+ using std::cbegin;
+ using std::cend;
+ using std::crbegin;
+ using std::crend;
+ using std::end;
+ using std::rbegin;
+ using std::rend;
+
+ using std::empty;
+ using std::size;
+ using std::ssize;
+
+ using std::data;
+
+ // [depr.iterator]
+ using std::iterator;
+} // namespace std
+
+// latch.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_THREADS
+ using std::latch;
+#endif // _LIBCPP_HAS_NO_THREADS
+} // namespace std
+
+// limits.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [fp.style], floating-point type properties
+ using std::float_denorm_style;
+ using std::float_round_style;
+
+ // [numeric.limits], class template numeric_­limits
+ using std::numeric_limits;
+} // namespace std
+
+// list.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [list], class template list
+ using std::list;
+
+ using std::operator==;
+ using std::operator<=>;
+
+ using std::swap;
+
+ // [list.erasure], erasure
+ using std::erase;
+ using std::erase_if;
+
+ namespace pmr {
+ using std::pmr::list;
+ }
+} // namespace std
+
+// locale.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ // [locale], locale
+ using std::has_facet;
+ using std::locale;
+ using std::use_facet;
+
+ // [locale.convenience], convenience interfaces
+ using std::isalnum;
+ using std::isalpha;
+ using std::isblank;
+ using std::iscntrl;
+ using std::isdigit;
+ using std::isgraph;
+ using std::islower;
+ using std::isprint;
+ using std::ispunct;
+ using std::isspace;
+ using std::isupper;
+ using std::isxdigit;
+ using std::tolower;
+ using std::toupper;
+
+ // [category.ctype], ctype
+ using std::codecvt;
+ using std::codecvt_base;
+ using std::codecvt_byname;
+ using std::ctype;
+ using std::ctype_base;
+ using std::ctype_byname;
+
+ // [category.numeric], numeric
+ using std::num_get;
+ using std::num_put;
+ using std::numpunct;
+ using std::numpunct_byname;
+
+ // [category.collate], collation
+ using std::collate;
+ using std::collate_byname;
+
+ // [category.time], date and time
+ using std::time_base;
+ using std::time_get;
+ using std::time_get_byname;
+ using std::time_put;
+ using std::time_put_byname;
+
+ // [category.monetary], money
+ using std::money_base;
+ using std::money_get;
+ using std::money_put;
+ using std::moneypunct;
+ using std::moneypunct_byname;
+
+ // [category.messages], message retrieval
+ using std::messages;
+ using std::messages_base;
+ using std::messages_byname;
+
+ // [depr.conversions.buffer]
+ using std::wbuffer_convert;
+
+ // [depr.conversions.string]
+ using std::wstring_convert;
+#endif // _LIBCPP_HAS_NO_LOCALIZATION
+} // namespace std
+
+// map.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [map], class template map
+ using std::map;
+
+ using std::operator==;
+ using std::operator<=>;
+
+ using std::swap;
+
+ // [map.erasure], erasure for map
+ using std::erase_if;
+
+ // [multimap], class template multimap
+ using std::multimap;
+
+ namespace pmr {
+ using std::pmr::map;
+ using std::pmr::multimap;
+ } // namespace pmr
+} // namespace std
+
+// mdspan.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#if _LIBCPP_STD_VER >= 23
+ // [mdspan.extents], class template extents
+ using std::extents;
+
+ // [mdspan.extents.dextents], alias template dextents
+ using std::dextents;
+
+ // [mdspan.layout], layout mapping
+ using std::layout_left;
+ using std::layout_right;
+ using std::layout_stride;
+
+ // [mdspan.accessor.default], class template default_accessor
+ using std::default_accessor;
+
+ // [mdspan.mdspan], class template mdspan
+ using std::mdspan;
+#endif // _LIBCPP_STD_VER >= 23
+} // namespace std
+
+// memory.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [pointer.traits], pointer traits
+ using std::pointer_traits;
+
+ // [pointer.conversion], pointer conversion
+ using std::to_address;
+
+ // [ptr.align], pointer alignment
+ using std::align;
+ using std::assume_aligned;
+
+ // [obj.lifetime], explicit lifetime management
+ // using std::start_lifetime_as;
+ // using std::start_lifetime_as_array;
+
+ // [allocator.tag], allocator argument tag
+ using std::allocator_arg;
+ using std::allocator_arg_t;
+
+ // [allocator.uses], uses_allocator
+ using std::uses_allocator;
+
+ // [allocator.uses.trait], uses_allocator
+ using std::uses_allocator_v;
+
+ // [allocator.uses.construction], uses-allocator construction
+ using std::uses_allocator_construction_args;
+
+ using std::make_obj_using_allocator;
+ using std::uninitialized_construct_using_allocator;
+
+ // [allocator.traits], allocator traits
+ using std::allocator_traits;
+
+#if _LIBCPP_STD_VER >= 23
+ using std::allocation_result;
+
+ // Note: no longer in Clang 19.
+ //
+ //using std::allocate_at_least;
+#endif
+
+ // [default.allocator], the default allocator
+ using std::allocator;
+ using std::operator==;
+
+ // [specialized.addressof], addressof
+ using std::addressof;
+
+ // [specialized.algorithms], specialized algorithms
+ // [special.mem.concepts], special memory concepts
+
+ using std::uninitialized_default_construct;
+ using std::uninitialized_default_construct_n;
+
+ namespace ranges {
+ using std::ranges::uninitialized_default_construct;
+ using std::ranges::uninitialized_default_construct_n;
+ } // namespace ranges
+
+ using std::uninitialized_value_construct;
+ using std::uninitialized_value_construct_n;
+
+ namespace ranges {
+ using std::ranges::uninitialized_value_construct;
+ using std::ranges::uninitialized_value_construct_n;
+ } // namespace ranges
+
+ using std::uninitialized_copy;
+ using std::uninitialized_copy_n;
+
+ namespace ranges {
+ using std::ranges::uninitialized_copy;
+ using std::ranges::uninitialized_copy_result;
+
+ using std::ranges::uninitialized_copy_n;
+ using std::ranges::uninitialized_copy_n_result;
+ } // namespace ranges
+
+ using std::uninitialized_move;
+ using std::uninitialized_move_n;
+
+ namespace ranges {
+ using std::ranges::uninitialized_move;
+ using std::ranges::uninitialized_move_result;
+
+ using std::ranges::uninitialized_move_n;
+ using std::ranges::uninitialized_move_n_result;
+ } // namespace ranges
+
+ using std::uninitialized_fill;
+ using std::uninitialized_fill_n;
+
+ namespace ranges {
+ using std::ranges::uninitialized_fill;
+ using std::ranges::uninitialized_fill_n;
+ } // namespace ranges
+
+ // [specialized.construct], construct_at
+ using std::construct_at;
+
+ namespace ranges {
+ using std::ranges::construct_at;
+ }
+ // [specialized.destroy], destroy
+ using std::destroy;
+ using std::destroy_at;
+ using std::destroy_n;
+
+ namespace ranges {
+ using std::ranges::destroy;
+ using std::ranges::destroy_at;
+ using std::ranges::destroy_n;
+ } // namespace ranges
+
+ // [unique.ptr], class template unique_ptr
+ using std::default_delete;
+ using std::unique_ptr;
+
+ using std::make_unique;
+ using std::make_unique_for_overwrite;
+
+ using std::operator<;
+ using std::operator>;
+ using std::operator<=;
+ using std::operator>=;
+ using std::operator<=>;
+
+ using std::operator<<;
+
+ // [util.smartptr.weak.bad], class bad_weak_ptr
+ using std::bad_weak_ptr;
+
+ // [util.smartptr.shared], class template shared_ptr
+ using std::shared_ptr;
+
+ // [util.smartptr.shared.create], shared_ptr creation
+ using std::allocate_shared;
+ using std::allocate_shared_for_overwrite;
+ using std::make_shared;
+ using std::make_shared_for_overwrite;
+
+ // [util.smartptr.shared.spec], shared_ptr specialized algorithms
+ using std::swap;
+
+ // [util.smartptr.shared.cast], shared_ptr casts
+ using std::const_pointer_cast;
+ using std::dynamic_pointer_cast;
+ using std::reinterpret_pointer_cast;
+ using std::static_pointer_cast;
+
+#ifndef _LIBCPP_HAS_NO_RTTI
+ using std::get_deleter;
+#endif // _LIBCPP_HAS_NO_RTTI
+
+ // [util.smartptr.shared.io], shared_ptr I/O
+
+ // [util.smartptr.weak], class template weak_ptr
+ using std::weak_ptr;
+
+ // [util.smartptr.weak.spec], weak_ptr specialized algorithms
+
+ // [util.smartptr.ownerless], class template owner_less
+ using std::owner_less;
+
+ // [util.smartptr.enab], class template enable_shared_from_this
+ using std::enable_shared_from_this;
+
+ // [util.smartptr.hash], hash support
+ using std::hash;
+
+ // [util.smartptr.atomic], atomic smart pointers
+ // using std::atomic;
+
+ // [out.ptr.t], class template out_ptr_t
+ // using std::out_ptr_t;
+
+ // [out.ptr], function template out_ptr
+ // using std::out_ptr;
+
+ // [inout.ptr.t], class template inout_ptr_t
+ // using std::inout_ptr_t;
+
+ // [inout.ptr], function template inout_ptr
+ // using std::inout_ptr;
+
+#ifndef _LIBCPP_HAS_NO_THREADS
+ // [depr.util.smartptr.shared.atomic]
+ using std::atomic_is_lock_free;
+
+ using std::atomic_load;
+ using std::atomic_load_explicit;
+
+ using std::atomic_store;
+ using std::atomic_store_explicit;
+
+ using std::atomic_exchange;
+ using std::atomic_exchange_explicit;
+
+ using std::atomic_compare_exchange_strong;
+ using std::atomic_compare_exchange_strong_explicit;
+ using std::atomic_compare_exchange_weak;
+ using std::atomic_compare_exchange_weak_explicit;
+#endif // _LIBCPP_HAS_NO_THREADS
+} // namespace std
+
+// memory_resource.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std::pmr {
+ // [mem.res.class], class memory_resource
+ using std::pmr::memory_resource;
+
+ using std::pmr::operator==;
+
+ // [mem.poly.allocator.class], class template polymorphic_allocator
+ using std::pmr::polymorphic_allocator;
+
+ // [mem.res.global], global memory resources
+ using std::pmr::get_default_resource;
+ using std::pmr::new_delete_resource;
+ using std::pmr::null_memory_resource;
+ using std::pmr::set_default_resource;
+
+ // [mem.res.pool], pool resource classes
+ using std::pmr::monotonic_buffer_resource;
+ using std::pmr::pool_options;
+ using std::pmr::synchronized_pool_resource;
+ using std::pmr::unsynchronized_pool_resource;
+} // namespace std::pmr
+
+// mutex.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_THREADS
+ // [thread.mutex.class], class mutex
+ using std::mutex;
+ // [thread.mutex.recursive], class recursive_mutex
+ using std::recursive_mutex;
+ // [thread.timedmutex.class] class timed_mutex
+ using std::timed_mutex;
+ // [thread.timedmutex.recursive], class recursive_timed_mutex
+ using std::recursive_timed_mutex;
+
+ using std::adopt_lock_t;
+ using std::defer_lock_t;
+ using std::try_to_lock_t;
+
+ using std::adopt_lock;
+ using std::defer_lock;
+ using std::try_to_lock;
+
+ // [thread.lock], locks
+ using std::lock_guard;
+ using std::scoped_lock;
+ using std::unique_lock;
+
+ using std::swap;
+
+ // [thread.lock.algorithm], generic locking algorithms
+ using std::lock;
+ using std::try_lock;
+#endif // _LIBCPP_HAS_NO_THREADS
+
+ using std::once_flag;
+
+ using std::call_once;
+} // namespace std
+
+// new.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [alloc.errors], storage allocation errors
+ using std::bad_alloc;
+ using std::bad_array_new_length;
+
+ using std::destroying_delete;
+ using std::destroying_delete_t;
+
+ // global operator new control
+ using std::align_val_t;
+
+ using std::nothrow;
+ using std::nothrow_t;
+
+ using std::get_new_handler;
+ using std::new_handler;
+ using std::set_new_handler;
+
+ // [ptr.launder], pointer optimization barrier
+ using std::launder;
+#if 0
+ // [hardware.interference], hardware interference size
+ using std::hardware_constructive_interference_size;
+ using std::hardware_destructive_interference_size;
+#endif
+} // namespace std
+
+export {
+ using ::operator new;
+ using ::operator delete;
+ using ::operator new[];
+ using ::operator delete[];
+} // export
+
+// numbers.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std::numbers {
+ using std::numbers::e_v;
+ using std::numbers::egamma_v;
+ using std::numbers::inv_pi_v;
+ using std::numbers::inv_sqrt3_v;
+ using std::numbers::inv_sqrtpi_v;
+ using std::numbers::ln10_v;
+ using std::numbers::ln2_v;
+ using std::numbers::log10e_v;
+ using std::numbers::log2e_v;
+ using std::numbers::phi_v;
+ using std::numbers::pi_v;
+ using std::numbers::sqrt2_v;
+ using std::numbers::sqrt3_v;
+
+ using std::numbers::e;
+ using std::numbers::egamma;
+ using std::numbers::inv_pi;
+ using std::numbers::inv_sqrt3;
+ using std::numbers::inv_sqrtpi;
+ using std::numbers::ln10;
+ using std::numbers::ln2;
+ using std::numbers::log10e;
+ using std::numbers::log2e;
+ using std::numbers::phi;
+ using std::numbers::pi;
+ using std::numbers::sqrt2;
+ using std::numbers::sqrt3;
+} // namespace std::numbers
+
+// numeric.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [accumulate], accumulate
+ using std::accumulate;
+
+ // [reduce], reduce
+ using std::reduce;
+
+ // [inner.product], inner product
+ using std::inner_product;
+
+ // [transform.reduce], transform reduce
+ using std::transform_reduce;
+
+ // [partial.sum], partial sum
+ using std::partial_sum;
+
+ // [exclusive.scan], exclusive scan
+ using std::exclusive_scan;
+
+ // [inclusive.scan], inclusive scan
+ using std::inclusive_scan;
+
+ // [transform.exclusive.scan], transform exclusive scan
+ using std::transform_exclusive_scan;
+
+ // [transform.inclusive.scan], transform inclusive scan
+ using std::transform_inclusive_scan;
+
+ // [adjacent.difference], adjacent difference
+ using std::adjacent_difference;
+
+ // [numeric.iota], iota
+ using std::iota;
+
+ namespace ranges {
+ // using std::ranges::iota_result;
+ // using std::ranges::iota;
+ } // namespace ranges
+
+ // [numeric.ops.gcd], greatest common divisor
+ using std::gcd;
+
+ // [numeric.ops.lcm], least common multiple
+ using std::lcm;
+
+ // [numeric.ops.midpoint], midpoint
+ using std::midpoint;
+
+#if _LIBCPP_STD_VER >= 26
+ // [numeric.sat], saturation arithmetic
+ using std::add_sat;
+ using std::div_sat;
+ using std::mul_sat;
+ using std::saturate_cast;
+ using std::sub_sat;
+#endif
+
+} // namespace std
+
+// optional.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [optional.optional], class template optional
+ using std::optional;
+
+ // [optional.nullopt], no-value state indicator
+ using std::nullopt;
+ using std::nullopt_t;
+
+ // [optional.bad.access], class bad_optional_access
+ using std::bad_optional_access;
+
+ // [optional.relops], relational operators
+ using std::operator==;
+ using std::operator!=;
+ using std::operator<;
+ using std::operator>;
+ using std::operator<=;
+ using std::operator>=;
+ using std::operator<=>;
+
+ // [optional.specalg], specialized algorithms
+ using std::swap;
+
+ using std::make_optional;
+
+ // [optional.hash], hash support
+ using std::hash;
+} // namespace std
+
+// ostream.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ using std::basic_ostream;
+
+ using std::ostream;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wostream;
+# endif
+
+ using std::endl;
+ using std::ends;
+ using std::flush;
+
+# if 0
+ using std::emit_on_flush;
+ using std::flush_emit;
+ using std::noemit_on_flush;
+# endif
+ using std::operator<<;
+
+# if _LIBCPP_STD_VER >= 23
+ // [ostream.formatted.print], print functions
+ using std::print;
+ using std::println;
+
+ using std::vprint_nonunicode;
+# ifndef _LIBCPP_HAS_NO_UNICODE
+ using std::vprint_unicode;
+# endif // _LIBCPP_HAS_NO_UNICODE
+# endif // _LIBCPP_STD_VER >= 23
+
+#endif // _LIBCPP_HAS_NO_LOCALIZATION
+} // namespace std
+
+// print.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#if _LIBCPP_STD_VER >= 23
+ // [print.fun], print functions
+ using std::print;
+ using std::println;
+
+ using std::vprint_nonunicode;
+# ifndef _LIBCPP_HAS_NO_UNICODE
+ using std::vprint_unicode;
+# endif // _LIBCPP_HAS_NO_UNICODE
+#endif // _LIBCPP_STD_VER >= 23
+} // namespace std
+
+// queue.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [queue], class template queue
+ using std::queue;
+
+ using std::operator==;
+ using std::operator!=;
+ using std::operator<;
+ using std::operator>;
+ using std::operator<=;
+ using std::operator>=;
+ using std::operator<=>;
+
+ using std::swap;
+ using std::uses_allocator;
+
+ // [priority.queue], class template priority_queue
+ using std::priority_queue;
+} // namespace std
+
+// random.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [rand.req.urng], uniform random bit generator requirements
+ using std::uniform_random_bit_generator;
+
+ // [rand.eng.lcong], class template linear_congruential_engine
+ using std::linear_congruential_engine;
+
+ // [rand.eng.mers], class template mersenne_twister_engine
+ using std::mersenne_twister_engine;
+
+ // [rand.eng.sub], class template subtract_with_carry_engine
+ using std::subtract_with_carry_engine;
+
+ // [rand.adapt.disc], class template discard_block_engine
+ using std::discard_block_engine;
+
+ // [rand.adapt.ibits], class template independent_bits_engine
+ using std::independent_bits_engine;
+
+ // [rand.adapt.shuf], class template shuffle_order_engine
+ using std::shuffle_order_engine;
+
+ // [rand.predef], engines and engine adaptors with predefined parameters
+ using std::knuth_b;
+ using std::minstd_rand;
+ using std::minstd_rand0;
+ using std::mt19937;
+ using std::mt19937_64;
+ using std::ranlux24;
+ using std::ranlux24_base;
+ using std::ranlux48;
+ using std::ranlux48_base;
+
+ using std::default_random_engine;
+
+#ifndef _LIBCPP_HAS_NO_RANDOM_DEVICE
+ // [rand.device], class random_device
+ using std::random_device;
+#endif
+
+ // [rand.util.seedseq], class seed_seq
+ using std::seed_seq;
+
+ // [rand.util.canonical], function template generate_canonical
+ using std::generate_canonical;
+
+ // [rand.dist.uni.int], class template uniform_int_distribution
+ using std::uniform_int_distribution;
+
+ // [rand.dist.uni.real], class template uniform_real_distribution
+ using std::uniform_real_distribution;
+
+ // [rand.dist.bern.bernoulli], class bernoulli_distribution
+ using std::bernoulli_distribution;
+
+ // [rand.dist.bern.bin], class template binomial_distribution
+ using std::binomial_distribution;
+
+ // [rand.dist.bern.geo], class template geometric_distribution
+ using std::geometric_distribution;
+
+ // [rand.dist.bern.negbin], class template negative_binomial_distribution
+ using std::negative_binomial_distribution;
+
+ // [rand.dist.pois.poisson], class template poisson_distribution
+ using std::poisson_distribution;
+
+ // [rand.dist.pois.exp], class template exponential_distribution
+ using std::exponential_distribution;
+
+ // [rand.dist.pois.gamma], class template gamma_distribution
+ using std::gamma_distribution;
+
+ // [rand.dist.pois.weibull], class template weibull_distribution
+ using std::weibull_distribution;
+
+ // [rand.dist.pois.extreme], class template extreme_value_distribution
+ using std::extreme_value_distribution;
+
+ // [rand.dist.norm.normal], class template normal_distribution
+ using std::normal_distribution;
+
+ // [rand.dist.norm.lognormal], class template lognormal_distribution
+ using std::lognormal_distribution;
+
+ // [rand.dist.norm.chisq], class template chi_squared_distribution
+ using std::chi_squared_distribution;
+
+ // [rand.dist.norm.cauchy], class template cauchy_distribution
+ using std::cauchy_distribution;
+
+ // [rand.dist.norm.f], class template fisher_f_distribution
+ using std::fisher_f_distribution;
+
+ // [rand.dist.norm.t], class template student_t_distribution
+ using std::student_t_distribution;
+
+ // [rand.dist.samp.discrete], class template discrete_distribution
+ using std::discrete_distribution;
+
+ // [rand.dist.samp.pconst], class template piecewise_constant_distribution
+ using std::piecewise_constant_distribution;
+
+ // [rand.dist.samp.plinear], class template piecewise_linear_distribution
+ using std::piecewise_linear_distribution;
+} // namespace std
+
+// ranges.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ namespace ranges {
+ inline namespace __cpo {
+ // [range.access], range access
+ using std::ranges::__cpo::begin;
+ using std::ranges::__cpo::cbegin;
+ using std::ranges::__cpo::cend;
+ using std::ranges::__cpo::crbegin;
+ using std::ranges::__cpo::crend;
+ using std::ranges::__cpo::end;
+ using std::ranges::__cpo::rbegin;
+ using std::ranges::__cpo::rend;
+
+ using std::ranges::__cpo::cdata;
+ using std::ranges::__cpo::data;
+ using std::ranges::__cpo::empty;
+ using std::ranges::__cpo::size;
+ using std::ranges::__cpo::ssize;
+ } // namespace __cpo
+
+ // [range.range], ranges
+ using std::ranges::range;
+
+ using std::ranges::enable_borrowed_range;
+
+ using std::ranges::borrowed_range;
+
+ // using std::ranges::const_iterator_t;
+ // using std::ranges::const_sentinel_t;
+ using std::ranges::iterator_t;
+ // using std::ranges::range_const_reference_t;
+ using std::ranges::range_common_reference_t;
+ using std::ranges::range_difference_t;
+ using std::ranges::range_reference_t;
+ using std::ranges::range_rvalue_reference_t;
+ using std::ranges::range_size_t;
+ using std::ranges::range_value_t;
+ using std::ranges::sentinel_t;
+
+ // [range.sized], sized ranges
+ using std::ranges::disable_sized_range;
+ using std::ranges::sized_range;
+
+ // [range.view], views
+ using std::ranges::enable_view;
+ using std::ranges::view;
+ using std::ranges::view_base;
+
+ // [range.refinements], other range refinements
+ using std::ranges::bidirectional_range;
+ using std::ranges::common_range;
+ // using std::ranges::constant_range;
+ using std::ranges::contiguous_range;
+ using std::ranges::forward_range;
+ using std::ranges::input_range;
+ using std::ranges::output_range;
+ using std::ranges::random_access_range;
+ using std::ranges::viewable_range;
+
+ // [view.interface], class template view_­interface
+ using std::ranges::view_interface;
+
+ // [range.subrange], sub-ranges
+ using std::ranges::subrange;
+ using std::ranges::subrange_kind;
+
+ using std::ranges::get;
+ } // namespace ranges
+
+ using std::ranges::get;
+
+ namespace ranges {
+
+ // [range.dangling], dangling iterator handling
+ using std::ranges::dangling;
+
+ // [range.elementsof], class template elements_­of
+ // using std::ranges::elements_of;
+
+ using std::ranges::borrowed_iterator_t;
+
+ using std::ranges::borrowed_subrange_t;
+
+#if _LIBCPP_STD_VER >= 23
+ // [range.utility.conv], range conversions
+ using std::ranges::to;
+#endif
+
+ // [range.empty], empty view
+ using std::ranges::empty_view;
+
+ namespace views {
+ using std::ranges::views::empty;
+ }
+
+ // [range.single], single view
+ using std::ranges::single_view;
+
+ namespace views {
+ using std::ranges::views::single;
+ } // namespace views
+
+ // [range.iota], iota view
+ using std::ranges::iota_view;
+
+ namespace views {
+ using std::ranges::views::iota;
+ } // namespace views
+
+#if _LIBCPP_STD_VER >= 23
+ // [range.repeat], repeat view
+ using std::ranges::repeat_view;
+
+ namespace views {
+ using std::ranges::views::repeat;
+ } // namespace views
+#endif // _LIBCPP_STD_VER >= 23
+
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ // [range.istream], istream view
+ using std::ranges::basic_istream_view;
+ using std::ranges::istream_view;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::ranges::wistream_view;
+# endif
+
+ namespace views {
+ using std::ranges::views::istream;
+ }
+#endif // _LIBCPP_HAS_NO_LOCALIZATION
+
+ // [range.adaptor.object], range adaptor objects
+ // using std::ranges::range_adaptor_closure;
+
+ // [range.all], all view
+ namespace views {
+ using std::ranges::views::all;
+ using std::ranges::views::all_t;
+ } // namespace views
+
+ // [range.ref.view], ref view
+ using std::ranges::ref_view;
+
+ // [range.owning.view], owning view
+ using std::ranges::owning_view;
+
+#if _LIBCPP_STD_VER >= 23
+ // [range.as.rvalue], as rvalue view
+ using std::ranges::as_rvalue_view;
+
+ namespace views {
+ using std::ranges::views::as_rvalue;
+ } // namespace views
+#endif // _LIBCPP_STD_VER >= 23
+
+ // [range.filter], filter view
+ using std::ranges::filter_view;
+
+ namespace views {
+ using std::ranges::views::filter;
+ } // namespace views
+
+ // [range.transform], transform view
+ using std::ranges::transform_view;
+
+ namespace views {
+ using std::ranges::views::transform;
+ } // namespace views
+
+ // [range.take], take view
+ using std::ranges::take_view;
+
+ namespace views {
+ using std::ranges::views::take;
+ } // namespace views
+
+ // [range.take.while], take while view
+ using std::ranges::take_while_view;
+
+ namespace views {
+ using std::ranges::views::take_while;
+ } // namespace views
+
+ // [range.drop], drop view
+ using std::ranges::drop_view;
+
+ namespace views {
+ using std::ranges::views::drop;
+ } // namespace views
+
+ // [range.drop.while], drop while view
+ using std::ranges::drop_while_view;
+
+ namespace views {
+ using std::ranges::views::drop_while;
+ } // namespace views
+
+ using std::ranges::join_view;
+
+ namespace views {
+ using std::ranges::views::join;
+ } // namespace views
+#if 0
+ using std::ranges::join_with_view;
+
+ namespace views {
+ using std::ranges::views::join_with;
+ } // namespace views
+#endif
+ using std::ranges::lazy_split_view;
+
+ // [range.split], split view
+ using std::ranges::split_view;
+
+ namespace views {
+ using std::ranges::views::lazy_split;
+ using std::ranges::views::split;
+ } // namespace views
+
+ // [range.counted], counted view
+ namespace views {
+ using std::ranges::views::counted;
+ } // namespace views
+
+ // [range.common], common view
+ using std::ranges::common_view;
+
+ namespace views {
+ using std::ranges::views::common;
+ } // namespace views
+
+ // [range.reverse], reverse view
+ using std::ranges::reverse_view;
+
+ namespace views {
+ using std::ranges::views::reverse;
+ } // namespace views
+
+ // [range.as.const], as const view
+#if 0
+ using std::ranges::as_const_view;
+
+ namespace views {
+ using std::ranges::views::as_const;
+ } // namespace views
+#endif
+ // [range.elements], elements view
+ using std::ranges::elements_view;
+
+ using std::ranges::keys_view;
+ using std::ranges::values_view;
+
+ namespace views {
+ using std::ranges::views::elements;
+ using std::ranges::views::keys;
+ using std::ranges::views::values;
+ } // namespace views
+
+#if _LIBCPP_STD_VER >= 23
+ // [range.zip], zip view
+ using std::ranges::zip_view;
+
+ namespace views {
+ using std::ranges::views::zip;
+ } // namespace views
+#endif // _LIBCPP_STD_VER >= 23
+
+#if 0
+ // [range.zip.transform], zip transform view
+ using std::ranges::zip_transform_view;
+
+ namespace views {
+ using std::ranges::views::zip_transform;
+ }
+
+ using std::ranges::adjacent_view;
+
+ namespace views {
+ using std::ranges::views::adjacent;
+ using std::ranges::views::pairwise;
+ } // namespace views
+
+ using std::ranges::adjacent_transform_view;
+
+ namespace views {
+ using std::ranges::views::adjacent_transform;
+ using std::ranges::views::pairwise_transform;
+ } // namespace views
+
+ using std::ranges::chunk_view;
+
+ using std::ranges::chunk_view<V>;
+
+ namespace views {
+ using std::ranges::views::chunk;
+ }
+
+ using std::ranges::slide_view;
+
+ namespace views {
+ using std::ranges::views::slide;
+ }
+#endif
+
+#if _LIBCPP_STD_VER >= 23
+ // [range.chunk.by], chunk by view
+ using std::ranges::chunk_by_view;
+
+ namespace views {
+ using std::ranges::views::chunk_by;
+ }
+#endif // _LIBCPP_STD_VER >= 23
+
+#if 0
+ // [range.stride], stride view
+ using std::ranges::stride_view;
+
+ namespace views {
+ using std::ranges::views::stride;
+ }
+
+ using std::ranges::cartesian_product_view;
+
+ namespace views {
+ using std::ranges::views::cartesian_product;
+ }
+#endif
+ } // namespace ranges
+
+ namespace views = ranges::views;
+
+ using std::tuple_element;
+ using std::tuple_size;
+
+#if _LIBCPP_STD_VER >= 23
+ using std::from_range;
+ using std::from_range_t;
+#endif // _LIBCPP_STD_VER >= 23
+} // namespace std
+
+// ratio.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [ratio.ratio], class template ratio
+ using std::ratio;
+
+ // [ratio.arithmetic], ratio arithmetic
+ using std::ratio_add;
+ using std::ratio_divide;
+ using std::ratio_multiply;
+ using std::ratio_subtract;
+
+ // [ratio.comparison], ratio comparison
+ using std::ratio_equal;
+ using std::ratio_greater;
+ using std::ratio_greater_equal;
+ using std::ratio_less;
+ using std::ratio_less_equal;
+ using std::ratio_not_equal;
+
+ using std::ratio_equal_v;
+ using std::ratio_greater_equal_v;
+ using std::ratio_greater_v;
+ using std::ratio_less_equal_v;
+ using std::ratio_less_v;
+ using std::ratio_not_equal_v;
+
+ // [ratio.si], convenience SI typedefs
+ using std::atto;
+ using std::centi;
+ using std::deca;
+ using std::deci;
+ using std::exa;
+ using std::femto;
+ using std::giga;
+ using std::hecto;
+ using std::kilo;
+ using std::mega;
+ using std::micro;
+ using std::milli;
+ using std::nano;
+ using std::peta;
+ using std::pico;
+ using std::tera;
+
+ // These are not supported by libc++, due to the range of intmax_t
+ // using std::yocto;
+ // using std::yotta;
+ // using std::zepto;
+ // using std::zetta
+} // namespace std
+
+// rcu.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#if 0
+# if _LIBCPP_STD_VER >= 23
+ // 2.2.3, class template rcu_obj_base using std::rcu_obj_base;
+ // 2.2.4, class rcu_domain
+ using std::rcu_domain;
+ using std::rcu_default_domain();
+ using std::rcu_barrier;
+ using std::rcu_retire;
+ using std::rcu_synchronize;
+# endif // _LIBCPP_STD_VER >= 23
+#endif
+} // namespace std
+
+// regex.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ // [re.const], regex constants
+ namespace regex_constants {
+ using std::regex_constants::error_type;
+ using std::regex_constants::match_flag_type;
+ using std::regex_constants::syntax_option_type;
+
+ // regex_constants is a bitmask type.
+ // [bitmask.types] specified operators
+ using std::regex_constants::operator&;
+ using std::regex_constants::operator&=;
+ using std::regex_constants::operator^;
+ using std::regex_constants::operator^=;
+ using std::regex_constants::operator|;
+ using std::regex_constants::operator|=;
+ using std::regex_constants::operator~;
+
+ } // namespace regex_constants
+
+ // [re.badexp], class regex_error
+ using std::regex_error;
+
+ // [re.traits], class template regex_traits
+ using std::regex_traits;
+
+ // [re.regex], class template basic_regex
+ using std::basic_regex;
+
+ using std::regex;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wregex;
+# endif
+
+ // [re.regex.swap], basic_regex swap
+ using std::swap;
+
+ // [re.submatch], class template sub_match
+ using std::sub_match;
+
+ using std::csub_match;
+ using std::ssub_match;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wcsub_match;
+ using std::wssub_match;
+# endif
+
+ // [re.submatch.op], sub_match non-member operators
+ using std::operator==;
+ using std::operator<=>;
+
+ using std::operator<<;
+
+ // [re.results], class template match_results
+ using std::match_results;
+
+ using std::cmatch;
+ using std::smatch;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wcmatch;
+ using std::wsmatch;
+# endif
+
+ // match_results comparisons
+
+ // [re.results.swap], match_results swap
+
+ // [re.alg.match], function template regex_match
+ using std::regex_match;
+
+ // [re.alg.search], function template regex_search
+ using std::regex_search;
+
+ // [re.alg.replace], function template regex_replace
+ using std::regex_replace;
+
+ // [re.regiter], class template regex_iterator
+ using std::regex_iterator;
+
+ using std::cregex_iterator;
+ using std::sregex_iterator;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wcregex_iterator;
+ using std::wsregex_iterator;
+# endif
+
+ // [re.tokiter], class template regex_token_iterator
+ using std::regex_token_iterator;
+
+ using std::cregex_token_iterator;
+ using std::sregex_token_iterator;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wcregex_token_iterator;
+ using std::wsregex_token_iterator;
+# endif
+
+ namespace pmr {
+ using std::pmr::match_results;
+
+ using std::pmr::cmatch;
+ using std::pmr::smatch;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::pmr::wcmatch;
+ using std::pmr::wsmatch;
+# endif
+ } // namespace pmr
+#endif // _LIBCPP_HAS_NO_LOCALIZATION
+} // namespace std
+
+// scoped_allocator.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // class template scoped_allocator_adaptor
+ using std::scoped_allocator_adaptor;
+
+ // [scoped.adaptor.operators], scoped allocator operators
+ using std::operator==;
+
+} // namespace std
+
+// semaphore.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_THREADS
+ // [thread.sema.cnt], class template counting_semaphore
+ using std::counting_semaphore;
+
+ using std::binary_semaphore;
+#endif // _LIBCPP_HAS_NO_THREADS
+} // namespace std
+
+// set.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [set], class template set
+ using std::set;
+
+ using std::operator==;
+ using std::operator<=>;
+
+ using std::swap;
+
+ // [set.erasure], erasure for set
+ using std::erase_if;
+
+ // [multiset], class template multiset
+ using std::multiset;
+
+ namespace pmr {
+ using std::pmr::multiset;
+ using std::pmr::set;
+ } // namespace pmr
+} // namespace std
+
+// shared_mutex.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_THREADS
+ // [thread.sharedmutex.class], class shared_­mutex
+ using std::shared_mutex;
+ // [thread.sharedtimedmutex.class], class shared_­timed_­mutex
+ using std::shared_timed_mutex;
+ // [thread.lock.shared], class template shared_­lock
+ using std::shared_lock;
+ using std::swap;
+#endif // _LIBCPP_HAS_NO_THREADS
+} // namespace std
+
+// source_location.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::source_location;
+} // namespace std
+
+// span.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // constants
+ using std::dynamic_extent;
+
+ // [views.span], class template span
+ using std::span;
+
+ namespace ranges {
+ using std::ranges::enable_borrowed_range;
+ using std::ranges::enable_view;
+ } // namespace ranges
+
+ // [span.objectrep], views of object representation
+ using std::as_bytes;
+
+ using std::as_writable_bytes;
+} // namespace std
+
+// spanstream.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#if 0
+ using std::basic_spanbuf;
+
+ using std::swap;
+
+ using std::spanbuf;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wspanbuf;
+# endif
+
+ using std::basic_ispanstream;
+
+ using std::ispanstream;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wispanstream;
+# endif
+
+ using std::basic_ospanstream;
+
+ using std::ospanstream;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wospanstream;
+# endif
+
+ using std::basic_spanstream;
+
+ using std::spanstream;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wspanstream;
+# endif
+#endif
+} // namespace std
+
+// sstream.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ using std::basic_stringbuf;
+
+ using std::swap;
+
+ using std::stringbuf;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wstringbuf;
+# endif
+
+ using std::basic_istringstream;
+
+ using std::istringstream;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wistringstream;
+# endif
+
+ using std::basic_ostringstream;
+
+ using std::ostringstream;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wostringstream;
+# endif
+
+ using std::basic_stringstream;
+
+ using std::stringstream;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wstringstream;
+# endif
+#endif // _LIBCPP_HAS_NO_LOCALIZATION
+} // namespace std
+
+// stack.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [stack], class template stack
+ using std::stack;
+
+ using std::operator==;
+ using std::operator!=;
+ using std::operator<;
+ using std::operator>;
+ using std::operator<=;
+ using std::operator>=;
+ using std::operator<=>;
+
+ using std::swap;
+ using std::uses_allocator;
+} // namespace std
+
+// stacktrace.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#if 0
+ // [stacktrace.entry], class stacktrace_­entry
+ using std::stacktrace_entry;
+
+ // [stacktrace.basic], class template basic_­stacktrace
+ using std::basic_stacktrace;
+
+ // basic_­stacktrace typedef-names
+ using std::stacktrace;
+
+ // [stacktrace.basic.nonmem], non-member functions
+ using std::swap;
+
+ using std::to_string;
+
+ using std::operator<<;
+
+ namespace pmr {
+ using std::pmr::stacktrace;
+ }
+
+ // [stacktrace.basic.hash], hash support
+ using std::hash;
+#endif
+} // namespace std
+
+// stdexcept.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::domain_error;
+ using std::invalid_argument;
+ using std::length_error;
+ using std::logic_error;
+ using std::out_of_range;
+ using std::overflow_error;
+ using std::range_error;
+ using std::runtime_error;
+ using std::underflow_error;
+} // namespace std
+
+// stdfloat.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#if defined(__STDCPP_FLOAT16_T__)
+ using std::float16_t;
+#endif
+#if defined(__STDCPP_FLOAT32_T__)
+ using std::float32_t;
+#endif
+#if defined(__STDCPP_FLOAT64_T__)
+ using std::float64_t;
+#endif
+#if defined(__STDCPP_FLOAT128_T__)
+ using std::float128_t;
+#endif
+#if defined(__STDCPP_BFLOAT16_T__)
+ using std::bfloat16_t;
+#endif
+} // namespace std
+
+// stop_token.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_THREADS
+# ifdef _LIBCPP_ENABLE_EXPERIMENTAL
+ // [stoptoken], class stop_­token
+ using std::stop_token;
+
+ // [stopsource], class stop_­source
+ using std::stop_source;
+
+ // no-shared-stop-state indicator
+ using std::nostopstate;
+ using std::nostopstate_t;
+
+ // [stopcallback], class template stop_­callback
+ using std::stop_callback;
+# endif // _LIBCPP_ENABLE_EXPERIMENTAL
+#endif // _LIBCPP_HAS_NO_THREADS
+} // namespace std
+
+// streambuf.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ using std::basic_streambuf;
+ using std::streambuf;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wstreambuf;
+# endif
+#endif // _LIBCPP_HAS_NO_LOCALIZATION
+} // namespace std
+
+// string.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [char.traits], character traits
+ using std::char_traits;
+
+ // [basic.string], basic_string
+ using std::basic_string;
+
+ using std::operator+;
+ using std::operator==;
+ using std::operator<=>;
+
+ // [string.special], swap
+ using std::swap;
+
+ // [string.io], inserters and extractors
+ using std::operator>>;
+ using std::operator<<;
+ using std::getline;
+
+ // [string.erasure], erasure
+ using std::erase;
+ using std::erase_if;
+
+ // basic_string typedef-names
+ using std::string;
+ using std::u16string;
+ using std::u32string;
+#ifndef _LIBCPP_HAS_NO_CHAR8_T
+ using std::u8string;
+#endif
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wstring;
+#endif
+
+ // [string.conversions], numeric conversions
+ using std::stod;
+ using std::stof;
+ using std::stoi;
+ using std::stol;
+ using std::stold;
+ using std::stoll;
+ using std::stoul;
+ using std::stoull;
+ using std::to_string;
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::to_wstring;
+#endif
+
+ namespace pmr {
+ using std::pmr::basic_string;
+ using std::pmr::string;
+ using std::pmr::u16string;
+ using std::pmr::u32string;
+#ifndef _LIBCPP_HAS_NO_CHAR8_T
+ using std::pmr::u8string;
+#endif
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::pmr::wstring;
+#endif
+ } // namespace pmr
+
+ // [basic.string.hash], hash support
+ using std::hash;
+
+ inline namespace literals {
+ inline namespace string_literals {
+ // [basic.string.literals], suffix for basic_string literals
+ using std::literals::string_literals::operator""s;
+ } // namespace string_literals
+ } // namespace literals
+} // namespace std
+
+// string_view.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [string.view.template], class template basic_string_view
+ using std::basic_string_view;
+
+ namespace ranges {
+ using std::ranges::enable_borrowed_range;
+ using std::ranges::enable_view;
+ } // namespace ranges
+
+ // [string.view.comparison], non-member comparison functions
+ using std::operator==;
+ using std::operator<=>;
+
+ // [string.view.io], inserters and extractors
+ using std::operator<<;
+
+ // basic_string_view typedef-names
+ using std::string_view;
+ using std::u16string_view;
+ using std::u32string_view;
+#ifndef _LIBCPP_HAS_NO_CHAR8_T
+ using std::u8string_view;
+#endif
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wstring_view;
+#endif
+
+ // [string.view.hash], hash support
+ using std::hash;
+
+ inline namespace literals {
+ inline namespace string_view_literals {
+ // [string.view.literals], suffix for basic_string_view literals
+ using std::literals::string_view_literals::operator""sv;
+ } // namespace string_view_literals
+ } // namespace literals
+} // namespace std
+
+// strstream.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ using std::istrstream;
+ using std::ostrstream;
+ using std::strstream;
+ using std::strstreambuf;
+#endif // _LIBCPP_HAS_NO_LOCALIZATION
+} // namespace std
+
+// syncstream.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
+ using std::basic_syncbuf;
+
+ // [syncstream.syncbuf.special], specialized algorithms
+ using std::swap;
+
+ using std::syncbuf;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wsyncbuf;
+# endif
+ using std::basic_osyncstream;
+
+ using std::osyncstream;
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using std::wosyncstream;
+# endif
+#endif // !defined(_LIBCPP_HAS_NO_LOCALIZATION) && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
+} // namespace std
+
+// system_error.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::error_category;
+ using std::generic_category;
+ using std::system_category;
+
+ using std::error_code;
+ using std::error_condition;
+ using std::system_error;
+
+ using std::is_error_code_enum;
+ using std::is_error_condition_enum;
+
+ using std::errc;
+
+ // [syserr.errcode.nonmembers], non-member functions
+ using std::make_error_code;
+
+ using std::operator<<;
+
+ // [syserr.errcondition.nonmembers], non-member functions
+ using std::make_error_condition;
+
+ // [syserr.compare], comparison operator functions
+ using std::operator==;
+ using std::operator<=>;
+
+ // [syserr.hash], hash support
+ using std::hash;
+
+ // [syserr], system error support
+ using std::is_error_code_enum_v;
+ using std::is_error_condition_enum_v;
+} // namespace std
+
+// text_encoding.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#if 0
+# if _LIBCPP_STD_VER >= 23
+ using std::text_encoding;
+
+ // hash support
+ using std::hash;
+# endif // _LIBCPP_STD_VER >= 23
+#endif
+} // namespace std
+
+// thread.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+#ifndef _LIBCPP_HAS_NO_THREADS
+ // [thread.thread.class], class thread
+ using std::thread;
+
+ using std::swap;
+
+ // [thread.jthread.class], class jthread
+# if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN)
+ using std::jthread;
+# endif
+
+ // [thread.thread.this], namespace this_thread
+ namespace this_thread {
+ using std::this_thread::get_id;
+
+ using std::this_thread::sleep_for;
+ using std::this_thread::sleep_until;
+ using std::this_thread::yield;
+ } // namespace this_thread
+
+ // [thread.thread.id]
+ using std::operator==;
+ using std::operator<=>;
+# ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ using std::operator<<;
+# endif // _LIBCPP_HAS_NO_LOCALIZATION
+
+# if _LIBCPP_STD_VER >= 23
+ using std::formatter;
+# endif
+
+ using std::hash;
+#endif // _LIBCPP_HAS_NO_THREADS
+} // namespace std
+
+// tuple.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [tuple.tuple], class template tuple
+ using std::tuple;
+
+ // [tuple.like], concept tuple-like
+
+#if _LIBCPP_STD_VER >= 23
+ // [tuple.common.ref], common_reference related specializations
+ using std::basic_common_reference;
+ using std::common_type;
+#endif
+
+ // [tuple.creation], tuple creation functions
+ using std::ignore;
+
+ using std::forward_as_tuple;
+ using std::make_tuple;
+ using std::tie;
+ using std::tuple_cat;
+
+ // [tuple.apply], calling a function with a tuple of arguments
+ using std::apply;
+
+ using std::make_from_tuple;
+
+ // [tuple.helper], tuple helper classes
+ using std::tuple_element;
+ using std::tuple_size;
+
+ // [tuple.elem], element access
+ using std::get;
+ using std::tuple_element_t;
+
+ // [tuple.rel], relational operators
+ using std::operator==;
+ using std::operator<=>;
+
+ // [tuple.traits], allocator-related traits
+ using std::uses_allocator;
+
+ // [tuple.special], specialized algorithms
+ using std::swap;
+
+ // [tuple.helper], tuple helper classes
+ using std::tuple_size_v;
+} // namespace std
+
+// type_traits.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [meta.help], helper class
+ using std::integral_constant;
+
+ using std::bool_constant;
+ using std::false_type;
+ using std::true_type;
+
+ // [meta.unary.cat], primary type categories
+ using std::is_array;
+ using std::is_class;
+ using std::is_enum;
+ using std::is_floating_point;
+ using std::is_function;
+ using std::is_integral;
+ using std::is_lvalue_reference;
+ using std::is_member_function_pointer;
+ using std::is_member_object_pointer;
+ using std::is_null_pointer;
+ using std::is_pointer;
+ using std::is_rvalue_reference;
+ using std::is_union;
+ using std::is_void;
+
+ // [meta.unary.comp], composite type categories
+ using std::is_arithmetic;
+ using std::is_compound;
+ using std::is_fundamental;
+ using std::is_member_pointer;
+ using std::is_object;
+ using std::is_reference;
+ using std::is_scalar;
+
+ // [meta.unary.prop], type properties
+ using std::is_abstract;
+ using std::is_aggregate;
+ using std::is_const;
+ using std::is_empty;
+ using std::is_final;
+ using std::is_polymorphic;
+ using std::is_standard_layout;
+ using std::is_trivial;
+ using std::is_trivially_copyable;
+ using std::is_volatile;
+
+ using std::is_bounded_array;
+#if _LIBCPP_STD_VER >= 23
+ using std::is_scoped_enum;
+#endif
+ using std::is_signed;
+ using std::is_unbounded_array;
+ using std::is_unsigned;
+
+ using std::is_constructible;
+ using std::is_copy_constructible;
+ using std::is_default_constructible;
+ using std::is_move_constructible;
+
+ using std::is_assignable;
+ using std::is_copy_assignable;
+ using std::is_move_assignable;
+
+ using std::is_swappable;
+ using std::is_swappable_with;
+
+ using std::is_destructible;
+
+ using std::is_trivially_constructible;
+ using std::is_trivially_copy_constructible;
+ using std::is_trivially_default_constructible;
+ using std::is_trivially_move_constructible;
+
+ using std::is_trivially_assignable;
+ using std::is_trivially_copy_assignable;
+ using std::is_trivially_destructible;
+ using std::is_trivially_move_assignable;
+
+ using std::is_nothrow_constructible;
+ using std::is_nothrow_copy_constructible;
+ using std::is_nothrow_default_constructible;
+ using std::is_nothrow_move_constructible;
+
+ using std::is_nothrow_assignable;
+ using std::is_nothrow_copy_assignable;
+ using std::is_nothrow_move_assignable;
+
+ using std::is_nothrow_swappable;
+ using std::is_nothrow_swappable_with;
+
+ using std::is_nothrow_destructible;
+
+ // using std::is_implicit_lifetime;
+
+ using std::has_virtual_destructor;
+
+ using std::has_unique_object_representations;
+
+ // using std::reference_constructs_from_temporary;
+ // using std::reference_converts_from_temporary;
+
+ // [meta.unary.prop.query], type property queries
+ using std::alignment_of;
+ using std::extent;
+ using std::rank;
+
+ // [meta.rel], type relations
+ using std::is_base_of;
+ using std::is_convertible;
+ // using std::is_layout_compatible;
+ using std::is_nothrow_convertible;
+ // using std::is_pointer_interconvertible_base_of;
+ using std::is_same;
+
+ using std::is_invocable;
+ using std::is_invocable_r;
+
+ using std::is_nothrow_invocable;
+ using std::is_nothrow_invocable_r;
+
+ // [meta.trans.cv], const-volatile modifications
+ using std::add_const;
+ using std::add_cv;
+ using std::add_volatile;
+ using std::remove_const;
+ using std::remove_cv;
+ using std::remove_volatile;
+
+ using std::add_const_t;
+ using std::add_cv_t;
+ using std::add_volatile_t;
+ using std::remove_const_t;
+ using std::remove_cv_t;
+ using std::remove_volatile_t;
+
+ // [meta.trans.ref], reference modifications
+ using std::add_lvalue_reference;
+ using std::add_rvalue_reference;
+ using std::remove_reference;
+
+ using std::add_lvalue_reference_t;
+ using std::add_rvalue_reference_t;
+ using std::remove_reference_t;
+
+ // [meta.trans.sign], sign modifications
+ using std::make_signed;
+ using std::make_unsigned;
+
+ using std::make_signed_t;
+ using std::make_unsigned_t;
+
+ // [meta.trans.arr], array modifications
+ using std::remove_all_extents;
+ using std::remove_extent;
+
+ using std::remove_all_extents_t;
+ using std::remove_extent_t;
+
+ // [meta.trans.ptr], pointer modifications
+ using std::add_pointer;
+ using std::remove_pointer;
+
+ using std::add_pointer_t;
+ using std::remove_pointer_t;
+
+ // [meta.trans.other], other transformations
+ using std::basic_common_reference;
+ using std::common_reference;
+ using std::common_type;
+ using std::conditional;
+ using std::decay;
+ using std::enable_if;
+ using std::invoke_result;
+ using std::remove_cvref;
+ using std::type_identity;
+ using std::underlying_type;
+ using std::unwrap_ref_decay;
+ using std::unwrap_reference;
+
+ using std::common_reference_t;
+ using std::common_type_t;
+ using std::conditional_t;
+ using std::decay_t;
+ using std::enable_if_t;
+ using std::invoke_result_t;
+ using std::remove_cvref_t;
+ using std::type_identity_t;
+ using std::underlying_type_t;
+ using std::unwrap_ref_decay_t;
+ using std::unwrap_reference_t;
+ using std::void_t;
+
+ // [meta.logical], logical operator traits
+ using std::conjunction;
+ using std::disjunction;
+ using std::negation;
+
+ // [meta.unary.cat], primary type categories
+ using std::is_array_v;
+ using std::is_class_v;
+ using std::is_enum_v;
+ using std::is_floating_point_v;
+ using std::is_function_v;
+ using std::is_integral_v;
+ using std::is_lvalue_reference_v;
+ using std::is_member_function_pointer_v;
+ using std::is_member_object_pointer_v;
+ using std::is_null_pointer_v;
+ using std::is_pointer_v;
+ using std::is_rvalue_reference_v;
+ using std::is_union_v;
+ using std::is_void_v;
+
+ // [meta.unary.comp], composite type categories
+ using std::is_arithmetic_v;
+ using std::is_compound_v;
+ using std::is_fundamental_v;
+ using std::is_member_pointer_v;
+ using std::is_object_v;
+ using std::is_reference_v;
+ using std::is_scalar_v;
+
+ // [meta.unary.prop], type properties
+ using std::has_unique_object_representations_v;
+ using std::has_virtual_destructor_v;
+ using std::is_abstract_v;
+ using std::is_aggregate_v;
+ using std::is_assignable_v;
+ using std::is_bounded_array_v;
+ using std::is_const_v;
+ using std::is_constructible_v;
+ using std::is_copy_assignable_v;
+ using std::is_copy_constructible_v;
+ using std::is_default_constructible_v;
+ using std::is_destructible_v;
+ using std::is_empty_v;
+ using std::is_final_v;
+ // using std::is_implicit_lifetime_v;
+ using std::is_move_assignable_v;
+ using std::is_move_constructible_v;
+ using std::is_nothrow_assignable_v;
+ using std::is_nothrow_constructible_v;
+ using std::is_nothrow_copy_assignable_v;
+ using std::is_nothrow_copy_constructible_v;
+ using std::is_nothrow_default_constructible_v;
+ using std::is_nothrow_destructible_v;
+ using std::is_nothrow_move_assignable_v;
+ using std::is_nothrow_move_constructible_v;
+ using std::is_nothrow_swappable_v;
+ using std::is_nothrow_swappable_with_v;
+ using std::is_polymorphic_v;
+#if _LIBCPP_STD_VER >= 23
+ using std::is_scoped_enum_v;
+#endif
+ using std::is_signed_v;
+ using std::is_standard_layout_v;
+ using std::is_swappable_v;
+ using std::is_swappable_with_v;
+ using std::is_trivial_v;
+ using std::is_trivially_assignable_v;
+ using std::is_trivially_constructible_v;
+ using std::is_trivially_copy_assignable_v;
+ using std::is_trivially_copy_constructible_v;
+ using std::is_trivially_copyable_v;
+ using std::is_trivially_default_constructible_v;
+ using std::is_trivially_destructible_v;
+ using std::is_trivially_move_assignable_v;
+ using std::is_trivially_move_constructible_v;
+ using std::is_unbounded_array_v;
+ using std::is_unsigned_v;
+ using std::is_volatile_v;
+ // using std::reference_constructs_from_temporary_v;
+ // using std::reference_converts_from_temporary_v;
+
+ // [meta.unary.prop.query], type property queries
+ using std::alignment_of_v;
+ using std::extent_v;
+ using std::rank_v;
+
+ // [meta.rel], type relations
+ using std::is_base_of_v;
+ using std::is_convertible_v;
+ using std::is_invocable_r_v;
+ using std::is_invocable_v;
+ // using std::is_layout_compatible_v;
+ using std::is_nothrow_convertible_v;
+ using std::is_nothrow_invocable_r_v;
+ using std::is_nothrow_invocable_v;
+ // using std::is_pointer_interconvertible_base_of_v;
+ using std::is_same_v;
+
+ // [meta.logical], logical operator traits
+ using std::conjunction_v;
+ using std::disjunction_v;
+ using std::negation_v;
+
+ // [meta.member], member relationships
+ // using std::is_corresponding_member;
+ // using std::is_pointer_interconvertible_with_class;
+
+ // [meta.const.eval], constant evaluation context
+ using std::is_constant_evaluated;
+
+ // [depr.meta.types]
+ using std::aligned_storage;
+ using std::aligned_storage_t;
+ using std::aligned_union;
+ using std::aligned_union_t;
+ using std::is_pod;
+ using std::is_pod_v;
+} // namespace std
+
+// typeindex.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::hash;
+ using std::type_index;
+} // namespace std
+
+// typeinfo.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::bad_cast;
+ using std::bad_typeid;
+ using std::type_info;
+} // namespace std
+
+// unordered_map.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [unord.map], class template unordered_­map
+ using std::unordered_map;
+
+ // [unord.multimap], class template unordered_­multimap
+ using std::unordered_multimap;
+
+ using std::operator==;
+
+ using std::swap;
+
+ // [unord.map.erasure], erasure for unordered_­map
+ using std::erase_if;
+
+ namespace pmr {
+ using std::pmr::unordered_map;
+ using std::pmr::unordered_multimap;
+ } // namespace pmr
+} // namespace std
+
+// unordered_set.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [unord.set], class template unordered_­set
+ using std::unordered_set;
+
+ // [unord.multiset], class template unordered_­multiset
+ using std::unordered_multiset;
+
+ using std::operator==;
+
+ using std::swap;
+
+ // [unord.set.erasure], erasure for unordered_­set
+ using std::erase_if;
+
+ namespace pmr {
+ using std::pmr::unordered_multiset;
+ using std::pmr::unordered_set;
+ } // namespace pmr
+} // namespace std
+
+// utility.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [utility.swap], swap
+ using std::swap;
+
+ // [utility.exchange], exchange
+ using std::exchange;
+
+ // [forward], forward/move
+ using std::forward;
+#if _LIBCPP_STD_VER >= 23
+ using std::forward_like;
+#endif
+ using std::move;
+ using std::move_if_noexcept;
+
+ // [utility.as.const], as_const
+ using std::as_const;
+
+ // [declval], declval
+ using std::declval;
+
+ // [utility.intcmp], integer comparison functions
+ using std::cmp_equal;
+ using std::cmp_not_equal;
+
+ using std::cmp_greater;
+ using std::cmp_greater_equal;
+ using std::cmp_less;
+ using std::cmp_less_equal;
+
+ using std::in_range;
+
+#if _LIBCPP_STD_VER >= 23
+ // [utility.underlying], to_underlying
+ using std::to_underlying;
+
+ // [utility.unreachable], unreachable
+ using std::unreachable;
+#endif // _LIBCPP_STD_VER >= 23
+
+ // [intseq], compile-time integer sequences
+ using std::index_sequence;
+ using std::integer_sequence;
+
+ using std::make_index_sequence;
+ using std::make_integer_sequence;
+
+ using std::index_sequence_for;
+
+ // [pairs], class template pair
+ using std::pair;
+
+#if _LIBCPP_STD_VER >= 23
+ using std::basic_common_reference;
+ using std::common_type;
+#endif
+ // [pairs.spec], pair specialized algorithms
+ using std::operator==;
+ using std::operator<=>;
+
+ using std::make_pair;
+
+ // [pair.astuple], tuple-like access to pair
+ using std::tuple_element;
+ using std::tuple_size;
+
+ using std::get;
+
+ // [pair.piecewise], pair piecewise construction
+ using std::piecewise_construct;
+ using std::piecewise_construct_t;
+
+ // in-place construction
+ using std::in_place;
+ using std::in_place_t;
+
+ using std::in_place_type;
+ using std::in_place_type_t;
+
+ using std::in_place_index;
+ using std::in_place_index_t;
+
+ // [depr.relops]
+ namespace rel_ops {
+ using rel_ops::operator!=;
+ using rel_ops::operator>;
+ using rel_ops::operator<=;
+ using rel_ops::operator>=;
+ } // namespace rel_ops
+} // namespace std
+
+// valarray.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ using std::gslice;
+ using std::gslice_array;
+ using std::indirect_array;
+ using std::mask_array;
+ using std::slice;
+ using std::slice_array;
+ using std::valarray;
+
+ using std::swap;
+
+ using std::operator*;
+ using std::operator/;
+ using std::operator%;
+ using std::operator+;
+ using std::operator-;
+
+ using std::operator^;
+ using std::operator&;
+ using std::operator|;
+
+ using std::operator<<;
+ using std::operator>>;
+
+ using std::operator&&;
+ using std::operator||;
+
+ using std::operator==;
+ using std::operator!=;
+
+ using std::operator<;
+ using std::operator>;
+ using std::operator<=;
+ using std::operator>=;
+
+ using std::abs;
+ using std::acos;
+ using std::asin;
+ using std::atan;
+
+ using std::atan2;
+
+ using std::cos;
+ using std::cosh;
+ using std::exp;
+ using std::log;
+ using std::log10;
+
+ using std::pow;
+
+ using std::sin;
+ using std::sinh;
+ using std::sqrt;
+ using std::tan;
+ using std::tanh;
+
+ using std::begin;
+ using std::end;
+} // namespace std
+
+// variant.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [variant.variant], class template variant
+ using std::variant;
+
+ // [variant.helper], variant helper classes
+ using std::variant_alternative;
+ using std::variant_npos;
+ using std::variant_size;
+ using std::variant_size_v;
+
+ // [variant.get], value access
+ using std::get;
+ using std::get_if;
+ using std::holds_alternative;
+ using std::variant_alternative_t;
+
+ // [variant.relops], relational operators
+ using std::operator==;
+ using std::operator!=;
+ using std::operator<;
+ using std::operator>;
+ using std::operator<=;
+ using std::operator>=;
+ using std::operator<=>;
+
+ // [variant.visit], visitation
+ using std::visit;
+
+ // [variant.monostate], class monostate
+ using std::monostate;
+
+ // [variant.specalg], specialized algorithms
+ using std::swap;
+
+ // [variant.bad.access], class bad_variant_access
+ using std::bad_variant_access;
+
+ // [variant.hash], hash support
+ using std::hash;
+} // namespace std
+
+// vector.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // [vector], class template vector
+ using std::vector;
+
+ using std::operator==;
+ using std::operator<=>;
+
+ using std::swap;
+
+ // [vector.erasure], erasure
+ using std::erase;
+ using std::erase_if;
+
+ namespace pmr {
+ using std::pmr::vector;
+ }
+
+ // hash support
+ using std::hash;
+
+#if _LIBCPP_STD_VER >= 23
+ // [vector.bool.fmt], formatter specialization for vector<bool>
+ using std::formatter;
+#endif
+} // namespace std
+
+// version.inc
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export namespace std {
+ // This module exports nothing.
+} // namespace std
diff --git a/libbuild2/cc/target.cxx b/libbuild2/cc/target.cxx
index d743752..6a518dd 100644
--- a/libbuild2/cc/target.cxx
+++ b/libbuild2/cc/target.cxx
@@ -66,6 +66,33 @@ namespace build2
target_type::flag::none
};
+ extern const char S_ext_def[] = "S";
+ const target_type S::static_type
+ {
+ "S",
+ &cc::static_type,
+ &target_factory<S>,
+ nullptr, /* fixed_extension */
+ &target_extension_var<S_ext_def>,
+ &target_pattern_var<S_ext_def>,
+ nullptr,
+ &file_search,
+ target_type::flag::none
+ };
+
+ const target_type c_inc::static_type
+ {
+ "c_inc",
+ &cc::static_type,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ &target_search,
+ target_type::flag::none
+ };
+
extern const char pc_ext[] = "pc"; // VC14 rejects constexpr.
const target_type pc::static_type
{
diff --git a/libbuild2/cc/target.hxx b/libbuild2/cc/target.hxx
index 87df326..01f2d6e 100644
--- a/libbuild2/cc/target.hxx
+++ b/libbuild2/cc/target.hxx
@@ -84,6 +84,41 @@ namespace build2
static const target_type static_type;
};
+ // Assembler with C preprocessor source file (the same rationale for
+ // having it here as for c{} above).
+ //
+ class LIBBUILD2_CC_SYMEXPORT S: public cc
+ {
+ public:
+ S (context& c, dir_path d, dir_path o, string n)
+ : cc (c, move (d), move (o), move (n))
+ {
+ dynamic_type = &static_type;
+ }
+
+ public:
+ static const target_type static_type;
+ };
+
+ // This is an abstract base target for deriving additional targets that
+ // can be #include'd in C translation units (the same rationale for having
+ // it here as for c{} above). In particular, only such targets will be
+ // considered to reverse-lookup extensions to target types (see
+ // dyndep_rule::map_extension() for background).
+ //
+ class LIBBUILD2_CC_SYMEXPORT c_inc: public cc
+ {
+ public:
+ c_inc (context& c, dir_path d, dir_path o, string n)
+ : cc (c, move (d), move (o), move (n))
+ {
+ dynamic_type = &static_type;
+ }
+
+ public:
+ static const target_type static_type;
+ };
+
// pkg-config file targets.
//
class LIBBUILD2_CC_SYMEXPORT pc: public file // .pc (common)
diff --git a/libbuild2/cc/types.cxx b/libbuild2/cc/types.cxx
index 8ee4fa9..c6cfae9 100644
--- a/libbuild2/cc/types.cxx
+++ b/libbuild2/cc/types.cxx
@@ -6,6 +6,7 @@
#include <libbuild2/cc/utility.hxx>
using namespace std;
+using namespace butl;
namespace build2
{
@@ -123,6 +124,8 @@ namespace build2
size_t importable_headers::
insert_angle_pattern (const dir_paths& sys_hdr_dirs, const string& pat)
{
+ tracer trace ("importable_headers::insert_angle_pattern");
+
assert (pat.front () == '<' && pat.back () == '>' && path_pattern (pat));
// First see if it has already been inserted.
@@ -172,7 +175,17 @@ namespace build2
try
{
- path_search (f, process, dir);
+ path_search (
+ f,
+ process,
+ dir,
+ path_match_flags::follow_symlinks,
+ [&trace] (const dir_entry& de)
+ {
+ l5 ([&]{trace << "skipping inaccessible/dangling entry "
+ << de.base () / de.path ();});
+ return true;
+ });
}
catch (const system_error& e)
{
diff --git a/libbuild2/cc/windows-rpath.cxx b/libbuild2/cc/windows-rpath.cxx
index 9387078..eb62ad1 100644
--- a/libbuild2/cc/windows-rpath.cxx
+++ b/libbuild2/cc/windows-rpath.cxx
@@ -45,6 +45,8 @@ namespace build2
// Return the greatest (newest) timestamp of all the DLLs that we will be
// adding to the assembly or timestamp_nonexistent if there aren't any.
//
+ // Note: called during the execute phase.
+ //
timestamp link_rule::
windows_rpath_timestamp (const file& t,
const scope& bs,
@@ -88,7 +90,18 @@ namespace build2
//
if (l->is_a<libs> () && !l->path ().empty ()) // Also covers binless.
{
- timestamp t (l->load_mtime ());
+ // Handle the case where the library is a member of a group (for
+ // example, people are trying to hack something up with pre-built
+ // libraries; see GH issue #366).
+ //
+ timestamp t;
+ if (l->group_state (action () /* inner */))
+ {
+ t = l->group->is_a<mtime_target> ()->mtime ();
+ assert (t != timestamp_unknown);
+ }
+ else
+ t = l->load_mtime ();
if (t > r)
r = t;
@@ -128,7 +141,9 @@ namespace build2
library_cache lib_cache;
for (const prerequisite_target& pt: t.prerequisite_targets[a])
{
- if (pt == nullptr || pt.adhoc ())
+ // Note: during execute so check for ad hoc first to avoid data races.
+ //
+ if (pt.adhoc () || pt == nullptr)
continue;
bool la;
@@ -255,7 +270,9 @@ namespace build2
library_cache lib_cache;
for (const prerequisite_target& pt: t.prerequisite_targets[a])
{
- if (pt == nullptr || pt.adhoc ())
+ // Note: during execute so check for ad hoc first to avoid data races.
+ //
+ if (pt.adhoc () || pt == nullptr)
continue;
bool la;