Handle include dependencies

felipesanches-svg
Marius Kintel 2012-02-17 23:05:36 +01:00
parent 6845399e49
commit 2316127e62
7 changed files with 81 additions and 38 deletions

View File

@ -77,8 +77,8 @@ private:
AbstractNode *find_root_tag(AbstractNode *n);
void updateTemporalVariables();
bool fileChangedOnDisk();
void compileTopLevelDocument(bool reload);
void compile(bool reload, bool procevents);
bool compileTopLevelDocument(bool reload);
bool compile(bool reload, bool procevents);
void compileCSG(bool procevents);
bool maybeSave();
bool checkModified();

View File

@ -6,10 +6,12 @@
#include "boosty.h"
#include <boost/format.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
#include <stdio.h>
#include <fstream>
#include <sstream>
#include <time.h>
#include <sys/stat.h>
/*!
@ -18,10 +20,18 @@
ModuleCache *ModuleCache::inst = NULL;
static bool is_modified(const std::string &filename, const time_t &mtime)
{
struct stat st;
memset(&st, 0, sizeof(struct stat));
stat(filename.c_str(), &st);
return (st.st_mtime > mtime);
}
Module *ModuleCache::evaluate(const std::string &filename)
{
Module *lib_mod = NULL;
// Create cache ID
struct stat st;
memset(&st, 0, sizeof(struct stat));
@ -35,8 +45,14 @@ Module *ModuleCache::evaluate(const std::string &filename)
#ifdef DEBUG
PRINTB("Using cached library: %s (%s)", filename % cache_id);
#endif
PRINTB("%s", this->entries[filename].msg);
lib_mod = &(*this->entries[filename].module);
BOOST_FOREACH(const Module::IncludeContainer::value_type &item, lib_mod->includes) {
if (is_modified(item.first, item.second)) {
lib_mod = NULL;
break;
}
}
}
// If cache lookup failed (non-existing or old timestamp), compile module
@ -59,9 +75,10 @@ Module *ModuleCache::evaluate(const std::string &filename)
print_messages_push();
cache_entry e = { NULL, cache_id, std::string("WARNING: Library `") + filename + "' tries to recursively use itself!" };
if (this->entries.find(filename) != this->entries.end())
cache_entry e = { NULL, cache_id };
if (this->entries.find(filename) != this->entries.end()) {
delete this->entries[filename].module;
}
this->entries[filename] = e;
std::string pathname = boosty::stringy(fs::path(filename).parent_path());
@ -69,7 +86,6 @@ Module *ModuleCache::evaluate(const std::string &filename)
if (lib_mod) {
this->entries[filename].module = lib_mod;
this->entries[filename].msg = print_messages_stack.back();
} else {
this->entries.erase(filename);
}

View File

@ -17,7 +17,7 @@ private:
struct cache_entry {
class Module *module;
std::string cache_id, msg;
std::string cache_id;
};
boost::unordered_map<std::string, cache_entry> entries;
};

View File

@ -30,6 +30,7 @@
#include "printutils.h"
#include "parsersettings.h"
#include "parser_yacc.h"
#include "module.h"
#include <assert.h>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
@ -52,7 +53,8 @@ int lexerget_lineno(void);
static void yyunput(int, char*) __attribute__((unused));
#endif
extern const char *parser_input_buffer;
extern std::string parser_source_path;
extern std::string parser_source_path;
extern Module *currmodule;
#define YY_INPUT(buf,result,max_size) { \
if (yyin && yyin != stdin) { \
@ -219,8 +221,10 @@ void includefile()
filepath.clear();
path_stack.push_back(finfo.parent_path());
handle_dep(boosty::absolute(finfo).string());
yyin = fopen(boosty::absolute(finfo).string().c_str(), "r");
std::string fullname = boosty::absolute(finfo).string();
handle_dep(fullname);
currmodule->registerInclude(fullname);
yyin = fopen(fullname.c_str(), "r");
if (!yyin) {
PRINTB("WARNING: Can't open input file '%s'.", filename);
path_stack.pop_back();

View File

@ -79,6 +79,7 @@
#include <algorithm>
#include <boost/foreach.hpp>
#include <boost/version.hpp>
#include <sys/stat.h>
#ifdef ENABLE_CGAL
@ -598,10 +599,13 @@ AbstractNode *MainWindow::find_root_tag(AbstractNode *n)
/*!
Parse and evaluate the design => this->root_node
Returns true if something was compiled, false if nothing was changed
and the root_node was left untouched.
*/
void MainWindow::compile(bool reload, bool procevents)
bool MainWindow::compile(bool reload, bool procevents)
{
compileTopLevelDocument(reload);
if (!compileTopLevelDocument(reload)) return false;
// Invalidate renderers before we kill the CSG tree
this->glview->setRenderer(NULL);
@ -661,6 +665,8 @@ void MainWindow::compile(bool reload, bool procevents)
}
if (procevents) QApplication::processEvents();
}
return true;
}
/*!
@ -1000,13 +1006,15 @@ bool MainWindow::fileChangedOnDisk()
If reload is true, does a timestamp check on the document and tries to reload it.
Otherwise, just reparses the current document and any dependencies, updates the
GUI accordingly and populates this->root_module.
*/
void MainWindow::compileTopLevelDocument(bool reload)
{
bool shouldcompiletoplevel = true;
if (reload && fileChangedOnDisk()) {
if (!checkModified()) shouldcompiletoplevel = false;
Returns true if anything was compiled.
*/
bool MainWindow::compileTopLevelDocument(bool reload)
{
bool shouldcompiletoplevel = !reload;
if (reload && fileChangedOnDisk() && checkModified()) {
shouldcompiletoplevel = true;
refreshDocument();
}
@ -1046,17 +1054,18 @@ void MainWindow::compileTopLevelDocument(bool reload)
}
}
bool changed = shouldcompiletoplevel;
if (this->root_module) {
this->root_module->handleDependencies();
PRINTB("Module cache size: %d modules", ModuleCache::instance()->size());
changed |= this->root_module->handleDependencies();
if (changed) PRINTB("Module cache size: %d modules", ModuleCache::instance()->size());
}
return changed;
}
void MainWindow::checkAutoReload()
{
if (GuiLocker::isLocked()) return;
GuiLocker lock;
compile(true, true);
if (!this->fileName.isEmpty()) actionReloadCompile();
}
void MainWindow::autoReloadSet(bool on)
@ -1091,17 +1100,12 @@ void MainWindow::actionReloadCompile()
{
if (GuiLocker::isLocked()) return;
GuiLocker lock;
if (!checkModified()) return;
setCurrentOutput();
console->clear();
refreshDocument();
setCurrentOutput();
PRINT("Parsing design (AST generation)...");
QApplication::processEvents();
compile(true, true);
// PRINT("Parsing design (AST generation)...");
// QApplication::processEvents();
if (!compile(true, true)) return;
if (this->root_node) compileCSG(true);
// Go to non-CGAL view mode
@ -1123,7 +1127,6 @@ void MainWindow::actionCompile()
{
if (GuiLocker::isLocked()) return;
GuiLocker lock;
setCurrentOutput();
console->clear();
@ -1819,7 +1822,7 @@ void MainWindow::consoleOutput(const std::string &msg, void *userdata)
void MainWindow::setCurrentOutput()
{
set_output_handler(&MainWindow::consoleOutput, this);
// set_output_handler(&MainWindow::consoleOutput, this);
}
void MainWindow::clearCurrentOutput()

View File

@ -34,6 +34,7 @@
#include <boost/foreach.hpp>
#include <sstream>
#include <sys/stat.h>
AbstractModule::~AbstractModule()
{
@ -203,18 +204,33 @@ std::string Module::dump(const std::string &indent, const std::string &name) con
return dump.str();
}
void Module::handleDependencies()
void Module::registerInclude(const std::string &filename)
{
// PRINTB_NOCACHE("Module::handleDependencies(): %p (%d libs %p)", this % this->usedlibs.size() % &this->usedlibs);
struct stat st;
memset(&st, 0, sizeof(struct stat));
stat(filename.c_str(), &st);
this->includes[filename] = st.st_mtime;
}
/*!
Check if any dependencies have been modified and recompile them.
Returns true if anything was recompiled.
*/
bool Module::handleDependencies()
{
bool changed = false;
// Iterating manually since we want to modify the container while iterating
Module::ModuleContainer::iterator iter = this->usedlibs.begin();
while (iter != this->usedlibs.end()) {
Module::ModuleContainer::iterator curr = iter++;
Module *oldmodule = curr->second;
curr->second = ModuleCache::instance()->evaluate(curr->first);
if (curr->second != oldmodule) changed = true;
PRINTB_NOCACHE(" %s: %p", curr->first % curr->second);
if (!curr->second) {
PRINTB_NOCACHE("WARNING: Failed to compile library '%s'.", curr->first);
this->usedlibs.erase(curr);
}
}
return changed;
}

View File

@ -3,6 +3,7 @@
#include <string>
#include <vector>
#include <list>
#include <boost/unordered_map.hpp>
#include "value.h"
@ -67,7 +68,10 @@ public:
typedef boost::unordered_map<std::string, class Module*> ModuleContainer;
ModuleContainer usedlibs;
void handleDependencies();
void registerInclude(const std::string &filename);
typedef boost::unordered_map<std::string, time_t> IncludeContainer;
IncludeContainer includes;
bool handleDependencies();
std::vector<std::string> assignments_var;
std::vector<Expression*> assignments_expr;