/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** 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 PathTools = require("qbs.PathTools"); var Process = require("qbs.Process"); var TemporaryDir = require("qbs.TemporaryDir"); var TextFile = require("qbs.TextFile"); var Utilities = require("qbs.Utilities"); function isMcs51Architecture(architecture) { return architecture === "mcs51"; } function isMcs251Architecture(architecture) { return architecture === "mcs251"; } function isMcsArchitecture(architecture) { return isMcs51Architecture(architecture) || isMcs251Architecture(architecture); } function isC166Architecture(architecture) { return architecture === "c166"; } function isArmArchitecture(architecture) { return architecture.startsWith("arm"); } function isMcsCompiler(compilerPath) { var base = FileInfo.baseName(compilerPath).toLowerCase(); return base === "c51" || base === "cx51" || base === "c251"; } function isC166Compiler(compilerPath) { return FileInfo.baseName(compilerPath).toLowerCase() === "c166"; } function isArmCCCompiler(compilerPath) { return FileInfo.baseName(compilerPath).toLowerCase() === "armcc"; } function isArmClangCompiler(compilerPath) { return FileInfo.baseName(compilerPath).toLowerCase() === "armclang"; } function preincludeFlag(compilerPath) { if (isArmCCCompiler(compilerPath)) return "--preinclude"; else if (isArmClangCompiler(compilerPath)) return "-include"; } function toolchainDetails(qbs) { var architecture = qbs.architecture; if (isMcs51Architecture(architecture)) { return { "imageFormat": "omf", "linkerMapSuffix":".m51", "objectSuffix": ".obj", "executableSuffix": ".abs", "compilerName": "c51", "assemblerName": "a51", "linkerName": "bl51", "archiverName": "lib51" }; } else if (isMcs251Architecture(architecture)) { return { "imageFormat": "omf", "linkerMapSuffix":".m51", "objectSuffix": ".obj", "executableSuffix": ".abs", "compilerName": "c251", "assemblerName": "a251", "linkerName": "l251", "archiverName": "lib251" }; } else if (isC166Architecture(architecture)) { return { "imageFormat": "omf", "linkerMapSuffix":".m66", "objectSuffix": ".obj", "executableSuffix": ".abs", "compilerName": "c166", "assemblerName": "a166", "linkerName": "l166", "archiverName": "lib166" }; } else if (isArmArchitecture(architecture)) { return { "imageFormat": "elf", "linkerMapSuffix":".map", "objectSuffix": ".o", "executableSuffix": ".axf", "disassemblerName": "fromelf", "compilerName": "armcc", "assemblerName": "armasm", "linkerName": "armlink", "archiverName": "armar" }; } } function guessArmCCArchitecture(targetArchArm, targetArchThumb) { var arch = "arm"; if (targetArchArm === "4" && targetArchThumb === "0") arch += "v4"; else if (targetArchArm === "4" && targetArchThumb === "1") arch += "v4t"; else if (targetArchArm === "5" && targetArchThumb === "2") arch += "v5t"; else if (targetArchArm === "6" && targetArchThumb === "3") arch += "v6"; else if (targetArchArm === "6" && targetArchThumb === "4") arch += "v6t2"; else if (targetArchArm === "0" && targetArchThumb === "3") arch += "v6m"; else if (targetArchArm === "7" && targetArchThumb === "4") arch += "v7r"; else if (targetArchArm === "0" && targetArchThumb === "4") arch += "v7m"; return arch; } function guessArmClangArchitecture(targetArchArm, targetArchProfile) { targetArchProfile = targetArchProfile.replace(/'/g, ""); var arch = "arm"; if (targetArchArm !== "" && targetArchProfile !== "") arch += "v" + targetArchArm + targetArchProfile.toLowerCase(); return arch; } function guessArchitecture(macros) { if (macros["__C51__"]) return "mcs51"; else if (macros["__C251__"]) return "mcs251"; else if (macros["__C166__"]) return "c166"; else if (macros["__CC_ARM"] === "1") return guessArmCCArchitecture(macros["__TARGET_ARCH_ARM"], macros["__TARGET_ARCH_THUMB"]); else if (macros["__clang__"] === "1" && macros["__arm__"] === "1") return guessArmClangArchitecture(macros["__ARM_ARCH"], macros["__ARM_ARCH_PROFILE"]); } function guessEndianness(macros) { if (macros["__C51__"] || macros["__C251__"]) { // The 8051 processors are 8-bit. So, the data with an integer type // represented by more than one byte is stored as big endian in the // Keil toolchain. See for more info: // * http://www.keil.com/support/man/docs/c51/c51_ap_2bytescalar.htm // * http://www.keil.com/support/man/docs/c51/c51_ap_4bytescalar.htm // * http://www.keil.com/support/man/docs/c251/c251_ap_2bytescalar.htm // * http://www.keil.com/support/man/docs/c251/c251_ap_4bytescalar.htm return "big"; } else if (macros["__C166__"]) { // The C166 processors are 16-bit. So, the data with an integer type // represented by more than one byte is stored as little endian in the // Keil toolchain. See for more info: // * http://www.keil.com/support/man/docs/c166/c166_ap_ints.htm // * http://www.keil.com/support/man/docs/c166/c166_ap_longs.htm return "little"; } else if (macros["__CC_ARM"]) { return macros["__BIG_ENDIAN"] ? "big" : "little"; } else if (macros["__clang__"] && macros["__arm__"]) { switch (macros["__BYTE_ORDER__"]) { case "__ORDER_BIG_ENDIAN__": return "big"; case "__ORDER_LITTLE_ENDIAN__": return "little"; } } } function guessVersion(macros) { if (macros["__C51__"] || macros["__C251__"]) { var mcsVersion = macros["__C51__"] || macros["__C251__"]; return { major: parseInt(mcsVersion / 100), minor: parseInt(mcsVersion % 100), patch: 0 } } else if (macros["__C166__"]) { var xcVersion = macros["__C166__"]; return { major: parseInt(xcVersion / 100), minor: parseInt(xcVersion % 100), patch: 0 } } else if (macros["__CC_ARM"] || macros["__clang__"]) { var armVersion = macros["__ARMCC_VERSION"]; return { major: parseInt(armVersion / 1000000), minor: parseInt(armVersion / 10000) % 100, patch: parseInt(armVersion) % 10000 } } } function dumpMcsCompilerMacros(compilerFilePath, tag) { // C51 or C251 compiler support only C language. if (tag === "cpp") return {}; // Note: The C51 or C251 compiler does not support the predefined // macros dumping. So, we do it with the following trick, where we try // to create and compile a special temporary file and to parse the console // output with the own magic pattern: (""|"key"|"value"|""). var outputDirectory = new TemporaryDir(); var outputFilePath = FileInfo.fromNativeSeparators(FileInfo.joinPaths(outputDirectory.path(), "dump-macros.c")); var outputFile = new TextFile(outputFilePath, TextFile.WriteOnly); outputFile.writeLine("#define VALUE_TO_STRING(x) #x"); outputFile.writeLine("#define VALUE(x) VALUE_TO_STRING(x)"); // Predefined keys for C51 and C251 compilers, see details: // * https://www.keil.com/support/man/docs/c51/c51_pp_predefmacroconst.htm // * https://www.keil.com/support/man/docs/c251/c251_pp_predefmacroconst.htm var keys = ["__C51__", "__CX51__", "__C251__", "__MODEL__", "__STDC__", "__FLOAT64__", "__MODSRC__"]; // For C51 compiler. outputFile.writeLine("#if defined(__C51__) || defined(__CX51__)"); outputFile.writeLine("# define VAR_NAME_VALUE(var) \"(\"\"\"\"|\"#var\"|\"VALUE(var)\"|\"\"\"\")\""); for (var i in keys) { var key = keys[i]; outputFile.writeLine("# if defined (" + key + ")"); outputFile.writeLine("# pragma message (VAR_NAME_VALUE(" + key + "))"); outputFile.writeLine("# endif"); } outputFile.writeLine("#endif"); // For C251 compiler. outputFile.writeLine("#if defined(__C251__)"); outputFile.writeLine("# define VAR_NAME_VALUE(var) \"\"|#var|VALUE(var)|\"\""); for (var i in keys) { var key = keys[i]; outputFile.writeLine("# if defined (" + key + ")"); outputFile.writeLine("# warning (VAR_NAME_VALUE(" + key + "))"); outputFile.writeLine("# endif"); } outputFile.writeLine("#endif"); outputFile.close(); var process = new Process(); process.exec(compilerFilePath, [outputFilePath], false); File.remove(outputFilePath); var map = {}; process.readStdOut().trim().split(/\r?\n/g).map(function(line) { var parts = line.split("\"|\"", 4); if (parts.length === 4) map[parts[1]] = parts[2]; }); return map; } function dumpC166CompilerMacros(compilerFilePath, tag) { // C166 compiler support only C language. if (tag === "cpp") return {}; // Note: The C166 compiler does not support the predefined // macros dumping. Also, it does not support the '#pragma' and // '#message|warning|error' directives properly (it is impossible // to print to console the value of macro). // So, we do it with the following trick, where we try // to create and compile a special temporary file and to parse the console // output with the own magic pattern, e.g: // // *** WARNING C320 IN LINE 41 OF c51.c: __C166__ // *** WARNING C2 IN LINE 42 OF c51.c: '757': unknown #pragma/control, line ignored // // where the '__C166__' is a key, and the '757' is a value. var outputDirectory = new TemporaryDir(); var outputFilePath = FileInfo.fromNativeSeparators(outputDirectory.path() + "/dump-macros.c"); var outputFile = new TextFile(outputFilePath, TextFile.WriteOnly); // Predefined keys for C166 compiler, see details: // * https://www.keil.com/support/man/docs/c166/c166_pp_predefmacroconst.htm var keys = ["__C166__", "__DUS__", "__MAC__", "__MOD167__", "__MODEL__", "__MODV2__", "__SAVEMAC__", "__STDC__"]; // For C166 compiler. outputFile.writeLine("#if defined(__C166__)"); for (var i in keys) { var key = keys[i]; outputFile.writeLine("# if defined (" + key + ")"); outputFile.writeLine("# warning " + key); outputFile.writeLine("# pragma " + key); outputFile.writeLine("# endif"); } outputFile.writeLine("#endif"); outputFile.close(); function extractKey(line, knownKeys) { for (var i in keys) { var key = knownKeys[i]; var regexp = new RegExp("^\\*\\*\\* WARNING C320 IN LINE .+: (" + key + ")$"); var match = regexp.exec(line); if (match) return key; } }; function extractValue(line) { var regexp = new RegExp("^\\*\\*\\* WARNING C2 IN LINE .+'(.+)':.+$"); var match = regexp.exec(line); if (match) return match[1]; }; var process = new Process(); process.exec(compilerFilePath, [outputFilePath], false); File.remove(outputFilePath); var lines = process.readStdOut().trim().split(/\r?\n/g); var map = {}; for (var i = 0; i < lines.length; ++i) { // First line should contains the macro key. var keyLine = lines[i]; var key = extractKey(keyLine, keys); if (!key) continue; i += 1; if (i >= lines.length) break; // Second line should contains the macro value. var valueLine = lines[i]; var value = extractValue(valueLine); if (!value) continue; map[key] = value; } return map; } function dumpArmCCCompilerMacros(compilerFilePath, tag, nullDevice) { var args = [ "-E", "--list-macros", "--cpu=cortex-m0", nullDevice ]; if (tag === "cpp") args.push("--cpp"); var p = new Process(); p.exec(compilerFilePath, args, false); return Cpp.extractMacros(p.readStdOut()); } function dumpArmClangCompilerMacros(compilerFilePath, tag, nullDevice) { var args = [ "--target=arm-arm-none-eabi", "-mcpu=cortex-m0", "-dM", "-E", "-x", ((tag === "cpp") ? "c++" : "c"), nullDevice ]; var p = new Process(); p.exec(compilerFilePath, args, false); return Cpp.extractMacros(p.readStdOut()); } function dumpMacros(compilerFilePath, tag, nullDevice) { if (isMcsCompiler(compilerFilePath)) return dumpMcsCompilerMacros(compilerFilePath, tag, nullDevice); else if (isC166Compiler(compilerFilePath)) return dumpC166CompilerMacros(compilerFilePath, tag, nullDevice); else if (isArmCCCompiler(compilerFilePath)) return dumpArmCCCompilerMacros(compilerFilePath, tag, nullDevice); else if (isArmClangCompiler(compilerFilePath)) return dumpArmClangCompilerMacros(compilerFilePath, tag, nullDevice); return {}; } function dumpMcsCompilerIncludePaths(compilerFilePath) { var includePath = compilerFilePath.replace(/bin[\\\/](.*)$/i, "inc"); return [includePath]; } function dumpC166CompilerIncludePaths(compilerFilePath) { // Same as for MCS compiler. return dumpMcsCompilerIncludePaths(compilerFilePath); } function dumpArmCCCompilerIncludePaths(compilerFilePath) { var includePath = compilerFilePath.replace(/bin[\\\/](.*)$/i, "include"); return [includePath]; } function dumpArmClangCompilerIncludePaths(compilerFilePath, nullDevice) { var args = [ "--target=arm-arm-none-eabi", "-mcpu=cortex-m0", "-v", "-E", "-x", "c++", nullDevice ]; var p = new Process(); p.exec(compilerFilePath, args, false); var lines = p.readStdErr().trim().split(/\r?\n/g).map(function (line) { return line.trim(); }); var addIncludes = false; var includePaths = []; for (var i = 0; i < lines.length; ++i) { var line = lines[i]; if (line === "#include <...> search starts here:") addIncludes = true; else if (line === "End of search list.") addIncludes = false; else if (addIncludes) includePaths.push(line); } return includePaths; } function dumpDefaultPaths(compilerFilePath, nullDevice) { var includePaths = []; if (isMcsCompiler(compilerFilePath)) includePaths = dumpMcsCompilerIncludePaths(compilerFilePath); else if (isC166Compiler(compilerFilePath)) includePaths = dumpC166CompilerIncludePaths(compilerFilePath); else if (isArmCCCompiler(compilerFilePath)) includePaths = dumpArmCCCompilerIncludePaths(compilerFilePath); else if (isArmClangCompiler(compilerFilePath)) includePaths = dumpArmClangCompilerIncludePaths(compilerFilePath, nullDevice); return { "includePaths": includePaths }; } function filterMcsOutput(output) { var filteredLines = []; output.split(/\r\n|\r|\n/).forEach(function(line) { var regexp = /^\s*\*{3}\s|^\s{29}|^\s{4}\S|^\s{2}[0-9A-F]{4}|^\s{21,25}\d+|^[0-9A-F]{4}\s\d+/; if (regexp.exec(line)) filteredLines.push(line); }); return filteredLines.join('\n'); }; function filterC166Output(output) { var filteredLines = []; output.split(/\r\n|\r|\n/).forEach(function(line) { var regexp = /^\s*\*{3}\s|^\s{29}|^\s{27,28}\d+|^\s{21}\d+|^\s{4}\S|^\s{2}[0-9A-F]{4}|^[0-9A-F]{4}\s\d+/; if (regexp.exec(line)) filteredLines.push(line); }); return filteredLines.join('\n'); }; function compilerFlags(project, product, input, outputs, explicitlyDependsOn) { // Determine which C-language we're compiling. var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(outputs.obj[0].fileTags)); var args = []; var architecture = input.qbs.architecture; if (isMcsArchitecture(architecture) || isC166Architecture(architecture)) { // Input. args.push(input.filePath); // Output. args.push("OBJECT (" + outputs.obj[0].filePath + ")"); // Defines. var defines = Cpp.collectDefines(input); if (defines.length > 0) args = args.concat("DEFINE (" + defines.join(",") + ")"); // Includes. var allIncludePaths = [].concat(Cpp.collectIncludePaths(input), Cpp.collectSystemIncludePaths(input)); if (allIncludePaths.length > 0) args = args.concat("INCDIR (" + allIncludePaths.join(";") + ")"); // Debug information flags. if (input.cpp.debugInformation) args.push("DEBUG"); // Optimization level flags. switch (input.cpp.optimization) { case "small": args.push("OPTIMIZE (SIZE)"); break; case "fast": args.push("OPTIMIZE (SPEED)"); break; case "none": args.push("OPTIMIZE (0)"); break; } // Warning level flags. switch (input.cpp.warningLevel) { case "none": args.push("WARNINGLEVEL (0)"); break; case "all": args.push("WARNINGLEVEL (2)"); if (isMcs51Architecture(architecture)) args.push("FARWARNING"); break; } // Listing files generation flag. if (!input.cpp.generateCompilerListingFiles) args.push("NOPRINT"); else args.push("PRINT(" + outputs.lst[0].filePath + ")"); } else if (isArmArchitecture(architecture)) { // Input. args.push("-c", input.filePath); // Output. args.push("-o", outputs.obj[0].filePath); // Preinclude headers. args = args.concat(Cpp.collectPreincludePathsArguments(input, true)); // Defines. args = args.concat(Cpp.collectDefinesArguments(input)); // Includes. args = args.concat(Cpp.collectIncludePathsArguments(input)); args = args.concat(Cpp.collectSystemIncludePathsArguments(input)); var compilerPath = input.cpp.compilerPath; if (isArmCCCompiler(compilerPath)) { // Debug information flags. if (input.cpp.debugInformation) { args.push("--debug"); args.push("-g"); } // Optimization level flags. switch (input.cpp.optimization) { case "small": args.push("-Ospace") break; case "fast": args.push("-Otime") break; case "none": args.push("-O0") break; } // Warning level flags. switch (input.cpp.warningLevel) { case "none": args.push("-W"); break; default: // By default all warnings are enabled. break; } if (tag === "c") { // C language version flags. var knownCLanguageValues = ["c99", "c90"]; var cLanguageVersion = Cpp.languageVersion( input.cpp.cLanguageVersion, knownCLanguageValues, "C"); switch (cLanguageVersion) { case "c99": args.push("--c99"); break; case "c90": args.push("--c90"); break; } } else if (tag === "cpp") { // C++ language version flags. var knownCppLanguageValues = ["c++11", "c++03"]; var cppLanguageVersion = Cpp.languageVersion( input.cpp.cxxLanguageVersion, knownCppLanguageValues, "C++"); switch (cppLanguageVersion) { case "c++11": args.push("--cpp11"); break; default: // Default C++ language is C++03. args.push("--cpp"); break; } // Exceptions flags. var enableExceptions = input.cpp.enableExceptions; if (enableExceptions !== undefined) args.push(enableExceptions ? "--exceptions" : "--no_exceptions"); // RTTI flags. var enableRtti = input.cpp.enableRtti; if (enableRtti !== undefined) args.push(enableRtti ? "--rtti" : "--no_rtti"); } // Listing files generation flag. if (input.cpp.generateCompilerListingFiles) { args.push("--list"); args.push("--list_dir", FileInfo.path(outputs.lst[0].filePath)); } } else if (isArmClangCompiler(compilerPath)) { // Debug information flags. if (input.cpp.debugInformation) args.push("-g"); // Optimization level flags. switch (input.cpp.optimization) { case "small": args.push("-Oz") break; case "fast": args.push("-Ofast") break; case "none": args.push("-O0") break; } // Warning level flags. switch (input.cpp.warningLevel) { case "all": args.push("-Wall"); break; default: break; } if (input.cpp.treatWarningsAsErrors) args.push("-Werror"); if (tag === "c") { // C language version flags. var knownCLanguageValues = ["c11", "c99", "c90", "c89"]; var cLanguageVersion = Cpp.languageVersion( input.cpp.cLanguageVersion, knownCLanguageValues, "C"); if (cLanguageVersion) args.push("-std=" + cLanguageVersion); } else if (tag === "cpp") { // C++ language version flags. var knownCppLanguageValues = ["c++17", "c++14", "c++11", "c++03", "c++98"]; var cppLanguageVersion = Cpp.languageVersion( input.cpp.cxxLanguageVersion, knownCppLanguageValues, "C++"); if (cppLanguageVersion) args.push("-std=" + cppLanguageVersion); // Exceptions flags. var enableExceptions = input.cpp.enableExceptions; if (enableExceptions !== undefined) args.push(enableExceptions ? "-fexceptions" : "-fno-exceptions"); // RTTI flags. var enableRtti = input.cpp.enableRtti; if (enableRtti !== undefined) args.push(enableRtti ? "-frtti" : "-fno-rtti"); } // Listing files generation does not supported! // There are only a workaround: http://www.keil.com/support/docs/4152.htm } } // Misc flags. args = args.concat(Cpp.collectMiscCompilerArguments(input, tag), Cpp.collectMiscDriverArguments(input)); return args; } function assemblerFlags(project, product, input, outputs, explicitlyDependsOn) { // Determine which C-language we're compiling var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(outputs.obj[0].fileTags)); var args = []; var architecture = input.qbs.architecture; if (isMcsArchitecture(architecture) || isC166Architecture(architecture)) { // Input. args.push(input.filePath); // Output. args.push("OBJECT (" + outputs.obj[0].filePath + ")"); // Includes. var allIncludePaths = [].concat(Cpp.collectIncludePaths(input), Cpp.collectSystemIncludePaths(input)); if (allIncludePaths.length > 0) args = args.concat("INCDIR (" + allIncludePaths.join(";") + ")"); // Debug information flags. if (input.cpp.debugInformation) args.push("DEBUG"); // Enable errors printing. args.push("EP"); // Listing files generation flag. if (!input.cpp.generateAssemblerListingFiles) args.push("NOPRINT"); else args.push("PRINT(" + outputs.lst[0].filePath + ")"); } else if (isArmArchitecture(architecture)) { // Input. args.push(input.filePath); // Output. args.push("-o", outputs.obj[0].filePath); // Includes. args = args.concat(Cpp.collectIncludePathsArguments(input)); args = args.concat(Cpp.collectSystemIncludePathsArguments(input)); // Debug information flags. if (input.cpp.debugInformation) { args.push("--debug"); args.push("-g"); } // Warning level flags. if (input.cpp.warningLevel === "none") args.push("--no_warn"); // Byte order flags. var endianness = input.cpp.endianness; if (endianness) args.push((endianness === "little") ? "--littleend" : "--bigend"); // Listing files generation flag. if (input.cpp.generateAssemblerListingFiles) args.push("--list", outputs.lst[0].filePath); } // Misc flags. args = args.concat(Cpp.collectMiscAssemblerArguments(input, tag)); return args; } function disassemblerFlags(project, product, input, outputs, explicitlyDependsOn) { var args = ["--disassemble", "--interleave=source"]; args.push(outputs.obj[0].filePath); args.push("--output=" + outputs.lst[0].filePath); return args; } function linkerFlags(project, product, inputs, outputs) { var args = []; var libraryPaths = Cpp.collectLibraryPaths(product); var architecture = product.qbs.architecture; if (isMcsArchitecture(architecture) || isC166Architecture(architecture)) { // Semi-intelligent handling the library paths. // We need to add the full path prefix to the library file if this // file is not absolute or not relative. Reason is that the C51, C251, // and C166 linkers does not support the library paths. function collectLibraryObjectPaths(product) { var libraryObjects = Cpp.collectLibraryDependencies(product); return libraryObjects.map(function(dep) { var filePath = dep.filePath; if (FileInfo.isAbsolutePath(filePath)) return filePath; for (var i = 0; i < libraryPaths.length; ++i) { var fullPath = FileInfo.joinPaths(libraryPaths[i], filePath); if (File.exists(fullPath)) return fullPath; } return filePath; }); } // Note: The C51, C251, or C166 linker does not distinguish an object files and // a libraries, it interpret all this stuff as an input objects, // so, we need to pass it together in one string. function collectAllObjectPathsArguments(product, inputs) { return [].concat(Cpp.collectLinkerObjectPaths(inputs), collectLibraryObjectPaths(product)); } // Add all input objects as arguments (application and library object files). var allObjectPaths = collectAllObjectPathsArguments(product, inputs); if (allObjectPaths.length > 0) args = args.concat(allObjectPaths.join(",")); // Output. args.push("TO", outputs.application[0].filePath); // Map file generation flag. if (!product.cpp.generateLinkerMapFile) args.push("NOPRINT"); else args.push("PRINT(" + outputs.mem_map[0].filePath + ")"); } else if (isArmArchitecture(architecture)) { // Inputs. args = args.concat(Cpp.collectLinkerObjectPaths(inputs)); // Output. args.push("--output", outputs.application[0].filePath); // Library paths. if (libraryPaths.length > 0) args.push(product.cpp.libraryPathFlag + libraryPaths.join(",")); // Library dependencies. args = args.concat(Cpp.collectLibraryDependenciesArguments(product)); // Linker scripts. args = args.concat(Cpp.collectLinkerScriptPathsArguments(product, inputs)); // Map file generation flag. if (product.cpp.generateLinkerMapFile) args.push("--list", outputs.mem_map[0].filePath); // Entry point flag. if (product.cpp.entryPoint) args.push("--entry", product.cpp.entryPoint); // Debug information flag. var debugInformation = product.cpp.debugInformation; if (debugInformation !== undefined) args.push(debugInformation ? "--debug" : "--no_debug"); } // Misc flags. args = args.concat(Cpp.collectMiscEscapableLinkerArguments(product), Cpp.collectMiscLinkerArguments(product), Cpp.collectMiscDriverArguments(product)); return args; } function archiverFlags(project, product, inputs, outputs) { var args = []; // Inputs. var objectPaths = Cpp.collectLinkerObjectPaths(inputs); var architecture = product.qbs.architecture; if (isMcsArchitecture(architecture) || isC166Architecture(architecture)) { // Library creation command. args.push("TRANSFER"); // Inputs. if (objectPaths.length > 0) args = args.concat(objectPaths.join(",")); // Output. args.push("TO", outputs.staticlibrary[0].filePath); } else if (isArmArchitecture(architecture)) { // Note: The ARM archiver command line expect the output file // first, and then a set of input objects. // Output. args.push("--create", outputs.staticlibrary[0].filePath); // Inputs. args = args.concat(objectPaths); // Debug information flag. if (product.cpp.debugInformation) args.push("--debug_symbols"); } return args; } // The ARMCLANG compiler does not support generation // for the listing files: // * https://www.keil.com/support/docs/4152.htm // So, we generate the listing files from the object files // using the disassembler. function generateClangCompilerListing(project, product, inputs, outputs, input, output) { if (isArmClangCompiler(input.cpp.compilerPath) && input.cpp.generateCompilerListingFiles) { var args = disassemblerFlags(project, product, input, outputs, explicitlyDependsOn); var disassemblerPath = input.cpp.disassemblerPath; var cmd = new Command(disassemblerPath, args); cmd.silent = true; return cmd; } } // The ARMCC compiler generates the listing files only in a short form, // e.g. to 'module.lst' instead of 'module.{c|cpp}.lst', that complicates // the auto-tests. Therefore we need to rename generated listing files // with correct unified names. function generateArmccCompilerListing(project, product, inputs, outputs, input, output) { if (isArmCCCompiler(input.cpp.compilerPath) && input.cpp.generateCompilerListingFiles) { var listingPath = FileInfo.path(outputs.lst[0].filePath); var cmd = new JavaScriptCommand(); cmd.oldListing = FileInfo.joinPaths(listingPath, input.baseName + ".lst"); cmd.newListing = FileInfo.joinPaths( listingPath, input.fileName + input.cpp.compilerListingSuffix); cmd.silent = true; cmd.sourceCode = function() { File.move(oldListing, newListing); }; return cmd; } } function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmds = []; var args = compilerFlags(project, product, input, outputs, explicitlyDependsOn); var compilerPath = input.cpp.compilerPath; var architecture = input.cpp.architecture; var cmd = new Command(compilerPath, args); cmd.description = "compiling " + input.fileName; cmd.highlight = "compiler"; if (isMcsArchitecture(architecture)) { cmd.maxExitCode = 1; cmd.stdoutFilterFunction = filterMcsOutput; } else if (isC166Architecture(architecture)) { cmd.maxExitCode = 1; cmd.stdoutFilterFunction = filterC166Output; } cmds.push(cmd); cmd = generateClangCompilerListing(project, product, inputs, outputs, input, output); if (cmd) cmds.push(cmd); cmd = generateArmccCompilerListing(project, product, inputs, outputs, input, output); if (cmd) cmds.push(cmd); return cmds; } function prepareAssembler(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var args = assemblerFlags(project, product, input, outputs, explicitlyDependsOn); var assemblerPath = input.cpp.assemblerPath; var architecture = input.cpp.architecture; var cmd = new Command(assemblerPath, args); cmd.description = "assembling " + input.fileName; cmd.highlight = "compiler"; if (isMcsArchitecture(architecture)) { cmd.maxExitCode = 1; cmd.stdoutFilterFunction = filterMcsOutput; } else if (isC166Architecture(architecture)) { cmd.maxExitCode = 1; cmd.stdoutFilterFunction = filterC166Output; } return [cmd]; } function prepareLinker(project, product, inputs, outputs, input, output) { var primaryOutput = outputs.application[0]; var args = linkerFlags(project, product, inputs, outputs); var linkerPath = product.cpp.linkerPath; var architecture = product.cpp.architecture; var cmd = new Command(linkerPath, args); cmd.description = "linking " + primaryOutput.fileName; cmd.highlight = "linker"; if (isMcsArchitecture(architecture)) { cmd.maxExitCode = 1; cmd.stdoutFilterFunction = filterMcsOutput; } else if (isC166Architecture(architecture)) { cmd.maxExitCode = 1; cmd.stdoutFilterFunction = filterC166Output; } return [cmd]; } function prepareArchiver(project, product, inputs, outputs, input, output) { var args = archiverFlags(project, product, inputs, outputs); var archiverPath = product.cpp.archiverPath; var architecture = product.cpp.architecture; var cmd = new Command(archiverPath, args); cmd.description = "linking " + output.fileName; cmd.highlight = "linker"; if (isMcsArchitecture(architecture)) { cmd.stdoutFilterFunction = filterMcsOutput; } else if (isC166Architecture(architecture)) { cmd.stdoutFilterFunction = filterC166Output; } return [cmd]; }