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.

826 lines
31KB

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