aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/cc/pkgconfig.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/cc/pkgconfig.cxx')
-rw-r--r--libbuild2/cc/pkgconfig.cxx519
1 files changed, 411 insertions, 108 deletions
diff --git a/libbuild2/cc/pkgconfig.cxx b/libbuild2/cc/pkgconfig.cxx
index 5efab0d..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)
{
@@ -161,6 +164,8 @@ namespace build2
const string& stem,
bool common) const
{
+ tracer trace (x, "pkgconfig_search");
+
// When it comes to looking for .pc files we have to decide where to
// search (which directory(ies)) as well as what to search for (which
// names). Suffix is our ".shared" or ".static" extension.
@@ -182,28 +187,36 @@ namespace build2
// then you get something like zlib which calls it zlib.pc. So let's
// just do it.
//
- f = dir;
- f /= "lib";
- f += stem;
- f += sfx;
- f += ".pc";
- if (exists (f))
- return f;
+ // And as you think you've covered all the bases, someone decides to
+ // play with the case (libXau.* vs xau.pc). So let's also try the
+ // lower-case versions of the stem unless we are on a case-insensitive
+ // filesystem.
+ //
+ auto check = [&dir, & sfx, &f] (const string& n)
+ {
+ f = dir;
+ f /= n;
+ f += sfx;
+ f += ".pc";
+ return exists (f);
+ };
- f = dir;
- f /= stem;
- f += sfx;
- f += ".pc";
- if (exists (f))
+ if (check ("lib" + stem) || check (stem))
return f;
+#ifndef _WIN32
+ string lstem (lcase (stem));
+
+ if (lstem != stem)
+ {
+ if (check ("lib" + lstem) || check (lstem))
+ return f;
+ }
+#endif
+
if (proj)
{
- f = dir;
- f /= proj->string ();
- f += sfx;
- f += ".pc";
- if (exists (f))
+ if (check (proj->string ()))
return f;
}
@@ -243,12 +256,15 @@ namespace build2
if (pkgconfig_derive (libd, check))
{
+ l6 ([&]{trace << "found " << libd << stem << " in "
+ << (d.a.empty () ? d.a : d.s).directory ();});
+
r.first = move (d.a);
r.second = move (d.s);
}
return r;
- };
+ }
bool common::
pkgconfig_load (optional<action> act,
@@ -300,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 parse_cflags = [&trace, this] (target& t,
- const pkgconfig& pc,
- bool la)
+ 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,
+ &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;
}
@@ -327,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;
}
@@ -337,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 ())
@@ -350,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;
@@ -379,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;
}
@@ -397,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
@@ -413,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.
//
@@ -435,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;
}
@@ -446,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.
@@ -454,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 += ' ';
@@ -463,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;
@@ -504,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") ||
@@ -522,6 +687,7 @@ namespace build2
cmp ("kernel32") ||
cmp ("mincore") ||
cmp ("mpr") ||
+ cmp ("msimg32") ||
cmp ("mswsock") ||
cmp ("msxml", 5) || // msxml*
cmp ("netapi32") ||
@@ -534,6 +700,7 @@ namespace build2
cmp ("psapi") ||
cmp ("rpcrt4") ||
cmp ("secur32") ||
+ cmp ("setupapi") ||
cmp ("shell32") ||
cmp ("shlwapi") ||
cmp ("synchronization") ||
@@ -541,6 +708,7 @@ namespace build2
cmp ("userenv") ||
cmp ("uuid") ||
cmp ("version") ||
+ cmp ("windowscodecs") ||
cmp ("winhttp") ||
cmp ("winmm") ||
cmp ("winspool") ||
@@ -591,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")
@@ -608,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
{
@@ -630,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)
@@ -709,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;
}
}
@@ -805,6 +965,8 @@ namespace build2
optional<uint64_t> ver;
optional<string> pfx;
+ variable_pool* vp (nullptr); // Resolve lazily.
+
string s;
for (size_t b (0), e (0); !(s = next (md, b, e)).empty (); )
{
@@ -865,8 +1027,13 @@ namespace build2
: name (move (s)));
}
- auto& vp (ctx.var_pool.rw ()); // Load phase.
- const variable& var (vp.insert (move (vn)));
+ // These should be public (qualified) variables so go straight for
+ // the public variable pool.
+ //
+ if (vp == nullptr)
+ vp = &ctx.var_pool.rw (); // Load phase if user==true.
+
+ const variable& var (vp->insert (move (vn)));
value& v (t.assign (var));
v.assign (move (ns), &var);
@@ -913,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.
@@ -937,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
@@ -955,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
@@ -1005,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 (
@@ -1017,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
@@ -1026,6 +1210,7 @@ namespace build2
//
if (tl.second.owns_lock ())
{
+ ht.path (move (hp));
ht.vars.assign (c_importable) = true;
tl.second.unlock ();
}
@@ -1053,9 +1238,16 @@ namespace build2
// Note that we rely on the "small function object" optimization here.
//
- auto add_pc_dir = [&pc_dirs] (dir_path&& d) -> bool
+ auto add_pc_dir = [&trace, &pc_dirs] (dir_path&& d) -> bool
{
- pc_dirs.emplace_back (move (d));
+ // Suppress duplicated.
+ //
+ if (find (pc_dirs.begin (), pc_dirs.end (), d) == pc_dirs.end ())
+ {
+ l6 ([&]{trace << "search path " << d;});
+ pc_dirs.emplace_back (move (d));
+ }
+
return false;
};
@@ -1182,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
@@ -1221,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);
}
@@ -1341,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;
@@ -1350,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 ())
@@ -1372,14 +1577,79 @@ namespace build2
// Note that generation can take some time if we have a large number of
// prerequisite libraries.
//
- if (verb)
- text << "pc " << *t;
- else if (verb >= 2)
+ if (verb >= 2)
text << "cat >" << p;
+ else if (verb)
+ print_diag ("pc", g, *t);
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
@@ -1531,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;
@@ -1551,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
@@ -1644,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;
@@ -1738,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)
@@ -1896,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.
@@ -1974,6 +2272,8 @@ namespace build2
//
if (la)
{
+ // Note: go straight for the public variable pool.
+ //
if (cast_false<bool> (l.lookup_original (
ctx.var_pool["bin.whole"],
true /* target_only */).first))
@@ -2061,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]))
{
@@ -2104,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;
@@ -2130,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;
}
@@ -2141,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;
}