1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Projucer: Add an option to specify per-file compiler flags

This commit is contained in:
ed 2019-01-22 15:48:15 +00:00
parent 315f803c49
commit b2e2346745
12 changed files with 459 additions and 111 deletions

View file

@ -37,8 +37,8 @@ public:
: item (group),
header (item.getName(), { getIcons().openFolder, Colours::transparentBlack })
{
list.setHeaderComponent (new ListBoxHeader ( { "File", "Binary Resource", "Xcode Resource", "Compile" },
{ 0.4f, 0.2f, 0.2f, 0.2f } ));
list.setHeaderComponent (new ListBoxHeader ( { "File", "Binary Resource", "Xcode Resource", "Compile", "Compiler Flag Scheme" },
{ 0.3f, 0.15f, 0.15f, 0.15f, 0.25f } ));
list.setModel (this);
list.setColour (ListBox::backgroundColourId, Colours::transparentBlack);
addAndMakeVisible (list);
@ -132,18 +132,23 @@ private:
public:
FileOptionComponent (const Project::Item& fileItem, ListBoxHeader* listBoxHeader)
: item (fileItem),
header (listBoxHeader)
header (listBoxHeader),
compilerFlagSchemeSelector (item)
{
if (item.isFile())
{
addAndMakeVisible (compileButton);
compileButton.getToggleStateValue().referTo (item.getShouldCompileValue());
compileButton.onStateChange = [this] { compilerFlagSchemeSelector.setVisible (compileButton.getToggleState()); };
addAndMakeVisible (binaryResourceButton);
binaryResourceButton.getToggleStateValue().referTo (item.getShouldAddToBinaryResourcesValue());
addAndMakeVisible (xcodeResourceButton);
xcodeResourceButton.getToggleStateValue().referTo (item.getShouldAddToXcodeResourcesValue());
addChildComponent (compilerFlagSchemeSelector);
compilerFlagSchemeSelector.setVisible (compileButton.getToggleState());
}
}
@ -175,18 +180,163 @@ private:
bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (0) * width));
binaryResourceButton.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (1) * width)));
xcodeResourceButton.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (2) * width)));
compileButton.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (3) * width)));
binaryResourceButton.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (1) * width)));
xcodeResourceButton.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (2) * width)));
compileButton.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (3) * width)));
compilerFlagSchemeSelector.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (4) * width)));
}
}
Project::Item item;
private:
//==============================================================================
class CompilerFlagSchemeSelector : public Component,
private Value::Listener
{
public:
CompilerFlagSchemeSelector (Project::Item& it)
: item (it)
{
schemeBox.setTextWhenNothingSelected ("None");
updateCompilerFlagSchemeComboBox();
schemeBox.onChange = [this] { handleComboBoxSelection(); };
addAndMakeVisible (schemeBox);
addChildComponent (newSchemeLabel);
newSchemeLabel.setEditable (true);
newSchemeLabel.setJustificationType (Justification::centredLeft);
newSchemeLabel.onEditorHide = [this]
{
newSchemeLabel.setVisible (false);
schemeBox.setVisible (true);
auto newScheme = newSchemeLabel.getText();
item.project.addCompilerFlagScheme (newScheme);
if (item.getCompilerFlagSchemeString().isEmpty())
item.setCompilerFlagScheme (newScheme);
updateCompilerFlagSchemeComboBox();
};
selectScheme (item.getCompilerFlagSchemeString());
projectCompilerFlagSchemesValue = item.project.getProjectValue (Ids::compilerFlagSchemes);
projectCompilerFlagSchemesValue.addListener (this);
lookAndFeelChanged();
}
void resized() override
{
auto b = getLocalBounds();
schemeBox.setBounds (b);
newSchemeLabel.setBounds (b);
}
private:
void valueChanged (Value&) override { updateCompilerFlagSchemeComboBox(); }
void lookAndFeelChanged() override
{
schemeBox.setColour (ComboBox::outlineColourId, Colours::transparentBlack);
schemeBox.setColour (ComboBox::textColourId, findColour (defaultTextColourId));
}
void updateCompilerFlagSchemeComboBox()
{
auto itemScheme = item.getCompilerFlagSchemeString();
auto allSchemes = item.project.getCompilerFlagSchemes();
if (itemScheme.isNotEmpty() && ! allSchemes.contains (itemScheme))
{
item.clearCurrentCompilerFlagScheme();
itemScheme = {};
}
schemeBox.clear();
schemeBox.addItemList (allSchemes, 1);
schemeBox.addSeparator();
schemeBox.addItem ("Add a new scheme...", -1);
schemeBox.addItem ("Delete selected scheme", -2);
schemeBox.addItem ("Clear", -3);
selectScheme (itemScheme);
}
void handleComboBoxSelection()
{
auto selectedID = schemeBox.getSelectedId();
if (selectedID > 0)
{
item.setCompilerFlagScheme (schemeBox.getItemText (selectedID - 1));
}
else if (selectedID == -1)
{
newSchemeLabel.setText ("NewScheme", dontSendNotification);
schemeBox.setVisible (false);
newSchemeLabel.setVisible (true);
newSchemeLabel.showEditor();
if (auto* ed = newSchemeLabel.getCurrentTextEditor())
ed->setInputRestrictions (64, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_");
}
else if (selectedID == -2)
{
auto currentScheme = item.getCompilerFlagSchemeString();
if (currentScheme.isNotEmpty())
{
item.project.removeCompilerFlagScheme (currentScheme);
item.clearCurrentCompilerFlagScheme();
}
updateCompilerFlagSchemeComboBox();
}
else if (selectedID == -3)
{
schemeBox.setSelectedId (0);
item.clearCurrentCompilerFlagScheme();
}
}
void selectScheme (const String& schemeToSelect)
{
if (schemeToSelect.isNotEmpty())
{
for (int i = 0; i < schemeBox.getNumItems(); ++i)
{
if (schemeBox.getItemText (i) == schemeToSelect)
{
schemeBox.setSelectedItemIndex (i);
return;
}
}
}
schemeBox.setSelectedId (0);
}
Project::Item& item;
Value projectCompilerFlagSchemesValue;
ComboBox schemeBox;
Label newSchemeLabel;
};
//==============================================================================
ListBoxHeader* header;
ToggleButton compileButton, binaryResourceButton, xcodeResourceButton;
CompilerFlagSchemeSelector compilerFlagSchemeSelector;
};
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileGroupInformationComponent)

