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.

1210 lines
57KB

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