Birch-san / juicysfplugin

Audio plugin (e.g. VST, AU) to play soundfonts on macOS, Windows, Linux
GNU General Public License v3.0
209 stars 27 forks source link

Compiling on Windows fails when using Dockerfile #56

Open DaforLynx opened 11 months ago

DaforLynx commented 11 months ago

When running docker build . -f win32.Dockerfile --tag=llvm-mingw as per instructions with WSL and msys2 mingw64 installed on Windows 10, the build fails while building fluidsynth with "undefined symbol: __declspec(dllimport)" errors related to glib2 functions, coming from the LLD linker.

This doesn't happen while building fluidsynth normally (per their wiki) with the same config flags that juicysfplugin uses. This is probably unrelated to the libpcre2 problem which was discovered and fixed here, because the functions indicated by the errors seem more related to threads and memory than regex.

Relevant excerpt of the console output starting at the compile step that spawns the errors: excerpt.txt

Solutions I've tried include trying to install libglib2.0-dev on the relevant docker images by editing the dockerfile and sh files, changing CMAKE_FIND_ROOT_PATH_MODE variables in [arch]_toolchain.make, trying to install all the fluidsynth dependencies via the dockerfile. A potential solution may be to try using the posix version of mingw, but I'm unsure how to get that working in Docker.

I know the maintainer uses OSX to develop, so I urge anybody reading this who uses a Windows machine to try to replicate it. So far myself and one other person have gotten these same errors.

Birch-san commented 11 months ago

I know the maintainer uses OSX to develop, so I urge anybody reading this who uses a Windows machine to try to replicate it.

Windows isn't a confounding factor; you're (cross-)compiling this in a Linux virtual machine + container, just like I do. the Dockerfile worked at the time I made it, but some of the dependencies it's fetching have undergone changes since the time it was last working. we've been forced onto a new major version of pcre, for example (probably indicates that glib updated -- glib uses pcre to implement regex).

A potential solution may be to try using the posix version of mingw

hmm I don't think there's anything here that suggests that the compiler toolchain is making a mistake. I think this would happen even if you changed toolchain. if you stick with the current toolchain, then you at least don't have to solve cross-compilation, because that's known-good.

and msys2 mingw64 installed on Windows 10

the compilation happens inside a container, inside a WSL Linux virtual machine. so it doesn't matter what's installed on Windows — the compilation's happening inside a Linux container.

the build fails while building fluidsynth

actually it built fluidsynth successfully, then proceeded on to the next step: building juicysfplugin.

but we're doing static linking (the goal is to create a single-file .exe or .dll with all libraries included inside it, instead of a folder of .dlls), so the libfluidsynth we're linking in, doesn't actually come with its own dependencies (e.g. glib).

so, when building a statically-linked juicysfplugin: our job is to know what dependencies we have, and what dependencies they have, and make sure we include them all in our build.
whereas usually people do dynamic-linking, where you're only responsible for linking in your immediate dependencies, not your transitive dependencies too.

ordinarily, pkgconfig is supposed to be the mechanism for juicysfplugin's build to lookup what fluidsynth's dependencies were, and from there it would learn that to build juicysfplugin: we'll need to link in glib, to ensure fluidsynth can work.

so, I think something's missing in fluidsynth's pkgconfig output. ordinarily it's supposed to include some linker flags saying to go find glib. maybe that mechanism failed, or maybe it's resulted in the wrong glib being included, or glib being included but not its dependencies.

DaforLynx commented 11 months ago

Thanks for the corrections. So I guess to find out more, we'd have to find what "fluidsynth's pkgconfig output" is spitting out?

Birch-san commented 11 months ago

to investigate this, I did the following:

this reproduced your "juicysfplugin didn't link glib" error:
ld.lld: error: undefined symbol: __declspec(dllimport) g_rec_mutex_init.

next, I wanted an interactive shell into the failed build. I scrolled up to the beginning of the RUN make_juicysfplugin.sh step:

 ---> 3d048cb29897
Step 74/76 : RUN /juicysfplugin/make_juicysfplugin.sh x64
 ---> Running in 51a95ad2b92b
arch: x64
/usr/bin/cmake -P /juicysfplugin/build_x64/CMakeFiles/VerifyGlobs.cmake

