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

Projucer: Generate moduleinfo.json file during VST3 build

This commit is contained in:
reuk 2023-04-24 17:44:21 +01:00
parent 0032e1ec86
commit b8f116c5c5
No known key found for this signature in database
GPG key ID: FCB43929F012EE5C
10 changed files with 310 additions and 95 deletions

View file

@ -78,7 +78,8 @@ namespace build_tools
case Type::StaticLibrary:
case Type::DynamicLibrary:
case Type::LV2PlugIn:
case Type::LV2TurtleProgram:
case Type::LV2Helper:
case Type::VST3Helper:
case Type::SharedCodeTarget:
case Type::AggregateTarget:
case Type::unspecified:
@ -109,7 +110,8 @@ namespace build_tools
case Type::StaticLibrary:
case Type::DynamicLibrary:
case Type::LV2PlugIn:
case Type::LV2TurtleProgram:
case Type::LV2Helper:
case Type::VST3Helper:
case Type::SharedCodeTarget:
case Type::AggregateTarget:
case Type::unspecified:

View file

@ -82,7 +82,8 @@ namespace build_tools
SharedCodeTarget = 20, // internal
AggregateTarget = 21,
LV2TurtleProgram = 25, // internal
LV2Helper = 25, // internal
VST3Helper = 26, // internal
unspecified = 30
};
@ -118,7 +119,8 @@ namespace build_tools
case LV2PlugIn: return "LV2 Plugin";
case SharedCodeTarget: return "Shared Code";
case AggregateTarget: return "All";
case LV2TurtleProgram: return "LV2 Manifest Helper";
case LV2Helper: return "LV2 Manifest Helper";
case VST3Helper: return "VST3 Manifest Helper";
case unspecified: break;
}
@ -141,7 +143,8 @@ namespace build_tools
if (name == "LV2 Plugin") return Type::LV2PlugIn;
if (name == "Shared Code") return Type::SharedCodeTarget;
if (name == "All") return Type::AggregateTarget;
if (name == "LV2 Manifest Helper") return Type::LV2TurtleProgram;
if (name == "LV2 Manifest Helper") return Type::LV2Helper;
if (name == "VST3 Manifest Helper") return Type::VST3Helper;
jassertfalse;
return Type::ConsoleApp;
@ -164,7 +167,8 @@ namespace build_tools
case UnityPlugIn: return pluginBundle;
case LV2PlugIn: return pluginBundle;
case SharedCodeTarget: return staticLibrary;
case LV2TurtleProgram: return executable;
case LV2Helper: return executable;
case VST3Helper: return executable;
case AggregateTarget:
case unspecified:
break;
@ -249,7 +253,8 @@ namespace build_tools
case Target::StandalonePlugIn:
case Target::UnityPlugIn:
case Target::LV2PlugIn:
case Target::LV2TurtleProgram:
case Target::LV2Helper:
case Target::VST3Helper:
case Target::SharedCodeTarget:
case Target::AggregateTarget:
return true;
@ -295,7 +300,8 @@ namespace build_tools
case Target::DynamicLibrary:
case Target::unspecified:
case Target::LV2PlugIn:
case Target::LV2TurtleProgram:
case Target::LV2Helper:
case Target::VST3Helper:
break;
}

View file