View file

@ -225,13 +225,13 @@ void Project::initialiseProjectValues()
reportAppUsageValue.setDefault (true);
}
cppStandardValue.referTo (projectRoot, Ids::cppLanguageStandard, getUndoManager(), "14");
cppStandardValue.referTo (projectRoot, Ids::cppLanguageStandard, getUndoManager(), "14");
headerSearchPathsValue.referTo (projectRoot, Ids::headerPath, getUndoManager());
preprocessorDefsValue.referTo (projectRoot, Ids::defines, getUndoManager());
userNotesValue.referTo (projectRoot, Ids::userNotes, getUndoManager());
headerSearchPathsValue.referTo (projectRoot, Ids::headerPath, getUndoManager());
preprocessorDefsValue.referTo (projectRoot, Ids::defines, getUndoManager());
userNotesValue.referTo (projectRoot, Ids::userNotes, getUndoManager());
maxBinaryFileSizeValue.referTo (projectRoot, Ids::maxBinaryFileSize, getUndoManager(), 10240 * 1024);
maxBinaryFileSizeValue.referTo (projectRoot, Ids::maxBinaryFileSize, getUndoManager(), 10240 * 1024);
// this is here for backwards compatibility with old projects using the incorrect id
if (projectRoot.hasProperty ("includeBinaryInAppConfig"))
@ -239,7 +239,9 @@ void Project::initialiseProjectValues()
else
includeBinaryDataInJuceHeaderValue.referTo (projectRoot, Ids::includeBinaryInJuceHeader, getUndoManager(), true);
binaryDataNamespaceValue.referTo (projectRoot, Ids::binaryDataNamespace, getUndoManager(), "BinaryData");
binaryDataNamespaceValue.referTo (projectRoot, Ids::binaryDataNamespace, getUndoManager(), "BinaryData");
compilerFlagSchemesValue.referTo (projectRoot, Ids::compilerFlagSchemes, getUndoManager(), Array<var>(), ",");
}
void Project::initialiseAudioPluginValues()
@ -1273,6 +1275,19 @@ bool Project::Item::shouldInhibitWarnings() const { return state [Ids:
bool Project::Item::isModuleCode() const { return belongsToModule; }
Value Project::Item::getCompilerFlagSchemeValue() { return state.getPropertyAsValue (Ids::compilerFlagScheme, getUndoManager()); }
String Project::Item::getCompilerFlagSchemeString() const { return state [Ids::compilerFlagScheme]; }
void Project::Item::setCompilerFlagScheme (const String& scheme)
{
state.getPropertyAsValue (Ids::compilerFlagScheme, getUndoManager()).setValue (scheme);
}
void Project::Item::clearCurrentCompilerFlagScheme()
{
state.removeProperty (Ids::compilerFlagScheme, getUndoManager());
}
String Project::Item::getFilePath() const
{
if (isFile())
@ -1641,6 +1656,55 @@ bool Project::isConfigFlagEnabled (const String& name, bool defaultIsEnabled) co
return configValue;
}
//==============================================================================
StringArray Project::getCompilerFlagSchemes() const
{
if (compilerFlagSchemesValue.isUsingDefault())
return {};
StringArray schemes;
auto schemesVar = compilerFlagSchemesValue.get();
if (auto* arr = schemesVar.getArray())
schemes.addArray (arr->begin(), arr->end());
return schemes;
}
void Project::addCompilerFlagScheme (const String& schemeToAdd)
{
auto schemesVar = compilerFlagSchemesValue.get();
if (auto* arr = schemesVar.getArray())
{
arr->addIfNotAlreadyThere (schemeToAdd);
compilerFlagSchemesValue.setValue ({ *arr }, getUndoManager());
}
}
void Project::removeCompilerFlagScheme (const String& schemeToRemove)
{
auto schemesVar = compilerFlagSchemesValue.get();
if (auto* arr = schemesVar.getArray())
{
for (int i = 0; i < arr->size(); ++i)
{
if (arr->getUnchecked (i).toString() == schemeToRemove)
{
arr->remove (i);
if (arr->isEmpty())
compilerFlagSchemesValue.resetToDefault();
else
compilerFlagSchemesValue.setValue ({ *arr }, getUndoManager());
return;
}
}
}
}
//==============================================================================
static String getCompanyNameOrDefault (StringRef str)
{

View file

@ -129,6 +129,10 @@ public:
String getCppStandardString() const { return cppStandardValue.get(); }
StringArray getCompilerFlagSchemes() const;
void addCompilerFlagScheme (const String&);
void removeCompilerFlagScheme (const String&);
//==============================================================================
String getPluginNameString() const { return pluginNameValue.get(); }
String getPluginDescriptionString() const { return pluginDescriptionValue.get();}
@ -280,6 +284,12 @@ public:
bool isModuleCode() const;
Value getCompilerFlagSchemeValue();
String getCompilerFlagSchemeString() const;
void setCompilerFlagScheme (const String&);
void clearCurrentCompilerFlagScheme();
//==============================================================================
bool canContain (const Item& child) const;
int getNumChildren() const { return state.getNumChildren(); }
@ -417,7 +427,8 @@ private:
ValueWithDefault pluginFormatsValue, pluginNameValue, pluginDescriptionValue, pluginManufacturerValue, pluginManufacturerCodeValue,
pluginCodeValue, pluginChannelConfigsValue, pluginCharacteristicsValue, pluginAUExportPrefixValue, pluginAAXIdentifierValue,
pluginAUMainTypeValue, pluginAUSandboxSafeValue, pluginRTASCategoryValue, pluginVSTCategoryValue, pluginVST3CategoryValue, pluginAAXCategoryValue;
pluginAUMainTypeValue, pluginAUSandboxSafeValue, pluginRTASCategoryValue, pluginVSTCategoryValue, pluginVST3CategoryValue, pluginAAXCategoryValue,
compilerFlagSchemesValue;
//==============================================================================
std::unique_ptr<CompileEngineSettings> compileEngineSettings;

View file

@ -501,12 +501,13 @@ private:
}
Array<RelativePath> excludeFromBuild;
Array<std::pair<RelativePath, String>> extraCompilerFlags;
mo << "add_library( ${BINARY_NAME}" << newLine;
mo << newLine;
mo << " " << (getProject().getProjectType().isStaticLibrary() ? "STATIC" : "SHARED") << newLine;
mo << newLine;
addCompileUnits (mo, excludeFromBuild);
addCompileUnits (mo, excludeFromBuild, extraCompilerFlags);
mo << ")" << newLine << newLine;
if (excludeFromBuild.size() > 0)
@ -517,6 +518,14 @@ private:
mo << newLine;
}
if (! extraCompilerFlags.isEmpty())
{
for (auto& extra : extraCompilerFlags)
mo << "set_source_files_properties(\"" << extra.first.toUnixStyle() << "\" PROPERTIES COMPILE_FLAGS " << extra.second << " )" << newLine;
mo << newLine;
}
auto libraries = getAndroidLibraries();
if (libraries.size() > 0)
{
@ -1258,32 +1267,45 @@ private:
}
//==============================================================================
void addCompileUnits (const Project::Item& projectItem, MemoryOutputStream& mo, Array<RelativePath>& excludeFromBuild) const
void addCompileUnits (const Project::Item& projectItem, MemoryOutputStream& mo,
Array<RelativePath>& excludeFromBuild, Array<std::pair<RelativePath, String>>& extraCompilerFlags) const
{
if (projectItem.isGroup())
{
for (int i = 0; i < projectItem.getNumChildren(); ++i)
addCompileUnits (projectItem.getChild(i), mo, excludeFromBuild);
addCompileUnits (projectItem.getChild(i), mo, excludeFromBuild, extraCompilerFlags);
}
else if (projectItem.shouldBeAddedToTargetProject())
{
RelativePath file (projectItem.getFile(), getTargetFolder().getChildFile ("app"), RelativePath::buildTargetFolder);
auto targetType = getProject().getTargetTypeFromFilePath (projectItem.getFile(), true);
auto f = projectItem.getFile();
RelativePath file (f, getTargetFolder().getChildFile ("app"), RelativePath::buildTargetFolder);
auto targetType = getProject().getTargetTypeFromFilePath (f, true);
mo << " \"" << file.toUnixStyle() << "\"" << newLine;
if ((! projectItem.shouldBeCompiled()) || (! shouldFileBeCompiledByDefault (file))
if ((! projectItem.shouldBeCompiled()) || (! shouldFileBeCompiledByDefault (f))
|| (getProject().getProjectType().isAudioPlugin()
&& targetType != ProjectType::Target::SharedCodeTarget
&& targetType != ProjectType::Target::StandalonePlugIn))
{
excludeFromBuild.add (file);
}
else
{
auto extraFlags = compilerFlagSchemesMap[projectItem.getCompilerFlagSchemeString()].get().toString();
if (extraFlags.isNotEmpty())
extraCompilerFlags.add ({ file, extraFlags });
}
}
}
void addCompileUnits (MemoryOutputStream& mo, Array<RelativePath>& excludeFromBuild) const
void addCompileUnits (MemoryOutputStream& mo, Array<RelativePath>& excludeFromBuild,
Array<std::pair<RelativePath, String>>& extraCompilerFlags) const
{
for (int i = 0; i < getAllGroups().size(); ++i)
addCompileUnits (getAllGroups().getReference(i), mo, excludeFromBuild);
addCompileUnits (getAllGroups().getReference(i), mo, excludeFromBuild, extraCompilerFlags);
}
//==============================================================================

View file

@ -302,7 +302,7 @@ private:
}
template <class Target, class Exporter>
void getFileInfoList (Target& target, Exporter& exporter, const Project::Item& projectItem, std::vector<std::pair<String, bool>>& fileInfoList) const
void getFileInfoList (Target& target, Exporter& exporter, const Project::Item& projectItem, std::vector<std::tuple<String, bool, String>>& fileInfoList) const
{
auto targetType = (getProject().getProjectType().isAudioPlugin() ? target.type : Target::Type::SharedCodeTarget);
@ -314,7 +314,9 @@ private:
else if (projectItem.shouldBeAddedToTargetProject() && getProject().getTargetTypeFromFilePath (projectItem.getFile(), true) == targetType )
{
auto path = RelativePath (projectItem.getFile(), exporter.getTargetFolder(), RelativePath::buildTargetFolder).toUnixStyle();
fileInfoList.push_back ({ path, projectItem.shouldBeCompiled() });
fileInfoList.push_back (std::make_tuple (path, projectItem.shouldBeCompiled(),
exporter.compilerFlagSchemesMap[projectItem.getCompilerFlagSchemeString()].get().toString()));
}
}
@ -364,12 +366,12 @@ private:
out << newLine;
std::vector<std::pair<String, bool>> fileInfoList;
std::vector<std::tuple<String, bool, String>> fileInfoList;
for (auto& group : exporter.getAllGroups())
getFileInfoList (*target, exporter, group, fileInfoList);
for (auto& fileInfo : fileInfoList)
out << " " << fileInfo.first.quoted() << newLine;
out << " " << std::get<0> (fileInfo).quoted() << newLine;
auto isCMakeBundle = exporter.isXcode() && target->getTargetFileType() == ProjectType::Target::TargetFileType::pluginBundle;
auto pkgInfoPath = String ("PkgInfo").quoted();
@ -414,8 +416,19 @@ private:
out << "set_source_files_properties (" << xcodeIcnsFilePath << " PROPERTIES MACOSX_PACKAGE_LOCATION \"Resources\")" << newLine;
for (auto& fileInfo : fileInfoList)
if (! fileInfo.second)
out << "set_source_files_properties (" << fileInfo.first.quoted() << " PROPERTIES HEADER_FILE_ONLY TRUE)" << newLine;
{
if (std::get<1> (fileInfo))
{
auto extraCompilerFlags = std::get<2> (fileInfo);
if (extraCompilerFlags.isNotEmpty())
out << "set_source_files_properties(" << std::get<0> (fileInfo).quoted() << " PROPERTIES COMPILE_FLAGS " << extraCompilerFlags << " )" << newLine;
}
else
{
out << "set_source_files_properties (" << std::get<0> (fileInfo).quoted() << " PROPERTIES HEADER_FILE_ONLY TRUE)" << newLine;
}
}
out << newLine;
}

