1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00
JUCE/extras/Introjucer/Source/Project Saving/jucer_ProjectExport_Make.h

335 lines
12 KiB
C++

/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-11 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/
#ifndef __JUCER_PROJECTEXPORT_MAKE_JUCEHEADER__
#define __JUCER_PROJECTEXPORT_MAKE_JUCEHEADER__
#include "jucer_ProjectExporter.h"
//==============================================================================
class MakefileProjectExporter : public ProjectExporter
{
public:
//==============================================================================
static const char* getNameLinux() { return "Linux Makefile"; }
static const char* getValueTreeTypeName() { return "LINUX_MAKE"; }
static MakefileProjectExporter* createForSettings (Project& project, const ValueTree& settings)
{
if (settings.hasType (getValueTreeTypeName()))
return new MakefileProjectExporter (project, settings);
return nullptr;
}
//==============================================================================
MakefileProjectExporter (Project& project_, const ValueTree& settings_)
: ProjectExporter (project_, settings_)
{
name = getNameLinux();
if (getTargetLocation().toString().isEmpty())
getTargetLocation() = getDefaultBuildsRootFolder() + "Linux";
}
//==============================================================================
int getLaunchPreferenceOrderForCurrentOS()
{
#if JUCE_LINUX
return 1;
#else
return 0;
#endif
}
bool isPossibleForCurrentProject() { return true; }
bool usesMMFiles() const { return false; }
bool isLinux() const { return true; }
bool canCopeWithDuplicateFiles() { return false; }
void launchProject()
{
// what to do on linux?
}
void createPropertyEditors (PropertyListBuilder& props)
{
ProjectExporter::createPropertyEditors (props);
}
//==============================================================================
void create (const OwnedArray<LibraryModule>&)
{
Array<RelativePath> files;
for (int i = 0; i < groups.size(); ++i)
findAllFilesToCompile (groups.getReference(i), files);
MemoryOutputStream mo;
writeMakefile (mo, files);
overwriteFileIfDifferentOrThrow (getTargetFolder().getChildFile ("Makefile"), mo);
}
protected:
//==============================================================================
class MakeBuildConfiguration : public BuildConfiguration
{
public:
MakeBuildConfiguration (Project& project, const ValueTree& settings)
: BuildConfiguration (project, settings)
{
if (getLibrarySearchPath().getValue().isVoid())
getLibrarySearchPath() = "/usr/X11R6/lib/";
}
void createPropertyEditors (PropertyListBuilder& props)
{
createBasicPropertyEditors (props);
}
};
BuildConfiguration::Ptr createBuildConfig (const ValueTree& settings) const
{
return new MakeBuildConfiguration (project, settings);
}
private:
//==============================================================================
void findAllFilesToCompile (const Project::Item& projectItem, Array<RelativePath>& results)
{
if (projectItem.isGroup())
{
for (int i = 0; i < projectItem.getNumChildren(); ++i)
findAllFilesToCompile (projectItem.getChild(i), results);
}
else
{
if (projectItem.shouldBeCompiled())
results.add (RelativePath (projectItem.getFile(), getTargetFolder(), RelativePath::buildTargetFolder));
}
}
void writeDefineFlags (OutputStream& out, const BuildConfiguration& config)
{
StringPairArray defines;
defines.set ("LINUX", "1");
if (config.isDebug().getValue())
{
defines.set ("DEBUG", "1");
defines.set ("_DEBUG", "1");
}
else
{
defines.set ("NDEBUG", "1");
}
out << createGCCPreprocessorFlags (mergePreprocessorDefs (defines, getAllPreprocessorDefs (config)));
}
void writeHeaderPathFlags (OutputStream& out, const BuildConfiguration& config)
{
StringArray searchPaths (extraSearchPaths);
searchPaths.addArray (config.getHeaderSearchPaths());
searchPaths.insert (0, "/usr/include/freetype2");
searchPaths.insert (0, "/usr/include");
searchPaths.removeDuplicates (false);
for (int i = 0; i < searchPaths.size(); ++i)
out << " -I " << addQuotesIfContainsSpaces (FileHelpers::unixStylePath (replacePreprocessorTokens (config, searchPaths[i])));
}
void writeCppFlags (OutputStream& out, const BuildConfiguration& config)
{
out << " CPPFLAGS := $(DEPFLAGS)";
writeDefineFlags (out, config);
writeHeaderPathFlags (out, config);
out << newLine;
}
void writeLinkerFlags (OutputStream& out, const BuildConfiguration& config)
{
out << " LDFLAGS += -L$(BINDIR) -L$(LIBDIR)";
if (makefileIsDLL)
out << " -shared";
out << config.getGCCLibraryPathFlags();
const char* defaultLibs[] = { "freetype", "pthread", "rt", "X11", "GL", "GLU", "Xinerama", "asound", "Xext", 0 };
StringArray libs (defaultLibs);
for (int i = 0; i < libs.size(); ++i)
out << " -l" << libs[i];
out << " " << replacePreprocessorTokens (config, getExtraLinkerFlags().toString()).trim()
<< newLine;
}
void writeConfig (OutputStream& out, const BuildConfiguration& config)
{
const String buildDirName ("build");
const String intermediatesDirName (buildDirName + "/intermediate/" + config.getName().toString());
String outputDir (buildDirName);
if (config.getTargetBinaryRelativePath().toString().isNotEmpty())
{
RelativePath binaryPath (config.getTargetBinaryRelativePath().toString(), RelativePath::projectFolder);
outputDir = binaryPath.rebased (projectFolder, getTargetFolder(), RelativePath::buildTargetFolder).toUnixStyle();
}
out << "ifeq ($(CONFIG)," << escapeSpaces (config.getName().toString()) << ")" << newLine;
out << " BINDIR := " << escapeSpaces (buildDirName) << newLine
<< " LIBDIR := " << escapeSpaces (buildDirName) << newLine
<< " OBJDIR := " << escapeSpaces (intermediatesDirName) << newLine
<< " OUTDIR := " << escapeSpaces (outputDir) << newLine;
writeCppFlags (out, config);
out << " CFLAGS += $(CPPFLAGS) $(TARGET_ARCH)";
if (config.isDebug().getValue())
out << " -g -ggdb";
if (makefileIsDLL)
out << " -fPIC";
out << " -O" << config.getGCCOptimisationFlag() << newLine;
out << " CXXFLAGS += $(CFLAGS) " << replacePreprocessorTokens (config, getExtraCompilerFlags().toString()).trim() << newLine;
writeLinkerFlags (out, config);
out << " LDDEPS :=" << newLine
<< " RESFLAGS := ";
writeDefineFlags (out, config);
writeHeaderPathFlags (out, config);
out << newLine;
String targetName (config.getTargetBinaryName().getValue().toString());
if (projectType.isLibrary())
targetName = getLibbedFilename (targetName);
else
targetName = targetName.upToLastOccurrenceOf (".", false, false) + makefileTargetSuffix;
out << " TARGET := " << escapeSpaces (targetName) << newLine;
if (projectType.isLibrary())
out << " BLDCMD = ar -rcs $(OUTDIR)/$(TARGET) $(OBJECTS) $(TARGET_ARCH)" << newLine;
else
out << " BLDCMD = $(CXX) -o $(OUTDIR)/$(TARGET) $(OBJECTS) $(LDFLAGS) $(RESOURCES) $(TARGET_ARCH)" << newLine;
out << "endif" << newLine << newLine;
}
void writeObjects (OutputStream& out, const Array<RelativePath>& files)
{
out << "OBJECTS := \\" << newLine;
for (int i = 0; i < files.size(); ++i)
if (shouldFileBeCompiledByDefault (files.getReference(i)))
out << " $(OBJDIR)/" << escapeSpaces (getObjectFileFor (files.getReference(i))) << " \\" << newLine;
out << newLine;
}
void writeMakefile (OutputStream& out, const Array<RelativePath>& files)
{
out << "# Automatically generated makefile, created by the Introjucer" << newLine
<< "# Don't edit this file! Your changes will be overwritten when you re-save the Introjucer project!" << newLine
<< newLine;
out << "ifndef CONFIG" << newLine
<< " CONFIG=" << escapeSpaces (getConfiguration(0)->getName().toString()) << newLine
<< "endif" << newLine
<< newLine;
if (! projectType.isLibrary())
out << "ifeq ($(TARGET_ARCH),)" << newLine
<< " TARGET_ARCH := -march=native" << newLine
<< "endif" << newLine << newLine;
out << "# (this disables dependency generation if multiple architectures are set)" << newLine
<< "DEPFLAGS := $(if $(word 2, $(TARGET_ARCH)), , -MMD)" << newLine
<< newLine;
for (ConfigIterator config (*this); config.next();)
writeConfig (out, *config);
writeObjects (out, files);
out << ".PHONY: clean" << newLine
<< newLine;
out << "$(OUTDIR)/$(TARGET): $(OBJECTS) $(LDDEPS) $(RESOURCES)" << newLine
<< "\t@echo Linking " << projectName << newLine
<< "\t-@mkdir -p $(BINDIR)" << newLine
<< "\t-@mkdir -p $(LIBDIR)" << newLine
<< "\t-@mkdir -p $(OUTDIR)" << newLine
<< "\t@$(BLDCMD)" << newLine
<< newLine;
out << "clean:" << newLine
<< "\t@echo Cleaning " << projectName << newLine
<< "\t-@rm -f $(OUTDIR)/$(TARGET)" << newLine
<< "\t-@rm -rf $(OBJDIR)/*" << newLine
<< "\t-@rm -rf $(OBJDIR)" << newLine
<< newLine;
for (int i = 0; i < files.size(); ++i)
{
if (shouldFileBeCompiledByDefault (files.getReference(i)))
{
jassert (files.getReference(i).getRoot() == RelativePath::buildTargetFolder);
out << "$(OBJDIR)/" << escapeSpaces (getObjectFileFor (files.getReference(i)))
<< ": " << escapeSpaces (files.getReference(i).toUnixStyle()) << newLine
<< "\t-@mkdir -p $(OBJDIR)" << newLine
<< "\t@echo \"Compiling " << files.getReference(i).getFileName() << "\"" << newLine
<< (files.getReference(i).hasFileExtension (".c") ? "\t@$(CC) $(CFLAGS) -o \"$@\" -c \"$<\""
: "\t@$(CXX) $(CXXFLAGS) -o \"$@\" -c \"$<\"")
<< newLine << newLine;
}
}
out << "-include $(OBJECTS:%.o=%.d)" << newLine;
}
String getObjectFileFor (const RelativePath& file) const
{
return file.getFileNameWithoutExtension()
+ "_" + String::toHexString (file.toUnixStyle().hashCode()) + ".o";
}
JUCE_DECLARE_NON_COPYABLE (MakefileProjectExporter);
};
#endif // __JUCER_PROJECTEXPORT_MAKE_JUCEHEADER__