@ -369,6 +369,8 @@ void Project::initialiseAudioPluginValues()
pluginVSTNumMidiOutputsValue.referTo (projectRoot, Ids::pluginVSTNumMidiOutputs, getUndoManager(), 16);
pluginLV2URIValue.referTo (projectRoot, Ids::lv2Uri, getUndoManager(), getDefaultLV2URI());
vst3ManifestEnabledValue.referTo (projectRoot, Ids::vst3ManifestEnabled, getUndoManager(), false);
}
void Project::updateOldStyleConfigList()
@ -1262,6 +1264,8 @@ bool Project::shouldBuildTargetType (build_tools::ProjectType::Target::Type targ
return shouldBuildVST();
case Target::VST3PlugIn:
return shouldBuildVST3();
case Target::VST3Helper:
return shouldBuildVST3() && isVst3ManifestEnabled();
case Target::AAXPlugIn:
return shouldBuildAAX();
case Target::AudioUnitPlugIn:
@ -1273,7 +1277,7 @@ bool Project::shouldBuildTargetType (build_tools::ProjectType::Target::Type targ
case Target::UnityPlugIn:
return shouldBuildUnityPlugin();
case Target::LV2PlugIn:
case Target::LV2TurtleProgram:
case Target::LV2Helper:
return shouldBuildLV2();
case Target::AggregateTarget:
case Target::SharedCodeTarget:
@ -1537,6 +1541,14 @@ void Project::createAudioPluginPropertyEditors (PropertyListBuilder& props)
"If neither of these are selected, the appropriate one will be automatically added based on the \"Plugin is a synth\" option.");
}
props.add (new ChoicePropertyComponent (vst3ManifestEnabledValue, "Plugin VST3 moduleinfo.json Enabled"),
"Check this box if you want a moduleinfo.json file to be generated as part of the VST3 build. "
"This may improve startup/scanning time for hosts that understand the contents of this file. "
"This setting is disabled by default because the moduleinfo.json path can cause problems during code signing on macOS. "
"Bundles containing a moduleinfo.json may be rejected by code signing verification at any point in the future without notice per https://developer.apple.com/library/archive/technotes/tn2206."
"If you enable this setting, be aware that the code signature for the moduleinfo.json will be stored in its extended file attributes. "
"Therefore, you will need to ensure that these attributes are not changed or removed when distributing the VST3.");
props.add (new MultiChoicePropertyComponent (pluginAAXCategoryValue, "Plugin AAX Category", getAllAAXCategoryStrings(), getAllAAXCategoryVars()),
"AAX category.");
@ -1570,7 +1582,6 @@ void Project::createAudioPluginPropertyEditors (PropertyListBuilder& props)
props.add (new TextPropertyComponent (pluginARACompatibleArchiveIDsValue, "Plugin ARA Compatible Document Archive IDs", 1024, true),
"List of compatible ARA Document Archive IDs - one per line");
}
}

View file

@ -159,6 +159,7 @@ public:
static String getJuceSourceHFilename() { return "JuceHeader.h"; }
static String getJuceLV2DefinesFilename() { return "JuceLV2Defines.h"; }
static String getLV2FileWriterName() { return "juce_lv2_helper"; }
static String getVST3FileWriterName() { return "juce_vst3_helper"; }
//==============================================================================
template <class FileType>
@ -291,6 +292,8 @@ public:
bool isPluginAAXBypassDisabled() const { return checkMultiChoiceVar (pluginCharacteristicsValue, Ids::pluginAAXDisableBypass); }
bool isPluginAAXMultiMonoDisabled() const { return checkMultiChoiceVar (pluginCharacteristicsValue, Ids::pluginAAXDisableMultiMono); }
bool isVst3ManifestEnabled() const { return vst3ManifestEnabledValue.get(); }
void disableStandaloneForARAPlugIn();
static StringArray getAllAUMainTypeStrings() noexcept;
@ -583,7 +586,7 @@ private:
pluginCodeValue, pluginChannelConfigsValue, pluginCharacteristicsValue, pluginAUExportPrefixValue, pluginAAXIdentifierValue,
pluginAUMainTypeValue, pluginAUSandboxSafeValue, pluginVSTCategoryValue, pluginVST3CategoryValue, pluginAAXCategoryValue,
pluginEnableARA, pluginARAAnalyzableContentValue, pluginARAFactoryIDValue, pluginARAArchiveIDValue, pluginARACompatibleArchiveIDsValue, pluginARATransformFlagsValue,
pluginVSTNumMidiInputsValue, pluginVSTNumMidiOutputsValue, pluginLV2URIValue;
pluginVSTNumMidiInputsValue, pluginVSTNumMidiOutputsValue, pluginLV2URIValue, vst3ManifestEnabledValue;
//==============================================================================
std::unique_ptr<EnabledModulesList> enabledModulesList;

View file

@ -122,8 +122,9 @@ public:
case Target::AAXPlugIn:
case Target::UnityPlugIn:
case Target::LV2PlugIn:
case Target::LV2TurtleProgram:
case Target::LV2Helper:
case Target::VST3PlugIn:
case Target::VST3Helper:
case Target::AudioUnitPlugIn:
case Target::AudioUnitv3PlugIn:
case Target::unspecified:

View file

