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.

1188 lines
55KB

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