aboutsummaryrefslogtreecommitdiff
path: root/build2/cc
diff options
context:
space:
mode:
Diffstat (limited to 'build2/cc')
-rw-r--r--build2/cc/common.hxx8
-rw-r--r--build2/cc/compile.cxx24
-rw-r--r--build2/cc/gcc.cxx133
-rw-r--r--build2/cc/module.cxx38
-rw-r--r--build2/cc/module.hxx9
-rw-r--r--build2/cc/msvc.cxx19
-rw-r--r--build2/cc/pkgconfig.cxx3
7 files changed, 207 insertions, 27 deletions
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 </dev/null method.
+ //
+ dir_paths config_module::
+ gcc_header_search_paths (process_path& xc, scope& rs) const
+ {
+ dir_paths r;
+
+ cstrings args;
+ string std; // Storage.
+
+ args.push_back (xc.recall_string ());
+ append_options (args, rs, c_coptions);
+ append_options (args, rs, x_coptions);
+ append_options (args, tstd);
+
+ // Compile as.
+ //
+ auto langopt = [this] () -> 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);