Compilation fails on (Windows) Clang 13 due to inline ASM

I’m cross-compiling my audio plugin for Windows via a Linux Docker container, mstorsjo/llvm-mingw.

I think this has exposed me to an obscure combination (Clang on Windows). It fails to compile juce_MathsFunctions.h (using the macros in juce_PlatformDefs.h).

Because, juce_MathsFunctions.h has the first usage of jassert(), which ultimately expands the JUCE_BREAK_IN_DEBUGGER macro, { __asm int 3 }.

We can see in Godbolt that Clang 13 cannot compile __asm int 3.

Verbose build output is as follows:

[  2%] Building CXX object CMakeFiles/JuicySFPlugin.dir/Source/FilePicker.cpp.obj
/opt/llvm-mingw/bin/x86_64-w64-mingw32-clang++ -DDEBUG=1 -DDONT_SET_USING_JUCE_NAMESPACE=1 -DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1 -DJUCE_MODULE_AVAILABLE_juce_audio_basics=1 -DJUCE_MODULE_AVAILABLE_juce_audio_devices=1 -DJUCE_MODULE_AVAILABLE_juce_audio_formats=1 -DJUCE_MODULE_AVAILABLE_juce_audio_plugin_client=1 -DJUCE_MODULE_AVAILABLE_juce_audio_processors=1 -DJUCE_MODULE_AVAILABLE_juce_audio_utils=1 -DJUCE_MODULE_AVAILABLE_juce_core=1 -DJUCE_MODULE_AVAILABLE_juce_data_structures=1 -DJUCE_MODULE_AVAILABLE_juce_events=1 -DJUCE_MODULE_AVAILABLE_juce_graphics=1 -DJUCE_MODULE_AVAILABLE_juce_gui_basics=1 -DJUCE_MODULE_AVAILABLE_juce_gui_extra=1 -DJUCE_SHARED_CODE=1 -DJUCE_STANDALONE_APPLICATION=JucePlugin_Build_Standalone -DJUCE_USE_CURL=0 -DJUCE_VST3_CAN_REPLACE_VST2=1 -DJUCE_WEB_BROWSER=0 -DJucePlugin_AAXCategory=2048 -DJucePlugin_AAXDisableBypass=0 -DJucePlugin_AAXDisableMultiMono=0 -DJucePlugin_AAXIdentifier=com.Birchlabs.JuicySFPlugin -DJucePlugin_AAXManufacturerCode=JucePlugin_ManufacturerCode -DJucePlugin_AAXProductId=JucePlugin_PluginCode -DJucePlugin_AUExportPrefix=juicysfpluginAU -DJucePlugin_AUExportPrefixQuoted=\"juicysfpluginAU\" -DJucePlugin_AUMainType="'aumu'" -DJucePlugin_AUManufacturerCode=JucePlugin_ManufacturerCode -DJucePlugin_AUSubType=JucePlugin_PluginCode -DJucePlugin_Build_AAX=0 -DJucePlugin_Build_AU=0 -DJucePlugin_Build_AUv3=0 -DJucePlugin_Build_Standalone=1 -DJucePlugin_Build_Unity=0 -DJucePlugin_Build_VST3=1 -DJucePlugin_Build_VST=1 -DJucePlugin_CFBundleIdentifier=com.Birchlabs.JuicySFPlugin -DJucePlugin_Desc="\"Audio plugin to play soundfonts\"" -DJucePlugin_EditorRequiresKeyboardFocus=1 -DJucePlugin_IsMidiEffect=0 -DJucePlugin_IsSynth=1 -DJucePlugin_Manufacturer=\"Birchlabs\" -DJucePlugin_ManufacturerCode=0x426c6273 -DJucePlugin_ManufacturerEmail=\"\" -DJucePlugin_ManufacturerWebsite=\"https://birchlabs.co.uk\" -DJucePlugin_Name=\"juicysfplugin\" -DJucePlugin_PluginCode=0x4a736670 -DJucePlugin_ProducesMidiOutput=0 -DJucePlugin_VSTCategory=kPlugCategSynth -DJucePlugin_VSTNumMidiInputs=16 -DJucePlugin_VSTNumMidiOutputs=16 -DJucePlugin_VSTUniqueID=JucePlugin_PluginCode -DJucePlugin_Version=3.0.0 -DJucePlugin_VersionCode=0x30000 -DJucePlugin_VersionString=\"3.0.0\" -DJucePlugin_Vst3Category="\"Instrument|Synth\"" -DJucePlugin_WantsMidiInput=1 -D_DEBUG=1 @CMakeFiles/JuicySFPlugin.dir/includes_CXX.rsp -g -fvisibility=hidden -fvisibility-inlines-hidden -Wa,-mbig-obj -pthread -mms-bitfields -g -O0 -Wall -Wshadow-all -Wshorten-64-to-32 -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wconversion -Wsign-compare -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wsign-conversion -Wbool-conversion -Wextra-semi -Wunreachable-code -Wcast-align -Wshift-sign-overflow -Wno-missing-field-initializers -Wnullable-to-nonnull-conversion -Wno-ignored-qualifiers -Wswitch-enum -Wpedantic -Wzero-as-null-pointer-constant -Wunused-private-field -Woverloaded-virtual -Wreorder -Winconsistent-missing-destructor-override -std=gnu++17 -MD -MT CMakeFiles/JuicySFPlugin.dir/Source/FilePicker.cpp.obj -MF CMakeFiles/JuicySFPlugin.dir/Source/FilePicker.cpp.obj.d -o CMakeFiles/JuicySFPlugin.dir/Source/FilePicker.cpp.obj -c /build/juicysfplugin/Source/FilePicker.cpp
In file included from /build/juicysfplugin/Source/FilePicker.cpp:5:
In file included from /build/juicysfplugin/Source/FilePicker.h:7:
In file included from /build/juicysfplugin/Source/../JuceLibraryCode/JuceHeader.h:14:
In file included from /linux_native/include/JUCE-6.1.4/modules/juce_audio_basics/juce_audio_basics.h:54:
In file included from /linux_native/include/JUCE-6.1.4/modules/juce_core/juce_core.h:223:
/linux_native/include/JUCE-6.1.4/modules/juce_core/maths/juce_MathsFunctions.h:129:5: error: expected 'volatile', 'inline', 'goto', or '('
    jassert (sourceRangeMax != sourceRangeMin); // mapping from a range of zero will produce NaN!
    ^
