aboutsummaryrefslogtreecommitdiff
path: root/build2/bin
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-01-05 11:55:15 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-01-05 11:55:15 +0200
commit9fb791e9fad6c63fc1dac49f4d05ae63b8a3db9b (patch)
treed60322d4382ca5f97b676c5abe2e39524f35eab4 /build2/bin
parentf159b1dac68c8714f7ba71ca168e3b695891aad9 (diff)
Rename build directory/namespace to build2
Diffstat (limited to 'build2/bin')
-rw-r--r--build2/bin/module23
-rw-r--r--build2/bin/module.cxx188
-rw-r--r--build2/bin/rule39
-rw-r--r--build2/bin/rule.cxx145
-rw-r--r--build2/bin/target99
-rw-r--r--build2/bin/target.cxx190
6 files changed, 684 insertions, 0 deletions
diff --git a/build2/bin/module b/build2/bin/module
new file mode 100644
index 0000000..85be444
--- /dev/null
+++ b/build2/bin/module
@@ -0,0 +1,23 @@
+// file : build2/bin/module -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BUILD2_BIN_MODULE
+#define BUILD2_BIN_MODULE
+
+#include <build2/types>
+#include <build2/utility>
+
+#include <build2/module>
+
+namespace build2
+{
+ namespace bin
+ {
+ extern "C" bool
+ bin_init (
+ scope&, scope&, const location&, unique_ptr<module>&, bool, bool);
+ }
+}
+
+#endif // BUILD2_BIN_MODULE
diff --git a/build2/bin/module.cxx b/build2/bin/module.cxx
new file mode 100644
index 0000000..624a8d3
--- /dev/null
+++ b/build2/bin/module.cxx
@@ -0,0 +1,188 @@
+// file : build2/bin/module.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <build2/bin/module>
+
+#include <build2/scope>
+#include <build2/variable>
+#include <build2/diagnostics>
+
+#include <build2/config/utility>
+#include <build2/install/utility>
+
+#include <build2/bin/rule>
+#include <build2/bin/target>
+
+using namespace std;
+
+namespace build2
+{
+ namespace bin
+ {
+ static obj_rule obj_;
+ static lib_rule lib_;
+
+ // Default config.bin.*.lib values.
+ //
+ static const strings exe_lib {"shared", "static"};
+ static const strings liba_lib {"static"};
+ static const strings libso_lib {"shared"};
+
+ extern "C" bool
+ bin_init (scope& r,
+ scope& b,
+ const location&,
+ std::unique_ptr<module>&,
+ bool first,
+ bool)
+ {
+ tracer trace ("bin::init");
+ level5 ([&]{trace << "for " << b.out_path ();});
+
+ // Enter module variables.
+ //
+ if (first)
+ {
+ auto& v (var_pool);
+
+ v.find ("config.bin.lib", string_type);
+ v.find ("config.bin.exe.lib", strings_type);
+ v.find ("config.bin.liba.lib", strings_type);
+ v.find ("config.bin.libso.lib", strings_type);
+ v.find ("config.bin.rpath", strings_type); //@@ VAR paths_type
+
+ v.find ("bin.lib", string_type);
+ v.find ("bin.exe.lib", strings_type);
+ v.find ("bin.liba.lib", strings_type);
+ v.find ("bin.libso.lib", strings_type);
+ v.find ("bin.rpath", strings_type); //@@ VAR paths_type
+
+ v.find ("bin.libprefix", string_type);
+ }
+
+ // Register target types.
+ //
+ {
+ 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> ();
+ }
+
+ // Register rules.
+ //
+ {
+ auto& r (b.rules);
+
+ r.insert<obj> (perform_update_id, "bin.obj", obj_);
+ r.insert<obj> (perform_clean_id, "bin.obj", obj_);
+
+ r.insert<lib> (perform_update_id, "bin.lib", lib_);
+ r.insert<lib> (perform_clean_id, "bin.lib", lib_);
+
+ // Configure member.
+ //
+ r.insert<lib> (configure_update_id, "bin.lib", lib_);
+
+ //@@ Should we check if the install module was loaded
+ // (by checking if install operation is registered
+ // for this project)? If we do that, then install
+ // will have to be loaded before bin. Perhaps we
+ // should enforce loading of all operation-defining
+ // modules before all others?
+ //
+ r.insert<lib> (perform_install_id, "bin.lib", lib_);
+ }
+
+ // Configure.
+ //
+ using config::required;
+
+ // The idea here is as follows: if we already have one of
+ // the bin.* variables set, then we assume this is static
+ // project configuration and don't bother setting the
+ // corresponding config.bin.* variable.
+ //
+ //@@ Need to validate the values. Would be more efficient
+ // to do it once on assignment than every time on query.
+ // Custom var type?
+ //
+
+ // config.bin.lib
+ //
+ {
+ value& v (b.assign ("bin.lib"));
+ if (!v)
+ v = required (r, "config.bin.lib", "both").first;
+ }
+
+ // config.bin.exe.lib
+ //
+ {
+ value& v (b.assign ("bin.exe.lib"));
+ if (!v)
+ v = required (r, "config.bin.exe.lib", exe_lib).first;
+ }
+
+ // config.bin.liba.lib
+ //
+ {
+ value& v (b.assign ("bin.liba.lib"));
+ if (!v)
+ v = required (r, "config.bin.liba.lib", liba_lib).first;
+ }
+
+ // config.bin.libso.lib
+ //
+ {
+ value& v (b.assign ("bin.libso.lib"));
+ if (!v)
+ v = required (r, "config.bin.libso.lib", libso_lib).first;
+ }
+
+ // config.bin.rpath
+ //
+ // This one is optional and we merge it into bin.rpath, if any.
+ // See the cxx module for details on merging.
+ //
+ if (const value& v = config::optional (r, "config.bin.rpath"))
+ b.assign ("bin.rpath") += as<strings> (v);
+
+
+ // Configure "installability" of our target types.
+ //
+ install::path<exe> (b, dir_path ("bin")); // Install into install.bin.
+
+ // Should shared libraries have executable bit? That depends on
+ // who you ask. In Debian, for example, it should not unless, it
+ // really is executable (i.e., has main()). On the other hand, on
+ // some systems, this may be required in order for the dynamic
+ // linker to be able to load the library. So, by default, we will
+ // keep it executable, especially seeing that this is also the
+ // behavior of autotools. At the same time, it is easy to override
+ // this, for example:
+ //
+ // config.install.lib.mode=644
+ //
+ // And a library that wants to override any such overrides (e.g.,
+ // because it does have main()) can do:
+ //
+ // libso{foo}: install.mode=755
+ //
+ // Everyone is happy then?
+ //
+ install::path<libso> (b, dir_path ("lib")); // Install into install.lib.
+
+ install::path<liba> (b, dir_path ("lib")); // Install into install.lib.
+ install::mode<liba> (b, "644");
+
+ return true;
+ }
+ }
+}
diff --git a/build2/bin/rule b/build2/bin/rule
new file mode 100644
index 0000000..ad52396
--- /dev/null
+++ b/build2/bin/rule
@@ -0,0 +1,39 @@
+// file : build2/bin/rule -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BUILD2_BIN_RULE
+#define BUILD2_BIN_RULE
+
+#include <build2/rule>
+
+namespace build2
+{
+ namespace bin
+ {
+ class obj_rule: public rule
+ {
+ public:
+ virtual match_result
+ match (action, target&, const std::string& hint) const;
+
+ virtual recipe
+ apply (action, target&, const match_result&) const;
+ };
+
+ class lib_rule: public rule
+ {
+ public:
+ virtual match_result
+ match (action, target&, const std::string& hint) const;
+
+ virtual recipe
+ apply (action, target&, const match_result&) const;
+
+ static target_state
+ perform (action, target&);
+ };
+ }
+}
+
+#endif // BUILD2_BIN_RULE
diff --git a/build2/bin/rule.cxx b/build2/bin/rule.cxx
new file mode 100644
index 0000000..9d93b0a
--- /dev/null
+++ b/build2/bin/rule.cxx
@@ -0,0 +1,145 @@
+// file : build2/bin/rule.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <build2/bin/rule>
+
+#include <build2/scope>
+#include <build2/target>
+#include <build2/algorithm>
+#include <build2/diagnostics>
+
+#include <build2/bin/target>
+
+using namespace std;
+
+namespace build2
+{
+ namespace bin
+ {
+ // obj
+ //
+ match_result obj_rule::
+ match (action a, target& t, const std::string&) const
+ {
+ fail << diag_doing (a, t) << " target group" <<
+ info << "explicitly select either obja{} or objso{} member";
+
+ return nullptr;
+ }
+
+ recipe obj_rule::
+ apply (action, target&, const match_result&) const {return empty_recipe;}
+
+ // lib
+ //
+ // 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 std::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().
+ //
+ const string& type (as<string> (*t["bin.lib"]));
+
+ bool ar (type == "static" || type == "both");
+ bool so (type == "shared" || type == "both");
+
+ if (!ar && !so)
+ fail << "unknown library type: " << type <<
+ info << "'static', 'shared', or 'both' expected";
+
+ // Search and pre-match the members. The pre-match here is part
+ // of the "library meta-information protocol" that could be used
+ // by the module that actually builds the members. The idea is
+ // that pre-matching members may populate our prerequisite_targets
+ // with prerequisite libraries from which others can extract the
+ // meta-information about the library, such as the options to use
+ // when linking it, etc.
+ //
+ if (ar)
+ {
+ if (t.a == nullptr)
+ t.a = &search<liba> (t.dir, t.name, t.ext, nullptr);
+
+ match_only (a, *t.a);
+ }
+
+ if (so)
+ {
+ if (t.so == nullptr)
+ t.so = &search<libso> (t.dir, t.name, t.ext, nullptr);
+
+ match_only (a, *t.so);
+ }
+
+ match_result mr (t, &type);
+
+ // 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 ());
+
+ return mr;
+ }
+
+ recipe lib_rule::
+ apply (action a, 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");
+
+ // Now we do full match.
+ //
+ if (ar)
+ build2::match (a, *t.a);
+
+ if (so)
+ build2::match (a, *t.so);
+
+ return &perform;
+ }
+
+ target_state lib_rule::
+ perform (action a, target& xt)
+ {
+ lib& t (static_cast<lib&> (xt));
+
+ //@@ Not cool we have to do this again. Looks like we need
+ // some kind of a cache vs resolved pointer, like in
+ // prerequisite vs prerequisite_target.
+ //
+ //
+ const string& type (as<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);
+
+ if (current_mode == execution_mode::last)
+ swap (m1, m2);
+
+ target_state r (target_state::unchanged);
+
+ if (m1 != nullptr)
+ r |= execute (a, *m1);
+
+ if (m2 != nullptr)
+ r |= execute (a, *m2);
+
+ return r;
+ }
+ }
+}
diff --git a/build2/bin/target b/build2/bin/target
new file mode 100644
index 0000000..e785ac0
--- /dev/null
+++ b/build2/bin/target
@@ -0,0 +1,99 @@
+// file : build2/bin/target -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BUILD2_BIN_TARGET
+#define BUILD2_BIN_TARGET
+
+#include <build2/target>
+
+namespace build2
+{
+ namespace bin
+ {
+ // The obj{} target group.
+ //
+ class obja: public file
+ {
+ public:
+ using file::file;
+
+ public:
+ static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
+ };
+
+ class objso: public file
+ {
+ public:
+ using file::file;
+
+ public:
+ static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
+ };
+
+ class obj: public target
+ {
+ public:
+ using target::target;
+
+ obja* a {nullptr};
+ objso* so {nullptr};
+
+ public:
+ static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
+ };
+
+ class exe: public file
+ {
+ public:
+ using file::file;
+
+ public:
+ static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
+ };
+
+ // The lib{} target group.
+ //
+ class liba: public file
+ {
+ public:
+ using file::file;
+
+ public:
+ static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
+ };
+
+ class libso: public file
+ {
+ public:
+ using file::file;
+
+ public:
+ static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
+ };
+
+ class lib: public target
+ {
+ public:
+ using target::target;
+
+ liba* a {nullptr};
+ libso* so {nullptr};
+
+ virtual void
+ reset (action_type);
+
+ public:
+ static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
+ };
+ }
+}
+
+#endif // BUILD2_BIN_TARGET
diff --git a/build2/bin/target.cxx b/build2/bin/target.cxx
new file mode 100644
index 0000000..6241a7b
--- /dev/null
+++ b/build2/bin/target.cxx
@@ -0,0 +1,190 @@
+// file : build2/bin/target.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <build2/bin/target>
+
+using namespace std;
+
+namespace build2
+{
+ namespace bin
+ {
+ static target*
+ obja_factory (const target_type&, dir_path d, string n, const string* e)
+ {
+ obj* o (targets.find<obj> (d, n));
+ obja* a (new obja (move (d), move (n), e));
+
+ if ((a->group = o))
+ o->a = a;
+
+ return a;
+ }
+
+ const target_type obja::static_type
+ {
+ "obja",
+ &file::static_type,
+ &obja_factory,
+ nullptr,
+ &search_target, // Note: not _file(); don't look for an existing file.
+ false
+ };
+
+ static target*
+ objso_factory (const target_type&, dir_path d, string n, const string* e)
+ {
+ obj* o (targets.find<obj> (d, n));
+ objso* so (new objso (move (d), move (n), e));
+
+ if ((so->group = o))
+ o->so = so;
+
+ return so;
+ }
+
+ const target_type objso::static_type
+ {
+ "objso",
+ &file::static_type,
+ &objso_factory,
+ nullptr,
+ &search_target, // Note: not _file(); don't look for an existing file.
+ false
+ };
+
+ static target*
+ obj_factory (const target_type&, dir_path d, string n, const string* e)
+ {
+ obja* a (targets.find<obja> (d, n));
+ objso* so (targets.find<objso> (d, n));
+ obj* o (new obj (move (d), move (n), e));
+
+ if ((o->a = a))
+ a->group = o;
+
+ if ((o->so = so))
+ so->group = o;
+
+ return o;
+ }
+
+ const target_type obj::static_type
+ {
+ "obj",
+ &target::static_type,
+ &obj_factory,
+ nullptr,
+ &search_target,
+ false
+ };
+
+ const target_type exe::static_type
+ {
+ "exe",
+ &file::static_type,
+ &target_factory<exe>,
+ nullptr,
+ &search_file,
+ false
+ };
+
+ static target*
+ liba_factory (const target_type& t, dir_path d, string n, const string* e)
+ {
+ // Only link-up to the group if the types match exactly.
+ //
+ lib* l (t == liba::static_type ? targets.find<lib> (d, n) : nullptr);
+ liba* a (new liba (move (d), move (n), e));
+
+ if ((a->group = l))
+ l->a = a;
+
+ return a;
+ }
+
+ // @@
+ //
+ // What extensions should we use? At the outset, this is platform-
+ // dependent. And if we consider cross-compilation, is it build or
+ // host-dependent? Feels like it should be host-dependent so that
+ // we can copy things between cross and native environments. So
+ // these will have to be determined based on what we are building.
+ // As if this is not complicated enough, the bin module doesn't
+ // know anything about building. So perhaps the extension should
+ // come from a variable that is set not by bin but by the module
+ // whose rule matched the target (e.g., cxx::link).
+ //
+ constexpr const char a_ext[] = "a";
+ const target_type liba::static_type
+ {
+ "liba",
+ &file::static_type,
+ &liba_factory,
+ &target_extension_fix<a_ext>,
+ &search_file,
+ false
+ };
+
+ static target*
+ libso_factory (const target_type& t, dir_path d, string n, const string* e)
+ {
+ // Only link-up to the group if the types match exactly.
+ //
+ lib* l (t == libso::static_type ? targets.find<lib> (d, n) : nullptr);
+ libso* so (new libso (move (d), move (n), e));
+
+ if ((so->group = l))
+ l->so = so;
+
+ return so;
+ }
+
+ constexpr const char so_ext[] = "so";
+ const target_type libso::static_type
+ {
+ "libso",
+ &file::static_type,
+ &libso_factory,
+ &target_extension_fix<so_ext>,
+ &search_file,
+ false
+ };
+
+ // lib
+ //
+ void lib::
+ reset (action_type)
+ {
+ // Don't clear prerequisite_targets since it is "given" to our
+ // members to implement "library meta-information protocol".
+ }
+
+ static target*
+ lib_factory (const target_type&, dir_path d, string n, const string* e)
+ {
+ liba* a (targets.find<liba> (d, n));
+ libso* so (targets.find<libso> (d, n));
+ lib* l (new lib (move (d), move (n), e));
+
+ if ((l->a = a))
+ a->group = l;
+
+ if ((l->so = so))
+ so->group = l;
+
+ return l;
+ }
+
+ const target_type lib::static_type
+ {
+ "lib",
+ &target::static_type,
+ &lib_factory,
+ nullptr,
+ &search_target,
+ false
+ };
+ }
+}