Deploying DLL Dependencies

Topics: Backward Compatibility
Aug 5, 2015 at 12:14 PM
I'm having with DLL dependencies. I'm a bit stuck.

My VST has many dependencies. I need to break my DLLs up for various reasons. For one thing, this VST will be compiling DLLs on the fly.

For some reason though, the framework doesn't seem to pick up DLL dependencies when I simply put them in the same folder as the VST dll. I used the fusion logger, and I found that it was looking for DLLs in my host's bin folder (Ableton). So, I stuck my DLLs in there and it worked fine.

I just need to know what the usual procedure is for deploying DLL dependencies so that the framework picks them up and loads them in to the App Domain...
Coordinator
Aug 5, 2015 at 1:31 PM
VST.NET has an AssemblyLoader that is used to load static dependencies from the installation folder (where the MyPlugin.dll and MyPlugin.net.vstdll are located).
https://vstnet.codeplex.com/SourceControl/latest#Source/Code/Jacobi.Vst.Core/Plugin/AssemblyLoader.cs

Dynamic dependencies - the generated assemblies, should be handled manually by you. So if you have code the (end) user can manipulate and need to compile an assembly from that, you need to manage that separately.

I think I remember seeing an open source c#-script compiler app somewhere that used Roslyn to do its magic. That may be an helpful starting point for seeing how to do assembly reloads and compile C# on the fly...
I think this was it: https://github.com/scriptcs/scriptcs
Aug 5, 2015 at 7:12 PM
I plan on deploying Vst.Net assemblies in the GAC because of the licensing issues.
It provides a reliable search path for your dependencies system-wide.

Dynamic loading accepts full path to the library, I don't see a problem here, you could just reload the path from a configuration settings set by your installer.

I can vouch for CS-Script and AvalonEdit, using these for scripting in my host and no issues so far.
Aug 5, 2015 at 11:26 PM
"AssemblyLoader that is used to load static dependencies from the installation folder (where the MyPlugin.dll and MyPlugin.net.vstdll are located). "

That's what I was looking for! I will get on to this soon.

Dynamic dependencies - the generated assemblies, should be handled manually by you. So if you have code the (end) user can manipulate and need to compile an assembly from that, you need to manage that separately.

Yes. Understood. In the past, the way I have done this is to compile using .Net's built in compiler, and when I reload the DLL, I don't use the normal assembly loading routines. I read the file in to a byte buffer and then load that byte buffer in to the app domain. This way, the DLL doesn't get locked up next time you try to compile it.
I plan on deploying Vst.Net assemblies in the GAC because of the licensing issues. 
I see. What re the licensing issues?
Aug 6, 2015 at 2:14 AM
Vst.Net is distributed under the LGPL license (lesser GNU).

My understanding is that the GNU license absorb your software license in most cases. If you use a GNU licenced component then your software is automatically attributed the GNU licence unless you communicate with the component via interprocess mecanism such as pipes or standard streams. Avoid like hell... last resort.

The lesser GNU license has lowered the bar. You are allowed to statically link to a LGPL component that is logically and physically separate from your program in the file system. IE if the same unmodified component on the storage medium can be successfully linked to by any process wishing to use that library then usage of LGPL is compliant and your software isn't required to be redistributed under LGPL. The GAC acts as a repository of memory shared libraries for any programs wishing to use a specific library so it falls under the proper guidelīnes of the LGPL and it helps alleviate assembly location resolving issues like your problem with ableton.

If I distribute the official signed build of Vst.Net and register it into the GAC any program can statically linked to the trusted build of Vst.Net. The installer/process can also install/use a specific version of the libray and/or overwrite my copy of Vst.Net without conflicts (dll hell). If I were to redistribute unsigned build of Vst.Net or worse like self signed assemblies (marc owns the official keys) then that would be a strict violation of the LGPL licence. I don't think registering the library in the GAC is a requirement but it is surely more inline with the spirit of the LGPL.

With liberally licensed libraries I just copy paste their files into my assembly and modify to my taste instead of linking to them. Of course you always have to give proper credits and include a copy or a link to sources and license documents in most cases.
Coordinator
Aug 6, 2015 at 6:21 AM
Edited Aug 6, 2015 at 6:22 AM
The spirit of why I chose the LGPL license is the principle that if you use the official build you're free to do so (even commercially) - if you change the source code you have to open source those changes. That seemed fair to me.

I never interpreted the LGPL license as something to do with how you deploy it...

Anyway - for a plugin I would prefer to have all files in one location (as an end user). Makes life so much easier. For a host I would prefer the same but sometimes that is not possible.

The early versions of VST.NET assumed GAC deployment, but I quickly realized that that was not ideal.
Aug 16, 2015 at 7:58 AM
This works a treat!
            AssemblyLoader.Current.GlobalProbePaths.Add(GlobalVariables.PluginPath);
            AssemblyLoader.Current.LoadAssembly("MySynth.AudioProcessing", new List<string> { "dll" });
            AssemblyLoader.Current.LoadAssembly("MySynth.AudioProcessing", new List<string> { "dll" });
            AssemblyLoader.Current.LoadAssembly("MySynth.CodeEditing", new List<string> { "dll" });
            AssemblyLoader.Current.LoadAssembly("MySynth.Hosting", new List<string> { "dll" });
            AssemblyLoader.Current.LoadAssembly("MySynth.PluginManagement", new List<string> { "dll" });
            AssemblyLoader.Current.LoadAssembly("MySynth.Utilities", new List<string> { "dll" });
It's a little different to normal deployment in that usually, I wouldn't want to load each of my app's dependencies manually, but it's not too onerous.
Coordinator
Aug 22, 2015 at 7:03 AM
The AssemblyLoader is subscribed to the AppDomain.AssemblyResolve event. This 'connection' is part of the bootstrapping of a VST.NET plugin. .NET should raise the event when it is unable to locate a specific assembly (dependency) and the AssemblyLoader will then try to load the Assembly from one of the locations in its probe path collections.

So I am surprised you have to manually load the Assemblies. Would you mind debugging into VST.NET and see if the AssemblyResolve event is raised?
Also the PluginPath should already be in the AssemblyLoader's probe paths...
Aug 23, 2015 at 1:30 AM
I'll give it a go soon, but I did run the Fusion logging tool that you recommended a while back. What I found was that VST.Net wasn't probing the path of the of VST dll, it was actually only probing the Ableton bin directory. So, for a long time I just lumped them in there until the above code alleviated that necessity.
Sep 13, 2015 at 4:25 AM
Oops. It turns out that I hadn't removed all the copy commands from the post build event and the reason why it was working was that it was actually still copying the DLLs in to the Ableton folder.

Obiwan, I will try this, however, quick question - am I supposed to supply a probing path somewhere? Do I need to specify this in the config or something?
Coordinator
Sep 13, 2015 at 6:08 AM
Depends. If you have all your files in the same folder - the folder the plugin dll is loaded from, then no.
If you wish to add extra probe paths - use the GlobalProbePaths collection on the AssemblyLoader. Make sure you don't add duplicates and it might be a good idea to remove them when you're done - because they are global - meaning, they're also used for loading other managed plugins.

There is a host configuration file app-setting 'vstnetProbePaths' but using host configuration files is not recommended and should be avoided. A host configuration file is where you add (to) a host.exe.config which is loaded when the first managed plugin is loaded (or when the host itself is managed). It's is hard to manage - not your first option.

Note that there is a FileFinder class in Core: http://vstnet.codeplex.com/SourceControl/latest#Source/Code/Jacobi.Vst.Core/Plugin/FileFinder.cs
On the AssemblyLoaded there is a CreateFileFinder() method that creates one for you with the probe-paths already set. The FileFinder locates a specific file (name) in the probepaths - you can even look for different extensions. This was something I needed for loading managed plugin assemblies but the class is public and may be helpful.

Hope it helps,
Marc