diff options
-rw-r--r-- | build/b.cxx | 6 | ||||
-rw-r--r-- | build/rule | 13 | ||||
-rw-r--r-- | build/rule.cxx | 59 | ||||
-rw-r--r-- | build/target | 17 | ||||
-rw-r--r-- | build/target.cxx | 9 |
5 files changed, 103 insertions, 1 deletions
diff --git a/build/b.cxx b/build/b.cxx index 1edce6b..05dac4c 100644 --- a/build/b.cxx +++ b/build/b.cxx @@ -84,6 +84,7 @@ main (int argc, char* argv[]) // target_types.insert (file::static_type); target_types.insert (dir::static_type); + target_types.insert (fsdir::static_type); target_types.insert (exe::static_type); target_types.insert (obj::static_type); @@ -164,7 +165,7 @@ main (int argc, char* argv[]) try { - p.parse (ifs, bf, scopes[path::current ()]); + p.parse (ifs, bf, scopes[out_base]); } catch (const std::ios_base::failure&) { @@ -184,6 +185,9 @@ main (int argc, char* argv[]) dir_rule dir_r; rules[typeid (dir)].emplace ("dir", dir_r); + fsdir_rule fsdir_r; + rules[typeid (fsdir)].emplace ("fsdir", fsdir_r); + path_rule path_r; rules[typeid (path_target)].emplace ("path", path_r); @@ -58,6 +58,19 @@ namespace build static target_state update (target&); }; + + class fsdir_rule: public rule + { + public: + virtual void* + match (target&, const std::string& hint) const; + + virtual recipe + apply (target&, void*) const; + + static target_state + update (target&); + }; } #endif // BUILD_RULE diff --git a/build/rule.cxx b/build/rule.cxx index dcb6df1..e57feca 100644 --- a/build/rule.cxx +++ b/build/rule.cxx @@ -4,10 +4,15 @@ #include <build/rule> +#include <string.h> // strerror_r() +#include <sys/stat.h> // mkdir() +#include <sys/types.h> // mkdir() + #include <utility> // move() #include <build/algorithm> #include <build/diagnostics> +#include <build/timestamp> using namespace std; @@ -121,4 +126,58 @@ namespace build // return update_prerequisites (t); } + + // fsdir_rule + // + void* fsdir_rule:: + match (target& t, const string&) const + { + return &t; + } + + recipe fsdir_rule:: + apply (target& t, void*) const + { + // Let's not allow any prerequisites for this target since it + // doesn't make much sense. The sole purpose of this target type + // is to create a directory. + // + if (!t.prerequisites.empty ()) + fail << "no prerequisites allowed for target " << t; + + return &update; + } + + target_state fsdir_rule:: + update (target& t) + { + path d (t.dir / path (t.name)); + + // Add the extension back if it was specified. + // + if (t.ext != nullptr) + { + d += '.'; + d += *t.ext; + } + + if (path_mtime (d) != timestamp_nonexistent) + return target_state::uptodate; + + if (verb >= 1) + text << "mkdir " << d.string (); + else + text << "mkdir " << t; //@@ Probably only show if [show]? + + if (mkdir (d.string ().c_str (), 0777) != 0) + { + char b[512]; + const char* m (strerror_r (errno, b, sizeof (b)) == 0 + ? b + : "error message too long"); + fail << "mkdir: unable to create directory " << d.string () << ": " << m; + } + + return target_state::updated; + } } diff --git a/build/target b/build/target index da5cf71..881bfb7 100644 --- a/build/target +++ b/build/target @@ -255,6 +255,23 @@ namespace build virtual const target_type& type () const {return static_type;} static const target_type static_type; }; + + // While a filesystem directory is mtime-based, the semantics is + // not very useful in our case. In particular, if another target + // depends on fsdir{}, then all that's desired is the creation of + // the directory if it doesn't already exist. In particular, we + // don't want to update the target just because some unrelated + // entry was created in that directory. + // + class fsdir: public target + { + public: + using target::target; + + public: + virtual const target_type& type () const {return static_type;} + static const target_type static_type; + }; } #endif // BUILD_TARGET diff --git a/build/target.cxx b/build/target.cxx index 50a7cc6..235ceef 100644 --- a/build/target.cxx +++ b/build/target.cxx @@ -212,4 +212,13 @@ namespace build &target_factory<dir>, &search_alias }; + + const target_type fsdir::static_type + { + typeid (fsdir), + "fsdir", + &target::static_type, + &target_factory<fsdir>, + target::static_type.search + }; } |