aboutsummaryrefslogtreecommitdiff
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
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.
-rw-r--r--libbuild2/bin/target.cxx2
-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
-rw-r--r--libbuild2/types.hxx1
8 files changed, 90 insertions, 27 deletions
diff --git a/libbuild2/bin/target.cxx b/libbuild2/bin/target.cxx
index a8f3bf0..bf701c9 100644
--- a/libbuild2/bin/target.cxx
+++ b/libbuild2/bin/target.cxx
@@ -83,7 +83,7 @@ namespace build2
// running serial. For the members it is also safe to set the group during
// creation.
- // obj*{} and [h]bmi*{} member factory.
+ // obj*{}, lib*{}, and [h]bmi*{} member factory.
//
template <typename M, typename G>
static target*
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
diff --git a/libbuild2/types.hxx b/libbuild2/types.hxx
index e24c9a6..022a6a4 100644
--- a/libbuild2/types.hxx
+++ b/libbuild2/types.hxx
@@ -268,6 +268,7 @@ namespace build2
using butl::timestamp_unknown;
using butl::timestamp_unknown_rep;
using butl::timestamp_nonexistent;
+ using butl::timestamp_unreal;
using butl::to_string;
using butl::operator<<;