AviSynth / AviSynthPlus

AviSynth with improvements
http://avs-plus.net
963 stars 73 forks source link

Instruction of how to link AviSynth+ statically? #204

Open CrendKing opened 3 years ago

CrendKing commented 3 years ago

I see the 3.7.0 update has feature of "Support for building the core as a static library". I checked out the source and turned off BUILD_SHARED_LIBS. I can see a bigger AviSynth.lib generated, but I have trouble linking it. Please help?

  1. During compilation, I see a warning message saying "You must satisfy the conditions of the GPL license when linking against the AviSynth library." My project is using MIT license. avisynth.h has a paragraph granting users to link to it without adopting GPL, but I think it's more appropriate for dynamic linking. Can you guys confirm in a formal means that this still stands or act differently for static linking?
  2. When importing, capi.h has __declspec(dllimport) regardless. Thus, APIs with AVSC_API such as CreateScriptEnvironment cannot be resolved.
  3. If I remove __declspec(dllimport), these APIs can be resolved, but lots of functions are not found defined in multiple modules, such as VideoInfo::ComponentSize(). This is because avisynth.h actually defines them with a proxying body to the linkage implementation. If linked dynamically, this will be the only definition, which is fine. However, when built statically, interface.cpp will be linked into my module, thus causing duplicate definition. The solution is to turn off the whole "linkage" mechanism for static linking including all the proxy definition. But that's big change.

What I'm getting is either 3.7.0 is not ready for the static library, or the static library is for a completely different purpose that I'm not aware of. Otherwise, please provide some instructions. I'd like to statically link AviSynth+ instead of dealing with the dll loading situations. Thanks.

qyot27 commented 3 years ago

See #192 for the background on the static linking reasoning (and a GPL mini-discussion; I honestly don't know where I'm supposed to come down on that topic, as it sort of depends on whether a client program that calls in AviSynth itself is substantively different from plugins, which AFAICT is what the GPL linking exception was actually intended to cover). There's also a rather hacky example of what I did to make FFmpeg use a static build of it on Linux. FFmpeg, of course, uses the C API, not the C++ API.

130 is also probably related, as I brought up in the static linking discussion too. I'm generally not convinced of the usefulness of AVS_Linkage on platforms other than Windows, and there'll probably need to be some switchable logic for traditional linking even on Windows if this ends up being a serious and recurring issue.

Generally, I'd consider static linking an experimental feature, much like being able to build with MinGW-w64/GCC (which you can also do, even though using it seriously means you would have to either restrict yourself to using only C plugins, or use g++ to recompile every C++ plugin you use as well*).

*and a special build of FFmpeg with alternate --extra-cflags to talk to it if it's 32-bit. Regular 64-bit builds of FFmpeg are fine with GCC builds of AviSynth+.

CrendKing commented 3 years ago

Thanks for providing the PR link and ffmpeg example. As I understand,

  1. AviSynth+ 3.7.0 as-is won't work with Windows + MSVC + C++ API case, with the reasons in my original post. Linux + C API could work because the capi.h problem does not apply.
  2. ffmpeg example works with the license because it is already GPL. In my case since it is MIT, static linking avs+ will force me to change it to GPL, even though I'm not introducing any effective additional dependency or logic.

Regarding #130, I think what I get is, if static linking is possible, the whole AVS_linkage issue would not happen because non-Windows users could simply static link avs+. Dynamic linking exists only to loose license requirement. But pylorak mentioned in the PR that "Unfortunate because Avisynth will never be able to change it. It has already tried, very aggressively even, but the task was impossible in the end." I guess the mechanism and dynamic linking has to stay (unless someone complete rewrites avs+ from scratch with non-GPL licensing :) )

OK. So the conclusion is, for non-GPL Windows MSVC C++ API users, static linking won't ever be not available, correct?

qyot27 commented 3 years ago

The binaries would be required to be distributed under the terms of the GPL if linked (but, you know, IANAL). Just look at FFMS2, for example:

The FFMS2 source is licensed under the MIT license, but its binaries
are licensed under the GPL because GPL components of FFmpeg are
used. FFmpeg can be built as either LGPL, GPLv2, GPLv3, or even be
nonredistributable. Refer to FFmpeg's sources for licensing information.

As far as I understand it, AVS_Linkage has nothing to do with license trickery, it's some sort of plaster over incompatibilities in AVISYNTH_INTERFACE_VERSION and its very potentially Windows-specific nature is more about keeping users of old plugins happy than anything else, or for program authors wishing to support incompatible AVISYNTH_INTERFACE_VERSIONs (read: 2.5 vs. 2.6) at the same time instead of simply tracking upstream and dropping support for the incompatible ones as the library evolves.

CrendKing commented 3 years ago

IANAL too. What does it mean by distributing binaries under GPL? Does that mean anything that loads FFMS2 as plugin and be distributed as a whole (e.g. a player that bundles FFMS2 binaries in its distributed form) must be under GPL, but if that player compiles FFMS2 from source and static link it with a non-GPL ffmpeg version it can be non-GPL?

About AVS_linkage. Yes, the interface version is also a main reason for AVS_linkage. But the whole AVS_linkage mechanism works because of dynamic linking. If I link avs+ statically, there is just the one interface version that I choose to support at the compile time. It sounds to be much cleaner than dealing with a version-feature matrix at runtime. I no longer need to worry if my program is loaded in a system where avs+ 3.5 or 4.0 is installed, which might be completely incompatible with my 3.6 tested code.

CrendKing commented 3 years ago

So I hacked a version of avs+ locally that is fully statically linked into my program. It works for sure, and my program size jumped from 500KB to 5MB (with /MT runtime of course), which is approximately the whole size of the AviSynth.dll, which is expected.

To make it work, I basically made 3 changes:

  1. Add a macro AVS_STATIC_LIB from CMake, which is defined only if the core is built static for backward compatibility. Then check the macro in capi.h and remove those __declspec(dllxxx) if defined.
  2. In avisynth.h, there are blocks that defines macros like AVS_BakedCode and AVS_linkage, which is currently checked by BUILDING_AVSCORE. I add AVS_STATIC_LIB with OR relation to it. So all those linkage stuff are undefined.
  3. In core's main.cpp, there are currently DLL specific methods such as DllMain(). I need to extract the body of DllMain into methods that are exported in avisynth.h, and call those methods in my program the same way as how when a DLL is loaded, to setup the TLS.

I don't know if you guys want these changes as a PR. Let me know.

qyot27 commented 3 years ago

Go ahead and open a PR, as that way it can be reviewed more in-depth.

CrendKing commented 3 years ago

https://github.com/AviSynth/AviSynthPlus/pull/205

CrendKing commented 3 years ago

Thanks for merging the PR. I suppose we still need to wait for pinterf to make the final decision on XP TLS support, right?

qyot27 commented 3 years ago

I dunno. I mean, we already have a -DWINXP_SUPPORT option in the CMake configuration, so shuffling the (de)activation of the XP_TLS defines based on whether we're telling it to build with XP compatibility makes sense.

CrendKing commented 3 years ago

Seems logical to me. Want me to create an issue for tracking?

Also, just to confirm the last time: if anyone statically link Avs+ to their program and distribute, the program must be on GPL, period, right?