From 09839eea3a69e258555eb4ef6d05cd4799ccd7a0 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 29 Sep 2017 20:57:05 +0200 Subject: Extract system header search paths from GCC or compatible --- build2/c/init.cxx | 3 + build2/cc/common.hxx | 8 ++- build2/cc/compile.cxx | 24 +++++--- build2/cc/gcc.cxx | 133 +++++++++++++++++++++++++++++++++++++++++- build2/cc/module.cxx | 38 +++++++----- build2/cc/module.hxx | 9 +++ build2/cc/msvc.cxx | 19 ++++++ build2/cc/pkgconfig.cxx | 3 - build2/config/module.hxx | 1 - build2/cxx/init.cxx | 3 + build2/test/script/regex.cxx | 2 - build2/test/script/script.cxx | 1 - 12 files changed, 213 insertions(+), 31 deletions(-) diff --git a/build2/c/init.cxx b/build2/c/init.cxx index 45097bb..e473e58 100644 --- a/build2/c/init.cxx +++ b/build2/c/init.cxx @@ -301,6 +301,9 @@ namespace build2 cast (rs[cm.x_sys_lib_dirs]), cast (rs[cm.x_sys_inc_dirs]), + cm.sys_lib_dirs_extra, + cm.sys_inc_dirs_extra, + c::static_type, nullptr, // No C modules yet. hdr, diff --git a/build2/cc/common.hxx b/build2/cc/common.hxx index 3c4b693..d4f8bd2 100644 --- a/build2/cc/common.hxx +++ b/build2/cc/common.hxx @@ -42,7 +42,7 @@ namespace build2 const variable& x_path; // Compiler process path. const variable& x_sys_lib_dirs; // System library search directories. - const variable& x_sys_inc_dirs; // Extra header search directories. + const variable& x_sys_inc_dirs; // System header search directories. const variable& x_poptions; const variable& x_coptions; @@ -123,6 +123,9 @@ namespace build2 const dir_paths& sys_lib_dirs; // x.sys_lib_dirs const dir_paths& sys_inc_dirs; // x.sys_inc_dirs + size_t sys_lib_dirs_extra; // First extra path (size if none). + size_t sys_inc_dirs_extra; // First extra path (size if none). + const target_type& x_src; // Source target type (c{}, cxx{}). const target_type* x_mod; // Module target type (mxx{}), if any. @@ -164,6 +167,8 @@ namespace build2 bool fs, const dir_paths& sld, const dir_paths& sid, + size_t sle, + size_t sie, const target_type& src, const target_type* mod, const target_type* const* hdr, @@ -179,6 +184,7 @@ namespace build2 modules (fm), symexport (fs), sys_lib_dirs (sld), sys_inc_dirs (sid), + sys_lib_dirs_extra (sle), sys_inc_dirs_extra (sie), x_src (src), x_mod (mod), x_hdr (hdr), x_inc (inc) {} }; diff --git a/build2/cc/compile.cxx b/build2/cc/compile.cxx index c1f4e08..639d3e2 100644 --- a/build2/cc/compile.cxx +++ b/build2/cc/compile.cxx @@ -760,8 +760,10 @@ namespace build2 // Extra system header dirs (last). // - for (const dir_path& d: sys_inc_dirs) - cs.append (d.string ()); + assert (sys_inc_dirs_extra <= sys_inc_dirs.size ()); + for (auto i (sys_inc_dirs.begin () + sys_inc_dirs_extra); + i != sys_inc_dirs.end (); ++i) + cs.append (i->string ()); } hash_options (cs, t, c_coptions); @@ -1709,10 +1711,12 @@ namespace build2 // Extra system header dirs (last). // - for (const dir_path& d: sys_inc_dirs) + assert (sys_inc_dirs_extra <= sys_inc_dirs.size ()); + for (auto i (sys_inc_dirs.begin () + sys_inc_dirs_extra); + i != sys_inc_dirs.end (); ++i) { args.push_back ("-I"); - args.push_back (d.string ().c_str ()); + args.push_back (i->string ().c_str ()); } if (md.symexport) @@ -2670,10 +2674,12 @@ namespace build2 append_options (args, t, c_poptions); append_options (args, t, x_poptions); - for (const dir_path& d: sys_inc_dirs) + assert (sys_inc_dirs_extra <= sys_inc_dirs.size ()); + for (auto i (sys_inc_dirs.begin () + sys_inc_dirs_extra); + i != sys_inc_dirs.end (); ++i) { args.push_back ("-I"); - args.push_back (d.string ().c_str ()); + args.push_back (i->string ().c_str ()); } if (md.symexport) @@ -3879,10 +3885,12 @@ namespace build2 // Extra system header dirs (last). // - for (const dir_path& d: sys_inc_dirs) + assert (sys_inc_dirs_extra <= sys_inc_dirs.size ()); + for (auto i (sys_inc_dirs.begin () + sys_inc_dirs_extra); + i != sys_inc_dirs.end (); ++i) { args.push_back ("-I"); - args.push_back (d.string ().c_str ()); + args.push_back (i->string ().c_str ()); } if (md.symexport) diff --git a/build2/cc/gcc.cxx b/build2/cc/gcc.cxx index 7f52a91..64c78ca 100644 --- a/build2/cc/gcc.cxx +++ b/build2/cc/gcc.cxx @@ -24,6 +24,133 @@ namespace build2 { using namespace bin; + // Extract system header search paths from GCC (gcc/g++) or compatible + // (Clang, Intel) using the -v -E const char* + { + switch (x_lang) + { + case lang::c: return "c"; + case lang::cxx: return "c++"; + } + + assert (false); // Can't get here. + return nullptr; + }; + + args.push_back ("-x"); + args.push_back (langopt ()); + args.push_back ("-v"); + args.push_back ("-E"); + args.push_back ("-"); + args.push_back (nullptr); + + if (verb >= 3) + print_process (args); + + try + { + // Open pipe to stderr, redirect stdin and stdout to /dev/null. + // + process pr (xc, args.data (), -2, -2, -1); + + try + { + ifdstream is ( + move (pr.in_efd), fdstream_mode::skip, ifdstream::badbit); + + // Normally the system header paths appear between the following + // lines: + // + // #include <...> search starts here: + // End of search list. + // + // The exact text depends on the current locale. What we can rely on + // is the unique "#include <" prefix of the "opening" line and the + // fact that the paths are indented with a single space character, + // unlike the "closing" line. + // + // Note that on Mac OS we will also see some framework paths among + // system header paths, followed with a comment. For example: + // + // /Library/Frameworks (framework directory) + // + // For now we ignore framework paths and to filter them out we will + // only consider valid paths to existing directories, skipping those + // which we fail to stat or normalize. + // + string s; + for (bool found (false); getline (is, s); ) + { + if (!found) + found = s.compare (0, 10, "#include <") == 0; + else + { + if (s[0] != ' ') + break; + + try + { + dir_path d (s, 1, s.size () - 1); + + // @@ Pass true as the ignore_error argument for exists(), when + // supported. + // + if (d.absolute () && exists (d) && + find (r.begin (), r.end (), d.normalize ()) == r.end ()) + r.emplace_back (move (d)); + } + catch (const invalid_path&) {} + } + } + + is.close (); // Don't block. + + if (!pr.wait ()) + throw failed (); + } + catch (const io_error&) + { + pr.wait (); + fail << "error reading " << x_lang << " compiler -v -E output"; + } + } + catch (const process_error& e) + { + error << "unable to execute " << args[0] << ": " << e; + + if (e.child) + exit (1); + + throw failed (); + } + + // It's highly unlikely not to have any system directories. More likely + // we misinterpreted the compiler output. + // + if (r.empty ()) + fail << "unable to extract " << x_lang << " compiler system header " + << "search paths"; + + return r; + } + // Extract system library search paths from GCC (gcc/g++) or compatible // (Clang, Intel) using the -print-search-dirs option. // @@ -125,8 +252,10 @@ namespace build2 // for (string::size_type b (0);; e = l.find (d, (b = e + 1))) { - r.emplace_back (l, b, (e != string::npos ? e - b : e)); - r.back ().normalize (); + dir_path d (l, b, (e != string::npos ? e - b : e)); + + if (find (r.begin (), r.end (), d.normalize ()) == r.end ()) + r.emplace_back (move (d)); if (e == string::npos) break; diff --git a/build2/cc/module.cxx b/build2/cc/module.cxx index 0245def..141f3c8 100644 --- a/build2/cc/module.cxx +++ b/build2/cc/module.cxx @@ -160,27 +160,39 @@ namespace build2 dir_paths inc_dirs; if (ci.id.value () == compiler_id::msvc) + { lib_dirs = msvc_library_search_paths (ci.path, rs); + inc_dirs = msvc_header_search_paths (ci.path, rs); + } else { lib_dirs = gcc_library_search_paths (ci.path, rs); + inc_dirs = gcc_header_search_paths (ci.path, rs); + } + + sys_lib_dirs_extra = lib_dirs.size (); + sys_inc_dirs_extra = inc_dirs.size (); #ifndef _WIN32 - // 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. - // - lib_dirs.push_back (dir_path ("/usr/local/lib")); + // 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. + // + { + dir_path d ("/usr/local/lib"); + if (find (lib_dirs.begin (), lib_dirs.end (), d) == lib_dirs.end ()) + lib_dirs.emplace_back (move (d)); + } - // 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. Note that we don't add it for all the - // platforms for good measure because this will actually appear as - // usually unnecessary noise on the command line. - // - if (tt.system == "freebsd") - inc_dirs.push_back (dir_path ("/usr/local/include")); -#endif + // 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. + // + { + dir_path d ("/usr/local/include"); + if (find (inc_dirs.begin (), inc_dirs.end (), d) == inc_dirs.end ()) + inc_dirs.emplace_back (move (d)); } +#endif // If this is a new value (e.g., we are configuring), then print the // report at verbosity level 2 and up (-v). diff --git a/build2/cc/module.hxx b/build2/cc/module.hxx index 08f573b..928e16c 100644 --- a/build2/cc/module.hxx +++ b/build2/cc/module.hxx @@ -49,13 +49,22 @@ namespace build2 translate_std (const compiler_info&, scope&, const string*) const = 0; strings tstd; + size_t sys_lib_dirs_extra; // First extra path (size if none). + size_t sys_inc_dirs_extra; // First extra path (size if none). + compiler_info ci; // Note: some members are moved from. private: dir_paths + gcc_header_search_paths (process_path&, scope&) const; // gcc.cxx + + dir_paths gcc_library_search_paths (process_path&, scope&) const; // gcc.cxx dir_paths + msvc_header_search_paths (process_path&, scope&) const; // msvc.cxx + + dir_paths msvc_library_search_paths (process_path&, scope&) const; // msvc.cxx private: diff --git a/build2/cc/msvc.cxx b/build2/cc/msvc.cxx index b7b5828..aa4095e 100644 --- a/build2/cc/msvc.cxx +++ b/build2/cc/msvc.cxx @@ -83,6 +83,25 @@ namespace build2 } } + // Extract system header search paths from MSVC. + // + dir_paths config_module:: + msvc_header_search_paths (process_path&, scope&) const + { + // The compiler doesn't seem to have any built-in paths and all of them + // come from the INCLUDE environment variable. + + // @@ VC: how are we going to do this? E.g., cl-14 does this internally. + // cl.exe /Be prints INCLUDE. + // + // 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. + // + return dir_paths (); + } + // Extract system library search paths from MSVC. // dir_paths config_module:: diff --git a/build2/cc/pkgconfig.cxx b/build2/cc/pkgconfig.cxx index f920dbd..a9e3a34 100644 --- a/build2/cc/pkgconfig.cxx +++ b/build2/cc/pkgconfig.cxx @@ -1057,9 +1057,6 @@ namespace build2 // pkgconf& ipc (sp.empty () ? apc : spc); // Interface package info. - // @@ Currently sys_inc_dirs doesn't contain the compiler-extracted - // paths. - // bool pa (at != nullptr && !ap.empty ()); if (pa || sp.empty ()) apc = pkgconf (ap, pc_dirs, sys_lib_dirs, sys_inc_dirs); diff --git a/build2/config/module.hxx b/build2/config/module.hxx index d997802..1f48181 100644 --- a/build2/config/module.hxx +++ b/build2/config/module.hxx @@ -6,7 +6,6 @@ #define BUILD2_CONFIG_MODULE_HXX #include -#include // find_if() #include diff --git a/build2/cxx/init.cxx b/build2/cxx/init.cxx index ca75de3..25dd7da 100644 --- a/build2/cxx/init.cxx +++ b/build2/cxx/init.cxx @@ -511,6 +511,9 @@ namespace build2 cast (rs[cm.x_sys_lib_dirs]), cast (rs[cm.x_sys_inc_dirs]), + cm.sys_lib_dirs_extra, + cm.sys_inc_dirs_extra, + cxx::static_type, modules ? &mxx::static_type : nullptr, hdr, diff --git a/build2/test/script/regex.cxx b/build2/test/script/regex.cxx index 38ac096..fe8bcb0 100644 --- a/build2/test/script/regex.cxx +++ b/build2/test/script/regex.cxx @@ -4,8 +4,6 @@ #include -#include // copy(), copy_backward() - using namespace std; namespace build2 diff --git a/build2/test/script/script.cxx b/build2/test/script/script.cxx index 7ddd63a..eb366c1 100644 --- a/build2/test/script/script.cxx +++ b/build2/test/script/script.cxx @@ -5,7 +5,6 @@ #include #include -#include // find() #include #include -- cgit v1.1