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.

320 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. #ifndef __JUCER_PROJECTEXPORT_MAKE_JUCEHEADER__
  19. #define __JUCER_PROJECTEXPORT_MAKE_JUCEHEADER__
  20. #include "jucer_ProjectExporter.h"
  21. //==============================================================================
  22. class MakefileProjectExporter : public ProjectExporter
  23. {
  24. public:
  25. //==============================================================================
  26. static const char* getNameLinux() { return "Linux Makefile"; }
  27. static const char* getValueTreeTypeName() { return "LINUX_MAKE"; }
  28. static MakefileProjectExporter* createForSettings (Project& project, const ValueTree& settings)
  29. {
  30. if (settings.hasType (getValueTreeTypeName()))
  31. return new MakefileProjectExporter (project, settings);
  32. return nullptr;
  33. }
  34. //==============================================================================
  35. MakefileProjectExporter (Project& p, const ValueTree& t) : ProjectExporter (p, t)
  36. {
  37. name = getNameLinux();
  38. if (getTargetLocationString().isEmpty())
  39. getTargetLocationValue() = getDefaultBuildsRootFolder() + "Linux";
  40. }
  41. //==============================================================================
  42. bool launchProject() { return false; }
  43. bool usesMMFiles() const { return false; }
  44. bool isLinux() const { return true; }
  45. bool canCopeWithDuplicateFiles() { return false; }
  46. void createExporterProperties (PropertyListBuilder&)
  47. {
  48. }
  49. //==============================================================================
  50. void create (const OwnedArray<LibraryModule>&) const
  51. {
  52. Array<RelativePath> files;
  53. for (int i = 0; i < getAllGroups().size(); ++i)
  54. findAllFilesToCompile (getAllGroups().getReference(i), files);
  55. MemoryOutputStream mo;
  56. writeMakefile (mo, files);
  57. overwriteFileIfDifferentOrThrow (getTargetFolder().getChildFile ("Makefile"), mo);
  58. }
  59. protected:
  60. //==============================================================================
  61. class MakeBuildConfiguration : public BuildConfiguration
  62. {
  63. public:
  64. MakeBuildConfiguration (Project& project, const ValueTree& settings)
  65. : BuildConfiguration (project, settings)
  66. {
  67. setValueIfVoid (getLibrarySearchPathValue(), "/usr/X11R6/lib/");
  68. }
  69. void createConfigProperties (PropertyListBuilder&)
  70. {
  71. }
  72. };
  73. BuildConfiguration::Ptr createBuildConfig (const ValueTree& settings) const
  74. {
  75. return new MakeBuildConfiguration (project, settings);
  76. }
  77. private:
  78. //==============================================================================
  79. void findAllFilesToCompile (const Project::Item& projectItem, Array<RelativePath>& results) const
  80. {
  81. if (projectItem.isGroup())
  82. {
  83. for (int i = 0; i < projectItem.getNumChildren(); ++i)
  84. findAllFilesToCompile (projectItem.getChild(i), results);
  85. }
  86. else
  87. {
  88. if (projectItem.shouldBeCompiled())
  89. results.add (RelativePath (projectItem.getFile(), getTargetFolder(), RelativePath::buildTargetFolder));
  90. }
  91. }
  92. void writeDefineFlags (OutputStream& out, const BuildConfiguration& config) const
  93. {
  94. StringPairArray defines;
  95. defines.set ("LINUX", "1");
  96. if (config.isDebug())
  97. {
  98. defines.set ("DEBUG", "1");
  99. defines.set ("_DEBUG", "1");
  100. }
  101. else
  102. {
  103. defines.set ("NDEBUG", "1");
  104. }
  105. out << createGCCPreprocessorFlags (mergePreprocessorDefs (defines, getAllPreprocessorDefs (config)));
  106. }
  107. void writeHeaderPathFlags (OutputStream& out, const BuildConfiguration& config) const
  108. {
  109. StringArray searchPaths (extraSearchPaths);
  110. searchPaths.addArray (config.getHeaderSearchPaths());
  111. searchPaths.insert (0, "/usr/include/freetype2");
  112. searchPaths.insert (0, "/usr/include");
  113. searchPaths.removeDuplicates (false);
  114. for (int i = 0; i < searchPaths.size(); ++i)
  115. out << " -I " << addQuotesIfContainsSpaces (FileHelpers::unixStylePath (replacePreprocessorTokens (config, searchPaths[i])));
  116. }
  117. void writeCppFlags (OutputStream& out, const BuildConfiguration& config) const
  118. {
  119. out << " CPPFLAGS := $(DEPFLAGS)";
  120. writeDefineFlags (out, config);
  121. writeHeaderPathFlags (out, config);
  122. out << newLine;
  123. }
  124. void writeLinkerFlags (OutputStream& out, const BuildConfiguration& config) const
  125. {
  126. out << " LDFLAGS += -L$(BINDIR) -L$(LIBDIR)";
  127. if (makefileIsDLL)
  128. out << " -shared";
  129. out << config.getGCCLibraryPathFlags();
  130. for (int i = 0; i < linuxLibs.size(); ++i)
  131. out << " -l" << linuxLibs[i];
  132. out << " " << replacePreprocessorTokens (config, getExtraLinkerFlagsString()).trim()
  133. << newLine;
  134. }
  135. void writeConfig (OutputStream& out, const BuildConfiguration& config) const
  136. {
  137. const String buildDirName ("build");
  138. const String intermediatesDirName (buildDirName + "/intermediate/" + config.getName());
  139. String outputDir (buildDirName);
  140. if (config.getTargetBinaryRelativePathString().isNotEmpty())
  141. {
  142. RelativePath binaryPath (config.getTargetBinaryRelativePathString(), RelativePath::projectFolder);
  143. outputDir = binaryPath.rebased (projectFolder, getTargetFolder(), RelativePath::buildTargetFolder).toUnixStyle();
  144. }
  145. out << "ifeq ($(CONFIG)," << escapeSpaces (config.getName()) << ")" << newLine;
  146. out << " BINDIR := " << escapeSpaces (buildDirName) << newLine
  147. << " LIBDIR := " << escapeSpaces (buildDirName) << newLine
  148. << " OBJDIR := " << escapeSpaces (intermediatesDirName) << newLine
  149. << " OUTDIR := " << escapeSpaces (outputDir) << newLine;
  150. writeCppFlags (out, config);
  151. out << " CFLAGS += $(CPPFLAGS) $(TARGET_ARCH)";
  152. if (config.isDebug())
  153. out << " -g -ggdb";
  154. if (makefileIsDLL)
  155. out << " -fPIC";
  156. out << " -O" << config.getGCCOptimisationFlag() << newLine;
  157. out << " CXXFLAGS += $(CFLAGS) " << replacePreprocessorTokens (config, getExtraCompilerFlagsString()).trim() << newLine;
  158. writeLinkerFlags (out, config);
  159. out << " LDDEPS :=" << newLine
  160. << " RESFLAGS := ";
  161. writeDefineFlags (out, config);
  162. writeHeaderPathFlags (out, config);
  163. out << newLine;
  164. String targetName (config.getTargetBinaryNameString());
  165. if (projectType.isLibrary())
  166. targetName = getLibbedFilename (targetName);
  167. else
  168. targetName = targetName.upToLastOccurrenceOf (".", false, false) + makefileTargetSuffix;
  169. out << " TARGET := " << escapeSpaces (targetName) << newLine;
  170. if (projectType.isLibrary())
  171. out << " BLDCMD = ar -rcs $(OUTDIR)/$(TARGET) $(OBJECTS) $(TARGET_ARCH)" << newLine;
  172. else
  173. out << " BLDCMD = $(CXX) -o $(OUTDIR)/$(TARGET) $(OBJECTS) $(LDFLAGS) $(RESOURCES) $(TARGET_ARCH)" << newLine;
  174. out << "endif" << newLine << newLine;
  175. }
  176. void writeObjects (OutputStream& out, const Array<RelativePath>& files) const
  177. {
  178. out << "OBJECTS := \\" << newLine;
  179. for (int i = 0; i < files.size(); ++i)
  180. if (shouldFileBeCompiledByDefault (files.getReference(i)))
  181. out << " $(OBJDIR)/" << escapeSpaces (getObjectFileFor (files.getReference(i))) << " \\" << newLine;
  182. out << newLine;
  183. }
  184. void writeMakefile (OutputStream& out, const Array<RelativePath>& files) const
  185. {
  186. out << "# Automatically generated makefile, created by the Introjucer" << newLine
  187. << "# Don't edit this file! Your changes will be overwritten when you re-save the Introjucer project!" << newLine
  188. << newLine;
  189. out << "ifndef CONFIG" << newLine
  190. << " CONFIG=" << escapeSpaces (getConfiguration(0)->getName()) << newLine
  191. << "endif" << newLine
  192. << newLine;
  193. if (! projectType.isLibrary())
  194. out << "ifeq ($(TARGET_ARCH),)" << newLine
  195. << " TARGET_ARCH := -march=native" << newLine
  196. << "endif" << newLine << newLine;
  197. out << "# (this disables dependency generation if multiple architectures are set)" << newLine
  198. << "DEPFLAGS := $(if $(word 2, $(TARGET_ARCH)), , -MMD)" << newLine
  199. << newLine;
  200. for (ConstConfigIterator config (*this); config.next();)
  201. writeConfig (out, *config);
  202. writeObjects (out, files);
  203. out << ".PHONY: clean" << newLine
  204. << newLine;
  205. out << "$(OUTDIR)/$(TARGET): $(OBJECTS) $(LDDEPS) $(RESOURCES)" << newLine
  206. << "\t@echo Linking " << projectName << newLine
  207. << "\t-@mkdir -p $(BINDIR)" << newLine
  208. << "\t-@mkdir -p $(LIBDIR)" << newLine
  209. << "\t-@mkdir -p $(OUTDIR)" << newLine
  210. << "\t@$(BLDCMD)" << newLine
  211. << newLine;
  212. out << "clean:" << newLine
  213. << "\t@echo Cleaning " << projectName << newLine
  214. << "\t-@rm -f $(OUTDIR)/$(TARGET)" << newLine
  215. << "\t-@rm -rf $(OBJDIR)/*" << newLine
  216. << "\t-@rm -rf $(OBJDIR)" << newLine
  217. << newLine;
  218. out << "strip:" << newLine
  219. << "\t@echo Stripping " << projectName << newLine
  220. << "\t-@strip --strip-unneeded $(OUTDIR)/$(TARGET)" << newLine
  221. << newLine;
  222. for (int i = 0; i < files.size(); ++i)
  223. {
  224. if (shouldFileBeCompiledByDefault (files.getReference(i)))
  225. {
  226. jassert (files.getReference(i).getRoot() == RelativePath::buildTargetFolder);
  227. out << "$(OBJDIR)/" << escapeSpaces (getObjectFileFor (files.getReference(i)))
  228. << ": " << escapeSpaces (files.getReference(i).toUnixStyle()) << newLine
  229. << "\t-@mkdir -p $(OBJDIR)" << newLine
  230. << "\t@echo \"Compiling " << files.getReference(i).getFileName() << "\"" << newLine
  231. << (files.getReference(i).hasFileExtension (".c") ? "\t@$(CC) $(CFLAGS) -o \"$@\" -c \"$<\""
  232. : "\t@$(CXX) $(CXXFLAGS) -o \"$@\" -c \"$<\"")
  233. << newLine << newLine;
  234. }
  235. }
  236. out << "-include $(OBJECTS:%.o=%.d)" << newLine;
  237. }
  238. String getObjectFileFor (const RelativePath& file) const
  239. {
  240. return file.getFileNameWithoutExtension()
  241. + "_" + String::toHexString (file.toUnixStyle().hashCode()) + ".o";
  242. }
  243. JUCE_DECLARE_NON_COPYABLE (MakefileProjectExporter);
  244. };
  245. #endif // __JUCER_PROJECTEXPORT_MAKE_JUCEHEADER__