View file

@ -787,7 +787,20 @@ private:
unit->createNewChildElement ("Option")->setAttribute ("target", targetName);
}
if (! projectItem.shouldBeCompiled())
if (projectItem.shouldBeCompiled())
{
auto extraCompilerFlags = compilerFlagSchemesMap[projectItem.getCompilerFlagSchemeString()].get().toString();
if (extraCompilerFlags.isNotEmpty())
{
auto* optionElement = unit->createNewChildElement ("Option");
optionElement->setAttribute ("compiler", "gcc");
optionElement->setAttribute ("use", 1);
optionElement->setAttribute ("buildCommand", "$compiler $options " + extraCompilerFlags + " $includes -c $file -o $object");
}
}
else
{
unit->createNewChildElement ("Option")->setAttribute ("compile", 0);
unit->createNewChildElement ("Option")->setAttribute ("link", 0);

View file

@ -767,8 +767,17 @@ public:
if (shouldUseStdCall (path))
e->createNewChildElement ("CallingConvention")->addTextElement ("StdCall");
if (! projectItem.shouldBeCompiled())
if (projectItem.shouldBeCompiled())
{
auto extraCompilerFlags = owner.compilerFlagSchemesMap[projectItem.getCompilerFlagSchemeString()].get().toString();
if (extraCompilerFlags.isNotEmpty())
e->createNewChildElement ("AdditionalOptions")->addTextElement (extraCompilerFlags + " %(AdditionalOptions)");
}
else
{
e->createNewChildElement ("ExcludedFromBuild")->addTextElement ("true");
}
}
}
else if (path.hasFileExtension (headerFileExtensions))

