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.

834 lines
30KB

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