diff options
25 files changed, 481 insertions, 11 deletions
diff --git a/doc/reference/modules/cpp-module.qdoc b/doc/reference/modules/cpp-module.qdoc index 31ea7e378..42eb04832 100644 --- a/doc/reference/modules/cpp-module.qdoc +++ b/doc/reference/modules/cpp-module.qdoc @@ -467,6 +467,19 @@ Name of the entry point of an executable or dynamic library. If this property is undefined, the toolchain's default is used. + \section2 runtimeLibrary + + \table + \row \li \b{Type:} \li \c{string} + \row \li \b{Default:} \li \c{"dynamic"} for MSVC, \c{undefined} for others + \endtable + + Type of the used runtime library. Accepted values are \c{"static"} and \c{"dynamic"}. + If this property is set to \c{undefined}, then the default runtime library of the toolchain + is used. + \note For MSVC the default value is \c{"dynamic"}. + \note At the moment this property is only functional for MSVC. + \section1 Properties Specific to iOS and OS X diff --git a/share/qbs/modules/cpp/CppModule.qbs b/share/qbs/modules/cpp/CppModule.qbs index 1bde0efed..e1b66df8f 100644 --- a/share/qbs/modules/cpp/CppModule.qbs +++ b/share/qbs/modules/cpp/CppModule.qbs @@ -160,6 +160,13 @@ Module { description: "entry point symbol for an executable or dynamic library" } + property string runtimeLibrary + PropertyOptions { + name: "runtimeLibrary" + description: "determine which runtime library to use" + allowedValues: ['static', 'dynamic'] + } + property string visibility: 'default' PropertyOptions { name: "visibility" diff --git a/share/qbs/modules/cpp/msvc.js b/share/qbs/modules/cpp/msvc.js index 903a5fbba..23e587df4 100644 --- a/share/qbs/modules/cpp/msvc.js +++ b/share/qbs/modules/cpp/msvc.js @@ -19,12 +19,18 @@ function prepareCompiler(project, product, inputs, outputs, input, output) { args.push('/Os') else if (optimization === 'fast') args.push('/O2') - if (debugInformation) { + + if (debugInformation) args.push('/Zi') - args.push('/MDd') - } else { - args.push('/MD') + + var rtl = ModUtils.moduleProperty(product, "runtimeLibrary"); + if (rtl) { + rtl = (rtl === "static" ? "/MT" : "/MD"); + if (debugInformation) + rtl += "d"; + args.push(rtl); } + // warnings: var warningLevel = ModUtils.moduleProperty(input, "warningLevel") if (warningLevel === 'none') diff --git a/share/qbs/modules/cpp/windows-msvc.qbs b/share/qbs/modules/cpp/windows-msvc.qbs index e3c18bb59..bad42b62a 100644 --- a/share/qbs/modules/cpp/windows-msvc.qbs +++ b/share/qbs/modules/cpp/windows-msvc.qbs @@ -17,6 +17,7 @@ CppModule { warningLevel: "default" compilerName: "cl.exe" linkerName: "link.exe" + runtimeLibrary: "dynamic" property bool generateManifestFiles: true property path toolchainInstallPath diff --git a/src/lib/corelib/api/api.pri b/src/lib/corelib/api/api.pri index 2bd59b5b6..18b3b4716 100644 --- a/src/lib/corelib/api/api.pri +++ b/src/lib/corelib/api/api.pri @@ -7,7 +7,9 @@ HEADERS += \ $$PWD/project.h \ $$PWD/project_p.h \ $$PWD/propertymap_p.h \ - $$PWD/projectdata_p.h + $$PWD/projectdata_p.h \ + $$PWD/rulecommand.h \ + $$PWD/rulecommand_p.h SOURCES += \ $$PWD/internaljobs.cpp \ @@ -15,7 +17,8 @@ SOURCES += \ $$PWD/projectdata.cpp \ $$PWD/jobs.cpp \ $$PWD/languageinfo.cpp \ - $$PWD/project.cpp + $$PWD/project.cpp \ + $$PWD/rulecommand.cpp !qbs_no_dev_install { api_headers.files = \ @@ -23,6 +26,7 @@ SOURCES += \ $$PWD/languageinfo.h \ $$PWD/project.h \ $$PWD/projectdata.h \ + $$PWD/rulecommand.h \ $$PWD/runenvironment.h api_headers.path = $${QBS_INSTALL_PREFIX}/include/qbs/api INSTALLS += api_headers diff --git a/src/lib/corelib/api/project.cpp b/src/lib/corelib/api/project.cpp index 54c3585d2..f1b4be33a 100644 --- a/src/lib/corelib/api/project.cpp +++ b/src/lib/corelib/api/project.cpp @@ -38,9 +38,11 @@ #include "jobs.h" #include "projectdata_p.h" #include "propertymap_p.h" +#include "rulecommand_p.h" #include "runenvironment.h" #include <buildgraph/artifact.h> #include <buildgraph/buildgraph.h> +#include <buildgraph/command.h> #include <buildgraph/emptydirectoriesremover.h> #include <buildgraph/productbuilddata.h> #include <buildgraph/productinstaller.h> @@ -614,6 +616,59 @@ void ProjectPrivate::prepareChangeToProject() retrieveProjectData(m_projectData, internalProject); } +RuleCommandList ProjectPrivate::ruleCommands(const ProductData &product, + const QString &inputFilePath, const QString &outputFileTag) const +{ + if (internalProject->locked) + throw ErrorInfo(Tr::tr("A job is currently in process.")); + const ResolvedProductConstPtr resolvedProduct = internalProduct(product); + if (!resolvedProduct) + throw ErrorInfo(Tr::tr("No such product '%1'.").arg(product.name())); + if (!resolvedProduct->enabled) + throw ErrorInfo(Tr::tr("Product '%1' is disabled.").arg(product.name())); + QBS_CHECK(resolvedProduct->buildData); + const ArtifactSet &outputArtifacts = resolvedProduct->buildData->artifactsByFileTag + .value(FileTag(outputFileTag.toLocal8Bit())); + foreach (const Artifact * const outputArtifact, outputArtifacts) { + const TransformerConstPtr transformer = outputArtifact->transformer; + if (!transformer) + continue; + foreach (const Artifact * const inputArtifact, transformer->inputs) { + if (inputArtifact->filePath() == inputFilePath) { + RuleCommandList list; + foreach (const AbstractCommandPtr &internalCommand, transformer->commands) { + RuleCommand externalCommand; + externalCommand.d->description = internalCommand->description(); + switch (internalCommand->type()) { + case AbstractCommand::JavaScriptCommandType: { + externalCommand.d->type = RuleCommand::JavaScriptCommandType; + const JavaScriptCommandPtr &jsCmd + = internalCommand.staticCast<JavaScriptCommand>(); + externalCommand.d->sourceCode = jsCmd->sourceCode(); + break; + } + case AbstractCommand::ProcessCommandType: { + externalCommand.d->type = RuleCommand::ProcessCommandType; + const ProcessCommandPtr &procCmd + = internalCommand.staticCast<ProcessCommand>(); + externalCommand.d->executable = procCmd->program(); + externalCommand.d->arguments = procCmd->arguments(); + externalCommand.d->workingDir = procCmd->workingDir(); + externalCommand.d->environment = procCmd->environment(); + break; + } + } + list << externalCommand; + } + return list; + } + } + } + + throw ErrorInfo(Tr::tr("No rule was found that produces an artifact tagged '%1' " + "from input file '%2'.").arg(outputFileTag, inputFilePath)); +} + static bool productIsRunnable(const ResolvedProductConstPtr &product) { return product->fileTags.contains("application") @@ -1070,6 +1125,21 @@ QSet<QString> Project::buildSystemFiles() const return d->internalProject->buildSystemFiles; } +RuleCommandList Project::ruleCommands(const ProductData &product, + const QString &inputFilePath, const QString &outputFileTag, ErrorInfo *error) const +{ + QBS_ASSERT(isValid(), return RuleCommandList()); + QBS_ASSERT(product.isValid(), return RuleCommandList()); + + try { + return d->ruleCommands(product, inputFilePath, outputFileTag); + } catch (const ErrorInfo &e) { + if (error) + *error = e; + return RuleCommandList(); + } +} + #ifdef QBS_ENABLE_PROJECT_FILE_UPDATES /*! * \brief Adds a new empty group to the given product. diff --git a/src/lib/corelib/api/project.h b/src/lib/corelib/api/project.h index de90bbff2..d8e78be3e 100644 --- a/src/lib/corelib/api/project.h +++ b/src/lib/corelib/api/project.h @@ -30,6 +30,7 @@ #ifndef QBS_PROJECT_H #define QBS_PROJECT_H +#include "rulecommand.h" #include "../language/forward_decls.h" #include "../tools/qbs_export.h" @@ -130,6 +131,9 @@ public: QSet<QString> buildSystemFiles() const; + RuleCommandList ruleCommands(const ProductData &product, const QString &inputFilePath, + const QString &outputFileTag, ErrorInfo *error = 0) const; + #ifdef QBS_ENABLE_PROJECT_FILE_UPDATES ErrorInfo addGroup(const ProductData &product, const QString &groupName); ErrorInfo addFiles(const ProductData &product, const GroupData &group, diff --git a/src/lib/corelib/api/project_p.h b/src/lib/corelib/api/project_p.h index 2fbb01e85..ae17d8058 100644 --- a/src/lib/corelib/api/project_p.h +++ b/src/lib/corelib/api/project_p.h @@ -31,6 +31,7 @@ #define QBS_PROJECT_P_H #include "projectdata.h" +#include "rulecommand.h" #include <language/language.h> #include <logging/logger.h> @@ -105,6 +106,9 @@ public: const CodeLocation &changeLocation, int lineOffset); void prepareChangeToProject(); + RuleCommandList ruleCommands(const ProductData &product, + const QString &inputFilePath, const QString &outputFileTag) const; + TopLevelProjectPtr internalProject; Logger logger; diff --git a/src/lib/corelib/api/rulecommand.cpp b/src/lib/corelib/api/rulecommand.cpp new file mode 100644 index 000000000..844b9e975 --- /dev/null +++ b/src/lib/corelib/api/rulecommand.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "rulecommand.h" +#include "rulecommand_p.h" + +#include <tools/qbsassert.h> + +namespace qbs { + +/*! + * \class RuleCommand + * \brief The \c RuleCommand class corresponds to a \c ProcessCommand or \c JavaScriptCommand + * in \QBS. + */ + +/*! + * \enum RuleCommand::Type + * This enum type represents the different kinds of commands. + * \value ProcessCommandType For the \QBS type \c ProcessCommand, which represents a command + * whose execution involves calling an executable. + * \value JavaScriptCommandType For the \QBS type \c JavaScriptCommand, which represents a command + * whose execution involves running a piece of JavaScript code inside \QBS. + * \value InvalidType Used to mark \c RuleCommand objects as invalid. + */ + + +RuleCommand::RuleCommand() : d(new Internal::RuleCommandPrivate) +{ +} + +RuleCommand::RuleCommand(const RuleCommand &other) : d(other.d) {} + +RuleCommand::~RuleCommand() +{ +} + +RuleCommand& RuleCommand::operator=(const RuleCommand &other) +{ + d = other.d; + return *this; +} + +/*! + * Returns the type of this object. If the value is \c InvalidType, the object is invalid. + */ +RuleCommand::Type RuleCommand::type() const +{ + return d->type; +} + +/*! + * Returns the human-readable description of this command that \QBS will print when + * the command executed. + */ +QString RuleCommand::description() const +{ + return d->description; +} + +/*! + * Returns the source of the command if \c type() is \c JavaScriptCommandType. + * If \c type() is anything else, the behavior of this function is undefined. + */ +QString RuleCommand::sourceCode() const +{ + QBS_ASSERT(type() == JavaScriptCommandType, return QString()); + return d->sourceCode; +} + +/*! + * Returns the executable that will be called when the corresponding \c ProcessCommand + * is executed. + * If \c type() is not \c ProcessCommandType, the behavior of this function is undefined. + */ +QString RuleCommand::executable() const +{ + QBS_ASSERT(type() == ProcessCommandType, return QString()); + return d->executable; +} + +/*! + * Returns the command-line arguments of the executable that will be called when the + * corresponding \c ProcessCommand is executed. + * If \c type() is not \c ProcessCommandType, the behavior of this function is undefined. + */ +QStringList RuleCommand::arguments() const +{ + QBS_ASSERT(type() == ProcessCommandType, return QStringList()); + return d->arguments; +} + +/*! + * Returns the working directory of the executable that will be called when the + * corresponding \c ProcessCommand is executed. + * If \c type() is not \c ProcessCommandType, the behavior of this function is undefined. + */ +QString RuleCommand::workingDirectory() const +{ + QBS_ASSERT(type() == ProcessCommandType, return QString()); + return d->workingDir; +} + +/*! + * Returns the environment of the executable that will be called when the + * corresponding \c ProcessCommand is executed. + * If \c type() is not \c ProcessCommandType, the behavior of this function is undefined. + */ +QProcessEnvironment RuleCommand::environment() const +{ + QBS_ASSERT(type() == ProcessCommandType, return QProcessEnvironment()); + return d->environment; +} + +} // namespace qbs diff --git a/src/lib/corelib/api/rulecommand.h b/src/lib/corelib/api/rulecommand.h new file mode 100644 index 000000000..04c89d190 --- /dev/null +++ b/src/lib/corelib/api/rulecommand.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef QBS_RULECOMMAND_H +#define QBS_RULECOMMAND_H + +#include <tools/qbs_export.h> + +#include <QExplicitlySharedDataPointer> +#include <QStringList> + +QT_BEGIN_NAMESPACE +class QProcessEnvironment; +QT_END_NAMESPACE + +namespace qbs { +namespace Internal { +class ProjectPrivate; +class RuleCommandPrivate; +} + +class QBS_EXPORT RuleCommand +{ + friend class Internal::ProjectPrivate; +public: + RuleCommand(); + RuleCommand(const RuleCommand &other); + ~RuleCommand(); + RuleCommand &operator=(const RuleCommand &other); + + enum Type { ProcessCommandType, JavaScriptCommandType, InvalidType }; + + + Type type() const; + QString description() const; + QString sourceCode() const; + QString executable() const; + QStringList arguments() const; + QString workingDirectory() const; + QProcessEnvironment environment() const; + +private: + QExplicitlySharedDataPointer<Internal::RuleCommandPrivate> d; +}; + + +typedef QList<RuleCommand> RuleCommandList; + +} // namespace qbs + +#endif // Include guard. diff --git a/src/lib/corelib/api/rulecommand_p.h b/src/lib/corelib/api/rulecommand_p.h new file mode 100644 index 000000000..529c18636 --- /dev/null +++ b/src/lib/corelib/api/rulecommand_p.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef QBS_RULECOMMAND_P_H +#define QBS_RULECOMMAND_P_H + +#include "rulecommand.h" + +#include <QProcessEnvironment> +#include <QSharedData> + +namespace qbs { +namespace Internal { + +class RuleCommandPrivate : public QSharedData +{ +public: + RuleCommandPrivate(): type(RuleCommand::InvalidType) {} + + RuleCommand::Type type; + QString description; + QString sourceCode; + QString executable; + QStringList arguments; + QString workingDir; + QProcessEnvironment environment; +}; + +} // namespace Internal +} // namespace qbs + +#endif // Include guard. diff --git a/src/lib/corelib/buildgraph/buildgraphloader.cpp b/src/lib/corelib/buildgraph/buildgraphloader.cpp index 08ddce78f..9298185e5 100644 --- a/src/lib/corelib/buildgraph/buildgraphloader.cpp +++ b/src/lib/corelib/buildgraph/buildgraphloader.cpp @@ -275,6 +275,8 @@ void BuildGraphLoader::trackProjectChanges() if (newlyResolvedProduct->uniqueName() == restoredProduct->uniqueName()) { if (newlyResolvedProduct->enabled) newlyResolvedProduct->buildData.swap(restoredProduct->buildData); + else + productsWithChangedFiles.removeOne(restoredProduct); if (newlyResolvedProduct->buildData) { foreach (BuildGraphNode *node, newlyResolvedProduct->buildData->nodes) node->product = newlyResolvedProduct; diff --git a/src/lib/corelib/buildgraph/projectbuilddata.cpp b/src/lib/corelib/buildgraph/projectbuilddata.cpp index 18c56533a..253f1e063 100644 --- a/src/lib/corelib/buildgraph/projectbuilddata.cpp +++ b/src/lib/corelib/buildgraph/projectbuilddata.cpp @@ -448,8 +448,12 @@ void BuildDataResolver::resolveProductBuildData(const ResolvedProductPtr &produc foreach (ResolvedProductPtr dependency, product->dependencies) { if (Q_UNLIKELY(!dependency->enabled)) { - QString msg = Tr::tr("Product '%1' depends on '%2' but '%2' is disabled."); - throw ErrorInfo(msg.arg(product->name, dependency->name)); + ErrorInfo e; + e.append(Tr::tr("Product '%1' depends on '%2',") + .arg(product->name, dependency->name), product->location); + e.append(Tr::tr("but product '%1' is disabled.").arg(dependency->name), + dependency->location); + throw e; } resolveProductBuildData(dependency); } diff --git a/src/lib/corelib/corelib.qbs b/src/lib/corelib/corelib.qbs index 3dfe917c8..ceec8fa1c 100644 --- a/src/lib/corelib/corelib.qbs +++ b/src/lib/corelib/corelib.qbs @@ -57,6 +57,8 @@ QbsLibrary { "projectdata.cpp", "projectdata_p.h", "propertymap_p.h", + "rulecommand.cpp", + "rulecommand_p.h", "runenvironment.cpp", ] } @@ -70,6 +72,7 @@ QbsLibrary { "languageinfo.h", "project.h", "projectdata.h", + "rulecommand.h", "runenvironment.h" ] } diff --git a/src/lib/corelib/qbs.h b/src/lib/corelib/qbs.h index 2bd3e7529..4c39c3dc1 100644 --- a/src/lib/corelib/qbs.h +++ b/src/lib/corelib/qbs.h @@ -34,6 +34,7 @@ #include "api/languageinfo.h" #include "api/project.h" #include "api/projectdata.h" +#include "api/rulecommand.h" #include "logging/ilogsink.h" #include "tools/architectures.h" #include "tools/buildoptions.h" diff --git a/src/lib/qtprofilesetup/templates/core.qbs b/src/lib/qtprofilesetup/templates/core.qbs index dbe16e02b..44a67dffd 100644 --- a/src/lib/qtprofilesetup/templates/core.qbs +++ b/src/lib/qtprofilesetup/templates/core.qbs @@ -75,9 +75,6 @@ Module { property string generatedFilesDir: product.buildDirectory + "/GeneratedFiles" property string qmFilesDir: product.destinationDirectory - // private properties - property string libraryInfix: cpp.debugInformation ? 'd' : '' - cpp.defines: { var defines = @defines@; // ### QT_NO_DEBUG must be added if the current build variant is derived diff --git a/tests/auto/api/testdata/command-extraction/main.cpp b/tests/auto/api/testdata/command-extraction/main.cpp new file mode 100644 index 000000000..237c8ce18 --- /dev/null +++ b/tests/auto/api/testdata/command-extraction/main.cpp @@ -0,0 +1 @@ +int main() {} diff --git a/tests/auto/api/testdata/command-extraction/project.qbs b/tests/auto/api/testdata/command-extraction/project.qbs new file mode 100644 index 000000000..73b66aaa0 --- /dev/null +++ b/tests/auto/api/testdata/command-extraction/project.qbs @@ -0,0 +1,5 @@ +import qbs + +CppApplication { + files: "main.cpp" +} diff --git a/tests/auto/api/tst_api.cpp b/tests/auto/api/tst_api.cpp index 9b72c0f04..d488068e3 100644 --- a/tests/auto/api/tst_api.cpp +++ b/tests/auto/api/tst_api.cpp @@ -682,6 +682,49 @@ void TestApi::changeContent() #endif // QBS_ENABLE_PROJECT_FILE_UPDATES +void TestApi::commandExtraction() +{ + qbs::SetupProjectParameters setupParams + = defaultSetupParameters("/command-extraction/project.qbs"); + QScopedPointer<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(setupParams, + m_logSink, 0)); + waitForFinished(setupJob.data()); + QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); + qbs::Project project = setupJob->project(); + qbs::ProjectData projectData = project.projectData(); + QCOMPARE(projectData.allProducts().count(), 1); + qbs::ProductData productData = projectData.allProducts().first(); + qbs::ErrorInfo errorInfo; + const QString projectDirPath = QDir::cleanPath(QFileInfo(setupParams.projectFilePath()).path()); + const QString sourceFilePath = projectDirPath + "/main.cpp"; + + // Before the first build, no rules exist. + qbs::RuleCommandList commands + = project.ruleCommands(productData, sourceFilePath, "obj", &errorInfo); + QCOMPARE(commands.count(), 0); + QVERIFY(errorInfo.hasError()); + QVERIFY2(errorInfo.toString().contains("No rule"), qPrintable(errorInfo.toString())); + + qbs::BuildOptions options; + options.setDryRun(true); + QScopedPointer<qbs::BuildJob> buildJob(project.buildAllProducts(options)); + waitForFinished(buildJob.data()); + QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); + projectData = project.projectData(); + QCOMPARE(projectData.allProducts().count(), 1); + productData = projectData.allProducts().first(); + errorInfo = qbs::ErrorInfo(); + + // After the build, the compile command must be found. + commands = project.ruleCommands(productData, sourceFilePath, "obj", &errorInfo); + QCOMPARE(commands.count(), 1); + QVERIFY2(!errorInfo.hasError(), qPrintable(errorInfo.toString())); + const qbs::RuleCommand command = commands.first(); + QCOMPARE(command.type(), qbs::RuleCommand::ProcessCommandType); + QVERIFY(!command.executable().isEmpty()); + QVERIFY(!command.arguments().isEmpty()); +} + void TestApi::changeDependentLib() { qbs::ErrorInfo errorInfo = doBuildProject("change-dependent-lib/change-dependent-lib.qbs"); diff --git a/tests/auto/api/tst_api.h b/tests/auto/api/tst_api.h index 47bfb829d..3f0f19145 100644 --- a/tests/auto/api/tst_api.h +++ b/tests/auto/api/tst_api.h @@ -65,6 +65,7 @@ private slots: #ifdef QBS_ENABLE_PROJECT_FILE_UPDATES void changeContent(); #endif + void commandExtraction(); void changeDependentLib(); void enableAndDisableProduct(); void disabledInstallGroup(); diff --git a/tests/auto/blackbox/testdata/change-in-disabled-product/project.qbs b/tests/auto/blackbox/testdata/change-in-disabled-product/project.qbs new file mode 100644 index 000000000..8a99d2c8c --- /dev/null +++ b/tests/auto/blackbox/testdata/change-in-disabled-product/project.qbs @@ -0,0 +1,9 @@ +import qbs + +Product { + condition: false + files: [ + 'test1.txt', + // 'test2.txt' + ] +} diff --git a/tests/auto/blackbox/testdata/change-in-disabled-product/test1.txt b/tests/auto/blackbox/testdata/change-in-disabled-product/test1.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/change-in-disabled-product/test1.txt diff --git a/tests/auto/blackbox/testdata/change-in-disabled-product/test2.txt b/tests/auto/blackbox/testdata/change-in-disabled-product/test2.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/change-in-disabled-product/test2.txt diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp index 7f1f21252..6537fd5d3 100644 --- a/tests/auto/blackbox/tst_blackbox.cpp +++ b/tests/auto/blackbox/tst_blackbox.cpp @@ -242,6 +242,21 @@ void TestBlackbox::changedFiles() QVERIFY2(m_qbsStdout.contains("file1.cpp"), m_qbsStdout.constData()); } +void TestBlackbox::changeInDisabledProduct() +{ + QDir::setCurrent(testDataDir + "/change-in-disabled-product"); + QCOMPARE(runQbs(), 0); + waitForNewTimestamp(); + QFile projectFile("project.qbs"); + QVERIFY2(projectFile.open(QIODevice::ReadWrite), qPrintable(projectFile.errorString())); + QByteArray content = projectFile.readAll(); + content.replace("// 'test2.txt'", "'test2.txt'"); + projectFile.resize(0); + projectFile.write(content); + projectFile.close(); + QCOMPARE(runQbs(), 0); +} + void TestBlackbox::dependenciesProperty() { QDir::setCurrent(testDataDir + QLatin1String("/dependenciesProperty")); diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h index f83c5b4c6..459b2e071 100644 --- a/tests/auto/blackbox/tst_blackbox.h +++ b/tests/auto/blackbox/tst_blackbox.h @@ -96,6 +96,7 @@ private slots: void buildDirectories(); void changedFiles_data(); void changedFiles(); + void changeInDisabledProduct(); void dependenciesProperty(); void dynamicMultiplexRule(); void dynamicRuleOutputs(); |