Skip to content

Linking of VST3 plugin fails on Clang + MinGW due to CheckSettingMacros undefining JucePlugin_Build_VST3 #993

@Birch-san

Description

@Birch-san

I've been attempting to use a Linux Docker container to cross-compile my audio plugin for Windows x86_64, using Clang and MinGW.

The problem only occurs when you use JUCE_VST3_CAN_REPLACE_VST2=1 (so, to repro this you'll need a VST2 SDK).

It fails at link-time; juce_VST3_Wrapper.cpp fails to find symbol getUUIDForVST2ID.

/opt/llvm-mingw/bin/x86_64-w64-mingw32-clang++ -DJUCE_DISABLE_ASSERTIONS -g -shared -o "AudioPluginExample_artefacts/Debug/VST3/Audio Plugin Example.vst3/Contents/x86_64-win/Audio Plugin Example.vst3" -Wl,--major-image-version,0,--minor-image-version,0 -Wl,--whole-archive CMakeFiles/AudioPluginExample_VST3.dir/objects.a -Wl,--no-whole-archive @CMakeFiles/AudioPluginExample_VST3.dir/linklibs.rsp
ld.lld: error: undefined symbol: juce::getUUIDForVST2ID(bool, unsigned char*)
>>> referenced by /linux_native/include/JUCE-6.1.2/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp:3572
>>>               objects.a(juce_audio_plugin_client_VST3.cpp.obj):(juce::getFUIDForVST2ID(bool))
clang-13: error: linker command failed with exit code 1 (use -v to see invocation)
CMakeFiles/AudioPluginExample_VST3.dir/build.make:256: recipe for target 'AudioPluginExample_artefacts/Debug/VST3/Audio Plugin Example.vst3/Contents/x86_64-win/Audio Plugin Example.vst3' failed

The symbol is supposed to be created in juce_PluginUtilities.cpp, provided JucePlugin_Build_VST3 is defined.

But juce_CheckSettingMacros.h undefines it since our toolchain is not whitelisted.

As a result: juce_audio_plugin_client_utils.cpp.obj (the file responsible for including juce_PluginUtilities.cpp) gets created without the symbol juce::getUUIDForVST2ID(bool, unsigned char*) .

here's how to reproduce the problem inside a Linux Docker container (cross-compiling for Windows):

# I assume that you have a VST2_SDK installed at ~/SDKs/VST_SDK/VST2_SDK/, and mount it into the container
docker run -it --rm --name=mingw-repro -v "$HOME/SDKs/VST_SDK/VST2_SDK/:/VST2_SDK/:ro" mstorsjo/llvm-mingw

# now you're inside the container
# install juceaide dependencies:
apt-get update -qq && \
apt-get install -qqy --no-install-recommends libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libfreetype6-dev && \
apt-get clean -y && \
rm -rf /var/lib/apt/lists/*

TOOLCHAIN=x86_64
TOOLCHAIN_FILE="/${TOOLCHAIN}_toolchain.cmake"
MINGW_REPO=clang64

# define CMake toolchain for cross-compiling to x86_64 Windows via MinGW:
cat >"$TOOLCHAIN_FILE" <<EOF
# the name of the target operating system
set(CMAKE_SYSTEM_NAME Windows)

# which compilers to use for C and C++
set(CMAKE_C_COMPILER   $TOOLCHAIN-w64-mingw32-clang)
set(CMAKE_CXX_COMPILER $TOOLCHAIN-w64-mingw32-clang++)

# where is the target environment located
# https://cmake.org/cmake/help/latest/command/find_library.html
set(CMAKE_FIND_ROOT_PATH  /$MINGW_REPO;/opt/llvm-mingw/$TOOLCHAIN-w64-mingw32)

# adjust the default behavior of the FIND_XXX() commands:
# search programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)

# search headers and libraries in the target environment
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
EOF

# clone last-known-good JUCE
# we cannot use a newer JUCE due to https://github.com/juce-framework/JUCE/issues/985
git clone --branch 6.1.2 --depth 1 https://github.com/juce-framework/JUCE.git

cd JUCE

# build juceaide (we will *not* cross-compile this for Windows; we build natively for the build machine)
cmake -B build -DCMAKE_INSTALL_PREFIX="/linux_native"
cmake --build build --target install

cd examples/CMake/AudioPlugin
# uncomment find_package line
sed -i '/^# find_package(JUCE/ s/# //' CMakeLists.txt
# enable JUCE_VST3_CAN_REPLACE_VST2
sed -i '/JUCE_VST3_CAN_REPLACE_VST2=0/ s/0/1/' CMakeLists.txt
# set VST2_SDK path
sed -i '/^juce_add_plugin/i juce_set_vst2_sdk_path(/VST2_SDK)' CMakeLists.txt

# I've disabled assertions because of an unrelated issue (compiling asm on Clang):
#   https://github.com/juce-framework/JUCE/issues/986
VERBOSE=1 cmake -Bbuild \
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \
-DCMAKE_PREFIX_PATH="/linux_native" \
-DCMAKE_INSTALL_PREFIX="/$MINGW_REPO" \
-DCMAKE_CXX_FLAGS='-DJUCE_DISABLE_ASSERTIONS' \
-DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN_FILE" \
-DCMAKE_BUILD_TYPE=Debug
# will encounter link failure in juce_VST3_Wrapper.cpp
cmake --build build --target AudioPluginExample_VST3

cd build
# the reason for the link failure is because the symbol is missing:
llvm-nm -gU CMakeFiles/AudioPluginExample.dir/linux_native/include/JUCE-6.1.2/modules/juce_audio_plugin_client/juce_audio_plugin_client_utils.cpp.obj
# no symbols printed at all!

I'm currently working around this with the following patch:
Birch-san@7182e6e

In my branch (Birch-san/juicysfplugin#32), build and link succeed. I get the following symbols returned:

llvm-nm -gU CMakeFiles/JuicySFPlugin.dir/linux_native/include/JUCE-6.1.2/modules/juce_audio_plugin_client/juce_audio_plugin_client_utils.cpp.obj
00001200 T _ZN4juce16getUUIDForVST2IDEbPh
000019c0 T _ZN4juce36handleManufacturerSpecificVST2OpcodeEixPvf
00000000 T _ZN4juce9ByteOrder12bigEndianIntEPKv
00000000 T _ZN4juce9ByteOrder7makeIntEhhhh

With my patch: this successfully builds & links a VST3 plugin, which runs fine in FL Studio.
perhaps Clang+MinGW should be added to the whitelist of supported toolchains in juce_CheckSettingMacros.h?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions