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.

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