diff --git a/src/jomlib/makefile.cpp b/src/jomlib/makefile.cpp index 720be01..94ef2d4 100644 --- a/src/jomlib/makefile.cpp +++ b/src/jomlib/makefile.cpp @@ -114,6 +114,7 @@ void Command::evaluateModifiers() DescriptionBlock::DescriptionBlock(Makefile* mkfile) : m_bFileExists(false), m_bVisitedByCycleCheck(false), + m_bNoCyclesRootedHere(false), m_canAddCommands(ACSUnknown), m_pMakefile(mkfile) { diff --git a/src/jomlib/makefile.h b/src/jomlib/makefile.h index 4199b8a..84ae63d 100644 --- a/src/jomlib/makefile.h +++ b/src/jomlib/makefile.h @@ -103,6 +103,7 @@ class DescriptionBlock : public CommandContainer { FileTime m_timeStamp; bool m_bFileExists; bool m_bVisitedByCycleCheck; + bool m_bNoCyclesRootedHere; QVector m_inferenceRules; enum AddCommandsState { ACSUnknown, ACSEnabled, ACSDisabled }; diff --git a/src/jomlib/parser.cpp b/src/jomlib/parser.cpp index a33a550..f3dd51c 100644 --- a/src/jomlib/parser.cpp +++ b/src/jomlib/parser.cpp @@ -149,6 +149,11 @@ void Parser::apply(Preprocessor* pp, checkForCycles(target); preselectInferenceRules(target); } + // reset the droppings left by the cycle checker + foreach (const QString& targetName, m_activeTargets) { + DescriptionBlock *target = m_makefile->target(targetName); + resetCycleChecker(target); + } } MacroTable* Parser::macroTable() @@ -637,20 +642,57 @@ void Parser::parseDotDirective() void Parser::checkForCycles(DescriptionBlock* target) { +#ifdef DEBUG_CYCLE_CHECKER + static int depth = 0; +#endif + if (!target) return; +#ifdef DEBUG_CYCLE_CHECKER + { + int i = depth; + while (i--) + putc(' ', stdout); + } + printf("%s\n", qPrintable(target->targetName())); +#endif + + if (target->m_bNoCyclesRootedHere) + return; + if (target->m_bVisitedByCycleCheck) { QString msg = QLatin1String("cycle in targets detected: %1"); throw Exception(msg.arg(target->targetName())); } +#ifdef DEBUG_CYCLE_CHECKER + depth++; +#endif target->m_bVisitedByCycleCheck = true; for (int i = target->m_dependents.count(); --i >= 0;) { DescriptionBlock *const dep = m_makefile->target(target->m_dependents.at(i)); checkForCycles(dep); } target->m_bVisitedByCycleCheck = false; +#ifdef DEBUG_CYCLE_CHECKER + depth--; +#endif + + target->m_bNoCyclesRootedHere = true; +} + +void Parser::resetCycleChecker(DescriptionBlock* target) +{ + if (!target || !target->m_bNoCyclesRootedHere) + return; + + for (int i = target->m_dependents.count(); --i >= 0;) { + DescriptionBlock *const dep = m_makefile->target(target->m_dependents.at(i)); + resetCycleChecker(dep); + } + + target->m_bNoCyclesRootedHere = false; } QVector Parser::findRulesByTargetName(const QString& targetFilePath) @@ -684,7 +726,13 @@ QVector Parser::findRulesByTargetName(const QString& targetFileP void Parser::preselectInferenceRules(DescriptionBlock *target) { - if (target->m_commands.isEmpty()) { + if (!target->m_commands.isEmpty()) { + /* If we already have commands for this target, then we've already + * generated all the commands for the dependents already. Nothing + * more to do. */ + return; + } + { QVector rules = findRulesByTargetName(target->targetName()); if (!rules.isEmpty()) target->m_inferenceRules = rules; diff --git a/src/jomlib/parser.h b/src/jomlib/parser.h index 60c3dcd..f746ba1 100644 --- a/src/jomlib/parser.h +++ b/src/jomlib/parser.h @@ -64,6 +64,7 @@ class Parser void parseCommandLine(const QString& cmdLine, QList& commands, bool inferenceRule); void parseInlineFiles(Command& cmd, bool inferenceRule); void checkForCycles(DescriptionBlock* target); + void resetCycleChecker(DescriptionBlock* target); QVector findRulesByTargetName(const QString& targetFilePath); void preselectInferenceRules(DescriptionBlock *target); void error(const QString& msg);