mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
CMake: Add support for building JUCE projects with CMake
This commit is contained in:
parent
1fdba480cc
commit
ece5644a20
149 changed files with 9921 additions and 3693 deletions
|
|
@ -0,0 +1,344 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE 6 technical preview.
|
||||
Copyright (c) 2017 - ROLI Ltd.
|
||||
|
||||
You may use this code under the terms of the GPL v3
|
||||
(see www.gnu.org/licenses).
|
||||
|
||||
For this technical preview, this file is not subject to commercial licensing.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
namespace build_tools
|
||||
{
|
||||
void overwriteFileIfDifferentOrThrow (const File& file, const MemoryOutputStream& newData)
|
||||
{
|
||||
if (! overwriteFileWithNewDataIfDifferent (file, newData))
|
||||
throw SaveError (file);
|
||||
}
|
||||
|
||||
void overwriteFileIfDifferentOrThrow (const File& file, const String& newData)
|
||||
{
|
||||
if (! overwriteFileWithNewDataIfDifferent (file, newData))
|
||||
throw SaveError (file);
|
||||
}
|
||||
|
||||
String replacePreprocessorDefs (const StringPairArray& definitions, String sourceString)
|
||||
{
|
||||
for (int i = 0; i < definitions.size(); ++i)
|
||||
{
|
||||
const String key (definitions.getAllKeys()[i]);
|
||||
const String value (definitions.getAllValues()[i]);
|
||||
|
||||
sourceString = sourceString.replace ("${" + key + "}", value);
|
||||
}
|
||||
|
||||
return sourceString;
|
||||
}
|
||||
|
||||
String getXcodePackageType (ProjectType::Target::Type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ProjectType::Target::Type::GUIApp:
|
||||
case ProjectType::Target::Type::StandalonePlugIn:
|
||||
return "APPL";
|
||||
|
||||
case ProjectType::Target::Type::VSTPlugIn:
|
||||
case ProjectType::Target::Type::VST3PlugIn:
|
||||
case ProjectType::Target::Type::AudioUnitPlugIn:
|
||||
case ProjectType::Target::Type::UnityPlugIn:
|
||||
return "BNDL";
|
||||
|
||||
case ProjectType::Target::Type::AudioUnitv3PlugIn:
|
||||
return "XPC!";
|
||||
|
||||
case ProjectType::Target::Type::AAXPlugIn:
|
||||
case ProjectType::Target::Type::RTASPlugIn:
|
||||
return "TDMw";
|
||||
|
||||
case ProjectType::Target::Type::ConsoleApp:
|
||||
case ProjectType::Target::Type::StaticLibrary:
|
||||
case ProjectType::Target::Type::DynamicLibrary:
|
||||
case ProjectType::Target::Type::SharedCodeTarget:
|
||||
case ProjectType::Target::Type::AggregateTarget:
|
||||
case ProjectType::Target::Type::unspecified:
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
String getXcodeBundleSignature (ProjectType::Target::Type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ProjectType::Target::Type::GUIApp:
|
||||
case ProjectType::Target::Type::VSTPlugIn:
|
||||
case ProjectType::Target::Type::VST3PlugIn:
|
||||
case ProjectType::Target::Type::AudioUnitPlugIn:
|
||||
case ProjectType::Target::Type::StandalonePlugIn:
|
||||
case ProjectType::Target::Type::AudioUnitv3PlugIn:
|
||||
case ProjectType::Target::Type::UnityPlugIn:
|
||||
return "????";
|
||||
|
||||
case ProjectType::Target::Type::AAXPlugIn:
|
||||
case ProjectType::Target::Type::RTASPlugIn:
|
||||
return "PTul";
|
||||
|
||||
case ProjectType::Target::Type::ConsoleApp:
|
||||
case ProjectType::Target::Type::StaticLibrary:
|
||||
case ProjectType::Target::Type::DynamicLibrary:
|
||||
case ProjectType::Target::Type::SharedCodeTarget:
|
||||
case ProjectType::Target::Type::AggregateTarget:
|
||||
case ProjectType::Target::Type::unspecified:
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int calculateHash (const String& s, const unsigned int hashMultiplier)
|
||||
{
|
||||
auto t = s.toUTF8();
|
||||
unsigned int hash = 0;
|
||||
|
||||
while (*t != 0)
|
||||
hash = hashMultiplier * hash + (unsigned int) *t++;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static unsigned int findBestHashMultiplier (const StringArray& strings)
|
||||
{
|
||||
unsigned int v = 31;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
SortedSet<unsigned int> hashes;
|
||||
bool collision = false;
|
||||
|
||||
for (int i = strings.size(); --i >= 0;)
|
||||
{
|
||||
auto hash = calculateHash (strings[i], v);
|
||||
|
||||
if (hashes.contains (hash))
|
||||
{
|
||||
collision = true;
|
||||
break;
|
||||
}
|
||||
|
||||
hashes.add (hash);
|
||||
}
|
||||
|
||||
if (! collision)
|
||||
break;
|
||||
|
||||
v += 2;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
String makeValidIdentifier (String s, bool capitalise, bool removeColons, bool allowTemplates, bool allowAsterisks)
|
||||
{
|
||||
if (s.isEmpty())
|
||||
return "unknown";
|
||||
|
||||
if (removeColons)
|
||||
s = s.replaceCharacters (".,;:/@", "______");
|
||||
else
|
||||
s = s.replaceCharacters (".,;/@", "_____");
|
||||
|
||||
for (int i = s.length(); --i > 0;)
|
||||
if (CharacterFunctions::isLetter (s[i])
|
||||
&& CharacterFunctions::isLetter (s[i - 1])
|
||||
&& CharacterFunctions::isUpperCase (s[i])
|
||||
&& ! CharacterFunctions::isUpperCase (s[i - 1]))
|
||||
s = s.substring (0, i) + " " + s.substring (i);
|
||||
|
||||
String allowedChars ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_ 0123456789");
|
||||
if (allowTemplates)
|
||||
allowedChars += "<>";
|
||||
|
||||
if (! removeColons)
|
||||
allowedChars += ":";
|
||||
|
||||
if (allowAsterisks)
|
||||
allowedChars += "*";
|
||||
|
||||
StringArray words;
|
||||
words.addTokens (s.retainCharacters (allowedChars), false);
|
||||
words.trim();
|
||||
|
||||
auto n = words[0];
|
||||
|
||||
if (capitalise)
|
||||
n = n.toLowerCase();
|
||||
|
||||
for (int i = 1; i < words.size(); ++i)
|
||||
{
|
||||
if (capitalise && words[i].length() > 1)
|
||||
n << words[i].substring (0, 1).toUpperCase()
|
||||
<< words[i].substring (1).toLowerCase();
|
||||
else
|
||||
n << words[i];
|
||||
}
|
||||
|
||||
if (CharacterFunctions::isDigit (n[0]))
|
||||
n = "_" + n;
|
||||
|
||||
if (isReservedKeyword (n))
|
||||
n << '_';
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
String makeBinaryDataIdentifierName (const File& file)
|
||||
{
|
||||
return makeValidIdentifier (file.getFileName()
|
||||
.replaceCharacters (" .", "__")
|
||||
.retainCharacters ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_0123456789"),
|
||||
false, true, false);
|
||||
}
|
||||
|
||||
void writeDataAsCppLiteral (const MemoryBlock& mb, OutputStream& out,
|
||||
bool breakAtNewLines, bool allowStringBreaks)
|
||||
{
|
||||
const int maxCharsOnLine = 250;
|
||||
|
||||
auto data = (const unsigned char*) mb.getData();
|
||||
int charsOnLine = 0;
|
||||
|
||||
bool canUseStringLiteral = mb.getSize() < 32768; // MS compilers can't handle big string literals..
|
||||
|
||||
if (canUseStringLiteral)
|
||||
{
|
||||
unsigned int numEscaped = 0;
|
||||
|
||||
for (size_t i = 0; i < mb.getSize(); ++i)
|
||||
{
|
||||
auto num = (unsigned int) data[i];
|
||||
|
||||
if (! ((num >= 32 && num < 127) || num == '\t' || num == '\r' || num == '\n'))
|
||||
{
|
||||
if (++numEscaped > mb.getSize() / 4)
|
||||
{
|
||||
canUseStringLiteral = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! canUseStringLiteral)
|
||||
{
|
||||
out << "{ ";
|
||||
|
||||
for (size_t i = 0; i < mb.getSize(); ++i)
|
||||
{
|
||||
auto num = (int) (unsigned int) data[i];
|
||||
out << num << ',';
|
||||
|
||||
charsOnLine += 2;
|
||||
|
||||
if (num >= 10)
|
||||
{
|
||||
++charsOnLine;
|
||||
|
||||
if (num >= 100)
|
||||
++charsOnLine;
|
||||
}
|
||||
|
||||
if (charsOnLine >= maxCharsOnLine)
|
||||
{
|
||||
charsOnLine = 0;
|
||||
out << newLine;
|
||||
}
|
||||
}
|
||||
|
||||
out << "0,0 };";
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "\"";
|
||||
writeEscapeChars (out, (const char*) data, (int) mb.getSize(),
|
||||
maxCharsOnLine, breakAtNewLines, false, allowStringBreaks);
|
||||
out << "\";";
|
||||
}
|
||||
}
|
||||
|
||||
void createStringMatcher (OutputStream& out, const String& utf8PointerVariable,
|
||||
const StringArray& strings, const StringArray& codeToExecute, const int indentLevel)
|
||||
{
|
||||
jassert (strings.size() == codeToExecute.size());
|
||||
auto indent = String::repeatedString (" ", indentLevel);
|
||||
auto hashMultiplier = findBestHashMultiplier (strings);
|
||||
|
||||
out << indent << "unsigned int hash = 0;" << newLine
|
||||
<< newLine
|
||||
<< indent << "if (" << utf8PointerVariable << " != nullptr)" << newLine
|
||||
<< indent << " while (*" << utf8PointerVariable << " != 0)" << newLine
|
||||
<< indent << " hash = " << (int) hashMultiplier << " * hash + (unsigned int) *" << utf8PointerVariable << "++;" << newLine
|
||||
<< newLine
|
||||
<< indent << "switch (hash)" << newLine
|
||||
<< indent << "{" << newLine;
|
||||
|
||||
for (int i = 0; i < strings.size(); ++i)
|
||||
{
|
||||
out << indent << " case 0x" << hexString8Digits ((int) calculateHash (strings[i], hashMultiplier))
|
||||
<< ": " << codeToExecute[i] << newLine;
|
||||
}
|
||||
|
||||
out << indent << " default: break;" << newLine
|
||||
<< indent << "}" << newLine << newLine;
|
||||
}
|
||||
|
||||
String unixStylePath (const String& path) { return path.replaceCharacter ('\\', '/'); }
|
||||
String windowsStylePath (const String& path) { return path.replaceCharacter ('/', '\\'); }
|
||||
|
||||
String currentOSStylePath (const String& path)
|
||||
{
|
||||
#if JUCE_WINDOWS
|
||||
return windowsStylePath (path);
|
||||
#else
|
||||
return unixStylePath (path);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool isAbsolutePath (const String& path)
|
||||
{
|
||||
return File::isAbsolutePath (path)
|
||||
|| path.startsWithChar ('/') // (needed because File::isAbsolutePath will ignore forward-slashes on Windows)
|
||||
|| path.startsWithChar ('$')
|
||||
|| path.startsWithChar ('~')
|
||||
|| (CharacterFunctions::isLetter (path[0]) && path[1] == ':')
|
||||
|| path.startsWithIgnoreCase ("smb:");
|
||||
}
|
||||
|
||||
String getRelativePathFrom (const File& file, const File& sourceFolder)
|
||||
{
|
||||
#if ! JUCE_WINDOWS
|
||||
// On a non-windows machine, we can't know if a drive-letter path may be relative or not.
|
||||
if (CharacterFunctions::isLetter (file.getFullPathName()[0]) && file.getFullPathName()[1] == ':')
|
||||
return file.getFullPathName();
|
||||
#endif
|
||||
|
||||
return file.getRelativePathFrom (sourceFolder);
|
||||
}
|
||||
|
||||
void writeStreamToFile (const File& file, const std::function<void (MemoryOutputStream&)>& writer)
|
||||
{
|
||||
MemoryOutputStream mo;
|
||||
writer (mo);
|
||||
overwriteFileIfDifferentOrThrow (file, mo);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue