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.

831 lines
31KB

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