@ -228,9 +228,12 @@ public:
{
using Target = build_tools::ProjectType::Target::Type;
if (type == Target::LV2TurtleProgram)
if (type == Target::LV2Helper)
return Project::getLV2FileWriterName() + suffix;
if (type == Target::VST3Helper)
return Project::getVST3FileWriterName() + suffix;
const auto forceUnityPrefix = type == Target::UnityPlugIn;
auto target = File::createLegalFileName (getTargetBinaryNameString (forceUnityPrefix).trim());
@ -655,12 +658,12 @@ public:
}
auto externalLibraries = getExternalLibraries (config, getOwner().getExternalLibrariesStringArray());
auto additionalDependencies = type != SharedCodeTarget && type != LV2TurtleProgram && ! externalLibraries.isEmpty()
auto additionalDependencies = type != SharedCodeTarget && type != LV2Helper && type != VST3Helper && ! externalLibraries.isEmpty()
? externalLibraries.joinIntoString (";") + ";%(AdditionalDependencies)"
: String();
auto librarySearchPaths = config.getLibrarySearchPaths();
auto additionalLibraryDirs = type != SharedCodeTarget && type != LV2TurtleProgram && librarySearchPaths.size() > 0
auto additionalLibraryDirs = type != SharedCodeTarget && type != LV2Helper && type != VST3Helper && librarySearchPaths.size() > 0
? getOwner().replacePreprocessorTokens (config, librarySearchPaths.joinIntoString (";")) + ";%(AdditionalLibraryDirectories)"
: String();
@ -672,7 +675,7 @@ public:
: "%(IgnoreSpecificDefaultLibraries)");
link->createNewChildElement ("GenerateDebugInformation")->addTextElement ((isDebug || config.shouldGenerateDebugSymbols()) ? "true" : "false");
link->createNewChildElement ("ProgramDatabaseFile")->addTextElement (pdbFilename);
link->createNewChildElement ("SubSystem")->addTextElement (type == ConsoleApp || type == LV2TurtleProgram ? "Console" : "Windows");
link->createNewChildElement ("SubSystem")->addTextElement (type == ConsoleApp || type == LV2Helper || type == VST3Helper ? "Console" : "Windows");
if (config.getArchitectureString() == "Win32")
link->createNewChildElement ("TargetMachine")->addTextElement ("MachineX86");
@ -718,7 +721,7 @@ public:
bsc->createNewChildElement ("OutputFile")->addTextElement (getOwner().getIntDirFile (config, config.getOutputFilename (".bsc", true, type)));
}
if (type != SharedCodeTarget && type != LV2TurtleProgram)
if (type != SharedCodeTarget && type != LV2Helper && type != VST3Helper)
{
auto* lib = group->createNewChildElement ("Lib");
@ -729,14 +732,27 @@ public:
lib->createNewChildElement ("AdditionalLibraryDirectories")->addTextElement (additionalLibraryDirs);
}
auto manifestFile = getOwner().getManifestPath();
if (manifestFile.getRoot() != build_tools::RelativePath::unknown)
if (auto manifestFile = getOwner().getManifestPath(); manifestFile.getRoot() != build_tools::RelativePath::unknown || type == VST3Helper)
{
auto* bsc = group->createNewChildElement ("Manifest");
bsc->createNewChildElement ("AdditionalManifestFiles")
->addTextElement (manifestFile.rebased (getOwner().getProject().getFile().getParentDirectory(),
getOwner().getTargetFolder(),
build_tools::RelativePath::buildTargetFolder).toWindowsStyle());
auto* additional = bsc->createNewChildElement ("AdditionalManifestFiles");
if (manifestFile.getRoot() != build_tools::RelativePath::unknown)
{
additional->addTextElement (manifestFile.rebased (getOwner().getProject().getFile().getParentDirectory(),
getOwner().getTargetFolder(),
build_tools::RelativePath::buildTargetFolder).toWindowsStyle());
}
if (type == VST3Helper)
{
const auto manifest = getOwner().getModuleFolderRelativeToProject ("juce_audio_processors").getChildFile ("format_types")
.getChildFile ("VST3_SDK")
.getChildFile ("helper.manifest");
additional->addTextElement (manifest.rebased (getOwner().getProject().getFile().getParentDirectory(),
getOwner().getTargetFolder(),
build_tools::RelativePath::buildTargetFolder).toWindowsStyle());
}
}
if (getTargetFileType() == staticLibrary && config.getArchitectureString() == "Win32")
@ -774,12 +790,21 @@ public:
addFilesToCompile (group, *cppFiles, *headerFiles, *otherFilesGroup);
}
if (type == LV2TurtleProgram)
if (type == LV2Helper)
{
const auto location = owner.rebaseFromProjectFolderToBuildTarget (owner.getLV2TurtleDumpProgramSource())
const auto location = owner.rebaseFromProjectFolderToBuildTarget (owner.getLV2HelperProgramSource())
.toWindowsStyle();
cppFiles->createNewChildElement ("ClCompile")->setAttribute ("Include", location);
}
else if (type == VST3Helper)
{
for (const auto& source : owner.getVST3HelperProgramSources (owner))
{
const auto location = owner.rebaseFromProjectFolderToBuildTarget (source)
.toWindowsStyle();
cppFiles->createNewChildElement ("ClCompile")->setAttribute ("Include", location);
}
}
}
if (getOwner().iconFile.existsAsFile())
@ -1274,7 +1299,7 @@ public:
const auto* writerTarget = [&]() -> MSVCTargetBase*
{
for (auto* target : owner.targets)
if (target->type == LV2TurtleProgram)
if (target->type == LV2Helper)
return target;
return nullptr;
@ -1298,10 +1323,42 @@ public:
if (type == VST3PlugIn)
{
const auto segments = getVst3BundleStructure (config);
const auto manifestScript = [&]() -> String
{
const auto* writerTarget = [&]() -> MSVCTargetBase*
{
for (auto* target : owner.targets)
if (target->type == VST3Helper)
return target;
return nullptr;
}();
if (writerTarget == nullptr)
return "";
const auto writer = writerTarget->getConfigTargetPath (config)
+ "\\"
+ writerTarget->getBinaryNameWithSuffix (config);
// moduleinfotool doesn't handle Windows-style path separators properly when computing the bundle name
const auto normalisedBundlePath = getOwner().getOutDirFile (config, segments[0]).replace ("\\", "/");
return "\r\n"
+ writer.quoted()
+ " -create -version "
+ getOwner().project.getVersionString().quoted()
+ " -path "
+ normalisedBundlePath.quoted()
+ " -output "
+ (getOwner().getOutDirFile (config, segments[0]) + "\\Contents\\moduleinfo.json").quoted();
}();
const auto pkgScript = copyBuildOutputIntoBundle (segments);
const auto copyScript = copyBundleToInstallDirectory (segments, config.getVST3BinaryLocationString());
return pkgScript + copyScript;
return pkgScript + manifestScript + copyScript;
}
if (type == VSTPlugIn && config.isPluginBinaryCopyStepEnabled())
@ -1365,7 +1422,7 @@ public:
{
auto librarySearchPaths = config.getLibrarySearchPaths();
if (type != SharedCodeTarget && type != LV2TurtleProgram)
if (type != SharedCodeTarget && type != LV2Helper && type != VST3Helper)
if (auto* shared = getOwner().getSharedCodeTarget())
librarySearchPaths.add (shared->getConfigTargetPath (config));
@ -1388,7 +1445,7 @@ public:
result.addArray (msBuildEscape (getOwner().getModuleLibs()));
if (type != SharedCodeTarget && type != LV2TurtleProgram)
if (type != SharedCodeTarget && type != LV2Helper && type != VST3Helper)
if (auto* shared = getOwner().getSharedCodeTarget())
result.add (msBuildEscape (shared->getBinaryNameWithSuffix (config)));
@ -1487,10 +1544,11 @@ public:
case Target::AggregateTarget:
case Target::VSTPlugIn:
case Target::VST3PlugIn:
case Target::VST3Helper:
case Target::AAXPlugIn:
case Target::UnityPlugIn:
case Target::LV2PlugIn:
case Target::LV2TurtleProgram:
case Target::LV2Helper:
case Target::DynamicLibrary:
return true;
case Target::AudioUnitPlugIn:
@ -1690,7 +1748,8 @@ protected:
void writeProjectDependencies (OutputStream& out) const
{
const auto sharedCodeGuid = getTargetGuid (MSVCTargetBase::SharedCodeTarget);
const auto turtleGuid = getTargetGuid (MSVCTargetBase::LV2TurtleProgram);
const auto lv2HelperGuid = getTargetGuid (MSVCTargetBase::LV2Helper);
const auto vst3HelperGuid = getTargetGuid (MSVCTargetBase::VST3Helper);
for (int addingOtherTargets = 0; addingOtherTargets < (sharedCodeGuid.isNotEmpty() ? 2 : 1); ++addingOtherTargets)
{
@ -1706,13 +1765,17 @@ protected:
if (sharedCodeGuid.isNotEmpty()
&& target->type != MSVCTargetBase::SharedCodeTarget
&& target->type != MSVCTargetBase::LV2TurtleProgram)
&& target->type != MSVCTargetBase::LV2Helper
&& target->type != MSVCTargetBase::VST3Helper)
{
out << "\tProjectSection(ProjectDependencies) = postProject" << newLine
<< "\t\t" << sharedCodeGuid << " = " << sharedCodeGuid << newLine;
if (target->type == MSVCTargetBase::LV2PlugIn && turtleGuid.isNotEmpty())
out << "\t\t" << turtleGuid << " = " << turtleGuid << newLine;
if (target->type == MSVCTargetBase::LV2PlugIn && lv2HelperGuid.isNotEmpty())
out << "\t\t" << lv2HelperGuid << " = " << lv2HelperGuid << newLine;
if (target->type == MSVCTargetBase::VST3PlugIn && vst3HelperGuid.isNotEmpty() && project.isVst3ManifestEnabled())
out << "\t\t" << vst3HelperGuid << " = " << vst3HelperGuid << newLine;
out << "\tEndProjectSection" << newLine;
}

View file

@ -221,10 +221,14 @@ public:
s.add ("JUCE_LV2DIR := " + escapeQuotesAndSpaces (targetName) + ".lv2");
targetName = "$(JUCE_LV2DIR)/" + targetName + ".so";
}
else if (type == LV2TurtleProgram)
else if (type == LV2Helper)
{
targetName = Project::getLV2FileWriterName();
}
else if (type == VST3Helper)
{
targetName = Project::getVST3FileWriterName();
}
s.add ("JUCE_TARGET_" + getTargetVarName() + String (" := ") + escapeQuotesAndSpaces (targetName));
@ -331,9 +335,12 @@ public:
String getPhonyName() const
{
if (type == LV2TurtleProgram)
if (type == LV2Helper)
return "LV2_MANIFEST_HELPER";
if (type == VST3Helper)
return "VST3_MANIFEST_HELPER";
return String (getName()).upToFirstOccurrenceOf (" ", false, false);
}
@ -349,6 +356,8 @@ public:
if (type == LV2PlugIn)
out << " $(JUCE_OUTDIR)/$(JUCE_TARGET_LV2_MANIFEST_HELPER)";
else if (type == VST3PlugIn && owner.project.isVst3ManifestEnabled())
out << " $(JUCE_OUTDIR)/$(JUCE_TARGET_VST3_MANIFEST_HELPER)";
out << newLine;
@ -399,6 +408,15 @@ public:
if (type == VST3PlugIn)
{
if (owner.project.isVst3ManifestEnabled())
{
out << "\t$(V_AT) $(JUCE_OUTDIR)/$(JUCE_TARGET_VST3_MANIFEST_HELPER) "
"-create "
"-version " << owner.project.getVersionString().quoted() << " "
"-path \"$(JUCE_OUTDIR)/$(JUCE_VST3DIR)\" "
"-output \"$(JUCE_OUTDIR)/$(JUCE_VST3DIR)/Contents/moduleinfo.json\" " << newLine;
}
out << "\t-$(V_AT)[ ! \"$(JUCE_VST3DESTDIR)\" ] || (mkdir -p $(JUCE_VST3DESTDIR) && cp -R $(JUCE_COPYCMD_VST3))" << newLine;
}
else if (type == VSTPlugIn)
@ -486,11 +504,12 @@ public:
case Target::AggregateTarget:
case Target::VSTPlugIn:
case Target::VST3PlugIn:
case Target::VST3Helper:
case Target::StandalonePlugIn:
case Target::DynamicLibrary:
case Target::UnityPlugIn:
case Target::LV2PlugIn:
case Target::LV2TurtleProgram:
case Target::LV2Helper:
return true;
case Target::AAXPlugIn:
case Target::AudioUnitPlugIn:
@ -1172,13 +1191,23 @@ private:
targetFiles.emplace_back (linuxSubprocessHelperProperties.getLinuxSubprocessHelperBinaryDataSource(), "");
}
if (targetType == MakefileTarget::LV2TurtleProgram)
if (targetType == MakefileTarget::LV2Helper)
{
targetFiles.emplace_back (getLV2TurtleDumpProgramSource().rebased (projectFolder,
getTargetFolder(),
build_tools::RelativePath::buildTargetFolder),
targetFiles.emplace_back (getLV2HelperProgramSource().rebased (projectFolder,
getTargetFolder(),
build_tools::RelativePath::buildTargetFolder),
String{});
}
else if (targetType == MakefileTarget::VST3Helper)
{
for (const auto& source : getVST3HelperProgramSources (*this))
{
targetFiles.emplace_back (source.rebased (projectFolder,
getTargetFolder(),
build_tools::RelativePath::buildTargetFolder),
String{});
}
}
return targetFiles;
};

View file

@ -298,10 +298,10 @@ public:
case Target::AudioUnitPlugIn:
case Target::UnityPlugIn:
case Target::LV2PlugIn:
case Target::LV2TurtleProgram:
case Target::LV2Helper:
case Target::VST3Helper:
return ! iOS;
case Target::unspecified:
default:
break;
}
@ -1068,11 +1068,16 @@ public:
break;
case ConsoleApp:
case LV2TurtleProgram:
case LV2Helper:
case VST3Helper:
xcodeFileType = "compiled.mach-o.executable";
xcodeBundleExtension = String();
xcodeProductType = "com.apple.product-type.tool";
xcodeCopyToProductInstallPathAfterBuild = false;
if (type == VST3Helper)
xcodeFrameworks.add ("Cocoa");
break;
case StaticLibrary:
@ -1216,9 +1221,12 @@ public:
if (xcodeFileType == "archive.ar")
return getStaticLibbedFilename (binaryName);
if (type == LV2TurtleProgram)
if (type == LV2Helper)
return Project::getLV2FileWriterName();
if (type == VST3Helper)
return Project::getVST3FileWriterName();
return binaryName + xcodeBundleExtension;
}();
@ -1257,37 +1265,43 @@ public:
if (! owner.project.isAudioPluginProject())
return;
if (type == XcodeTarget::StandalonePlugIn) // depends on AUv3 and shared code
{
if (auto* auv3Target = owner.getTargetOfType (XcodeTarget::AudioUnitv3PlugIn))
dependencyIDs.add (auv3Target->addDependencyFor (*this));
if (auto* sharedCodeTarget = owner.getTargetOfType (XcodeTarget::SharedCodeTarget))
dependencyIDs.add (sharedCodeTarget->addDependencyFor (*this));
}
else if (type == XcodeTarget::AggregateTarget) // depends on all other targets
if (type == XcodeTarget::AggregateTarget) // depends on all other targets
{
for (auto* target : owner.targets)
if (target->type != XcodeTarget::AggregateTarget)
dependencyIDs.add (target->addDependencyFor (*this));
}
else if (type == XcodeTarget::LV2PlugIn)
{
if (auto* helperTarget = owner.getTargetOfType (XcodeTarget::LV2TurtleProgram))
dependencyIDs.add (helperTarget->addDependencyFor (*this));
if (auto* sharedCodeTarget = owner.getTargetOfType (XcodeTarget::SharedCodeTarget))
dependencyIDs.add (sharedCodeTarget->addDependencyFor (*this));
return;
}
else if (type == XcodeTarget::LV2TurtleProgram)
if (type == XcodeTarget::LV2Helper || type == XcodeTarget::VST3Helper)
{
// No thanks
return;
}
else if (type != XcodeTarget::SharedCodeTarget) // shared code doesn't depend on anything; all other targets depend only on the shared code
if (type != XcodeTarget::SharedCodeTarget) // everything else depends on the sharedCodeTarget
{
if (auto* sharedCodeTarget = owner.getTargetOfType (XcodeTarget::SharedCodeTarget))
dependencyIDs.add (sharedCodeTarget->addDependencyFor (*this));
}
if (type == LV2PlugIn)
{
if (auto* helperTarget = owner.getTargetOfType (LV2Helper))
dependencyIDs.add (helperTarget->addDependencyFor (*this));
}
if (type == VST3PlugIn && owner.project.isVst3ManifestEnabled())
{
if (auto* helperTarget = owner.getTargetOfType (VST3Helper))
dependencyIDs.add (helperTarget->addDependencyFor (*this));
}
if (type == XcodeTarget::StandalonePlugIn)
{
if (auto* auv3Target = owner.getTargetOfType (XcodeTarget::AudioUnitv3PlugIn))
dependencyIDs.add (auv3Target->addDependencyFor (*this));
}
}
//==============================================================================
@ -1479,9 +1493,12 @@ public:
const auto productName = [&]
{
if (type == LV2TurtleProgram)
if (type == LV2Helper)
return Project::getLV2FileWriterName().quoted();
if (type == VST3Helper)
return Project::getVST3FileWriterName().quoted();
return owner.replacePreprocessorTokens (config, config.getTargetBinaryNameString (type == UnityPlugIn)).quoted();
}();
@ -1815,7 +1832,8 @@ public:
case LV2PlugIn: return config.isPluginBinaryCopyStepEnabled() ? config.getLV2PluginBinaryLocationString() : String();
case SharedCodeTarget: return owner.isiOS() ? "@executable_path/Frameworks" : "@executable_path/../Frameworks";
case StaticLibrary:
case LV2TurtleProgram:
case LV2Helper:
case VST3Helper:
case DynamicLibrary:
case AudioUnitv3PlugIn:
case StandalonePlugIn:
@ -1831,7 +1849,7 @@ public:
if (getTargetFileType() == pluginBundle)
flags.add (owner.isiOS() ? "-bitcode_bundle" : "-bundle");
if (type != Target::SharedCodeTarget && type != Target::LV2TurtleProgram)
if (type != Target::SharedCodeTarget && type != Target::LV2Helper && type != Target::VST3Helper)
{
if (owner.project.isAudioPluginProject())
{
@ -2104,10 +2122,10 @@ private:
target->addMainBuildProduct();
if (target->type == XcodeTarget::LV2TurtleProgram
if (target->type == XcodeTarget::LV2Helper
&& project.getEnabledModules().isModuleEnabled ("juce_audio_plugin_client"))
{
const auto path = rebaseFromProjectFolderToBuildTarget (getLV2TurtleDumpProgramSource());
const auto path = rebaseFromProjectFolderToBuildTarget (getLV2HelperProgramSource ());
addFile (FileOptions().withRelativePath ({ expandPath (path.toUnixStyle()), path.getRoot() })
.withSkipPCHEnabled (true)
.withCompilationEnabled (true)
@ -2116,6 +2134,21 @@ private:
.withXcodeTarget (target));
}
if (target->type == XcodeTarget::VST3Helper
&& project.getEnabledModules().isModuleEnabled ("juce_audio_processors"))
{
for (const auto& source : getVST3HelperProgramSources (*this))
{
const auto path = rebaseFromProjectFolderToBuildTarget (source);
addFile (FileOptions().withRelativePath ({ expandPath (path.toUnixStyle()), path.getRoot() })
.withSkipPCHEnabled (true)
.withCompilationEnabled (true)
.withInhibitWarningsEnabled (true)
.withCompilerFlags ("-std=c++17 -fobjc-arc")
.withXcodeTarget (target));
}
}
auto targetName = String (target->getName());
auto fileID = createID (targetName + "__targetbuildref");
auto fileRefID = createID ("__productFileID" + targetName);
@ -2266,7 +2299,8 @@ private:
if (! projectType.isStaticLibrary()
&& target->type != XcodeTarget::SharedCodeTarget
&& target->type != XcodeTarget::LV2TurtleProgram
&& target->type != XcodeTarget::LV2Helper
&& target->type != XcodeTarget::VST3Helper
&& ! skipAUv3)
target->addBuildPhase ("PBXResourcesBuildPhase", resourceIDs);
@ -2286,42 +2320,68 @@ private:
if (! projectType.isStaticLibrary()
&& target->type != XcodeTarget::SharedCodeTarget
&& target->type != XcodeTarget::LV2TurtleProgram)
&& target->type != XcodeTarget::LV2Helper)
{
target->addBuildPhase ("PBXFrameworksBuildPhase", target->frameworkIDs);
}
}
if (target->type == XcodeTarget::LV2PlugIn)
// When building LV2 and VST3 plugins on Arm macs, we need to load and run the plugin
// bundle during a post-build step in order to generate the plugin's supporting files.
// Arm macs will only load shared libraries if they are signed, but Xcode runs its
// signing step after any post-build scripts. As a workaround, we check whether the
// plugin is signed and generate an adhoc certificate if necessary, before running
// the manifest-generator.
if (target->type == XcodeTarget::VST3PlugIn || target->type == XcodeTarget::LV2PlugIn)
{
// When building LV2 plugins on Arm macs, we need to load and run the plugin bundle
// during a post-build step in order to generate the plugin's supporting files. Arm
// macs will only load shared libraries if they are signed, but Xcode runs its
// signing step after any post-build scripts. As a workaround, we check whether the
// plugin is signed and generate an adhoc certificate if necessary, before running
// the manifest-generator.
auto script = "set -e\n"
"xcrun codesign --verify \"$CONFIGURATION_BUILD_DIR/$PRODUCT_NAME\" "
"|| xcrun codesign -s - \"$CONFIGURATION_BUILD_DIR/$PRODUCT_NAME\"\n"
"\"$CONFIGURATION_BUILD_DIR/../"
+ Project::getLV2FileWriterName()
+ "\" \"$CONFIGURATION_BUILD_DIR/$PRODUCT_NAME\"\n";
String script = "set -e\n";
for (ConstConfigIterator config (*this); config.next();)
// Delete manifest if it's left over from an old build
if (target->type == XcodeTarget::VST3PlugIn)
script << "rm -f \"$CONFIGURATION_BUILD_DIR/$FULL_PRODUCT_NAME/Contents/moduleinfo.json\"\n";
// Sign the bundle so that it can be loaded by the manifest generator tools
script << "xcrun codesign --verify \"$CONFIGURATION_BUILD_DIR/$FULL_PRODUCT_NAME\" "
"|| xcrun codesign -f -s - \"$CONFIGURATION_BUILD_DIR/$FULL_PRODUCT_NAME\"\n";
if (target->type == XcodeTarget::LV2PlugIn)
{
auto& xcodeConfig = dynamic_cast<const XcodeBuildConfiguration&> (*config);
const auto installPath = target->getInstallPathForConfiguration (xcodeConfig);
// Note: LV2 has a non-standard config build dir
script << "\"$CONFIGURATION_BUILD_DIR/../"
+ Project::getLV2FileWriterName()
+ "\" \"$CONFIGURATION_BUILD_DIR/$FULL_PRODUCT_NAME\"\n";
if (installPath.isNotEmpty())
for (ConstConfigIterator config (*this); config.next();)
{
const auto destination = installPath.replace ("$(HOME)", "$HOME");
auto& xcodeConfig = dynamic_cast<const XcodeBuildConfiguration&> (*config);
const auto installPath = target->getInstallPathForConfiguration (xcodeConfig);
script << "if [ \"$CONFIGURATION\" = \"" << config->getName() << "\" ]; then\n"
"mkdir -p \"" << destination << "\"\n"
"/bin/ln -sfh \"$CONFIGURATION_BUILD_DIR\" \"" << destination << "\"\n"
"fi\n";
if (installPath.isNotEmpty())
{
const auto destination = installPath.replace ("$(HOME)", "$HOME");
script << R"(if [ "$CONFIGURATION" = ")" << config->getName() << "\" ]; then\n"
"mkdir -p \"" << destination << "\"\n"
"/bin/ln -sfh \"$CONFIGURATION_BUILD_DIR/$FULL_PRODUCT_NAME\" \"" << destination << "\"\n"
"fi\n";
}
}
}
else if (target->type == XcodeTarget::VST3PlugIn && project.isVst3ManifestEnabled())
{
// Generate the manifest
script << "\"$CONFIGURATION_BUILD_DIR/" << Project::getVST3FileWriterName() << "\" "
"-create "
"-version " << project.getVersionString().quoted() << " "
"-path \"$CONFIGURATION_BUILD_DIR/$FULL_PRODUCT_NAME\" "
"-output \"$CONFIGURATION_BUILD_DIR/$FULL_PRODUCT_NAME/Contents/moduleinfo.json\"\n";
// Sign the manifest (a prerequisite of signing the containing bundle)
script << "xcrun codesign -f -s - \"$CONFIGURATION_BUILD_DIR/$FULL_PRODUCT_NAME/Contents/moduleinfo.json\"\n";
// Sign the full bundle
script << "xcrun codesign -f -s - \"$CONFIGURATION_BUILD_DIR/$FULL_PRODUCT_NAME\"\n";
}
target->addShellScriptBuildPhase ("Generate manifest", script);
target->addShellScriptBuildPhase ("Update manifest", script);
}
target->addShellScriptBuildPhase ("Post-build script", getPostBuildScript());

