aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2020-06-16 09:43:27 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2020-06-16 09:43:27 +0200
commitecfae2da0b23631cee3e723a562f64f8aace6879 (patch)
tree6f7bae1bec966bcc456b71fbaabf8556f031d61b
parentbd9ca1e55dc1396da73c4699ccc021dc1f604fe6 (diff)
Move common functionality from cc to bin
-rw-r--r--libbuild2/bin/rule.cxx22
-rw-r--r--libbuild2/bin/rule.hxx12
-rw-r--r--libbuild2/bin/types.hxx58
-rw-r--r--libbuild2/bin/utility.cxx134
-rw-r--r--libbuild2/bin/utility.hxx67
-rw-r--r--libbuild2/bin/utility.ixx21
-rw-r--r--libbuild2/cc/link-rule.cxx2
-rw-r--r--libbuild2/cc/types.hxx43
-rw-r--r--libbuild2/cc/utility.cxx94
-rw-r--r--libbuild2/cc/utility.hxx41
-rw-r--r--libbuild2/cc/utility.ixx15
11 files changed, 283 insertions, 226 deletions
diff --git a/libbuild2/bin/rule.cxx b/libbuild2/bin/rule.cxx
index a2cdf8c..0abfcb5 100644
--- a/libbuild2/bin/rule.cxx
+++ b/libbuild2/bin/rule.cxx
@@ -9,6 +9,7 @@
#include <libbuild2/diagnostics.hxx>
#include <libbuild2/bin/target.hxx>
+#include <libbuild2/bin/utility.hxx>
using namespace std;
@@ -36,29 +37,14 @@ namespace build2
// The whole logic is pretty much as if we had our two group members as
// our prerequisites.
//
- lib_rule::members lib_rule::
- build_members (const scope& rs)
- {
- const string& type (cast<string> (rs["bin.lib"]));
-
- bool a (type == "static" || type == "both");
- bool s (type == "shared" || type == "both");
-
- if (!a && !s)
- fail << "unknown library type: " << type <<
- info << "'static', 'shared', or 'both' expected";
-
- return members {a, s};
- }
-
bool lib_rule::
match (action a, target& xt, const string&) const
{
lib& t (xt.as<lib> ());
- members bm (a.meta_operation () != dist_id
- ? build_members (t.root_scope ())
- : members {true, true});
+ lmembers bm (a.meta_operation () != dist_id
+ ? link_members (t.root_scope ())
+ : lmembers {true, true});
t.a = bm.a ? &search<liba> (t, t.dir, t.out, t.name) : nullptr;
t.s = bm.s ? &search<libs> (t, t.dir, t.out, t.name) : nullptr;
diff --git a/libbuild2/bin/rule.hxx b/libbuild2/bin/rule.hxx
index 57c784f..074b46d 100644
--- a/libbuild2/bin/rule.hxx
+++ b/libbuild2/bin/rule.hxx
@@ -45,18 +45,6 @@ namespace build2
static target_state
perform (action, const target&);
-
- // Return library types to build according to the bin.lib value (set
- // on project's root scope by init()).
- //
- struct members
- {
- bool a; // static
- bool s; // shared
- };
-
- static members
- build_members (const scope&);
};
}
}
diff --git a/libbuild2/bin/types.hxx b/libbuild2/bin/types.hxx
new file mode 100644
index 0000000..773ef20
--- /dev/null
+++ b/libbuild2/bin/types.hxx
@@ -0,0 +1,58 @@
+// file : libbuild2/bin/types.hxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#ifndef LIBBUILD2_BIN_TYPES_HXX
+#define LIBBUILD2_BIN_TYPES_HXX
+
+#include <libbuild2/types.hxx>
+#include <libbuild2/utility.hxx>
+
+namespace build2
+{
+ namespace bin
+ {
+ // Compiler/linker output type (executable, static, or shared).
+ //
+ enum class otype {e, a, s};
+
+ struct ltype
+ {
+ otype type;
+ bool utility; // True for utility libraries.
+
+ bool executable () const {return type == otype::e && !utility;}
+ bool library () const {return type != otype::e || utility;}
+ bool static_library () const {return type == otype::a || utility;}
+ bool shared_library () const {return type == otype::s && !utility;}
+ bool member_library () const {return type != otype::e;}
+ };
+
+ // Library group (lib{}) members to build.
+ //
+ struct lmembers
+ {
+ bool a;
+ bool s;
+ };
+
+ // Library link order.
+ //
+ enum class lorder {a, s, a_s, s_a};
+
+ // Link information: output type and link order.
+ //
+ struct linfo
+ {
+ otype type;
+ lorder order;
+ };
+
+ // Prerequisite target link flags (saved in prerequisite_target::data).
+ //
+ using lflags = uintptr_t;
+
+ const lflags lflag_whole = 0x00000001U; // Link whole liba{}/libu*{}.
+ }
+}
+
+#endif // LIBBUILD2_BIN_TYPES_HXX
diff --git a/libbuild2/bin/utility.cxx b/libbuild2/bin/utility.cxx
new file mode 100644
index 0000000..8032b79
--- /dev/null
+++ b/libbuild2/bin/utility.cxx
@@ -0,0 +1,134 @@
+// file : libbuild2/bin/utility.cxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#include <libbuild2/bin/utility.hxx>
+
+#include <libbuild2/scope.hxx>
+#include <libbuild2/variable.hxx>
+#include <libbuild2/algorithm.hxx> // search()
+
+namespace build2
+{
+ namespace bin
+ {
+ lorder
+ link_order (const scope& bs, otype ot)
+ {
+ // Initialize to suppress 'may be used uninitialized' warning produced
+ // by MinGW GCC 5.4.0.
+ //
+ const char* var (nullptr);
+
+ switch (ot)
+ {
+ case otype::e: var = "bin.exe.lib"; break;
+ case otype::a: var = "bin.liba.lib"; break;
+ case otype::s: var = "bin.libs.lib"; break;
+ }
+
+ const auto& v (cast<strings> (bs[var]));
+ return v[0] == "shared"
+ ? v.size () > 1 && v[1] == "static" ? lorder::s_a : lorder::s
+ : v.size () > 1 && v[1] == "shared" ? lorder::a_s : lorder::a;
+ }
+
+ lmembers
+ link_members (const scope& rs)
+ {
+ const string& type (cast<string> (rs["bin.lib"]));
+
+ bool a (type == "static" || type == "both");
+ bool s (type == "shared" || type == "both");
+
+ if (!a && !s)
+ fail << "unknown library type: " << type <<
+ info << "'static', 'shared', or 'both' expected";
+
+ return lmembers {a, s};
+ }
+
+ const target*
+ link_member (const libx& x, action a, linfo li, bool exist)
+ {
+ if (x.is_a<libul> ())
+ {
+ // For libul{} that is linked to an executable the member choice
+ // should be dictated by the members of lib{} this libul{} is
+ // "primarily" for. If both are being built, then it seems natural to
+ // prefer static over shared since it could be faster (but I am sure
+ // someone will probably want this configurable).
+ //
+ if (li.type == otype::e)
+ {
+ // Utility libraries are project-local which means the primarily
+ // target should be in the same project as us.
+ //
+ li.type = link_members (x.root_scope ()).a ? otype::a : otype::s;
+ }
+
+ const target_type& tt (li.type == otype::a
+ ? libua::static_type
+ : libus::static_type);
+
+ // Called by the compile rule during execute.
+ //
+ return x.ctx.phase == run_phase::match && !exist
+ ? &search (x, tt, x.dir, x.out, x.name)
+ : search_existing (x.ctx, tt, x.dir, x.out, x.name);
+ }
+ else
+ {
+ assert (!exist);
+
+ const lib& l (x.as<lib> ());
+
+ // Make sure group members are resolved.
+ //
+ group_view gv (resolve_members (a, l));
+ assert (gv.members != nullptr);
+
+ lorder lo (li.order);
+
+ bool ls (true);
+ switch (lo)
+ {
+ case lorder::a:
+ case lorder::a_s:
+ ls = false; // Fall through.
+ case lorder::s:
+ case lorder::s_a:
+ {
+ if (ls ? l.s == nullptr : l.a == nullptr)
+ {
+ if (lo == lorder::a_s || lo == lorder::s_a)
+ ls = !ls;
+ else
+ fail << (ls ? "shared" : "static") << " variant of " << l
+ << " is not available";
+ }
+ }
+ }
+
+ return ls ? static_cast<const target*> (l.s) : l.a;
+ }
+ }
+
+ pattern_paths
+ lookup_pattern (const scope& rs)
+ {
+ pattern_paths r;
+
+ // Theoretically, we could have both the pattern and the search paths,
+ // for example, the pattern can come first followed by the paths.
+ //
+ if (const string* v = cast_null<string> (rs["bin.pattern"]))
+ {
+ (path::traits_type::is_separator (v->back ())
+ ? r.paths
+ : r.pattern) = v->c_str ();
+ }
+
+ return r;
+ }
+ }
+}
diff --git a/libbuild2/bin/utility.hxx b/libbuild2/bin/utility.hxx
index 8fe0037..91b51f8 100644
--- a/libbuild2/bin/utility.hxx
+++ b/libbuild2/bin/utility.hxx
@@ -7,13 +7,55 @@
#include <libbuild2/types.hxx>
#include <libbuild2/utility.hxx>
-#include <libbuild2/scope.hxx>
-#include <libbuild2/variable.hxx>
+#include <libbuild2/action.hxx>
+
+#include <libbuild2/bin/types.hxx>
+#include <libbuild2/bin/target.hxx>
namespace build2
{
namespace bin
{
+ // @@ Here we conflate the term "link" to mean both linker output and
+ // linking of a library.
+
+ // Linker output type from binary (exe{}, lib*{}) target.
+ //
+ ltype
+ link_type (const target&);
+
+ // Library group (lib{}) members to build according to the bin.lib value.
+ //
+ LIBBUILD2_BIN_SYMEXPORT lmembers
+ link_members (const scope& rs);
+
+ // Library link order.
+ //
+ // The reason we pass scope and not the target is because this function is
+ // called not only for exe/lib but also for obj as part of the library
+ // metadata protocol implementation. Normally the bin.*.lib values will be
+ // project-wide. With this scheme they can be customized on the per-
+ // directory basis but not per-target which means all exe/lib in the same
+ // directory have to have the same link order.
+ //
+ LIBBUILD2_BIN_SYMEXPORT lorder
+ link_order (const scope& base, otype);
+
+ inline linfo
+ link_info (const scope& base, otype ot)
+ {
+ return linfo {ot, link_order (base, ot)};
+ }
+
+ // Given the link order return the library member to link. That is, liba{}
+ // or libs{} for lib{} and libua{} or libus{} for libul{}.
+ //
+ // If existing is true, then only return the member target if it exists
+ // (currently only used and supported for utility libraries).
+ //
+ LIBBUILD2_BIN_SYMEXPORT const target*
+ link_member (const libx&, action, linfo, bool existing = false);
+
// Lookup the bin.pattern value and split it into the pattern and the
// search paths.
//
@@ -23,24 +65,11 @@ namespace build2
const char* paths = nullptr;
};
- inline pattern_paths
- lookup_pattern (const scope& rs)
- {
- pattern_paths r;
-
- // Theoretically, we could have both the pattern and the search paths,
- // for example, the pattern can come first followed by the paths.
- //
- if (const string* v = cast_null<string> (rs["bin.pattern"]))
- {
- (path::traits_type::is_separator (v->back ())
- ? r.paths
- : r.pattern) = v->c_str ();
- }
-
- return r;
- }
+ LIBBUILD2_BIN_SYMEXPORT pattern_paths
+ lookup_pattern (const scope& rs);
}
}
+#include <libbuild2/bin/utility.ixx>
+
#endif // LIBBUILD2_BIN_UTILITY_HXX
diff --git a/libbuild2/bin/utility.ixx b/libbuild2/bin/utility.ixx
new file mode 100644
index 0000000..91c919b
--- /dev/null
+++ b/libbuild2/bin/utility.ixx
@@ -0,0 +1,21 @@
+// file : libbuild2/bin/utility.ixx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+namespace build2
+{
+ namespace bin
+ {
+ inline ltype
+ link_type (const target& t)
+ {
+ bool u (false);
+ otype o (
+ t.is_a<exe> () || (u = t.is_a<libue> ()) ? otype::e :
+ t.is_a<liba> () || (u = t.is_a<libua> ()) ? otype::a :
+ t.is_a<libs> () || (u = t.is_a<libus> ()) ? otype::s :
+ static_cast<otype> (0xFF));
+
+ return ltype {o, u};
+ }
+ }
+}
diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx
index bc8eb8e..9b526ee 100644
--- a/libbuild2/cc/link-rule.cxx
+++ b/libbuild2/cc/link-rule.cxx
@@ -1050,7 +1050,7 @@ namespace build2
// Note also that the order in which we are adding these members
// is important (see add_addhoc_member() for details).
//
- if (ot == otype::a || !lib_rule::build_members (rs).a)
+ if (ot == otype::a || !link_members (rs).a)
{
auto& pc (add_adhoc_member<pc> (t));
diff --git a/libbuild2/cc/types.hxx b/libbuild2/cc/types.hxx
index f74fc94..0a6b6cc 100644
--- a/libbuild2/cc/types.hxx
+++ b/libbuild2/cc/types.hxx
@@ -9,10 +9,19 @@
#include <libbuild2/target-type.hxx>
+#include <libbuild2/bin/types.hxx>
+
namespace build2
{
namespace cc
{
+ using bin::otype;
+ using bin::ltype;
+ using bin::lorder;
+ using bin::linfo;
+ using bin::lflags;
+ using bin::lflag_whole;
+
// Translation unit information.
//
// We use absolute and normalized header path as the header unit module
@@ -67,22 +76,6 @@ namespace build2
return os << (l == lang::c ? "C" : "C++");
}
- // Compile/link output type (executable, static, or shared).
- //
- enum class otype {e, a, s};
-
- struct ltype
- {
- otype type;
- bool utility; // True for utility libraries.
-
- bool executable () const {return type == otype::e && !utility;}
- bool library () const {return type != otype::e || utility;}
- bool static_library () const {return type == otype::a || utility;}
- bool shared_library () const {return type == otype::s && !utility;}
- bool member_library () const {return type != otype::e;}
- };
-
// Compile target types.
//
struct compile_target_types
@@ -91,24 +84,6 @@ namespace build2
const target_type& bmi;
const target_type& hbmi;
};
-
- // Library link order.
- //
- enum class lorder {a, s, a_s, s_a};
-
- // Link information: output type and link order.
- //
- struct linfo
- {
- otype type;
- lorder order;
- };
-
- // Prerequisite link flags.
- //
- using lflags = uintptr_t; // To match prerequisite_target::data.
-
- const lflags lflag_whole = 0x00000001U; // Link whole liba{}/libu*}.
}
}
diff --git a/libbuild2/cc/utility.cxx b/libbuild2/cc/utility.cxx
index 93f94ae..283e1b4 100644
--- a/libbuild2/cc/utility.cxx
+++ b/libbuild2/cc/utility.cxx
@@ -4,11 +4,6 @@
#include <libbuild2/cc/utility.hxx>
#include <libbuild2/file.hxx>
-#include <libbuild2/variable.hxx>
-#include <libbuild2/algorithm.hxx> // search()
-
-#include <libbuild2/bin/rule.hxx>
-#include <libbuild2/bin/target.hxx>
using namespace std;
@@ -22,94 +17,5 @@ namespace build2
const dir_path module_build_dir (dir_path (module_dir) /= "build");
const dir_path module_build_modules_dir (
dir_path (module_build_dir) /= "modules");
-
- lorder
- link_order (const scope& bs, otype ot)
- {
- // Initialize to suppress 'may be used uninitialized' warning produced
- // by MinGW GCC 5.4.0.
- //
- const char* var (nullptr);
-
- switch (ot)
- {
- case otype::e: var = "bin.exe.lib"; break;
- case otype::a: var = "bin.liba.lib"; break;
- case otype::s: var = "bin.libs.lib"; break;
- }
-
- const auto& v (cast<strings> (bs[var]));
- return v[0] == "shared"
- ? v.size () > 1 && v[1] == "static" ? lorder::s_a : lorder::s
- : v.size () > 1 && v[1] == "shared" ? lorder::a_s : lorder::a;
- }
-
- const target*
- link_member (const bin::libx& x, action a, linfo li, bool exist)
- {
- if (x.is_a<libul> ())
- {
- // For libul{} that is linked to an executable the member choice
- // should be dictated by the members of lib{} this libul{} is
- // "primarily" for. If both are being built, then it seems natural to
- // prefer static over shared since it could be faster (but I am sure
- // someone will probably want this configurable).
- //
- if (li.type == otype::e)
- {
- // Utility libraries are project-local which means the primarily
- // target should be in the same project as us.
- //
- li.type = lib_rule::build_members (x.root_scope ()).a
- ? otype::a
- : otype::s;
- }
-
- const target_type& tt (li.type == otype::a
- ? libua::static_type
- : libus::static_type);
-
- // Called by the compile rule during execute.
- //
- return x.ctx.phase == run_phase::match && !exist
- ? &search (x, tt, x.dir, x.out, x.name)
- : search_existing (x.ctx, tt, x.dir, x.out, x.name);
- }
- else
- {
- assert (!exist);
-
- const lib& l (x.as<lib> ());
-
- // Make sure group members are resolved.
- //
- group_view gv (resolve_members (a, l));
- assert (gv.members != nullptr);
-
- lorder lo (li.order);
-
- bool ls (true);
- switch (lo)
- {
- case lorder::a:
- case lorder::a_s:
- ls = false; // Fall through.
- case lorder::s:
- case lorder::s_a:
- {
- if (ls ? l.s == nullptr : l.a == nullptr)
- {
- if (lo == lorder::a_s || lo == lorder::s_a)
- ls = !ls;
- else
- fail << (ls ? "shared" : "static") << " variant of " << l
- << " is not available";
- }
- }
- }
-
- return ls ? static_cast<const target*> (l.s) : l.a;
- }
- }
}
}
diff --git a/libbuild2/cc/utility.hxx b/libbuild2/cc/utility.hxx
index 5aef14c..458aa25 100644
--- a/libbuild2/cc/utility.hxx
+++ b/libbuild2/cc/utility.hxx
@@ -9,7 +9,9 @@
#include <libbuild2/utility.hxx>
#include <libbuild2/target.hxx>
+
#include <libbuild2/bin/target.hxx>
+#include <libbuild2/bin/utility.hxx>
#include <libbuild2/cc/types.hxx>
@@ -17,6 +19,11 @@ namespace build2
{
namespace cc
{
+ using bin::link_type;
+ using bin::link_order;
+ using bin::link_info;
+ using bin::link_member;
+
// To form the complete path do:
//
// root.out_path () / root.root_extra->build_dir / X_dir
@@ -25,45 +32,13 @@ namespace build2
extern const dir_path module_build_dir; // cc/build/
extern const dir_path module_build_modules_dir; // cc/build/modules/
- // Compile output type.
+ // Compile output type from source target.
//
otype
compile_type (const target&, unit_type);
compile_target_types
compile_types (otype);
-
- // Link output type.
- //
- ltype
- link_type (const target&);
-
- // Library link order.
- //
- // The reason we pass scope and not the target is because this function is
- // called not only for exe/lib but also for obj as part of the library
- // metadata protocol implementation. Normally the bin.*.lib values will be
- // project-wide. With this scheme they can be customized on the per-
- // directory basis but not per-target which means all exe/lib in the same
- // directory have to have the same link order.
- //
- lorder
- link_order (const scope& base, otype);
-
- inline linfo
- link_info (const scope& base, otype ot)
- {
- return linfo {ot, link_order (base, ot)};
- }
-
- // Given the link order return the library member to link. That is, liba{}
- // or libs{} for lib{} and libua{} or libus{} for libul{}.
- //
- // If existing is true, then only return the member target if it exists
- // (currently only used and supported for utility libraries).
- //
- const target*
- link_member (const bin::libx&, action, linfo, bool existing = false);
}
}
diff --git a/libbuild2/cc/utility.ixx b/libbuild2/cc/utility.ixx
index d69b898..0b94780 100644
--- a/libbuild2/cc/utility.ixx
+++ b/libbuild2/cc/utility.ixx
@@ -23,21 +23,6 @@ namespace build2
otype::s;
}
- inline ltype
- link_type (const target& t)
- {
- using namespace bin;
-
- bool u (false);
- otype o (
- t.is_a<exe> () || (u = t.is_a<libue> ()) ? otype::e :
- t.is_a<liba> () || (u = t.is_a<libua> ()) ? otype::a :
- t.is_a<libs> () || (u = t.is_a<libus> ()) ? otype::s :
- static_cast<otype> (0xFF));
-
- return ltype {o, u};
- }
-
inline compile_target_types
compile_types (otype t)
{