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.

1183 lines
55KB

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