Polymorphic plugin build gone in Juce 4.2

That was easy to fix with a pre-build script!

This was also possible by either looking at the wrapperType member of the AudioProcessor or (as a second choice by looking at the extension of the binary loaded by the host for the plug-in)

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.

Thoughts?

Thanks,
Chris

2 Likes

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.

1 Like

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 …

1 Like

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.

Ok, looking at this more I have a question …

I notice the plugin wrappers are all in the “shared code” part of the project.

It seems that moving them to the individual plug-format targets could let you have multiple plugins in the same project (like a delay and a filter or something).

You can’t currently do that (at least, with any shared code), since the juce_core code seems to want an entrance point now (ie. createPluginFilter()).

Any chance we could figure out a way to have multiple plugins in the same project? It was fairly easy to do in the old polymorphic way.

How does one go with stripping symbols in the new scheme?

By previously running strip in a post-build step our plugins only exposed 13 required symbols, which can be checked by doing nm <EXECUTABLE> -s __TEXT __text.

Looks like all the symbols in the framework are exposed now. This is a major concern for developers of closed-source software.

1 Like

Besides exposing all the symbols the framework also leads to bloat. Can OSX load only the needed parts of a framework to memory or do plugins now use more memory due to larger binaries?

Wouldn’t it be possible to offer the option to link with a static library instead of a framework? That way symbol stripping and dead code stripping could work.

I also imagine the framework build doesn’t work very well with some copy protection schemes.

2 Likes

Is this actually the case? And if yes, what copy protection schemes are breaking? This would be great for us to know as we are thinking about how to further improve the plug-in build mechanism.

I totally agree with you pflugshaupt, I guess however that having static libraries could increase build times due to the linker stage?

At the moment we handle exported symbols using an exported symbols file to explicitly declare the symbols to export. I haven’t tried this with JUCE 4.2 yet but I suspect this won’t work (at least not without an impressive post-build script). As I assume the exported symbols file will be applied to both binaries (Shared code and which ever wrapper I’m building), Unfortunately if the exported symbols file contains any symbols NOT in the binary it will fail. Plus I assume the process becomes more complex as the file would need to include various C++ symbols so that the wrapper can access them, right?

As it stands I think for me a static library could possibly be a better option even if it means increased build times!

I would also like to express that although I think a great deal of JUCE and it really is a fantastic library, in future when you are planning to make fundamental changes like this it would be greatly appreciated if you can announce the upcoming change as soon as possible… but at the very least add it to the release notes. Unless I’m sadly mistaken this post from pflugshaupt is the only place where this change has been documented.

1 Like

Yes, we hear you! Thanks for the feedback, we will definitely keep it in mind for future releases!

2 Likes

I haven’t really tested JUCE 4.2 yet because of all the uncertainties it brought along, I will wait a little until the dust settles… However, my protection is dependent on a external copy protection software being able to search and access/modify a single executable (Mach-O) file that contains the required byte markers etc. I also need the software to be fully functional when every symbol not absolutely needed is stripped away.

1 Like

+1 for this, at least for the “stripping symbols” part. I don’t think we’ll ever ship any code that has its symbols in clear view.

1 Like

We are trying out the static library approach right now! Hopefully it won’t increase the build times too much because it still has to compile the shared code only once, there’s just a bit more linking to do. And yes, obviously we’ll add stripping symbols, we just overlooked that with 4.2.

Watch this space for a JUCE update!

3 Likes

The new version with the static library instead of the framework fails compiling the standalone version with Scheme (AUv3 AppExtension):

Undefined symbols for architecture x86_64:
  "_main", referenced from:
        start in crt1.10.6.o
        (maybe you meant: __ZN4juce16jpeglibNamespace23jinit_c_main_controllerEPNS0_20jpeg_compress_structEh, __ZN4juce16jpeglibNamespace23jinit_d_main_controllerEPNS0_22jpeg_decompress_structEh )
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

EDIT: This is because i have reverted temporarily back the Deployment Target to 10.7. Since AUv3 cannot be compiled with anything less than 10.10 as Target, would be cool to have it set automatically by the jucer to 10.10 for the AUv3 Scheme and whatever you specified in the Projucer xcode exporter settings for the VST and AUv2 Schemes. This way i’m not forced to use 10.10 for those other formats, for which i would like to maintain compatibility with 10.7.

I think this is not going to work because most of your code will be compiled only once (the shared code part) and then the plug-in wrappers link to this statically. So you can’t use different build settings for different plug-in formats. This was never possible with the old polymorphic build, either.

What we can do though is check for <10.10 if you have AUv3 ticked, and give a warning, so peoplewon’t run into the same problem with the plug-in not compiling.

1 Like

makes sense. anyway since there is no use for AU3 in any host at the moment i will disable it.

the only drawback is that it enabled the standalone build, which was really convenient and fast for testing changes right away without the hassle of starting a full host. would be cool if you could enable the standalone build even when not building AU3, wouldn’t be hard to do it as the StandaloneFilterWindow is there.

Thanks for addressing the framework issue and making it a high priority, the new static approach looks good to me and the newly added strip symbols options in projucer is very nice!