Using 3d048cb29897 (the name of the last saved image), I used my terminal on macOS to open a Linux container based on that image. in your case you'd use your Windows terminal.

docker run -it --rm 3d048cb29897

this gave me a shell into the container, from just before the command /juicysfplugin/make_juicysfplugin.sh x64 was run.
so, if I were interested in interactively running the build again, I could run the command /juicysfplugin/make_juicysfplugin.sh x64 from this shell. but I'm not interested in watching it fail again; I'm here to investigate the pkgconfig files.

All the libraries for our cross-compile-to-win32-x86_64 are in /clang64/lib.

The pkgconfig output for those libraries is in /clang64/lib/pkgconfig.

So we can take a look at glib's pkgconfig file:

cat /clang64/lib/pkgconfig/fluidsynth.pc
prefix=/clang64
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include

Name: FluidSynth
Description: Software SoundFont synth
Version: 2.2.5
Requires.private: glib-2.0 gthread-2.0
Libs: -L${libdir} -lfluidsynth
Libs.private: -lgthread-2.0 -lglib-2.0 -lintl 
Cflags: -I${includedir}

those linker flags -lgthread-2.0 -lglib-2.0 -lintl are what our application's build needs. ordinarily (dynamic linking) those private dependencies would be already atteched to libfluidsynth, but we're doing static linking, so it becomes our job.

so… that actually looks okay. so long as our application's pkgconfig mechanism actually finds and uses fluidsynth.pc and its Libs.private section correctly. which I think it should, since I was already relying on this mechanism since before we ended up with a newer glib.

====

hmmm looks like that g_rec_mutex_init is specifically a threading API, so maybe we're missing -lgthread-2.0 rather than -lglib-2.0.

I think next step is to check what linker flags the juicysfplugin build uses in practice (i.e. check whether it gleaned the right flags from the pkgconfig files).

Birch-san commented 11 months ago

since our container is running from an image that was saved shortly after /juicysfplugin/configure_juicysfplugin.sh x64 was run: all of the cmake build config is already in this container, so we can check what flags would be used in the build:

cat build_x64/CMakeFiles/JuicySFPlugin_Standalone.dir/link.txt

The link command that cmake built was:

/usr/bin/cmake -E rm -f CMakeFiles/JuicySFPlugin_Standalone.dir/objects.a
/opt/llvm-mingw/bin/llvm-ar qc CMakeFiles/JuicySFPlugin_Standalone.dir/objects.a @CMakeFiles/JuicySFPlugin_Standalone.dir/objects1.rsp
/opt/llvm-mingw/bin/x86_64-w64-mingw32-clang++ -D__UIAutomationClient_LIBRARY_DEFINED__  -DUIA_IsDialogPropertyId="(30174)" -DUIA_IsPasswordPropertyId="(30019)" -DUIA_IsOffscreenPropertyId="(30022)" -DUIA_ToggleToggleStatePropertyId="(30086)" -DUIA_IsKeyboardFocusablePropertyId="(30009)" -DUIA_ProcessIdPropertyId="(30002)" -DUIA_HelpTextPropertyId="(30013)" -DUIA_HasKeyboardFocusPropertyId="(30008)" -DUIA_FrameworkIdPropertyId="(30024)" -DUIA_NamePropertyId="(30005)" -DUIA_RangeValueValuePropertyId="(30047)" -DUIA_NativeWindowHandlePropertyId="(30020)" -DUIA_ControlTypePropertyId="(30003)" -DUIA_IsEnabledPropertyId="(30010)" -DUIA_IsContentElementPropertyId="(30017)" -DUIA_FullDescriptionPropertyId="(30159)" -DUIA_ValueValuePropertyId="(30045)" -DUIA_AutomationIdPropertyId="(30011)" -DUIA_IsControlElementPropertyId="(30016)" -O3 -DNDEBUG -static-libgcc -static-libstdc++ /clang64/lib/libiconv.a /opt/llvm-mingw/x86_64-w64-mingw32/lib/libwinpthread.a -mwindows -Wl,--whole-archive CMakeFiles/JuicySFPlugin_Standalone.dir/objects.a -Wl,--no-whole-archive -o JuicySFPlugin_artefacts/Release/Standalone/juicysfplugin.exe -Wl,--out-implib,JuicySFPlugin_artefacts/Release/Standalone/libjuicysfplugin.dll.a -Wl,--major-image-version,0,--minor-image-version,0 @CMakeFiles/JuicySFPlugin_Standalone.dir/linklibs.rsp

