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.

326 lines
12KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. class CodeBlocksProjectExporter : public ProjectExporter
  19. {
  20. public:
  21. //==============================================================================
  22. static const char* getNameCodeBlocks() { return "Code::Blocks project"; }
  23. static const char* getValueTreeTypeName() { return "CODEBLOCKS"; }
  24. static CodeBlocksProjectExporter* createForSettings (Project& project, const ValueTree& settings)
  25. {
  26. if (settings.hasType (getValueTreeTypeName()))
  27. return new CodeBlocksProjectExporter (project, settings);
  28. return nullptr;
  29. }
  30. //==============================================================================
  31. CodeBlocksProjectExporter (Project& p, const ValueTree& t) : ProjectExporter (p, t)
  32. {
  33. name = getNameCodeBlocks();
  34. if (getTargetLocationString().isEmpty())
  35. getTargetLocationValue() = getDefaultBuildsRootFolder() + "CodeBlocks";
  36. }
  37. //==============================================================================
  38. bool launchProject() { return false; }
  39. bool isCodeBlocks() const { return true; }
  40. bool isWindows() const { return true; }
  41. bool usesMMFiles() const { return false; }
  42. bool canCopeWithDuplicateFiles() { return false; }
  43. void createExporterProperties (PropertyListBuilder&)
  44. {
  45. }
  46. //==============================================================================
  47. void create (const OwnedArray<LibraryModule>&) const
  48. {
  49. Array<RelativePath> files;
  50. for (int i = 0; i < getAllGroups().size(); ++i)
  51. findAllFilesToCompile (getAllGroups().getReference(i), files);
  52. const File cbpFile (getTargetFolder().getChildFile (project.getProjectFilenameRoot())
  53. .withFileExtension (".cbp"));
  54. XmlElement xml ("CodeBlocks_project_file");
  55. addVersion (xml);
  56. createProject (*xml.createNewChildElement ("Project"), files);
  57. writeXmlOrThrow (xml, cbpFile, "UTF-8", 10);
  58. }
  59. private:
  60. //==============================================================================
  61. class CodeBlocksBuildConfiguration : public BuildConfiguration
  62. {
  63. public:
  64. CodeBlocksBuildConfiguration (Project& p, const ValueTree& settings)
  65. : BuildConfiguration (p, settings)
  66. {
  67. }
  68. void createConfigProperties (PropertyListBuilder&)
  69. {
  70. }
  71. };
  72. BuildConfiguration::Ptr createBuildConfig (const ValueTree& tree) const
  73. {
  74. return new CodeBlocksBuildConfiguration (project, tree);
  75. }
  76. //==============================================================================
  77. void findAllFilesToCompile (const Project::Item& projectItem, Array<RelativePath>& results) const
  78. {
  79. if (projectItem.isGroup())
  80. {
  81. for (int i = 0; i < projectItem.getNumChildren(); ++i)
  82. findAllFilesToCompile (projectItem.getChild(i), results);
  83. }
  84. else
  85. {
  86. if (projectItem.shouldBeCompiled())
  87. results.add (RelativePath (projectItem.getFile(), getTargetFolder(), RelativePath::buildTargetFolder));
  88. }
  89. }
  90. void addVersion (XmlElement& xml) const
  91. {
  92. XmlElement* fileVersion = xml.createNewChildElement ("FileVersion");
  93. fileVersion->setAttribute ("major", 1);
  94. fileVersion->setAttribute ("minor", 6);
  95. }
  96. void addOptions (XmlElement& xml) const
  97. {
  98. xml.createNewChildElement ("Option")->setAttribute ("title", project.getTitle());
  99. xml.createNewChildElement ("Option")->setAttribute ("pch_mode", 2);
  100. xml.createNewChildElement ("Option")->setAttribute ("compiler", "gcc");
  101. }
  102. static StringArray cleanArray (StringArray s)
  103. {
  104. s.trim();
  105. s.removeDuplicates (false);
  106. s.removeEmptyStrings (true);
  107. return s;
  108. }
  109. StringArray getDefines (const BuildConfiguration& config) const
  110. {
  111. StringPairArray defines;
  112. defines.set ("__MINGW__", "1");
  113. defines.set ("__MINGW_EXTENSION", String::empty);
  114. defines = mergePreprocessorDefs (defines, getAllPreprocessorDefs (config));
  115. StringArray defs;
  116. for (int i = 0; i < defines.size(); ++i)
  117. defs.add (defines.getAllKeys()[i] + "=" + defines.getAllValues()[i]);
  118. return cleanArray (defs);
  119. }
  120. StringArray getCompilerFlags (const BuildConfiguration& config) const
  121. {
  122. StringArray flags;
  123. flags.add ("-O" + config.getGCCOptimisationFlag());
  124. flags.add ("-std=gnu++0x");
  125. flags.add ("-march=pentium4");
  126. flags.addTokens (replacePreprocessorTokens (config, getExtraCompilerFlagsString()).trim(),
  127. " \n", "\"'");
  128. {
  129. const StringArray defines (getDefines (config));
  130. for (int i = 0; i < defines.size(); ++i)
  131. {
  132. String def (defines[i]);
  133. if (! def.containsChar ('='))
  134. def << '=';
  135. flags.add ("-D" + def);
  136. }
  137. }
  138. return cleanArray (flags);
  139. }
  140. StringArray getLinkerFlags (const BuildConfiguration& config) const
  141. {
  142. StringArray flags;
  143. if (! config.isDebug())
  144. flags.add ("-s");
  145. flags.addTokens (replacePreprocessorTokens (config, getExtraLinkerFlagsString()).trim(),
  146. " \n", "\"'");
  147. return cleanArray (flags);
  148. }
  149. StringArray getIncludePaths (const BuildConfiguration& config) const
  150. {
  151. StringArray paths;
  152. paths.add (".");
  153. paths.add (RelativePath (project.getGeneratedCodeFolder(),
  154. getTargetFolder(), RelativePath::buildTargetFolder).toWindowsStyle());
  155. paths.addArray (config.getHeaderSearchPaths());
  156. return cleanArray (paths);
  157. }
  158. static int getTypeIndex (const ProjectType& type)
  159. {
  160. if (type.isGUIApplication()) return 0;
  161. if (type.isCommandLineApp()) return 1;
  162. if (type.isStaticLibrary()) return 2;
  163. if (type.isDynamicLibrary()) return 3;
  164. return 0;
  165. }
  166. void createBuildTarget (XmlElement& xml, const BuildConfiguration& config) const
  167. {
  168. xml.setAttribute ("title", config.getName());
  169. {
  170. XmlElement* output = xml.createNewChildElement ("Option");
  171. String outputPath;
  172. if (config.getTargetBinaryRelativePathString().isNotEmpty())
  173. {
  174. RelativePath binaryPath (config.getTargetBinaryRelativePathString(), RelativePath::projectFolder);
  175. binaryPath = binaryPath.rebased (projectFolder, getTargetFolder(), RelativePath::buildTargetFolder);
  176. outputPath = config.getTargetBinaryRelativePathString();
  177. }
  178. else
  179. {
  180. outputPath ="bin/" + File::createLegalFileName (config.getName().trim());
  181. }
  182. output->setAttribute ("output", outputPath + "/" + config.getTargetBinaryNameString());
  183. output->setAttribute ("prefix_auto", 1);
  184. output->setAttribute ("extension_auto", 1);
  185. }
  186. xml.createNewChildElement ("Option")
  187. ->setAttribute ("object_output", "obj/" + File::createLegalFileName (config.getName().trim()));
  188. xml.createNewChildElement ("Option")->setAttribute ("type", getTypeIndex (project.getProjectType()));
  189. xml.createNewChildElement ("Option")->setAttribute ("compiler", "gcc");
  190. {
  191. XmlElement* const compiler = xml.createNewChildElement ("Compiler");
  192. {
  193. const StringArray compilerFlags (getCompilerFlags (config));
  194. for (int i = 0; i < compilerFlags.size(); ++i)
  195. setAddOption (*compiler, "option", compilerFlags[i]);
  196. }
  197. {
  198. const StringArray includePaths (getIncludePaths (config));
  199. for (int i = 0; i < includePaths.size(); ++i)
  200. setAddOption (*compiler, "directory", includePaths[i]);
  201. }
  202. }
  203. {
  204. XmlElement* const linker = xml.createNewChildElement ("Linker");
  205. const StringArray linkerFlags (getLinkerFlags (config));
  206. for (int i = 0; i < linkerFlags.size(); ++i)
  207. setAddOption (*linker, "option", linkerFlags[i]);
  208. for (int i = 0; i < mingwLibs.size(); ++i)
  209. setAddOption (*linker, "library", mingwLibs[i]);
  210. }
  211. }
  212. void addBuild (XmlElement& xml) const
  213. {
  214. XmlElement* const build = xml.createNewChildElement ("Build");
  215. for (ConstConfigIterator config (*this); config.next();)
  216. createBuildTarget (*build->createNewChildElement ("Target"), *config);
  217. }
  218. void addProjectCompilerOptions (XmlElement& xml) const
  219. {
  220. XmlElement* const compiler = xml.createNewChildElement ("Compiler");
  221. setAddOption (*compiler, "option", "-Wall");
  222. }
  223. void addProjectLinkerOptions (XmlElement& xml) const
  224. {
  225. XmlElement* const linker = xml.createNewChildElement ("Linker");
  226. const char* defaultLibs[] = { "gdi32", "user32", "kernel32", "comctl32" };
  227. StringArray libs (defaultLibs, numElementsInArray (defaultLibs));
  228. libs.addTokens (getExternalLibrariesString(), ";\n", "\"'");
  229. libs = cleanArray (libs);
  230. for (int i = 0; i < libs.size(); ++i)
  231. setAddOption (*linker, "library", replacePreprocessorDefs (getAllPreprocessorDefs(), libs[i]));
  232. }
  233. void addCompileUnits (XmlElement& xml, const Array<RelativePath>& files) const
  234. {
  235. for (int i = 0; i < files.size(); ++i)
  236. {
  237. const RelativePath& file = files.getReference(i);
  238. xml.createNewChildElement ("Unit")->setAttribute ("filename", file.toUnixStyle());
  239. }
  240. }
  241. void createProject (XmlElement& xml, const Array<RelativePath>& files) const
  242. {
  243. addOptions (xml);
  244. addBuild (xml);
  245. addProjectCompilerOptions (xml);
  246. addProjectLinkerOptions (xml);
  247. addCompileUnits (xml, files);
  248. }
  249. void setAddOption (XmlElement& xml, const String& name, const String& value) const
  250. {
  251. xml.createNewChildElement ("Add")->setAttribute (name, value);
  252. }
  253. JUCE_DECLARE_NON_COPYABLE (CodeBlocksProjectExporter)
  254. };