aboutsummaryrefslogtreecommitdiffstats
path: root/share/qbs
diff options
context:
space:
mode:
Diffstat (limited to 'share/qbs')
-rw-r--r--share/qbs/imports/qbs/base/Application.qbs3
-rw-r--r--share/qbs/imports/qbs/base/DynamicLibrary.qbs3
-rw-r--r--share/qbs/imports/qbs/base/QmlApp.qbs22
-rw-r--r--share/qbs/imports/qbs/base/StaticLibrary.qbs3
-rw-r--r--share/qbs/imports/qbs/base/qmlapplicationviewer/qmlapplicationviewer.cpp174
-rw-r--r--share/qbs/imports/qbs/base/qmlapplicationviewer/qmlapplicationviewer.h46
-rw-r--r--share/qbs/imports/qbs/fileinfo/fileinfo.js62
-rw-r--r--share/qbs/modules/cpp/CppModule.qbs75
-rw-r--r--share/qbs/modules/cpp/GenericGCC.qbs300
-rw-r--r--share/qbs/modules/cpp/gcc.js113
-rw-r--r--share/qbs/modules/cpp/linux-gcc.qbs6
-rw-r--r--share/qbs/modules/cpp/mac-gcc.qbs69
-rw-r--r--share/qbs/modules/cpp/msvc.js173
-rw-r--r--share/qbs/modules/cpp/ponyphone.qbs28
-rw-r--r--share/qbs/modules/cpp/windows-msvc.qbs199
-rw-r--r--share/qbs/modules/qbs/common.qbs50
-rw-r--r--share/qbs/modules/qt/QtModule.qbs19
-rw-r--r--share/qbs/modules/qt/core/moc.js15
-rw-r--r--share/qbs/modules/qt/core/qtcore.qbs130
-rw-r--r--share/qbs/modules/qt/declarative/module.qbs9
-rw-r--r--share/qbs/modules/qt/designer/module.qbs8
-rw-r--r--share/qbs/modules/qt/designercomponents/module.qbs8
-rw-r--r--share/qbs/modules/qt/gui/qtgui.qbs33
-rw-r--r--share/qbs/modules/qt/help/module.qbs8
-rw-r--r--share/qbs/modules/qt/network/module.qbs8
-rw-r--r--share/qbs/modules/qt/opengl/module.qbs8
-rw-r--r--share/qbs/modules/qt/qtfunctions.js12
-rw-r--r--share/qbs/modules/qt/script/module.qbs8
-rw-r--r--share/qbs/modules/qt/sql/module.qbs8
-rw-r--r--share/qbs/modules/qt/svg/module.qbs8
-rw-r--r--share/qbs/modules/qt/webkit/module.qbs8
-rw-r--r--share/qbs/modules/qt/xml/module.qbs8
-rw-r--r--share/qbs/modules/utils.js133
33 files changed, 1757 insertions, 0 deletions
diff --git a/share/qbs/imports/qbs/base/Application.qbs b/share/qbs/imports/qbs/base/Application.qbs
new file mode 100644
index 000000000..5865e6a99
--- /dev/null
+++ b/share/qbs/imports/qbs/base/Application.qbs
@@ -0,0 +1,3 @@
+Product {
+ type: qbs.targetOS == 'mac' ? "applicationbundle" : "application"
+}
diff --git a/share/qbs/imports/qbs/base/DynamicLibrary.qbs b/share/qbs/imports/qbs/base/DynamicLibrary.qbs
new file mode 100644
index 000000000..bf71dc8d5
--- /dev/null
+++ b/share/qbs/imports/qbs/base/DynamicLibrary.qbs
@@ -0,0 +1,3 @@
+Product {
+ type: "dynamiclibrary"
+}
diff --git a/share/qbs/imports/qbs/base/QmlApp.qbs b/share/qbs/imports/qbs/base/QmlApp.qbs
new file mode 100644
index 000000000..2d1ce228c
--- /dev/null
+++ b/share/qbs/imports/qbs/base/QmlApp.qbs
@@ -0,0 +1,22 @@
+import qbs.base 1.0
+
+Product {
+ type: ["application", "installed_content"]
+ Depends { name: "qt.declarative" }
+ Depends { name: "cpp" }
+ property string appViewerPath: localPath + "/qmlapplicationviewer"
+ cpp.includePaths: [appViewerPath]
+
+ Group {
+ files: [
+ appViewerPath + "/qmlapplicationviewer.h",
+ appViewerPath + "/qmlapplicationviewer.cpp"
+ ]
+ }
+
+ FileTagger {
+ pattern: "*.qml"
+ fileTags: ["install"]
+ }
+}
+
diff --git a/share/qbs/imports/qbs/base/StaticLibrary.qbs b/share/qbs/imports/qbs/base/StaticLibrary.qbs
new file mode 100644
index 000000000..da0416bee
--- /dev/null
+++ b/share/qbs/imports/qbs/base/StaticLibrary.qbs
@@ -0,0 +1,3 @@
+Product {
+ type: "staticlibrary"
+}
diff --git a/share/qbs/imports/qbs/base/qmlapplicationviewer/qmlapplicationviewer.cpp b/share/qbs/imports/qbs/base/qmlapplicationviewer/qmlapplicationviewer.cpp
new file mode 100644
index 000000000..997bbfcc7
--- /dev/null
+++ b/share/qbs/imports/qbs/base/qmlapplicationviewer/qmlapplicationviewer.cpp
@@ -0,0 +1,174 @@
+// checksum 0xee24 version 0x70013
+/*
+ This file was generated by the Qt Quick Application wizard of Qt Creator.
+ QmlApplicationViewer is a convenience class containing mobile device specific
+ code such as screen orientation handling. Also QML paths and debugging are
+ handled here.
+ It is recommended not to modify this file, since newer versions of Qt Creator
+ may offer an updated version of it.
+*/
+
+#include "qmlapplicationviewer.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtGui/QApplication>
+#include <QtDeclarative/QDeclarativeComponent>
+#include <QtDeclarative/QDeclarativeEngine>
+#include <QtDeclarative/QDeclarativeContext>
+
+#include <qplatformdefs.h> // MEEGO_EDITION_HARMATTAN
+
+#ifdef HARMATTAN_BOOSTER
+#include <MDeclarativeCache>
+#endif
+
+#if defined(QMLJSDEBUGGER) && QT_VERSION < 0x040800
+
+#include <qt_private/qdeclarativedebughelper_p.h>
+
+#if !defined(NO_JSDEBUGGER)
+#include <jsdebuggeragent.h>
+#endif
+#if !defined(NO_QMLOBSERVER)
+#include <qdeclarativeviewobserver.h>
+#endif
+
+// Enable debugging before any QDeclarativeEngine is created
+struct QmlJsDebuggingEnabler
+{
+ QmlJsDebuggingEnabler()
+ {
+ QDeclarativeDebugHelper::enableDebugging();
+ }
+};
+
+// Execute code in constructor before first QDeclarativeEngine is instantiated
+static QmlJsDebuggingEnabler enableDebuggingHelper;
+
+#endif // QMLJSDEBUGGER
+
+class QmlApplicationViewerPrivate
+{
+ QString mainQmlFile;
+ friend class QmlApplicationViewer;
+ static QString adjustPath(const QString &path);
+};
+
+QString QmlApplicationViewerPrivate::adjustPath(const QString &path)
+{
+#ifdef Q_OS_UNIX
+#ifdef Q_OS_MAC
+ if (!QDir::isAbsolutePath(path))
+ return QString::fromLatin1("%1/../Resources/%2")
+ .arg(QCoreApplication::applicationDirPath(), path);
+#else
+ const QString pathInInstallDir =
+ QString::fromLatin1("%1/../%2").arg(QCoreApplication::applicationDirPath(), path);
+ if (QFileInfo(pathInInstallDir).exists())
+ return pathInInstallDir;
+#endif
+#endif
+ return path;
+}
+
+QmlApplicationViewer::QmlApplicationViewer(QWidget *parent)
+ : QDeclarativeView(parent)
+ , d(new QmlApplicationViewerPrivate())
+{
+ connect(engine(), SIGNAL(quit()), SLOT(close()));
+ setResizeMode(QDeclarativeView::SizeRootObjectToView);
+ // Qt versions prior to 4.8.0 don't have QML/JS debugging services built in
+#if defined(QMLJSDEBUGGER) && QT_VERSION < 0x040800
+#if !defined(NO_JSDEBUGGER)
+ new QmlJSDebugger::JSDebuggerAgent(engine());
+#endif
+#if !defined(NO_QMLOBSERVER)
+ new QmlJSDebugger::QDeclarativeViewObserver(this, this);
+#endif
+#endif
+}
+
+QmlApplicationViewer::~QmlApplicationViewer()
+{
+ delete d;
+}
+
+QmlApplicationViewer *QmlApplicationViewer::create()
+{
+ return new QmlApplicationViewer();
+}
+
+void QmlApplicationViewer::setMainQmlFile(const QString &file)
+{
+ d->mainQmlFile = QmlApplicationViewerPrivate::adjustPath(file);
+ setSource(QUrl::fromLocalFile(d->mainQmlFile));
+}
+
+void QmlApplicationViewer::addImportPath(const QString &path)
+{
+ engine()->addImportPath(QmlApplicationViewerPrivate::adjustPath(path));
+}
+
+void QmlApplicationViewer::setOrientation(ScreenOrientation orientation)
+{
+#if defined(Q_OS_SYMBIAN)
+ // If the version of Qt on the device is < 4.7.2, that attribute won't work
+ if (orientation != ScreenOrientationAuto) {
+ const QStringList v = QString::fromAscii(qVersion()).split(QLatin1Char('.'));
+ if (v.count() == 3 && (v.at(0).toInt() << 16 | v.at(1).toInt() << 8 | v.at(2).toInt()) < 0x040702) {
+ qWarning("Screen orientation locking only supported with Qt 4.7.2 and above");
+ return;
+ }
+ }
+#endif // Q_OS_SYMBIAN
+
+ Qt::WidgetAttribute attribute;
+ switch (orientation) {
+#if QT_VERSION < 0x040702
+ // Qt < 4.7.2 does not yet have the Qt::WA_*Orientation attributes
+ case ScreenOrientationLockPortrait:
+ attribute = static_cast<Qt::WidgetAttribute>(128);
+ break;
+ case ScreenOrientationLockLandscape:
+ attribute = static_cast<Qt::WidgetAttribute>(129);
+ break;
+ default:
+ case ScreenOrientationAuto:
+ attribute = static_cast<Qt::WidgetAttribute>(130);
+ break;
+#else // QT_VERSION < 0x040702
+ case ScreenOrientationLockPortrait:
+ attribute = Qt::WA_LockPortraitOrientation;
+ break;
+ case ScreenOrientationLockLandscape:
+ attribute = Qt::WA_LockLandscapeOrientation;
+ break;
+ default:
+ case ScreenOrientationAuto:
+ attribute = Qt::WA_AutoOrientation;
+ break;
+#endif // QT_VERSION < 0x040702
+ };
+ setAttribute(attribute, true);
+}
+
+void QmlApplicationViewer::showExpanded()
+{
+#if defined(Q_OS_SYMBIAN) || defined(MEEGO_EDITION_HARMATTAN) || defined(Q_WS_SIMULATOR)
+ showFullScreen();
+#elif defined(Q_WS_MAEMO_5)
+ showMaximized();
+#else
+ show();
+#endif
+}
+
+QApplication *createApplication(int &argc, char **argv)
+{
+#ifdef HARMATTAN_BOOSTER
+ return MDeclarativeCache::qApplication(argc, argv);
+#else
+ return new QApplication(argc, argv);
+#endif
+}
diff --git a/share/qbs/imports/qbs/base/qmlapplicationviewer/qmlapplicationviewer.h b/share/qbs/imports/qbs/base/qmlapplicationviewer/qmlapplicationviewer.h
new file mode 100644
index 000000000..b01cc886f
--- /dev/null
+++ b/share/qbs/imports/qbs/base/qmlapplicationviewer/qmlapplicationviewer.h
@@ -0,0 +1,46 @@
+// checksum 0x898f version 0x70013
+/*
+ This file was generated by the Qt Quick Application wizard of Qt Creator.
+ QmlApplicationViewer is a convenience class containing mobile device specific
+ code such as screen orientation handling. Also QML paths and debugging are
+ handled here.
+ It is recommended not to modify this file, since newer versions of Qt Creator
+ may offer an updated version of it.
+*/
+
+#ifndef QMLAPPLICATIONVIEWER_H
+#define QMLAPPLICATIONVIEWER_H
+
+#include <QtDeclarative/QDeclarativeView>
+
+class QmlApplicationViewer : public QDeclarativeView
+{
+ Q_OBJECT
+
+public:
+ enum ScreenOrientation {
+ ScreenOrientationLockPortrait,
+ ScreenOrientationLockLandscape,
+ ScreenOrientationAuto
+ };
+
+ explicit QmlApplicationViewer(QWidget *parent = 0);
+ virtual ~QmlApplicationViewer();
+
+ static QmlApplicationViewer *create();
+
+ void setMainQmlFile(const QString &file);
+ void addImportPath(const QString &path);
+
+ // Note that this will only have an effect on Symbian and Fremantle.
+ void setOrientation(ScreenOrientation orientation);
+
+ void showExpanded();
+
+private:
+ class QmlApplicationViewerPrivate *d;
+};
+
+QApplication *createApplication(int &argc, char **argv);
+
+#endif // QMLAPPLICATIONVIEWER_H
diff --git a/share/qbs/imports/qbs/fileinfo/fileinfo.js b/share/qbs/imports/qbs/fileinfo/fileinfo.js
new file mode 100644
index 000000000..b65e4073c
--- /dev/null
+++ b/share/qbs/imports/qbs/fileinfo/fileinfo.js
@@ -0,0 +1,62 @@
+function path(fp) {
+ if (fp[fp.length -1] == '/')
+ return fp;
+ var last = fp.lastIndexOf('/');
+ if (last < 0)
+ return '.';
+ return fp.slice(0, last);
+}
+
+function fileName(fph) {
+ var fp = fph.toString();
+ if (fp[fp.length -1] == '/')
+ return fp;
+ var last = fp.lastIndexOf('/');
+ if (last < 0)
+ return '.';
+ return fp.slice(last + 1);
+}
+
+function baseName(fph) {
+ var fn = fileName(fph);
+ return fn.split('.')[0];
+}
+
+function relativePath(base, rel)
+{
+ var basel = base.split('/');
+ var rell = rel.split('/');
+ var i = 0;
+
+ while (i < basel.length && i < rell.length && basel[i] == rell[i])
+ i++;
+
+ var j = i;
+ var r = [];
+
+ for (; i < basel.length; i++)
+ r.push('..');
+
+ for (; j < rell.length; j++)
+ r.push(rell[j]);
+
+ return r.join('/');
+}
+
+function isAbsolutePath(path)
+{
+ if (!path)
+ return false;
+ return (path.charAt(0) == '/');
+}
+
+function toWindowsSeparators(str)
+{
+ return str.toString().replace(/\//g, '\\');
+}
+
+function fromWindowsSeparators(str)
+{
+ return str.toString().replace(/\\/g, '/');
+}
+
diff --git a/share/qbs/modules/cpp/CppModule.qbs b/share/qbs/modules/cpp/CppModule.qbs
new file mode 100644
index 000000000..f4204dad1
--- /dev/null
+++ b/share/qbs/modules/cpp/CppModule.qbs
@@ -0,0 +1,75 @@
+// base for Cpp modules
+
+Module {
+ condition: false
+ additionalProductFileTags: ["hpp"] // to include all rules that generate hpp files
+
+ property string warningLevel : 'all' // 'none', 'all'
+ property bool treatWarningsAsErrors : false
+ property string architecture: qbs.architecture
+ property string optimization: qbs.optimization
+ property bool debugInformation: qbs.debugInformation
+ property string precompiledHeader
+ property paths precompiledHeaderDir: [product.buildDirectory]
+ property var defines
+ property paths includePaths
+ property paths libraryPaths
+ property paths frameworkPaths
+ property var compilerFlags
+ property string compilerPath
+ // ### same separation in msvc?
+ property var dynamicLibraries // list of names, will be linked with -lname
+ property var staticLibraries // list of static library files
+ property var frameworks // list of frameworks, will be linked with '-framework <name>'
+ property var rpaths
+
+ FileTagger {
+ pattern: "*.c"
+ fileTags: ["c"]
+ }
+
+ FileTagger {
+ pattern: "*.C"
+ fileTags: ["c"]
+ }
+
+ FileTagger {
+ pattern: "*.cpp"
+ fileTags: ["cpp"]
+ }
+
+ FileTagger {
+ pattern: "*.cxx"
+ fileTags: ["cpp"]
+ }
+
+ FileTagger {
+ pattern: "*.c++"
+ fileTags: ["cpp"]
+ }
+
+ FileTagger {
+ pattern: "*.h"
+ fileTags: ["hpp"]
+ }
+
+ FileTagger {
+ pattern: "*.H"
+ fileTags: ["hpp"]
+ }
+
+ FileTagger {
+ pattern: "*.hpp"
+ fileTags: ["hpp"]
+ }
+
+ FileTagger {
+ pattern: "*.hxx"
+ fileTags: ["hpp"]
+ }
+
+ FileTagger {
+ pattern: "*.h++"
+ fileTags: ["hpp"]
+ }
+}
diff --git a/share/qbs/modules/cpp/GenericGCC.qbs b/share/qbs/modules/cpp/GenericGCC.qbs
new file mode 100644
index 000000000..14ee2753f
--- /dev/null
+++ b/share/qbs/modules/cpp/GenericGCC.qbs
@@ -0,0 +1,300 @@
+import qbs.base 1.0
+import qbs.fileinfo 1.0 as FileInfo
+import 'gcc.js' as Gcc
+import '../utils.js' as ModUtils
+
+CppModule {
+ condition: false
+
+ property var transitiveSOs
+ property string toolchainPrefix
+ property string toolchainInstallPath
+ property string compilerName: 'g++'
+
+ property string compilerPath: {
+ var path = ''
+ if (toolchainInstallPath) {
+ path += toolchainInstallPath
+ if (path.substr(-1) !== '/')
+ path += '/'
+ }
+ if (toolchainPrefix)
+ path += toolchainPrefix
+ path += compilerName
+ return path
+ }
+
+ Rule {
+ id: dynamicLibraryLinker
+ multiplex: true
+ inputs: ["obj"]
+ usings: ['dynamiclibrary', 'staticlibrary']
+
+ Artifact {
+ fileName: product.destinationDirectory + "/lib" + product.name + ".so"
+ fileTags: ["dynamiclibrary"]
+ cpp.transitiveSOs: {
+ var result = []
+ for (var i in inputs.dynamiclibrary) {
+ var lib = inputs.dynamiclibrary[i]
+ result.push(lib.fileName)
+ var impliedLibs = ModUtils.appendAll(lib, 'transitiveSOs')
+ result = result.concat(impliedLibs)
+ }
+ return result
+ }
+ }
+
+ TransformProperties {
+ property var libraryPaths: ModUtils.appendAll(product, 'libraryPaths')
+ property var dynamicLibraries: ModUtils.appendAll(product, 'dynamicLibraries')
+ property var staticLibraries: ModUtils.appendAll(product, 'staticLibraries')
+ property var rpaths: ModUtils.appendAll(product, 'rpaths')
+ }
+
+ prepare: {
+ var args = Gcc.configFlags(product);
+ if (product.modules.qbs.targetOS == 'linux')
+ args = args.concat([
+ '-Wl,--hash-style=gnu',
+ '-Wl,--as-needed',
+ '-Wl,--allow-shlib-undefined',
+ '-Wl,--no-undefined',
+ '-Wl,-soname=' + FileInfo.fileName(output.fileName)
+ ]);
+ args = args.concat([
+ '-Wl,-rpath,\$ORIGIN',
+ '-shared'
+ ]);
+ for (var i in inputs.obj)
+ args.push(inputs.obj[i].fileName);
+
+ var staticLibrariesI = [];
+ for (i in inputs.staticlibrary) {
+ staticLibrariesI.push(inputs.staticlibrary[i].fileName);
+ }
+ staticLibrariesI = staticLibrariesI.concat(staticLibraries);
+
+ var dynamicLibrariesI = [];
+ for (i in inputs.dynamiclibrary) {
+ libraryPaths.push(FileInfo.path(inputs.dynamiclibrary[i].fileName))
+ var fileName = FileInfo.fileName(inputs.dynamiclibrary[i].fileName)
+ fileName = fileName.substr(3, fileName.length - 6)
+ dynamicLibrariesI.push(fileName)
+ }
+ dynamicLibrariesI = dynamicLibrariesI.concat(dynamicLibraries);
+
+ args.push('-o');
+ args.push(output.fileName);
+ args = args.concat(Gcc.libs(libraryPaths, rpaths, dynamicLibrariesI, staticLibrariesI));
+ var cmd = new Command(product.module.compilerPath, args);
+ Gcc.linkEnv(cmd)
+ cmd.description = 'linking ' + FileInfo.fileName(output.fileName);
+ cmd.highlight = 'linker';
+ return cmd;
+ }
+ }
+
+ Rule {
+ id: staticLibraryLinker
+ multiplex: true
+ inputs: ["obj"]
+ usings: ['dynamiclibrary', 'staticlibrary']
+
+ Artifact {
+ fileName: product.destinationDirectory + "/lib" + product.name + ".a"
+ fileTags: ["staticlibrary"]
+ cpp.staticLibraries: {
+ var result = []
+ for (var i in inputs.staticlibrary) {
+ var lib = inputs.staticlibrary[i]
+ result.push(lib.fileName)
+ var impliedLibs = ModUtils.appendAll(lib, 'staticLibraries')
+ result.concat(impliedLibs)
+ }
+ return result
+ }
+ cpp.dynamicLibraries: {
+ var result = []
+ for (var i in inputs.dynamiclibrary) {
+ var lib = inputs.dynamiclibrary[i]
+ result.push(lib.fileName)
+ var impliedLibs = ModUtils.appendAll(lib, 'dynamicLibraries')
+ result.concat(impliedLibs)
+ }
+ return result
+ }
+ }
+
+ prepare: {
+ var args = ['rcs', output.fileName];
+ for (var i in inputs.obj)
+ args.push(inputs.obj[i].fileName);
+ var cmd = new Command('ar', args);
+ cmd.description = 'creating ' + FileInfo.fileName(output.fileName);
+ cmd.highlight = 'linker'
+ return cmd;
+ }
+ }
+
+ Rule {
+ id: applicationLinker
+ multiplex: true
+ inputs: ["obj"]
+ usings: ['dynamiclibrary', 'staticlibrary']
+
+ Artifact {
+ fileName: product.destinationDirectory + "/" + product.name
+ fileTags: ["application"]
+ }
+
+ TransformProperties {
+ property var libraryPaths: ModUtils.appendAll(product, 'libraryPaths')
+ property var dynamicLibraries: ModUtils.appendAllFromArtifacts(product, inputs.dynamiclibrary, 'cpp', 'dynamicLibraries')
+ property var staticLibraries: ModUtils.appendAllFromArtifacts(product, inputs.staticlibrary, 'cpp', 'staticLibraries')
+ property var rpaths: ModUtils.appendAll(product, 'rpaths')
+ }
+
+ prepare: {
+ var args = Gcc.configFlags(product);
+ for (var i in inputs.obj)
+ args.push(inputs.obj[i].fileName)
+ args.push('-Wl,-rpath,\$ORIGIN');
+ args.push('-o');
+ args.push(output.fileName);
+
+ var staticLibrariesI = [];
+ for (i in inputs.staticlibrary) {
+ staticLibrariesI.push(inputs.staticlibrary[i].fileName);
+ }
+ staticLibrariesI = staticLibrariesI.concat(staticLibraries);
+
+ var dynamicLibrariesI = [];
+ for (i in dynamicLibraries) {
+ if (dynamicLibraries[i].match("lib.*\\.so$") != null) {
+ // shared object filename found
+ var libDir = FileInfo.path(dynamicLibraries[i])
+ var libName = FileInfo.fileName(dynamicLibraries[i])
+ libName = libName.substr(3, libName.length - 6)
+ libraryPaths.push(libDir)
+ dynamicLibrariesI.push(libName)
+ } else {
+ // shared object libname found
+ dynamicLibrariesI.push(dynamicLibraries[i])
+ }
+ }
+
+ if (product.modules.qbs.targetOS === 'linux') {
+ var transitiveSOs = ModUtils.appendAllFromArtifacts(product, inputs.dynamiclibrary, 'cpp', 'transitiveSOs')
+ for (i in transitiveSOs) {
+ args.push("-Wl,-rpath-link=" + FileInfo.path(transitiveSOs[i]))
+ }
+ }
+
+ for (i in inputs.dynamiclibrary) {
+ libraryPaths.push(FileInfo.path(inputs.dynamiclibrary[i].fileName))
+ var fileName = FileInfo.fileName(inputs.dynamiclibrary[i].fileName)
+ fileName = fileName.substr(3, fileName.length - 6)
+ dynamicLibrariesI.push(fileName)
+ }
+
+ args = args.concat(Gcc.libs(libraryPaths, rpaths, dynamicLibrariesI, staticLibrariesI));
+ var cmd = new Command(product.module.compilerPath, args);
+ Gcc.linkEnv(cmd, product)
+ cmd.description = 'linking ' + FileInfo.fileName(output.fileName);
+ cmd.highlight = 'linker'
+ return cmd;
+ }
+ }
+
+ Rule {
+ id: compiler
+ inputs: ["cpp", "c"]
+ explicitlyDependsOn: ["c++_pch"]
+
+ Artifact {
+ fileTags: ["obj"]
+ // ### make it possible to override ".obj" in a project file
+ fileName: ".obj/" + product.name + "/" + input.baseDir + "/" + input.baseName + ".o"
+ }
+
+ TransformProperties {
+ property var defines: ModUtils.appendAll(input, 'defines')
+ property var includePaths: ModUtils.appendAll(input, 'includePaths')
+ property var compilerFlags: ModUtils.appendAll(input, 'compilerFlags')
+ }
+
+ prepare: {
+ var args = Gcc.configFlags(input);
+
+ // ### what we actually need here is something like product.usedFileTags
+ // that contains all fileTags that have been used when applying the rules.
+ if (product.type.indexOf('staticlibrary') >= 0 || product.type.indexOf('dynamiclibrary') >= 0) {
+ args.push('-fPIC');
+ } else if (product.type.indexOf('application') < 0) {
+ throw ("OK, now we got a problem... The product's type must be in {staticlibrary, dynamiclibrary, application}. But it is " + product.type + '.');
+ }
+
+ for (var i in defines)
+ args.push('-D' + defines[i]);
+ for (var i in includePaths)
+ args.push('-I' + includePaths[i]);
+ if (product.module.precompiledHeader) {
+ args.push('-include')
+ args.push(product.name)
+ var pchPath = product.module.precompiledHeaderDir[0]
+ var pchPathIncluded = false
+ for (var i in includePaths) {
+ if (includePaths[i] == pchPath) {
+ pchPathIncluded = true
+ break
+ }
+ }
+ if (!pchPathIncluded)
+ args.push('-I' + pchPath)
+ }
+ if (input.fileTags.indexOf("c") >= 0) {
+ args.push('-x')
+ args.push('c')
+ }
+ args.push('-c');
+ args.push(input.fileName);
+ args.push('-o');
+ args.push(output.fileName);
+ args = args.concat(compilerFlags);
+ var cmd = new Command(product.module.compilerPath, args);
+ cmd.description = 'compiling ';
+ Gcc.describe(cmd, input.fileName, output.fileName);
+ cmd.highlight = "compiler";
+ return cmd;
+ }
+ }
+
+ Transformer {
+ condition: precompiledHeader != null
+ inputs: precompiledHeader
+ Artifact {
+ fileName: product.name + ".gch"
+ fileTags: "c++_pch"
+ }
+ prepare: {
+ var args = Gcc.configFlags(product);
+ for (var i in product.module.defines)
+ args.push('-D' + defines[i]);
+ for (var i in product.module.includePaths)
+ args.push('-I' + includePaths[i]);
+ args.push('-x');
+ args.push('c++-header');
+ args.push('-c');
+ args.push(product.module.precompiledHeader);
+ args.push('-o');
+ args.push(output.fileName);
+ if (product.module.compilerFlags)
+ args = args.concat(product.module.compilerFlags);
+ var cmd = new Command(product.module.compilerPath, args);
+ cmd.description = 'precompiling ' + FileInfo.fileName(input.fileName);
+ return cmd;
+ }
+ }
+}
+
diff --git a/share/qbs/modules/cpp/gcc.js b/share/qbs/modules/cpp/gcc.js
new file mode 100644
index 000000000..a4155ad9b
--- /dev/null
+++ b/share/qbs/modules/cpp/gcc.js
@@ -0,0 +1,113 @@
+function collectDynamicLinkPaths(config) {
+ var paths = []
+
+ var linkProducts = config.linkProducts || []
+ for (var libPath in linkProducts) {
+ var linkedConfig = linkProducts[libPath]
+ var fileTags = linkedConfig['fileTags']
+ if (fileTags.indexOf('dynamiclibrary') >= 0) {
+ paths.push(FileInfo.path(libPath))
+ paths = paths.concat(collectDynamicLinkPaths(linkedConfig))
+ }
+ }
+ return paths
+}
+
+function linkEnv(cmd) {
+ // ### setup LD_LIBRARY_PATH for ProductModule dynamiclibrary depends
+// var paths = []
+// for (var i in config.linkProducts) {
+// var linkedConfig = config.linkProducts[i]
+// var fileTags = linkedConfig['fileTags']
+// if (fileTags.indexOf('dynamiclibrary') >= 0) {
+// paths = paths.concat(collectDynamicLinkPaths(linkedConfig))
+// }
+// }
+
+// if (paths.length) {
+// var envdef = newEnvironmentDefinition("LD_LIBRARY_PATH")
+// envdef.pathNames = true
+// envdef.separator = ':'
+// envdef.prepend = paths
+// cmd.addEnvironmentDefinition(envdef)
+// }
+}
+
+function libs(libraryPaths, rpaths, dynamicLibraries, staticLibraries) {
+
+ var args = [];
+ if (rpaths && rpaths.length)
+ args.push('-Wl,-rpath,' + rpaths.join(':'));
+ for (var i in libraryPaths) {
+ args.push('-L' + libraryPaths[i]);
+ }
+ for (var i in staticLibraries) {
+ args.push(staticLibraries[i]);
+ }
+ for (var i in dynamicLibraries) {
+ if (FileInfo.isAbsolutePath(dynamicLibraries[i])) {
+ args.push(dynamicLibraries[i]);
+ } else {
+ args.push('-l' + dynamicLibraries[i]);
+ }
+ }
+ return args;
+}
+
+function macLibs(libraryPaths, rpaths, dynamicLibraries, staticLibraries, frameworks)
+{
+ var args = libs(libraryPaths, rpaths, dynamicLibraries, staticLibraries);
+ for (var i in libraryPaths) {
+ args.push('-F' + libraryPaths[i]);
+ }
+ for (var i in frameworks) {
+ args.push('-framework');
+ args.push(frameworks[i]);
+ }
+ return args;
+}
+
+function configFlags(config) {
+ var args = [];
+ // optimization:
+ if (config.module.debugInformation === 'on')
+ args.push('-g');
+ if (config.module.optimization === 'fast')
+ args.push('-O2');
+ if (config.module.optimization === 'small')
+ args.push('-Os');
+ // warnings:
+ if (config.module.warningLevel === 'none')
+ args.push('-w');
+ if (config.module.warningLevel === 'all') {
+ args.push('-Wall');
+ args.push('-W');
+ }
+ if (config.module.treatWarningsAsErrors)
+ args.push('-Werror');
+
+ return args;
+}
+
+function frameworkPaths(config) {
+ var args = [];
+ for (var i in config.frameworkPaths) {
+ args.push('-F' + config.frameworkPaths[i]);
+ }
+ return args;
+}
+
+function frameworks(config) {
+ var args = [];
+ for (var i in config.frameworks) {
+ args.push('-framework');
+ args.push(config.frameworks[i]
+ .replace(/.framework$/,''));
+ }
+ return args;
+}
+
+function describe(cmd, input, output)
+{
+ cmd.description += FileInfo.fileName(input);
+}
diff --git a/share/qbs/modules/cpp/linux-gcc.qbs b/share/qbs/modules/cpp/linux-gcc.qbs
new file mode 100644
index 000000000..ff1827ebb
--- /dev/null
+++ b/share/qbs/modules/cpp/linux-gcc.qbs
@@ -0,0 +1,6 @@
+import qbs.base 1.0
+
+GenericGCC {
+ condition: qbs.hostOS == 'linux' && qbs.targetOS == 'linux' && qbs.toolchain == 'gcc'
+}
+
diff --git a/share/qbs/modules/cpp/mac-gcc.qbs b/share/qbs/modules/cpp/mac-gcc.qbs
new file mode 100644
index 000000000..fda5da3f2
--- /dev/null
+++ b/share/qbs/modules/cpp/mac-gcc.qbs
@@ -0,0 +1,69 @@
+import qbs.base 1.0
+
+GenericGCC {
+ condition: qbs.hostOS == 'mac' && qbs.targetOS == 'mac' && qbs.toolchain == 'gcc'
+
+ Rule {
+ multiplex: true
+ inputs: ["qbs"]
+
+ Artifact {
+ fileName: product.name + ".app/Info.plist"
+ fileTags: ["infoplist"]
+ }
+
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "generating Info.plist";
+ cmd.highlight = "codegen";
+ cmd.sourceCode = function() {
+ var infoplist = new TextFile(outputs.infoplist[0].fileName, TextFile.WriteOnly);
+ infoplist.write("<foobar>");
+ infoplist.close();
+ }
+ return cmd;
+ }
+ }
+
+ Rule {
+ multiplex: true
+ inputs: ["qbs"]
+
+ Artifact {
+ fileName: product.name + ".app/PkgInfo"
+ fileTags: ["pkginfo"]
+ }
+
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "generating PkgInfo";
+ cmd.highlight = "codegen";
+ cmd.sourceCode = function() {
+ var pkginfo = new TextFile(outputs.pkginfo[0].fileName, TextFile.WriteOnly);
+ pkginfo.write("FOO");
+ pkginfo.close();
+ }
+ return cmd;
+ }
+ }
+
+ Rule {
+ multiplex: true
+ inputs: ["application", "infoplist", "pkginfo"]
+
+ Artifact {
+ fileName: product.name + ".app/Contents/MacOS/" + product.name
+ fileTags: ["applicationbundle"]
+ }
+
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "generating app bundle";
+ cmd.highlight = "codegen";
+ cmd.sourceCode = function() {
+ File.copy(inputs.application[0].fileName, outputs.applicationbundle[0].fileName);
+ }
+ return cmd;
+ }
+ }
+}
diff --git a/share/qbs/modules/cpp/msvc.js b/share/qbs/modules/cpp/msvc.js
new file mode 100644
index 000000000..0f306eced
--- /dev/null
+++ b/share/qbs/modules/cpp/msvc.js
@@ -0,0 +1,173 @@
+function prepareCompiler(product, input, outputs, defines, includePaths, compilerFlags)
+{
+ var optimization = input.module.optimization
+ var debugInformation = input.module.debugInformation
+ var architecture = input.module.architecture
+ var toolchainInstallPath = product.module.toolchainInstallPath
+
+ var args = ['/nologo', '/c', '/Zm200', '/Zc:wchar_t-']
+
+ // C or C++
+ if (input.fileTags.indexOf('c') >= 0) {
+ args.push('/TC')
+ }
+
+ // enable unwind semantics
+ args.push("/EHsc")
+ // optimization:
+ if (optimization === 'small')
+ args.push('/Os')
+ else if (optimization === 'fast')
+ args.push('/O2')
+ if (debugInformation) {
+ args.push('/Zi')
+ args.push('/MDd')
+ } else {
+ args.push('/MD')
+ }
+ // warnings:
+ var warningLevel = input.module.warningLevel
+ if (warningLevel === 'none')
+ args.push('/w')
+ if (warningLevel === 'all')
+ args.push('/Wall')
+ for (var i in includePaths)
+ args.push('/I' + FileInfo.toWindowsSeparators(includePaths[i]))
+ for (i in defines)
+ args.push('/D' + defines[i])
+
+ var objOutput = outputs.obj ? outputs.obj[0] : undefined
+ var pchOutput = outputs["c++_pch"] ? outputs["c++_pch"][0] : undefined
+
+ // precompiled header file
+ if (product.module.precompiledHeader) {
+ if (pchOutput) {
+ // create pch
+ args.push('/Yc')
+ args.push('/Fp' + FileInfo.toWindowsSeparators(pchOutput.fileName))
+ args.push('/Fo' + FileInfo.toWindowsSeparators(objOutput.fileName))
+ args.push('/TP')
+ args.push(FileInfo.toWindowsSeparators(input.fileName))
+ } else {
+ // use pch
+ var pchHeaderName = FileInfo.toWindowsSeparators(product.module.precompiledHeader)
+ var pchName = FileInfo.toWindowsSeparators(product.module.precompiledHeaderDir[0] + "\\.obj\\" + product.name + "\\" + product.name + ".pch")
+ args.push("/FI" + pchHeaderName)
+ args.push("/Yu" + pchHeaderName)
+ args.push("/Fp" + pchName)
+ }
+ }
+ args.push('/Fo' + FileInfo.toWindowsSeparators(objOutput.fileName))
+ args.push(FileInfo.toWindowsSeparators(input.fileName))
+
+ var clPath = toolchainInstallPath + '/VC/bin/'
+ var is64bit = (architecture === "x86_64")
+ if (is64bit)
+ clPath += 'amd64/'
+ clPath += 'cl.exe'
+
+ for (var i in compilerFlags) {
+ args.push(i)
+ }
+
+ var cmd = new Command(clPath, args)
+ cmd.description = (pchOutput ? 'pre' : '') + 'compiling ' + FileInfo.fileName(input.fileName)
+ cmd.highlight = "compiler";
+ cmd.workingDirectory = FileInfo.path(objOutput.fileName)
+ cmd.responseFileThreshold = product.module.responseFileThreshold
+ cmd.responseFileUsagePrefix = '@';
+ // cl.exe outputs the cpp file name. We filter that out.
+ cmd.stdoutFilterFunction = "function(output) {";
+ cmd.stdoutFilterFunction += "return output.replace('" + FileInfo.fileName(input.fileName) + "\\r\\n', '');";
+ cmd.stdoutFilterFunction += "}";
+ return cmd;
+}
+
+function prepareLinker(product, inputs, outputs, libraryPaths, dynamicLibraries, staticLibraries)
+{
+ var linkDLL = (outputs.dynamiclibrary ? true : false)
+ var primaryOutput = (linkDLL ? outputs.dynamiclibrary[0] : outputs.application[0])
+ var optimization = product.module.optimization
+ var debugInformation = product.module.debugInformation
+ var architecture = product.module.architecture
+ var windowsSDKPath = product.module.windowsSDKPath
+ var generateManifestFiles = !linkDLL && product.module.generateManifestFiles
+ var toolchainInstallPath = product.module.toolchainInstallPath
+
+ var args = ['/nologo']
+ if (linkDLL) {
+ args.push('/DLL');
+ args.push('/IMPLIB:' + FileInfo.toWindowsSeparators(outputs.dynamiclibrary_import[0].fileName));
+ }
+
+ if (debugInformation)
+ args.push('/DEBUG')
+ else
+ args.push('/INCREMENTAL:NO')
+
+ var manifestFileName
+ if (generateManifestFiles) {
+ manifestFileName = FileInfo.toWindowsSeparators(primaryOutput.fileName)
+ manifestFileName += '.intermediate.manifest'
+ args.push('/MANIFEST', '/MANIFESTFILE:' + manifestFileName)
+ }
+
+ var allInputs = inputs.obj.concat(inputs.staticlibrary || [])
+ if (inputs.dynamiclibrary_import)
+ allInputs = inputs.obj.concat(inputs.dynamiclibrary_import)
+ for (var i in allInputs) {
+ var fileName = FileInfo.toWindowsSeparators(allInputs[i].fileName)
+ args.push(fileName)
+ }
+ for (var i in staticLibraries) {
+ var staticLibrary = staticLibraries[i];
+ if (!staticLibrary.match(/\.lib$/i))
+ staticLibrary += ".lib";
+ args.push(staticLibrary)
+ }
+ for (var i in dynamicLibraries) {
+ var dynamicLibrary = dynamicLibraries[i];
+ if (!dynamicLibrary.match(/\.lib$/i))
+ dynamicLibrary += ".lib";
+ args.push(dynamicLibrary)
+ }
+
+ var nativeOutputFileName = FileInfo.toWindowsSeparators(primaryOutput.fileName)
+ args.push('/OUT:' + nativeOutputFileName)
+ for (var i in libraryPaths) {
+ args.push('/LIBPATH:' + FileInfo.toWindowsSeparators(libraryPaths[i]))
+ }
+ args = args.concat(dynamicLibraries)
+ var is64bit = (architecture == "x86_64")
+
+ var linkerPath = toolchainInstallPath + '/VC/bin/'
+ if (is64bit)
+ linkerPath += 'amd64/'
+ linkerPath += 'link.exe'
+
+ var commands = [];
+ var cmd = new Command(linkerPath, args)
+ cmd.description = 'linking ' + FileInfo.fileName(primaryOutput.fileName)
+ cmd.highlight = 'linker';
+ cmd.workingDirectory = FileInfo.path(primaryOutput.fileName)
+ cmd.responseFileThreshold = product.module.responseFileThreshold
+ cmd.responseFileUsagePrefix = '@';
+ commands.push(cmd);
+
+ if (generateManifestFiles) {
+ // embed the generated manifest files
+ var args = [
+ '/nologo', '/manifest', manifestFileName,
+ '/outputresource:' + nativeOutputFileName + ';1'
+ ]
+ var mtPath = windowsSDKPath + '/bin/mt.exe'
+ var cmd = new Command(mtPath, args)
+ cmd.description = 'embedding manifest into ' + FileInfo.fileName(primaryOutput.fileName)
+ cmd.highlight = 'linker';
+ cmd.workingDirectory = FileInfo.path(primaryOutput.fileName)
+ commands.push(cmd);
+ }
+
+ return commands;
+}
+
diff --git a/share/qbs/modules/cpp/ponyphone.qbs b/share/qbs/modules/cpp/ponyphone.qbs
new file mode 100644
index 000000000..e7ea9dfe4
--- /dev/null
+++ b/share/qbs/modules/cpp/ponyphone.qbs
@@ -0,0 +1,28 @@
+/*
+ Giddyup, pony pony pony!
+
+ How to setup this crazy horsey platform?
+ - install the pony SDK
+ - call the following
+ qbs config --global ponyphone/substitute theLittlePrancingPony
+ qbs config --global ponyphone/sdkInstallPath ~/theLittlePrancingPonySDK
+ - stand up and sing the Mr. Ed theme song!
+*/
+
+import qbs.base 1.0
+
+GenericGCC {
+ property string substitute: qbs.configurationValue('ponyphone/substitute')
+
+ condition: qbs.hostOS == 'linux' && qbs.targetOS == 'linux' && qbs.toolchain == 'gcc' && qbs.platform == 'ponyphone'
+
+ toolchainPrefix: {
+ if (architecture == 'i586')
+ return architecture + '-' + substitute + '-linux-'
+ else if (architecture == 'armv7hl')
+ return architecture + '-' + substitute + '-linux-gnueabi-'
+ throw "unknown target architecture: " + architecture
+ }
+ toolchainInstallPath: qbs.configurationValue('ponyphone/sdkInstallPath') + "/" + substitute + "/" + architecture + "/toolchain/bin"
+}
+
diff --git a/share/qbs/modules/cpp/windows-msvc.qbs b/share/qbs/modules/cpp/windows-msvc.qbs
new file mode 100644
index 000000000..535df9491
--- /dev/null
+++ b/share/qbs/modules/cpp/windows-msvc.qbs
@@ -0,0 +1,199 @@
+import qbs.base 1.0
+import qbs.fileinfo 1.0 as FileInfo
+import '../utils.js' as ModUtils
+import 'msvc.js' as MSVC
+
+CppModule {
+ condition: qbs.hostOS == 'windows' && qbs.targetOS == 'windows' && qbs.toolchain == 'msvc'
+
+ id: module
+
+ defines: ['UNICODE', 'WIN32']
+ warningLevel: "default"
+
+ property bool generateManifestFiles: true
+ property string toolchainInstallPath: "UNKNOWN"
+ property string windowsSDKPath: "UNKNOWN"
+ property string architecture: "x86"
+ property int responseFileThreshold: 32000
+
+ setupBuildEnvironment: {
+ var v = new ModUtils.EnvironmentVariable("INCLUDE", ";", true)
+ v.prepend(toolchainInstallPath + "/VC/ATLMFC/INCLUDE")
+ v.prepend(toolchainInstallPath + "/VC/INCLUDE")
+ v.prepend(windowsSDKPath + "/include")
+ v.set()
+
+ if (architecture == 'x86') {
+ v = new ModUtils.EnvironmentVariable("PATH", ";", true)
+ v.prepend(toolchainInstallPath + "/Common7/IDE")
+ v.prepend(toolchainInstallPath + "/VC/bin")
+ v.prepend(toolchainInstallPath + "/Common7/Tools")
+ v.set()
+
+ v = new ModUtils.EnvironmentVariable("LIB", ";", true)
+ v.prepend(toolchainInstallPath + "/VC/ATLMFC/LIB")
+ v.prepend(toolchainInstallPath + "/VC/LIB")
+ v.prepend(windowsSDKPath + "/lib")
+ v.set()
+ } else if (architecture == 'x86_64') {
+ v = new ModUtils.EnvironmentVariable("PATH", ";", true)
+ v.prepend(toolchainInstallPath + "/Common7/IDE")
+ v.prepend(toolchainInstallPath + "/VC/bin/amd64")
+ v.prepend(toolchainInstallPath + "/Common7/Tools")
+ v.set()
+
+ v = new ModUtils.EnvironmentVariable("LIB", ";", true)
+ v.prepend(toolchainInstallPath + "/VC/ATLMFC/LIB/amd64")
+ v.prepend(toolchainInstallPath + "/VC/LIB/amd64")
+ v.prepend(windowsSDKPath + "/lib/x64")
+ v.set()
+ }
+ }
+
+ Artifact {
+ // This adds the filename in precompiledHeader to the set of source files.
+ // If its already in there, then this makes sure it has the right file tag.
+ condition: precompiledHeader != null
+ fileName: precompiledHeader
+ fileTags: ["hpp_pch"]
+ }
+
+ Rule {
+ id: pchCompiler
+ inputs: ["hpp_pch"]
+ Artifact {
+ fileTags: ['obj']
+ // ### make the object file dir overridable
+ fileName: ".obj/" + product.name + "/" + input.baseName + '.obj'
+ }
+ Artifact {
+ fileTags: ['c++_pch']
+ // ### make the object file dir overridable
+ fileName: ".obj/" + product.name + "/" + product.name + '.pch'
+ }
+ TransformProperties {
+ property var defines: ModUtils.appendAll(input, 'defines')
+ property var includePaths: ModUtils.appendAll(input, 'includePaths')
+ property var compilerFlags: ModUtils.appendAll(input, 'compilerFlags')
+ }
+ prepare: {
+ return MSVC.prepareCompiler(product, input, outputs)
+ }
+ }
+
+ Rule {
+ id: compiler
+ inputs: ["cpp", "c"]
+ explicitlyDependsOn: ["c++_pch"]
+ Artifact {
+ fileTags: ['obj']
+ // ### make the object file dir overridable
+ fileName: ".obj/" + product.name + "/" + input.baseDir + "/" + input.baseName + ".obj"
+ }
+
+ TransformProperties {
+ property var defines: ModUtils.appendAll(input, 'defines')
+ property var includePaths: ModUtils.appendAll(input, 'includePaths')
+ property var compilerFlags: ModUtils.appendAll(input, 'compilerFlags')
+ }
+
+ prepare: {
+ return MSVC.prepareCompiler(product, input, outputs, defines, includePaths, compilerFlags)
+ }
+ }
+
+ Rule {
+ id: applicationLinker
+ multiplex: true
+ inputs: ['obj']
+ usings: ['staticlibrary', 'dynamiclibrary_import']
+ Artifact {
+ fileTags: ["application"]
+ fileName: product.destinationDirectory + "/" + product.name + ".exe"
+ }
+
+ TransformProperties {
+ property var libraryPaths: ModUtils.appendAll(product, 'libraryPaths')
+ property var dynamicLibraries: ModUtils.appendAllFromArtifacts(product, inputs.dynamiclibrary_import, 'cpp', 'dynamicLibraries')
+ property var staticLibraries: ModUtils.appendAllFromArtifacts(product, (inputs.staticlibrary || []).concat(inputs.obj), 'cpp', 'staticLibraries')
+ }
+
+ prepare: {
+ return MSVC.prepareLinker(product, inputs, outputs, libraryPaths, dynamicLibraries, staticLibraries)
+ }
+ }
+
+ Rule {
+ id: dynamicLibraryLinker
+ multiplex: true
+ inputs: ['obj']
+ usings: ['staticlibrary', 'dynamiclibrary_import']
+
+ Artifact {
+ fileTags: ["dynamiclibrary"]
+ fileName: product.destinationDirectory + "/" + product.name + ".dll"
+ }
+
+ Artifact {
+ fileTags: ["dynamiclibrary_import"]
+ fileName: product.destinationDirectory + "/" + product.name + "_imp.lib"
+ }
+
+ TransformProperties {
+ property var libraryPaths: ModUtils.appendAll(product, 'libraryPaths')
+ property var dynamicLibraries: ModUtils.appendAll(product, 'dynamicLibraries')
+ property var staticLibraries: ModUtils.appendAllFromArtifacts(product, (inputs.staticlibrary || []).concat(inputs.obj), 'cpp', 'staticLibraries')
+ }
+
+ prepare: {
+ return MSVC.prepareLinker(product, inputs, outputs, libraryPaths, dynamicLibraries, staticLibraries)
+ }
+ }
+
+ Rule {
+ id: libtool
+ multiplex: true
+ inputs: ["obj"]
+ usings: ["staticlibrary"]
+
+ Artifact {
+ fileTags: ["staticlibrary"]
+ fileName: product.destinationDirectory + "/" + product.name + ".lib"
+ cpp.staticLibraries: {
+ var result = []
+ for (var i in inputs.staticlibrary) {
+ var lib = inputs.staticlibrary[i]
+ result.push(lib.fileName)
+ var impliedLibs = ModUtils.appendAll(lib, 'staticLibraries')
+ result.concat(impliedLibs)
+ }
+ return result
+ }
+ }
+
+ prepare: {
+ var toolchainInstallPath = product.module.toolchainInstallPath
+
+ var args = ['/nologo']
+ var nativeOutputFileName = FileInfo.toWindowsSeparators(output.fileName)
+ args.push('/OUT:' + nativeOutputFileName)
+ for (var i in inputs.obj) {
+ var fileName = FileInfo.toWindowsSeparators(inputs.obj[i].fileName)
+ args.push(fileName)
+ }
+ var is64bit = (product.module.architecture == "x86_64")
+ var linkerPath = toolchainInstallPath + '/VC/bin/'
+ if (is64bit)
+ linkerPath += 'amd64/'
+ linkerPath += 'lib.exe'
+ var cmd = new Command(linkerPath, args)
+ cmd.description = 'creating ' + FileInfo.fileName(output.fileName)
+ cmd.highlight = 'linker';
+ cmd.workingDirectory = FileInfo.path(output.fileName)
+ cmd.responseFileThreshold = product.module.responseFileThreshold
+ cmd.responseFileUsagePrefix = '@';
+ return cmd;
+ }
+ }
+}
diff --git a/share/qbs/modules/qbs/common.qbs b/share/qbs/modules/qbs/common.qbs
new file mode 100644
index 000000000..e9e311e93
--- /dev/null
+++ b/share/qbs/modules/qbs/common.qbs
@@ -0,0 +1,50 @@
+import qbs.base 1.0
+import qbs.fileinfo 1.0 as FileInfo
+
+Module {
+ property list<string> references;
+ property string buildVariant: "debug"
+ property bool debugInformation: (buildVariant == "debug")
+ property string optimization: (buildVariant == "debug" ? "none" : "fast")
+ property string platform: null
+ property string hostOS: getHostOS()
+ property string hostArchitecture: getHostDefaultArchitecture()
+ property string targetOS: null
+ property string targetName: null
+ property string toolchain: null
+ property string architecture: null
+ property string endianness: null
+ property string installDir: '.'
+
+ PropertyOptions {
+ name: "buildVariant"
+ allowedValues: ['debug', 'release']
+ description: "Defines the consistence of your ice cream sandwich"
+ }
+
+ PropertyOptions {
+ name: "optimization"
+ allowedValues: ['none', 'fast', 'small']
+ description: "optimization level"
+ }
+
+ Rule {
+ inputs: ["install"]
+ Artifact {
+ fileTags: ["installed_content"]
+ fileName: input.modules.qbs.installDir + "/" + input.fileName
+ }
+
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.sourceCode = function() {
+ File.remove(output.fileName);
+ File.copy(input.fileName, output.fileName);
+ }
+ cmd.description = "installing " + FileInfo.fileName(output.fileName);
+ cmd.highlight = "linker";
+ return cmd;
+ }
+
+ }
+}
diff --git a/share/qbs/modules/qt/QtModule.qbs b/share/qbs/modules/qt/QtModule.qbs
new file mode 100644
index 000000000..b1a03d4c2
--- /dev/null
+++ b/share/qbs/modules/qt/QtModule.qbs
@@ -0,0 +1,19 @@
+import qbs.base 1.0
+import qbs.fileinfo 1.0 as FileInfo
+import 'qtfunctions.js' as QtFunctions
+
+Module {
+ condition: false
+
+ Depends { name: "cpp" }
+ Depends { id: qtcore; name: "Qt.core" }
+
+ property string binPath: qtcore.binPath
+ property string incPath: qtcore.incPath
+ property string libPath: qtcore.libPath
+ property string qtModuleName: ''
+ property string internalQtModuleName: 'Qt' + qtModuleName
+ cpp.includePaths: [incPath + '/' + internalQtModuleName]
+ cpp.dynamicLibraries: [QtFunctions.getLibraryName(internalQtModuleName, qbs.targetOS, cpp.debugInformation)]
+ cpp.frameworks: [QtFunctions.getLibraryName(internalQtModuleName, qbs.targetOS, cpp.debugInformation)]
+}
diff --git a/share/qbs/modules/qt/core/moc.js b/share/qbs/modules/qt/core/moc.js
new file mode 100644
index 000000000..c0845220c
--- /dev/null
+++ b/share/qbs/modules/qt/core/moc.js
@@ -0,0 +1,15 @@
+function args(input, output, config) {
+ var args = [];
+
+ // ### fixme
+ var defines = ModUtils.appendAll_internal(config.modules, 'cpp', 'defines') //config.modules.cpp.compiler.defines
+ var includePaths = ModUtils.appendAll_internal(config.modules, 'cpp', 'includePaths') //config.modules.cpp.compiler.includePaths
+ for (var i in defines)
+ args.push('-D' + defines[i]);
+ for (var i in includePaths)
+ args.push('-I' + includePaths[i]);
+ args.push('-o', output);
+ args.push(input);
+ return args;
+}
+
diff --git a/share/qbs/modules/qt/core/qtcore.qbs b/share/qbs/modules/qt/core/qtcore.qbs
new file mode 100644
index 000000000..075b462b6
--- /dev/null
+++ b/share/qbs/modules/qt/core/qtcore.qbs
@@ -0,0 +1,130 @@
+import qbs.base 1.0
+import qbs.fileinfo 1.0 as FileInfo
+import '../../utils.js' as ModUtils
+import "moc.js" 1.0 as Moc
+import '../qtfunctions.js' as QtFunctions
+
+Module {
+ Depends { name: "cpp" }
+
+ property string qtVersionName: "default"
+ property string configKey: "qt/" + qtVersionName + "/"
+ property string qtNamespace: qbs.configurationValue(configKey + "namespace", undefined)
+ property string qtPath: qbs.configurationValue(configKey + "path", undefined)
+ property string binPath: qtPath ? qtPath + "/bin" : qbs.configurationValue(configKey + "binPath", undefined)
+ property string incPath: qtPath ? qtPath + "/include" : qbs.configurationValue(configKey + "incPath", undefined)
+ property string libPath: qtPath ? qtPath + "/lib" : qbs.configurationValue(configKey + "libPath", undefined)
+ property string mkspecsPath: qtPath ? qtPath + "/mkspecs" : qbs.configurationValue(configKey + "mkspecsPath", undefined)
+ property string generatedFilesDir: 'GeneratedFiles/' + product.name // ### TODO: changing this property does not change the path in the rule ATM.
+ property string libraryInfix: cpp.debugInformation ? 'd' : ''
+ cpp.defines: {
+ if (!qtNamespace)
+ return undefined;
+ return ["QT_NAMESPACE=" + qtNamespace]
+ }
+ cpp.includePaths: [
+ mkspecsPath + '/default',
+ incPath + '/QtCore',
+ incPath,
+ product.buildDirectory + '/' + generatedFilesDir
+ ]
+ cpp.libraryPaths: [libPath]
+ cpp.dynamicLibraries: qbs.targetOS != 'mac' ? [QtFunctions.getLibraryName('QtCore', qbs.targetOS, cpp.debugInformation)] : []
+ cpp.frameworkPaths: [libPath]
+ cpp.frameworks: [QtFunctions.getLibraryName('QtCore', qbs.targetOS, cpp.debugInformation)]
+ cpp.rpaths: [libPath]
+
+ setupBuildEnvironment: {
+ // Not really a setup in this case. Just some sanity checks.
+ if (!binPath)
+ throw "qt/core.binPath not set. Set the configuration values qt/default/binPath or qt/default/path.";
+ if (!incPath)
+ throw "qt/core.incPath not set. Set the configuration values qt/default/incPath or qt/default/path.";
+ if (!libPath)
+ throw "qt/core.libPath not set. Set the configuration values qt/default/libPath or qt/default/path.";
+ if (!mkspecsPath)
+ throw "qt/core.mkspecsPath not set. Set the configuration values qt/default/mkspecsPath or qt/default/path.";
+ }
+
+ setupRunEnvironment: {
+ var v = getenv('PATH') || ''
+ if (v.length > 0 && v.charAt(0) != ';')
+ v = ';' + v
+ var y = binPath
+ if (qbs.targetOS === 'windows')
+ v = FileInfo.toWindowsSeparators(y) + v
+ else
+ v = y + v
+ putenv('PATH', v)
+ }
+
+ FileTagger {
+ pattern: "*.qrc"
+ fileTags: ["qrc"]
+ }
+
+ Rule {
+ inputs: ["moc_cpp"]
+
+ Artifact {
+ fileName: 'GeneratedFiles/' + product.name + '/' + input.baseName + '.moc'
+// fileName: input.baseDir + '/' + input.baseName + '.moc'
+ fileTags: ["hpp"]
+ }
+
+ prepare: {
+ var cmd = new Command(product.module.binPath + '/moc', Moc.args(input.fileName, output.fileName, input));
+ cmd.description = 'moc ' + FileInfo.fileName(input.fileName);
+ cmd.highlight = 'codegen';
+ return cmd;
+ }
+ }
+
+ Rule {
+ inputs: ["moc_hpp"]
+
+ Artifact {
+ fileName: 'GeneratedFiles/' + product.name + '/moc_' + input.baseName + '.cpp'
+ fileTags: [ "cpp" ]
+ }
+
+ prepare: {
+ var cmd = new Command(product.module.binPath + '/moc', Moc.args(input.fileName, output.fileName, input));
+ cmd.description = 'moc ' + FileInfo.fileName(input.fileName);
+ cmd.highlight = 'codegen';
+ return cmd;
+ }
+ }
+
+ Rule {
+ inputs: ["moc_hpp_inc"]
+
+ Artifact {
+ fileName: 'GeneratedFiles/' + product.name + '/moc_' + input.baseName + '.cpp'
+ fileTags: [ "hpp" ]
+ }
+
+ prepare: {
+ var cmd = new Command(product.module.binPath + '/moc', Moc.args(input.fileName, output.fileName, input));
+ cmd.description = 'moc ' + FileInfo.fileName(input.fileName);
+ cmd.highlight = 'codegen';
+ return cmd;
+ }
+ }
+
+ Rule {
+ inputs: ["qrc"]
+
+ Artifact {
+// ### TODO we want to access the module's property "generatedFilesDir" here. But without evaluating all available properties a priori.
+ fileName: 'GeneratedFiles/' + product.name + '/qrc_' + input.baseName + '.cpp'
+ fileTags: ["cpp"]
+ }
+ prepare: {
+ var cmd = new Command(product.module.binPath + '/rcc', [input.fileName, '-name', FileInfo.baseName(input.fileName), '-o', output.fileName]);
+ cmd.description = 'rcc ' + FileInfo.fileName(input.fileName);
+ cmd.highlight = 'codegen';
+ return cmd;
+ }
+ }
+}
diff --git a/share/qbs/modules/qt/declarative/module.qbs b/share/qbs/modules/qt/declarative/module.qbs
new file mode 100644
index 000000000..3f4bf5b0f
--- /dev/null
+++ b/share/qbs/modules/qt/declarative/module.qbs
@@ -0,0 +1,9 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: "Declarative"
+ Depends { name: "Qt.gui" }
+}
+
diff --git a/share/qbs/modules/qt/designer/module.qbs b/share/qbs/modules/qt/designer/module.qbs
new file mode 100644
index 000000000..c2e319d88
--- /dev/null
+++ b/share/qbs/modules/qt/designer/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'Designer'
+}
+
diff --git a/share/qbs/modules/qt/designercomponents/module.qbs b/share/qbs/modules/qt/designercomponents/module.qbs
new file mode 100644
index 000000000..eb700eb7f
--- /dev/null
+++ b/share/qbs/modules/qt/designercomponents/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'DesignerComponents'
+}
+
diff --git a/share/qbs/modules/qt/gui/qtgui.qbs b/share/qbs/modules/qt/gui/qtgui.qbs
new file mode 100644
index 000000000..2a300a00c
--- /dev/null
+++ b/share/qbs/modules/qt/gui/qtgui.qbs
@@ -0,0 +1,33 @@
+import qbs.base 1.0
+import qbs.fileinfo 1.0 as FileInfo
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ qtModuleName: "Gui"
+
+ Depends { id: qtcore; name: "Qt.core" }
+
+ FileTagger {
+ pattern: "*.ui"
+ fileTags: ["ui"]
+ }
+
+ Rule {
+ inputs: ["ui"]
+
+ Artifact {
+// ### TODO we want to access the module's property "qtcore.generatedFilesDir" here. But without evaluating all available properties a priori.
+// fileName: input.baseDir + '/qrc_' + input.baseName + '.cpp'
+ fileName: 'GeneratedFiles/' + product.name + '/ui_' + input.baseName + '.h'
+ fileTags: ["hpp"]
+ }
+
+ prepare: {
+ var cmd = new Command(product.module.binPath + '/uic', [input.fileName, '-o', output.fileName])
+ cmd.description = 'uic ' + FileInfo.fileName(input.fileName);
+ cmd.highlight = 'codegen';
+ return cmd;
+ }
+ }
+}
+
diff --git a/share/qbs/modules/qt/help/module.qbs b/share/qbs/modules/qt/help/module.qbs
new file mode 100644
index 000000000..6bf5616f9
--- /dev/null
+++ b/share/qbs/modules/qt/help/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'Help'
+}
+
diff --git a/share/qbs/modules/qt/network/module.qbs b/share/qbs/modules/qt/network/module.qbs
new file mode 100644
index 000000000..00aa5386a
--- /dev/null
+++ b/share/qbs/modules/qt/network/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'Network'
+}
+
diff --git a/share/qbs/modules/qt/opengl/module.qbs b/share/qbs/modules/qt/opengl/module.qbs
new file mode 100644
index 000000000..fed343603
--- /dev/null
+++ b/share/qbs/modules/qt/opengl/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'OpenGL'
+}
+
diff --git a/share/qbs/modules/qt/qtfunctions.js b/share/qbs/modules/qt/qtfunctions.js
new file mode 100644
index 000000000..c6dbf4de5
--- /dev/null
+++ b/share/qbs/modules/qt/qtfunctions.js
@@ -0,0 +1,12 @@
+// helper functions for the Qt modules
+
+function getLibraryName(qtModule, targetOS, debugInfo)
+{
+ var isUnix = (targetOS == 'linux' || targetOS == 'mac')
+ var libName
+ if (isUnix)
+ libName = qtModule
+ else if (targetOS == 'windows')
+ libName = qtModule + (debugInfo ? 'd' : '') + '4.lib'
+ return libName
+}
diff --git a/share/qbs/modules/qt/script/module.qbs b/share/qbs/modules/qt/script/module.qbs
new file mode 100644
index 000000000..96e292bb4
--- /dev/null
+++ b/share/qbs/modules/qt/script/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'Script'
+}
+
diff --git a/share/qbs/modules/qt/sql/module.qbs b/share/qbs/modules/qt/sql/module.qbs
new file mode 100644
index 000000000..23892e162
--- /dev/null
+++ b/share/qbs/modules/qt/sql/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'Sql'
+}
+
diff --git a/share/qbs/modules/qt/svg/module.qbs b/share/qbs/modules/qt/svg/module.qbs
new file mode 100644
index 000000000..e06e9277a
--- /dev/null
+++ b/share/qbs/modules/qt/svg/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'Svg'
+}
+
diff --git a/share/qbs/modules/qt/webkit/module.qbs b/share/qbs/modules/qt/webkit/module.qbs
new file mode 100644
index 000000000..ea598d61f
--- /dev/null
+++ b/share/qbs/modules/qt/webkit/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'WebKit'
+}
+
diff --git a/share/qbs/modules/qt/xml/module.qbs b/share/qbs/modules/qt/xml/module.qbs
new file mode 100644
index 000000000..5b4a462a7
--- /dev/null
+++ b/share/qbs/modules/qt/xml/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'Xml'
+}
+
diff --git a/share/qbs/modules/utils.js b/share/qbs/modules/utils.js
new file mode 100644
index 000000000..4d1e08418
--- /dev/null
+++ b/share/qbs/modules/utils.js
@@ -0,0 +1,133 @@
+//
+// utility functions for modules
+//
+
+function appendAll_internal2(modules, name, property, seenValues)
+{
+ var result = []
+ for (var m in modules) {
+ if (m == name) {
+ var value = modules[m][property]
+ if (value) {
+ if (!seenValues[value]) {
+ seenValues[value] = true
+ result = result.concat(value)
+ }
+ }
+ } else {
+ var values = appendAll_internal2(modules[m].modules, name, property, seenValues)
+ if (values && values.length > 0)
+ result = result.concat(values)
+ }
+ }
+ return result
+}
+
+function appendAll_internal(modules, name, property)
+{
+ var seenValues = []
+ return appendAll_internal2(modules, name, property, seenValues)
+}
+
+function appendAll(config, property)
+{
+ return appendAll_internal(config.modules, config.module.name, property)
+}
+
+function appendAllFromArtifacts(product, artifacts, moduleName, propertyName)
+{
+ var seenValues = []
+ var result = appendAll_internal2(product.modules, moduleName, propertyName, seenValues)
+ for (var i in artifacts)
+ result = result.concat(appendAll_internal2(artifacts[i].modules, moduleName, propertyName, seenValues))
+ return result
+}
+
+function findFirst(modules, name, property)
+{
+ for (var m in modules) {
+ if (m == name) {
+ var value = modules[m][property]
+ if (value)
+ return value
+ } else {
+ var value = findFirst(m.modules, name, property)
+ if (value)
+ return value
+ }
+ }
+ return null
+}
+
+function dumpProperty(key, value, level)
+{
+ var indent = ''
+ for (var k=0; k < level; ++k)
+ indent += ' '
+ print(indent + key + ': ' + value)
+}
+
+function traverseObject(obj, func, level)
+{
+ if (!level)
+ level = 0
+ var children = {}
+ for (var i in obj) {
+ if (typeof(obj[i]) == "object" && !(obj[i] instanceof Array))
+ children[i] = obj[i]
+ else
+ func.apply(this, [i, obj[i], level])
+ }
+ level++
+ for (var i in children) {
+ func.apply(this, [i, children[i], level - 1])
+ traverseObject(children[i], func, level)
+ }
+ level--
+}
+
+function dumpObject(obj, description)
+{
+ if (!description)
+ description = 'object dump'
+ print('+++++++++ ' + description + ' +++++++++')
+ traverseObject(obj, dumpProperty)
+}
+
+
+//////////////////////////////////////////////////////////
+// The EnvironmentVariable class
+//
+function EnvironmentVariable(name, separator, convertPathSeparators)
+{
+ if (!name)
+ throw "EnvironmentVariable c'tor needs a name as first argument."
+ this.name = name
+ this.value = getenv(name).toString()
+ this.separator = separator || ''
+ this.convertPathSeparators = convertPathSeparators || false
+}
+
+EnvironmentVariable.prototype.prepend = function(v)
+{
+ if (this.value.length > 0 && this.value.charAt(0) != this.separator)
+ this.value = this.separator + this.value
+ if (this.convertPathSeparators)
+ v = FileInfo.toWindowsSeparators(v)
+ this.value = v + this.value
+}
+
+EnvironmentVariable.prototype.append = function(v)
+{
+ if (this.value.length > 0)
+ this.value += this.separator
+ if (this.convertPathSeparators)
+ v = FileInfo.toWindowsSeparators(v)
+ this.value += v
+}
+
+EnvironmentVariable.prototype.set = function()
+{
+ putenv(this.name, this.value)
+}
+