View file

@ -216,13 +216,52 @@ public:
void createPropertyEditors (PropertyListBuilder&);
void addSettingsForProjectType (const build_tools::ProjectType&);
build_tools::RelativePath getLV2TurtleDumpProgramSource() const
build_tools::RelativePath getLV2HelperProgramSource() const
{
return getModuleFolderRelativeToProject ("juce_audio_plugin_client")
.getChildFile ("LV2")
.getChildFile ("juce_LV2TurtleDumpProgram.cpp");
}
std::vector<build_tools::RelativePath> getVST3HelperProgramSources (const ProjectExporter& exporter) const
{
const auto base = getModuleFolderRelativeToProject ("juce_audio_processors").getChildFile ("format_types")
.getChildFile ("VST3_SDK");
const auto vst = base.getChildFile ("public.sdk")
.getChildFile ("source")
.getChildFile ("vst");
const auto hosting = vst.getChildFile ("hosting");
std::vector<build_tools::RelativePath> result
{
base.getChildFile ("public.sdk")
.getChildFile ("samples")
.getChildFile ("vst-utilities")
.getChildFile ("moduleinfotool")
.getChildFile ("source")
.getChildFile ("main.cpp"),
base.getChildFile ("pluginterfaces")
.getChildFile ("base")
.getChildFile ("coreiids.cpp"),
hosting.getChildFile ("module.cpp"),
vst.getChildFile ("moduleinfo")
.getChildFile ("moduleinfocreator.cpp"),
vst.getChildFile ("moduleinfo")
.getChildFile ("moduleinfoparser.cpp"),
vst.getChildFile ("utility")
.getChildFile ("stringconvert.cpp"),
};
if (exporter.isOSX())
result.push_back (hosting.getChildFile ("module_mac.mm"));
else if (exporter.isLinux())
result.push_back (hosting.getChildFile ("module_linux.cpp"));
else if (exporter.isWindows())
result.push_back (hosting.getChildFile ("module_win32.cpp"));
return result;
}
//==============================================================================
void copyMainGroupFromProject();
Array<Project::Item>& getAllGroups() noexcept { jassert (itemGroups.size() > 0); return itemGroups; }

View file

@ -391,6 +391,7 @@ namespace Ids
DECLARE_ID (lv2Uri);
DECLARE_ID (lv2UriUi);
DECLARE_ID (lv2BinaryLocation);
DECLARE_ID (vst3ManifestEnabled);
DECLARE_ID (osxSDK);
DECLARE_ID (osxCompatibility);