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.

351 lines
13KB

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