2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-10 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #ifndef __JUCER_PROJECTEXPORT_MAKE_JUCEHEADER__
27 #define __JUCER_PROJECTEXPORT_MAKE_JUCEHEADER__
29 #include "jucer_ProjectExporter.h"
32 //==============================================================================
33 class MakefileProjectExporter
: public ProjectExporter
36 //==============================================================================
37 static const char* getNameLinux() { return "Linux Makefile"; }
38 static const char* getValueTreeTypeName() { return "LINUX_MAKE"; }
40 static MakefileProjectExporter
* createForSettings (Project
& project
, const ValueTree
& settings
)
42 if (settings
.hasType (getValueTreeTypeName()))
43 return new MakefileProjectExporter (project
, settings
);
49 //==============================================================================
50 MakefileProjectExporter (Project
& project_
, const ValueTree
& settings_
)
51 : ProjectExporter (project_
, settings_
)
53 name
= getNameLinux();
55 if (getTargetLocation().toString().isEmpty())
56 getTargetLocation() = getDefaultBuildsRootFolder() + "Linux";
58 if (getVSTFolder().toString().isEmpty())
59 getVSTFolder() = "~/SDKs/vstsdk2.4";
62 //==============================================================================
63 bool isDefaultFormatForCurrentOS()
72 bool isPossibleForCurrentProject() { return true; }
73 bool usesMMFiles() const { return false; }
77 // what to do on linux?
80 void createPropertyEditors (Array
<PropertyComponent
*>& props
)
82 ProjectExporter::createPropertyEditors (props
);
85 //==============================================================================
88 Array
<RelativePath
> files
;
89 findAllFilesToCompile (project
.getMainGroup(), files
);
91 for (int i
= 0; i
< juceWrapperFiles
.size(); ++i
)
92 if (shouldFileBeCompiledByDefault (juceWrapperFiles
.getReference(i
)))
93 files
.add (juceWrapperFiles
.getReference(i
));
95 const Array
<RelativePath
> vstFiles (getVSTFilesRequired());
96 for (int i
= 0; i
< vstFiles
.size(); i
++)
97 files
.add (vstFiles
.getReference(i
));
99 MemoryOutputStream mo
;
100 writeMakefile (mo
, files
);
102 overwriteFileIfDifferentOrThrow (getTargetFolder().getChildFile ("Makefile"), mo
);
106 //==============================================================================
107 void findAllFilesToCompile (const Project::Item
& projectItem
, Array
<RelativePath
>& results
)
109 if (projectItem
.isGroup())
111 for (int i
= 0; i
< projectItem
.getNumChildren(); ++i
)
112 findAllFilesToCompile (projectItem
.getChild(i
), results
);
116 if (projectItem
.shouldBeCompiled())
117 results
.add (RelativePath (projectItem
.getFile(), getTargetFolder(), RelativePath::buildTargetFolder
));
121 void writeDefineFlags (OutputStream
& out
, const Project::BuildConfiguration
& config
)
123 StringPairArray defines
;
124 defines
.set ("LINUX", "1");
126 if (config
.isDebug().getValue())
128 defines
.set ("DEBUG", "1");
129 defines
.set ("_DEBUG", "1");
133 defines
.set ("NDEBUG", "1");
136 out
<< createGCCPreprocessorFlags (mergePreprocessorDefs (defines
, getAllPreprocessorDefs (config
)));
139 void writeHeaderPathFlags (OutputStream
& out
, const Project::BuildConfiguration
& config
)
141 StringArray
headerPaths (config
.getHeaderSearchPaths());
142 headerPaths
.insert (0, "/usr/include/freetype2");
143 headerPaths
.insert (0, "/usr/include");
145 if (project
.shouldAddVSTFolderToPath() && getVSTFolder().toString().isNotEmpty())
146 headerPaths
.insert (0, rebaseFromProjectFolderToBuildTarget (RelativePath (getVSTFolder().toString(), RelativePath::projectFolder
)).toUnixStyle());
149 headerPaths
.insert (0, juceWrapperFolder
.toUnixStyle());
151 for (int i
= 0; i
< headerPaths
.size(); ++i
)
152 out
<< " -I " << FileHelpers::unixStylePath (replacePreprocessorTokens (config
, headerPaths
[i
])).quoted();
155 void writeCppFlags (OutputStream
& out
, const Project::BuildConfiguration
& config
)
157 out
<< " CPPFLAGS := $(DEPFLAGS)";
158 writeDefineFlags (out
, config
);
159 writeHeaderPathFlags (out
, config
);
163 void writeLinkerFlags (OutputStream
& out
, const Project::BuildConfiguration
& config
)
165 out
<< " LDFLAGS += -L$(BINDIR) -L$(LIBDIR)";
167 if (project
.isAudioPlugin())
171 Array
<RelativePath
> libraryPaths
;
172 libraryPaths
.add (RelativePath ("/usr/X11R6/lib/", RelativePath::unknown
));
173 libraryPaths
.add (getJucePathFromTargetFolder().getChildFile ("bin"));
175 for (int i
= 0; i
< libraryPaths
.size(); ++i
)
176 out
<< " -L" << libraryPaths
.getReference(i
).toUnixStyle().quoted();
179 const char* defaultLibs
[] = { "freetype", "pthread", "rt", "X11", "GL", "GLU", "Xinerama", "asound", 0 };
180 StringArray
libs (defaultLibs
);
182 if (project
.getJuceLinkageMode() == Project::useLinkedJuce
)
185 for (int i
= 0; i
< libs
.size(); ++i
)
186 out
<< " -l" << libs
[i
];
188 out
<< " " << replacePreprocessorTokens (config
, getExtraLinkerFlags().toString()).trim()
192 void writeConfig (OutputStream
& out
, const Project::BuildConfiguration
& config
)
194 const String
buildDirName ("build");
195 const String
intermediatesDirName (buildDirName
+ "/intermediate/" + config
.getName().toString());
196 String
outputDir (buildDirName
);
198 if (config
.getTargetBinaryRelativePath().toString().isNotEmpty())
200 RelativePath
binaryPath (config
.getTargetBinaryRelativePath().toString(), RelativePath::projectFolder
);
201 outputDir
= binaryPath
.rebased (project
.getFile().getParentDirectory(), getTargetFolder(), RelativePath::buildTargetFolder
).toUnixStyle();
204 out
<< "ifeq ($(CONFIG)," << escapeSpaces (config
.getName().toString()) << ")" << newLine
;
205 out
<< " BINDIR := " << escapeSpaces (buildDirName
) << newLine
206 << " LIBDIR := " << escapeSpaces (buildDirName
) << newLine
207 << " OBJDIR := " << escapeSpaces (intermediatesDirName
) << newLine
208 << " OUTDIR := " << escapeSpaces (outputDir
) << newLine
;
210 writeCppFlags (out
, config
);
212 out
<< " CFLAGS += $(CPPFLAGS) $(TARGET_ARCH)";
214 if (config
.isDebug().getValue())
217 if (project
.isAudioPlugin())
220 out
<< " -O" << config
.getGCCOptimisationFlag() << newLine
;
222 out
<< " CXXFLAGS += $(CFLAGS) " << replacePreprocessorTokens (config
, getExtraCompilerFlags().toString()).trim() << newLine
;
224 writeLinkerFlags (out
, config
);
226 out
<< " LDDEPS :=" << newLine
228 writeDefineFlags (out
, config
);
229 writeHeaderPathFlags (out
, config
);
232 String
targetName (config
.getTargetBinaryName().getValue().toString());
234 if (project
.isLibrary())
235 targetName
= getLibbedFilename (targetName
);
237 targetName
= targetName
.upToLastOccurrenceOf (".", false, false) + ".so";
239 out
<< " TARGET := " << escapeSpaces (targetName
) << newLine
;
241 if (project
.isLibrary())
242 out
<< " BLDCMD = ar -rcs $(OUTDIR)/$(TARGET) $(OBJECTS) $(TARGET_ARCH)" << newLine
;
244 out
<< " BLDCMD = $(CXX) -o $(OUTDIR)/$(TARGET) $(OBJECTS) $(LDFLAGS) $(RESOURCES) $(TARGET_ARCH)" << newLine
;
246 out
<< "endif" << newLine
<< newLine
;
249 void writeObjects (OutputStream
& out
, const Array
<RelativePath
>& files
)
251 out
<< "OBJECTS := \\" << newLine
;
253 for (int i
= 0; i
< files
.size(); ++i
)
254 if (shouldFileBeCompiledByDefault (files
.getReference(i
)))
255 out
<< " $(OBJDIR)/" << escapeSpaces (getObjectFileFor (files
.getReference(i
))) << " \\" << newLine
;
260 void writeMakefile (OutputStream
& out
, const Array
<RelativePath
>& files
)
262 out
<< "# Automatically generated makefile, created by the Jucer" << newLine
263 << "# Don't edit this file! Your changes will be overwritten when you re-save the Jucer project!" << newLine
266 out
<< "ifndef CONFIG" << newLine
267 << " CONFIG=" << escapeSpaces (project
.getConfiguration(0).getName().toString()) << newLine
268 << "endif" << newLine
271 if (! project
.isLibrary())
272 out
<< "ifeq ($(TARGET_ARCH),)" << newLine
273 << " TARGET_ARCH := -march=native" << newLine
274 << "endif" << newLine
<< newLine
;
276 out
<< "# (this disables dependency generation if multiple architectures are set)" << newLine
277 << "DEPFLAGS := $(if $(word 2, $(TARGET_ARCH)), , -MMD)" << newLine
281 for (i
= 0; i
< project
.getNumConfigurations(); ++i
)
282 writeConfig (out
, project
.getConfiguration(i
));
284 writeObjects (out
, files
);
286 out
<< ".PHONY: clean" << newLine
289 out
<< "$(OUTDIR)/$(TARGET): $(OBJECTS) $(LDDEPS) $(RESOURCES)" << newLine
290 << "\t@echo Linking " << project
.getProjectName() << newLine
291 << "\t-@mkdir -p $(BINDIR)" << newLine
292 << "\t-@mkdir -p $(LIBDIR)" << newLine
293 << "\t-@mkdir -p $(OUTDIR)" << newLine
294 << "\t@$(BLDCMD)" << newLine
297 out
<< "clean:" << newLine
298 << "\t@echo Cleaning " << project
.getProjectName() << newLine
299 << "\t-@rm -f $(OUTDIR)/$(TARGET)" << newLine
300 << "\t-@rm -rf $(OBJDIR)/*" << newLine
301 << "\t-@rm -rf $(OBJDIR)" << newLine
304 for (i
= 0; i
< files
.size(); ++i
)
306 if (shouldFileBeCompiledByDefault (files
.getReference(i
)))
308 jassert (files
.getReference(i
).getRoot() == RelativePath::buildTargetFolder
);
310 out
<< "$(OBJDIR)/" << escapeSpaces (getObjectFileFor (files
.getReference(i
)))
311 << ": " << escapeSpaces (files
.getReference(i
).toUnixStyle()) << newLine
312 << "\t-@mkdir -p $(OBJDIR)" << newLine
313 << "\t@echo \"Compiling " << files
.getReference(i
).getFileName() << "\"" << newLine
314 << (files
.getReference(i
).hasFileExtension (".c") ? "\t@$(CC) $(CFLAGS) -o \"$@\" -c \"$<\""
315 : "\t@$(CXX) $(CXXFLAGS) -o \"$@\" -c \"$<\"")
316 << newLine
<< newLine
;
320 out
<< "-include $(OBJECTS:%.o=%.d)" << newLine
;
323 const String
getObjectFileFor (const RelativePath
& file
) const
325 return file
.getFileNameWithoutExtension()
326 + "_" + String::toHexString (file
.toUnixStyle().hashCode()) + ".o";
329 JUCE_DECLARE_NON_COPYABLE (MakefileProjectExporter
);
333 #endif // __JUCER_PROJECTEXPORT_MAKE_JUCEHEADER__