aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/reference/modules/cpp-module.qdoc13
-rw-r--r--share/qbs/modules/cpp/CppModule.qbs7
-rw-r--r--share/qbs/modules/cpp/msvc.js14
-rw-r--r--share/qbs/modules/cpp/windows-msvc.qbs1
-rw-r--r--src/lib/corelib/api/api.pri8
-rw-r--r--src/lib/corelib/api/project.cpp70
-rw-r--r--src/lib/corelib/api/project.h4
-rw-r--r--src/lib/corelib/api/project_p.h4
-rw-r--r--src/lib/corelib/api/rulecommand.cpp142
-rw-r--r--src/lib/corelib/api/rulecommand.h78
-rw-r--r--src/lib/corelib/api/rulecommand_p.h59
-rw-r--r--src/lib/corelib/buildgraph/buildgraphloader.cpp2
-rw-r--r--src/lib/corelib/buildgraph/projectbuilddata.cpp8
-rw-r--r--src/lib/corelib/corelib.qbs3
-rw-r--r--src/lib/corelib/qbs.h1
-rw-r--r--src/lib/qtprofilesetup/templates/core.qbs3
-rw-r--r--tests/auto/api/testdata/command-extraction/main.cpp1
-rw-r--r--tests/auto/api/testdata/command-extraction/project.qbs5
-rw-r--r--tests/auto/api/tst_api.cpp43
-rw-r--r--tests/auto/api/tst_api.h1
-rw-r--r--tests/auto/blackbox/testdata/change-in-disabled-product/project.qbs9
-rw-r--r--tests/auto/blackbox/testdata/change-in-disabled-product/test1.txt0
-rw-r--r--tests/auto/blackbox/testdata/change-in-disabled-product/test2.txt0
-rw-r--r--tests/auto/blackbox/tst_blackbox.cpp15
-rw-r--r--tests/auto/blackbox/tst_blackbox.h1
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();