From 977d07a3ae47ef204665d1eda2d642e5064724f3 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 24 Jun 2019 12:01:19 +0200 Subject: Split build system into library and driver --- build2/depdb.hxx | 286 ------------------------------------------------------- 1 file changed, 286 deletions(-) delete mode 100644 build2/depdb.hxx (limited to 'build2/depdb.hxx') diff --git a/build2/depdb.hxx b/build2/depdb.hxx deleted file mode 100644 index 95d9f4b..0000000 --- a/build2/depdb.hxx +++ /dev/null @@ -1,286 +0,0 @@ -// file : build2/depdb.hxx -*- C++ -*- -// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#ifndef BUILD2_DEPDB_HXX -#define BUILD2_DEPDB_HXX - -#include // strlen() - -#include -#include - -namespace build2 -{ - // Auxiliary dependency database (those .d files). Prints the diagnostics - // and fails on system and IO errors. - // - // This is a strange beast: a line-oriented, streaming database that can, at - // some point, be switched from reading to (over)writing. The idea is to - // store auxiliary/ad-hoc dependency information in the "invalidation" - // order. That is, if an earlier line is out of date, then all the - // subsequent ones are out of date as well. - // - // As an example, consider a dependency database for foo.o which is built - // from foo.cxx by the cxx.compile rule. The first line could be the rule - // name itself (perhaps with the version). If a different rule is now - // building foo.o, then any dep info that was saved by cxx.compile is - // probably useless. Next we can have the command line options that were - // used to build foo.o. Then could come the source file name followed by the - // extracted header dependencies. If the compile options or the source file - // name have changed, then the header dependencies are likely to have - // changed as well. - // - // As an example, here is what our foo.o.d could look like (the first line - // is the database format version and the last '\0' character is the end - // marker): - // - // 1 - // cxx.compile 1 - // g++-4.8 -I/tmp/foo -O3 - // /tmp/foo/foo.cxx - // /tmp/foo/foo.hxx - // /usr/include/string.h - // /usr/include/stdlib.h - // /tmp/foo/bar.hxx - // ^@ - // - // A race is possible between updating the database and the target. For - // example, we may detect a line mismatch that renders the target out-of- - // date (say, compile options in the above example). We update the database - // but before getting a chance to update the target, we get interrupted. On - // a subsequent re-run, because the database has been updated, we will miss - // the "target requires update" condition. - // - // If we assume that an update of the database also means an update of the - // target, then this "interrupted update" situation can be easily detected - // by comparing the database and target modification timestamps. This is - // also used to handle the dry-run mode where we essentially do the - // interruption ourselves. - // - struct depdb_base - { - explicit - depdb_base (const path&, timestamp); - - ~depdb_base (); - - enum class state {read, read_eof, write} state_; - - union - { - ifdstream is_; // read, read_eof - ofdstream os_; // write - }; - - butl::fdbuf* buf_; // Current buffer (for tellg()/tellp()). - }; - - class depdb: private depdb_base - { - public: - using path_type = build2::path; - - // The modification time of the database only makes sense while reading - // (in the write mode it will be set to timestamp_unknown). - // - // If touch is set to true, update the database modification time in - // close() even if otherwise no modifications are necessary (i.e., the - // database is in the read mode and is at eof). - // - path_type path; - timestamp mtime; - bool touch; - - // Open the database for reading. Note that if the file does not exist, - // has wrong format version, or is corrupt, then the database will be - // immediately switched to writing. - // - // The failure commonly happens when the user tries to stash the target in - // a non-existent subdirectory but forgets to add the corresponding fsdir{} - // prerequisite. That's why the issued diagnostics may provide the - // corresponding hint. - // - explicit - depdb (path_type); - - // Close the database. If this function is not called, then the database - // may be left in the old/currupt state. Note that in the read mode this - // function will "chop off" lines that haven't been read. - // - // Make sure to also call check_mtime() after updating the target to - // perform the target/database modification times sanity checks. - // - void - close (); - - // Flush any unwritten data to disk. This is primarily useful when reusing - // a (partially written) database as an input to external programs (e.g., - // as a module map). - // - void - flush (); - - // Perform target/database modification times sanity check. - // - // Note that it would also be good to compare the target timestamp against - // the newest prerequisite. However, obtaining this information would cost - // extra (see execute_prerequisites()). So maybe later, if we get a case - // where this is a problem (in a sense, the database is a buffer between - // prerequisites and the target). - // - void - check_mtime (const path_type& target, timestamp end = timestamp_unknown); - - static void - check_mtime (timestamp start, - const path_type& db, - const path_type& target, - timestamp end); - - // Return true if mtime checks are enabled. - // - static bool - mtime_check (); - - // Read the next line. If the result is not NULL, then it is a pointer to - // the next line in the database (which you are free to move from). If you - // then call write(), this line will be overwritten. - // - // If the result is NULL, then it means no next line is unavailable. This - // can be due to several reasons: - // - // - eof reached (you can detect this by calling more() before read()) - // - database is already in the write mode - // - the next line (and the rest of the database are corrupt) - // - string* - read () {return state_ == state::write ? nullptr : read_ ();} - - // Return true if the database is in the read mode and there is at least - // one more line available. Note that there is no guarantee that the line - // is not corrupt. In other words, read() can still return NULL, it just - // won't be because of eof. - // - bool - more () const {return state_ == state::read;} - - bool - reading () const {return state_ != state::write;} - - bool - writing () const {return state_ == state::write;} - - // Skip to the end of the database and return true if it is valid. - // Otherwise, return false, in which case the database must be - // overwritten. Note that this function expects the database to be in the - // read state. - // - bool - skip (); - - // Write the next line. If nl is false then don't write the newline yet. - // Note that this switches the database into the write mode and no further - // reading will be possible. - // - void - write (const string& l, bool nl = true) {write (l.c_str (), l.size (), nl);} - - void - write (const path_type& p, bool nl = true) {write (p.string (), nl);} - - void - write (const char* s, bool nl = true) {write (s, std::strlen (s), nl);} - - void - write (const char*, size_t, bool nl = true); - - void - write (char, bool nl = true); - - // Mark the previously read line as to be overwritte. - // - void - write () {if (state_ != state::write) change ();} - - // Read the next line and compare it to the expected value. If it matches, - // return NULL. Otherwise, overwrite it and return the old value (which - // could also be NULL). This strange-sounding result semantics is used to - // detect the "there is a value but it does not match" case for tracing: - // - // if (string* o = d.expect (...)) - // l4 ([&]{trace << "X mismatch forcing update of " << t;}); - // - string* - expect (const string& v) - { - string* l (read ()); - if (l == nullptr || *l != v) - { - write (v); - return l; - } - - return nullptr; - } - - string* - expect (const path_type& v) - { - string* l (read ()); - if (l == nullptr || - path_type::traits_type::compare (*l, v.string ()) != 0) - { - write (v); - return l; - } - - return nullptr; - } - - string* - expect (const char* v) - { - string* l (read ()); - if (l == nullptr || *l != v) - { - write (v); - return l; - } - - return nullptr; - } - - // Could be supported if required. - // - depdb (depdb&&) = delete; - depdb (const depdb&) = delete; - - depdb& operator= (depdb&&) = delete; - depdb& operator= (const depdb&) = delete; - - private: - depdb (path_type&&, timestamp); - - void - change (bool truncate = true); - - string* - read_ (); - - void - check_mtime_ (const path_type&, timestamp); - - static void - check_mtime_ (timestamp, const path_type&, const path_type&, timestamp); - - private: - uint64_t pos_; // Start of the last returned line. - string line_; // Current line. - timestamp start_; // Sequence start (mtime check). - }; -} - -#include - -#endif // BUILD2_DEPDB_HXX -- cgit v1.1