aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/cc
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2020-03-20 12:56:12 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2020-03-20 12:56:12 +0200
commita18661636cd169b0912cc58c623fdd69e3250229 (patch)
tree785943e5fba6808c69c58cbeadaf66d6257c36ca /libbuild2/cc
parent3b361af7681125e7db98a9e4e69c80d469cae256 (diff)
Generate common .pc file in addition to static/staged when installing lib{}
The common .pc file is produced by ignoring any static/shared-specific poptions and splitting loptions/libs into Libs/Libs.private. It is "best effort", in a sense that it's not guaranteed to be sufficient in all cases, but it will probably cover the majority of cases, even on Windows, thanks to automatic dllimport'ing of functions.
Diffstat (limited to 'libbuild2/cc')
-rw-r--r--libbuild2/cc/link-rule.cxx58
-rw-r--r--libbuild2/cc/link-rule.hxx2
-rw-r--r--libbuild2/cc/module.cxx1
-rw-r--r--libbuild2/cc/pkgconfig.cxx36
-rw-r--r--libbuild2/cc/target.cxx14
-rw-r--r--libbuild2/cc/target.hxx3
6 files changed, 88 insertions, 26 deletions
diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx
index 6047206..b11ee42 100644
--- a/libbuild2/cc/link-rule.cxx
+++ b/libbuild2/cc/link-rule.cxx
@@ -17,6 +17,7 @@
#include <libbuild2/filesystem.hxx>
#include <libbuild2/diagnostics.hxx>
+#include <libbuild2/bin/rule.hxx> // lib_rule::build_members()
#include <libbuild2/bin/target.hxx>
#include <libbuild2/bin/utility.hxx>
@@ -125,7 +126,7 @@ namespace build2
// doing here since if there is no existing target, then there can
// be no prerequisites.
//
- // Note, however, that we cannot linkup a prerequisite target
+ // Note, however, that we cannot link-up a prerequisite target
// member to its group since we are not matching this target. As
// result we have to do all the steps except for setting t.group
// and pass both member and group (we also cannot query t.group
@@ -1029,21 +1030,41 @@ namespace build2
// cleanup automagically. The actual generation happens in
// perform_update() below.
//
+ // Things are even trickier for the common .pc file: we only want to
+ // have it in the shared library if we are not installing static
+ // (see pkgconfig_save() for details). But we can't know it at this
+ // stage. So what we are going to do is conceptually tie the common
+ // file to the lib{} group (which does somehow feel correct) by only
+ // installing it if the lib{} group is installed. Specifically, here
+ // we will use its bin.lib to decide what will be installed and in
+ // perform_update() we will confirm that it is actually installed.
+ //
if (ot != otype::e)
{
- file& pc (add_adhoc_member<file> (t,
- (ot == otype::a
- ? pca::static_type
- : 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 refer to the library. This
// is also the reason why we use the .static and .shared second-
// level extensions rather that a./.lib and .so/.dylib/.dll.
+
+ // Note also that the order in which we are adding these members
+ // is important (see add_addhoc_member() for details).
//
- if (pc.path ().empty ())
- pc.derive_path (nullptr, (p == nullptr ? "lib" : p), s);
+ if (ot == otype::a || !lib_rule::build_members (rs).a)
+ {
+ auto& pc (add_adhoc_member<pc> (t));
+
+ if (pc.path ().empty ())
+ pc.derive_path (nullptr, (p == nullptr ? "lib" : p), s);
+ }
+
+ auto& pcx (add_adhoc_member<file> (t,
+ (ot == otype::a
+ ? pca::static_type
+ : pcs::static_type)));
+
+ if (pcx.path ().empty ())
+ pcx.derive_path (nullptr, (p == nullptr ? "lib" : p), s);
}
// Add the Windows rpath emulating assembly directory as fsdir{}.
@@ -1984,7 +2005,26 @@ namespace build2
// for install, we have no idea where-to things will be installed.
//
if (for_install && lt.library () && !lt.utility)
- pkgconfig_save (a, t, lt.static_library (), binless);
+ {
+ bool la (lt.static_library ());
+
+ pkgconfig_save (a, t, la, false /* common */, binless);
+
+ // Generate the common .pc file if the lib{} rule is matched (see
+ // apply() for details on this two-stage logic).
+ //
+ auto* m (find_adhoc_member<pc> (t)); // Will be pca/pcs if not found.
+
+ if (!m->is_a (la ? pca::static_type : pcs::static_type))
+ {
+ if (t.group->matched (a))
+ pkgconfig_save (a, t, la, true /* common */, binless);
+ else
+ // Mark as non-existent not to confuse the install rule.
+ //
+ m->mtime (timestamp_nonexistent);
+ }
+ }
// If we have no binary to build then we are done.
//
diff --git a/libbuild2/cc/link-rule.hxx b/libbuild2/cc/link-rule.hxx
index 6fa8343..ce514b5 100644
--- a/libbuild2/cc/link-rule.hxx
+++ b/libbuild2/cc/link-rule.hxx
@@ -178,7 +178,7 @@ namespace build2
// pkg-config's .pc file generation (pkgconfig.cxx).
//
void
- pkgconfig_save (action, const file&, bool, bool) const;
+ pkgconfig_save (action, const file&, bool, bool, bool) const;
private:
const string rule_id;
diff --git a/libbuild2/cc/module.cxx b/libbuild2/cc/module.cxx
index 70cbc47..d6c337d 100644
--- a/libbuild2/cc/module.cxx
+++ b/libbuild2/cc/module.cxx
@@ -776,6 +776,7 @@ namespace build2
if (*x_hdr != &h::static_type)
insert_hdr (h::static_type);
+ rs.insert_target_type<pc> ();
rs.insert_target_type<pca> ();
rs.insert_target_type<pcs> ();
diff --git a/libbuild2/cc/pkgconfig.cxx b/libbuild2/cc/pkgconfig.cxx
index 64dd9ca..f95599f 100644
--- a/libbuild2/cc/pkgconfig.cxx
+++ b/libbuild2/cc/pkgconfig.cxx
@@ -1301,8 +1301,19 @@ namespace build2
#endif
+ // If common is true, generate a "best effort" (i.e., not guaranteed to be
+ // sufficient in all cases) common .pc file by ignoring any static/shared-
+ // specific poptions and splitting loptions/libs into Libs/Libs.private.
+ // Note that if both static and shared are being installed, the common
+ // file must be generated based on the static library to get accurate
+ // Libs.private.
+ //
void link_rule::
- pkgconfig_save (action a, const file& l, bool la, bool binless) const
+ pkgconfig_save (action a,
+ const file& l,
+ bool la,
+ bool common,
+ bool binless) const
{
tracer trace (x, "pkgconfig_save");
@@ -1311,15 +1322,22 @@ namespace build2
const scope& bs (l.base_scope ());
const scope& rs (*bs.root_scope ());
- auto* t (find_adhoc_member<pc> (l));
+ auto* t (find_adhoc_member<pc> (l, (common ? pc::static_type :
+ la ? pca::static_type :
+ /* */ pcs::static_type)));
assert (t != nullptr);
+ // This is the lib{} group if we are generating the common file and the
+ // target itself otherwise.
+ //
+ const file& g (common ? l.group->as<file> () : l);
+
// By default we assume things go into install.{include, lib}.
//
using install::resolve_dir;
- dir_path idir (resolve_dir (l, cast<dir_path> (l["install.include"])));
- dir_path ldir (resolve_dir (l, cast<dir_path> (l["install.lib"])));
+ dir_path idir (resolve_dir (g, cast<dir_path> (g["install.include"])));
+ dir_path ldir (resolve_dir (g, cast<dir_path> (g["install.lib"])));
const path& p (t->path ());
@@ -1363,9 +1381,9 @@ namespace build2
os << "URL: " << *u << endl;
}
- auto save_poptions = [&l, &os] (const variable& var)
+ auto save_poptions = [&g, &os] (const variable& var)
{
- if (const strings* v = cast_null<strings> (l[var]))
+ if (const strings* v = cast_null<strings> (g[var]))
{
for (auto i (v->begin ()); i != v->end (); ++i)
{
@@ -1469,11 +1487,11 @@ namespace build2
// we still want to sort things out into Libs/Libs.private. This is
// necessary to distinguish between interface and implementation
// dependencies if we don't have the shared variant (see the load
- // logic for details).
+ // logic for details). And also for the common .pc file, naturally.
//
//@@ TODO: would be nice to weed out duplicates. But is it always
// safe? Think linking archives: will have to keep duplicates in
- // the second position, not first. Gets even trickier with
+ // the second position, not first. Gets even trickier with the
// Libs.private split.
//
{
@@ -1556,7 +1574,7 @@ namespace build2
};
vector<module> modules;
- for (const target* pt: l.prerequisite_targets[a])
+ for (const target* pt: g.prerequisite_targets[a])
{
// @@ UTL: we need to (recursively) see through libu*{} (and
// also in search_modules()).
diff --git a/libbuild2/cc/target.cxx b/libbuild2/cc/target.cxx
index a962575..b17e1ef 100644
--- a/libbuild2/cc/target.cxx
+++ b/libbuild2/cc/target.cxx
@@ -54,16 +54,18 @@ namespace build2
false
};
+ extern const char pc_ext[] = "pc"; // VC14 rejects constexpr.
+
const target_type pc::static_type
{
"pc",
&file::static_type,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- &target_search,
+ &target_factory<pc>,
+ &target_extension_fix<pc_ext>,
+ nullptr, /* default_extension */
+ &target_pattern_fix<pc_ext>,
+ &target_print_0_ext_verb, // Fixed extension, no use printing.
+ &file_search,
false
};
diff --git a/libbuild2/cc/target.hxx b/libbuild2/cc/target.hxx
index 42d15c8..7067421 100644
--- a/libbuild2/cc/target.hxx
+++ b/libbuild2/cc/target.hxx
@@ -61,13 +61,14 @@ namespace build2
// pkg-config file targets.
//
- class LIBBUILD2_CC_SYMEXPORT pc: public file
+ class LIBBUILD2_CC_SYMEXPORT pc: public file // .pc (common)
{
public:
using file::file;
public:
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
class LIBBUILD2_CC_SYMEXPORT pca: public pc // .static.pc