The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

827 lines
31KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 7 technical preview.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For the technical preview this file cannot be licensed commercially.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. #pragma once
  14. #include "jucer_ProjectExport_MSVC.h"
  15. //==============================================================================
  16. class CodeBlocksProjectExporter : public ProjectExporter
  17. {
  18. public:
  19. enum CodeBlocksOS
  20. {
  21. windowsTarget,
  22. linuxTarget
  23. };
  24. //==============================================================================
  25. static String getDisplayNameWindows() { return "Code::Blocks (Windows)"; }
  26. static String getDisplayNameLinux() { return "Code::Blocks (Linux)"; }
  27. static String getValueTreeTypeNameWindows() { return "CODEBLOCKS_WINDOWS"; }
  28. static String getValueTreeTypeNameLinux() { return "CODEBLOCKS_LINUX"; }
  29. static String getTargetFolderNameWindows() { return "CodeBlocksWindows"; }
  30. static String getTargetFolderNameLinux() { return "CodeBlocksLinux"; }
  31. //==============================================================================
  32. static CodeBlocksProjectExporter* createForSettings (Project& projectToUse, const ValueTree& settingsToUse)
  33. {
  34. // this will also import legacy jucer files where CodeBlocks only worked for Windows,
  35. // had valueTreetTypeName "CODEBLOCKS", and there was no OS distinction
  36. if (settingsToUse.hasType (getValueTreeTypeNameWindows()) || settingsToUse.hasType ("CODEBLOCKS"))
  37. return new CodeBlocksProjectExporter (projectToUse, settingsToUse, windowsTarget);
  38. if (settingsToUse.hasType (getValueTreeTypeNameLinux()))
  39. return new CodeBlocksProjectExporter (projectToUse, settingsToUse, linuxTarget);
  40. return nullptr;
  41. }
  42. //==============================================================================
  43. CodeBlocksProjectExporter (Project& p, const ValueTree& t, CodeBlocksOS codeBlocksOs)
  44. : ProjectExporter (p, t), os (codeBlocksOs)
  45. {
  46. if (isWindows())
  47. {
  48. name = getDisplayNameWindows();
  49. targetLocationValue.setDefault (getDefaultBuildsRootFolder() + getTargetFolderNameWindows());
  50. targetPlatformValue.referTo (settings, Ids::codeBlocksWindowsTarget, getUndoManager());
  51. }
  52. else
  53. {
  54. name = getDisplayNameLinux();
  55. targetLocationValue.setDefault (getDefaultBuildsRootFolder() + getTargetFolderNameLinux());
  56. }
  57. }
  58. //==============================================================================
  59. bool canLaunchProject() override { return false; }
  60. bool launchProject() override { return false; }
  61. bool usesMMFiles() const override { return false; }
  62. bool canCopeWithDuplicateFiles() override { return false; }
  63. bool supportsUserDefinedConfigurations() const override { return true; }
  64. bool isXcode() const override { return false; }
  65. bool isVisualStudio() const override { return false; }
  66. bool isCodeBlocks() const override { return true; }
  67. bool isMakefile() const override { return false; }
  68. bool isAndroidStudio() const override { return false; }
  69. bool isCLion() const override { return false; }
  70. bool isAndroid() const override { return false; }
  71. bool isWindows() const override { return os == windowsTarget; }
  72. bool isLinux() const override { return os == linuxTarget; }
  73. bool isOSX() const override { return false; }
  74. bool isiOS() const override { return false; }
  75. Identifier getExporterIdentifier() const override
  76. {
  77. return isLinux() ? getValueTreeTypeNameLinux() : getValueTreeTypeNameWindows();
  78. }
  79. String getNewLineString() const override { return isWindows() ? "\r\n" : "\n"; }
  80. bool supportsTargetType (build_tools::ProjectType::Target::Type type) const override
  81. {
  82. using Target = build_tools::ProjectType::Target;
  83. switch (type)
  84. {
  85. case Target::StandalonePlugIn:
  86. case Target::GUIApp:
  87. case Target::ConsoleApp:
  88. case Target::StaticLibrary:
  89. case Target::SharedCodeTarget:
  90. case Target::AggregateTarget:
  91. case Target::VSTPlugIn:
  92. case Target::DynamicLibrary:
  93. return true;
  94. case Target::AAXPlugIn:
  95. case Target::RTASPlugIn:
  96. case Target::UnityPlugIn:
  97. case Target::LV2PlugIn:
  98. case Target::LV2TurtleProgram:
  99. case Target::VST3PlugIn:
  100. case Target::AudioUnitPlugIn:
  101. case Target::AudioUnitv3PlugIn:
  102. case Target::unspecified:
  103. default:
  104. break;
  105. }
  106. return false;
  107. }
  108. void createExporterProperties (PropertyListBuilder& props) override
  109. {
  110. if (isWindows())
  111. {
  112. props.add (new ChoicePropertyComponent (targetPlatformValue, "Target platform",
  113. { "Windows NT 4.0", "Windows 2000", "Windows XP", "Windows Server 2003", "Windows Vista", "Windows Server 2008",
  114. "Windows 7", "Windows 8", "Windows 8.1", "Windows 10" },
  115. { "0x0400", "0x0500", "0x0501", "0x0502", "0x0600", "0x0600",
  116. "0x0601", "0x0602", "0x0603", "0x0A00" }),
  117. "This sets the preprocessor macro WINVER to an appropriate value for the corresponding platform.");
  118. }
  119. }
  120. //==============================================================================
  121. void create (const OwnedArray<LibraryModule>&) const override
  122. {
  123. auto cbpFile = getTargetFolder().getChildFile (project.getProjectFilenameRootString())
  124. .withFileExtension (".cbp");
  125. XmlElement xml ("CodeBlocks_project_file");
  126. addVersion (xml);
  127. createProject (*xml.createNewChildElement ("Project"));
  128. writeXmlOrThrow (xml, cbpFile, "UTF-8", 10, true);
  129. }
  130. //==============================================================================
  131. void addPlatformSpecificSettingsForProjectType (const build_tools::ProjectType&) override
  132. {
  133. // add shared code target first as order matters for Codeblocks
  134. if (shouldBuildTargetType (build_tools::ProjectType::Target::SharedCodeTarget))
  135. targets.add (new CodeBlocksTarget (*this, build_tools::ProjectType::Target::SharedCodeTarget));
  136. //resource::ProjectType::Target::SharedCodeTarget
  137. callForAllSupportedTargets ([this] (build_tools::ProjectType::Target::Type targetType)
  138. {
  139. if (targetType == build_tools::ProjectType::Target::SharedCodeTarget)
  140. return;
  141. targets.insert (targetType == build_tools::ProjectType::Target::AggregateTarget ? 0 : -1,
  142. new CodeBlocksTarget (*this, targetType));
  143. });
  144. // If you hit this assert, you tried to generate a project for an exporter
  145. // that does not support any of your targets!
  146. jassert (targets.size() > 0);
  147. }
  148. void initialiseDependencyPathValues() override
  149. {
  150. auto targetOS = isWindows() ? TargetOS::windows : TargetOS::linux;
  151. vstLegacyPathValueWrapper.init ({ settings, Ids::vstLegacyFolder, nullptr },
  152. getAppSettings().getStoredPath (Ids::vstLegacyPath, targetOS), targetOS);
  153. }
  154. private:
  155. ValueTreePropertyWithDefault targetPlatformValue;
  156. String getTargetPlatformString() const { return targetPlatformValue.get(); }
  157. //==============================================================================
  158. class CodeBlocksBuildConfiguration : public BuildConfiguration
  159. {
  160. public:
  161. CodeBlocksBuildConfiguration (Project& p, const ValueTree& settings, const ProjectExporter& e)
  162. : BuildConfiguration (p, settings, e),
  163. architectureTypeValue (config, exporter.isWindows() ? Ids::windowsCodeBlocksArchitecture
  164. : Ids::linuxCodeBlocksArchitecture, getUndoManager(), "-m64")
  165. {
  166. linkTimeOptimisationValue.setDefault (false);
  167. optimisationLevelValue.setDefault (isDebug() ? gccO0 : gccO3);
  168. }
  169. void createConfigProperties (PropertyListBuilder& props) override
  170. {
  171. addRecommendedLinuxCompilerWarningsProperty (props);
  172. addGCCOptimisationProperty (props);
  173. props.add (new ChoicePropertyComponent (architectureTypeValue, "Architecture",
  174. { "32-bit (-m32)", "64-bit (-m64)", "ARM v6", "ARM v7" },
  175. { "-m32", "-m64", "-march=armv6", "-march=armv7" }),
  176. "Specifies the 32/64-bit architecture to use.");
  177. }
  178. String getModuleLibraryArchName() const override
  179. {
  180. auto archFlag = getArchitectureTypeString();
  181. String prefix ("-march=");
  182. if (archFlag.startsWith (prefix))
  183. return archFlag.substring (prefix.length());
  184. else if (archFlag == "-m64")
  185. return "x86_64";
  186. else if (archFlag == "-m32")
  187. return "i386";
  188. jassertfalse;
  189. return {};
  190. }
  191. String getArchitectureTypeString() const { return architectureTypeValue.get(); }
  192. //==============================================================================
  193. ValueTreePropertyWithDefault architectureTypeValue;
  194. };
  195. BuildConfiguration::Ptr createBuildConfig (const ValueTree& tree) const override
  196. {
  197. return *new CodeBlocksBuildConfiguration (project, tree, *this);
  198. }
  199. //==============================================================================
  200. class CodeBlocksTarget : public build_tools::ProjectType::Target
  201. {
  202. public:
  203. CodeBlocksTarget (const CodeBlocksProjectExporter& e,
  204. build_tools::ProjectType::Target::Type typeToUse)
  205. : Target (typeToUse),
  206. exporter (e)
  207. {}
  208. String getTargetNameForConfiguration (const BuildConfiguration& config) const
  209. {
  210. if (type == build_tools::ProjectType::Target::AggregateTarget)
  211. return config.getName();
  212. return getName() + String (" | ") + config.getName();
  213. }
  214. String getTargetSuffix() const
  215. {
  216. auto fileType = getTargetFileType();
  217. if (exporter.isWindows())
  218. {
  219. switch (fileType)
  220. {
  221. case executable: return ".exe";
  222. case staticLibrary: return ".lib";
  223. case sharedLibraryOrDLL:
  224. case pluginBundle: return ".dll";
  225. case macOSAppex:
  226. case unknown:
  227. default:
  228. break;
  229. }
  230. }
  231. else
  232. {
  233. switch (fileType)
  234. {
  235. case executable: return {};
  236. case staticLibrary: return ".a";
  237. case pluginBundle:
  238. case sharedLibraryOrDLL: return ".so";
  239. case macOSAppex:
  240. case unknown:
  241. default:
  242. break;
  243. }
  244. }
  245. return {};
  246. }
  247. bool isDynamicLibrary() const
  248. {
  249. return (type == DynamicLibrary || type == VSTPlugIn);
  250. }
  251. const CodeBlocksProjectExporter& exporter;
  252. };
  253. //==============================================================================
  254. void addVersion (XmlElement& xml) const
  255. {
  256. auto* fileVersion = xml.createNewChildElement ("FileVersion");
  257. fileVersion->setAttribute ("major", 1);
  258. fileVersion->setAttribute ("minor", 6);
  259. }
  260. void addOptions (XmlElement& xml) const
  261. {
  262. xml.createNewChildElement ("Option")->setAttribute ("title", project.getProjectNameString());
  263. xml.createNewChildElement ("Option")->setAttribute ("pch_mode", 2);
  264. xml.createNewChildElement ("Option")->setAttribute ("compiler", "gcc");
  265. }
  266. StringArray getDefines (const BuildConfiguration& config, CodeBlocksTarget& target) const
  267. {
  268. StringPairArray defines;
  269. if (isWindows())
  270. {
  271. defines.set ("__MINGW__", "1");
  272. defines.set ("__MINGW_EXTENSION", {});
  273. auto targetPlatform = getTargetPlatformString();
  274. if (targetPlatform.isNotEmpty())
  275. defines.set ("WINVER", targetPlatform);
  276. }
  277. else
  278. {
  279. defines.set ("LINUX", "1");
  280. }
  281. if (config.isDebug())
  282. {
  283. defines.set ("DEBUG", "1");
  284. defines.set ("_DEBUG", "1");
  285. }
  286. else
  287. {
  288. defines.set ("NDEBUG", "1");
  289. }
  290. defines = mergePreprocessorDefs (defines, getAllPreprocessorDefs (config, target.type));
  291. StringArray defs;
  292. auto keys = defines.getAllKeys();
  293. auto values = defines.getAllValues();
  294. const auto escapedQuote = isWindows() ? "\\\"" : "\\\\\"";
  295. for (int i = 0; i < defines.size(); ++i)
  296. {
  297. auto result = keys[i];
  298. if (values[i].isNotEmpty())
  299. result += "=\"" + values[i].replace ("\"", escapedQuote) + "\"";
  300. defs.add (result);
  301. }
  302. return getCleanedStringArray (defs);
  303. }
  304. StringArray getCompilerFlags (const BuildConfiguration& config, CodeBlocksTarget& target) const
  305. {
  306. StringArray flags;
  307. if (auto* codeBlocksConfig = dynamic_cast<const CodeBlocksBuildConfiguration*> (&config))
  308. flags.add (codeBlocksConfig->getArchitectureTypeString());
  309. auto recommendedFlags = config.getRecommendedCompilerWarningFlags();
  310. for (auto& recommendedFlagsType : { recommendedFlags.common, recommendedFlags.cpp })
  311. for (auto& recommended : recommendedFlagsType)
  312. flags.add (recommended);
  313. flags.add ("-O" + config.getGCCOptimisationFlag());
  314. if (config.isLinkTimeOptimisationEnabled())
  315. flags.add ("-flto");
  316. {
  317. auto cppStandard = config.project.getCppStandardString();
  318. if (cppStandard == "latest")
  319. cppStandard = project.getLatestNumberedCppStandardString();
  320. flags.add ("-std=" + String (shouldUseGNUExtensions() ? "gnu++" : "c++") + cppStandard);
  321. }
  322. flags.add ("-mstackrealign");
  323. if (config.isDebug())
  324. flags.add ("-g");
  325. flags.addTokens (replacePreprocessorTokens (config, getExtraCompilerFlagsString()).trim(),
  326. " \n", "\"'");
  327. if (config.exporter.isLinux())
  328. {
  329. if (target.isDynamicLibrary() || getProject().isAudioPluginProject())
  330. flags.add ("-fPIC");
  331. auto packages = config.exporter.getLinuxPackages (PackageDependencyType::compile);
  332. if (! packages.isEmpty())
  333. {
  334. auto pkgconfigFlags = String ("`pkg-config --cflags");
  335. for (auto& p : packages)
  336. pkgconfigFlags << " " << p;
  337. pkgconfigFlags << "`";
  338. flags.add (pkgconfigFlags);
  339. }
  340. if (linuxLibs.contains ("pthread"))
  341. flags.add ("-pthread");
  342. }
  343. return getCleanedStringArray (flags);
  344. }
  345. StringArray getLinkerFlags (const BuildConfiguration& config, CodeBlocksTarget& target) const
  346. {
  347. auto flags = makefileExtraLinkerFlags;
  348. if (auto* codeBlocksConfig = dynamic_cast<const CodeBlocksBuildConfiguration*> (&config))
  349. flags.add (codeBlocksConfig->getArchitectureTypeString());
  350. if (! config.isDebug())
  351. flags.add ("-s");
  352. if (config.isLinkTimeOptimisationEnabled())
  353. flags.add ("-flto");
  354. flags.addTokens (replacePreprocessorTokens (config, getExtraLinkerFlagsString()).trim(), " \n", "\"'");
  355. if (config.exporter.isLinux())
  356. {
  357. if (target.isDynamicLibrary())
  358. flags.add ("-shared");
  359. auto packages = config.exporter.getLinuxPackages (PackageDependencyType::link);
  360. if (! packages.isEmpty())
  361. {
  362. String pkgconfigLibs ("`pkg-config --libs");
  363. for (auto& p : packages)
  364. pkgconfigLibs << " " << p;
  365. pkgconfigLibs << "`";
  366. flags.add (pkgconfigLibs);
  367. }
  368. }
  369. return getCleanedStringArray (flags);
  370. }
  371. StringArray getLinkerSearchPaths (const BuildConfiguration& config, CodeBlocksTarget& target) const
  372. {
  373. auto librarySearchPaths = config.getLibrarySearchPaths();
  374. if (getProject().isAudioPluginProject() && target.type != build_tools::ProjectType::Target::SharedCodeTarget)
  375. librarySearchPaths.add (build_tools::RelativePath (getSharedCodePath (config), build_tools::RelativePath::buildTargetFolder).getParentDirectory().toUnixStyle().quoted());
  376. return librarySearchPaths;
  377. }
  378. StringArray getIncludePaths (const BuildConfiguration& config) const
  379. {
  380. StringArray paths;
  381. paths.add (".");
  382. paths.addArray (extraSearchPaths);
  383. paths.addArray (config.getHeaderSearchPaths());
  384. if (! isWindows())
  385. {
  386. paths.add ("/usr/include/freetype2");
  387. // Replace ~ character with $(HOME) environment variable
  388. for (auto& path : paths)
  389. path = path.replace ("~", "$(HOME)");
  390. }
  391. return getCleanedStringArray (paths);
  392. }
  393. static int getTypeIndex (const build_tools::ProjectType::Target::Type& type)
  394. {
  395. if (type == build_tools::ProjectType::Target::GUIApp || type == build_tools::ProjectType::Target::StandalonePlugIn) return 0;
  396. if (type == build_tools::ProjectType::Target::ConsoleApp) return 1;
  397. if (type == build_tools::ProjectType::Target::StaticLibrary || type == build_tools::ProjectType::Target::SharedCodeTarget) return 2;
  398. if (type == build_tools::ProjectType::Target::DynamicLibrary || type == build_tools::ProjectType::Target::VSTPlugIn) return 3;
  399. return 0;
  400. }
  401. String getOutputPathForTarget (CodeBlocksTarget& target, const BuildConfiguration& config) const
  402. {
  403. String outputPath;
  404. if (config.getTargetBinaryRelativePathString().isNotEmpty())
  405. {
  406. build_tools::RelativePath binaryPath (config.getTargetBinaryRelativePathString(), build_tools::RelativePath::projectFolder);
  407. binaryPath = binaryPath.rebased (projectFolder, getTargetFolder(), build_tools::RelativePath::buildTargetFolder);
  408. outputPath = config.getTargetBinaryRelativePathString();
  409. }
  410. else
  411. {
  412. outputPath ="bin/" + File::createLegalFileName (config.getName().trim());
  413. }
  414. return outputPath + "/" + replacePreprocessorTokens (config, config.getTargetBinaryNameString() + target.getTargetSuffix());
  415. }
  416. String getSharedCodePath (const BuildConfiguration& config) const
  417. {
  418. auto outputPath = getOutputPathForTarget (getTargetWithType (build_tools::ProjectType::Target::SharedCodeTarget), config);
  419. build_tools::RelativePath path (outputPath, build_tools::RelativePath::buildTargetFolder);
  420. auto filename = path.getFileName();
  421. if (isLinux())
  422. filename = "lib" + filename;
  423. return path.getParentDirectory().getChildFile (filename).toUnixStyle();
  424. }
  425. void createBuildTarget (XmlElement& xml, CodeBlocksTarget& target, const BuildConfiguration& config) const
  426. {
  427. xml.setAttribute ("title", target.getTargetNameForConfiguration (config));
  428. {
  429. auto* output = xml.createNewChildElement ("Option");
  430. output->setAttribute ("output", getOutputPathForTarget (target, config));
  431. if (isLinux())
  432. {
  433. bool keepPrefix = (target.type == build_tools::ProjectType::Target::VSTPlugIn);
  434. output->setAttribute ("prefix_auto", keepPrefix ? 0 : 1);
  435. }
  436. else
  437. {
  438. output->setAttribute ("prefix_auto", 0);
  439. }
  440. output->setAttribute ("extension_auto", 0);
  441. }
  442. xml.createNewChildElement ("Option")
  443. ->setAttribute ("object_output", "obj/" + File::createLegalFileName (config.getName().trim()));
  444. xml.createNewChildElement ("Option")->setAttribute ("type", getTypeIndex (target.type));
  445. xml.createNewChildElement ("Option")->setAttribute ("compiler", "gcc");
  446. if (getProject().isAudioPluginProject() && target.type != build_tools::ProjectType::Target::SharedCodeTarget)
  447. xml.createNewChildElement ("Option")->setAttribute ("external_deps", getSharedCodePath (config));
  448. {
  449. auto* compiler = xml.createNewChildElement ("Compiler");
  450. {
  451. StringArray flags;
  452. for (auto& def : getDefines (config, target))
  453. {
  454. if (! def.containsChar ('='))
  455. def << '=';
  456. flags.add ("-D" + def);
  457. }
  458. flags.addArray (getCompilerFlags (config, target));
  459. for (auto flag : flags)
  460. setAddOption (*compiler, "option", flag);
  461. }
  462. {
  463. auto includePaths = getIncludePaths (config);
  464. for (auto path : includePaths)
  465. setAddOption (*compiler, "directory", path);
  466. }
  467. }
  468. {
  469. auto* linker = xml.createNewChildElement ("Linker");
  470. if (getProject().isAudioPluginProject() && target.type != build_tools::ProjectType::Target::SharedCodeTarget)
  471. setAddOption (*linker, "option", getSharedCodePath (config).quoted());
  472. for (auto& flag : getLinkerFlags (config, target))
  473. setAddOption (*linker, "option", flag);
  474. const StringArray& libs = isWindows() ? mingwLibs : linuxLibs;
  475. for (auto lib : libs)
  476. setAddOption (*linker, "library", lib);
  477. for (auto& path : getLinkerSearchPaths (config, target))
  478. setAddOption (*linker, "directory",
  479. build_tools::replacePreprocessorDefs (getAllPreprocessorDefs(), path));
  480. }
  481. }
  482. void addBuild (XmlElement& xml) const
  483. {
  484. auto* build = xml.createNewChildElement ("Build");
  485. for (ConstConfigIterator config (*this); config.next();)
  486. for (auto target : targets)
  487. if (target->type != build_tools::ProjectType::Target::AggregateTarget)
  488. createBuildTarget (*build->createNewChildElement ("Target"), *target, *config);
  489. }
  490. void addVirtualTargets (XmlElement& xml) const
  491. {
  492. auto* virtualTargets = xml.createNewChildElement ("VirtualTargets");
  493. for (ConstConfigIterator config (*this); config.next();)
  494. {
  495. StringArray allTargets;
  496. for (auto target : targets)
  497. if (target->type != build_tools::ProjectType::Target::AggregateTarget)
  498. allTargets.add (target->getTargetNameForConfiguration (*config));
  499. for (auto target : targets)
  500. {
  501. if (target->type == build_tools::ProjectType::Target::AggregateTarget)
  502. {
  503. auto* configTarget = virtualTargets->createNewChildElement ("Add");
  504. configTarget->setAttribute ("alias", config->getName());
  505. configTarget->setAttribute ("targets", allTargets.joinIntoString (";"));
  506. }
  507. }
  508. }
  509. }
  510. StringArray getProjectCompilerOptions() const
  511. {
  512. return { "-Wall", "-Wno-strict-aliasing", "-Wno-strict-overflow" };
  513. }
  514. void addProjectCompilerOptions (XmlElement& xml) const
  515. {
  516. auto* compiler = xml.createNewChildElement ("Compiler");
  517. for (auto& option : getProjectCompilerOptions())
  518. setAddOption (*compiler, "option", option);
  519. }
  520. StringArray getProjectLinkerLibs() const
  521. {
  522. StringArray result;
  523. if (isWindows())
  524. result.addArray ({ "gdi32", "user32", "kernel32", "comctl32" });
  525. result.addTokens (getExternalLibrariesString(), ";\n", "\"'");
  526. result = getCleanedStringArray (result);
  527. for (auto& option : result)
  528. option = build_tools::replacePreprocessorDefs (getAllPreprocessorDefs(), option);
  529. return result;
  530. }
  531. void addProjectLinkerOptions (XmlElement& xml) const
  532. {
  533. auto* linker = xml.createNewChildElement ("Linker");
  534. for (auto& lib : getProjectLinkerLibs())
  535. setAddOption (*linker, "library", lib);
  536. }
  537. CodeBlocksTarget& getTargetWithType (build_tools::ProjectType::Target::Type type) const
  538. {
  539. CodeBlocksTarget* nonAggregrateTarget = nullptr;
  540. for (auto* target : targets)
  541. {
  542. if (target->type == type)
  543. return *target;
  544. if (target->type != build_tools::ProjectType::Target::AggregateTarget)
  545. nonAggregrateTarget = target;
  546. }
  547. // this project has no valid targets
  548. jassert (nonAggregrateTarget != nullptr);
  549. return *nonAggregrateTarget;
  550. }
  551. // Returns SharedCode target for multi-target projects, otherwise it returns
  552. // the single target
  553. CodeBlocksTarget& getMainTarget() const
  554. {
  555. if (getProject().isAudioPluginProject())
  556. return getTargetWithType (build_tools::ProjectType::Target::SharedCodeTarget);
  557. for (auto* target : targets)
  558. if (target->type != build_tools::ProjectType::Target::AggregateTarget)
  559. return *target;
  560. jassertfalse;
  561. return *targets[0];
  562. }
  563. CodeBlocksTarget& getTargetForProjectItem (const Project::Item& projectItem) const
  564. {
  565. if (getProject().isAudioPluginProject())
  566. {
  567. if (! projectItem.shouldBeCompiled())
  568. return getTargetWithType (build_tools::ProjectType::Target::SharedCodeTarget);
  569. return getTargetWithType (getProject().getTargetTypeFromFilePath (projectItem.getFile(), true));
  570. }
  571. return getMainTarget();
  572. }
  573. void addCompileUnits (const Project::Item& projectItem, XmlElement& xml) const
  574. {
  575. if (projectItem.isGroup())
  576. {
  577. for (int i = 0; i < projectItem.getNumChildren(); ++i)
  578. addCompileUnits (projectItem.getChild(i), xml);
  579. }
  580. else if (projectItem.shouldBeAddedToTargetProject() && projectItem.shouldBeAddedToTargetExporter (*this))
  581. {
  582. build_tools::RelativePath file (projectItem.getFile(), getTargetFolder(), build_tools::RelativePath::buildTargetFolder);
  583. auto* unit = xml.createNewChildElement ("Unit");
  584. unit->setAttribute ("filename", file.toUnixStyle());
  585. for (ConstConfigIterator config (*this); config.next();)
  586. {
  587. auto targetName = getTargetForProjectItem (projectItem).getTargetNameForConfiguration (*config);
  588. unit->createNewChildElement ("Option")->setAttribute ("target", targetName);
  589. }
  590. if (projectItem.shouldBeCompiled())
  591. {
  592. auto extraCompilerFlags = compilerFlagSchemesMap[projectItem.getCompilerFlagSchemeString()].get().toString();
  593. if (extraCompilerFlags.isNotEmpty())
  594. {
  595. auto* optionElement = unit->createNewChildElement ("Option");
  596. optionElement->setAttribute ("compiler", "gcc");
  597. optionElement->setAttribute ("use", 1);
  598. optionElement->setAttribute ("buildCommand", "$compiler $options " + extraCompilerFlags + " $includes -c $file -o $object");
  599. }
  600. }
  601. else
  602. {
  603. unit->createNewChildElement ("Option")->setAttribute ("compile", 0);
  604. unit->createNewChildElement ("Option")->setAttribute ("link", 0);
  605. }
  606. }
  607. }
  608. bool hasResourceFile() const
  609. {
  610. return ! projectType.isStaticLibrary();
  611. }
  612. void addCompileUnits (XmlElement& xml) const
  613. {
  614. for (int i = 0; i < getAllGroups().size(); ++i)
  615. addCompileUnits (getAllGroups().getReference(i), xml);
  616. if (hasResourceFile())
  617. {
  618. const auto iconFile = getTargetFolder().getChildFile ("icon.ico");
  619. if (! build_tools::asArray (getIcons()).isEmpty())
  620. build_tools::writeWinIcon (getIcons(), iconFile);
  621. auto rcFile = getTargetFolder().getChildFile ("resources.rc");
  622. MSVCProjectExporterBase::createRCFile (project, iconFile, rcFile);
  623. auto* unit = xml.createNewChildElement ("Unit");
  624. unit->setAttribute ("filename", rcFile.getFileName());
  625. unit->createNewChildElement ("Option")->setAttribute ("compilerVar", "WINDRES");
  626. }
  627. }
  628. void createProject (XmlElement& xml) const
  629. {
  630. addOptions (xml);
  631. addBuild (xml);
  632. addVirtualTargets (xml);
  633. addProjectCompilerOptions (xml);
  634. addProjectLinkerOptions (xml);
  635. addCompileUnits (xml);
  636. }
  637. void setAddOption (XmlElement& xml, const String& nm, const String& value) const
  638. {
  639. xml.createNewChildElement ("Add")->setAttribute (nm, value);
  640. }
  641. CodeBlocksOS os;
  642. OwnedArray<CodeBlocksTarget> targets;
  643. friend class CLionProjectExporter;
  644. JUCE_DECLARE_NON_COPYABLE (CodeBlocksProjectExporter)
  645. };