/**************************************************************************** ** ** 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. ** ****************************************************************************/ #include "armgeneralsettingsgroup_v8.h" #include "../../iarewutils.h" #include namespace qbs { namespace iarew { namespace arm { namespace v8 { constexpr int kGeneralArchiveVersion = 3; constexpr int kGeneralDataVersion = 30; namespace { struct CpuCoreEntry final { enum CpuCoreCode { Arm7tdmi = 0, Arm7tdmis = 1, Arm710t = 2, Arm720t = 3, Arm740t = 4, Arm7ejs = 5, Arm9tdmi = 6, Arm920t = 7, Arm922t = 8, Arm940t = 9, Arm9e = 10, Arm9es = 11, Arm926ejs = 12, Arm946es = 13, Arm966es = 14, Arm968es = 15, Arm10e = 16, Arm1020e = 17, Arm1022e = 18, Arm1026ejs = 19, Arm1136j = 20, Arm1136js = 21, Arm1176j = 24, Arm1176js = 25, Xscale = 32, XscaleIr7 = 33, CortexM0 = 34, CortexM0Plus = 35, CortexM1 = 36, CortexMs1 = 37, CortexM3 = 38, CortexM4 = 39, CortexM7 = 41, CortexR4 = 42, CortexR5 = 44, CortexR7 = 46, CortexR8 = 48, CortexR52 = 49, CortexA5 = 50, CortexA7 = 52, CortexA8 = 53, CortexA9 = 54, CortexA15 = 55, CortexA17 = 56, CortexM23 = 58, CortexM33 = 59 }; // Required to compile in MSVC2015. CpuCoreEntry(CpuCoreCode cc, QByteArray tf) : coreCode(cc), targetFlag(std::move(tf)) {} CpuCoreCode coreCode = Arm7tdmi; QByteArray targetFlag; }; // Dictionary of known ARM CPU cores and its compiler options. static const CpuCoreEntry cpusDict[] = { {CpuCoreEntry::Arm7tdmi, "arm7tdmi"}, // same as 'sc100' {CpuCoreEntry::Arm7tdmis, "arm7tdmi-s"}, {CpuCoreEntry::Arm710t, "arm710t"}, {CpuCoreEntry::Arm720t, "arm720t"}, {CpuCoreEntry::Arm740t, "arm740t"}, {CpuCoreEntry::Arm7ejs, "arm7ej-s"}, {CpuCoreEntry::Arm9tdmi, "arm9tdmi"}, {CpuCoreEntry::Arm920t, "arm920t"}, {CpuCoreEntry::Arm922t, "arm922t"}, {CpuCoreEntry::Arm940t, "arm940t"}, {CpuCoreEntry::Arm9e, "arm9e"}, {CpuCoreEntry::Arm9es, "arm9e-s"}, {CpuCoreEntry::Arm926ejs, "arm926ej-s"}, {CpuCoreEntry::Arm946es, "arm946e-s"}, {CpuCoreEntry::Arm966es, "arm966e-s"}, {CpuCoreEntry::Arm968es, "arm968e-s"}, {CpuCoreEntry::Arm10e, "arm10e"}, {CpuCoreEntry::Arm1020e, "arm1020e"}, {CpuCoreEntry::Arm1022e, "arm1022e"}, {CpuCoreEntry::Arm1026ejs, "arm1026ej-s"}, {CpuCoreEntry::Arm1136j, "arm1136j"}, {CpuCoreEntry::Arm1136js, "arm1136j-s"}, {CpuCoreEntry::Arm1176j, "arm1176j"}, {CpuCoreEntry::Arm1176js, "arm1176j-s"}, {CpuCoreEntry::Xscale, "xscale"}, {CpuCoreEntry::XscaleIr7, "xscale-ir7"}, {CpuCoreEntry::CortexM0, "cortex-m0"}, {CpuCoreEntry::CortexM0Plus, "cortex-m0+"}, // same as 'sc000' {CpuCoreEntry::CortexM1, "cortex-m1"}, {CpuCoreEntry::CortexMs1, "cortex-ms1"}, {CpuCoreEntry::CortexM3, "cortex-m3"}, // same as 'sc300' {CpuCoreEntry::CortexM4, "cortex-m4"}, {CpuCoreEntry::CortexM7, "cortex-m7"}, {CpuCoreEntry::CortexR4, "cortex-r4"}, {CpuCoreEntry::CortexR5, "cortex-r5"}, {CpuCoreEntry::CortexR7, "cortex-r7"}, {CpuCoreEntry::CortexR8, "cortex-r8"}, {CpuCoreEntry::CortexR52, "cortex-r52"}, {CpuCoreEntry::CortexA5, "cortex-a5"}, {CpuCoreEntry::CortexA7, "cortex-a7"}, {CpuCoreEntry::CortexA8, "cortex-a8"}, {CpuCoreEntry::CortexA9, "cortex-a9"}, {CpuCoreEntry::CortexA15, "cortex-a15"}, {CpuCoreEntry::CortexA17, "cortex-a17"}, {CpuCoreEntry::CortexM23, "cortex-m23"}, {CpuCoreEntry::CortexM33, "cortex-m33"}, }; struct FpuCoreEntry final { enum FpuRegistersCount { NoFpuRegisters, Fpu16Registers, Fpu32Registers }; enum FpuCoreCode { NoVfp = 0, Vfp2 = 2, Vfp3d16 = 3, Vfp3 = 3, Vfp4sp = 4, Vfp4d16 = 5, Vfp4 = 5, Vfp5sp = 6, Vfp5d16 = 7, Vfp9s = 8 }; // Required to compile in MSVC2015. FpuCoreEntry(FpuCoreCode cc, FpuRegistersCount rc, QByteArray tf) : coreCode(cc), regsCount(rc), targetFlag(std::move(tf)) {} FpuCoreCode coreCode = NoVfp; FpuRegistersCount regsCount = NoFpuRegisters; QByteArray targetFlag; }; // Dictionary of known ARM FPU cores and its compiler options. static const FpuCoreEntry fpusDict[] = { {FpuCoreEntry::Vfp2, FpuCoreEntry::NoFpuRegisters, "vfpv2"}, {FpuCoreEntry::Vfp3d16, FpuCoreEntry::Fpu16Registers, "vfpv3_d16"}, {FpuCoreEntry::Vfp3, FpuCoreEntry::Fpu32Registers, "vfpv3"}, {FpuCoreEntry::Vfp4sp, FpuCoreEntry::Fpu16Registers, "vfpv4_sp"}, {FpuCoreEntry::Vfp4d16, FpuCoreEntry::Fpu16Registers, "vfpv4_d16"}, {FpuCoreEntry::Vfp4, FpuCoreEntry::Fpu32Registers, "vfpv4"}, {FpuCoreEntry::Vfp5sp, FpuCoreEntry::Fpu16Registers, "vfpv5_sp"}, {FpuCoreEntry::Vfp5d16, FpuCoreEntry::Fpu16Registers, "vfpv5_d16"}, {FpuCoreEntry::Vfp9s, FpuCoreEntry::NoFpuRegisters, "vfp9-s"}, }; // Target page options. struct TargetPageOptions final { enum Endianness { LittleEndian, BigEndian }; explicit TargetPageOptions(const ProductData &qbsProduct) { const auto &qbsProps = qbsProduct.moduleProperties(); const QStringList flags = gen::utils::cppStringModuleProperties( qbsProps, {QStringLiteral("driverFlags")}); // Detect target CPU code. const QString cpuValue = IarewUtils::flagValue( flags, QStringLiteral("--cpu")) .toLower(); const auto cpuEnd = std::cend(cpusDict); const auto cpuIt = std::find_if(std::cbegin(cpusDict), cpuEnd, [cpuValue]( const CpuCoreEntry &entry) { return entry.targetFlag == cpuValue.toLatin1(); }); if (cpuIt != cpuEnd) targetCpu = cpuIt->coreCode; // Detect target FPU code. const QString fpuValue = IarewUtils::flagValue( flags, QStringLiteral("--fpu")) .toLower(); const auto fpuEnd = std::cend(fpusDict); const auto fpuIt = std::find_if(std::cbegin(fpusDict), fpuEnd, [fpuValue]( const FpuCoreEntry &entry) { return entry.targetFlag == fpuValue.toLatin1(); }); if (fpuIt != fpuEnd) { targetFpu = fpuIt->coreCode; targetFpuRegs = fpuIt->regsCount; } // Detect endian. const QString prop = gen::utils::cppStringModuleProperty( qbsProps, QStringLiteral("endianness")); if (prop == QLatin1String("big")) endianness = TargetPageOptions::BigEndian; else if (prop == QLatin1String("little")) endianness = TargetPageOptions::LittleEndian; } CpuCoreEntry::CpuCoreCode targetCpu = CpuCoreEntry::Arm7tdmi; FpuCoreEntry::FpuCoreCode targetFpu = FpuCoreEntry::NoVfp; FpuCoreEntry::FpuRegistersCount targetFpuRegs = FpuCoreEntry::NoFpuRegisters; Endianness endianness = LittleEndian; }; // Library 1 page options. struct LibraryOnePageOptions final { enum PrintfFormatter { PrintfAutoFormatter, PrintfFullFormatter, PrintfLargeFormatter, PrintfSmallFormatter, PrintfTinyFormatter }; enum ScanfFormatter { ScanfAutoFormatter, ScanfFullFormatter, ScanfLargeFormatter, ScanfSmallFormatter }; explicit LibraryOnePageOptions(const ProductData &qbsProduct) { const auto &qbsProps = qbsProduct.moduleProperties(); const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps); for (auto flagIt = flags.cbegin(); flagIt < flags.cend(); ++flagIt) { if (*flagIt != QLatin1String("--redirect")) continue; ++flagIt; if (flagIt->startsWith(QLatin1String("_printf="), Qt::CaseInsensitive)) { const QString prop = flagIt->split( QLatin1Char('=')).at(1).toLower(); if (prop == QLatin1String("_printffullnomb")) printfFormatter = LibraryOnePageOptions::PrintfFullFormatter; else if (prop == QLatin1String("_printflargenomb")) printfFormatter = LibraryOnePageOptions::PrintfLargeFormatter; else if (prop == QLatin1String("_printfsmallnomb")) printfFormatter = LibraryOnePageOptions::PrintfSmallFormatter; else if (prop == QLatin1String("_printftiny")) printfFormatter = LibraryOnePageOptions::PrintfTinyFormatter; } else if (flagIt->startsWith(QLatin1String("_scanf="), Qt::CaseInsensitive)) { const QString prop = flagIt->split( QLatin1Char('=')).at(1).toLower();; if (prop == QLatin1String("_scanffullnomb")) scanfFormatter = LibraryOnePageOptions::ScanfFullFormatter; else if (prop == QLatin1String("_scanflargenomb")) scanfFormatter = LibraryOnePageOptions::ScanfLargeFormatter; else if (prop == QLatin1String("_scanfsmallnomb")) scanfFormatter = LibraryOnePageOptions::ScanfSmallFormatter; } } } PrintfFormatter printfFormatter = PrintfAutoFormatter; ScanfFormatter scanfFormatter = ScanfAutoFormatter; }; // Library 2 page options. struct LibraryTwoPageOptions final { enum HeapType { AutomaticHeap, AdvancedHeap, BasicHeap, NoFreeHeap }; explicit LibraryTwoPageOptions(const ProductData &qbsProduct) { const auto &qbsProps = qbsProduct.moduleProperties(); const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps); if (flags.contains(QLatin1String("--advanced_heap"))) heapType = LibraryTwoPageOptions::AdvancedHeap; else if (flags.contains(QLatin1String("--basic_heap"))) heapType = LibraryTwoPageOptions::BasicHeap; else if (flags.contains(QLatin1String("--no_free_heap"))) heapType = LibraryTwoPageOptions::NoFreeHeap; else heapType = LibraryTwoPageOptions::AutomaticHeap; } HeapType heapType = AutomaticHeap; }; // Library configuration page options. struct LibraryConfigPageOptions final { enum RuntimeLibrary { NoLibrary, NormalLibrary, FullLibrary, CustomLibrary }; enum ThreadSupport { NoThread, EnableThread }; enum LowLevelInterface { NoInterface, SemihostedInterface }; explicit LibraryConfigPageOptions(const QString &baseDirectory, const ProductData &qbsProduct) { const auto &qbsProps = qbsProduct.moduleProperties(); const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps); const QFileInfo dlibFileInfo(IarewUtils::flagValue( flags, QStringLiteral("--dlib_config"))); if (!dlibFileInfo.exists()) { dlibType = LibraryConfigPageOptions::NoLibrary; } else { const QString toolkitPath = IarewUtils::toolkitRootPath(qbsProduct); const QString dlibFilePath = dlibFileInfo.absoluteFilePath(); if (dlibFilePath.startsWith(toolkitPath, Qt::CaseInsensitive)) { if (dlibFilePath.endsWith(QLatin1String("dlib_config_normal.h"), Qt::CaseInsensitive)) { dlibType = LibraryConfigPageOptions::NormalLibrary; } else if (dlibFilePath.endsWith( QLatin1String("dlib_config_full.h"), Qt::CaseInsensitive)) { dlibType = LibraryConfigPageOptions::FullLibrary; } else { dlibType = LibraryConfigPageOptions::CustomLibrary; } dlibConfigPath = IarewUtils::toolkitRelativeFilePath( toolkitPath, dlibFilePath); } else { dlibType = LibraryConfigPageOptions::CustomLibrary; dlibConfigPath = IarewUtils::projectRelativeFilePath( baseDirectory, dlibFilePath); } } threadSupport = flags.contains(QLatin1String("--threaded_lib")) ? LibraryConfigPageOptions::EnableThread : LibraryConfigPageOptions::NoThread; lowLevelInterface = flags.contains(QLatin1String("--semihosting")) ? LibraryConfigPageOptions::SemihostedInterface : LibraryConfigPageOptions::NoInterface; } RuntimeLibrary dlibType = NoLibrary; QString dlibConfigPath; ThreadSupport threadSupport = NoThread; LowLevelInterface lowLevelInterface = NoInterface; }; // Output page options. struct OutputPageOptions final { explicit OutputPageOptions(const QString &baseDirectory, const ProductData &qbsProduct) { binaryType = IarewUtils::outputBinaryType(qbsProduct); binaryDirectory = gen::utils::binaryOutputDirectory( baseDirectory, qbsProduct); objectDirectory = gen::utils::objectsOutputDirectory( baseDirectory, qbsProduct); listingDirectory = gen::utils::listingOutputDirectory( baseDirectory, qbsProduct); } IarewUtils::OutputBinaryType binaryType = IarewUtils::ApplicationOutputType; QString binaryDirectory; QString objectDirectory; QString listingDirectory; }; } // namespace // ArmGeneralSettingsGroup ArmGeneralSettingsGroup::ArmGeneralSettingsGroup( const Project &qbsProject, const ProductData &qbsProduct, const std::vector &qbsProductDeps) { Q_UNUSED(qbsProductDeps) setName(QByteArrayLiteral("General")); setArchiveVersion(kGeneralArchiveVersion); setDataVersion(kGeneralDataVersion); setDataDebugInfo(gen::utils::debugInformation(qbsProduct)); const QString buildRootDirectory = gen::utils::buildRootPath(qbsProject); buildTargetPage(qbsProduct); buildLibraryOptionsOnePage(qbsProduct); buildLibraryOptionsTwoPage(qbsProduct); buildLibraryConfigPage(buildRootDirectory, qbsProduct); buildOutputPage(buildRootDirectory, qbsProduct); } void ArmGeneralSettingsGroup::buildTargetPage( const ProductData &qbsProduct) { const TargetPageOptions opts(qbsProduct); // Add 'GBECoreSlave', 'CoreVariant', 'GFPUCoreSlave2' items // (Processor variant chooser). addOptionsGroup(QByteArrayLiteral("GBECoreSlave"), {26}, {opts.targetCpu}); addOptionsGroup(QByteArrayLiteral("CoreVariant"), {26}, {opts.targetCpu}); addOptionsGroup(QByteArrayLiteral("GFPUCoreSlave2"), {26}, {opts.targetCpu}); // Add 'FPU2', 'NrRegs' item (Floating point settings chooser). addOptionsGroup(QByteArrayLiteral("FPU2"), {0}, {opts.targetFpu}); addOptionsGroup(QByteArrayLiteral("NrRegs"), {0}, {opts.targetFpuRegs}); // Add 'GEndianMode' item (Endian mode chooser). addOptionsGroup(QByteArrayLiteral("GEndianMode"), {}, {opts.endianness}); } void ArmGeneralSettingsGroup::buildLibraryOptionsOnePage( const ProductData &qbsProduct) { const LibraryOnePageOptions opts(qbsProduct); // Add 'OGPrintfVariant' item (Printf formatter). addOptionsGroup(QByteArrayLiteral("OGPrintfVariant"), {}, {opts.printfFormatter}); // Add 'OGScanfVariant' item (Printf formatter). addOptionsGroup(QByteArrayLiteral("OGScanfVariant"), {}, {opts.scanfFormatter}); } void ArmGeneralSettingsGroup::buildLibraryOptionsTwoPage( const ProductData &qbsProduct) { const LibraryTwoPageOptions opts(qbsProduct); // Add 'OgLibHeap' item (Heap selection: // auto/advanced/basic/nofree). addOptionsGroup(QByteArrayLiteral("OgLibHeap"), {}, {opts.heapType}); } void ArmGeneralSettingsGroup::buildLibraryConfigPage( const QString baseDirectory, const ProductData &qbsProduct) { const LibraryConfigPageOptions opts(baseDirectory, qbsProduct); // Add 'GRuntimeLibSelect', 'GRuntimeLibSelectSlave' // and 'RTConfigPath2' items // (Link with runtime: none/normal/full/custom). addOptionsGroup(QByteArrayLiteral("GRuntimeLibSelect"), {}, {opts.dlibType}); addOptionsGroup(QByteArrayLiteral("GRuntimeLibSelectSlave"), {}, {opts.dlibType}); addOptionsGroup(QByteArrayLiteral("RTConfigPath2"), {}, {opts.dlibConfigPath}); // Add 'GRuntimeLibThreads'item // (Enable thread support in library). addOptionsGroup(QByteArrayLiteral("GRuntimeLibThreads"), {}, {opts.threadSupport}); // Add 'GenLowLevelInterface' item (Library low-level // interface: none/semihosted/breakpoint). addOptionsGroup(QByteArrayLiteral("GenLowLevelInterface"), {}, {opts.lowLevelInterface}); } void ArmGeneralSettingsGroup::buildOutputPage( const QString baseDirectory, const ProductData &qbsProduct) { const OutputPageOptions opts(baseDirectory, qbsProduct); // Add 'GOutputBinary' item // (Output file: executable/library). addOptionsGroup(QByteArrayLiteral("GOutputBinary"), {}, {opts.binaryType}); // Add 'ExePath' item // (Executable/binaries output directory). addOptionsGroup(QByteArrayLiteral("ExePath"), {}, {opts.binaryDirectory}); // Add 'ObjPath' item // (Object files output directory). addOptionsGroup(QByteArrayLiteral("ObjPath"), {}, {opts.objectDirectory}); // Add 'ListPath' item // (List files output directory). addOptionsGroup(QByteArrayLiteral("ListPath"), {}, {opts.listingDirectory}); } } // namespace v8 } // namespace arm } // namespace iarew } // namespace qbs