mirror of https://github.com/vitalif/openscad
Handle include dependencies
parent
6845399e49
commit
2316127e62
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
10
src/lexer.l
10
src/lexer.l
|
@ -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();
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue