diff options
Diffstat (limited to 'libbuild2/cc')
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 = ∈} 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 = ∈} 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; |