View file

@ -194,63 +194,31 @@ public:
return String (getName()).toUpperCase().replaceCharacter (L' ', L'_');
}
void writeObjects (OutputStream& out) const
void writeObjects (OutputStream& out, const Array<std::pair<File, String>>& filesToCompile) const
{
Array<RelativePath> targetFiles;
for (int i = 0; i < owner.getAllGroups().size(); ++i)
findAllFilesToCompile (owner.getAllGroups().getReference(i), targetFiles);
out << "OBJECTS_" + getTargetVarName() + String (" := \\") << newLine;
for (int i = 0; i < targetFiles.size(); ++i)
out << " $(JUCE_OBJDIR)/" << escapeSpaces (owner.getObjectFileFor (targetFiles.getReference(i))) << " \\" << newLine;
for (auto& f : filesToCompile)
out << " $(JUCE_OBJDIR)/" << escapeSpaces (owner.getObjectFileFor ({ f.first, owner.getTargetFolder(), RelativePath::buildTargetFolder })) << " \\" << newLine;
out << newLine;
}
void findAllFilesToCompile (const Project::Item& projectItem, Array<RelativePath>& results) const
void addFiles (OutputStream& out, const Array<std::pair<File, String>>& filesToCompile)
{
if (projectItem.isGroup())
{
for (int i = 0; i < projectItem.getNumChildren(); ++i)
findAllFilesToCompile (projectItem.getChild(i), results);
}
else
{
if (projectItem.shouldBeCompiled())
{
auto targetType = (owner.getProject().getProjectType().isAudioPlugin() ? type : SharedCodeTarget);
auto f = projectItem.getFile();
RelativePath relativePath (f, owner.getTargetFolder(), RelativePath::buildTargetFolder);
if (owner.shouldFileBeCompiledByDefault (relativePath)
&& owner.getProject().getTargetTypeFromFilePath (f, true) == targetType)
results.add (relativePath);
}
}
}
void addFiles (OutputStream& out)
{
Array<RelativePath> targetFiles;
for (int i = 0; i < owner.getAllGroups().size(); ++i)
findAllFilesToCompile (owner.getAllGroups().getReference(i), targetFiles);
auto cppflagsVarName = "JUCE_CPPFLAGS_" + getTargetVarName();
auto cflagsVarName = "JUCE_CFLAGS_" + getTargetVarName();
for (int i = 0; i < targetFiles.size(); ++i)
for (auto& f : filesToCompile)
{
jassert (targetFiles.getReference(i).getRoot() == RelativePath::buildTargetFolder);
RelativePath relativePath (f.first, owner.getTargetFolder(), RelativePath::buildTargetFolder);
out << "$(JUCE_OBJDIR)/" << escapeSpaces (owner.getObjectFileFor (targetFiles.getReference(i)))
<< ": " << escapeSpaces (targetFiles.getReference(i).toUnixStyle()) << newLine
<< "\t-$(V_AT)mkdir -p $(JUCE_OBJDIR)" << newLine
<< "\t@echo \"Compiling " << targetFiles.getReference(i).getFileName() << "\"" << newLine
<< (targetFiles.getReference(i).hasFileExtension ("c;s;S") ? "\t$(V_AT)$(CC) $(JUCE_CFLAGS) "
: "\t$(V_AT)$(CXX) $(JUCE_CXXFLAGS) ")
<< "$(" << cppflagsVarName << ") $(" << cflagsVarName << ") -o \"$@\" -c \"$<\""
<< newLine
out << "$(JUCE_OBJDIR)/" << escapeSpaces (owner.getObjectFileFor (relativePath)) << ": " << escapeSpaces (relativePath.toUnixStyle()) << newLine
<< "\t-$(V_AT)mkdir -p $(JUCE_OBJDIR)" << newLine
<< "\t@echo \"Compiling " << relativePath.getFileName() << "\"" << newLine
<< (relativePath.hasFileExtension ("c;s;S") ? "\t$(V_AT)$(CC) $(JUCE_CFLAGS) " : "\t$(V_AT)$(CXX) $(JUCE_CXXFLAGS) ")
<< "$(" << cppflagsVarName << ") $(" << cflagsVarName << ")"
<< (f.second.isNotEmpty() ? " $(" + owner.getCompilerFlagSchemeVariableName (f.second) + ")" : "") << " -o \"$@\" -c \"$<\"" << newLine
<< newLine;
}
}
@ -736,7 +704,7 @@ private:
}
out << "all : " << dependencies.joinIntoString (" ") << newLine << newLine;
out << subTargetLines.toString() << newLine << newLine;
out << subTargetLines.toString() << newLine << newLine;
}
else
{
@ -761,15 +729,15 @@ private:
outputDir = binaryPath.rebased (projectFolder, getTargetFolder(), RelativePath::buildTargetFolder).toUnixStyle();
}
out << "ifeq ($(CONFIG)," << escapeSpaces (config.getName()) << ")" << newLine;
out << " JUCE_BINDIR := " << escapeSpaces (buildDirName) << newLine
<< " JUCE_LIBDIR := " << escapeSpaces (buildDirName) << newLine
<< " JUCE_OBJDIR := " << escapeSpaces (intermediatesDirName) << newLine
<< " JUCE_OUTDIR := " << escapeSpaces (outputDir) << newLine
out << "ifeq ($(CONFIG)," << escapeSpaces (config.getName()) << ")" << newLine
<< " JUCE_BINDIR := " << escapeSpaces (buildDirName) << newLine
<< " JUCE_LIBDIR := " << escapeSpaces (buildDirName) << newLine
<< " JUCE_OBJDIR := " << escapeSpaces (intermediatesDirName) << newLine
<< " JUCE_OUTDIR := " << escapeSpaces (outputDir) << newLine
<< newLine
<< " ifeq ($(TARGET_ARCH),)" << newLine
<< " TARGET_ARCH := " << getArchFlags (config) << newLine
<< " endif" << newLine
<< " ifeq ($(TARGET_ARCH),)" << newLine
<< " TARGET_ARCH := " << getArchFlags (config) << newLine
<< " endif" << newLine
<< newLine;
writeCppFlags (out, config);
@ -828,37 +796,84 @@ private:
}
}
static String getCompilerFlagSchemeVariableName (const String& schemeName) { return "JUCE_COMPILERFLAGSCHEME_" + schemeName; }
void findAllFilesToCompile (const Project::Item& projectItem, Array<std::pair<File, String>>& results) const
{
if (projectItem.isGroup())
{
for (int i = 0; i < projectItem.getNumChildren(); ++i)
findAllFilesToCompile (projectItem.getChild (i), results);
}
else
{
if (projectItem.shouldBeCompiled())
{
auto f = projectItem.getFile();
if (shouldFileBeCompiledByDefault (f))
{
auto scheme = projectItem.getCompilerFlagSchemeString();
auto flags = compilerFlagSchemesMap[scheme].get().toString();
if (scheme.isNotEmpty() && flags.isNotEmpty())
results.add ({ f, scheme });
else
results.add ({ f, {} });
}
}
}
}
void writeCompilerFlagSchemes (OutputStream& out, const Array<std::pair<File, String>>& filesToCompile) const
{
StringArray schemesToWrite;
for (auto& f : filesToCompile)
if (f.second.isNotEmpty())
schemesToWrite.addIfNotAlreadyThere (f.second);
if (! schemesToWrite.isEmpty())
{
for (auto& s : schemesToWrite)
out << getCompilerFlagSchemeVariableName (s) << " := "
<< compilerFlagSchemesMap[s].get().toString() << newLine;
out << newLine;
}
}
void writeMakefile (OutputStream& out) const
{
out << "# Automatically generated makefile, created by the Projucer" << newLine
out << "# Automatically generated makefile, created by the Projucer" << newLine
<< "# Don't edit this file! Your changes will be overwritten when you re-save the Projucer project!" << newLine
<< newLine;
out << "# build with \"V=1\" for verbose builds" << newLine
<< "ifeq ($(V), 1)" << newLine
<< "V_AT =" << newLine
<< "else" << newLine
<< "V_AT = @" << newLine
<< "endif" << newLine
<< "ifeq ($(V), 1)" << newLine
<< "V_AT =" << newLine
<< "else" << newLine
<< "V_AT = @" << newLine
<< "endif" << newLine
<< newLine;
out << "# (this disables dependency generation if multiple architectures are set)" << newLine
<< "DEPFLAGS := $(if $(word 2, $(TARGET_ARCH)), , -MMD)" << newLine
<< "DEPFLAGS := $(if $(word 2, $(TARGET_ARCH)), , -MMD)" << newLine
<< newLine;
out << "ifndef STRIP" << newLine
out << "ifndef STRIP" << newLine
<< " STRIP=strip" << newLine
<< "endif" << newLine
<< "endif" << newLine
<< newLine;
out << "ifndef AR" << newLine
<< " AR=ar" << newLine
<< "endif" << newLine
<< " AR=ar" << newLine
<< "endif" << newLine
<< newLine;
out << "ifndef CONFIG" << newLine
out << "ifndef CONFIG" << newLine
<< " CONFIG=" << escapeSpaces (getConfiguration(0)->getName()) << newLine
<< "endif" << newLine
<< "endif" << newLine
<< newLine;
out << "JUCE_ARCH_LABEL := $(shell uname -m)" << newLine
@ -867,21 +882,43 @@ private:
for (ConstConfigIterator config (*this); config.next();)
writeConfig (out, dynamic_cast<const MakeBuildConfiguration&> (*config));
Array<std::pair<File, String>> filesToCompile;
for (int i = 0; i < getAllGroups().size(); ++i)
findAllFilesToCompile (getAllGroups().getReference (i), filesToCompile);
writeCompilerFlagSchemes (out, filesToCompile);
auto getFilesForTarget = [] (const Array<std::pair<File, String>>& files, MakefileTarget* target, const Project& p) -> Array<std::pair<File, String>>
{
Array<std::pair<File, String>> targetFiles;
auto targetType = (p.getProjectType().isAudioPlugin() ? target->type : MakefileTarget::SharedCodeTarget);
for (auto& f : files)
if (p.getTargetTypeFromFilePath (f.first, true) == targetType)
targetFiles.add (f);
return targetFiles;
};
for (auto target : targets)
target->writeObjects (out);
target->writeObjects (out, getFilesForTarget (filesToCompile, target, project));
out << getPhonyTargetLine() << newLine << newLine;
writeTargetLines (out, getPackages());
for (auto target : targets)
target->addFiles (out);out << "clean:" << newLine
target->addFiles (out, getFilesForTarget (filesToCompile, target, project));
out << "clean:" << newLine
<< "\t@echo Cleaning " << projectName << newLine
<< "\t$(V_AT)$(CLEANCMD)" << newLine
<< "\t$(V_AT)$(CLEANCMD)" << newLine
<< newLine;
out << "strip:" << newLine
<< "\t@echo Stripping " << projectName << newLine
out << "strip:" << newLine
<< "\t@echo Stripping " << projectName << newLine
<< "\t-$(V_AT)$(STRIP) --strip-unneeded $(JUCE_OUTDIR)/$(TARGET)" << newLine
<< newLine;

View file

@ -2720,7 +2720,8 @@ private:
output << "\t};\n\trootObject = " << createID ("__root") << ";\n}\n";
}
String addBuildFile (const String& path, const String& fileRefID, bool addToSourceBuildPhase, bool inhibitWarnings, XcodeTarget* xcodeTarget = nullptr) const
String addBuildFile (const String& path, const String& fileRefID, bool addToSourceBuildPhase, bool inhibitWarnings,
XcodeTarget* xcodeTarget = nullptr, String compilerFlags = {}) const
{
auto fileID = createID (path + "buildref");
@ -2737,7 +2738,10 @@ private:
v->setProperty ("fileRef", fileRefID, nullptr);
if (inhibitWarnings)
v->setProperty ("settings", "{ COMPILER_FLAGS = \"-w\"; }", nullptr);
compilerFlags += " -w";
if (compilerFlags.isNotEmpty())
v->setProperty ("settings", "{ COMPILER_FLAGS = \"" + compilerFlags.trim() + "\"; }", nullptr);
pbxBuildFiles.add (v);
return fileID;
@ -2865,14 +2869,14 @@ private:
}
String addFile (const RelativePath& path, bool shouldBeCompiled, bool shouldBeAddedToBinaryResources,
bool shouldBeAddedToXcodeResources, bool inhibitWarnings, XcodeTarget* xcodeTarget) const
bool shouldBeAddedToXcodeResources, bool inhibitWarnings, XcodeTarget* xcodeTarget, const String& compilerFlags) const
{
auto pathAsString = path.toUnixStyle();
auto refID = addFileReference (path.toUnixStyle());
if (shouldBeCompiled)
{
addBuildFile (pathAsString, refID, true, inhibitWarnings, xcodeTarget);
addBuildFile (pathAsString, refID, true, inhibitWarnings, xcodeTarget, compilerFlags);
}
else if (! shouldBeAddedToBinaryResources || shouldBeAddedToXcodeResources)
{
@ -2991,7 +2995,7 @@ private:
overwriteFileIfDifferentOrThrow (entitlementsFile, content);
RelativePath plistPath (entitlementsFile, getTargetFolder(), RelativePath::buildTargetFolder);
return addFile (plistPath, false, false, false, false, nullptr);
return addFile (plistPath, false, false, false, false, nullptr, {});
}
String addProjectItem (const Project::Item& projectItem) const
@ -3039,7 +3043,8 @@ private:
projectItem.shouldBeAddedToBinaryResources(),
projectItem.shouldBeAddedToXcodeResources(),
projectItem.shouldInhibitWarnings(),
xcodeTarget);
xcodeTarget,
compilerFlagSchemesMap[projectItem.getCompilerFlagSchemeString()].get());
}
return {};
@ -3508,7 +3513,7 @@ private:
String createFileRefID (const String& path) const { return createID ("__fileref_" + path); }
String getIDForGroup (const Project::Item& item) const { return createID (item.getID()); }
bool shouldFileBeCompiledByDefault (const RelativePath& file) const override
bool shouldFileBeCompiledByDefault (const File& file) const override
{
return file.hasFileExtension (sourceFileExtensions);
}

