aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build2/bin/module.cxx51
-rw-r--r--build2/bin/rule.cxx61
-rw-r--r--build2/bin/target19
-rw-r--r--build2/bin/target.cxx105
-rw-r--r--build2/buildfile1
-rw-r--r--build2/cxx/common60
-rw-r--r--build2/cxx/common.cxx70
-rw-r--r--build2/cxx/compile.cxx80
-rw-r--r--build2/cxx/install.cxx14
-rw-r--r--build2/cxx/link20
-rw-r--r--build2/cxx/link.cxx226
-rw-r--r--build2/cxx/module.cxx30
-rw-r--r--build2/cxx/utility.cxx4
-rw-r--r--build2/cxx/windows-rpath.cxx4
-rw-r--r--build2/target2
15 files changed, 463 insertions, 284 deletions
diff --git a/build2/bin/module.cxx b/build2/bin/module.cxx
index 306d8de..334384a 100644
--- a/build2/bin/module.cxx
+++ b/build2/bin/module.cxx
@@ -31,7 +31,7 @@ namespace build2
//
static const strings exe_lib {"shared", "static"};
static const strings liba_lib {"static"};
- static const strings libso_lib {"shared"};
+ static const strings libs_lib {"shared"};
// Apply the specified stem to the config.bin.pattern. If there is no
// pattern, then return the stem itself. Assume the pattern is valid,
@@ -73,22 +73,22 @@ namespace build2
// Note: some overridable, some not.
//
- v.insert<string> ("config.bin.target", true);
- v.insert<string> ("config.bin.pattern", true);
+ v.insert<string> ("config.bin.target", true);
+ v.insert<string> ("config.bin.pattern", true);
- v.insert<path> ("config.bin.ar", true);
- v.insert<path> ("config.bin.ranlib", true);
+ v.insert<path> ("config.bin.ar", true);
+ v.insert<path> ("config.bin.ranlib", true);
- v.insert<string> ("config.bin.lib", true);
- v.insert<strings> ("config.bin.exe.lib", true);
- v.insert<strings> ("config.bin.liba.lib", true);
- v.insert<strings> ("config.bin.libso.lib", true);
- v.insert<dir_paths> ("config.bin.rpath", true);
+ v.insert<string> ("config.bin.lib", true);
+ v.insert<strings> ("config.bin.exe.lib", true);
+ v.insert<strings> ("config.bin.liba.lib", true);
+ v.insert<strings> ("config.bin.libs.lib", true);
+ v.insert<dir_paths> ("config.bin.rpath", true);
v.insert<string> ("bin.lib");
v.insert<strings> ("bin.exe.lib");
v.insert<strings> ("bin.liba.lib");
- v.insert<strings> ("bin.libso.lib");
+ v.insert<strings> ("bin.libs.lib");
v.insert<dir_paths> ("bin.rpath");
v.insert<string> ("bin.libprefix", true);
@@ -133,12 +133,12 @@ namespace build2
v = required (r, "config.bin.liba.lib", liba_lib).first;
}
- // config.bin.libso.lib
+ // config.bin.libs.lib
//
{
- value& v (b.assign ("bin.libso.lib"));
+ value& v (b.assign ("bin.libs.lib"));
if (!v)
- v = required (r, "config.bin.libso.lib", libso_lib).first;
+ v = required (r, "config.bin.libs.lib", libs_lib).first;
}
// config.bin.rpath
@@ -353,13 +353,14 @@ namespace build2
{
auto& t (b.target_types);
- t.insert<obja> ();
- t.insert<objso> ();
- t.insert<obj> ();
- t.insert<exe> ();
- t.insert<liba> ();
- t.insert<libso> ();
- t.insert<lib> ();
+ t.insert<obje> ();
+ t.insert<obja> ();
+ t.insert<objs> ();
+ t.insert<obj> ();
+ t.insert<exe> ();
+ t.insert<liba> ();
+ t.insert<libs> ();
+ t.insert<lib> ();
}
// Register rules.
@@ -407,15 +408,15 @@ namespace build2
// And a library that wants to override any such overrides (e.g.,
// because it does have main()) can do:
//
- // libso{foo}: install.mode=755
+ // libs{foo}: install.mode=755
//
// Everyone is happy then? Not Windows users. When targeting Windows
- // libso{} is an import library and shouldn't be exec.
+ // libs{} is an import library and shouldn't be exec.
//
- install_path<libso> (b, dir_path ("lib")); // Install into install.lib.
+ install_path<libs> (b, dir_path ("lib")); // Install into install.lib.
if (tclass == "windows")
- install_mode<libso> (b, "644");
+ install_mode<libs> (b, "644");
install_path<liba> (b, dir_path ("lib")); // Install into install.lib.
install_mode<liba> (b, "644");
diff --git a/build2/bin/rule.cxx b/build2/bin/rule.cxx
index 072e931..7710a53 100644
--- a/build2/bin/rule.cxx
+++ b/build2/bin/rule.cxx
@@ -23,7 +23,7 @@ namespace build2
match (action a, target& t, const string&) const
{
fail << diag_doing (a, t) << " target group" <<
- info << "explicitly select either obja{} or objso{} member";
+ info << "explicitly select obje{}, obja{}, or objs{} member";
return nullptr;
}
@@ -33,25 +33,25 @@ namespace build2
// lib
//
- // The whole logic is pretty much as if we had our two group
- // members as our prerequisites.
+ // The whole logic is pretty much as if we had our two group members as
+ // our prerequisites.
//
match_result lib_rule::
- match (action a, target& xt, const string&) const
+ match (action act, target& xt, const string&) const
{
lib& t (static_cast<lib&> (xt));
// @@ We have to re-query it on each match_only()!
// Get the library type to build. If not set for a target, this
- // should be configured at the project scope by init_lib().
+ // should be configured at the project scope by init().
//
const string& type (cast<string> (t["bin.lib"]));
- bool ar (type == "static" || type == "both");
- bool so (type == "shared" || type == "both");
+ bool a (type == "static" || type == "both");
+ bool s (type == "shared" || type == "both");
- if (!ar && !so)
+ if (!a && !s)
fail << "unknown library type: " << type <<
info << "'static', 'shared', or 'both' expected";
@@ -63,20 +63,20 @@ namespace build2
// meta-information about the library, such as the options to use
// when linking it, etc.
//
- if (ar)
+ if (a)
{
if (t.a == nullptr)
t.a = &search<liba> (t.dir, t.out, t.name, nullptr, nullptr);
- match_only (a, *t.a);
+ match_only (act, *t.a);
}
- if (so)
+ if (s)
{
- if (t.so == nullptr)
- t.so = &search<libso> (t.dir, t.out, t.name, nullptr, nullptr);
+ if (t.s == nullptr)
+ t.s = &search<libs> (t.dir, t.out, t.name, nullptr, nullptr);
- match_only (a, *t.so);
+ match_only (act, *t.s);
}
match_result mr (t, &type);
@@ -84,35 +84,35 @@ namespace build2
// If there is an outer operation, indicate that we match
// unconditionally so that we don't override ourselves.
//
- if (a.outer_operation () != 0)
- mr.recipe_action = action (a.meta_operation (), a.operation ());
+ if (act.outer_operation () != 0)
+ mr.recipe_action = action (act.meta_operation (), act.operation ());
return mr;
}
recipe lib_rule::
- apply (action a, target& xt, const match_result& mr) const
+ apply (action act, target& xt, const match_result& mr) const
{
lib& t (static_cast<lib&> (xt));
const string& type (*static_cast<const string*> (mr.cpvalue));
- bool ar (type == "static" || type == "both");
- bool so (type == "shared" || type == "both");
+ bool a (type == "static" || type == "both");
+ bool s (type == "shared" || type == "both");
// Now we do full match.
//
- if (ar)
- build2::match (a, *t.a);
+ if (a)
+ build2::match (act, *t.a);
- if (so)
- build2::match (a, *t.so);
+ if (s)
+ build2::match (act, *t.s);
return &perform;
}
target_state lib_rule::
- perform (action a, target& xt)
+ perform (action act, target& xt)
{
lib& t (static_cast<lib&> (xt));
@@ -122,11 +122,12 @@ namespace build2
//
//
const string& type (cast<string> (t["bin.lib"]));
- bool ar (type == "static" || type == "both");
- bool so (type == "shared" || type == "both");
- target* m1 (ar ? t.a : nullptr);
- target* m2 (so ? t.so : nullptr);
+ bool a (type == "static" || type == "both");
+ bool s (type == "shared" || type == "both");
+
+ target* m1 (a ? t.a : nullptr);
+ target* m2 (s ? t.s : nullptr);
if (current_mode == execution_mode::last)
swap (m1, m2);
@@ -134,10 +135,10 @@ namespace build2
target_state r (target_state::unchanged);
if (m1 != nullptr)
- r |= execute (a, *m1);
+ r |= execute (act, *m1);
if (m2 != nullptr)
- r |= execute (a, *m2);
+ r |= execute (act, *m2);
return r;
}
diff --git a/build2/bin/target b/build2/bin/target
index f386592..8c32e84 100644
--- a/build2/bin/target
+++ b/build2/bin/target
@@ -16,6 +16,16 @@ namespace build2
{
// The obj{} target group.
//
+ class obje: public file
+ {
+ public:
+ using file::file;
+
+ public:
+ static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
+ };
+
class obja: public file
{
public:
@@ -26,7 +36,7 @@ namespace build2
virtual const target_type& dynamic_type () const {return static_type;}
};
- class objso: public file
+ class objs: public file
{
public:
using file::file;
@@ -41,8 +51,9 @@ namespace build2
public:
using target::target;
+ obje* e {nullptr};
obja* a {nullptr};
- objso* so {nullptr};
+ objs* s {nullptr};
public:
static const target_type static_type;
@@ -71,7 +82,7 @@ namespace build2
virtual const target_type& dynamic_type () const {return static_type;}
};
- class libso: public file
+ class libs: public file
{
public:
using file::file;
@@ -87,7 +98,7 @@ namespace build2
using target::target;
liba* a {nullptr};
- libso* so {nullptr};
+ libs* s {nullptr};
virtual void
reset (action_type);
diff --git a/build2/bin/target.cxx b/build2/bin/target.cxx
index f141d97..3f16467 100644
--- a/build2/bin/target.cxx
+++ b/build2/bin/target.cxx
@@ -13,14 +13,41 @@ namespace build2
extern const char ext_var[] = "extension"; // VC 19 rejects constexpr.
static target*
+ obje_factory (const target_type&,
+ dir_path dir,
+ dir_path out,
+ string n,
+ const string* ext)
+ {
+ obj* o (targets.find<obj> (dir, out, n));
+ obje* e (new obje (move (dir), move (out), move (n), ext));
+
+ if ((e->group = o))
+ o->e = e;
+
+ return e;
+ }
+
+ const target_type obje::static_type
+ {
+ "obje",
+ &file::static_type,
+ &obje_factory,
+ &target_extension_var<ext_var, nullptr>,
+ nullptr,
+ &search_target, // Note: not _file(); don't look for an existing file.
+ false
+ };
+
+ static target*
obja_factory (const target_type&,
dir_path dir,
dir_path out,
string n,
- const string* e)
+ const string* ext)
{
obj* o (targets.find<obj> (dir, out, n));
- obja* a (new obja (move (dir), move (out), move (n), e));
+ obja* a (new obja (move (dir), move (out), move (n), ext));
if ((a->group = o))
o->a = a;
@@ -40,26 +67,26 @@ namespace build2
};
static target*
- objso_factory (const target_type&,
+ objs_factory (const target_type&,
dir_path dir,
dir_path out,
string n,
- const string* e)
+ const string* ext)
{
obj* o (targets.find<obj> (dir, out, n));
- objso* so (new objso (move (dir), move (out), move (n), e));
+ objs* s (new objs (move (dir), move (out), move (n), ext));
- if ((so->group = o))
- o->so = so;
+ if ((s->group = o))
+ o->s = s;
- return so;
+ return s;
}
- const target_type objso::static_type
+ const target_type objs::static_type
{
- "objso",
+ "objs",
&file::static_type,
- &objso_factory,
+ &objs_factory,
&target_extension_var<ext_var, nullptr>,
nullptr,
&search_target, // Note: not _file(); don't look for an existing file.
@@ -71,17 +98,22 @@ namespace build2
dir_path dir,
dir_path out,
string n,
- const string* e)
+ const string* ext)
{
+ obje* e (targets.find<obje> (dir, out, n));
obja* a (targets.find<obja> (dir, out, n));
- objso* so (targets.find<objso> (dir, out, n));
- obj* o (new obj (move (dir), move (out), move (n), e));
+ objs* s (targets.find<objs> (dir, out, n));
+
+ obj* o (new obj (move (dir), move (out), move (n), ext));
+
+ if ((o->e = e))
+ e->group = o;
if ((o->a = a))
a->group = o;
- if ((o->so = so))
- so->group = o;
+ if ((o->s = s))
+ s->group = o;
return o;
}
@@ -124,12 +156,12 @@ namespace build2
dir_path d,
dir_path o,
string n,
- const string* e)
+ const string* ext)
{
// Only link-up to the group if the types match exactly.
//
lib* l (t == liba::static_type ? targets.find<lib> (d, o, n) : nullptr);
- liba* a (new liba (move (d), move (o), move (n), e));
+ liba* a (new liba (move (d), move (o), move (n), ext));
if ((a->group = l))
l->a = a;
@@ -161,28 +193,28 @@ namespace build2
};
static target*
- libso_factory (const target_type& t,
- dir_path d,
- dir_path o,
- string n,
- const string* e)
+ libs_factory (const target_type& t,
+ dir_path d,
+ dir_path o,
+ string n,
+ const string* ext)
{
// Only link-up to the group if the types match exactly.
//
- lib* l (t == libso::static_type ? targets.find<lib> (d, o, n) : nullptr);
- libso* so (new libso (move (d), move (o), move (n), e));
+ lib* l (t == libs::static_type ? targets.find<lib> (d, o, n) : nullptr);
+ libs* s (new libs (move (d), move (o), move (n), ext));
- if ((so->group = l))
- l->so = so;
+ if ((s->group = l))
+ l->s = s;
- return so;
+ return s;
}
- const target_type libso::static_type
+ const target_type libs::static_type
{
- "libso",
+ "libs",
&file::static_type,
- &libso_factory,
+ &libs_factory,
&target_extension_var<ext_var, nullptr>,
nullptr,
&search_file,
@@ -203,17 +235,18 @@ namespace build2
dir_path d,
dir_path o,
string n,
- const string* e)
+ const string* ext)
{
liba* a (targets.find<liba> (d, o, n));
- libso* so (targets.find<libso> (d, o, n));
- lib* l (new lib (move (d), move (o), move (n), e));
+ libs* s (targets.find<libs> (d, o, n));
+
+ lib* l (new lib (move (d), move (o), move (n), ext));
if ((l->a = a))
a->group = l;
- if ((l->so = so))
- so->group = l;
+ if ((l->s = s))
+ s->group = l;
return l;
}
diff --git a/build2/buildfile b/build2/buildfile
index 5474fbd..cbd09e8 100644
--- a/build2/buildfile
+++ b/build2/buildfile
@@ -44,6 +44,7 @@ exe{b}: \
config/{hxx cxx}{ module } \
config/{hxx cxx}{ operation } \
config/{hxx txx cxx}{ utility } \
+ cxx/{hxx cxx}{ common } \
cxx/{hxx cxx}{ compile } \
cxx/{hxx cxx}{ guess } \
cxx/{hxx cxx}{ install } \
diff --git a/build2/cxx/common b/build2/cxx/common
new file mode 100644
index 0000000..77f1149
--- /dev/null
+++ b/build2/cxx/common
@@ -0,0 +1,60 @@
+// file : build2/cxx/common -*- C++ -*-
+// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BUILD2_CXX_COMMON
+#define BUILD2_CXX_COMMON
+
+#include <build2/types>
+#include <build2/utility>
+
+#include <build2/bin/target>
+
+namespace build2
+{
+ namespace cxx
+ {
+ // Compile/link output type (executable, static, or shared).
+ //
+ enum class otype {e, a, s};
+
+ inline otype
+ compile_type (target& t)
+ {
+ return
+ t.is_a<bin::obje> () ? otype::e :
+ t.is_a<bin::obja> () ? otype::a :
+ otype::s;
+ }
+
+ inline otype
+ link_type (target& t)
+ {
+ return
+ t.is_a<bin::exe> () ? otype::e :
+ t.is_a<bin::liba> () ? otype::a :
+ otype::s;
+ }
+
+ // Library link order.
+ //
+ enum class lorder {a, s, a_s, s_a};
+
+ // 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
+ // meta-information 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 (scope& base, otype);
+
+ // Given the link order return the library member (liba or libs) to link.
+ //
+ target&
+ link_member (bin::lib&, lorder);
+ }
+}
+
+#endif // BUILD2_CXX_COMMON
diff --git a/build2/cxx/common.cxx b/build2/cxx/common.cxx
new file mode 100644
index 0000000..0b66eb5
--- /dev/null
+++ b/build2/cxx/common.cxx
@@ -0,0 +1,70 @@
+// file : build2/cxx/common.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <build2/cxx/common>
+
+#include <build2/variable>
+#include <build2/algorithm>
+
+using namespace std;
+
+namespace build2
+{
+ namespace cxx
+ {
+ using namespace bin;
+
+ lorder
+ link_order (scope& bs, otype ot)
+ {
+ const char* var;
+
+ 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;
+ }
+
+ target&
+ link_member (bin::lib& l, lorder lo)
+ {
+ bool ls (true);
+ const string& at (cast<string> (l["bin.lib"])); // Available members.
+
+ switch (lo)
+ {
+ case lorder::a:
+ case lorder::a_s:
+ ls = false; // Fall through.
+ case lorder::s:
+ case lorder::s_a:
+ {
+ if (ls ? at == "static" : at == "shared")
+ {
+ if (lo == lorder::a_s || lo == lorder::s_a)
+ ls = !ls;
+ else
+ fail << (ls ? "shared" : "static") << " variant of " << l
+ << " is not available";
+ }
+ }
+ }
+
+ target* r (ls ? static_cast<target*> (l.s) : l.a);
+
+ if (r == nullptr)
+ r = &search (ls ? libs::static_type : liba::static_type,
+ prerequisite_key {nullptr, l.key (), nullptr});
+
+ return *r;
+ }
+ }
+}
diff --git a/build2/cxx/compile.cxx b/build2/cxx/compile.cxx
index 504df7f..645e818 100644
--- a/build2/cxx/compile.cxx
+++ b/build2/cxx/compile.cxx
@@ -21,6 +21,7 @@
#include <build2/cxx/target>
#include <build2/cxx/link>
+#include <build2/cxx/common>
#include <build2/cxx/utility>
@@ -69,15 +70,57 @@ namespace build2
path_target& t (static_cast<path_target&> (xt));
scope& rs (t.root_scope ());
+
const string& cid (cast<string> (rs["cxx.id"]));
+ const string& tsys (cast<string> (rs["cxx.target.system"]));
const string& tclass (cast<string> (rs["cxx.target.class"]));
+ otype ct (compile_type (t));
+
// Derive file name from target name.
//
if (t.path ().empty ())
{
- const char* ext (cid == "msvc" ? "obj" : "o");
- t.derive_path (ext, nullptr, (t.is_a<objso> () ? "-so" : nullptr));
+ const char* e (nullptr);
+
+ if (tsys == "win32-msvc")
+ {
+ switch (ct)
+ {
+ case otype::e: e = "exe.obj"; break;
+ case otype::a: e = "lib.obj"; break;
+ case otype::s: e = "dll.obj"; break;
+ }
+ }
+ else if (tsys == "mingw32")
+ {
+ switch (ct)
+ {
+ case otype::e: e = "exe.o"; break;
+ case otype::a: e = "a.o"; break;
+ case otype::s: e = "dll.o"; break;
+ }
+ }
+ else if (tsys == "darwin")
+ {
+ switch (ct)
+ {
+ case otype::e: e = "o"; break;
+ case otype::a: e = "a.o"; break;
+ case otype::s: e = "dylib.o"; break;
+ }
+ }
+ else
+ {
+ switch (ct)
+ {
+ case otype::e: e = "o"; break;
+ case otype::a: e = "a.o"; break;
+ case otype::s: e = "so.o"; break;
+ }
+ }
+
+ t.derive_path (e);
}
// Inject dependency on the output directory.
@@ -102,7 +145,7 @@ namespace build2
// meta-information protocol". See also append_lib_options()
// above.
//
- if (p.is_a<lib> () || p.is_a<liba> () || p.is_a<libso> ())
+ if (p.is_a<lib> () || p.is_a<liba> () || p.is_a<libs> ())
{
if (a.operation () == update_id)
{
@@ -184,7 +227,7 @@ namespace build2
{
target& pt (*p.target); // Already searched and matched.
- if (pt.is_a<lib> () || pt.is_a<liba> () || pt.is_a<libso> ())
+ if (pt.is_a<lib> () || pt.is_a<liba> () || pt.is_a<libs> ())
hash_lib_options (cs, pt, "cxx.export.poptions");
}
@@ -192,7 +235,7 @@ namespace build2
hash_options (cs, t, "cxx.coptions");
hash_std (cs, rs, cid, t);
- if (t.is_a<objso> ())
+ if (ct == otype::s)
{
// On Darwin, Win32 -fPIC is the default.
//
@@ -369,7 +412,7 @@ namespace build2
if (t == nullptr)
continue;
- if (t->is_a<lib> () || t->is_a<liba> () || t->is_a<libso> ())
+ if (t->is_a<lib> () || t->is_a<liba> () || t->is_a<libs> ())
append_lib_prefixes (m, *t);
}
@@ -389,7 +432,7 @@ namespace build2
{
target& pt (*p.target); // Already searched and matched.
- if (pt.is_a<lib> () || pt.is_a<liba> () || pt.is_a<libso> ())
+ if (pt.is_a<lib> () || pt.is_a<liba> () || pt.is_a<libs> ())
append_lib_prefixes (m, pt);
}
@@ -617,7 +660,7 @@ namespace build2
{
target& pt (*p.target); // Already searched and matched.
- if (pt.is_a<lib> () || pt.is_a<liba> () || pt.is_a<libso> ())
+ if (pt.is_a<lib> () || pt.is_a<liba> () || pt.is_a<libs> ())
append_lib_options (args, pt, "cxx.export.poptions");
}
@@ -628,7 +671,7 @@ namespace build2
append_options (args, t, "cxx.coptions");
append_std (args, rs, cid, t, cxx_std);
- if (t.is_a<objso> ())
+ if (t.is_a<objs> ())
{
// On Darwin, Win32 -fPIC is the default.
//
@@ -1181,19 +1224,22 @@ namespace build2
if (s == nullptr)
return target_state::unchanged;
- // Translate paths to relative (to working directory) ones. This
- // results in easier to read diagnostics.
- //
- path relo (relative (t.path ()));
- path rels (relative (s->path ()));
-
scope& rs (t.root_scope ());
+
const path& cxx (cast<path> (rs["config.cxx"]));
const string& cid (cast<string> (rs["cxx.id"]));
const string& tclass (cast<string> (rs["cxx.target.class"]));
+ otype ct (compile_type (t));
+
cstrings args {cxx.string ().c_str ()};
+ // Translate paths to relative (to working directory) ones. This
+ // results in easier to read diagnostics.
+ //
+ path relo (relative (t.path ()));
+ path rels (relative (s->path ()));
+
// Add cxx.export.poptions from prerequisite libraries. Note that
// here we don't need to see group members (see apply()).
//
@@ -1201,7 +1247,7 @@ namespace build2
{
target& pt (*p.target); // Already searched and matched.
- if (pt.is_a<lib> () || pt.is_a<liba> () || pt.is_a<libso> ())
+ if (pt.is_a<lib> () || pt.is_a<liba> () || pt.is_a<libs> ())
append_lib_options (args, pt, "cxx.export.poptions");
}
@@ -1268,7 +1314,7 @@ namespace build2
}
else
{
- if (t.is_a<objso> ())
+ if (ct == otype::s)
{
// On Darwin, Win32 -fPIC is the default.
//
diff --git a/build2/cxx/install.cxx b/build2/cxx/install.cxx
index f6f502a..e07d115 100644
--- a/build2/cxx/install.cxx
+++ b/build2/cxx/install.cxx
@@ -6,8 +6,9 @@
#include <build2/bin/target>
-#include <build2/cxx/target>
#include <build2/cxx/link>
+#include <build2/cxx/common>
+#include <build2/cxx/target>
using namespace std;
@@ -31,17 +32,20 @@ namespace build2
// If this is a shared library prerequisite, install it as long as it
// is in the same amalgamation as we are.
//
- if ((t.is_a<exe> () || t.is_a<libso> ()) &&
- (p.is_a<lib> () || p.is_a<libso> ()))
+ // @@ Shouldn't we also install a static library prerequisite of a
+ // static library?
+ //
+ if ((t.is_a<exe> () || t.is_a<libs> ()) &&
+ (p.is_a<lib> () || p.is_a<libs> ()))
{
target* pt (&p.search ());
// If this is the lib{} group, pick a member which we would link.
//
if (lib* l = pt->is_a<lib> ())
- pt = &link::link_member (*l, link::link_order (t));
+ pt = &link_member (*l, link_order (t.base_scope (), link_type (t)));
- if (pt->is_a<libso> ()) // Can be liba{}.
+ if (pt->is_a<libs> ()) // Can be liba{}.
return pt->in (t.weak_scope ()) ? pt : nullptr;
}
diff --git a/build2/cxx/link b/build2/cxx/link
index ca45e17..4f00ea0 100644
--- a/build2/cxx/link
+++ b/build2/cxx/link
@@ -33,26 +33,6 @@ namespace build2
static link instance;
- public:
- enum class type {e, a, so};
- enum class order {a, so, a_so, so_a};
-
- static type
- link_type (target& t)
- {
- return t.is_a<bin::exe> ()
- ? type::e
- : (t.is_a<bin::liba> () ? type::a : type::so);
- }
-
- static order
- link_order (target&);
-
- // Determine the library member (liba or libso) to link.
- //
- static target&
- link_member (bin::lib&, order);
-
private:
friend class compile;
diff --git a/build2/cxx/link.cxx b/build2/cxx/link.cxx
index 181c2b8..002cd42 100644
--- a/build2/cxx/link.cxx
+++ b/build2/cxx/link.cxx
@@ -19,6 +19,7 @@
#include <build2/bin/target>
#include <build2/cxx/target>
+#include <build2/cxx/common>
#include <build2/cxx/utility>
using namespace std;
@@ -30,58 +31,6 @@ namespace build2
{
using namespace bin;
- link::order link::
- link_order (target& t)
- {
- const char* var;
-
- switch (link_type (t))
- {
- case type::e: var = "bin.exe.lib"; break;
- case type::a: var = "bin.liba.lib"; break;
- case type::so: var = "bin.libso.lib"; break;
- }
-
- const auto& v (cast<strings> (t[var]));
- return v[0] == "shared"
- ? v.size () > 1 && v[1] == "static" ? order::so_a : order::so
- : v.size () > 1 && v[1] == "shared" ? order::a_so : order::a;
- }
-
- target& link::
- link_member (bin::lib& l, order lo)
- {
- bool lso (true);
- const string& at (cast<string> (l["bin.lib"])); // Available types.
-
- switch (lo)
- {
- case order::a:
- case order::a_so:
- lso = false; // Fall through.
- case order::so:
- case order::so_a:
- {
- if (lso ? at == "static" : at == "shared")
- {
- if (lo == order::a_so || lo == order::so_a)
- lso = !lso;
- else
- fail << (lso ? "shared" : "static") << " build of " << l
- << " is not available";
- }
- }
- }
-
- target* r (lso ? static_cast<target*> (l.so) : l.a);
-
- if (r == nullptr)
- r = &search (lso ? libso::static_type : liba::static_type,
- prerequisite_key {nullptr, l.key (), nullptr});
-
- return *r;
- }
-
// Extract system library search paths from GCC or compatible (Clang,
// Intel C++) using the -print-search-dirs option.
//
@@ -261,7 +210,7 @@ namespace build2
const string& tsys (cast<string> (rs["cxx.target.system"]));
bool l (p.is_a<lib> ());
- const string* ext (l ? nullptr : p.ext); // Only for liba/libso.
+ const string* ext (l ? nullptr : p.ext); // Only for liba/libs.
// Then figure out what we need to search for.
//
@@ -302,12 +251,12 @@ namespace build2
}
}
- // libso
+ // libs
//
path sn;
const string* se (nullptr);
- if (l || p.is_a<libso> ())
+ if (l || p.is_a<libs> ())
{
const char* e ("");
@@ -358,7 +307,7 @@ namespace build2
spc = extract_library_paths (p.scope);
liba* a (nullptr);
- libso* s (nullptr);
+ libs* s (nullptr);
path f; // Reuse the buffer.
const dir_path* pd;
@@ -390,7 +339,7 @@ namespace build2
}
}
- // libso
+ // libs
//
if (!sn.empty ())
{
@@ -403,7 +352,7 @@ namespace build2
// Above we searched for the import library (.dll.a) but if it's
// not found, then we also search for the .dll (unless the
// extension was specified explicitly) since we can link to it
- // directly. Note also that the resulting libso{} would end up
+ // directly. Note also that the resulting libs{} would end up
// being the .dll.
//
if (mt == timestamp_nonexistent && ext == nullptr)
@@ -416,7 +365,7 @@ namespace build2
if (mt != timestamp_nonexistent)
{
- s = &targets.insert<libso> (d, dir_path (), p.name, se, trace);
+ s = &targets.insert<libs> (d, dir_path (), p.name, se, trace);
if (s->path ().empty ())
s->path (move (f));
@@ -444,7 +393,7 @@ namespace build2
// It should automatically link-up to the members we have found.
//
assert (l.a == a);
- assert (l.so == s);
+ assert (l.s == s);
// Set the bin.lib variable to indicate what's available.
//
@@ -474,11 +423,11 @@ namespace build2
//
// - if there is no .o, are we going to check if the one derived
// from target exist or can be built? A: No.
- // What if there is a library. Probably ok if .a, not if .so.
+ // What if there is a library. Probably ok if static, not if shared,
// (i.e., a utility library).
//
- type lt (link_type (t));
+ otype lt (link_type (t));
// Scan prerequisites and see if we can work with what we've got.
//
@@ -495,22 +444,34 @@ namespace build2
{
seen_c = seen_c || true;
}
+ else if (p.is_a<obj> ())
+ {
+ seen_obj = seen_obj || true;
+ }
+ else if (p.is_a<obje> ())
+ {
+ if (lt != otype::e)
+ fail << "obje{} as prerequisite of " << t;
+
+ seen_obj = seen_obj || true;
+ }
else if (p.is_a<obja> ())
{
- if (lt == type::so)
- fail << "shared library " << t << " prerequisite " << p
- << " is static object";
+ if (lt != otype::a)
+ fail << "obja{} as prerequisite of " << t;
seen_obj = seen_obj || true;
}
- else if (p.is_a<objso> () ||
- p.is_a<obj> ())
+ else if (p.is_a<objs> ())
{
+ if (lt != otype::s)
+ fail << "objs{} as prerequisite of " << t;
+
seen_obj = seen_obj || true;
}
- else if (p.is_a<liba> () ||
- p.is_a<libso> () ||
- p.is_a<lib> ())
+ else if (p.is_a<lib> () ||
+ p.is_a<liba> () ||
+ p.is_a<libs> ())
{
seen_lib = seen_lib || true;
}
@@ -530,7 +491,7 @@ namespace build2
// "library meta-information protocol". Don't do this if we are
// called from the install rule just to check if we would match.
//
- if (seen_lib && lt != type::e &&
+ if (seen_lib && lt != otype::e &&
a.operation () != install_id && a.outer_operation () != install_id)
{
if (t.group != nullptr)
@@ -540,7 +501,7 @@ namespace build2
for (prerequisite_member p: group_prerequisite_members (a, t))
{
- if (p.is_a<lib> () || p.is_a<liba> () || p.is_a<libso> ())
+ if (p.is_a<lib> () || p.is_a<liba> () || p.is_a<libs> ())
{
target* pt (nullptr);
@@ -583,9 +544,8 @@ namespace build2
const string& tsys (cast<string> (rs["cxx.target.system"]));
const string& tclass (cast<string> (rs["cxx.target.class"]));
- type lt (link_type (t));
- order lo (link_order (t));
- bool so (lt == type::so);
+ otype lt (link_type (t));
+ lorder lo (link_order (bs, lt));
// Derive file name from target name.
//
@@ -596,7 +556,7 @@ namespace build2
switch (lt)
{
- case type::e:
+ case otype::e:
{
if (tclass == "windows")
e = "exe";
@@ -605,7 +565,7 @@ namespace build2
break;
}
- case type::a:
+ case otype::a:
{
// To be anally precise, let's use the ar id to decide how to name
// the library in case, for example, someone wants to archive
@@ -626,7 +586,7 @@ namespace build2
break;
}
- case type::so:
+ case otype::s:
{
//@@ VC: DLL name.
@@ -637,9 +597,9 @@ namespace build2
}
else if (tclass == "windows")
{
- // On Windows libso{} is an ad hoc group. The libso{} itself is
+ // On Windows libs{} is an ad hoc group. The libs{} itself is
// the import library and we add dll{} as a member (see below).
- // While at first it may seem strange that libso{} is the import
+ // While at first it may seem strange that libs{} is the import
// library and not the DLL, if you meditate on it, you will see
// it makes a lot of sense: our main task here is building and
// for that we need the import library, not the DLL.
@@ -697,7 +657,7 @@ namespace build2
{
// DLL
//
- if (so)
+ if (lt == otype::s)
{
file& dll (add_adhoc (t, "dll"));
@@ -707,7 +667,7 @@ namespace build2
// PDB
//
- if (lt != type::a &&
+ if (lt != otype::a &&
cid == "msvc" &&
find_option ("/DEBUG", t, "cxx.loptions", true))
{
@@ -734,6 +694,10 @@ namespace build2
// When cleaning, ignore prerequisites that are not in the same
// or a subdirectory of our project root.
//
+ const target_type& ott (lt == otype::e ? obje::static_type :
+ lt == otype::a ? obja::static_type :
+ objs::static_type);
+
for (prerequisite_member p: group_prerequisite_members (a, t))
{
target* pt (nullptr);
@@ -758,11 +722,15 @@ namespace build2
//
if (obj* o = pt->is_a<obj> ())
{
- pt = so ? static_cast<target*> (o->so) : o->a;
+ switch (lt)
+ {
+ case otype::e: pt = o->e; break;
+ case otype::a: pt = o->a; break;
+ case otype::s: pt = o->s; break;
+ }
if (pt == nullptr)
- pt = &search (so ? objso::static_type : obja::static_type,
- p.key ());
+ pt = &search (ott, p.key ());
}
else if (lib* l = pt->is_a<lib> ())
{
@@ -785,10 +753,7 @@ namespace build2
bool group (!p.prerequisite.belongs (t)); // Group's prerequisite.
const prerequisite_key& cp (p.key ()); // c(xx){} prerequisite key.
- const target_type& otype (
- group
- ? obj::static_type
- : (so ? objso::static_type : obja::static_type));
+ const target_type& tt (group ? obj::static_type : ott);
// Come up with the obj*{} target. The c(xx){} prerequisite directory
// can be relative (to the scope) or absolute. If it is relative, then
@@ -807,7 +772,7 @@ namespace build2
{
if (!cpd.sub (rs.src_path ()))
fail << "out of project prerequisite " << cp <<
- info << "specify corresponding " << otype.name << "{} "
+ info << "specify corresponding " << tt.name << "{} "
<< "target explicitly";
d = rs.out_path () / cpd.leaf (rs.src_path ());
@@ -817,7 +782,7 @@ namespace build2
// obj*{} is always in the out tree.
//
target& ot (
- search (otype, d, dir_path (), *cp.tk.name, nullptr, cp.scope));
+ search (tt, d, dir_path (), *cp.tk.name, nullptr, cp.scope));
// If we are cleaning, check that this target is in the same or
// a subdirectory of our project root.
@@ -838,11 +803,16 @@ namespace build2
if (group)
{
obj& o (static_cast<obj&> (ot));
- pt = so ? static_cast<target*> (o.so) : o.a;
+
+ switch (lt)
+ {
+ case otype::e: pt = o.e; break;
+ case otype::a: pt = o.a; break;
+ case otype::s: pt = o.s; break;
+ }
if (pt == nullptr)
- pt = &search (so ? objso::static_type : obja::static_type,
- o.dir, o.out, o.name, o.ext, nullptr);
+ pt = &search (ott, o.dir, o.out, o.name, o.ext, nullptr);
}
else
pt = &ot;
@@ -869,9 +839,9 @@ namespace build2
(p.is_a<cxx> () && (p1.is_a<hxx> () ||
p1.is_a<ixx> () ||
p1.is_a<txx> ())) ||
- p1.is_a<lib> () ||
+ p1.is_a<lib> () ||
p1.is_a<liba> () ||
- p1.is_a<libso> ())
+ p1.is_a<libs> ())
{
continue;
}
@@ -893,7 +863,7 @@ namespace build2
<< "be incompatible with existing target " << *pt <<
info << "existing prerequisite " << p1 << " does not match "
<< cp <<
- info << "specify corresponding " << otype.name << "{} target "
+ info << "specify corresponding " << tt.name << "{} target "
<< "explicitly";
found = true;
@@ -918,7 +888,7 @@ namespace build2
//
for (prerequisite& p: group_prerequisites (t))
{
- if (p.is_a<lib> () || p.is_a<liba> () || p.is_a<libso> ())
+ if (p.is_a<lib> () || p.is_a<liba> () || p.is_a<libs> ())
ot.prerequisites.emplace_back (p);
}
@@ -948,7 +918,7 @@ namespace build2
args.push_back (relative (pa->path ()).string ()); // string()&&
append_libraries (args, *pa);
}
- else if (libso* ps = pt->is_a<libso> ())
+ else if (libs* ps = pt->is_a<libs> ())
args.push_back (relative (ps->path ()).string ()); // string()&&
}
}
@@ -963,17 +933,17 @@ namespace build2
cs.append (pa->path ().string ());
hash_libraries (cs, *pa);
}
- else if (libso* ps = pt->is_a<libso> ())
+ else if (libs* ps = pt->is_a<libs> ())
cs.append (ps->path ().string ());
}
}
static void
- append_rpath_link (strings& args, libso& t)
+ append_rpath_link (strings& args, libs& t)
{
for (target* pt: t.prerequisite_targets)
{
- if (libso* ls = pt->is_a<libso> ())
+ if (libs* ls = pt->is_a<libs> ())
{
args.push_back ("-Wl,-rpath-link," +
ls->path ().directory ().string ());
@@ -1002,8 +972,7 @@ namespace build2
file& t (static_cast<file&> (xt));
- type lt (link_type (t));
- bool so (lt == type::so);
+ otype lt (link_type (t));
// Update prerequisites.
//
@@ -1020,7 +989,7 @@ namespace build2
path manifest; // Manifest itself (msvc) or compiled object file.
timestamp rpath_timestamp (timestamp_nonexistent); // DLLs timestamp.
- if (lt == type::e && tclass == "windows")
+ if (lt == otype::e && tclass == "windows")
{
// First determine if we need to add our rpath emulating assembly. The
// assembly itself is generated later, after updating the target. Omit
@@ -1130,7 +1099,7 @@ namespace build2
// Then the linker checksum (ar/ranlib or C++ compiler).
//
- if (lt == type::a)
+ if (lt == otype::a)
{
ranlib = rs["config.bin.ranlib"];
@@ -1195,7 +1164,7 @@ namespace build2
args.push_back (m);
}
- if (lt == type::a)
+ if (lt == otype::a)
{
if (cid == "msvc") ;
else
@@ -1238,7 +1207,7 @@ namespace build2
{
// Set soname.
//
- if (so)
+ if (lt == otype::s)
{
const string& leaf (t.path ().leaf ().string ());
@@ -1277,7 +1246,7 @@ namespace build2
//
for (target* pt: t.prerequisite_targets)
{
- if (libso* ls = pt->is_a<libso> ())
+ if (libs* ls = pt->is_a<libs> ())
{
if (a.outer_operation () != install_id)
{
@@ -1330,11 +1299,12 @@ namespace build2
path_target* ppt;
liba* a (nullptr);
- if ((ppt = pt->is_a<obja> ()) ||
- (ppt = pt->is_a<objso> ()) ||
- (lt != type::a &&
+ if ((ppt = pt->is_a<obje> ()) ||
+ (ppt = pt->is_a<obja> ()) ||
+ (ppt = pt->is_a<objs> ()) ||
+ (lt != otype::a &&
((ppt = a = pt->is_a<liba> ()) ||
- (ppt = pt->is_a<libso> ()))))
+ (ppt = pt->is_a<libs> ()))))
{
cs.append (ppt->path ().string ());
@@ -1353,7 +1323,7 @@ namespace build2
// Treat them as inputs, not options.
//
- if (lt != type::a)
+ if (lt != otype::a)
hash_options (cs, t, "cxx.libs");
if (dd.expect (cs.string ()) != nullptr)
@@ -1387,7 +1357,7 @@ namespace build2
switch (lt)
{
- case type::e:
+ case otype::e:
{
if (cid == "msvc")
{
@@ -1449,7 +1419,7 @@ namespace build2
break;
}
- case type::a:
+ case otype::a:
{
args[0] = cast<path> (rs["config.bin.ar"]).string ().c_str ();
@@ -1470,7 +1440,7 @@ namespace build2
break;
}
- case type::so:
+ case otype::s:
{
if (cid == "msvc")
{
@@ -1489,7 +1459,7 @@ namespace build2
if (tsys == "mingw32")
{
- // On Windows libso{} is the import stub and its first ad hoc
+ // On Windows libs{} is the import stub and its first ad hoc
// group member is dll{}.
//
out = "-Wl,--out-implib=" + relt.string ();
@@ -1514,13 +1484,13 @@ namespace build2
{
path_target* ppt;
liba* a (nullptr);
- libso* so (nullptr);
- if ((ppt = pt->is_a<obja> ()) ||
- (ppt = pt->is_a<objso> ()) ||
- (lt != type::a &&
+ if ((ppt = pt->is_a<obje> ()) ||
+ (ppt = pt->is_a<obja> ()) ||
+ (ppt = pt->is_a<objs> ()) ||
+ (lt != otype::a &&
((ppt = a = pt->is_a<liba> ()) ||
- (ppt = so = pt->is_a<libso> ()))))
+ (ppt = pt->is_a<libs> ()))))
{
sargs.push_back (relative (ppt->path ()).string ()); // string()&&
@@ -1543,7 +1513,7 @@ namespace build2
for (size_t i (0); i != sargs.size (); ++i)
args.push_back (sargs[i].c_str ());
- if (lt != type::a)
+ if (lt != otype::a)
append_options (args, t, "cxx.libs");
args.push_back (nullptr);
@@ -1615,7 +1585,7 @@ namespace build2
// For Windows generate rpath-emulating assembly (unless updaing for
// install).
//
- if (lt == type::e && tclass == "windows")
+ if (lt == otype::e && tclass == "windows")
{
if (a.outer_operation () != install_id)
windows_rpath_assembly (t, rpath_timestamp, scratch);
@@ -1644,12 +1614,12 @@ namespace build2
switch (link_type (t))
{
- case type::a:
+ case otype::a:
{
e = {"+.d"};
break;
}
- case type::e:
+ case otype::e:
{
if (tclass == "windows")
{
@@ -1671,7 +1641,7 @@ namespace build2
break;
}
- case type::so:
+ case otype::s:
{
e = {"+.d"};
break;
diff --git a/build2/cxx/module.cxx b/build2/cxx/module.cxx
index 6a5469c..69e76a3 100644
--- a/build2/cxx/module.cxx
+++ b/build2/cxx/module.cxx
@@ -316,38 +316,40 @@ namespace build2
auto& r (b.rules);
- r.insert<obja> (perform_update_id, "cxx.compile", compile::instance);
+ r.insert<obje> (perform_update_id, "cxx.compile", compile::instance);
+ r.insert<obje> (perform_clean_id, "cxx.compile", compile::instance);
r.insert<obja> (perform_update_id, "cxx.compile", compile::instance);
r.insert<obja> (perform_clean_id, "cxx.compile", compile::instance);
- r.insert<objso> (perform_update_id, "cxx.compile", compile::instance);
- r.insert<objso> (perform_clean_id, "cxx.compile", compile::instance);
+ r.insert<objs> (perform_update_id, "cxx.compile", compile::instance);
+ r.insert<objs> (perform_clean_id, "cxx.compile", compile::instance);
- r.insert<exe> (perform_update_id, "cxx.link", link::instance);
- r.insert<exe> (perform_clean_id, "cxx.link", link::instance);
+ r.insert<exe> (perform_update_id, "cxx.link", link::instance);
+ r.insert<exe> (perform_clean_id, "cxx.link", link::instance);
r.insert<liba> (perform_update_id, "cxx.link", link::instance);
r.insert<liba> (perform_clean_id, "cxx.link", link::instance);
- r.insert<libso> (perform_update_id, "cxx.link", link::instance);
- r.insert<libso> (perform_clean_id, "cxx.link", link::instance);
+ r.insert<libs> (perform_update_id, "cxx.link", link::instance);
+ r.insert<libs> (perform_clean_id, "cxx.link", link::instance);
- // Register for configure so that we detect unresolved imports
- // during configuration rather that later, e.g., during update.
+ // Register for configure so that we detect unresolved imports during
+ // configuration rather that later, e.g., during update.
//
+ r.insert<obje> (configure_update_id, "cxx.compile", compile::instance);
r.insert<obja> (configure_update_id, "cxx.compile", compile::instance);
- r.insert<objso> (configure_update_id, "cxx.compile", compile::instance);
+ r.insert<objs> (configure_update_id, "cxx.compile", compile::instance);
- r.insert<exe> (configure_update_id, "cxx.link", link::instance);
+ r.insert<exe> (configure_update_id, "cxx.link", link::instance);
r.insert<liba> (configure_update_id, "cxx.link", link::instance);
- r.insert<libso> (configure_update_id, "cxx.link", link::instance);
+ r.insert<libs> (configure_update_id, "cxx.link", link::instance);
//@@ Should we check if install module was loaded (see bin)?
//
- r.insert<exe> (perform_install_id, "cxx.install", install::instance);
+ r.insert<exe> (perform_install_id, "cxx.install", install::instance);
r.insert<liba> (perform_install_id, "cxx.install", install::instance);
- r.insert<libso> (perform_install_id, "cxx.install", install::instance);
+ r.insert<libs> (perform_install_id, "cxx.install", install::instance);
}
// Configure "installability" of our target types.
diff --git a/build2/cxx/utility.cxx b/build2/cxx/utility.cxx
index ed57fd2..cf9c4d0 100644
--- a/build2/cxx/utility.cxx
+++ b/build2/cxx/utility.cxx
@@ -79,7 +79,7 @@ namespace build2
for (target* t: l.prerequisite_targets)
{
- if (t->is_a<lib> () || t->is_a<liba> () || t->is_a<libso> ())
+ if (t->is_a<lib> () || t->is_a<liba> () || t->is_a<libs> ())
append_lib_options (args, *t, var);
}
@@ -93,7 +93,7 @@ namespace build2
for (target* t: l.prerequisite_targets)
{
- if (t->is_a<lib> () || t->is_a<liba> () || t->is_a<libso> ())
+ if (t->is_a<lib> () || t->is_a<liba> () || t->is_a<libs> ())
hash_lib_options (csum, *t, var);
}
diff --git a/build2/cxx/windows-rpath.cxx b/build2/cxx/windows-rpath.cxx
index 8f19f79..0bd4bc5 100644
--- a/build2/cxx/windows-rpath.cxx
+++ b/build2/cxx/windows-rpath.cxx
@@ -49,7 +49,7 @@ namespace build2
for (target* pt: t.prerequisite_targets)
{
- if (libso* ls = pt->is_a<libso> ())
+ if (libs* ls = pt->is_a<libs> ())
{
// This can be an installed library in which case we will have just
// the import stub but may also have just the DLL. For now we don't
@@ -84,7 +84,7 @@ namespace build2
{
for (target* pt: t.prerequisite_targets)
{
- if (libso* ls = pt->is_a<libso> ())
+ if (libs* ls = pt->is_a<libs> ())
{
if (ls->member == nullptr)
continue;
diff --git a/build2/target b/build2/target
index 955c2f9..28753df 100644
--- a/build2/target
+++ b/build2/target
@@ -192,7 +192,7 @@ namespace build2
// is an explicit mechanism for discovering the group's members.
//
// However, sometimes, we may want to create a group on the fly out of a
- // normal target type. For example, we have the libso{} target type. But
+ // normal target type. For example, we have the libs{} target type. But
// on Windows a shared library consist of (at least) two files: the import
// library and the DLL itself. So we somehow need to be able to capture
// that. One approach would be to imply the presence of the second file.