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.

1222 lines
57KB

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