View file

@ -257,6 +257,9 @@ ProjectExporter::ProjectExporter (Project& p, const ValueTree& state)
smallIconValue (settings, Ids::smallIcon, getUndoManager()),
extraPPDefsValue (settings, Ids::extraDefs, getUndoManager())
{
projectCompilerFlagSchemesValue = project.getProjectValue (Ids::compilerFlagSchemes);
projectCompilerFlagSchemesValue.addListener (this);
updateCompilerFlagValues();
}
ProjectExporter::~ProjectExporter()
@ -283,12 +286,20 @@ RelativePath ProjectExporter::rebaseFromProjectFolderToBuildTarget (const Relati
return path.rebased (project.getProjectFolder(), getTargetFolder(), RelativePath::buildTargetFolder);
}
bool ProjectExporter::shouldFileBeCompiledByDefault (const RelativePath& file) const
bool ProjectExporter::shouldFileBeCompiledByDefault (const File& file) const
{
return file.hasFileExtension (cOrCppFileExtensions)
|| file.hasFileExtension (asmFileExtensions);
}
void ProjectExporter::updateCompilerFlagValues()
{
compilerFlagSchemesMap.clear();
for (auto& scheme : project.getCompilerFlagSchemes())
compilerFlagSchemesMap.set (scheme, { settings, scheme, getUndoManager() });
}
//==============================================================================
void ProjectExporter::createPropertyEditors (PropertyListBuilder& props)
{
@ -336,6 +347,10 @@ void ProjectExporter::createPropertyEditors (PropertyListBuilder& props)
"Extra command-line flags to be passed to the compiler. This string can contain references to preprocessor definitions in the "
"form ${NAME_OF_DEFINITION}, which will be replaced with their values.");
for (HashMap<String, ValueWithDefault>::Iterator i (compilerFlagSchemesMap); i.next();)
props.add (new TextPropertyComponent (compilerFlagSchemesMap.getReference (i.getKey()), "Compiler Flags for " + i.getKey().quoted(), 8192, false),
"The exporter-specific compiler flags that will be added to files using this scheme.");
props.add (new TextPropertyComponent (extraLinkerFlagsValue, "Extra Linker Flags", 8192, true),
"Extra command-line flags to be passed to the linker. You might want to use this for adding additional libraries. "
"This string can contain references to preprocessor definitions in the form ${NAME_OF_VALUE}, which will be replaced with their values.");

