aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenis Shienkov <denis.shienkov@gmail.com>2019-03-19 16:23:32 +0300
committerDenis Shienkov <denis.shienkov@gmail.com>2019-04-10 12:31:41 +0000
commit77218b44b1b12c2b18e4655e114ec0323285e303 (patch)
tree9825e2ed7aca806e3da1702120aed7d9b6dab9c0
parent62e07306481373d9d9b6b656d855b204aa6964f3 (diff)
bare-metal: Add SDCC toolchain support
This commit adds a basic support for the SDCC compiler: * http://sdcc.sourceforge.net/ As this compiler support multiple architectures, then it is impossible to uniquely identify the current architecture by dumping of the pre-defined macros (because its content depends on a target flag). In this case the cpp.architecture will contains a default architecture (which is dumped with an omitted target flag). To use it with Qt Creator, it is enough to add there a desired Kit with a custom SDCC C/C++ compiler, and then set the following in the Kit's Qbs profile settings: * Key: qbs.toolchainType * Value: sdcc To create the SDCC profile it is enougth to use the following command: qbs setup-toolchains --type sdcc <path/to/sdcc/compiler/binary> <profile name> A toolchain type can be omitted; in this case the QBS will tries to detect the toolchain type from the specified compiler name. Also it is possible to auto-detect the SDCC toolchain from the PATH environment using the following command: qbs setup-toolchain --detect At current time are supported only the 8051 (aka MCS51) architecture; other architectures can be added later. Change-Id: I8cc239d62e35472ab667e054a64a1e59c2d548bd Reviewed-by: Richard Weickelt <richard@weickelt.de> Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
-rw-r--r--doc/reference/cli/cli-options.qdocinc1
-rw-r--r--doc/reference/items/probe/sdcc-probe.qdoc93
-rw-r--r--share/qbs/imports/qbs/Probes/SdccProbe.qbs62
-rw-r--r--share/qbs/modules/cpp/sdcc.js340
-rw-r--r--share/qbs/modules/cpp/sdcc.qbs203
-rw-r--r--src/app/qbs-setup-toolchains/probe.cpp65
6 files changed, 764 insertions, 0 deletions
diff --git a/doc/reference/cli/cli-options.qdocinc b/doc/reference/cli/cli-options.qdocinc
index 2d35bea61..d4c3280a2 100644
--- a/doc/reference/cli/cli-options.qdocinc
+++ b/doc/reference/cli/cli-options.qdocinc
@@ -496,6 +496,7 @@
\li \c msvc
\li \c iar
\li \c keil
+ \li \c sdcc
\endlist
//! [type]
diff --git a/doc/reference/items/probe/sdcc-probe.qdoc b/doc/reference/items/probe/sdcc-probe.qdoc
new file mode 100644
index 000000000..1353eb736
--- /dev/null
+++ b/doc/reference/items/probe/sdcc-probe.qdoc
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+/*!
+ \contentspage list-of-probes.html
+ \qmltype SdccProbe
+ \ingroup list-of-probes
+ \ingroup list-of-items
+ \keyword QML.SdccProbe
+ \inherits PathProbe
+ \brief Collects SDCC toolchain compiler information.
+ \since Qbs 1.14
+ \internal
+
+ Detects the version, supported architecture and the platform
+ endianness of the specified compiler executable file from the
+ \l{http://sdcc.sourceforge.net/}{SDCC} toolchain.
+*/
+
+/*!
+ \qmlproperty string SdccProbe::compilerFilePath
+
+ An input property which is a full path to the SDCC compiler executable file.
+
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty string SdccProbe::architecture
+
+ Detected architecture of the target platform's processor.
+
+ The possible values are \c "mcs51".
+
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty string SdccProbe::endianness
+
+ Detected endianness of the target platform's processor architecture.
+
+ The possible values are \c "little".
+
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty int SdccProbe::versionMajor
+
+ Detected major compiler version.
+
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty int SdccProbe::versionMinor
+
+ Detected minor compiler version.
+
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty int SdccProbe::versionPatch
+
+ Detected patch compiler version.
+
+ \nodefaultvalue
+*/
diff --git a/share/qbs/imports/qbs/Probes/SdccProbe.qbs b/share/qbs/imports/qbs/Probes/SdccProbe.qbs
new file mode 100644
index 000000000..4ff7b0ad8
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/SdccProbe.qbs
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** 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 The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. 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, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs.File
+import "../../../modules/cpp/sdcc.js" as SDCC
+
+PathProbe {
+ // Inputs
+ property string compilerFilePath;
+
+ // Outputs
+ property string architecture;
+ property string endianness;
+ property int versionMajor;
+ property int versionMinor;
+ property int versionPatch;
+
+ configure: {
+ if (!File.exists(compilerFilePath)) {
+ found = false;
+ return;
+ }
+
+ var macros = SDCC.dumpMacros(compilerFilePath, qbs);
+
+ architecture = SDCC.guessArchitecture(macros);
+ endianness = SDCC.guessEndianness(macros);
+
+ versionMajor = parseInt(macros["__SDCC_VERSION_MAJOR"], 10);
+ versionMinor = parseInt(macros["__SDCC_VERSION_MINOR"], 10);
+ versionPatch = parseInt(macros["__SDCC_VERSION_PATCH"], 10);
+
+ found = macros["SDCC"];
+ }
+}
diff --git a/share/qbs/modules/cpp/sdcc.js b/share/qbs/modules/cpp/sdcc.js
new file mode 100644
index 000000000..d5138d949
--- /dev/null
+++ b/share/qbs/modules/cpp/sdcc.js
@@ -0,0 +1,340 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** 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 The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. 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, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+var Cpp = require("cpp.js");
+var Environment = require("qbs.Environment");
+var File = require("qbs.File");
+var FileInfo = require("qbs.FileInfo");
+var ModUtils = require("qbs.ModUtils");
+var Process = require("qbs.Process");
+var TemporaryDir = require("qbs.TemporaryDir");
+var TextFile = require("qbs.TextFile");
+var Utilities = require("qbs.Utilities");
+var WindowsUtils = require("qbs.WindowsUtils");
+
+function guessArchitecture(macros)
+{
+ if (macros["__SDCC_mcs51"] === "1")
+ return "mcs51";
+}
+
+function guessEndianness(macros)
+{
+ // SDCC stores numbers in little-endian format.
+ return "little";
+}
+
+function dumpMacros(compilerFilePath, qbs) {
+ var tempDir = new TemporaryDir();
+ var fakeIn = new TextFile(tempDir.path() + "/empty-source.c", TextFile.WriteOnly);
+ var p = new Process();
+ p.exec(compilerFilePath,
+ [ fakeIn.filePath(), "-dM", "-E" ],
+ true);
+ var map = {};
+ p.readStdOut().trim().split(/\r?\n/g).map(function (line) {
+ var parts = line.split(" ", 3);
+ map[parts[1]] = parts[2];
+ });
+ return map;
+}
+
+function effectiveLinkerPath(product) {
+ if (product.cpp.linkerMode === "automatic")
+ return product.cpp.compilerPath;
+ return product.cpp.linkerPath;
+}
+
+function useCompilerDriverLinker(product) {
+ var linker = effectiveLinkerPath(product);
+ return linker === product.cpp.compilerPath;
+}
+
+function escapeLinkerFlags(product, linkerFlags) {
+ if (!linkerFlags || linkerFlags.length === 0 || !useCompilerDriverLinker(product))
+ return linkerFlags;
+ return ["-Wl " + linkerFlags.join(",")];
+}
+
+function collectLibraryDependencies(product) {
+ var seen = {};
+ var result = [];
+
+ function addFilePath(filePath) {
+ result.push({ filePath: filePath });
+ }
+
+ function addArtifactFilePaths(dep, artifacts) {
+ if (!artifacts)
+ return;
+ var artifactFilePaths = artifacts.map(function(a) { return a.filePath; });
+ artifactFilePaths.forEach(addFilePath);
+ }
+
+ function addExternalStaticLibs(obj) {
+ if (!obj.cpp)
+ return;
+ function ensureArray(a) {
+ return Array.isArray(a) ? a : [];
+ }
+ function sanitizedModuleListProperty(obj, moduleName, propertyName) {
+ return ensureArray(ModUtils.sanitizedModuleProperty(obj, moduleName, propertyName));
+ }
+ var externalLibs = [].concat(
+ sanitizedModuleListProperty(obj, "cpp", "staticLibraries"));
+ var staticLibrarySuffix = obj.moduleProperty("cpp", "staticLibrarySuffix");
+ externalLibs.forEach(function(staticLibraryName) {
+ if (!staticLibraryName.endsWith(staticLibrarySuffix))
+ staticLibraryName += staticLibrarySuffix;
+ addFilePath(staticLibraryName);
+ });
+ }
+
+ function traverse(dep) {
+ if (seen.hasOwnProperty(dep.name))
+ return;
+ seen[dep.name] = true;
+
+ if (dep.parameters.cpp && dep.parameters.cpp.link === false)
+ return;
+
+ var staticLibraryArtifacts = dep.artifacts["staticlibrary"];
+ if (staticLibraryArtifacts) {
+ dep.dependencies.forEach(traverse);
+ addArtifactFilePaths(dep, staticLibraryArtifacts);
+ addExternalStaticLibs(dep);
+ }
+ }
+
+ product.dependencies.forEach(traverse);
+ addExternalStaticLibs(product);
+ return result;
+}
+
+function compilerFlags(project, product, input, output, explicitlyDependsOn) {
+ // Determine which C-language we"re compiling.
+ var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(output.fileTags));
+
+ var args = [];
+
+ args.push(input.filePath);
+ args.push("-c");
+ args.push("-o", output.filePath);
+
+ switch (input.cpp.optimization) {
+ case "small":
+ args.push("--opt-code-size");
+ break;
+ case "fast":
+ args.push("--opt-code-speed");
+ break;
+ case "none":
+ // SDCC has not option to disable the optimization.
+ break;
+ }
+
+ if (input.cpp.debugInformation)
+ args.push("--debug");
+
+ var warnings = input.cpp.warningLevel;
+ if (warnings === "none")
+ args.push("--less-pedantic");
+
+ if (input.cpp.treatWarningsAsErrors)
+ args.push("--Werror");
+
+ if (tag === "c") {
+ if (input.cpp.cLanguageVersion === "c89")
+ args.push("--std-c89");
+ else if (input.cpp.cLanguageVersion === "c11")
+ args.push("--std-c11");
+ }
+
+ var allDefines = [];
+ var platformDefines = input.cpp.platformDefines;
+ if (platformDefines)
+ allDefines = allDefines.uniqueConcat(platformDefines);
+ var defines = input.cpp.defines;
+ if (defines)
+ allDefines = allDefines.uniqueConcat(defines);
+ args = args.concat(allDefines.map(function(define) { return "-D" + define }));
+
+ var allIncludePaths = [];
+ var includePaths = input.cpp.includePaths;
+ if (includePaths)
+ allIncludePaths = allIncludePaths.uniqueConcat(includePaths);
+ var systemIncludePaths = input.cpp.systemIncludePaths;
+ if (systemIncludePaths)
+ allIncludePaths = allIncludePaths.uniqueConcat(systemIncludePaths);
+ var compilerIncludePaths = input.cpp.compilerIncludePaths;
+ if (compilerIncludePaths)
+ allIncludePaths = allIncludePaths.uniqueConcat(compilerIncludePaths);
+ args = args.concat(allIncludePaths.map(function(include) { return "-I" + include }));
+
+ args = args.concat(ModUtils.moduleProperty(input, "platformFlags"),
+ ModUtils.moduleProperty(input, "flags"),
+ ModUtils.moduleProperty(input, "platformFlags", tag),
+ ModUtils.moduleProperty(input, "flags", tag),
+ ModUtils.moduleProperty(input, "driverFlags", tag));
+
+ return args;
+}
+
+function assemblerFlags(project, product, input, output, explicitlyDependsOn) {
+ // Determine which C-language we"re compiling
+ var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(output.fileTags));
+
+ var args = [];
+ args.push(input.filePath);
+ args.push("-o", output.filePath);
+
+ var allIncludePaths = [];
+ var systemIncludePaths = input.cpp.systemIncludePaths;
+ if (systemIncludePaths)
+ allIncludePaths = allIncludePaths.uniqueConcat(systemIncludePaths);
+ var compilerIncludePaths = input.cpp.compilerIncludePaths;
+ if (compilerIncludePaths)
+ allIncludePaths = allIncludePaths.uniqueConcat(compilerIncludePaths);
+ args = args.concat(allIncludePaths.map(function(include) { return "-I" + include }));
+
+ args = args.concat(ModUtils.moduleProperty(input, "platformFlags", tag),
+ ModUtils.moduleProperty(input, "flags", tag),
+ ModUtils.moduleProperty(input, "driverFlags", tag));
+ return args;
+}
+
+function linkerFlags(project, product, input, outputs) {
+ var args = [];
+
+ var allLibraryPaths = [];
+ var libraryPaths = product.cpp.libraryPaths;
+ if (libraryPaths)
+ allLibraryPaths = allLibraryPaths.uniqueConcat(libraryPaths);
+ var distributionLibraryPaths = product.cpp.distributionLibraryPaths;
+ if (distributionLibraryPaths)
+ allLibraryPaths = allLibraryPaths.uniqueConcat(distributionLibraryPaths);
+
+ var libraryDependencies = collectLibraryDependencies(product);
+
+ var escapableLinkerFlags = [];
+
+ if (product.cpp.generateMapFile)
+ escapableLinkerFlags.push("-m");
+
+ if (product.cpp.platformLinkerFlags)
+ Array.prototype.push.apply(escapableLinkerFlags, product.cpp.platformLinkerFlags);
+ if (product.cpp.linkerFlags)
+ Array.prototype.push.apply(escapableLinkerFlags, product.cpp.linkerFlags);
+
+ var useCompilerDriver = useCompilerDriverLinker(product);
+ if (useCompilerDriver) {
+ args.push("-o", outputs.application[0].filePath);
+
+ if (inputs.obj)
+ args = args.concat(inputs.obj.map(function(obj) { return obj.filePath }));
+
+ args = args.concat(allLibraryPaths.map(function(path) { return "-L" + path }));
+
+ var scripts = inputs.linkerscript
+ ? inputs.linkerscript.map(function(scr) { return "-f" + scr.filePath; }) : [];
+ if (scripts)
+ Array.prototype.push.apply(escapableLinkerFlags, scripts);
+ } else {
+ args.push(outputs.application[0].filePath);
+
+ if (inputs.obj)
+ args = args.concat(inputs.obj.map(function(obj) { return obj.filePath }));
+
+ args = args.concat(allLibraryPaths.map(function(path) { return "-k" + path }));
+
+ var scripts = inputs.linkerscript;
+ if (scripts) {
+ // Note: We need to split the '-f' and the file path to separate
+ // lines; otherwise the linking fails.
+ scripts.forEach(function(scr) {
+ escapableLinkerFlags.push("-f", scr.filePath);
+ });
+ }
+ }
+
+ if (libraryDependencies)
+ args = args.concat(libraryDependencies.map(function(dep) { return "-l" + dep.filePath }));
+
+ var escapedLinkerFlags = escapeLinkerFlags(product, escapableLinkerFlags);
+ if (escapedLinkerFlags)
+ Array.prototype.push.apply(args, escapedLinkerFlags);
+
+ return args;
+}
+
+function archiverFlags(project, product, input, outputs) {
+ var args = [];
+ args.push(outputs.staticlibrary[0].filePath);
+ if (inputs.obj)
+ args = args.concat(inputs.obj.map(function(obj) { return obj.filePath }));
+ return args;
+}
+
+function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
+ var args = compilerFlags(project, product, input, output, explicitlyDependsOn);
+ var compilerPath = input.cpp.compilerPath;
+ var cmd = new Command(compilerPath, args)
+ cmd.description = "compiling " + input.fileName;
+ cmd.highlight = "compiler";
+ return [cmd];
+}
+
+function prepareAssembler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
+ var args = assemblerFlags(project, product, input, output, explicitlyDependsOn);
+ var assemblerPath = input.cpp.assemblerPath;
+ var cmd = new Command(assemblerPath, args)
+ cmd.description = "assembling " + input.fileName;
+ cmd.highlight = "compiler";
+ return [cmd];
+}
+
+function prepareLinker(project, product, inputs, outputs, input, output) {
+ var primaryOutput = outputs.application[0];
+ var args = linkerFlags(project, product, input, outputs);
+ var linkerPath = effectiveLinkerPath(product);
+ var cmd = new Command(linkerPath, args)
+ cmd.description = "linking " + primaryOutput.fileName;
+ cmd.highlight = "linker";
+ return [cmd];
+}
+
+function prepareArchiver(project, product, inputs, outputs, input, output) {
+ var args = archiverFlags(project, product, input, outputs);
+ var archiverPath = product.cpp.archiverPath;
+ var cmd = new Command(archiverPath, args)
+ cmd.description = "linking " + output.fileName;
+ cmd.highlight = "linker";
+ return [cmd];
+}
diff --git a/share/qbs/modules/cpp/sdcc.qbs b/share/qbs/modules/cpp/sdcc.qbs
new file mode 100644
index 000000000..e18f77985
--- /dev/null
+++ b/share/qbs/modules/cpp/sdcc.qbs
@@ -0,0 +1,203 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** 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 The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. 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, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs 1.0
+import qbs.File
+import qbs.FileInfo
+import qbs.ModUtils
+import qbs.PathTools
+import qbs.Probes
+import qbs.Utilities
+import "sdcc.js" as SDCC
+
+CppModule {
+ condition: qbs.toolchain && qbs.toolchain.contains("sdcc")
+
+ Probes.BinaryProbe {
+ id: compilerPathProbe
+ condition: !toolchainInstallPath && !_skipAllChecks
+ names: ["sdcc"]
+ }
+
+ Probes.SdccProbe {
+ id: sdccProbe
+ condition: !_skipAllChecks
+ compilerFilePath: compilerPath
+ }
+
+ qbs.architecture: sdccProbe.found ? sdccProbe.architecture : original
+
+ compilerVersionMajor: sdccProbe.versionMajor
+ compilerVersionMinor: sdccProbe.versionMinor
+ compilerVersionPatch: sdccProbe.versionPatch
+ endianness: sdccProbe.endianness
+
+ compilerDefinesByLanguage: []
+
+ property string toolchainInstallPath: compilerPathProbe.found
+ ? compilerPathProbe.path : undefined
+
+ property string compilerExtension: qbs.hostOS.contains("windows") ? ".exe" : ""
+
+ property bool generateMapFile: true
+ PropertyOptions {
+ name: "generateMapFile"
+ description: "produce a linker list file (enabled by default)"
+ }
+
+ /* Work-around for QtCreator which expects these properties to exist. */
+ property string cCompilerName: compilerName
+ property string cxxCompilerName: compilerName
+
+ property string linkerMode: "automatic"
+
+ compilerName: "sdcc" + compilerExtension
+ compilerPath: FileInfo.joinPaths(toolchainInstallPath, compilerName)
+
+ assemblerName: {
+ switch (qbs.architecture) {
+ case "mcs51":
+ return "sdas8051" + compilerExtension;
+ }
+ }
+ assemblerPath: FileInfo.joinPaths(toolchainInstallPath, assemblerName)
+
+ linkerName: {
+ switch (qbs.architecture) {
+ case "mcs51":
+ return "sdld" + compilerExtension;
+ }
+ }
+ linkerPath: FileInfo.joinPaths(toolchainInstallPath, linkerName)
+
+ property string archiverName: "sdcclib" + compilerExtension
+ property string archiverPath: FileInfo.joinPaths(toolchainInstallPath, archiverName)
+
+ runtimeLibrary: "static"
+
+ staticLibrarySuffix: ".lib"
+ executableSuffix: ".ihx"
+
+ property string objectSuffix: ".rel"
+
+ imageFormat: "ihx"
+
+ enableExceptions: false
+ enableRtti: false
+
+ Rule {
+ id: assembler
+ inputs: ["asm"]
+
+ Artifact {
+ fileTags: ["obj"]
+ filePath: Utilities.getHash(input.baseDir) + "/"
+ + input.fileName + input.cpp.objectSuffix
+ }
+
+ prepare: SDCC.prepareAssembler.apply(SDCC, arguments);
+ }
+
+ FileTagger {
+ condition: qbs.architecture === "arm";
+ patterns: "*.s"
+ fileTags: ["asm"]
+ }
+
+ FileTagger {
+ condition: qbs.architecture === "mcs51";
+ patterns: ["*.s51", "*.asm"]
+ fileTags: ["asm"]
+ }
+
+ Rule {
+ id: compiler
+ inputs: ["cpp", "c"]
+ auxiliaryInputs: ["hpp"]
+
+ Artifact {
+ fileTags: ["obj"]
+ filePath: Utilities.getHash(input.baseDir) + "/"
+ + input.fileName + input.cpp.objectSuffix
+ }
+
+ prepare: SDCC.prepareCompiler.apply(SDCC, arguments);
+ }
+
+ Rule {
+ id: applicationLinker
+ multiplex: true
+ inputs: ["obj", "linkerscript"]
+ inputsFromDependencies: ["staticlibrary"]
+
+ outputFileTags: {
+ var tags = ["application"];
+ if (product.moduleProperty("cpp", "generateMapFile"))
+ tags.push("map_file");
+ return tags;
+ }
+ outputArtifacts: {
+ var app = {
+ fileTags: ["application"],
+ filePath: FileInfo.joinPaths(
+ product.destinationDirectory,
+ PathTools.applicationFilePath(product))
+ };
+ var artifacts = [app];
+ if (product.cpp.generateMapFile) {
+ artifacts.push({
+ fileTags: ["map_file"],
+ filePath: FileInfo.joinPaths(
+ product.destinationDirectory,
+ product.targetName + ".map")
+ });
+ }
+ return artifacts;
+ }
+
+ prepare:SDCC.prepareLinker.apply(SDCC, arguments);
+ }
+
+ Rule {
+ id: staticLibraryLinker
+ multiplex: true
+ inputs: ["obj"]
+ inputsFromDependencies: ["staticlibrary"]
+
+ Artifact {
+ fileTags: ["staticlibrary"]
+ filePath: FileInfo.joinPaths(
+ product.destinationDirectory,
+ PathTools.staticLibraryFilePath(product))
+ }
+
+ prepare: SDCC.prepareArchiver.apply(SDCC, arguments);
+ }
+}
diff --git a/src/app/qbs-setup-toolchains/probe.cpp b/src/app/qbs-setup-toolchains/probe.cpp
index 6deac36ee..af46d451b 100644
--- a/src/app/qbs-setup-toolchains/probe.cpp
+++ b/src/app/qbs-setup-toolchains/probe.cpp
@@ -132,6 +132,18 @@ static bool isKeilCompiler(const QString &compilerName)
});
}
+static QStringList knownSdccCompilerNames()
+{
+ return {QStringLiteral("sdcc")};
+}
+
+static bool isSdccCompiler(const QString &compilerName)
+{
+ return Internal::any_of(knownSdccCompilerNames(), [compilerName](const QString &knownName) {
+ return compilerName.contains(knownName);
+ });
+}
+
static QStringList toolchainTypeFromCompilerName(const QString &compilerName)
{
if (compilerName == QLatin1String("cl.exe"))
@@ -150,6 +162,8 @@ static QStringList toolchainTypeFromCompilerName(const QString &compilerName)
return canonicalToolchain(QStringLiteral("iar"));
if (isKeilCompiler(compilerName))
return canonicalToolchain(QStringLiteral("keil"));
+ if (isSdccCompiler(compilerName))
+ return canonicalToolchain(QStringLiteral("sdcc"));
return {};
}
@@ -331,6 +345,35 @@ static Profile createKeilProfile(const QFileInfo &compiler, Settings *settings,
return profile;
}
+static QString guessSdccArchitecture(const QFileInfo &compiler)
+{
+ const auto baseName = compiler.baseName();
+ if (baseName == QLatin1String("sdcc"))
+ return QStringLiteral("mcs51");
+ return {};
+}
+
+static Profile createSdccProfile(const QFileInfo &compiler, Settings *settings,
+ QString profileName = QString())
+{
+ const QString architecture = guessSdccArchitecture(compiler);
+
+ // In case the profile is auto-detected.
+ if (profileName.isEmpty())
+ profileName = QLatin1String("sdcc-") + architecture;
+
+ Profile profile(profileName, settings);
+ profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), compiler.absolutePath());
+ profile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("sdcc"));
+ if (!architecture.isEmpty())
+ profile.setValue(QStringLiteral("qbs.architecture"), architecture);
+
+ qStdout << Tr::tr("Profile '%1' created for '%2'.").arg(
+ profile.name(), compiler.absoluteFilePath())
+ << endl;
+ return profile;
+}
+
static void gccProbe(Settings *settings, QList<Profile> &profiles, const QString &compilerName)
{
qStdout << Tr::tr("Trying to detect %1...").arg(compilerName) << endl;
@@ -407,6 +450,25 @@ static void keilProbe(Settings *settings, QList<Profile> &profiles)
qStdout << Tr::tr("No KEIL toolchains found.") << endl;
}
+static void sdccProbe(Settings *settings, QList<Profile> &profiles)
+{
+ qStdout << Tr::tr("Trying to detect SDCC toolchains...") << endl;
+
+ bool isFound = false;
+ const auto compilerNames = knownSdccCompilerNames();
+ for (const QString &compilerName : compilerNames) {
+ const QString sdccPath = findExecutable(HostOsInfo::appendExecutableSuffix(compilerName));
+ if (!sdccPath.isEmpty()) {
+ const auto profile = createSdccProfile(sdccPath, settings);
+ profiles.push_back(profile);
+ isFound = true;
+ }
+ }
+
+ if (!isFound)
+ qStdout << Tr::tr("No SDCC toolchains found.") << endl;
+}
+
void probe(Settings *settings)
{
QList<Profile> profiles;
@@ -425,6 +487,7 @@ void probe(Settings *settings)
mingwProbe(settings, profiles);
iarProbe(settings, profiles);
keilProbe(settings, profiles);
+ sdccProbe(settings, profiles);
if (profiles.empty()) {
qStderr << Tr::tr("Could not detect any toolchains. No profile created.") << endl;
@@ -463,6 +526,8 @@ void createProfile(const QString &profileName, const QString &toolchainType,
createIarProfile(compiler, settings, profileName);
else if (toolchainTypes.contains(QLatin1String("keil")))
createKeilProfile(compiler, settings, profileName);
+ else if (toolchainTypes.contains(QLatin1String("sdcc")))
+ createSdccProfile(compiler, settings, profileName);
else
throw qbs::ErrorInfo(Tr::tr("Cannot create profile: Unknown toolchain type."));
}