JuliaGraphics / QML.jl

Build Qt6 QML interfaces for Julia programs.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Segfault when calling Julia functions

veddox opened this issue · comments

When my QML window calls a function that was defined in Julia and tagged using @qmlfunction, I get a segfault:

[132030] signal (11.1): Segmentation fault
in expression starting at [...]/run.jl:13
_ZN7qmlwrap8JuliaAPI13set_js_engineEP9QJSEngine at ~/.julia/artifacts/5b399b8a0d2ef4ba00667e41a3fe59db6eaa6000/lib/libjlqml.so (unknown line)

It seems that libjlqml is not installed - how can I do so? Edit: I manually installed jlqml_jll 0.5.3, but the error persists.

I'm using QML.jl 0.8 with Qt6Base_jll 6.5.2 and CxxWrap 0.14.0 on Julia 1.9.3. Is there any other dependency I need?

I get the same segfault when running the code example at the @qmlfunction documentation:

julia> using QML

julia> greet() = "Hello, World!";

julia> @qmlfunction greet

julia> mktempdir() do folder
          path = joinpath(folder, "main.qml")
          write(path, """
          import org.julialang
          import QtQuick
          import QtQuick.Controls
          ApplicationWindow {
            visible: true
            Text {
              text: Julia.greet()
            }
            Timer {
              running: true; repeat: false
              onTriggered: Qt.exit(0)
            }
          }
          """)
          loadqml(path)
          exec()
        end

I get the same segfault when running the code example at the @qmlfunction documentation

This just got a bit weirder. I realised that the above statement is not strictly true. As long as I call @qmlfunction greet every time before executing the do block, it works. If I call the do block twice in succession, it segfaults.

The error seems to be in this function in jlqml_jll, but I don't understand the code well enough to see it.

Working through the code of julia_api.cpp a bit more, I found the following line:

  s_singletonInstance->set_js_engine(qmlEngine);

Shouldn't this pass scriptEngine rather than qmlEngine?

Thanks for reporting this and looking into it. The reason is that after exec has returned the internal Qt state is cleaned up completely, and the functions are no longer registered. So inded, you have to call @qmlfunction again before exec, but a segfault probably isn't the most user friendly way of communicating this, so that needs to be fixed.

Wonderful, thank you for addressing this so quickly!

However, I don't yet understand how this affects my original problem. Why do I get this segfault straight away when running my own code?

This is the file in question (redacted, but structurally unchanged):

global model = missing
const running = Observable(false)
const date = Observable(today())
const progress = Observable(0.0)
const delay = Observable(0.5)
const runbuttontext = Observable(">>")
const runbuttontip = Observable("Run")

function newsimulation()
    # do some stuff
    println("Model initialised.")
end

function nextstep()
    # do some stuff
    println("Updated model.")
end

function runsimulation()
    # do some stuff
end

function togglerunning()
    if running[]
        running[] = false
        runbuttontext[] = ">>"
        runbuttontip[] = "Run"
    else
        running[] = true
        runbuttontext[] = "||"
        runbuttontip[] = "Pause"
        runsimulation()
    end
end

function render_map(screen)
    # do some stuff
end

@qmlfunction newsimulation
@qmlfunction nextstep
@qmlfunction togglerunning
@qmlfunction render_map

on(delay) do d
    println("Delay is now $(round(d, digits=1)) seconds.")
end

on(running) do r
    r ? println("Simulation started.") : println("Simulation stopped.")
end

"""
    launch()

The main function that creates the application.
"""
function launch()
    qmlfile = joinpath(dirname(@__FILE__), "main.qml")
    loadqml(qmlfile,
            vars = JuliaPropertyMap("running" => running,
                                    "date" => date,
                                    "delay" => delay,
                                    "progress" => progress,
                                    "runbuttontext" => runbuttontext,
                                    "runbuttontip" => runbuttontip))
    println("Launched program.")
    exec()
end

When I load my package and run launch(), it segfaults immediately. It also crashes when I load the package but then manually execute loadqml() and exec().

Wonderful, thank you for addressing this so quickly!

However, I don't yet understand how this affects my original problem. Why do I get this segfault straight away when running my own code?

This is the file in question (redacted, but structurally unchanged):

global model = missing
const running = Observable(false)
const date = Observable(today())
const progress = Observable(0.0)
const delay = Observable(0.5)
const runbuttontext = Observable(">>")
const runbuttontip = Observable("Run")

function newsimulation()
    # do some stuff
    println("Model initialised.")
end

function nextstep()
    # do some stuff
    println("Updated model.")
end

function runsimulation()
    # do some stuff
end

function togglerunning()
    if running[]
        running[] = false
        runbuttontext[] = ">>"
        runbuttontip[] = "Run"
    else
        running[] = true
        runbuttontext[] = "||"
        runbuttontip[] = "Pause"
        runsimulation()
    end
end

function render_map(screen)
    # do some stuff
end

@qmlfunction newsimulation
@qmlfunction nextstep
@qmlfunction togglerunning
@qmlfunction render_map

on(delay) do d
    println("Delay is now $(round(d, digits=1)) seconds.")
end

on(running) do r
    r ? println("Simulation started.") : println("Simulation stopped.")
end

"""
    launch()

The main function that creates the application.
"""
function launch()
    qmlfile = joinpath(dirname(@__FILE__), "main.qml")
    loadqml(qmlfile,
            vars = JuliaPropertyMap("running" => running,
                                    "date" => date,
                                    "delay" => delay,
                                    "progress" => progress,
                                    "runbuttontext" => runbuttontext,
                                    "runbuttontip" => runbuttontip))
    println("Launched program.")
    exec()
end

When I load my package and run launch(), it segfaults immediately. It also crashes when I load the package but then manually execute loadqml() and exec().

Is this still an issue with QML 0.8.1?

Is this still an issue with QML 0.8.1?

No. Bart and I had a short video conference yesterday and it works now 🙂

One problem had been that I was calling @qmlfunction outside of the launch() function. The other problem was the QML module lookup bug, which is fixed now.