View file

@ -32,11 +32,11 @@
class ProjectSaver;
//==============================================================================
class ProjectExporter
class ProjectExporter : private Value::Listener
{
public:
ProjectExporter (Project&, const ValueTree& settings);
virtual ~ProjectExporter();
virtual ~ProjectExporter() override;
struct ExporterTypeInfo
{
@ -78,7 +78,7 @@ public:
virtual bool canLaunchProject() = 0;
virtual bool launchProject() = 0;
virtual void create (const OwnedArray<LibraryModule>&) const = 0; // may throw a SaveError
virtual bool shouldFileBeCompiledByDefault (const RelativePath& path) const;
virtual bool shouldFileBeCompiledByDefault (const File& path) const;
virtual bool canCopeWithDuplicateFiles() = 0;
virtual bool supportsUserDefinedConfigurations() const = 0; // false if exporter only supports two configs Debug and Release
virtual void updateDeprecatedProjectSettingsInteractively();
@ -406,6 +406,9 @@ protected:
ValueWithDefault targetLocationValue, extraCompilerFlagsValue, extraLinkerFlagsValue, externalLibrariesValue,
userNotesValue, gnuExtensionsValue, bigIconValue, smallIconValue, extraPPDefsValue;
Value projectCompilerFlagSchemesValue;
HashMap<String, ValueWithDefault> compilerFlagSchemesMap;
mutable Array<Project::Item> itemGroups;
void initItemGroups() const;
Project::Item* modulesGroup = nullptr;
@ -454,6 +457,10 @@ protected:
static Image rescaleImageForIcon (Drawable&, int iconSize);
private:
//==============================================================================
void valueChanged (Value&) override { updateCompilerFlagValues(); }
void updateCompilerFlagValues();
//==============================================================================
static String addLibPrefix (const String name)
{

View file

@ -345,6 +345,8 @@ namespace Ids
DECLARE_ID (continuousRebuildEnabled);
DECLARE_ID (warningsEnabled);
DECLARE_ID (projectLineFeed);
DECLARE_ID (compilerFlagSchemes);
DECLARE_ID (compilerFlagScheme);
const Identifier ID ("id");
const Identifier ID_uppercase ("ID");