aboutsummaryrefslogtreecommitdiff
path: root/build2/cc
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-07-31 18:42:47 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-07-31 18:44:07 +0200
commita84ff43b183181e0a12c6d5e31c1f366d39ce2fe (patch)
tree3dce54b64fd8e9917ed034a3e2c9e20f057eece4 /build2/cc
parent89f5bc3b423a1269a60ccca05174226c8de40357 (diff)
Experimental (and probably broken) pkg-config generation support
Diffstat (limited to 'build2/cc')
-rw-r--r--build2/cc/common.cxx7
-rw-r--r--build2/cc/common.hxx15
-rw-r--r--build2/cc/init.cxx7
-rw-r--r--build2/cc/install.cxx33
-rw-r--r--build2/cc/install.hxx9
-rw-r--r--build2/cc/link.cxx120
-rw-r--r--build2/cc/link.hxx2
-rw-r--r--build2/cc/pkgconfig.cxx341
8 files changed, 396 insertions, 138 deletions
diff --git a/build2/cc/common.cxx b/build2/cc/common.cxx
index ce8415c..6f51662 100644
--- a/build2/cc/common.cxx
+++ b/build2/cc/common.cxx
@@ -869,8 +869,11 @@ namespace build2
// information. The idea is that when we auto-generate .pc files, we
// will copy those macros (or custom ones) from *.export.poptions.
//
- if (pkgconfig == nullptr || !pkgconfig_extract (
- act, *p.scope, *lt, a, s, p.proj, name, *pd, sysd))
+ if (pkgconfig == nullptr ||
+ !pkgconfig_load (act, *p.scope,
+ *lt, a, s,
+ p.proj, name,
+ *pd, sysd))
{
if (a != nullptr) add_macro (*a, "STATIC");
if (s != nullptr) add_macro (*s, "SHARED");
diff --git a/build2/cc/common.hxx b/build2/cc/common.hxx
index 951863a..66c226c 100644
--- a/build2/cc/common.hxx
+++ b/build2/cc/common.hxx
@@ -266,15 +266,12 @@ namespace build2
extract_library_dirs (const scope&) const;
bool
- pkgconfig_extract (action,
- const scope&,
- bin::lib&,
- bin::liba*,
- bin::libs*,
- const optional<string>&,
- const string&,
- const dir_path&,
- const dir_paths&) const; // pkgconfig.cxx
+ pkgconfig_load (action, const scope&,
+ bin::lib&, bin::liba*, bin::libs*,
+ const optional<string>&,
+ const string&,
+ const dir_path&,
+ const dir_paths&) const; // pkgconfig.cxx
// Alternative search logic for VC (msvc.cxx).
//
diff --git a/build2/cc/init.cxx b/build2/cc/init.cxx
index ea42469..8dceda7 100644
--- a/build2/cc/init.cxx
+++ b/build2/cc/init.cxx
@@ -248,14 +248,15 @@ namespace build2
load_module (rs, rs, "bin.rc.config", loc);
}
- // Load (optionally) the pkgconfig.config module.
+ // Load (optionally) the pkgconfig module. Note that it registers the
+ // pc{} target whether the pkg-config utility is found or not.
//
// @@ At some point we may also want to verify that targets matched
// if it has already been loaded (by someone) else. Currently it
// doesn't set pkgconfig.target. Perhaps only set if it was used
// to derive the program name?
//
- if (!cast_false<bool> (rs["pkgconfig.config.loaded"]))
+ if (!cast_false<bool> (rs["pkgconfig.loaded"]))
{
// Prepare configuration hints.
//
@@ -266,7 +267,7 @@ namespace build2
const variable& t (vp.insert ("config.pkgconfig.target"));
h.assign (t) = cast<target_triplet> (rs["cc.target"]);
- load_module (rs, rs, "pkgconfig.config", loc, true, h);
+ load_module (rs, rs, "pkgconfig", loc, true, h);
}
return true;
diff --git a/build2/cc/install.cxx b/build2/cc/install.cxx
index a0dc9b8..c65e7f6 100644
--- a/build2/cc/install.cxx
+++ b/build2/cc/install.cxx
@@ -94,12 +94,43 @@ namespace build2
{
file* f;
if ((f = t.is_a<libs> ()) != nullptr && tclass != "windows")
- t.data (link_.derive_libs_paths (*f));
+ {
+ const string* p (cast_null<string> (t["bin.lib.prefix"]));
+ const string* s (cast_null<string> (t["bin.lib.suffix"]));
+ t.data (
+ link_.derive_libs_paths (*f,
+ p != nullptr ? p->c_str (): nullptr,
+ s != nullptr ? s->c_str (): nullptr));
+ }
}
return r;
}
+ target_state file_install::
+ update_extra (action act, const target& t) const
+ {
+ // (Re)generate pkg-config's .pc file. While the target itself might be
+ // up-to-date from a previous run, there is no guarantee that .pc exists
+ // or also up-to-date. So to keep things simple we just regenerate it
+ // unconditionally.
+ //
+ // Also, if you are wondering why don't we just always produce this .pc,
+ // install or no install, the reason is unless and until we are updating
+ // for install, we have no idea where to things will be installed.
+ //
+ bool a;
+ const file* f;
+
+ if ((a = (f = t.is_a<liba> ())) ||
+ ( f = t.is_a<libs> ()))
+ {
+ pkgconfig_save (act, *f, a);
+ }
+
+ return target_state::unchanged;
+ }
+
void file_install::
install_extra (const file& t, const install_dir& id) const
{
diff --git a/build2/cc/install.hxx b/build2/cc/install.hxx
index a846fc8..2dd2b71 100644
--- a/build2/cc/install.hxx
+++ b/build2/cc/install.hxx
@@ -41,6 +41,15 @@ namespace build2
virtual bool
uninstall_extra (const file&, const install_dir&) const override;
+ virtual target_state
+ update_extra (action, const target&) const override;
+
+ private:
+ // pkg-config's .pc file generation (in pkgconfig.cxx).
+ //
+ void
+ pkgconfig_save (action, const file&, bool) const;
+
private:
const link& link_;
};
diff --git a/build2/cc/link.cxx b/build2/cc/link.cxx
index 1cb3a11..08b5314 100644
--- a/build2/cc/link.cxx
+++ b/build2/cc/link.cxx
@@ -19,6 +19,7 @@
#include <build2/diagnostics.hxx>
#include <build2/bin/target.hxx>
+#include <build2/pkgconfig/target.hxx>
#include <build2/cc/target.hxx> // c
#include <build2/cc/utility.hxx>
@@ -142,34 +143,33 @@ namespace build2
}
auto link::
- derive_libs_paths (file& ls) const -> libs_paths
+ derive_libs_paths (file& ls, const char* pfx, const char* sfx) const
+ -> libs_paths
{
const char* ext (nullptr);
- const char* pfx (nullptr);
- const char* sfx (nullptr);
bool win (tclass == "windows");
if (win)
{
if (tsys == "mingw32")
- pfx = "lib";
+ {
+ if (pfx == nullptr)
+ pfx = "lib";
+ }
ext = "dll";
}
- else if (tclass == "macos")
- {
- pfx = "lib";
- ext = "dylib";
- }
else
{
- pfx = "lib";
- ext = "so";
- }
+ if (pfx == nullptr)
+ pfx = "lib";
- if (auto l = ls["bin.lib.prefix"]) pfx = cast<string> (l).c_str ();
- if (auto l = ls["bin.lib.suffix"]) sfx = cast<string> (l).c_str ();
+ if (tclass == "macos")
+ ext = "dylib";
+ else
+ ext = "so";
+ }
// First sort out which extension we are using.
//
@@ -315,14 +315,6 @@ namespace build2
// Derive file name(s) and add ad hoc group members.
//
-
- // Add if necessary and lock an ad hoc group member.
- //
- auto add_adhoc = [act, &bs] (target& t, const char* type) -> target_lock
- {
- return add_adhoc_member (act, t, *bs.find_target_type (type));
- };
-
{
target_lock libi; // Have to hold until after PDB member addition.
@@ -391,6 +383,11 @@ namespace build2
}
else
{
+ if (auto l = t[ot == otype::e ? "bin.exe.prefix" : "bin.lib.prefix"])
+ p = cast<string> (l).c_str ();
+ if (auto l = t[ot == otype::e ? "bin.exe.suffix" : "bin.lib.suffix"])
+ s = cast<string> (l).c_str ();
+
switch (ot)
{
case otype::e:
@@ -400,9 +397,6 @@ namespace build2
else
e = "";
- if (auto l = t["bin.exe.prefix"]) p = cast<string> (l).c_str ();
- if (auto l = t["bin.exe.suffix"]) s = cast<string> (l).c_str ();
-
t.derive_path (e, p, s);
break;
}
@@ -412,13 +406,10 @@ namespace build2
e = "lib";
else
{
- p = "lib";
+ if (p == nullptr) p = "lib";
e = "a";
}
- if (auto l = t["bin.lib.prefix"]) p = cast<string> (l).c_str ();
- if (auto l = t["bin.lib.suffix"]) s = cast<string> (l).c_str ();
-
t.derive_path (e, p, s);
break;
}
@@ -428,9 +419,9 @@ namespace build2
// the DLL and we add libi{} import library as its member.
//
if (tclass == "windows")
- libi = add_adhoc (t, "libi");
+ libi = add_adhoc_member<bin::libi> (act, t);
- t.data (derive_libs_paths (t)); // Cache in target.
+ t.data (derive_libs_paths (t, p, s)); // Cache in target.
if (libi)
match_recipe (libi, group_recipe); // Set recipe and unlock.
@@ -438,26 +429,57 @@ namespace build2
break;
}
}
- }
- // PDB
- //
- if (!lt.static_library () &&
- cid == compiler_id::msvc &&
- (find_option ("/DEBUG", t, c_loptions, true) ||
- find_option ("/DEBUG", t, x_loptions, true)))
- {
- // Add after the import library if any.
+ // Add VC's .pdb.
//
- target_lock pdb (
- add_adhoc (t.member == nullptr ? t : *t.member, "pdb"));
+ if (ot != otype::a &&
+ cid == compiler_id::msvc &&
+ (find_option ("/DEBUG", t, c_loptions, true) ||
+ find_option ("/DEBUG", t, x_loptions, true)))
+ {
+ // Note: add after the import library if any.
+ //
+ target_lock pdb (
+ add_adhoc_member (act, t, *bs.find_target_type ("pdb")));
+
+ // We call it foo.{exe,dll}.pdb rather than just foo.pdb because
+ // we can have both foo.exe and foo.dll in the same directory.
+ //
+ pdb.target->as<file> ().derive_path (t.path (), "pdb");
+
+ match_recipe (pdb, group_recipe); // Set recipe and unlock.
+ }
- // We call it foo.{exe,dll}.pdb rather than just foo.pdb because we
- // can have both foo.exe and foo.dll in the same directory.
+ // Add pkg-config's .pc file.
//
- pdb.target->as<file> ().derive_path (t.path (), "pdb");
+ // Note that we do it here regardless of whether we are installing
+ // or not for two reasons. Firstly, it is not easy to detect this
+ // situation in apply() since the action may (and is) overridden to
+ // unconditional install. Secondly, always having the member takes
+ // care of cleanup automagically. The actual generation happens in
+ // the install rule.
+ //
+ if (ot != otype::e)
+ {
+ target_lock pc (
+ add_adhoc_member (
+ act, t,
+ ot == otype::a
+ ? pkgconfig::pca::static_type
+ : pkgconfig::pcs::static_type));
+
+ // Note that here we always use the lib name prefix, even on
+ // Windows with VC. The reason is the user needs a consistent name
+ // across platforms by which they can refere to the library. This
+ // is also the reason why we use the static/shared suffixes rather
+ // that a./.lib/.so/.dylib/.dll.
+ //
+ pc.target->as<file> ().derive_path (nullptr,
+ (p == nullptr ? "lib" : p),
+ s);
- match_recipe (pdb, group_recipe); // Set recipe and unlock.
+ match_recipe (pc, group_recipe); // Set recipe and unlock.
+ }
}
}
@@ -1164,12 +1186,12 @@ namespace build2
{
tracer trace (x, "link::perform_update");
- const file& t (xt.as<file> ());
- const path& tp (t.path ());
-
auto oop (act.outer_operation ());
bool for_install (oop == install_id || oop == uninstall_id);
+ const file& t (xt.as<file> ());
+ const path& tp (t.path ());
+
const scope& bs (t.base_scope ());
const scope& rs (*bs.root_scope ());
diff --git a/build2/cc/link.hxx b/build2/cc/link.hxx
index c4c9c9e..cadc82c 100644
--- a/build2/cc/link.hxx
+++ b/build2/cc/link.hxx
@@ -70,7 +70,7 @@ namespace build2
};
libs_paths
- derive_libs_paths (file&) const;
+ derive_libs_paths (file&, const char*, const char*) const;
// Library handling.
//
diff --git a/build2/cc/pkgconfig.cxx b/build2/cc/pkgconfig.cxx
index 80f418c..3fc40ad 100644
--- a/build2/cc/pkgconfig.cxx
+++ b/build2/cc/pkgconfig.cxx
@@ -6,15 +6,20 @@
#include <build2/target.hxx>
#include <build2/context.hxx>
#include <build2/variable.hxx>
+#include <build2/algorithm.hxx>
#include <build2/filesystem.hxx>
#include <build2/diagnostics.hxx>
+#include <build2/install/utility.hxx>
+
#include <build2/bin/target.hxx>
+#include <build2/pkgconfig/target.hxx>
#include <build2/cc/types.hxx>
#include <build2/cc/utility.hxx>
#include <build2/cc/common.hxx>
+#include <build2/cc/install.hxx>
using namespace std;
using namespace butl;
@@ -27,7 +32,7 @@ namespace build2
// Try to find a .pc file in the pkgconfig/ subdirectory of libd, trying
// several names derived from stem. If not found, return false. If found,
- // extract poptions, loptions, and libs, set the corresponding *.export.*
+ // load poptions, loptions, and libs, set the corresponding *.export.*
// variables on targets, and return true.
//
// System library search paths (those extracted from the compiler) are
@@ -37,35 +42,36 @@ namespace build2
// search_library() POV.
//
bool common::
- pkgconfig_extract (action act,
- const scope& s,
- lib& lt,
- liba* at,
- libs* st,
- const optional<string>& proj,
- const string& stem,
- const dir_path& libd,
- const dir_paths& sysd) const
+ pkgconfig_load (action act,
+ const scope& s,
+ lib& lt,
+ liba* at,
+ libs* st,
+ const optional<string>& proj,
+ const string& stem,
+ const dir_path& libd,
+ const dir_paths& sysd) const
{
- tracer trace (x, "pkgconfig_extract");
+ tracer trace (x, "pkgconfig_load");
assert (pkgconfig != nullptr);
assert (at != nullptr || st != nullptr);
// 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).
+ // names). Suffix is our ".shared" or ".static" extension.
//
- path f;
- auto search = [&f, &proj, &stem, &libd] (const dir_path& dir) -> bool
+ auto search_dir = [&proj, &stem, &libd] (const dir_path& dir,
+ const string& sfx) -> path
{
- // Check if we have this directory inrelative to this library's
- // directory.
+ // Check if we have this subdirectory in this library's directory.
//
dir_path pkgd (dir_path (libd) /= dir);
if (!exists (pkgd))
- return false;
+ return path ();
+
+ path f;
// See if there is a corresponding .pc file. About half of them called
// foo.pc and half libfoo.pc (and one of the pkg-config's authors
@@ -73,70 +79,90 @@ namespace build2
// things interesting, you know).
//
// Given the (general) import in the form <proj>%lib{<stem>}, we will
- // first try <stem>.pc, then lib<stem>.pc. Maybe it also makes sense
+ // first try lib<stem>.pc, then <stem>.pc. Maybe it also makes sense
// to try <proj>.pc, just in case. Though, according to pkg-config
// docs, the .pc file should correspond to a library, not project. But
// then you get something like zlib which calls it zlib.pc. So let's
// just do it.
//
f = pkgd;
- f /= stem;
+ f /= "lib";
+ f += stem;
+ f += sfx;
f += ".pc";
-
if (exists (f))
- return true;
+ return f;
f = pkgd;
- f /= "lib";
- f += stem;
+ f /= stem;
+ f += sfx;
f += ".pc";
-
if (exists (f))
- return true;
+ return f;
if (proj)
{
f = pkgd;
f /= *proj;
+ f += sfx;
f += ".pc";
-
if (exists (f))
- return true;
+ return f;
}
- return false;
+ return path ();
};
- // First always check the pkgconfig/ subdirectory in this library's
- // directory. Even on platforms where this is not the canonical place,
- // .pc files of autotools-based packages installed by the user often
- // still end up there.
- //
- if (!search (dir_path ("pkgconfig")))
+ auto search = [&search_dir, this] () -> pair<path, path>
{
- // Platform-specific locations.
+ pair<path, path> r;
+
+ auto check = [&r, &search_dir] (const dir_path& d) -> bool
+ {
+ // First look for static/shared-specific files.
+ //
+ r.first = search_dir (d, ".static");
+ r.second = search_dir (d, ".shared");
+
+ if (!r.first.empty () || !r.second.empty ())
+ return true;
+
+ // Then the common.
+ //
+ r.first = r.second = search_dir (d, string ());
+ return !r.first.empty ();
+ };
+
+ // First always check the pkgconfig/ subdirectory in this library's
+ // directory. Even on platforms where this is not the canonical place,
+ // .pc files of autotools-based packages installed by the user often
+ // still end up there.
//
- if (tsys == "freebsd")
+ if (!check (dir_path ("pkgconfig")))
{
- // On FreeBSD .pc files go to libdata/pkgconfig/, not lib/pkgconfig/.
+ // Platform-specific locations.
//
- if (!search ((dir_path ("..") /= "libdata") /= "pkgconfig"))
- return false;
+ if (tsys == "freebsd")
+ {
+ // On FreeBSD .pc files go to libdata/pkgconfig/, not lib/pkgconfig/.
+ //
+ check ((dir_path ("..") /= "libdata") /= "pkgconfig");
+ }
}
- else
- return false;
- }
- // Ok, we are in business. Time to run pkg-config. To keep things
- // simple, we run it multiple times, for --cflag/--libs and --static.
+ return r;
+ };
+
+ // To keep things simple, we run pkg-config multiple times, for
+ // --cflag/--libs and --static.
//
- auto extract = [&f, this] (const char* op, bool impl) -> string
+ auto extract = [this] (const path& f, const char* o, bool a) -> string
{
const char* args[] = {
pkgconfig->recall_string (),
- op, // --cflags/--libs
- (impl ? "--static" : f.string ().c_str ()),
- (impl ? f.string ().c_str () : nullptr),
+ o, // --cflags/--libs
+ (a ? "--static" : f.string ().c_str ()),
+ (a ? f.string ().c_str () : nullptr),
nullptr
};
@@ -144,10 +170,9 @@ namespace build2
*pkgconfig, args, [] (string& s) -> string {return move (s);});
};
- // On Windows pkg-config (at least the MSYS2 one which we are using)
- // will escape backslahses in paths. In fact, it may escape things
- // even on non-Windows platforms, for example, spaces. So we use a
- // slightly modified version of next_word().
+ // On Windows pkg-config will escape backslahses in paths. In fact, it
+ // may escape things even on non-Windows platforms, for example,
+ // spaces. So we use a slightly modified version of next_word().
//
auto next = [] (const string& s, size_t& b, size_t& e) -> string
{
@@ -184,12 +209,13 @@ namespace build2
return r;
};
- // First extract --cflags and set them as lib{}:export.poptions (i.e.,
- // they will be common for both liba{} and libs{}; later when we do
- // split .pc files, we will have to run this twice).
+ // Extract --cflags and set them as lib?{}:export.poptions. Note that we
+ // still pass --static in case this is pkgconf which has Cflags.private.
//
+ auto parse_cflags = [&trace, &extract, &next, this]
+ (target& t, const path& f, bool a)
{
- string cstr (extract ("--cflags", false));
+ string cstr (extract (f, "--cflags", a));
strings pops;
string o;
@@ -243,7 +269,7 @@ namespace build2
if (!pops.empty ())
{
- auto p (lt.vars.insert (c_export_poptions));
+ auto p (t.vars.insert (c_export_poptions));
// The only way we could already have this value is if this same
// library was also imported as a project (as opposed to installed).
@@ -253,13 +279,15 @@ namespace build2
if (p.second)
p.first.get () = move (pops);
}
- }
+ };
- // Now parse --libs into loptions/libs (interface and implementation).
+ // Parse --libs into loptions/libs (interface and implementation).
//
- auto parse_libs = [act, &s, &f, sysd, &next, this] (
- const string& lstr, target& t)
+ auto parse_libs = [act, &s, sysd, &extract, &next, this]
+ (target& t, const path& f, bool a)
{
+ string lstr (extract (f, "--libs", a));
+
strings lops;
vector<name> libs;
@@ -274,7 +302,6 @@ 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;
string o;
for (size_t b (0), e (0); !(o = next (lstr, b, e)).empty (); )
@@ -438,8 +465,9 @@ namespace build2
all = false;
}
- // If all the -l's resolved and no other options, then drop all the
- // -L's. If we have unknown options, then leave them in to be safe.
+ // If all the -l's resolved and there were no other options, then drop
+ // all the -L's. If we have unknown options, then leave them in to be
+ // safe.
//
if (all && known)
lops.clear ();
@@ -487,20 +515,187 @@ namespace build2
}
};
- {
- string lstr_int (extract ("--libs", false));
- string lstr_imp (extract ("--libs", true));
+ pair<path, path> ps (search ());
+ const path& ap (ps.first);
+ const path& sp (ps.second);
- parse_libs (lstr_int, lt);
+ if (ap.empty () && sp.empty ())
+ return false;
- // Currently, these will result in the same values but it will be
- // different once we support split .pc files.
- //
- if (at != nullptr) parse_libs (lstr_imp, *at);
- if (st != nullptr) parse_libs (lstr_imp, *st);
+ if (at != nullptr && !ap.empty ())
+ {
+ parse_cflags (*at, ap, true);
+ parse_libs (*at, ap, true);
+ }
+
+ if (st != nullptr && !sp.empty ())
+ {
+ parse_cflags (*st, sp, false);
+ parse_libs (lt, sp, false); // Note: setting on lib{} (interface).
}
return true;
}
+
+ void file_install::
+ pkgconfig_save (action act, const file& l, bool la) const
+ {
+ tracer trace (x, "pkgconfig_save");
+
+ const scope& bs (l.base_scope ());
+ const scope& rs (*bs.root_scope ());
+
+ auto* pc (find_adhoc_member<pkgconfig::pc> (l));
+ assert (pc != nullptr);
+
+ const path& p (pc->path ());
+
+ if (verb >= 2)
+ text << "cat >" << p;
+
+ try
+ {
+ ofdstream os (p);
+ auto_rmfile arm (p);
+
+ // @@ version may not be string, need to reverse.
+ //
+ os << "Name: " << cast<string> (rs.vars[var_project]) << endl;
+ os << "Version: " << cast<string> (rs.vars["version"]) << endl;
+ os << "Description: @@ TODO" << endl;
+
+ // By default we assume things go into install.{include, lib}.
+ //
+ // @@ TODO: quoting/whitespace escaping.
+ // @@ TODO: support whole archive?
+ //
+ using install::resolve_dir;
+
+ dir_path id (resolve_dir (l, cast<dir_path> (l["install.include"])));
+
+ auto save_poptions = [&l, &os] (const variable& var)
+ {
+ if (const strings* v = cast_null<strings> (l[var]))
+ {
+ for (auto i (v->begin ()); i != v->end (); ++i)
+ {
+ const string& o (*i);
+ size_t n (o.size ());
+
+ // Filter out -I (both -I<dir> and -I <dir> forms).
+ //
+ if (n >= 2 && o[0] == '-' && o[1] == 'I')
+ {
+ if (n == 2)
+ ++i;
+
+ continue;
+ }
+
+ os << ' ' << o;
+ }
+ }
+ };
+
+ // Given a library save its -l-style library name.
+ //
+ auto save_library = [&os] (const file& l)
+ {
+ // Use the .pc file name to derive the -l library name (in case of
+ // the shared library, l.path() may contain version).
+ //
+ auto* pc (find_adhoc_member<pkgconfig::pc> (l));
+ assert (pc != nullptr);
+
+ // We also want to strip the lib prefix unless it is part of the
+ // target name while keeping custom library prefix/suffix, if any.
+ //
+ string n (pc->path ().leaf ().base ().base ().string ());
+ if (n.size () > 3 &&
+ path::traits::compare (n.c_str (), 3, "lib", 3) == 0 &&
+ path::traits::compare (n.c_str (), n.size (),
+ l.name.c_str (), l.name.size ()) != 0)
+ n.erase (0, 3);
+
+ os << " -l" << n;
+ };
+
+ // Cflags.
+ //
+ os << "Cflags:";
+ os << " -I" << id;
+ save_poptions (c_export_poptions);
+ save_poptions (x_export_poptions);
+ os << endl;
+
+ // Libs.
+ //
+ dir_path ld (resolve_dir (l, cast<dir_path> (l["install.lib"])));
+
+ os << "Libs:";
+ os << " -L" << ld;
+
+ // Now process ourselves as if we were being linked to something (so
+ // pretty similar to link::append_libraries()).
+ //
+ auto imp = [] (const file&, bool la) {return la;};
+
+ auto lib = [&os, &save_library] (const file* l,
+ const string& p,
+ lflags,
+ bool)
+ {
+ if (l != nullptr)
+ {
+ if (l->is_a<libs> () || l->is_a<liba> ()) // See through libux.
+ save_library (*l);
+ }
+ else
+ os << ' ' << p; // Something "system'y", pass as is.
+ };
+
+ auto opt = [&os] (const file&,
+ const string&,
+ bool, bool)
+ {
+ //@@ TODO: should we filter -L similar to -I?
+
+ /*
+ // If we need an interface value, then use the group (lib{}).
+ //
+ if (const target* g = exp && l.is_a<libs> () ? l.group : &l)
+ {
+ const variable& var (
+ com
+ ? (exp ? c_export_loptions : c_loptions)
+ : (t == x
+ ? (exp ? x_export_loptions : x_loptions)
+ : var_pool[t + (exp ? ".export.loptions" : ".loptions")]));
+
+ append_options (args, *g, var);
+ }
+ */
+ };
+
+ process_libraries (
+ act,
+ bs,
+ linfo {otype::e, la ? lorder::a_s : lorder::s_a}, // System-default.
+ sys_lib_dirs,
+ l, la,
+ 0, // Link flags.
+ imp, lib, opt,
+ true);
+
+ os << endl;
+
+ os.close ();
+ arm.cancel ();
+ }
+ catch (const io_error& e)
+ {
+ fail << "unable to write " << p << ": " << e;
+ }
+ }
}
}