aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/cc
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2019-10-07 09:41:13 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2019-10-07 09:41:13 +0200
commit4d43fc686427252367576bb1a37724bb45958358 (patch)
treeccc5bef784457788a1ff5c5f93c39f5b9090b107 /libbuild2/cc
parenta90eecb47438303ae3f6409276f8d9bb77c9f6fc (diff)
Pass MSVC system library search paths to linker if LIB envvar is unset
Diffstat (limited to 'libbuild2/cc')
-rw-r--r--libbuild2/cc/guess.cxx44
-rw-r--r--libbuild2/cc/guess.hxx5
-rw-r--r--libbuild2/cc/link-rule.cxx57
-rw-r--r--libbuild2/cc/module.cxx121
-rw-r--r--libbuild2/cc/module.hxx9
-rw-r--r--libbuild2/cc/msvc.cxx22
6 files changed, 183 insertions, 75 deletions
diff --git a/libbuild2/cc/guess.cxx b/libbuild2/cc/guess.cxx
index 9cfb1c8..5b0072a 100644
--- a/libbuild2/cc/guess.cxx
+++ b/libbuild2/cc/guess.cxx
@@ -951,7 +951,9 @@ namespace build2
move (bpat),
move (rt),
move (csl),
- move (xsl)};
+ move (xsl),
+ nullopt,
+ nullopt};
}
static compiler_info
@@ -1142,7 +1144,9 @@ namespace build2
"",
move (rt),
move (csl),
- move (xsl)};
+ move (xsl),
+ nullopt,
+ nullopt};
}
struct clang_msvc_info
@@ -1339,6 +1343,9 @@ namespace build2
return r;
}
+ const char*
+ msvc_cpu (const string&); // msvc.cxx
+
static compiler_info
guess_clang (const char* xm,
lang xl,
@@ -1469,6 +1476,8 @@ namespace build2
// For Clang on Windows targeting MSVC we remap the target to match
// MSVC's.
//
+ optional<dir_paths> sys_lib_dirs;
+
if (tt.system == "windows-msvc")
{
// Note that currently there is no straightforward way to determine
@@ -1501,6 +1510,29 @@ namespace build2
gr.signature += " MSVC version ";
gr.signature += mi.msvc_ver;
+
+ // Come up with the system library search paths. Ideally we would want
+ // to extract this from Clang and -print-search-paths would have been
+ // the natural way for Clang to report it. But no luck.
+ //
+ dir_paths ds;
+ const char* cpu (msvc_cpu (tt.cpu));
+
+ ds.push_back ((dir_path (mi.msvc_dir) /= "lib") /= cpu);
+
+ // This path structure only appeared in Platform SDK 10 (if anyone
+ // wants to use anything older, they will just have to use the MSVC
+ // command prompt).
+ //
+ if (!mi.psdk_ver.empty ())
+ {
+ dir_path d ((dir_path (mi.psdk_dir) /= "Lib") /= mi.psdk_ver);
+
+ ds.push_back ((dir_path (d) /= "ucrt") /= cpu);
+ ds.push_back ((dir_path (d) /= "um" ) /= cpu);
+ }
+
+ sys_lib_dirs = move (ds);
}
// Derive the toolchain pattern. Try clang/clang++, the gcc/g++ alias,
@@ -1595,7 +1627,9 @@ namespace build2
"",
move (rt),
move (csl),
- move (xsl)};
+ move (xsl),
+ move (sys_lib_dirs),
+ nullopt};
}
static compiler_info
@@ -1884,7 +1918,9 @@ namespace build2
"",
move (rt),
move (csl),
- move (xsl)};
+ move (xsl),
+ nullopt,
+ nullopt};
}
// Compiler checks can be expensive (we often need to run the compiler
diff --git a/libbuild2/cc/guess.hxx b/libbuild2/cc/guess.hxx
index 3677cc7..a8784fc 100644
--- a/libbuild2/cc/guess.hxx
+++ b/libbuild2/cc/guess.hxx
@@ -215,6 +215,11 @@ namespace build2
string runtime;
string c_stdlib;
string x_stdlib;
+
+ // System library/header search paths, if extracted at the guess stage.
+ //
+ optional<dir_paths> sys_lib_dirs;
+ optional<dir_paths> sys_inc_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 5341a2e..cd31058 100644
--- a/libbuild2/cc/link-rule.cxx
+++ b/libbuild2/cc/link-rule.cxx
@@ -2105,11 +2105,22 @@ namespace build2
// kind of a hybrid).
//
cstrings args {nullptr}; // Reserve one for config.bin.ar/config.x.
+ strings sargs; // Argument tail with storage.
- // Storage.
+ // Stored args.
//
string arg1, arg2;
- strings sargs;
+ strings sargs1;
+
+ // Shallow-copy over stored args to args. Note that this must only be
+ // done once we are finished appending to stored args because of
+ // potential reallocations.
+ //
+ auto append_args = [&args] (const strings& sargs)
+ {
+ for (const string& a: sargs)
+ args.push_back (a.c_str ());
+ };
if (lt.static_library ())
{
@@ -2190,14 +2201,36 @@ namespace build2
// Extra system library dirs (last).
//
- // @@ /LIBPATH:<path>, not /LIBPATH <path>
- //
assert (sys_lib_dirs_extra <= sys_lib_dirs.size ());
- append_option_values (
- args,
- cclass == compiler_class::msvc ? "/LIBPATH:" : "-L",
- sys_lib_dirs.begin () + sys_lib_dirs_extra, sys_lib_dirs.end (),
- [] (const dir_path& d) {return d.string ().c_str ();});
+
+ 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.
//
@@ -2649,11 +2682,9 @@ namespace build2
if (!manifest.empty () && tsys == "mingw32")
sargs.push_back (relative (manifest).string ());
- // Shallow-copy sargs to args. Why not do it as we go along pushing into
- // sargs? Because of potential reallocations in sargs.
+ // Shallow-copy sargs over to args.
//
- for (const string& a: sargs)
- args.push_back (a.c_str ());
+ append_args (sargs);
if (!lt.static_library ())
{
diff --git a/libbuild2/cc/module.cxx b/libbuild2/cc/module.cxx
index 39fd7d5..f3ce32b 100644
--- a/libbuild2/cc/module.cxx
+++ b/libbuild2/cc/module.cxx
@@ -116,7 +116,7 @@ namespace build2
// Figure out which compiler we are dealing with, its target, etc.
//
- ci_ = &build2::cc::guess (
+ x_info = &build2::cc::guess (
x,
x_lang,
cast<path> (*p.first),
@@ -130,7 +130,7 @@ namespace build2
cast_null<strings> (rs[config_c_loptions]),
cast_null<strings> (rs[config_x_loptions]));
- const compiler_info& ci (*ci_);
+ const compiler_info& xi (*x_info);
// Split/canonicalize the target. First see if the user asked us to
// use config.sub.
@@ -143,14 +143,14 @@ namespace build2
{
ct = run<string> (3,
*config_sub,
- ci.target.c_str (),
+ xi.target.c_str (),
[] (string& l, bool) {return move (l);});
l5 ([&]{trace << "config.sub target: '" << ct << "'";});
}
try
{
- tt = target_triplet (ct.empty () ? ci.target : ct);
+ tt = target_triplet (ct.empty () ? xi.target : ct);
l5 ([&]{trace << "canonical target: '" << tt.string () << "'; "
<< "class: " << tt.class_;});
}
@@ -160,24 +160,24 @@ namespace build2
// help us out.
//
fail << "unable to parse " << x_lang << " compiler target '"
- << ci.target << "': " << e <<
+ << xi.target << "': " << e <<
info << "consider using the --config-sub option";
}
}
// Assign values to variables that describe the compiler.
//
- rs.assign (x_id) = ci.id.string ();
- rs.assign (x_id_type) = to_string (ci.id.type);
- rs.assign (x_id_variant) = ci.id.variant;
+ rs.assign (x_id) = xi.id.string ();
+ rs.assign (x_id_type) = to_string (xi.id.type);
+ rs.assign (x_id_variant) = xi.id.variant;
- rs.assign (x_class) = to_string (ci.class_);
+ rs.assign (x_class) = to_string (xi.class_);
- rs.assign (x_version) = ci.version.string;
- rs.assign (x_version_major) = ci.version.major;
- rs.assign (x_version_minor) = ci.version.minor;
- rs.assign (x_version_patch) = ci.version.patch;
- rs.assign (x_version_build) = ci.version.build;
+ rs.assign (x_version) = xi.version.string;
+ rs.assign (x_version_major) = xi.version.major;
+ rs.assign (x_version_minor) = xi.version.minor;
+ rs.assign (x_version_patch) = xi.version.patch;
+ rs.assign (x_version_build) = xi.version.build;
// Also enter as x.target.{cpu,vendor,system,version,class} for
// convenience of access.
@@ -190,10 +190,10 @@ namespace build2
rs.assign (x_target) = move (tt);
- rs.assign (x_pattern) = ci.pattern;
+ rs.assign (x_pattern) = xi.pattern;
if (!x_stdlib.alias (c_stdlib))
- rs.assign (x_stdlib) = ci.x_stdlib;
+ rs.assign (x_stdlib) = xi.x_stdlib;
new_ = p.second;
@@ -211,11 +211,11 @@ namespace build2
h.assign ("config.cc.hinter") = string (x);
h.assign ("config.cc.target") = cast<target_triplet> (rs[x_target]);
- if (!ci.pattern.empty ())
- h.assign ("config.cc.pattern") = ci.pattern;
+ if (!xi.pattern.empty ())
+ h.assign ("config.cc.pattern") = xi.pattern;
- h.assign (c_runtime) = ci.runtime;
- h.assign (c_stdlib) = ci.c_stdlib;
+ h.assign (c_runtime) = xi.runtime;
+ h.assign (c_stdlib) = xi.c_stdlib;
load_module (rs, rs, "cc.core.guess", loc, false, h);
}
@@ -264,11 +264,11 @@ namespace build2
"target");
check (cast<string> (rs["cc.runtime"]),
- ci.runtime,
+ xi.runtime,
"runtime");
check (cast<string> (rs["cc.stdlib"]),
- ci.c_stdlib,
+ xi.c_stdlib,
"c standard library");
}
}
@@ -288,7 +288,7 @@ namespace build2
{
tracer trace (x, "config_init");
- const compiler_info& ci (*ci_);
+ const compiler_info& xi (*x_info);
const target_triplet& tt (cast<target_triplet> (rs[x_target]));
// config.x.std overrides x.std
@@ -307,7 +307,7 @@ namespace build2
// Translate x_std value (if any) to the compiler option(s) (if any).
//
- tstd = translate_std (ci, rs, v);
+ tstd = translate_std (xi, rs, v);
}
// Extract system header/library search paths from the compiler and
@@ -316,19 +316,32 @@ namespace build2
dir_paths lib_dirs;
dir_paths inc_dirs;
- switch (ci.class_)
+ if (xi.sys_lib_dirs)
+ lib_dirs = *xi.sys_lib_dirs;
+ else
{
- case compiler_class::gcc:
+ switch (xi.class_)
{
- //@@ CLANG-MSVC: libraries don't contain MSVC stuff.
- lib_dirs = gcc_library_search_paths (ci.path, rs);
- inc_dirs = gcc_header_search_paths (ci.path, rs);
+ case compiler_class::gcc:
+ lib_dirs = gcc_library_search_paths (xi.path, rs);
+ break;
+ case compiler_class::msvc:
+ lib_dirs = msvc_library_search_paths (xi.path, rs);
break;
}
- case compiler_class::msvc:
+ }
+
+ if (xi.sys_inc_dirs)
+ inc_dirs = *xi.sys_inc_dirs;
+ else
+ {
+ switch (xi.class_)
{
- lib_dirs = msvc_library_search_paths (ci.path, rs);
- inc_dirs = msvc_header_search_paths (ci.path, rs);
+ case compiler_class::gcc:
+ inc_dirs = gcc_header_search_paths (xi.path, rs);
+ break;
+ case compiler_class::msvc:
+ inc_dirs = msvc_header_search_paths (xi.path, rs);
break;
}
}
@@ -426,34 +439,34 @@ namespace build2
{
dr << x << ' ' << project (rs) << '@' << rs << '\n'
- << " " << left << setw (11) << x << ci.path << '\n'
- << " id " << ci.id << '\n'
- << " version " << ci.version.string << '\n'
- << " major " << ci.version.major << '\n'
- << " minor " << ci.version.minor << '\n'
- << " patch " << ci.version.patch << '\n';
+ << " " << left << setw (11) << x << xi.path << '\n'
+ << " id " << xi.id << '\n'
+ << " version " << xi.version.string << '\n'
+ << " major " << xi.version.major << '\n'
+ << " minor " << xi.version.minor << '\n'
+ << " patch " << xi.version.patch << '\n';
}
- if (!ci.version.build.empty ())
+ if (!xi.version.build.empty ())
{
- dr << " build " << ci.version.build << '\n';
+ dr << " build " << xi.version.build << '\n';
}
{
const string& ct (tt.string ()); // Canonical target.
- dr << " signature " << ci.signature << '\n'
- << " checksum " << ci.checksum << '\n'
+ dr << " signature " << xi.signature << '\n'
+ << " checksum " << xi.checksum << '\n'
<< " target " << ct;
- if (ct != ci.original_target)
- dr << " (" << ci.original_target << ")";
+ if (ct != xi.original_target)
+ dr << " (" << xi.original_target << ")";
- dr << "\n runtime " << ci.runtime
- << "\n stdlib " << ci.x_stdlib;
+ dr << "\n runtime " << xi.runtime
+ << "\n stdlib " << xi.x_stdlib;
if (!x_stdlib.alias (c_stdlib))
- dr << "\n c stdlib " << ci.c_stdlib;
+ dr << "\n c stdlib " << xi.c_stdlib;
}
if (!tstd.empty ())
@@ -462,9 +475,9 @@ namespace build2
for (const string& o: tstd) dr << ' ' << o;
}
- if (!ci.pattern.empty ()) // Note: bin_pattern printed by bin
+ if (!xi.pattern.empty ()) // Note: bin_pattern printed by bin
{
- dr << "\n pattern " << ci.pattern;
+ dr << "\n pattern " << xi.pattern;
}
if (verb >= 3 && !inc_dirs.empty ())
@@ -490,12 +503,12 @@ namespace build2
}
}
- rs.assign (x_path) = process_path (ci.path, false /* init */);
+ rs.assign (x_path) = process_path (xi.path, false /* init */);
rs.assign (x_sys_lib_dirs) = move (lib_dirs);
rs.assign (x_sys_inc_dirs) = move (inc_dirs);
- rs.assign (x_signature) = ci.signature;
- rs.assign (x_checksum) = ci.checksum;
+ rs.assign (x_signature) = xi.signature;
+ rs.assign (x_checksum) = xi.checksum;
// config.x.{p,c,l}options
// config.x.libs
@@ -550,8 +563,8 @@ namespace build2
{
variable_map h (rs.ctx);
- if (!ci.bin_pattern.empty ())
- h.assign ("config.bin.pattern") = ci.bin_pattern;
+ if (!xi.bin_pattern.empty ())
+ h.assign ("config.bin.pattern") = xi.bin_pattern;
load_module (rs, rs, "cc.core.config", loc, false, h);
}
diff --git a/libbuild2/cc/module.hxx b/libbuild2/cc/module.hxx
index 43670c3..77fe55c 100644
--- a/libbuild2/cc/module.hxx
+++ b/libbuild2/cc/module.hxx
@@ -52,10 +52,13 @@ 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).
- const compiler_info* ci_;
+ const compiler_info* x_info;
+
+ // Temporary storage for data::sys_*_dirs_extra.
+ //
+ size_t sys_lib_dirs_extra;
+ size_t sys_inc_dirs_extra;
private:
// Defined in gcc.cxx.
diff --git a/libbuild2/cc/msvc.cxx b/libbuild2/cc/msvc.cxx
index 2d53b69..e7251ac 100644
--- a/libbuild2/cc/msvc.cxx
+++ b/libbuild2/cc/msvc.cxx
@@ -28,6 +28,25 @@ namespace build2
{
using namespace bin;
+ // Translate the target triplet CPU to MSVC CPU (used in directory names,
+ // etc).
+ //
+ const char*
+ msvc_cpu (const string& cpu)
+ {
+ const char* m (cpu == "i386" || cpu == "i686" ? "x86" :
+ cpu == "x86_64" ? "x64" :
+ cpu == "arm" ? "arm" :
+ cpu == "arm64" ? "arm64" :
+ nullptr);
+
+ if (m == nullptr)
+ fail << "unable to translate target triplet CPU " << cpu
+ << " to MSVC CPU";
+
+ return m;
+ }
+
// Translate the target triplet CPU to lib.exe/link.exe /MACHINE option.
//
const char*
@@ -40,7 +59,8 @@ namespace build2
nullptr);
if (m == nullptr)
- fail << "unable to translate CPU " << cpu << " to /MACHINE";
+ fail << "unable to translate target triplet CPU " << cpu
+ << " to /MACHINE";
return m;
}