From 270063ac3114e4b8ce5bcaaa719a2f875a307854 Mon Sep 17 00:00:00 2001 From: Oli Date: Wed, 26 Mar 2025 16:09:39 +0000 Subject: [PATCH] Projucer: (MSVC) Emit message on plugin install location and config error --- .../ProjectSaving/jucer_ProjectExport_MSVC.h | 164 +++++++++++++++--- 1 file changed, 140 insertions(+), 24 deletions(-) diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h index 18ce0b809c..a1385168f4 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h @@ -77,6 +77,8 @@ public: MSVCScriptBuilder& deleteFile (const StringOrBuilder& path) { + jassert (path.value.isQuotedString()); + script << "del /s /q " << path.value; script << newLine; return *this; @@ -84,6 +86,8 @@ public: MSVCScriptBuilder& mkdir (const StringOrBuilder& path) { + jassert (path.value.isQuotedString()); + script << "mkdir " << path.value; script << newLine; return *this; @@ -175,7 +179,8 @@ public: MSVCScriptBuilder& append (const StringOrBuilder& string) { - script << string.value << newLine; + if (string.isNotEmpty()) + script << string.value << newLine; return *this; } @@ -1723,6 +1728,17 @@ public: return aaxSdk.getChildFile ("Utilities").getChildFile ("PlugIn.ico"); } + static bool shouldPerformCopyStepForPlugin (Target::Type pluginType, + const MSVCBuildConfiguration& config, + Architecture arch) + { + if (! config.isPluginBinaryCopyStepEnabled()) + return false; + + const auto binaryLocationId = getPluginTypeInfo (pluginType).second; + return binaryLocationId.isValid() && config.getBinaryPath (binaryLocationId, arch).isNotEmpty(); + } + String getExtraPostBuildSteps (const MSVCBuildConfiguration& config, Architecture arch) const { using Builder = MSVCScriptBuilder; @@ -1742,7 +1758,7 @@ public: + " " + (directory + "\\" + segments[0] + "\\").quoted(); - return config.isPluginBinaryCopyStepEnabled() ? copyStep : ""; + return shouldPerformCopyStepForPlugin (type, config, arch) ? copyStep : ""; }; if (type == AAXPlugIn) @@ -1778,7 +1794,7 @@ public: auto pkgScript = String ("copy /Y ") + scriptPath.toWindowsStyle().quoted() + " \"$(OutDir)\""; - if (config.isPluginBinaryCopyStepEnabled()) + if (shouldPerformCopyStepForPlugin (type, config, arch)) { auto copyLocation = config.getBinaryPath (Ids::unityPluginBinaryLocation, arch); @@ -1813,7 +1829,9 @@ public: + ".lv2\"\r\n"; builder.runAndCheck (writer, - config.isPluginBinaryCopyStepEnabled() ? copyStep : Builder{}.info ("Sucessfully generated LV2 manifest").build(), + shouldPerformCopyStepForPlugin (type, config, arch) + ? copyStep + : Builder{}.info ("Successfully generated LV2 manifest").build(), Builder{}.error ("Failed to generate LV2 manifest.") .exit (-1)); @@ -1923,7 +1941,7 @@ public: .build(); } - if (type == VSTPlugIn && config.isPluginBinaryCopyStepEnabled()) + if (type == VSTPlugIn && shouldPerformCopyStepForPlugin (type, config, arch)) { const String copyCommand = "copy /Y \"$(OutDir)$(TargetFileName)\" \"" + config.getBinaryPath (Ids::vstBinaryLocation, arch) @@ -1938,6 +1956,114 @@ public: return {}; } + static std::pair getPluginTypeInfo (Target::Type targetType) + { + if (targetType == AAXPlugIn) return { "AAX", Ids::aaxBinaryLocation }; + if (targetType == VSTPlugIn) return { "VST (Legacy)", Ids::vstBinaryLocation }; + if (targetType == VST3PlugIn) return { "VST3", Ids::vst3BinaryLocation }; + if (targetType == UnityPlugIn) return { "Unity", Ids::unityPluginBinaryLocation }; + if (targetType == LV2PlugIn) return { "LV2", Ids::lv2BinaryLocation }; + + return {}; + } + + static String generatePluginCopyStepPathValidatorScript (Target::Type targetType, + const MSVCBuildConfiguration& config, + Architecture arch) + { + MSVCScriptBuilder builder; + + if (config.isPluginBinaryCopyStepEnabled()) + { + const auto [projectTypeString, binaryLocationId] = getPluginTypeInfo (targetType); + + if (projectTypeString.isNotEmpty()) + { + const auto binaryPath = config.getBinaryPath (binaryLocationId, arch); + + if (binaryPath.isEmpty()) + { + String warningMessage = + "Plugin Configuration Warning: Plugin copy step is enabled but no target " + "path is specified in the Projucer."; + + warningMessage << " This can be configured via the \"" + << getArchitectureValueString (arch) << " " + << projectTypeString << " " + << "Binary Location\" option in the relevant Exporter configuration panel."; + + builder.warning (warningMessage.quoted()); + } + else + { + constexpr auto errorMessage = + "Plugin Copy Step Failure: Either the install path does not exist or you " + "do not have permission to write to the target directory. Ensure you " + "have the necessary permissions to write to the directory, or choose " + "a different install location (e.g., a folder in your user directory)."; + + MemoryOutputStream script; + + const auto validProjectName = build_tools::makeValidIdentifier (config.project.getProjectNameString(), + false, + true, + false, + false); + const auto validPluginName = build_tools::makeValidIdentifier (projectTypeString, + false, + true, + false, + false); + script << "set TOUCH_NAME=\".touch_\"" + << validProjectName << "_" + << validPluginName << "_" + << "\"%RANDOM%\"" << newLine; + + String tempPath = binaryPath; + tempPath << "\\%TOUCH_NAME%"; + + script << "(" << newLine; + script << "echo \".\" > " << tempPath.quoted() << newLine; + script << ") > nul 2>&1" << newLine; + + builder.append (script.toString()); + builder.ifelse ("exist " + tempPath.quoted(), + MSVCScriptBuilder{}.deleteFile (tempPath.quoted()), + MSVCScriptBuilder{}.error (String { errorMessage }.quoted()) + .exit (1)); + } + } + } + + return builder.build(); + } + + static String generateToolchainValidatorScript (Architecture arch) + { + MSVCScriptBuilder builder; + + if (arch == Architecture::win64) + { + const auto x86ToolchainErrorMessage = + "echo : Warning: Toolchain configuration issue!" + " You are using a 32-bit toolchain to compile a 64-bit target on a 64-bit system." + " This may cause problems with the build system." + " To resolve this, use the x64 version of MSBuild. You can invoke it directly at:" + " \"/MSBuild/Current/Bin/amd64/MSBuild.exe\"" + " Or, use the \"x64 Native Tools Command Prompt\" script."; + + builder.ifAllConditionsTrue ( + { + "\"$(PROCESSOR_ARCHITECTURE)\" == " + getVisualStudioArchitectureId (Architecture::win32).quoted(), + + // This only exists if the process is x86 but the host is x64. + "defined PROCESSOR_ARCHITEW6432" + }, MSVCScriptBuilder{}.append (x86ToolchainErrorMessage)); + } + + return builder.build(); + } + String getExtraPreBuildSteps (const MSVCBuildConfiguration& config, Architecture arch) const { const auto createBundleStructure = [&] (const StringArray& segments) @@ -1959,24 +2085,8 @@ public: MSVCScriptBuilder builder; - if (arch == Architecture::win64) - { - const auto x86ToolchainErrorMessage = - "echo : Warning: Toolchain configuration issue!" - " You are using a 32-bit toolchain to compile a 64-bit target on a 64-bit system." - " This may cause problems with the build system." - " To resolve this, use the x64 version of MSBuild. You can invoke it directly at:" - " \"/MSBuild/Current/Bin/amd64/MSBuild.exe\"" - " Or, use the \"x64 Native Tools Command Prompt\" script."; - - builder.ifAllConditionsTrue ( - { - "\"$(PROCESSOR_ARCHITECTURE)\" == " + getVisualStudioArchitectureId (Architecture::win32).quoted(), - - // This only exists if the process is x86 but the host is x64. - "defined PROCESSOR_ARCHITEW6432" - }, MSVCScriptBuilder{}.append (x86ToolchainErrorMessage)); - } + builder.append (generatePluginCopyStepPathValidatorScript (type, config, arch)); + builder.append (generateToolchainValidatorScript (arch)); if (type == LV2PlugIn) { @@ -2010,8 +2120,14 @@ public: return builder.build(); } + if (type == UnityPlugIn) + return builder.build(); + if (type == AAXPlugIn) - return createBundleStructure (getAaxBundleStructure (config, arch)); + return builder.build() + "\r\n" + createBundleStructure (getAaxBundleStructure (config, arch)); + + if (type == VSTPlugIn) + return builder.build(); if (type == VST3PlugIn) return builder.build() + "\r\n" + createBundleStructure (getVst3BundleStructure (config, arch));