@David-Healey I don't see how that would help, the problem isn't specific to my setup there are fundamental bugs in HISE/JUCE. the more dig into this with CC the more walls I hit. I've been running it for hours now, installing virtual machines blah. I'm at the point where I just pull the plug and go to the pool with all my other friends instead of wasting hour after hour. I write beautiful sounding DSP and I can compose and do graphics. the rest around it really isn't my forte.
it does finally make a sound in hise on linux after a long struggle, but whether a compiled vst3 works in linux - sstill no change to test.
here's more findings so far
HISE on ARM64 Linux: three bugs blocking DSP-network / project-DLL compilation
Environment: Debian 13 (trixie), aarch64 (Apple Silicon), HISE develop (4.9.x, JUCE 6.1.3),
g++-12, Faust 2.79.3. Building the standalone and exporting plugins/DLLs natively for arm64.
Three separate bugs had to be fixed to compile DSP networks / project DLLs on arm64. Two are
architecture-independent UB (only bite on arm64); one is an arm64 MIR codegen loop.
1. CustomKeyboardState writes one element past its array (segfaults on arm64)
Any project load / export / compile_networks crashes immediately:
#0 hise::CustomKeyboardState::CustomKeyboardState()
#1 hise::MainController::MainController()
#2 hise::BackendProcessor::BackendProcessor(...)
hi_core/hi_core/UtilityClasses.h:
Colour noteColours[127]; // 127 entries, valid 0..126
The constructor (UtilityClasses.cpp) writes all 128 MIDI notes:
for (int i = 0; i < 128; i++)
setColourForSingleKey(i, Colours::transparentBlack); // writes noteColours[127] -> OOB
setColourForSingleKey also guards noteNumber <= 127, so 128 entries are intended. Index 127
is out of bounds. Harmless on x86_64 (overwrites the adjacent lowestKey), segfaults under -O3
on arm64.
Fix:
Colour noteColours[128];
2. SNEX MIR JIT infinite loop on arm64 (expression node)
"Compile DSP networks as DLL" and the compile_networks CLI hang at 100% CPU forever on arm64
(IDE looks frozen). It happens while the exporter instantiates each node in
DspNetwork::createAllNodesOnce(). Backtrace of the spinning thread:
#0 generate_func_code () <- MIR generator
#1 MIR_link ()
#2 snex::mir::MirCompiler::compileMirCode(juce::String)
#3 snex::mir::MirCompiler::compileMirCode(juce::ValueTree)
#4 snex::jit::Compiler::compileJitObject(juce::String)
#5 snex::JitExpression::JitExpression(...)
#6 scriptnode::dynamic_expression::updateCode(...)
...
#15 scriptnode::DspNetwork::createAllNodesOnce()
#16 hise::DspNetworkCompileExporter::DspNetworkCompileExporter(...)
Creating a math.expr / dynamic_expression node JIT-compiles its expression through the MIR
backend. MIR's aarch64 generator (generate_func_code, from MIR_link) loops indefinitely.
Lowering MIR_gen_set_optimize_level from 3 to 1 in snex_MirObject.cpp does not help (it loops
at lower levels too), so this is a MIR aarch64 codegen bug (bundled MIR in hi_snex/snex_mir/src).
During createAllNodesOnce() the JIT result is never used (the node's C++ is generated from the
expression source), so the JIT is skippable there. Flag on DspNetwork set during
createAllNodesOnce, checked in dynamic_expression::updateCode before new JitExpression:
if (node->getRootNetwork()->isCreatingAllNodesOnce())
{
r = Result::ok();
return;
}
This unblocks DSP-network / DLL export on arm64. Live JIT of expression nodes in the IDE still
hits the MIR loop; the real fix belongs in the MIR aarch64 backend.
3. Headless/CLI export crash: JUCE display query derefs null
With #2 worked around, compile_networks on a headless display (no monitor / Xvfb) segfaults
while the export dialog is constructed:
#0 juce::Component::getParentMonitorArea() (then later centreWithSize)
#1 juce::AlertWindow::updateLayout(bool)
#2 juce::AlertWindow::setMessage(...)
#3 juce::AlertWindow::AlertWindow(...)
#4 hise::DialogWindowWithBackgroundThread::DialogWindowWithBackgroundThread(...)
#5 hise::DspNetworkCompileExporter::DspNetworkCompileExporter(...)
#6 CommandLineActions::compileNetworks(...)
DspNetworkCompileExporter is a DialogWindowWithBackgroundThread, so it builds an AlertWindow
even from the CLI. On a headless Linux session JUCE detects zero displays and these deref null:
juce_gui_basics/components/juce_Component.cpp:
// getParentMonitorArea():
return Desktop::getInstance().getDisplays().getDisplayForRect(getScreenBounds())->userArea;
// ComponentHelpers::getParentOrMainMonitorBounds():
return Desktop::getInstance().getDisplays().getPrimaryDisplay()->userArea;
getDisplayForRect() returns nullptr when no display intersects (or the list is empty);
getPrimaryDisplay() returns nullptr when the list is empty.
Fix - guard both:
Rectangle<int> Component::getParentMonitorArea() const
{
auto& d = Desktop::getInstance().getDisplays();
if (auto* x = d.getDisplayForRect(getScreenBounds())) return x->userArea;
if (auto* p = d.getPrimaryDisplay()) return p->userArea;
return { 0, 0, 1920, 1080 };
}
// getParentOrMainMonitorBounds(): same guard around getPrimaryDisplay()
After these three changes, compile_networks -c:Release runs to completion on a headless
display and produces a working DspNetworks/Binaries/dll/.so for arm64 Linux.
getParentMonitorArea / getParentOrMainMonitorBounds derefing null also affects the CLI on any
Linux box with no usable display, so it is worth guarding regardless of architecture.