diff options
-rw-r--r-- | src/app/qbs/parser/command.cpp | 1 | ||||
-rw-r--r-- | src/app/qbs/parser/commandlineoption.cpp | 12 | ||||
-rw-r--r-- | src/app/qbs/parser/commandlineoption.h | 8 | ||||
-rw-r--r-- | src/app/qbs/parser/commandlineoptionpool.cpp | 9 | ||||
-rw-r--r-- | src/app/qbs/parser/commandlineoptionpool.h | 1 | ||||
-rw-r--r-- | src/app/qbs/parser/commandlineparser.cpp | 6 | ||||
-rw-r--r-- | src/app/qbs/parser/commandlineparser.h | 1 | ||||
-rw-r--r-- | src/lib/corelib/buildgraph/executor.cpp | 20 | ||||
-rw-r--r-- | src/lib/corelib/tools/buildoptions.cpp | 21 | ||||
-rw-r--r-- | src/lib/corelib/tools/buildoptions.h | 3 | ||||
-rw-r--r-- | tests/auto/api/testdata/check-outputs/foo.txt | 1 | ||||
-rw-r--r-- | tests/auto/api/testdata/check-outputs/project.qbs | 37 | ||||
-rw-r--r-- | tests/auto/api/tst_api.cpp | 21 | ||||
-rw-r--r-- | tests/auto/api/tst_api.h | 2 | ||||
-rw-r--r-- | tests/auto/cmdlineparser/tst_cmdlineparser.cpp | 2 |
15 files changed, 143 insertions, 2 deletions
diff --git a/src/app/qbs/parser/command.cpp b/src/app/qbs/parser/command.cpp index 73c40867f..ed8352788 100644 --- a/src/app/qbs/parser/command.cpp +++ b/src/app/qbs/parser/command.cpp @@ -247,6 +247,7 @@ static QList<CommandLineOption::Type> buildOptions() << CommandLineOption::ProductsOptionType << CommandLineOption::ChangedFilesOptionType << CommandLineOption::ForceTimestampCheckOptionType + << CommandLineOption::ForceOutputCheckOptionType << CommandLineOption::BuildNonDefaultOptionType << CommandLineOption::VersionOptionType << CommandLineOption::CommandEchoModeOptionType diff --git a/src/app/qbs/parser/commandlineoption.cpp b/src/app/qbs/parser/commandlineoption.cpp index 42c167447..8a4adc63f 100644 --- a/src/app/qbs/parser/commandlineoption.cpp +++ b/src/app/qbs/parser/commandlineoption.cpp @@ -426,6 +426,18 @@ QString ForceTimeStampCheckOption::longRepresentation() const return QLatin1String("--check-timestamps"); } +QString ForceOutputCheckOption::description(CommandType command) const +{ + Q_UNUSED(command); + return Tr::tr("%1\n\tForce transformer output artifact checks.\n" + "\tVerify that the output artifacts declared by rules and transformers in the\n" + "\tproject are actually created.\n").arg(longRepresentation()); +} + +QString ForceOutputCheckOption::longRepresentation() const +{ + return QLatin1String("--check-outputs"); +} QString BuildNonDefaultOption::description(CommandType command) const { diff --git a/src/app/qbs/parser/commandlineoption.h b/src/app/qbs/parser/commandlineoption.h index b096ea2ba..244332574 100644 --- a/src/app/qbs/parser/commandlineoption.h +++ b/src/app/qbs/parser/commandlineoption.h @@ -55,6 +55,7 @@ public: InstallRootOptionType, RemoveFirstOptionType, NoBuildOptionType, ForceOptionType, ForceTimestampCheckOptionType, + ForceOutputCheckOptionType, BuildNonDefaultOptionType, VersionOptionType, LogTimeOptionType, @@ -230,6 +231,13 @@ class ForceTimeStampCheckOption : public OnOffOption QString longRepresentation() const; }; +class ForceOutputCheckOption : public OnOffOption +{ + QString description(CommandType command) const; + QString shortRepresentation() const { return QString(); } + QString longRepresentation() const; +}; + class BuildNonDefaultOption : public OnOffOption { QString description(CommandType command) const; diff --git a/src/app/qbs/parser/commandlineoptionpool.cpp b/src/app/qbs/parser/commandlineoptionpool.cpp index 212ea3d06..e5d8854a6 100644 --- a/src/app/qbs/parser/commandlineoptionpool.cpp +++ b/src/app/qbs/parser/commandlineoptionpool.cpp @@ -92,6 +92,9 @@ CommandLineOption *CommandLineOptionPool::getOption(CommandLineOption::Type type case CommandLineOption::ForceTimestampCheckOptionType: option = new ForceTimeStampCheckOption; break; + case CommandLineOption::ForceOutputCheckOptionType: + option = new ForceOutputCheckOption; + break; case CommandLineOption::BuildNonDefaultOptionType: option = new BuildNonDefaultOption; break; @@ -203,6 +206,12 @@ ForceTimeStampCheckOption *CommandLineOptionPool::forceTimestampCheckOption() co getOption(CommandLineOption::ForceTimestampCheckOptionType)); } +ForceOutputCheckOption *CommandLineOptionPool::forceOutputCheckOption() const +{ + return static_cast<ForceOutputCheckOption *>( + getOption(CommandLineOption::ForceOutputCheckOptionType)); +} + BuildNonDefaultOption *CommandLineOptionPool::buildNonDefaultOption() const { return static_cast<BuildNonDefaultOption *>( diff --git a/src/app/qbs/parser/commandlineoptionpool.h b/src/app/qbs/parser/commandlineoptionpool.h index cbea5023d..907fda0a0 100644 --- a/src/app/qbs/parser/commandlineoptionpool.h +++ b/src/app/qbs/parser/commandlineoptionpool.h @@ -59,6 +59,7 @@ public: NoBuildOption *noBuildOption() const; ForceOption *forceOption() const; ForceTimeStampCheckOption *forceTimestampCheckOption() const; + ForceOutputCheckOption *forceOutputCheckOption() const; BuildNonDefaultOption *buildNonDefaultOption() const; VersionOption *versionOption() const; LogTimeOption *logTimeOption() const; diff --git a/src/app/qbs/parser/commandlineparser.cpp b/src/app/qbs/parser/commandlineparser.cpp index 62e15f3e4..73f445947 100644 --- a/src/app/qbs/parser/commandlineparser.cpp +++ b/src/app/qbs/parser/commandlineparser.cpp @@ -206,6 +206,11 @@ bool CommandLineParser::forceTimestampCheck() const return d->optionPool.forceTimestampCheckOption()->enabled(); } +bool CommandLineParser::forceOutputCheck() const +{ + return d->optionPool.forceOutputCheckOption()->enabled(); +} + bool CommandLineParser::dryRun() const { return d->dryRun(); @@ -506,6 +511,7 @@ void CommandLineParser::CommandLineParserPrivate::setupBuildOptions() buildOptions.setChangedFiles(changedFiles); buildOptions.setKeepGoing(optionPool.keepGoingOption()->enabled()); buildOptions.setForceTimestampCheck(optionPool.forceTimestampCheckOption()->enabled()); + buildOptions.setForceOutputCheck(optionPool.forceOutputCheckOption()->enabled()); const JobsOption * jobsOption = optionPool.jobsOption(); buildOptions.setMaxJobCount(jobsOption->jobCount()); buildOptions.setLogElapsedTime(logTime); diff --git a/src/app/qbs/parser/commandlineparser.h b/src/app/qbs/parser/commandlineparser.h index 27df3c0db..41cdbd927 100644 --- a/src/app/qbs/parser/commandlineparser.h +++ b/src/app/qbs/parser/commandlineparser.h @@ -63,6 +63,7 @@ public: InstallOptions installOptions(const QString &profile) const; bool force() const; bool forceTimestampCheck() const; + bool forceOutputCheck() const; bool dryRun() const; bool logTime() const; bool withNonDefaultProducts() const; diff --git a/src/lib/corelib/buildgraph/executor.cpp b/src/lib/corelib/buildgraph/executor.cpp index 447cdd287..150133c04 100644 --- a/src/lib/corelib/buildgraph/executor.cpp +++ b/src/lib/corelib/buildgraph/executor.cpp @@ -510,10 +510,26 @@ void Executor::finishJob(ExecutorJob *job, bool success) if (success) { m_project->buildData->isDirty = true; foreach (Artifact *artifact, transformer->outputs) { - if (artifact->alwaysUpdated) + if (artifact->alwaysUpdated) { artifact->setTimestamp(FileTime::currentTime()); - else + if (m_buildOptions.forceOutputCheck() && !FileInfo(artifact->filePath()).exists()) { + if (transformer->rule) { + if (!transformer->rule->name.isEmpty()) { + throw ErrorInfo(tr("Rule '%1' declares artifact '%2', " + "but the artifact was not produced.") + .arg(transformer->rule->name, artifact->filePath())); + } + throw ErrorInfo(tr("Rule declares artifact '%1', " + "but the artifact was not produced.") + .arg(artifact->filePath())); + } + throw ErrorInfo(tr("Transformer declares artifact '%1', " + "but the artifact was not produced.") + .arg(artifact->filePath())); + } + } else { artifact->setTimestamp(FileInfo(artifact->filePath()).lastModified()); + } } finishTransformer(transformer); } diff --git a/src/lib/corelib/tools/buildoptions.cpp b/src/lib/corelib/tools/buildoptions.cpp index fafb86404..a2d5c2db2 100644 --- a/src/lib/corelib/tools/buildoptions.cpp +++ b/src/lib/corelib/tools/buildoptions.cpp @@ -40,6 +40,7 @@ class BuildOptionsPrivate : public QSharedData public: BuildOptionsPrivate() : maxJobCount(0), dryRun(false), keepGoing(false), forceTimestampCheck(false), + forceOutputCheck(false), logElapsedTime(false), echoMode(defaultCommandEchoMode()), install(true), removeExistingInstallation(false), onlyExecuteRules(false) { @@ -52,6 +53,7 @@ public: bool dryRun; bool keepGoing; bool forceTimestampCheck; + bool forceOutputCheck; bool logElapsedTime; CommandEchoMode echoMode; bool install; @@ -240,6 +242,25 @@ void BuildOptions::setForceTimestampCheck(bool enabled) } /*! + * \brief Returns true if qbs will test whether rules and transformers actually create their + * declared output artifacts. + * The default is \c false. + */ +bool BuildOptions::forceOutputCheck() const +{ + return d->forceOutputCheck; +} + +/*! + * \brief Controls whether qbs should test whether rules and transformers actually create their + * declared output artifacts. Enabling this may introduce some small I/O overhead during the build. + */ +void BuildOptions::setForceOutputCheck(bool enabled) +{ + d->forceOutputCheck = enabled; +} + +/*! * \brief Returns true iff the time the operation takes will be logged. * The default is \c false. */ diff --git a/src/lib/corelib/tools/buildoptions.h b/src/lib/corelib/tools/buildoptions.h index df582bc4b..03187bbfe 100644 --- a/src/lib/corelib/tools/buildoptions.h +++ b/src/lib/corelib/tools/buildoptions.h @@ -70,6 +70,9 @@ public: bool forceTimestampCheck() const; void setForceTimestampCheck(bool enabled); + bool forceOutputCheck() const; + void setForceOutputCheck(bool enabled); + bool logElapsedTime() const; void setLogElapsedTime(bool log); diff --git a/tests/auto/api/testdata/check-outputs/foo.txt b/tests/auto/api/testdata/check-outputs/foo.txt new file mode 100644 index 000000000..76e819701 --- /dev/null +++ b/tests/auto/api/testdata/check-outputs/foo.txt @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/tests/auto/api/testdata/check-outputs/project.qbs b/tests/auto/api/testdata/check-outputs/project.qbs new file mode 100644 index 000000000..27eada48f --- /dev/null +++ b/tests/auto/api/testdata/check-outputs/project.qbs @@ -0,0 +1,37 @@ +import qbs +import qbs.File + +Project { + Product { + type: 'application' + consoleApplication: true + Group { + files: 'foo.txt' + fileTags: ['text'] + } + Depends { name: 'cpp' } + } + + Rule { + inputs: ['text'] + Artifact { + fileTags: ['cpp'] + filePath: input.baseName + '.cpp' + } + Artifact { + fileTags: ['ghost'] + filePath: input.baseName + '.ghost' + } + + prepare: { + var cmd = new JavaScriptCommand(); + cmd.inp = inputs["text"][0].filePath; + cmd.out = outputs["cpp"][0].filePath; + cmd.description = "generating " + outputs["cpp"][0].fileName; + cmd.sourceCode = function() { + File.copy(inp, out); + }; + return cmd; + } + } +} diff --git a/tests/auto/api/tst_api.cpp b/tests/auto/api/tst_api.cpp index a33330d6f..dcef6b37b 100644 --- a/tests/auto/api/tst_api.cpp +++ b/tests/auto/api/tst_api.cpp @@ -389,6 +389,27 @@ void TestApi::buildSingleFile() qPrintable(receiver.descriptions)); } +void TestApi::checkOutputs() +{ + QFETCH(bool, check); + qbs::SetupProjectParameters params = defaultSetupParameters("/check-outputs/project.qbs"); + qbs::BuildOptions options; + options.setForceOutputCheck(check); + removeBuildDir(params); + qbs::ErrorInfo errorInfo = doBuildProject("/check-outputs/project.qbs", 0, 0, 0, options); + if (check) + QVERIFY(errorInfo.hasError()); + else + VERIFY_NO_ERROR(errorInfo); +} + +void TestApi::checkOutputs_data() +{ + QTest::addColumn<bool>("check"); + QTest::newRow("checked outputs") << true; + QTest::newRow("unchecked outputs") << false; +} + qbs::GroupData findGroup(const qbs::ProductData &product, const QString &name) { foreach (const qbs::GroupData &g, product.groups()) { diff --git a/tests/auto/api/tst_api.h b/tests/auto/api/tst_api.h index 6a3f50e1c..a4e83b717 100644 --- a/tests/auto/api/tst_api.h +++ b/tests/auto/api/tst_api.h @@ -67,6 +67,8 @@ private slots: void changeContent(); #endif void changeDependentLib(); + void checkOutputs(); + void checkOutputs_data(); void commandExtraction(); void disabledInstallGroup(); void disabledProduct(); diff --git a/tests/auto/cmdlineparser/tst_cmdlineparser.cpp b/tests/auto/cmdlineparser/tst_cmdlineparser.cpp index 60b7bfd73..f1f27d1e8 100644 --- a/tests/auto/cmdlineparser/tst_cmdlineparser.cpp +++ b/tests/auto/cmdlineparser/tst_cmdlineparser.cpp @@ -63,6 +63,7 @@ private slots: args << "--changed-files" << "foo,bar" << fileArgs; args << "--force"; args << "--check-timestamps"; + args << "--check-outputs"; CommandLineParser parser; QVERIFY(parser.parseCommandLine(args)); @@ -73,6 +74,7 @@ private slots: QVERIFY(parser.buildOptions(QString()).keepGoing()); QVERIFY(parser.force()); QVERIFY(parser.forceTimestampCheck()); + QVERIFY(parser.forceOutputCheck()); QVERIFY(!parser.logTime()); QCOMPARE(parser.buildConfigurations().count(), 1); |