From c0c85b67516653c181fbce7c61c2df3e31e4edd8 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 18 Dec 2014 07:14:53 +0200 Subject: Initial support for loading dependency info from buildfiles Also a new iteration on the overall architecture. Now, for the first time, build can read the buildfile and build itself. g++-4.9 -std=c++14 -g -I.. -o bd bd.cxx algorithm.cxx scope.cxx parser.cxx lexer.cxx target.cxx prerequisite.cxx rule.cxx native.cxx cxx/target.cxx cxx/rule.cxx process.cxx timestamp.cxx path.cxx g++-4.9 -std=c++14 -g -I../../.. -o driver driver.cxx ../../../build/lexer.cxx g++-4.9 -std=c++14 -g -I../../.. -o driver driver.cxx ../../../build/lexer.cxx ../../../build/parser.cxx ../../../build/scope.cxx ../../../build/target.cxx ../../../build/native.cxx ../../../build/prerequisite.cxx ../../../build/path.cxx ../../../build/timestamp.cxx --- build/cxx/rule | 5 ++- build/cxx/rule.cxx | 116 ++++++++++++++++++++++++++++++++++++--------------- build/cxx/target | 20 +++++---- build/cxx/target.cxx | 15 ++++--- 4 files changed, 108 insertions(+), 48 deletions(-) (limited to 'build/cxx') diff --git a/build/cxx/rule b/build/cxx/rule index 4900180..99e688d 100644 --- a/build/cxx/rule +++ b/build/cxx/rule @@ -12,12 +12,13 @@ namespace build { + class scope; + namespace cxx { // @@ Can't we do match(obj&) and then registration code extracts // that. And no virtuals. // - class compile: public rule { public: @@ -29,7 +30,7 @@ namespace build private: void - inject_prerequisites (obj&, const cxx&) const; + inject_prerequisites (obj&, const cxx&, scope&) const; }; class link: public rule diff --git a/build/cxx/rule.cxx b/build/cxx/rule.cxx index ccc9bb5..3cab2d4 100644 --- a/build/cxx/rule.cxx +++ b/build/cxx/rule.cxx @@ -12,6 +12,8 @@ #include +#include +#include #include #include #include @@ -45,26 +47,47 @@ namespace build // See if we have a source file. // - const cxx* s (nullptr); - for (const target& p: t.prerequisites ()) + prerequisite* sp (nullptr); + for (prerequisite& p: t.prerequisites) { - if ((s = dynamic_cast (&p)) != nullptr) + if (p.type.id == typeid (cxx)) + { + sp = &p; break; + } } - if (s == nullptr) + if (sp == nullptr) + { + cout << "no source file" << endl; return recipe (); + } // Derive object file name from target name. // obj& o (dynamic_cast (t)); if (o.path ().empty ()) - o.path (path (o.name () + ".o")); + o.path (o.directory / path (o.name + ".o")); - // Inject additional prerequisites. + // Resolve prerequisite to target and match it to a rule. We need + // this in order to get the source file path for prerequisite + // injections. // - inject_prerequisites (o, *s); + cxx* st ( + dynamic_cast ( + sp->target != nullptr ? sp->target : search (*sp))); + + if (st != nullptr) + { + if (st->recipe () || build::match (*st)) + { + // Don't bother if the file does not exist. + // + if (st->mtime () != timestamp_nonexistent) + inject_prerequisites (o, *st, sp->scope); + } + } return recipe (&update); } @@ -112,13 +135,13 @@ namespace build } void compile:: - inject_prerequisites (obj& o, const cxx& s) const + inject_prerequisites (obj& o, const cxx& s, scope& ds) const { const char* args[] = { "g++-4.9", "-std=c++14", "-I..", - "-M", + "-MM", //@@ TMP -M "-MG", // Treat missing headers as generated. "-MQ", "*", // Quoted target (older version can't handle empty name). s.path ().string ().c_str (), @@ -142,7 +165,7 @@ namespace build throw error (); } - size_t p (0); + size_t pos (0); if (first) { @@ -153,28 +176,47 @@ namespace build break; assert (l[0] == '*' && l[1] == ':' && l[2] == ' '); - next (l, (p = 3)); // Skip the source file. + next (l, (pos = 3)); // Skip the source file. first = false; } - while (p != l.size ()) + while (pos != l.size ()) { - path d (next (l, p)); + path file (next (l, pos)); + file.normalize (); - // If there is no extension (e.g., std C++ headers), then - // assume it is a header. Otherwise, let the normall - // mechanism to figure the type from the extension. + // If there is no extension (e.g., standard C++ headers), + // then assume it is a header. Otherwise, let the standard + // mechanism derive the type from the extension. // // @@ TODO: // - // - memory leak - hxx& h (*new hxx (d.leaf ().base ().string ())); - h.path (d); + // Split the name into its directory part and the name part. + // Here we assume the name part is a valid filesystem name. + // + path d (file.directory ()); + string n (file.leaf ().base ().string ()); + + // Find or insert. + // + auto r (ds.prerequisites.emplace ( + hxx::static_type, move (n), move (d), ds)); + + auto& p (const_cast (*r.first)); + + // Resolve to target so that we can assign its path. + // + path_target& t ( + dynamic_cast ( + p.target != nullptr ? *p.target : *search (p))); - o.prerequisite (h); + if (t.path ().empty ()) + t.path (file); + + o.prerequisites.push_back (p); } } @@ -208,14 +250,16 @@ namespace build bool u (mt == timestamp_nonexistent); const cxx* s (nullptr); - for (const target& p: t.prerequisites ()) + for (const prerequisite& p: t.prerequisites) { + const target& pt (*p.target); + // Assume all our prerequisites are mtime-based (checked in // match()). // if (!u) { - const auto& mtp (dynamic_cast (p)); + const auto& mtp (dynamic_cast (pt)); timestamp mp (mtp.mtime ()); // What do we do if timestamps are equal? This can happen, for @@ -229,7 +273,7 @@ namespace build } if (s == nullptr) - s = dynamic_cast (&p); + s = dynamic_cast (&pt); if (u && s != nullptr) break; @@ -241,6 +285,7 @@ namespace build const char* args[] = { "g++-4.9", "-std=c++14", + "-g", "-I..", "-c", "-o", o.path ().string ().c_str (), @@ -300,14 +345,17 @@ namespace build // See if we have at least one object file. // - const obj* o (nullptr); - for (const target& p: t.prerequisites ()) + prerequisite* op (nullptr); + for (prerequisite& p: t.prerequisites) { - if ((o = dynamic_cast (&p)) != nullptr) + if (p.type.id == typeid (obj)) + { + op = &p; break; + } } - if (o == nullptr) + if (op == nullptr) return recipe (); // Derive executable file name from target name. @@ -315,7 +363,7 @@ namespace build exe& e (dynamic_cast (t)); if (e.path ().empty ()) - e.path (path (e.name ())); + e.path (e.directory / path (e.name)); return recipe (&update); } @@ -333,12 +381,14 @@ namespace build bool u (mt == timestamp_nonexistent); - for (const target& p: t.prerequisites ()) + for (const prerequisite& p: t.prerequisites) { + const target& pt (*p.target); + // Assume all our prerequisites are mtime-based (checked in // match()). // - const auto& mtp (dynamic_cast (p)); + const auto& mtp (dynamic_cast (pt)); timestamp mp (mtp.mtime ()); // What do we do if timestamps are equal? This can happen, for @@ -357,13 +407,13 @@ namespace build if (!u) return target_state::uptodate; - vector args {"g++-4.9", "-std=c++14", "-o"}; + vector args {"g++-4.9", "-std=c++14", "-g", "-o"}; args.push_back (e.path ().string ().c_str ()); - for (const target& p: t.prerequisites ()) + for (const prerequisite& p: t.prerequisites) { - const obj& o (dynamic_cast (p)); + const obj& o (dynamic_cast (*p.target)); args.push_back (o.path ().string ().c_str ()); } diff --git a/build/cxx/target b/build/cxx/target index fe17c36..37b093b 100644 --- a/build/cxx/target +++ b/build/cxx/target @@ -16,8 +16,9 @@ namespace build public: using file::file; - public: virtual const type_info& type_id () const {return ti_;} - protected: static const type_info ti_; + public: + virtual const target_type& type () const {return static_type;} + static const target_type static_type; }; class ixx: public file @@ -25,8 +26,9 @@ namespace build public: using file::file; - public: virtual const type_info& type_id () const {return ti_;} - protected: static const type_info ti_; + public: + virtual const target_type& type () const {return static_type;} + static const target_type static_type; }; class txx: public file @@ -34,8 +36,9 @@ namespace build public: using file::file; - public: virtual const type_info& type_id () const {return ti_;} - protected: static const type_info ti_; + public: + virtual const target_type& type () const {return static_type;} + static const target_type static_type; }; class cxx: public file @@ -43,8 +46,9 @@ namespace build public: using file::file; - public: virtual const type_info& type_id () const {return ti_;} - protected: static const type_info ti_; + public: + virtual const target_type& type () const {return static_type;} + static const target_type static_type; }; } } diff --git a/build/cxx/target.cxx b/build/cxx/target.cxx index 7171e30..c4502b4 100644 --- a/build/cxx/target.cxx +++ b/build/cxx/target.cxx @@ -10,11 +10,16 @@ namespace build { namespace cxx { - using type_info = target::type_info; + const target_type hxx::static_type { + typeid (hxx), "hxx", &file::static_type, &target_factory}; - const type_info hxx::ti_ {typeid (hxx), "hxx", &file::ti_}; - const type_info ixx::ti_ {typeid (ixx), "ixx", &file::ti_}; - const type_info txx::ti_ {typeid (txx), "txx", &file::ti_}; - const type_info cxx::ti_ {typeid (cxx), "cxx", &file::ti_}; + const target_type ixx::static_type { + typeid (ixx), "ixx", &file::static_type, &target_factory}; + + const target_type txx::static_type { + typeid (txx), "txx", &file::static_type, &target_factory}; + + const target_type cxx::static_type { + typeid (cxx), "cxx", &file::static_type, &target_factory}; } } -- cgit v1.1