The final argument there, @CMakeFiles/JuicySFPlugin_Standalone.dir/linklibs.rsp, is where most of the answers will be. Let's check what linklibs.rsp contains:

cat build_x64/CMakeFiles/JuicySFPlugin_Standalone.dir/linklibs.rsp

It contains the rest of the linker flags:

 JuicySFPlugin_artefacts/Release/libjuicysfplugin_SharedCode.a -luuid -lwsock32 -lwininet -lversion -lole32 -lws2_32 -loleaut32 -limm32 -lcomdlg32 -lshlwapi -lrpcrt4 -lwinmm /clang64/lib/libfluidsynth.a /clang64/lib/libgthread-2.0.a /clang64/lib/libglib-2.0.a /clang64/lib/libintl.a /clang64/lib/libgthread-2.0.a /clang64/lib/libglib-2.0.a /clang64/lib/libintl.a /opt/llvm-mingw/x86_64-w64-mingw32/lib/libws2_32.a /opt/llvm-mingw/x86_64-w64-mingw32/lib/libole32.a /opt/llvm-mingw/x86_64-w64-mingw32/lib/libwinmm.a /opt/llvm-mingw/x86_64-w64-mingw32/lib/libshlwapi.a /opt/llvm-mingw/x86_64-w64-mingw32/lib/libuuid.a /opt/llvm-mingw/x86_64-w64-mingw32/lib/libm.a /clang64/lib/libpcre2-8.a -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32

okay, so archives of object code were found for gthread, glib and pcre2 (/clang64/lib/libgthread-2.0.a, /clang64/lib/libglib-2.0.a, /clang64/lib/libpcre2-8.a). this is a more explicit version of what -lgthread-2.0 -lglib-2.0 -lpcre2-8 resolve to (CMake searched for them at configure-time instead of leaving the work to clang).

hm. that actually sounds like we are linking those libraries in fine.

maybe we have a more subtle problem. was fluidsynth compiled against glib headers that don't match the glib library that we located via pkgconfig? I only see one header distribution for glib (/clang64/include/glib-2.0/), and one library distribution (/clang64/libglib-2.0.a). nothing suspicious nearby that could be picked up by mistake.

hmmm not sure what's going on. maybe need to understand a bit better why we got forced to upgrade pcre -- because if we find a way not to do that, then perhaps everything goes back to known-good versions.

maybe we just need to select an older glib2 in get_fluidsynth_deps.sh, instead of upgrading pcre.
the available glib2 versions are listed at: https://repo.msys2.org/mingw/clang64/
we are currently on 2.76.4, according to the pkgconfig. the oldest I see in the repository is 2.70.0.
we can make our package filename filter more specific, to pick up that older version:

-  declare -a PKGS=("libiconv" "flac" "glib2" "libogg" "opus-1" "libvorbis" "pcre-" "libsndfile" "gettext")
+  declare -a PKGS=("libiconv" "flac" "glib2-2.70.0" "libogg" "opus-1" "libvorbis" "pcre-" "libsndfile" "gettext")
Birch-san commented 11 months ago

hm, it gets me to a different linking error:
https://gist.github.com/Birch-san/e03d2472955c7b184e784baad9ce08fe

LLVM linker not happy about some -exclude-symbols options. not sure where those are coming from.

not sure if this means we failed earlier or later. the percentage progress is lower than in the build you posted, but if it's a multi-threaded build that could just be non-determinism.

DaforLynx commented 11 months ago

I got the same error, but at 76% Linking CXX executable (so it is probably non-deterministic, though that's the same step and percentage at which it errored out before). -exclude-symbols is found nowhere in fluidsynth's repo, and from what I could gather it's something coming from LLD. I think we need to use a newer version of LLD, perhaps, judging by this comment.

DaforLynx commented 10 months ago

Any update? I have an alternate solution for my personal dilemma but it asks potentially much from you: I've started a fork with the hopefully few changes I needed to make (https://github.com/DaforLynx/juicysfplugin-no-interp). If you have a build setup that already works, would it be feasible for you to build it on your system, then direct me to the build artifact (probably uploaded somewhere) so I can just download the compiled VSTs?