In Juce 4.2, I see that by default audio plugin projects no longer build polymorphic plugins where one binary would work as multiple plugin formats.
Is this gone for good? Or can it be somehow reenabled? I did use that so far, although I don’t totally need it and it does seem a bit hacky. Anyway I would very much like to know if this is a deprecated feature we all should move away from.
Yes, on Xcode the polymorphic build is gone. From now on, all the different plugin types are different targets in the generated Xcode project, and will compile to different binaries. As a bonus, Xcode will automatically put all those binaries into their respective default installation places: VST into ~/Library/Audio/Plug-Ins/VST, AudioUnit into ~/Library/Audio/Plug-Ins/Components, etc. and also automatically clean them from there if you clean in Xcode.
On Xcode, unfortunately there is no way to go back to the polymorphic thing. We had to do it because we added support for AudioUnit v3 plug-ins in JUCE 4.2, and that didn’t fit into the old polymorphic way at all since it requires multiple targets (an app and an appExtension).
No, unfortunately you cannot build them polymorphically on Mac anymore. It would have been too complicated to support both the old polymorphic world and AUv3, as we had to rewrite a lot of the Xcode exporter for AUv3 to support multiple targets per project.
Yes, it is still possible on other platforms as of now. But we plan to soon change that as well to have a similar and consistent logic everywhere. So e.g. in Visual Studio you’d get different vcxproj projects for every plugin format and then everything will be in one solution, similar to the Xcode stuff. I don’t know exactly when we get around to do this though. We unfortunately didn’t make it in time for 4.2, so you have the new logic only on Xcode for now.
OMG, this makes things complicated for me now, but anyway, introducing the polymorphic plugin build was a huge mistake from the past (unnecessary dependencies)
The problem is that some fixes in 4.1. doesn’t have to been fixed now and every time new juce versions break compatibility there is no way back.
It would be nice have something like a stable-branch were you back-port all fixes for 4.0
Is this true also if I don’t use Pro/Introjucer at all? In fact, I don’t use that in any project so it doesn’t make a difference to me if the exporter generates separate targets or not.
My question is if 4.2 introduces some breaking changes in the code that don’t allow for polymorphic plug-ins (without AUv3) to be built.
If that is so, well, then I second the idea of @chkn that a stable branch of previous versions should be kept for some time, where fixes to existing bugs are backported for maintainance.
Having to update beyond commits that introduce breaking changes just to fix existing bugs sounds like a contradiction (not to mention how much of a PITA it is)
The polymorphic build was a very nice feature. It made build times faster, installers smaller (faster downloads), and more benefits like less stuff to maintain wrt crash symbolication etc. With 6 formats and 32/64 bit, OS X & Windows and maybe more os’s that’s quite an exponential explosion…
It would be unfortunate to lose it. I understand that AU3 poses difficulties but maybe at least all other formats could be polymorphic together?
Yeah, well, having AUv3 and also all other formats “polymorphic together” would have resulted in a quite nasty unmaintainable spaghetti code in the Projucer, so we decided to ditch the polymorphic stuff.
However, we made sure that build times don’t increase significantly: there is a target “Shared Code” which actually contains 95% of the code and is compiled only once, and then this is linked to the thin layer of plugin-format-specific code that is per target. So you should not experience worse build times.
Also, the new target stuff gives us the opportunity to add more cool Projucer features in the future. Stay tuned for that
FWIW, many users, especially beginners, found the polymorphic thing confusing, and we felt the separate targets are much clearer.
Looking at the build results, am I right to assume that [PluginName].framework is exactly the same for all plugin formats? So if that would be installed to Library/Frameworks or ~/Library/Frameworks, couldn’t all formats just use the same file? That would save quite some space in both installers and installations.
I also see that my plugins got a lot larger now, maybe because stripping dead code doesn’t work so well with a framework? I see about 1/3 larger binaries. If I now just built a regular installer instead of the renaming installer I used with polymorphic binaries before, my installer would be about 6x as large as before … hmpf.
What is the reason you went for a framework and not a statically linked library for the shared code?
Let me clarify: the framework is inside the plug-in bundle so your plug-ins will remain monolithic as viewed by the user (i.e. you can simply copy the plug-in file to another computer). The framework is in deed the same for all plug-in formats, so a copy of the framework is inside each plug-in bundle. Installers and zip recognises this so the download size of your plug-ins will remain roughly the same (this also goes for compilation times as Timur has mentioned). Obviously, you can choose to also put the framework somewhere else - but I wouldn’t recommend this.
There are some nice (albeit small) side-effects of this new system
There is no complicated post build script anymore. This means that XCode automatically copies the plug-ins into the right places when building. If you hit clean, Xcode will even remove the plug-in from the plug-in folder (I don’t know how many times a keep deleting plug-ins from my plug-in folder in the past)
There is now a new static function PlugInHostType::getPlugInLoadedAs() which returns the wrapper-type of the main AudioProcessor of your plug-in. This means you can check - from anywhere in your code - if, for example, your plug-in is running as a standalone app and then for example, enable buttons for in-app purchases etc. Such a function was difficult to implement before in the polymorphic system
I’d like to add my 2 cents here. I love the monolithic build, because I already have plenty of targets, especially on Windows, where debug, release, Win32, etc. are separate builds. Multiplying all of that by 4 for separate VST, VST3, AAX and AU builds doesn’t seem appealing, even if that’s just on the Mac.
But I’m wondering if there is a semi-elegant solution we can all agree on. I don’t think I will ever use ProJucer, except possiblely when creating new projects from scratch. So I don’t need ProJucer to support this and I suspect many others are in the same boat. As long as there is a way to turn on monolithic builds (With a #define or whatever) then I’d be very happy with that. And then the ProJucer code wouldn’t need to be more any complicated.
I looked at the latest code and the Mac exports for VST, etc. look the same, so I suspect if I built with multiple formats enabled then it would work as a monolithic plug-in, except of course for AU. But that is more manageable, if just AU has to be it’s own build.
But I’m also thinking that I will want to stay on AU V2, because I don’t need of the new V3 features and it sounds like V2 hosts will need minor updates to support V3 plug-ins, but V2 plug-ins will continue to work just fine in V3 hosts. So I’d much rather stay on V2 for as long as I can.
I’m thinking I will make a copy of AU_Wrapper.cpp and call it AU_V2_Wrapper.cpp, so that hopefully I can continue using the old wrapper without too much trouble. I’d love it if Juce would continue to support V2 for a limited time period with a similar approach. Again this wouldn’t have to be something that ProJucer supports.
I’m not native english speaker, so perhaps it’s just me, but this sounds like a misnamed function: I can’t understand what this function does by just reading its name.
Why not a simple getPluginWrapperType()?
Also, there are a few variables/functions that are written with a capital ‘i’: ‘plugIn’. For consistency with the codebase, ‘plugin’ would be better.
Now that you point that out, some better names for that method come to my mind as well.
Perhaps PluginHostType::getLoadedWrapperType()? getLoadedPluginType(). “loaded”, to emphasize the fact that it is the actual loaded format the one you are interested in (which, of course, makes sense in the context of the polymorphic plug-in)
Now that I think about it, there is no use of such a method if the polymorphic stuff will be abandoned eventually: the plug-in format will be known at compile time thanks to the various macros, right?
(and thus, no need for a wrapperType member in AudioProcessor as well, right?)
well, no, not in the framework part (the shared code that is the same for all the plugin formats, which also includes all your user code), as it is only compiled once for all of the plug-in targets. So there you need to check this at runtime.
Wow, agreed. I currently have a single project with a dozen or so builds for various plugins that have a shared base.
Having to multiply the number of builds/targets by 3 or so is gonna make this a massive mess. There must be an easy way to retain the polymorphic builds (at least with the AU2 still in place), maybe adding new builds for AU3.
On the other hand, using target dependencies, maybe there is a way to make it still clean and manageable even with many targets. Hmmm …
Yes, this is why we added the “All” target, using target dependencies, which will build all plug-in formats simultaneously, just as it was before. The only difference is that they are separate binaries now.