/linux_native/include/JUCE-6.1.4/modules/juce_core/system/juce_PlatformDefs.h:162:95: note: expanded from macro 'jassert'
  #define jassert(expression)           JUCE_BLOCK_WITH_FORCED_SEMICOLON (if (! (expression)) jassertfalse;)
                                                                                              ^
/linux_native/include/JUCE-6.1.4/modules/juce_core/system/juce_PlatformDefs.h:152:144: note: expanded from macro 'jassertfalse'
  #define jassertfalse                  JUCE_BLOCK_WITH_FORCED_SEMICOLON (JUCE_LOG_CURRENT_ASSERTION; if (juce::juce_isRunningUnderDebugger()) JUCE_BREAK_IN_DEBUGGER; JUCE_ANALYZER_NORETURN)
                                                                                                                                               ^
/linux_native/include/JUCE-6.1.4/modules/juce_core/system/juce_PlatformDefs.h:85:49: note: expanded from macro 'JUCE_BREAK_IN_DEBUGGER'
  #define JUCE_BREAK_IN_DEBUGGER        { __asm int 3 }

Full context here:

I think the fix would be something like:

+ #elif JUCE_CLANG
+   // inline ASM not supported
+   #define JUCE_BREAK_IN_DEBUGGER        { }
  #else
    #define JUCE_BREAK_IN_DEBUGGER        { __asm int 3 }
  #endif

working around it for now by passing cmake option: -DCMAKE_CXX_FLAGS='-DJUCE_DISABLE_ASSERTIONS'

I’ve moved this over to a GitHub issue:

What arch are you targeting? Intel targets support __asm int 3 just fine, so I’m guessing you’re configured for ARM (which I believe is untested with JUCE on Windows/ARM)…

A compatibility list for the debug trap for various archs and toolchains can be found here: c++ - Is there a portable equivalent to DebugBreak()/__debugbreak? - Stack Overflow

I don’t think leaving the debug trap blank is the right solution.

1 Like

The first compile failure I’m experiencing occurs on x86_64. Here’s a minimal repro on Godbolt.

From the StackOverflow that you’ve linked, it sounds like the syntax Clang is expecting is:

// https://github.com/nemequ/portable-snippets/blob/84abba93ff3d52c87e08ba81de1cc6615a42b72e/debug-trap/debug-trap.h
__asm__ __volatile__("int3");

this does indeed look like it compiles on Clang x86_64.

Interesting. Then again, Godbolt + clang + x86_64 provides the int3 via __builtin_debugtrap() (as provided by Clang). That would probably be more well-rounded from the toolchain’s POV - it should work with ARM devices.

You can see an example of this working with Clang as far as back as 3.3: Compiler Explorer

1 Like

I’ve recently spent some time fixing JUCE builds for MinGW-W64 8.1.0+ (that’s the version that ships in the most recent CodeBlocks).

The relevant changes are

Please try building with JUCE from the most recent develop branch and let us know if you run into any further issues.

Hey, I’ve tried upgrading to JUCE 6.1.5 but still getting uuidof() errors:

and now cross-compilation is even harder, since a new dependency has been introduced on the Windows SDK:

how do I compile the Windows SDK headers with Clang on Linux?

okay, looks like MinGW does come with Windows SDK headers, but the filename is lowercase so it wasn’t discovered.

I do have some new Clang 14 related compile errors, and x86 audio plugins no longer compile at all. will raise tickets for those.

Tickets raised: