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.

342 lines
13KB

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