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.

841 lines
32KB

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