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.

1187 lines
54KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. #pragma once
  20. #include "jucer_ProjectExport_CodeBlocks.h"
  21. #include "jucer_ProjectExport_Make.h"
  22. #include "jucer_ProjectExport_Xcode.h"
  23. //==============================================================================
  24. class CLionProjectExporter : public ProjectExporter
  25. {
  26. protected:
  27. //==============================================================================
  28. class CLionBuildConfiguration : public BuildConfiguration
  29. {
  30. public:
  31. CLionBuildConfiguration (Project& p, const ValueTree& settings, const ProjectExporter& e)
  32. : BuildConfiguration (p, settings, e)
  33. {
  34. }
  35. void createConfigProperties (PropertyListBuilder&) override {}
  36. String getModuleLibraryArchName() const override { return {}; }
  37. };
  38. BuildConfiguration::Ptr createBuildConfig (const ValueTree& tree) const override
  39. {
  40. return *new CLionBuildConfiguration (project, tree, *this);
  41. }
  42. public:
  43. //==============================================================================
  44. static const char* getName() { return "CLion (beta)"; }
  45. static const char* getValueTreeTypeName() { return "CLION"; }
  46. static CLionProjectExporter* createForSettings (Project& projectToUse, const ValueTree& settingsToUse)
  47. {
  48. if (settingsToUse.hasType (getValueTreeTypeName()))
  49. return new CLionProjectExporter (projectToUse, settingsToUse);
  50. return nullptr;
  51. }
  52. static bool isExporterSupported (const ProjectExporter& exporter)
  53. {
  54. return exporter.isMakefile()
  55. || (exporter.isXcode() && ! exporter.isiOS())
  56. || (exporter.isCodeBlocks() && exporter.isWindows());
  57. }
  58. //==============================================================================
  59. CLionProjectExporter (Project& p, const ValueTree& t) : ProjectExporter (p, t)
  60. {
  61. name = getName();
  62. targetLocationValue.setDefault (getDefaultBuildsRootFolder() + getTargetFolderForExporter (getValueTreeTypeName()));
  63. }
  64. //==============================================================================
  65. bool usesMMFiles() const override { return false; }
  66. bool canCopeWithDuplicateFiles() override { return false; }
  67. bool supportsUserDefinedConfigurations() const override { return false; }
  68. bool isXcode() const override { return false; }
  69. bool isVisualStudio() const override { return false; }
  70. bool isCodeBlocks() const override { return false; }
  71. bool isMakefile() const override { return false; }
  72. bool isAndroidStudio() const override { return false; }
  73. bool isCLion() const override { return true; }
  74. bool isAndroid() const override { return false; }
  75. bool isWindows() const override { return false; }
  76. bool isLinux() const override { return false; }
  77. bool isOSX() const override { return false; }
  78. bool isiOS() const override { return false; }
  79. bool supportsTargetType (ProjectType::Target::Type) const override { return true; }
  80. void addPlatformSpecificSettingsForProjectType (const ProjectType&) override {}
  81. //==============================================================================
  82. bool canLaunchProject() override
  83. {
  84. #if JUCE_MAC
  85. static Identifier exporterName ("XCODE_MAC");
  86. #elif JUCE_WINDOWS
  87. static Identifier exporterName ("CODEBLOCKS_WINDOWS");
  88. #elif JUCE_LINUX
  89. static Identifier exporterName ("LINUX_MAKE");
  90. #else
  91. static Identifier exporterName;
  92. #endif
  93. if (getProject().getExporters().getChildWithName (exporterName).isValid())
  94. return getCLionExecutableOrApp().exists();
  95. return false;
  96. }
  97. bool launchProject() override
  98. {
  99. return getCLionExecutableOrApp().startAsProcess (getTargetFolder().getFullPathName().quoted());
  100. }
  101. String getDescription() override
  102. {
  103. String description;
  104. description << "The " << getName() << " exporter produces a single CMakeLists.txt file with "
  105. << "multiple platform dependent sections, where the configuration for each section "
  106. << "is inherited from other exporters added to this project." << newLine
  107. << newLine
  108. << "The exporters which provide the CLion configuration for the corresponding platform are:" << newLine
  109. << newLine;
  110. for (auto& exporterName : getExporterNames())
  111. {
  112. std::unique_ptr<ProjectExporter> exporter (createNewExporter (getProject(), exporterName));
  113. if (isExporterSupported (*exporter))
  114. description << exporter->getName() << newLine;
  115. }
  116. description << newLine
  117. << "Add these exporters to the project to enable CLion builds." << newLine
  118. << newLine
  119. << "Not all features of all the exporters are currently supported. Notable omissions are AUv3 "
  120. << "plug-ins, embedding resources and fat binaries on MacOS. On Windows the CLion exporter "
  121. << "requires a GCC-based compiler like MinGW.";
  122. return description;
  123. }
  124. void createExporterProperties (PropertyListBuilder& properties) override
  125. {
  126. for (Project::ExporterIterator exporter (getProject()); exporter.next();)
  127. if (isExporterSupported (*exporter))
  128. properties.add (new BooleanPropertyComponent (getExporterEnabledValue (*exporter), "Import settings from exporter", exporter->getName()),
  129. "If this is enabled then settings from the corresponding exporter will "
  130. "be used in the generated CMakeLists.txt");
  131. }
  132. void createDefaultConfigs() override {}
  133. void create (const OwnedArray<LibraryModule>&) const override
  134. {
  135. MemoryOutputStream out;
  136. out.setNewLineString ("\n");
  137. out << "# Automatically generated CMakeLists, created by the Projucer" << newLine
  138. << "# Do not edit this file! Your changes will be overwritten when you re-save the Projucer project!" << newLine
  139. << newLine;
  140. out << "cmake_minimum_required (VERSION 3.4.1)" << newLine
  141. << newLine;
  142. out << "if (NOT CMAKE_BUILD_TYPE)" << newLine
  143. << " set (CMAKE_BUILD_TYPE \"Debug\" CACHE STRING \"Choose the type of build.\" FORCE)" << newLine
  144. << "endif (NOT CMAKE_BUILD_TYPE)" << newLine
  145. << newLine;
  146. // We'll append to this later.
  147. overwriteFileIfDifferentOrThrow (getTargetFolder().getChildFile ("CMakeLists.txt"), out);
  148. // CMake has stopped adding PkgInfo files to bundles, so we need to do it manually
  149. MemoryOutputStream pkgInfoOut;
  150. pkgInfoOut << "BNDL????";
  151. overwriteFileIfDifferentOrThrow (getTargetFolder().getChildFile ("PkgInfo"), out);
  152. }
  153. void writeCMakeListsExporterSection (ProjectExporter* exporter) const
  154. {
  155. if (! (isExporterSupported (*exporter) && isExporterEnabled (*exporter)))
  156. return;
  157. MemoryBlock existingContent;
  158. getTargetFolder().getChildFile ("CMakeLists.txt").loadFileAsData (existingContent);
  159. MemoryOutputStream out (existingContent, true);
  160. out.setNewLineString ("\n");
  161. out << "###############################################################################" << newLine
  162. << "# " << exporter->getName() << newLine
  163. << "###############################################################################" << newLine
  164. << newLine;
  165. if (auto* makefileExporter = dynamic_cast<MakefileProjectExporter*> (exporter))
  166. {
  167. out << "if (UNIX AND NOT APPLE)" << newLine << newLine;
  168. writeCMakeListsMakefileSection (out, *makefileExporter);
  169. }
  170. else if (auto* xcodeExporter = dynamic_cast<XcodeProjectExporter*> (exporter))
  171. {
  172. out << "if (APPLE)" << newLine << newLine;
  173. writeCMakeListsXcodeSection (out, *xcodeExporter);
  174. }
  175. else if (auto* codeBlocksExporter = dynamic_cast<CodeBlocksProjectExporter*> (exporter))
  176. {
  177. out << "if (WIN32)" << newLine << newLine;
  178. writeCMakeListsCodeBlocksSection (out, *codeBlocksExporter);
  179. }
  180. out << "endif()" << newLine << newLine;
  181. overwriteFileIfDifferentOrThrow (getTargetFolder().getChildFile ("CMakeLists.txt"), out);
  182. }
  183. private:
  184. //==============================================================================
  185. static File getCLionExecutableOrApp()
  186. {
  187. File clionExeOrApp (getAppSettings()
  188. .getStoredPath (Ids::clionExePath, TargetOS::getThisOS()).get()
  189. .toString()
  190. .replace ("${user.home}", File::getSpecialLocation (File::userHomeDirectory).getFullPathName()));
  191. #if JUCE_MAC
  192. if (clionExeOrApp.getFullPathName().endsWith ("/Contents/MacOS/clion"))
  193. clionExeOrApp = clionExeOrApp.getParentDirectory()
  194. .getParentDirectory()
  195. .getParentDirectory();
  196. #endif
  197. return clionExeOrApp;
  198. }
  199. //==============================================================================
  200. Identifier getExporterEnabledId (const ProjectExporter& exporter) const
  201. {
  202. jassert (isExporterSupported (exporter));
  203. if (exporter.isMakefile()) return Ids::clionMakefileEnabled;
  204. else if (exporter.isXcode()) return Ids::clionXcodeEnabled;
  205. else if (exporter.isCodeBlocks()) return Ids::clionCodeBlocksEnabled;
  206. jassertfalse;
  207. return {};
  208. }
  209. bool isExporterEnabled (const ProjectExporter& exporter) const
  210. {
  211. auto setting = settings[getExporterEnabledId (exporter)];
  212. return setting.isVoid() || setting;
  213. }
  214. Value getExporterEnabledValue (const ProjectExporter& exporter)
  215. {
  216. auto enabledID = getExporterEnabledId (exporter);
  217. getSetting (enabledID) = isExporterEnabled (exporter);
  218. return getSetting (enabledID);
  219. }
  220. //==============================================================================
  221. static bool isWindowsAbsolutePath (const String& path)
  222. {
  223. return path.length() > 1 && path[1] == ':';
  224. }
  225. static bool isUnixAbsolutePath (const String& path)
  226. {
  227. return path.isNotEmpty() && (path[0] == '/' || path[0] == '~' || path.startsWith ("$ENV{HOME}"));
  228. }
  229. //==============================================================================
  230. static String setCMakeVariable (const String& variableName, const String& value)
  231. {
  232. return "set (" + variableName + " \"" + value + "\")";
  233. }
  234. static String addToCMakeVariable (const String& variableName, const String& value)
  235. {
  236. return setCMakeVariable (variableName, "${" + variableName + "} " + value);
  237. }
  238. static String getTargetVarName (ProjectType::Target& target)
  239. {
  240. return String (target.getName()).toUpperCase().replaceCharacter (L' ', L'_');
  241. }
  242. template <class Target, class Exporter>
  243. void getFileInfoList (Target& target, Exporter& exporter, const Project::Item& projectItem, std::vector<std::tuple<String, bool, String>>& fileInfoList) const
  244. {
  245. auto targetType = (getProject().isAudioPluginProject() ? target.type : Target::Type::SharedCodeTarget);
  246. if (projectItem.isGroup())
  247. {
  248. for (int i = 0; i < projectItem.getNumChildren(); ++i)
  249. getFileInfoList (target, exporter, projectItem.getChild(i), fileInfoList);
  250. }
  251. else if (projectItem.shouldBeAddedToTargetProject() && projectItem.shouldBeAddedToTargetExporter (*this)
  252. && getProject().getTargetTypeFromFilePath (projectItem.getFile(), true) == targetType )
  253. {
  254. auto path = RelativePath (projectItem.getFile(), exporter.getTargetFolder(), RelativePath::buildTargetFolder).toUnixStyle();
  255. fileInfoList.push_back (std::make_tuple (path, projectItem.shouldBeCompiled(),
  256. exporter.compilerFlagSchemesMap[projectItem.getCompilerFlagSchemeString()].get().toString()));
  257. }
  258. }
  259. template <class Exporter>
  260. void writeCMakeTargets (OutputStream& out, Exporter& exporter) const
  261. {
  262. for (auto* target : exporter.targets)
  263. {
  264. if (target->type == ProjectType::Target::Type::AggregateTarget
  265. || target->type == ProjectType::Target::Type::AudioUnitv3PlugIn)
  266. continue;
  267. String functionName;
  268. StringArray properties;
  269. switch (target->getTargetFileType())
  270. {
  271. case ProjectType::Target::TargetFileType::executable:
  272. functionName = "add_executable";
  273. if (exporter.isCodeBlocks() && exporter.isWindows()
  274. && target->type != ProjectType::Target::Type::ConsoleApp)
  275. properties.add ("WIN32");
  276. break;
  277. case ProjectType::Target::TargetFileType::staticLibrary:
  278. case ProjectType::Target::TargetFileType::sharedLibraryOrDLL:
  279. case ProjectType::Target::TargetFileType::pluginBundle:
  280. functionName = "add_library";
  281. if (target->getTargetFileType() == ProjectType::Target::TargetFileType::staticLibrary)
  282. properties.add ("STATIC");
  283. else if (target->getTargetFileType() == ProjectType::Target::TargetFileType::sharedLibraryOrDLL)
  284. properties.add ("SHARED");
  285. else
  286. properties.add ("MODULE");
  287. break;
  288. case ProjectType::Target::TargetFileType::macOSAppex:
  289. case ProjectType::Target::TargetFileType::unknown:
  290. default:
  291. continue;
  292. }
  293. out << functionName << " (" << getTargetVarName (*target);
  294. if (! properties.isEmpty())
  295. out << " " << properties.joinIntoString (" ");
  296. out << newLine;
  297. std::vector<std::tuple<String, bool, String>> fileInfoList;
  298. for (auto& group : exporter.getAllGroups())
  299. getFileInfoList (*target, exporter, group, fileInfoList);
  300. for (auto& fileInfo : fileInfoList)
  301. out << " " << std::get<0> (fileInfo).quoted() << newLine;
  302. auto isCMakeBundle = exporter.isXcode() && target->getTargetFileType() == ProjectType::Target::TargetFileType::pluginBundle;
  303. auto pkgInfoPath = String ("PkgInfo").quoted();
  304. if (isCMakeBundle)
  305. out << " " << pkgInfoPath << newLine;
  306. auto xcodeIcnsFilePath = [&] () -> String
  307. {
  308. if (exporter.isXcode() && target->getTargetFileType() == ProjectType::Target::TargetFileType::executable)
  309. {
  310. StringArray pathComponents = { "..", "MacOSX", "Icon.icns" };
  311. auto xcodeIcnsFile = getTargetFolder();
  312. for (auto& comp : pathComponents)
  313. xcodeIcnsFile = xcodeIcnsFile.getChildFile (comp);
  314. if (xcodeIcnsFile.existsAsFile())
  315. return pathComponents.joinIntoString ("/").quoted();
  316. }
  317. return {};
  318. }();
  319. if (xcodeIcnsFilePath.isNotEmpty())
  320. out << " " << xcodeIcnsFilePath << newLine;
  321. if (exporter.isCodeBlocks() && target->getTargetFileType() == ProjectType::Target::TargetFileType::executable)
  322. {
  323. StringArray pathComponents = { "..", "CodeBlocksWindows", "resources.rc" };
  324. auto windowsRcFile = getTargetFolder();
  325. for (auto& comp : pathComponents)
  326. windowsRcFile = windowsRcFile.getChildFile (comp);
  327. if (windowsRcFile.existsAsFile())
  328. out << " " << pathComponents.joinIntoString ("/").quoted() << newLine;
  329. }
  330. out << ")" << newLine << newLine;
  331. if (isCMakeBundle)
  332. out << "set_source_files_properties (" << pkgInfoPath << " PROPERTIES MACOSX_PACKAGE_LOCATION .)" << newLine;
  333. if (xcodeIcnsFilePath.isNotEmpty())
  334. out << "set_source_files_properties (" << xcodeIcnsFilePath << " PROPERTIES MACOSX_PACKAGE_LOCATION \"Resources\")" << newLine;
  335. for (auto& fileInfo : fileInfoList)
  336. {
  337. if (std::get<1> (fileInfo))
  338. {
  339. auto extraCompilerFlags = std::get<2> (fileInfo);
  340. if (extraCompilerFlags.isNotEmpty())
  341. out << "set_source_files_properties(" << std::get<0> (fileInfo).quoted() << " PROPERTIES COMPILE_FLAGS " << extraCompilerFlags << " )" << newLine;
  342. }
  343. else
  344. {
  345. out << "set_source_files_properties (" << std::get<0> (fileInfo).quoted() << " PROPERTIES HEADER_FILE_ONLY TRUE)" << newLine;
  346. }
  347. }
  348. out << newLine;
  349. }
  350. }
  351. //==============================================================================
  352. void writeCMakeListsMakefileSection (OutputStream& out, MakefileProjectExporter& exporter) const
  353. {
  354. out << "project (" << getProject().getProjectNameString().quoted() << " C CXX)" << newLine
  355. << newLine;
  356. out << "find_package (PkgConfig REQUIRED)" << newLine;
  357. StringArray cmakePkgconfigPackages;
  358. for (auto& package : exporter.getPackages())
  359. {
  360. cmakePkgconfigPackages.add (package.toUpperCase());
  361. out << "pkg_search_module (" << cmakePkgconfigPackages.strings.getLast() << " REQUIRED " << package << ")" << newLine;
  362. }
  363. out << newLine;
  364. writeCMakeTargets (out, exporter);
  365. for (auto* target : exporter.targets)
  366. {
  367. if (target->type == ProjectType::Target::Type::AggregateTarget)
  368. continue;
  369. if (target->getTargetFileType() == ProjectType::Target::TargetFileType::pluginBundle)
  370. out << "set_target_properties (" << getTargetVarName (*target) << " PROPERTIES PREFIX \"\")" << newLine;
  371. out << "set_target_properties (" << getTargetVarName (*target) << " PROPERTIES SUFFIX \"" << target->getTargetFileSuffix() << "\")" << newLine
  372. << newLine;
  373. }
  374. for (ProjectExporter::ConstConfigIterator c (exporter); c.next();)
  375. {
  376. auto& config = dynamic_cast<const MakefileProjectExporter::MakeBuildConfiguration&> (*c);
  377. out << "#------------------------------------------------------------------------------" << newLine
  378. << "# Config: " << config.getName() << newLine
  379. << "#------------------------------------------------------------------------------" << newLine
  380. << newLine;
  381. auto buildTypeCondition = String ("CMAKE_BUILD_TYPE STREQUAL " + config.getName());
  382. out << "if (" << buildTypeCondition << ")" << newLine
  383. << newLine;
  384. out << "execute_process (COMMAND uname -m OUTPUT_VARIABLE JUCE_ARCH_LABEL OUTPUT_STRIP_TRAILING_WHITESPACE)" << newLine
  385. << newLine;
  386. out << "include_directories (" << newLine;
  387. for (auto& path : exporter.getHeaderSearchPaths (config))
  388. out << " " << path.quoted() << newLine;
  389. for (auto& package : cmakePkgconfigPackages)
  390. out << " ${" << package << "_INCLUDE_DIRS}" << newLine;
  391. out << ")" << newLine << newLine;
  392. StringArray cmakeFoundLibraries;
  393. for (auto& library : exporter.getLibraryNames (config))
  394. {
  395. String cmakeLibraryID (library.toUpperCase());
  396. cmakeFoundLibraries.add (String ("${") + cmakeLibraryID + "}");
  397. out << "find_library (" << cmakeLibraryID << " " << library << newLine;
  398. for (auto& path : exporter.getLibrarySearchPaths (config))
  399. out << " " << path.quoted() << newLine;
  400. out << ")" << newLine
  401. << newLine;
  402. }
  403. for (auto* target : exporter.targets)
  404. {
  405. if (target->type == ProjectType::Target::Type::AggregateTarget)
  406. continue;
  407. auto targetVarName = getTargetVarName (*target);
  408. out << "set_target_properties (" << targetVarName << " PROPERTIES" << newLine
  409. << " OUTPUT_NAME " << config.getTargetBinaryNameString().quoted() << newLine;
  410. auto cxxStandard = project.getCppStandardString();
  411. if (cxxStandard == "latest")
  412. cxxStandard = "17";
  413. out << " CXX_STANDARD " << cxxStandard << newLine;
  414. if (! shouldUseGNUExtensions())
  415. out << " CXX_EXTENSIONS OFF" << newLine;
  416. out << ")" << newLine << newLine;
  417. auto defines = exporter.getDefines (config);
  418. defines.addArray (target->getDefines (config));
  419. out << "target_compile_definitions (" << targetVarName << " PRIVATE" << newLine;
  420. for (auto& key : defines.getAllKeys())
  421. out << " " << key << "=" << defines[key] << newLine;
  422. out << ")" << newLine << newLine;
  423. auto targetFlags = target->getCompilerFlags();
  424. if (! targetFlags.isEmpty())
  425. {
  426. out << "target_compile_options (" << targetVarName << " PRIVATE" << newLine;
  427. for (auto& flag : targetFlags)
  428. out << " " << flag << newLine;
  429. out << ")" << newLine << newLine;
  430. }
  431. out << "target_link_libraries (" << targetVarName << " PRIVATE" << newLine;
  432. if (target->getTargetFileType() == ProjectType::Target::TargetFileType::pluginBundle
  433. || target->type == ProjectType::Target::Type::StandalonePlugIn)
  434. out << " SHARED_CODE" << newLine;
  435. out << " " << exporter.getArchFlags (config) << newLine;
  436. for (auto& flag : target->getLinkerFlags())
  437. out << " " << flag << newLine;
  438. for (auto& flag : exporter.getLinkerFlags (config))
  439. out << " " << flag << newLine;
  440. for (auto& lib : cmakeFoundLibraries)
  441. out << " " << lib << newLine;
  442. for (auto& package : cmakePkgconfigPackages)
  443. out << " ${" << package << "_LIBRARIES}" << newLine;
  444. out << ")" << newLine << newLine;
  445. if (target->getTargetFileType() == ProjectType::Target::TargetFileType::pluginBundle
  446. || target->type == ProjectType::Target::Type::StandalonePlugIn)
  447. out << "add_dependencies (" << targetVarName << " " << "SHARED_CODE)" << newLine << newLine;
  448. }
  449. StringArray cFlags;
  450. cFlags.add (exporter.getArchFlags (config));
  451. cFlags.addArray (exporter.getCPreprocessorFlags (config));
  452. cFlags.addArray (exporter.getCFlags (config));
  453. out << addToCMakeVariable ("CMAKE_C_FLAGS", cFlags.joinIntoString (" ")) << newLine;
  454. String cxxFlags;
  455. for (auto& flag : exporter.getCXXFlags())
  456. if (! flag.startsWith ("-std="))
  457. cxxFlags += " " + flag;
  458. out << addToCMakeVariable ("CMAKE_CXX_FLAGS", "${CMAKE_C_FLAGS} " + cxxFlags) << newLine
  459. << newLine;
  460. out << "endif (" << buildTypeCondition << ")" << newLine
  461. << newLine;
  462. }
  463. }
  464. //==============================================================================
  465. void writeCMakeListsCodeBlocksSection (OutputStream& out, CodeBlocksProjectExporter& exporter) const
  466. {
  467. out << "project (" << getProject().getProjectNameString().quoted() << " C CXX)" << newLine
  468. << newLine;
  469. writeCMakeTargets (out, exporter);
  470. for (auto* target : exporter.targets)
  471. {
  472. if (target->type == ProjectType::Target::Type::AggregateTarget)
  473. continue;
  474. out << "set_target_properties (" << getTargetVarName (*target) << " PROPERTIES PREFIX \"\")" << newLine
  475. << "set_target_properties (" << getTargetVarName (*target) << " PROPERTIES SUFFIX " << target->getTargetSuffix().quoted() << ")" << newLine
  476. << newLine;
  477. }
  478. for (ProjectExporter::ConstConfigIterator c (exporter); c.next();)
  479. {
  480. auto& config = dynamic_cast<const CodeBlocksProjectExporter::CodeBlocksBuildConfiguration&> (*c);
  481. out << "#------------------------------------------------------------------------------" << newLine
  482. << "# Config: " << config.getName() << newLine
  483. << "#------------------------------------------------------------------------------" << newLine
  484. << newLine;
  485. auto buildTypeCondition = String ("CMAKE_BUILD_TYPE STREQUAL " + config.getName());
  486. out << "if (" << buildTypeCondition << ")" << newLine
  487. << newLine;
  488. out << "include_directories (" << newLine;
  489. for (auto& path : exporter.getIncludePaths (config))
  490. out << " " << path.replace ("\\", "/").quoted() << newLine;
  491. out << ")" << newLine << newLine;
  492. for (auto* target : exporter.targets)
  493. {
  494. if (target->type == ProjectType::Target::Type::AggregateTarget)
  495. continue;
  496. auto targetVarName = getTargetVarName (*target);
  497. out << "set_target_properties (" << targetVarName << " PROPERTIES" << newLine
  498. << " OUTPUT_NAME " << config.getTargetBinaryNameString().quoted() << newLine;
  499. auto cxxStandard = project.getCppStandardString();
  500. if (cxxStandard == "latest")
  501. cxxStandard = "17";
  502. out << " CXX_STANDARD " << cxxStandard << newLine;
  503. if (! shouldUseGNUExtensions())
  504. out << " CXX_EXTENSIONS OFF" << newLine;
  505. out << ")" << newLine << newLine;
  506. out << "target_compile_definitions (" << targetVarName << " PRIVATE" << newLine;
  507. for (auto& def : exporter.getDefines (config, *target))
  508. out << " " << def << newLine;
  509. out << ")" << newLine << newLine;
  510. out << "target_compile_options (" << targetVarName << " PRIVATE" << newLine;
  511. for (auto& option : exporter.getCompilerFlags (config, *target))
  512. if (! option.startsWith ("-std="))
  513. out << " " << option.quoted() << newLine;
  514. out << ")" << newLine << newLine;
  515. out << "target_link_libraries (" << targetVarName << " PRIVATE" << newLine;
  516. if (target->getTargetFileType() == ProjectType::Target::TargetFileType::pluginBundle
  517. || target->type == ProjectType::Target::Type::StandalonePlugIn)
  518. out << " SHARED_CODE" << newLine
  519. << " -L." << newLine;
  520. for (auto& path : exporter.getLinkerSearchPaths (config, *target))
  521. {
  522. out << " \"-L\\\"";
  523. if (! isWindowsAbsolutePath (path))
  524. out << "${CMAKE_CURRENT_SOURCE_DIR}/";
  525. out << path.replace ("\\", "/").unquoted() << "\\\"\"" << newLine;
  526. }
  527. for (auto& flag : exporter.getLinkerFlags (config, *target))
  528. out << " " << flag << newLine;
  529. for (auto& flag : exporter.getProjectLinkerLibs())
  530. out << " -l" << flag << newLine;
  531. for (auto& lib : exporter.mingwLibs)
  532. out << " -l" << lib << newLine;
  533. out << ")" << newLine << newLine;
  534. }
  535. out << addToCMakeVariable ("CMAKE_CXX_FLAGS", exporter.getProjectCompilerOptions().joinIntoString (" ")) << newLine
  536. << addToCMakeVariable ("CMAKE_C_FLAGS", "${CMAKE_CXX_FLAGS}") << newLine
  537. << newLine;
  538. out << "endif (" << buildTypeCondition << ")" << newLine
  539. << newLine;
  540. }
  541. }
  542. //==============================================================================
  543. void writeCMakeListsXcodeSection (OutputStream& out, XcodeProjectExporter& exporter) const
  544. {
  545. // We need to find out the SDK root before defining the project. Unfortunately this is
  546. // set per-target in the Xcode project, but we want it per-configuration.
  547. for (ProjectExporter::ConstConfigIterator c (exporter); c.next();)
  548. {
  549. auto& config = dynamic_cast<const XcodeProjectExporter::XcodeBuildConfiguration&> (*c);
  550. for (auto* target : exporter.targets)
  551. {
  552. if (target->getTargetFileType() == ProjectType::Target::TargetFileType::macOSAppex
  553. || target->type == ProjectType::Target::Type::AggregateTarget
  554. || target->type == ProjectType::Target::Type::AudioUnitv3PlugIn)
  555. continue;
  556. auto targetAttributes = target->getTargetSettings (config);
  557. auto targetAttributeKeys = targetAttributes.getAllKeys();
  558. if (targetAttributes.getAllKeys().contains ("SDKROOT"))
  559. {
  560. out << "if (CMAKE_BUILD_TYPE STREQUAL " + config.getName() << ")" << newLine
  561. << " set (CMAKE_OSX_SYSROOT " << targetAttributes["SDKROOT"] << ")" << newLine
  562. << "endif()" << newLine << newLine;
  563. break;
  564. }
  565. }
  566. }
  567. out << "project (" << getProject().getProjectNameString().quoted() << " C CXX)" << newLine << newLine;
  568. writeCMakeTargets (out, exporter);
  569. for (auto* target : exporter.targets)
  570. {
  571. if (target->getTargetFileType() == ProjectType::Target::TargetFileType::macOSAppex
  572. || target->type == ProjectType::Target::Type::AggregateTarget
  573. || target->type == ProjectType::Target::Type::AudioUnitv3PlugIn)
  574. continue;
  575. if (target->type == ProjectType::Target::Type::AudioUnitPlugIn)
  576. out << "find_program (RC_COMPILER Rez NO_DEFAULT_PATHS PATHS \"/Applications/Xcode.app/Contents/Developer/usr/bin\")" << newLine
  577. << "if (NOT RC_COMPILER)" << newLine
  578. << " message (WARNING \"failed to find Rez; older resource-based AU plug-ins may not work correctly\")" << newLine
  579. << "endif (NOT RC_COMPILER)" << newLine << newLine;
  580. if (target->getTargetFileType() == ProjectType::Target::TargetFileType::staticLibrary
  581. || target->getTargetFileType() == ProjectType::Target::TargetFileType::sharedLibraryOrDLL)
  582. out << "set_target_properties (" << getTargetVarName (*target) << " PROPERTIES SUFFIX \"" << target->xcodeBundleExtension << "\")" << newLine
  583. << newLine;
  584. }
  585. for (ProjectExporter::ConstConfigIterator c (exporter); c.next();)
  586. {
  587. auto& config = dynamic_cast<const XcodeProjectExporter::XcodeBuildConfiguration&> (*c);
  588. out << "#------------------------------------------------------------------------------" << newLine
  589. << "# Config: " << config.getName() << newLine
  590. << "#------------------------------------------------------------------------------" << newLine
  591. << newLine;
  592. auto buildTypeCondition = String ("CMAKE_BUILD_TYPE STREQUAL " + config.getName());
  593. out << "if (" << buildTypeCondition << ")" << newLine
  594. << newLine;
  595. out << "execute_process (COMMAND uname -m OUTPUT_VARIABLE JUCE_ARCH_LABEL OUTPUT_STRIP_TRAILING_WHITESPACE)" << newLine
  596. << newLine;
  597. auto configSettings = exporter.getProjectSettings (config);
  598. auto configSettingsKeys = configSettings.getAllKeys();
  599. auto binaryName = config.getTargetBinaryNameString();
  600. if (configSettingsKeys.contains ("PRODUCT_NAME"))
  601. binaryName = configSettings["PRODUCT_NAME"].unquoted();
  602. for (auto* target : exporter.targets)
  603. {
  604. if (target->getTargetFileType() == ProjectType::Target::TargetFileType::macOSAppex
  605. || target->type == ProjectType::Target::Type::AggregateTarget
  606. || target->type == ProjectType::Target::Type::AudioUnitv3PlugIn)
  607. continue;
  608. auto targetVarName = getTargetVarName (*target);
  609. auto targetAttributes = target->getTargetSettings (config);
  610. auto targetAttributeKeys = targetAttributes.getAllKeys();
  611. StringArray headerSearchPaths;
  612. if (targetAttributeKeys.contains ("HEADER_SEARCH_PATHS"))
  613. {
  614. auto paths = targetAttributes["HEADER_SEARCH_PATHS"].trim().substring (1).dropLastCharacters (1);
  615. paths = paths.replace ("\"$(inherited)\"", {})
  616. .replace ("$(HOME)", "$ENV{HOME}")
  617. .replace ("~", "$ENV{HOME}");
  618. headerSearchPaths.addTokens (paths, ",\"\t\\", {});
  619. headerSearchPaths.removeEmptyStrings();
  620. targetAttributeKeys.removeString ("HEADER_SEARCH_PATHS");
  621. }
  622. out << "target_include_directories (" << targetVarName << " PRIVATE" << newLine;
  623. for (auto& path : headerSearchPaths)
  624. out << " " << path.quoted() << newLine;
  625. out << ")" << newLine << newLine;
  626. StringArray defines;
  627. if (targetAttributeKeys.contains ("GCC_PREPROCESSOR_DEFINITIONS"))
  628. {
  629. defines.addTokens (targetAttributes["GCC_PREPROCESSOR_DEFINITIONS"], "() ,\t", {});
  630. defines.removeEmptyStrings();
  631. targetAttributeKeys.removeString ("GCC_PREPROCESSOR_DEFINITIONS");
  632. }
  633. out << "target_compile_definitions (" << targetVarName << " PRIVATE" << newLine;
  634. for (auto& def : defines)
  635. out << " " << def << newLine;
  636. out << ")" << newLine << newLine;
  637. StringArray cppFlags;
  638. String archLabel ("${JUCE_ARCH_LABEL}");
  639. // Fat binaries are not supported.
  640. if (targetAttributeKeys.contains ("ARCHS"))
  641. {
  642. auto value = targetAttributes["ARCHS"].unquoted();
  643. if (value.contains ("NATIVE_ARCH_ACTUAL"))
  644. {
  645. cppFlags.add ("-march=native");
  646. }
  647. else if (value.contains ("ARCHS_STANDARD_32_BIT"))
  648. {
  649. archLabel = "i386";
  650. cppFlags.add ("-arch x86");
  651. }
  652. else if (value.contains ("ARCHS_STANDARD_32_64_BIT")
  653. || value.contains ("ARCHS_STANDARD_64_BIT"))
  654. {
  655. archLabel = "x86_64";
  656. cppFlags.add ("-arch x86_64");
  657. }
  658. targetAttributeKeys.removeString ("ARCHS");
  659. }
  660. if (targetAttributeKeys.contains ("MACOSX_DEPLOYMENT_TARGET"))
  661. {
  662. cppFlags.add ("-mmacosx-version-min=" + targetAttributes["MACOSX_DEPLOYMENT_TARGET"]);
  663. targetAttributeKeys.removeString ("MACOSX_DEPLOYMENT_TARGET");
  664. }
  665. if (targetAttributeKeys.contains ("OTHER_CPLUSPLUSFLAGS"))
  666. {
  667. cppFlags.add (targetAttributes["OTHER_CPLUSPLUSFLAGS"].unquoted());
  668. targetAttributeKeys.removeString ("OTHER_CPLUSPLUSFLAGS");
  669. }
  670. if (targetAttributeKeys.contains ("GCC_OPTIMIZATION_LEVEL"))
  671. {
  672. cppFlags.add ("-O" + targetAttributes["GCC_OPTIMIZATION_LEVEL"]);
  673. targetAttributeKeys.removeString ("GCC_OPTIMIZATION_LEVEL");
  674. }
  675. if (targetAttributeKeys.contains ("LLVM_LTO"))
  676. {
  677. cppFlags.add ("-flto");
  678. targetAttributeKeys.removeString ("LLVM_LTO");
  679. }
  680. if (targetAttributeKeys.contains ("GCC_FAST_MATH"))
  681. {
  682. cppFlags.add ("-ffast-math");
  683. targetAttributeKeys.removeString ("GCC_FAST_MATH");
  684. }
  685. // We'll take this setting from the project
  686. targetAttributeKeys.removeString ("CLANG_CXX_LANGUAGE_STANDARD");
  687. if (targetAttributeKeys.contains ("CLANG_CXX_LIBRARY"))
  688. {
  689. cppFlags.add ("-stdlib=" + targetAttributes["CLANG_CXX_LIBRARY"].unquoted());
  690. targetAttributeKeys.removeString ("CLANG_CXX_LIBRARY");
  691. }
  692. out << "target_compile_options (" << targetVarName << " PRIVATE" << newLine;
  693. for (auto& flag : cppFlags)
  694. out << " " << flag << newLine;
  695. out << ")" << newLine << newLine;
  696. StringArray libSearchPaths;
  697. if (targetAttributeKeys.contains ("LIBRARY_SEARCH_PATHS"))
  698. {
  699. auto paths = targetAttributes["LIBRARY_SEARCH_PATHS"].trim().substring (1).dropLastCharacters (1);
  700. paths = paths.replace ("\"$(inherited)\"", {});
  701. paths = paths.replace ("$(HOME)", "$ENV{HOME}");
  702. libSearchPaths.addTokens (paths, ",\"\t\\", {});
  703. libSearchPaths.removeEmptyStrings();
  704. for (auto& libPath : libSearchPaths)
  705. {
  706. libPath = libPath.replace ("${CURRENT_ARCH}", archLabel);
  707. if (! isUnixAbsolutePath (libPath))
  708. libPath = "${CMAKE_CURRENT_SOURCE_DIR}/" + libPath;
  709. }
  710. targetAttributeKeys.removeString ("LIBRARY_SEARCH_PATHS");
  711. }
  712. StringArray linkerFlags;
  713. if (targetAttributeKeys.contains ("OTHER_LDFLAGS"))
  714. {
  715. // CMake adds its own SHARED_CODE library linking flags
  716. auto flagsWithReplacedSpaces = targetAttributes["OTHER_LDFLAGS"].unquoted().replace ("\\\\ ", "^^%%^^");
  717. linkerFlags.addTokens (flagsWithReplacedSpaces, true);
  718. linkerFlags.removeString ("-bundle");
  719. linkerFlags.removeString ("-l" + binaryName.replace (" ", "^^%%^^"));
  720. for (auto& flag : linkerFlags)
  721. flag = flag.replace ("^^%%^^", " ");
  722. targetAttributeKeys.removeString ("OTHER_LDFLAGS");
  723. }
  724. if (target->type == ProjectType::Target::Type::AudioUnitPlugIn)
  725. {
  726. String rezFlags;
  727. if (targetAttributeKeys.contains ("OTHER_REZFLAGS"))
  728. {
  729. rezFlags = targetAttributes["OTHER_REZFLAGS"];
  730. targetAttributeKeys.removeString ("OTHER_REZFLAGS");
  731. }
  732. for (auto& item : exporter.getAllGroups())
  733. {
  734. if (item.getName() == ProjectSaver::getJuceCodeGroupName())
  735. {
  736. auto resSourcesVar = targetVarName + "_REZ_SOURCES";
  737. auto resOutputVar = targetVarName + "_REZ_OUTPUT";
  738. auto sdkVersion = config.getOSXSDKVersionString().upToFirstOccurrenceOf (" ", false, false);
  739. auto sysroot = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX" + sdkVersion + ".sdk";
  740. RelativePath rFile ("JuceLibraryCode/include_juce_audio_plugin_client_AU.r", RelativePath::projectFolder);
  741. rFile = rebaseFromProjectFolderToBuildTarget (rFile);
  742. out << "if (RC_COMPILER)" << newLine
  743. << " set (" << resSourcesVar << newLine
  744. << " " << ("${CMAKE_CURRENT_SOURCE_DIR}/" + rFile.toUnixStyle()).quoted() << newLine
  745. << " )" << newLine
  746. << " set (" << resOutputVar << " " << ("${CMAKE_CURRENT_BINARY_DIR}/" + binaryName + ".rsrc").quoted() << ")" << newLine
  747. << " target_sources (" << targetVarName << " PRIVATE" << newLine
  748. << " ${" << resSourcesVar << "}" << newLine
  749. << " ${" << resOutputVar << "}" << newLine
  750. << " )" << newLine
  751. << " execute_process (COMMAND" << newLine
  752. << " ${RC_COMPILER}" << newLine
  753. << " " << rezFlags.unquoted().removeCharacters ("\\") << newLine
  754. << " -isysroot " << sysroot.quoted() << newLine;
  755. for (auto& path : headerSearchPaths)
  756. {
  757. out << " -I \"";
  758. if (! isUnixAbsolutePath (path))
  759. out << "${PROJECT_SOURCE_DIR}/";
  760. out << path << "\"" << newLine;
  761. }
  762. out << " ${" << resSourcesVar << "}" << newLine
  763. << " -o ${" << resOutputVar << "}" << newLine
  764. << " )" << newLine
  765. << " set_source_files_properties (${" << resOutputVar << "} PROPERTIES" << newLine
  766. << " GENERATED TRUE" << newLine
  767. << " MACOSX_PACKAGE_LOCATION Resources" << newLine
  768. << " )" << newLine
  769. << "endif (RC_COMPILER)" << newLine << newLine;
  770. break;
  771. }
  772. }
  773. }
  774. if (targetAttributeKeys.contains ("INFOPLIST_FILE"))
  775. {
  776. auto plistFile = exporter.getTargetFolder().getChildFile (targetAttributes["INFOPLIST_FILE"]);
  777. if (auto plist = parseXML (plistFile))
  778. {
  779. if (auto* dict = plist->getChildByName ("dict"))
  780. {
  781. if (auto* entry = dict->getChildByName ("key"))
  782. {
  783. while (entry != nullptr)
  784. {
  785. if (entry->getAllSubText() == "CFBundleExecutable")
  786. {
  787. if (auto* bundleName = entry->getNextElementWithTagName ("string"))
  788. {
  789. bundleName->deleteAllTextElements();
  790. bundleName->addTextElement (binaryName);
  791. }
  792. }
  793. entry = entry->getNextElementWithTagName ("key");
  794. }
  795. }
  796. }
  797. auto updatedPlist = getTargetFolder().getChildFile (config.getName() + "-" + plistFile.getFileName());
  798. XmlElement::TextFormat format;
  799. format.dtd = "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">";
  800. plist->writeTo (updatedPlist, format);
  801. targetAttributes.set ("INFOPLIST_FILE", ("${CMAKE_CURRENT_SOURCE_DIR}/" + updatedPlist.getFileName()).quoted());
  802. }
  803. else
  804. {
  805. targetAttributeKeys.removeString ("INFOPLIST_FILE");
  806. }
  807. }
  808. targetAttributeKeys.sort (false);
  809. out << "set_target_properties (" << targetVarName << " PROPERTIES" << newLine
  810. << " OUTPUT_NAME " << binaryName.quoted() << newLine;
  811. auto cxxStandard = project.getCppStandardString();
  812. if (cxxStandard == "latest")
  813. cxxStandard = "17";
  814. out << " CXX_STANDARD " << cxxStandard << newLine;
  815. if (! shouldUseGNUExtensions())
  816. out << " CXX_EXTENSIONS OFF" << newLine;
  817. for (auto& key : targetAttributeKeys)
  818. out << " XCODE_ATTRIBUTE_" << key << " " << targetAttributes[key] << newLine;
  819. if (target->getTargetFileType() == ProjectType::Target::TargetFileType::executable
  820. || target->getTargetFileType() == ProjectType::Target::TargetFileType::pluginBundle)
  821. {
  822. out << " MACOSX_BUNDLE_INFO_PLIST " << targetAttributes.getValue ("INFOPLIST_FILE", "\"\"") << newLine
  823. << " XCODE_ATTRIBUTE_PRODUCT_NAME " << binaryName.quoted() << newLine;
  824. if (target->getTargetFileType() == ProjectType::Target::TargetFileType::executable)
  825. {
  826. out << " MACOSX_BUNDLE TRUE" << newLine;
  827. }
  828. else
  829. {
  830. out << " BUNDLE TRUE" << newLine
  831. << " BUNDLE_EXTENSION " << targetAttributes.getValue ("WRAPPER_EXTENSION", "\"\"") << newLine
  832. << " XCODE_ATTRIBUTE_MACH_O_TYPE \"mh_bundle\"" << newLine;
  833. }
  834. }
  835. out << ")" << newLine << newLine;
  836. out << "target_link_libraries (" << targetVarName << " PRIVATE" << newLine;
  837. if (target->getTargetFileType() == ProjectType::Target::TargetFileType::pluginBundle
  838. || target->type == ProjectType::Target::Type::StandalonePlugIn)
  839. out << " SHARED_CODE" << newLine;
  840. for (auto& path : libSearchPaths)
  841. out << " \"-L\\\"" << path << "\\\"\"" << newLine;
  842. for (auto& flag : linkerFlags)
  843. out << " " << flag.quoted() << newLine;
  844. for (auto& framework : target->frameworkNames)
  845. out << " \"-framework " << framework << "\"" << newLine;
  846. out << ")" << newLine << newLine;
  847. if (target->getTargetFileType() == ProjectType::Target::TargetFileType::pluginBundle
  848. || target->type == ProjectType::Target::Type::StandalonePlugIn)
  849. {
  850. if (target->getTargetFileType() == ProjectType::Target::TargetFileType::pluginBundle
  851. && targetAttributeKeys.contains("INSTALL_PATH"))
  852. {
  853. auto installPath = targetAttributes["INSTALL_PATH"].unquoted().replace ("$(HOME)", "$ENV{HOME}");
  854. auto productFilename = binaryName + (targetAttributeKeys.contains ("WRAPPER_EXTENSION") ? "." + targetAttributes["WRAPPER_EXTENSION"] : String());
  855. auto productPath = (installPath + productFilename).quoted();
  856. out << "add_custom_command (TARGET " << targetVarName << " POST_BUILD" << newLine
  857. << " COMMAND ${CMAKE_COMMAND} -E remove_directory " << productPath << newLine
  858. << " COMMAND ${CMAKE_COMMAND} -E copy_directory \"${CMAKE_BINARY_DIR}/" << productFilename << "\" " << productPath << newLine
  859. << " COMMENT \"Copying \\\"" << productFilename << "\\\" to \\\"" << installPath.unquoted() << "\\\"\"" << newLine
  860. << ")" << newLine << newLine;
  861. }
  862. }
  863. }
  864. std::map<String, String> basicWarnings
  865. {
  866. { "CLANG_WARN_BOOL_CONVERSION", "bool-conversion" },
  867. { "CLANG_WARN_COMMA", "comma" },
  868. { "CLANG_WARN_CONSTANT_CONVERSION", "constant-conversion" },
  869. { "CLANG_WARN_EMPTY_BODY", "empty-body" },
  870. { "CLANG_WARN_ENUM_CONVERSION", "enum-conversion" },
  871. { "CLANG_WARN_INFINITE_RECURSION", "infinite-recursion" },
  872. { "CLANG_WARN_INT_CONVERSION", "int-conversion" },
  873. { "CLANG_WARN_RANGE_LOOP_ANALYSIS", "range-loop-analysis" },
  874. { "CLANG_WARN_STRICT_PROTOTYPES", "strict-prototypes" },
  875. { "GCC_WARN_CHECK_SWITCH_STATEMENTS", "switch" },
  876. { "GCC_WARN_UNUSED_VARIABLE", "unused-variable" },
  877. { "GCC_WARN_MISSING_PARENTHESES", "parentheses" },
  878. { "GCC_WARN_NON_VIRTUAL_DESTRUCTOR", "non-virtual-dtor" },
  879. { "GCC_WARN_64_TO_32_BIT_CONVERSION", "shorten-64-to-32" },
  880. { "GCC_WARN_UNDECLARED_SELECTOR", "undeclared-selector" },
  881. { "GCC_WARN_UNUSED_FUNCTION", "unused-function" }
  882. };
  883. StringArray compilerFlags;
  884. for (auto& key : configSettingsKeys)
  885. {
  886. auto basicWarning = basicWarnings.find (key);
  887. if (basicWarning != basicWarnings.end())
  888. {
  889. compilerFlags.add (configSettings[key] == "YES" ? "-W" + basicWarning->second : "-Wno-" + basicWarning->second);
  890. }
  891. else if (key == "CLANG_WARN_SUSPICIOUS_MOVE" && configSettings[key] == "YES") compilerFlags.add ("-Wmove");
  892. else if (key == "CLANG_WARN_UNREACHABLE_CODE" && configSettings[key] == "YES") compilerFlags.add ("-Wunreachable-code");
  893. else if (key == "CLANG_WARN__DUPLICATE_METHOD_MATCH" && configSettings[key] == "YES") compilerFlags.add ("-Wduplicate-method-match");
  894. else if (key == "GCC_INLINES_ARE_PRIVATE_EXTERN" && configSettings[key] == "YES") compilerFlags.add ("-fvisibility-inlines-hidden");
  895. else if (key == "GCC_NO_COMMON_BLOCKS" && configSettings[key] == "YES") compilerFlags.add ("-fno-common");
  896. else if (key == "GCC_WARN_ABOUT_RETURN_TYPE" && configSettings[key] != "YES") compilerFlags.add (configSettings[key] == "YES_ERROR" ? "-Werror=return-type" : "-Wno-return-type");
  897. else if (key == "GCC_WARN_TYPECHECK_CALLS_TO_PRINTF" && configSettings[key] != "YES") compilerFlags.add ("-Wno-format");
  898. else if (key == "GCC_WARN_UNINITIALIZED_AUTOS")
  899. {
  900. if (configSettings[key] == "YES") compilerFlags.add ("-Wuninitialized");
  901. else if (configSettings[key] == "YES_AGGRESSIVE") compilerFlags.add ("--Wconditional-uninitialized");
  902. else compilerFlags.add (")-Wno-uninitialized");
  903. }
  904. else if (key == "WARNING_CFLAGS") compilerFlags.add (configSettings[key].unquoted());
  905. }
  906. out << addToCMakeVariable ("CMAKE_CXX_FLAGS", compilerFlags.joinIntoString (" ")) << newLine
  907. << addToCMakeVariable ("CMAKE_C_FLAGS", "${CMAKE_CXX_FLAGS}") << newLine
  908. << newLine;
  909. out << "endif (" << buildTypeCondition << ")" << newLine
  910. << newLine;
  911. }
  912. }
  913. //==============================================================================
  914. JUCE_DECLARE_NON_COPYABLE (CLionProjectExporter)
  915. };