diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2020-02-03 14:51:43 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2020-02-03 14:51:43 +0200 |
commit | 1195f9307c425ed28075a17671c13676b65f4a43 (patch) | |
tree | 6014ef54bb736a2949eb1f31a63a95d336fffd9b /libbuild2 | |
parent | a9cadecf15385f93ad3eb6b6b0bdeaafd741b0a7 (diff) |
Add header/library search paths from compiler mode to sys_*_dirs
Diffstat (limited to 'libbuild2')
-rw-r--r-- | libbuild2/c/init.cxx | 9 | ||||
-rw-r--r-- | libbuild2/cc/common.cxx | 66 | ||||
-rw-r--r-- | libbuild2/cc/common.hxx | 28 | ||||
-rw-r--r-- | libbuild2/cc/compile-rule.cxx | 42 | ||||
-rw-r--r-- | libbuild2/cc/gcc.cxx | 78 | ||||
-rw-r--r-- | libbuild2/cc/guess.cxx | 63 | ||||
-rw-r--r-- | libbuild2/cc/guess.hxx | 10 | ||||
-rw-r--r-- | libbuild2/cc/link-rule.cxx | 68 | ||||
-rw-r--r-- | libbuild2/cc/module.cxx | 50 | ||||
-rw-r--r-- | libbuild2/cc/module.hxx | 24 | ||||
-rw-r--r-- | libbuild2/cc/msvc.cxx | 116 | ||||
-rw-r--r-- | libbuild2/cxx/init.cxx | 9 |
12 files changed, 364 insertions, 199 deletions
diff --git a/libbuild2/c/init.cxx b/libbuild2/c/init.cxx index 5939d4c..c72f729 100644 --- a/libbuild2/c/init.cxx +++ b/libbuild2/c/init.cxx @@ -35,8 +35,7 @@ namespace build2 { public: explicit - config_module (config_data&& d) - : config_data (move (d)), cc::config_module (move (d)) {} + config_module (config_data&& d): cc::config_module (move (d)) {} virtual strings translate_std (const compiler_info&, @@ -345,7 +344,11 @@ namespace build2 cast<dir_paths> (rs[cm.x_sys_lib_dirs]), cast<dir_paths> (rs[cm.x_sys_inc_dirs]), - cm.x_info->sys_mod_dirs, + cm.x_info->sys_mod_dirs ? &cm.x_info->sys_mod_dirs->first : nullptr, + + cm.sys_lib_dirs_mode, + cm.sys_inc_dirs_mode, + cm.sys_mod_dirs_mode, cm.sys_lib_dirs_extra, cm.sys_inc_dirs_extra, diff --git a/libbuild2/cc/common.cxx b/libbuild2/cc/common.cxx index 1af64c8..b949c2b 100644 --- a/libbuild2/cc/common.cxx +++ b/libbuild2/cc/common.cxx @@ -815,7 +815,7 @@ namespace build2 if (!usrd) { - usrd = extract_library_dirs (*p.scope); + usrd = extract_library_search_dirs (*p.scope); // Handle automatic importing of installed build2 libraries. This is a // mirror side of the uninstalled case that is handled via the special @@ -1011,8 +1011,14 @@ namespace build2 return r; } + void + gcc_extract_library_search_dirs (const strings&, dir_paths&); // gcc.cxx + + void + msvc_extract_library_search_dirs (const strings&, dir_paths&); // msvc.cxx + dir_paths common:: - extract_library_dirs (const scope& bs) const + extract_library_search_dirs (const scope& bs) const { dir_paths r; @@ -1020,58 +1026,18 @@ namespace build2 // auto extract = [&bs, &r, this] (const value& val, const variable& var) { - bool msvc (tsys == "win32-msvc"); - const auto& v (cast<strings> (val)); - for (auto i (v.begin ()), e (v.end ()); i != e; ++i) - { - const string& o (*i); - - dir_path d; - - try + auto df = make_diag_frame ( + [&var, &bs](const diag_record& dr) { - if (msvc) - { - // /LIBPATH:<dir> (case-insensitive). - // - if ((o[0] == '/' || o[0] == '-') && - icasecmp (o.c_str () + 1, "LIBPATH:", 8) == 0) - d = dir_path (o, 9, string::npos); - else - continue; - } - else - { - // -L can either be in the "-L<dir>" or "-L <dir>" form. - // - if (o == "-L") - { - if (++i == e) - break; // Let the compiler complain. - - d = dir_path (*i); - } - else if (o.compare (0, 2, "-L") == 0) - d = dir_path (o, 2, string::npos); - else - continue; - } - } - catch (const invalid_path& e) - { - fail << "invalid directory '" << e.path << "'" - << " in option '" << o << "'" - << " in variable " << var - << " for scope " << bs; - } + dr << info << "in variable " << var << " for scope " << bs; + }); - // Ignore relative paths. Or maybe we should warn? - // - if (!d.relative ()) - r.push_back (move (d)); - } + if (tsys == "win32-msvc") + msvc_extract_library_search_dirs (v, r); + else + gcc_extract_library_search_dirs (v, r); }; if (auto l = bs[c_loptions]) extract (*l, c_loptions); diff --git a/libbuild2/cc/common.hxx b/libbuild2/cc/common.hxx index a17442a..56dcec4 100644 --- a/libbuild2/cc/common.hxx +++ b/libbuild2/cc/common.hxx @@ -162,12 +162,20 @@ namespace build2 const strings* xlate_hdr; // x.translatable_headers (NULL if // unused/empty). - const dir_paths& sys_lib_dirs; // x.sys_lib_dirs - const dir_paths& sys_inc_dirs; // x.sys_inc_dirs - const optional<dir_paths>& sys_mod_dirs; // compiler_info::sys_mod_dirs + // 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/*). + // + const dir_paths& sys_lib_dirs; // x.sys_lib_dirs + const dir_paths& sys_inc_dirs; // x.sys_inc_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_inc_dirs_mode; + size_t sys_mod_dirs_mode; - size_t sys_lib_dirs_extra; // First extra path (size if none). - size_t sys_inc_dirs_extra; // First extra path (size if none). + size_t sys_lib_dirs_extra; // First trailing extra entry (size if none). + size_t sys_inc_dirs_extra; const target_type& x_src; // Source target type (c{}, cxx{}). const target_type* x_mod; // Module target type (mxx{}), if any. @@ -214,9 +222,9 @@ namespace build2 bool fs, const dir_paths& sld, const dir_paths& sid, - const optional<dir_paths>& smd, - size_t sle, - size_t sie, + const dir_paths* smd, + size_t slm, size_t sim, size_t smm, + size_t sle, size_t sie, const target_type& src, const target_type* mod, const target_type* const* hdr, @@ -235,6 +243,8 @@ namespace build2 symexport (fs), xlate_hdr (nullptr), sys_lib_dirs (sld), sys_inc_dirs (sid), sys_mod_dirs (smd), + sys_lib_dirs_mode (slm), sys_inc_dirs_mode (sim), + sys_mod_dirs_mode (smm), sys_lib_dirs_extra (sle), sys_inc_dirs_extra (sie), x_src (src), x_mod (mod), x_hdr (hdr), x_inc (inc) {} }; @@ -324,7 +334,7 @@ namespace build2 } dir_paths - extract_library_dirs (const scope&) const; + extract_library_search_dirs (const scope&) const; // Alternative search logic for VC (msvc.cxx). // diff --git a/libbuild2/cc/compile-rule.cxx b/libbuild2/cc/compile-rule.cxx index de35ad5..6d4321a 100644 --- a/libbuild2/cc/compile-rule.cxx +++ b/libbuild2/cc/compile-rule.cxx @@ -192,12 +192,19 @@ namespace build2 { assert (sys_inc_dirs_extra <= sys_inc_dirs.size ()); - auto b (sys_inc_dirs.begin ()); - auto m (b + sys_inc_dirs_extra); + // Note that the mode options are added as part of cmode. + // + auto b (sys_inc_dirs.begin () + sys_inc_dirs_mode); + auto m (sys_inc_dirs.begin () + sys_inc_dirs_extra); auto e (sys_inc_dirs.end ()); + // Note: starting from 15.6, MSVC gained /external:I option though it + // doesn't seem to affect the order, only "system-ness". + // append_option_values ( - args, cclass == compiler_class::msvc ? "/I" : "-I", + args, + cclass == compiler_class::gcc ? "-idirafter" : + cclass == compiler_class::msvc ? "/I" : "-I", m, e, [] (const dir_path& d) {return d.string ().c_str ();}); @@ -866,10 +873,6 @@ namespace build2 // Hash *.export.poptions from prerequisite libraries. // append_lib_options (bs, cs, a, t, li); - - // Extra system header dirs (last). - // - append_sys_inc_options (cs); } append_options (cs, t, c_coptions); @@ -886,6 +889,9 @@ namespace build2 append_options (cs, cmode); + if (md.pp != preprocessed::all) + append_sys_inc_options (cs); // Extra system header dirs (last). + if (dd.expect (cs.string ()) != nullptr) l4 ([&]{trace << "options mismatch forcing update of " << t;}); } @@ -2933,10 +2939,6 @@ namespace build2 } } - // Extra system header dirs (last). - // - append_sys_inc_options (args); - if (md.symexport) append_symexport_options (args, t); @@ -2980,6 +2982,7 @@ namespace build2 args.push_back ("/nologo"); append_options (args, cmode); + append_sys_inc_options (args); // Extra system header dirs (last). // See perform_update() for details on overriding the default // exceptions and runtime. @@ -3036,6 +3039,7 @@ namespace build2 } append_options (args, cmode); + append_sys_inc_options (args); // Extra system header dirs (last). // Setup the dynamic module mapper if needed. // @@ -4080,8 +4084,6 @@ namespace build2 append_lib_options (t.base_scope (), args, a, t, li); - append_sys_inc_options (args); - if (md.symexport) append_symexport_options (args, t); @@ -4112,6 +4114,7 @@ namespace build2 args.push_back ("/nologo"); append_options (args, cmode); + append_sys_inc_options (args); if (x_lang == lang::cxx && !find_option_prefix ("/EH", args)) args.push_back ("/EHsc"); @@ -4147,6 +4150,7 @@ namespace build2 } append_options (args, cmode); + append_sys_inc_options (args); args.push_back ("-E"); append_lang_options (args, md); @@ -5595,7 +5599,7 @@ namespace build2 { // Add the VC's default directory (should be only one). // - if (sys_mod_dirs && !sys_mod_dirs->empty ()) + if (sys_mod_dirs != nullptr && !sys_mod_dirs->empty ()) { args.push_back ("/module:stdIfcDir"); args.push_back (sys_mod_dirs->front ().string ().c_str ()); @@ -5693,10 +5697,6 @@ namespace build2 // append_lib_options (bs, args, a, t, li); - // Extra system header dirs (last). - // - append_sys_inc_options (args); - if (md.symexport) append_symexport_options (args, t); } @@ -5726,6 +5726,9 @@ namespace build2 append_options (args, cmode); + if (md.pp != preprocessed::all) + append_sys_inc_options (args); // Extra system header dirs (last). + // While we want to keep the low-level build as "pure" as possible, // the two misguided defaults, exceptions and runtime, just have to be // fixed. Otherwise the default build is pretty much unusable. But we @@ -5889,6 +5892,9 @@ namespace build2 append_options (args, cmode); + if (md.pp != preprocessed::all) + append_sys_inc_options (args); // Extra system header dirs (last). + append_header_options (env, args, header_args, a, t, md, md.dd); append_module_options (env, args, module_args, a, t, md, md.dd); diff --git a/libbuild2/cc/gcc.cxx b/libbuild2/cc/gcc.cxx index 91a04f6..5d84f85 100644 --- a/libbuild2/cc/gcc.cxx +++ b/libbuild2/cc/gcc.cxx @@ -23,17 +23,61 @@ namespace build2 { using namespace bin; + void + gcc_extract_library_search_dirs (const strings& v, dir_paths& r) + { + for (auto i (v.begin ()), e (v.end ()); i != e; ++i) + { + const string& o (*i); + + dir_path d; + try + { + // -L can either be in the "-L<dir>" or "-L <dir>" form. + // + if (o == "-L") + { + if (++i == e) + break; // Let the compiler complain. + + d = dir_path (*i); + } + else if (o.compare (0, 2, "-L") == 0) + d = dir_path (o, 2, string::npos); + else + continue; + } + catch (const invalid_path& e) + { + fail << "invalid directory '" << e.path << "'" << " in option '" + << o << "'"; + } + + // Ignore relative paths. Or maybe we should warn? + // + if (!d.relative ()) + r.push_back (move (d)); + } + } + // Extract system header search paths from GCC (gcc/g++) or compatible - // (Clang, Intel) using the -v -E </dev/null method. + // (Clang, Intel) using the `-v -E </dev/null` method. + // + // Note that we currently do not return an accurate number of mode paths + // though this information is currently not used for this compiler class. + // It's not even clear whether we can do this correctly since GCC will + // ignore an already-known system include path. Probably the only way to + // do this is to run the compiler twice. // - dir_paths config_module:: - gcc_header_search_paths (const process_path& xc, scope& rs) const + pair<dir_paths, size_t> config_module:: + gcc_header_search_dirs (const process_path& xc, 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. + // cstrings args {xc.recall_string ()}; - append_options (args, rs, c_coptions); - append_options (args, rs, x_coptions); append_options (args, tstd); append_options (args, rs, x_mode); @@ -154,14 +198,14 @@ namespace build2 fail << "unable to extract " << x_lang << " compiler system header " << "search paths"; - return r; + return make_pair (move (r), size_t (0)); } // Extract system library search paths from GCC (gcc/g++) or compatible // (Clang, Intel) using the -print-search-dirs option. // - dir_paths config_module:: - gcc_library_search_paths (const process_path& xc, scope& rs) const + pair<dir_paths, size_t> config_module:: + gcc_library_search_dirs (const process_path& xc, 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". @@ -176,16 +220,20 @@ namespace build2 // Maybe it's time we stop playing these games and start running // everything with LC_ALL=C? One drawback of this approach is that the // command that we print isn't exactly how we run. Maybe print it with - // the environment variables in front? + // the environment variables in front? Also there is MinGW GCC. + // + // Note also that any -L that we may specify on the command line are not + // factored into the output (unlike for headers above). // dir_paths r; + // Extract -L paths from the compiler mode. + // + gcc_extract_library_search_dirs (cast<strings> (rs[x_mode]), r); + size_t rn (r.size ()); + cstrings args {xc.recall_string ()}; - append_options (args, rs, c_coptions); - append_options (args, rs, x_coptions); append_options (args, tstd); - append_options (args, rs, x_loptions); - append_options (args, rs, c_loptions); append_options (args, rs, x_mode); args.push_back ("-print-search-dirs"); args.push_back (nullptr); @@ -267,7 +315,9 @@ namespace build2 break; } - return r; + return make_pair (move (r), rn); } + + } } diff --git a/libbuild2/cc/guess.cxx b/libbuild2/cc/guess.cxx index 182a997..b63765f 100644 --- a/libbuild2/cc/guess.cxx +++ b/libbuild2/cc/guess.cxx @@ -1353,17 +1353,29 @@ namespace build2 << "' to runtime version" << endf; } + void + msvc_extract_header_search_dirs (const strings&, dir_paths&); // msvc.cxx + + void + msvc_extract_library_search_dirs (const strings&, dir_paths&); // msvc.cxx + // Return the MSVC system header search paths (i.e., what the Visual - // Studio command prompt puts into INCLUDE). + // Studio command prompt puts into INCLUDE) including any paths from the + // compiler mode and their count. // // Note that currently we don't add any ATL/MFC or WinRT paths (but could // do that probably first checking if they exist/empty). // - static dir_paths - msvc_inc (const msvc_info& mi) + static pair<dir_paths, size_t> + msvc_inc (const msvc_info& mi, const strings& mo) { dir_paths r; + // Extract /I paths from the compiler mode. + // + msvc_extract_header_search_dirs (mo, r); + size_t rn (r.size ()); + r.push_back (dir_path (mi.msvc_dir) /= "include"); // This path structure only appeared in Platform SDK 10 (if anyone wants @@ -1379,30 +1391,39 @@ namespace build2 r.push_back (dir_path (d) /= "um" ); } - return r; + return make_pair (move (r), rn); } // Return the MSVC system module search paths (i.e., what the Visual - // Studio command prompt puts into IFCPATH). + // Studio command prompt puts into IFCPATH) including any paths from the + // compiler mode and their count. // - static dir_paths - msvc_mod (const msvc_info& mi, const char* cpu) + static pair<dir_paths, size_t> + msvc_mod (const msvc_info& mi, const strings&, const char* cpu) { + //@@ TODO: mode. + dir_paths r; r.push_back ((dir_path (mi.msvc_dir) /= "ifc") /= cpu); - return r; + return make_pair (move (r), size_t (0)); } // Return the MSVC system library search paths (i.e., what the Visual - // Studio command prompt puts into LIB). + // Studio command prompt puts into LIB) including any paths from the + // compiler mode and their count. // - static dir_paths - msvc_lib (const msvc_info& mi, const char* cpu) + static pair<dir_paths, size_t> + msvc_lib (const msvc_info& mi, const strings& mo, const char* cpu) { dir_paths r; + // Extract /LIBPATH paths from the compiler mode. + // + msvc_extract_library_search_dirs (mo, r); + size_t rn (r.size ()); + r.push_back ((dir_path (mi.msvc_dir) /= "lib") /= cpu); // This path structure only appeared in Platform SDK 10 (if anyone wants @@ -1417,7 +1438,7 @@ namespace build2 r.push_back ((dir_path (d) /= "um" ) /= cpu); } - return r; + return make_pair (move (r), rn); } // Return the MSVC binutils search paths (i.e., what the Visual Studio @@ -1452,7 +1473,7 @@ namespace build2 const path& xc, const string* xv, const string* xt, - const strings&, + const strings& x_mo, const strings*, const strings*, const strings*, const strings*, const strings*, const strings*, @@ -1616,18 +1637,18 @@ namespace build2 // running out of the Visual Studio command prompt and will have to // supply PATH/INCLUDE/LIB/IFCPATH equivalents ourselves. // - optional<dir_paths> lib_dirs; - optional<dir_paths> inc_dirs; - optional<dir_paths> mod_dirs; + optional<pair<dir_paths, size_t>> lib_dirs; + optional<pair<dir_paths, size_t>> inc_dirs; + optional<pair<dir_paths, size_t>> mod_dirs; string bpat; if (const msvc_info* mi = static_cast<msvc_info*> (gr.info.get ())) { const char* cpu (msvc_cpu (target_triplet (t).cpu)); - lib_dirs = msvc_lib (*mi, cpu); - inc_dirs = msvc_inc (*mi); - mod_dirs = msvc_mod (*mi, cpu); + lib_dirs = msvc_lib (*mi, x_mo, cpu); + inc_dirs = msvc_inc (*mi, x_mo); + mod_dirs = msvc_mod (*mi, x_mo, cpu); bpat = msvc_bin (*mi, cpu); } @@ -2291,7 +2312,7 @@ namespace build2 // For Clang on Windows targeting MSVC we remap the target to match // MSVC's. // - optional<dir_paths> lib_dirs; + optional<pair<dir_paths, size_t>> lib_dirs; string bpat; if (tt.system == "windows-msvc") @@ -2333,7 +2354,7 @@ namespace build2 // to extract this from Clang and -print-search-paths would have been // the natural way for Clang to report it. But no luck. // - lib_dirs = msvc_lib (mi, cpu); + lib_dirs = msvc_lib (mi, x_mo, cpu); // Binutils search paths. // diff --git a/libbuild2/cc/guess.hxx b/libbuild2/cc/guess.hxx index b32aaa9..97acbf9 100644 --- a/libbuild2/cc/guess.hxx +++ b/libbuild2/cc/guess.hxx @@ -227,12 +227,12 @@ namespace build2 string c_stdlib; string x_stdlib; - // System library/header/module search paths, if extracted at the guess - // stage. + // System library/header/module search paths and number of leading mode + // entries, if extracted at the guess stage. // - optional<dir_paths> sys_lib_dirs; - optional<dir_paths> sys_inc_dirs; - optional<dir_paths> sys_mod_dirs; + optional<pair<dir_paths, size_t>> sys_lib_dirs; + optional<pair<dir_paths, size_t>> sys_inc_dirs; + optional<pair<dir_paths, size_t>> sys_mod_dirs; }; // In a sense this is analagous to the language standard which we handle diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx index 6969ef2..bf474e6 100644 --- a/libbuild2/cc/link-rule.cxx +++ b/libbuild2/cc/link-rule.cxx @@ -2331,39 +2331,6 @@ namespace build2 append_options (args, t, x_loptions); append_options (args, t, c_loptions); - // Extra system library dirs (last). - // - assert (sys_lib_dirs_extra <= sys_lib_dirs.size ()); - - 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. - // - auto b (sys_lib_dirs.begin ()); - auto m (b + sys_lib_dirs_extra); - auto e (sys_lib_dirs.end ()); - - for (auto i (m); i != e; ++i) - sargs1.push_back ("/LIBPATH:" + i->string ()); - - if (!getenv ("LIB")) - { - for (auto i (b); i != m; ++i) - sargs1.push_back ("/LIBPATH:" + i->string ()); - } - - append_args (sargs1); - } - else - { - append_option_values ( - args, - "-L", - sys_lib_dirs.begin () + sys_lib_dirs_extra, sys_lib_dirs.end (), - [] (const dir_path& d) {return d.string ().c_str ();}); - } - // Handle soname/rpath. // if (tclass == "windows") @@ -2446,6 +2413,41 @@ namespace build2 if (ldc) append_options (args, cmode); + + // Extra system library dirs (last). + // + assert (sys_lib_dirs_extra <= sys_lib_dirs.size ()); + + 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) + sargs1.push_back ("/LIBPATH:" + i->string ()); + + if (!getenv ("LIB")) + { + for (auto i (b); i != m; ++i) + sargs1.push_back ("/LIBPATH:" + i->string ()); + } + + append_args (sargs1); + } + else + { + append_option_values ( + args, + "-L", + sys_lib_dirs.begin () + sys_lib_dirs_extra, sys_lib_dirs.end (), + [] (const dir_path& d) {return d.string ().c_str ();}); + } } // All the options should now be in. Hash them and compare with the db. diff --git a/libbuild2/cc/module.cxx b/libbuild2/cc/module.cxx index 69530a2..e31519c 100644 --- a/libbuild2/cc/module.cxx +++ b/libbuild2/cc/module.cxx @@ -409,9 +409,9 @@ namespace build2 // // Note that for now module search paths only come from compiler_info. // - dir_paths lib_dirs; - dir_paths inc_dirs; - const optional<dir_paths>& mod_dirs (xi.sys_mod_dirs); + pair<dir_paths, size_t> lib_dirs; + pair<dir_paths, size_t> inc_dirs; + const optional<pair<dir_paths, size_t>>& mod_dirs (xi.sys_mod_dirs); if (xi.sys_lib_dirs) lib_dirs = *xi.sys_lib_dirs; @@ -420,10 +420,10 @@ namespace build2 switch (xi.class_) { case compiler_class::gcc: - lib_dirs = gcc_library_search_paths (xi.path, rs); + lib_dirs = gcc_library_search_dirs (xi.path, rs); break; case compiler_class::msvc: - lib_dirs = msvc_library_search_paths (xi.path, rs); + lib_dirs = msvc_library_search_dirs (xi.path, rs); break; } } @@ -435,16 +435,20 @@ namespace build2 switch (xi.class_) { case compiler_class::gcc: - inc_dirs = gcc_header_search_paths (xi.path, rs); + inc_dirs = gcc_header_search_dirs (xi.path, rs); break; case compiler_class::msvc: - inc_dirs = msvc_header_search_paths (xi.path, rs); + inc_dirs = msvc_header_search_dirs (xi.path, rs); break; } } - sys_lib_dirs_extra = lib_dirs.size (); - sys_inc_dirs_extra = inc_dirs.size (); + sys_lib_dirs_mode = lib_dirs.second; + sys_inc_dirs_mode = inc_dirs.second; + sys_mod_dirs_mode = mod_dirs ? mod_dirs->second : 0; + + sys_lib_dirs_extra = lib_dirs.first.size (); + sys_inc_dirs_extra = inc_dirs.first.size (); #ifndef _WIN32 // Add /usr/local/{include,lib}. We definitely shouldn't do this if we @@ -460,8 +464,8 @@ namespace build2 // on the next invocation. // { - auto& is (inc_dirs); - auto& ls (lib_dirs); + auto& is (inc_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 ()); @@ -598,40 +602,44 @@ namespace build2 dr << "\n pattern " << xi.pattern; } - if (verb >= 3 && mod_dirs && !mod_dirs->empty ()) + auto& mods (mod_dirs ? mod_dirs->first : dir_paths ()); + auto& incs (inc_dirs.first); + auto& libs (lib_dirs.first); + + if (verb >= 3 && !mods.empty ()) { dr << "\n mod dirs"; - for (const dir_path& d: *mod_dirs) + for (const dir_path& d: mods) { dr << "\n " << d; } } - if (verb >= 3 && !inc_dirs.empty ()) + if (verb >= 3 && !incs.empty ()) { dr << "\n inc dirs"; - for (size_t i (0); i != inc_dirs.size (); ++i) + for (size_t i (0); i != incs.size (); ++i) { if (i == sys_inc_dirs_extra) dr << "\n --"; - dr << "\n " << inc_dirs[i]; + dr << "\n " << incs[i]; } } - if (verb >= 3 && !lib_dirs.empty ()) + if (verb >= 3 && !libs.empty ()) { dr << "\n lib dirs"; - for (size_t i (0); i != lib_dirs.size (); ++i) + for (size_t i (0); i != libs.size (); ++i) { if (i == sys_lib_dirs_extra) dr << "\n --"; - dr << "\n " << lib_dirs[i]; + dr << "\n " << libs[i]; } } } - rs.assign (x_sys_lib_dirs) = move (lib_dirs); - rs.assign (x_sys_inc_dirs) = move (inc_dirs); + rs.assign (x_sys_lib_dirs) = move (lib_dirs.first); + rs.assign (x_sys_inc_dirs) = move (inc_dirs.first); // Load cc.core.config. // diff --git a/libbuild2/cc/module.hxx b/libbuild2/cc/module.hxx index 5c7b8ab..ae121ef 100644 --- a/libbuild2/cc/module.hxx +++ b/libbuild2/cc/module.hxx @@ -26,7 +26,7 @@ namespace build2 struct compiler_info; class LIBBUILD2_CC_SYMEXPORT config_module: public build2::module, - public virtual config_data + public config_data { public: explicit @@ -55,27 +55,31 @@ namespace build2 const compiler_info* x_info; - // Temporary storage for data::sys_*_dirs_extra. + // Temporary storage for data::sys_*_dirs_*. // + size_t sys_lib_dirs_mode; + size_t sys_inc_dirs_mode; + size_t sys_mod_dirs_mode; + size_t sys_lib_dirs_extra; size_t sys_inc_dirs_extra; private: // Defined in gcc.cxx. // - dir_paths - gcc_header_search_paths (const process_path&, scope&) const; + pair<dir_paths, size_t> + gcc_header_search_dirs (const process_path&, scope&) const; - dir_paths - gcc_library_search_paths (const process_path&, scope&) const; + pair<dir_paths, size_t> + gcc_library_search_dirs (const process_path&, scope&) const; // Defined in msvc.cxx. // - dir_paths - msvc_header_search_paths (const process_path&, scope&) const; + pair<dir_paths, size_t> + msvc_header_search_dirs (const process_path&, scope&) const; - dir_paths - msvc_library_search_paths (const process_path&, scope&) const; + pair<dir_paths, size_t> + msvc_library_search_dirs (const process_path&, scope&) const; private: bool new_; // See guess() and init() for details. diff --git a/libbuild2/cc/msvc.cxx b/libbuild2/cc/msvc.cxx index ce54964..4e40bd4 100644 --- a/libbuild2/cc/msvc.cxx +++ b/libbuild2/cc/msvc.cxx @@ -214,43 +214,135 @@ namespace build2 } } + void + msvc_extract_header_search_dirs (const strings& v, dir_paths& r) + { + for (auto i (v.begin ()), e (v.end ()); i != e; ++i) + { + const string& o (*i); + + dir_path d; + try + { + // -I can either be in the "-Ifoo" or "-I foo" form. For VC it can + // also be /I. + // + if (o.size () > 1 && (o[0] == '-' || o[0] == '/') && o[1] == 'I') + { + if (o.size () == 2) + { + if (++i == e) + break; // Let the compiler complain. + + d = dir_path (*i); + } + else + d = dir_path (o, 2, string::npos); + } + else + continue; + } + catch (const invalid_path& e) + { + fail << "invalid directory '" << e.path << "'" << " in option '" + << o << "'"; + } + + // Ignore relative paths. Or maybe we should warn? + // + if (!d.relative ()) + r.push_back (move (d)); + } + } + + void + msvc_extract_library_search_dirs (const strings& v, dir_paths& r) + { + for (auto i (v.begin ()), e (v.end ()); i != e; ++i) + { + const string& o (*i); + + dir_path d; + try + { + // /LIBPATH:<dir> (case-insensitive). + // + if ((o[0] == '/' || o[0] == '-') && + icasecmp (o.c_str () + 1, "LIBPATH:", 8) == 0) + d = dir_path (o, 9, string::npos); + else + continue; + } + catch (const invalid_path& e) + { + fail << "invalid directory '" << e.path << "'" << " in option '" + << o << "'"; + } + + // Ignore relative paths. Or maybe we should warn? + // + if (!d.relative ()) + r.push_back (move (d)); + } + } + // Extract system header search paths from MSVC. // - dir_paths config_module:: - msvc_header_search_paths (const process_path&, scope&) const + pair<dir_paths, size_t> config_module:: + msvc_header_search_dirs (const process_path&, scope& rs) const { // The compiler doesn't seem to have any built-in paths and all of them // either come from the INCLUDE environment variable or are specified - // explicitly on the command line. + // explicitly on the command line (we now do this if running out of the + // command prompt; see guess). // @@ VC: how are we going to do this? E.g., cl-14 does this internally. - // cl.exe /Be prints INCLUDE. + // cl.exe /Be prints INCLUDE. One advantage of going through the + // compiler is that it may be a wrapper (like our msvc-linux). Note + // also that we will still have to incorporate mode options. And this + // is not used for Clang targeting MSVC. // // Should we actually bother? INCLUDE is normally used for system // headers and its highly unlikely we will see an imported library // that lists one of those directories in pkg-config Cflags value. - // Let's wait and see. + // So the only benefit is to be able to print them. Let's wait and + // see. + + // Extract -I paths from the compiler mode. // - return dir_paths (); + dir_paths r; + msvc_extract_header_search_dirs (cast<strings> (rs[x_mode]), r); + size_t rn (r.size ()); + + return make_pair (move (r), rn); } // Extract system library search paths from MSVC. // - dir_paths config_module:: - msvc_library_search_paths (const process_path&, scope&) const + pair<dir_paths, size_t> config_module:: + msvc_library_search_dirs (const process_path&, scope& rs) const { // The linker 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 the command line. + // explicitly on the command line (we now do this if running out of the + // command prompt; see guess). // @@ VC: how are we going to do this? E.g., cl-14 does this internally. - // cl.exe /Be prints LIB. + // cl.exe /Be prints LIB. See above for further discussion. // // Should we actually bother? LIB is normally used for system // libraries and its highly unlikely we will see an explicit import - // for a library from one of those directories. Let's wait and see. + // for a library from one of those directories. So the only benefit + // is to be able to print them. Let's wait and see. // - return dir_paths (); + + // Extract /LIBPATH paths from the compiler mode. + // + dir_paths r; + msvc_extract_library_search_dirs (cast<strings> (rs[x_mode]), r); + size_t rn (r.size ()); + + return make_pair (move (r), rn); } // Inspect the file and determine if it is static or import library. diff --git a/libbuild2/cxx/init.cxx b/libbuild2/cxx/init.cxx index 719a88a..e44b6fe 100644 --- a/libbuild2/cxx/init.cxx +++ b/libbuild2/cxx/init.cxx @@ -36,8 +36,7 @@ namespace build2 { public: explicit - config_module (config_data&& d) - : config_data (move (d)), cc::config_module (move (d)) {} + config_module (config_data&& d): cc::config_module (move (d)) {} virtual strings translate_std (const compiler_info&, @@ -612,7 +611,11 @@ namespace build2 cast<dir_paths> (rs[cm.x_sys_lib_dirs]), cast<dir_paths> (rs[cm.x_sys_inc_dirs]), - cm.x_info->sys_mod_dirs, + cm.x_info->sys_mod_dirs ? &cm.x_info->sys_mod_dirs->first : nullptr, + + cm.sys_lib_dirs_mode, + cm.sys_inc_dirs_mode, + cm.sys_mod_dirs_mode, cm.sys_lib_dirs_extra, cm.sys_inc_dirs_extra, |