Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bundling App on Windows Fails #14

Open
Arryk opened this issue Jul 22, 2024 · 11 comments
Open

Bundling App on Windows Fails #14

Arryk opened this issue Jul 22, 2024 · 11 comments

Comments

@Arryk
Copy link

Arryk commented Jul 22, 2024

Hi,

I am trying to build a very simple application to test the bundler on Windows, but the application returns an error.

I have a very simple main.jl that contains

println("main.jl has been called!")

My Project.toml file

name = "TestBundle"
authors = ["AH"]
version = "0.0.1"

[bundle]
APP_NAME = "TestBundle"
APP_DESCRIPTION = "An app to TestBundle"
APP_DISPLAY_NAME = "TestBundle"
APP_SUMMARY = "An app to rTestBundle"
BUNDLE_IDENTIFIER = "none"
PUBLISHER = "CN=AH"
PUBLISHER_DISPLAY_NAME = "AH"
WITH_SPLASH_SCREEN = true

After that I run in the REPL
AppBundler.bundle_app(Windows(:x86_64), "TestBundle", "build/TestBundle.zip")

And I get a lots of errors
image

Every single filename has an "issue" with invalid characters.

I am running Julia 1.10.4 on Windows 11 Pro 22H2 (build 22621.1413)

Any idea how to get this to work ?

@JanisErdmanis
Copy link
Member

Hi,

I have actually not tested running AppBundler on Windows, so issues are expected. The issue appears to be in checking that the path does not contain invalid characters, which include \, but I should have seen that in MacOS as well.

For the time being, you can comment out ensure_windows_compatability in bundle_app for the Windows platform, which is simply a safety check. I will try to fix that someday next week when I plan to do some Windows stuff.

@Arryk
Copy link
Author

Arryk commented Jul 23, 2024

Hi,

Thanks, after commenting the line out, it works fine now.

I had a look at the function and the problem lies with the RegEx, it is normally used to validate file / folder names and you are inputting a file path or folder path. A path in windows will includes \ characters and : characters in a specific pattern and the RegEx to validate those is much more complicated.

image

If the files you are checking exists on disk, then using the function ispath will yield the same result and will take care of all the corner cases for you. If you need to check path before creating the files, then you'll probably needs to update the RegEx to something like this:

^(?<ParentPath>(?:[a-zA-Z]\:|\\\\[\w\s\.]+\\[\w\s\.$]+)\\(?:[\w\s\.]+\\)*)(?<BaseName>[\w\s\.]*?)$

Taken from: https://regexr.com/52is4

@Arryk
Copy link
Author

Arryk commented Jul 23, 2024

For your reference, I ran some test on the installation and everything works fine until .msix package installation.

App installation failed with error message: error 0x8007007E: Failed to load the extension DLL due to the following error: The specified module could not be found.
. (0x8007007e)

I get this error during installation on the package.
Running the precompile script didn't create a compiled folder, maybe this is related

@JanisErdmanis
Copy link
Member

JanisErdmanis commented Jul 23, 2024

I will have to check whether I can use ispath. The issue the regex solves is that on Linux and MacOS path variables can contain more characters like : and \ so it just ensures that the resulting bundles are functional made on Windows. I guess on Windows this check shouldn't be present as file written on disk already indicates that it is a valid path.

Regarding the installation, I can't remember seeing such error before. There is a powershell script launcher in the bundled directory, does it work for you?

@Arryk
Copy link
Author

Arryk commented Jul 26, 2024

It doesn't really work either, the script doesn't return any errors but when I try to run the main.jl in the Julia session I get an error specifying precompiled folder doesn't exists

@JanisErdmanis
Copy link
Member

I have no idea what the issue is, so I will only try to reproduce the issue on my Windows VM. I may try to allocate a few hours for the windows next week if I feel that I can change focus from the cryptography stuff I am doing now.

@Arryk
Copy link
Author

Arryk commented Jul 26, 2024

If you have a simple test application to run on Windows, I can also try it on my setup and test for you, if this helps

@JanisErdmanis
Copy link
Member

JanisErdmanis commented Aug 4, 2024

I just pushed a new version, v0.1.5, with which I managed to bundle examples/qmlapp on Windows. The build script that should be used for Windows is:

using AppBundler

import Pkg.BinaryPlatforms: Linux, MacOS, Windows

APP_DIR = dirname(@__DIR__)

BUILD_DIR = joinpath(APP_DIR, "build")
mkpath(BUILD_DIR)

AppBundler.bundle_app(Windows(:x86_64), APP_DIR, "$BUILD_DIR/qmlapp-win64")

where it is reasonable to omit zip archive creation.

Running the script will produce build/qmlapp-win64, where one needs to run the precompile.ps1 and then qmlapp.ps1. Let me know if you can launch the app that way.

Note that creating a bundle in deeply nested subdirectories would fail if the path exceeded the 260-character limit. Also, there is buggy behaviour when one uses the Parallels Desktop bridged folder, seemingly indicating that a network drive is affected the same way.

@Arryk
Copy link
Author

Arryk commented Aug 15, 2024

Hi Janis,

Thanks for spending some time on this. I tried to replicate the same build but got some issues:

Julia bundle succeeded

julia> AppBundler.bundle_app(Windows(:x86_64), APP_DIR, "$BUILD_DIR/qmlapp-win64")
[ Info: Rule with origin windows/assets is skipped as not found in default or override path.
  Activating project at `C:\Users\user\AppData\Local\Temp\temp_env`
   Resolving package versions...
    Updating `C:\Users\user\AppData\Local\Temp\temp_env\Project.toml`
  [ca6e7d0a] + GLAbstraction v0.7.0
  [f7f18e0c] + GLFW v3.4.3
    Updating `C:\Users\user\AppData\Local\Temp\temp_env\Manifest.toml`
  [ca6e7d0a] + GLAbstraction v0.7.0
  [f7f18e0c] + GLFW v3.4.3
  [66fc600b] + ModernGL v1.1.7
  [aea7be01] + PrecompileTools v1.2.1
  [3cdcf5f2] + RecipesBase v1.3.4
  [90137ffa] + StaticArrays v1.9.7
  [1e83bf80] + StaticArraysCore v1.4.3
  [b189fb0b] + ThreadPools v2.1.1
  [83423d85] + Cairo_jll v1.18.0+2
  [ee1fde0b] + Dbus_jll v1.14.10+0
  [559328eb] + FriBidi_jll v1.0.14+0
  [0656b61e] + GLFW_jll v3.4.0+1
  [3b182d85] + Graphite2_jll v1.3.14+0
  [2e76f6c2] + HarfBuzz_jll v2.8.1+1
  [1d63c593] + LLVMOpenMP_jll v15.0.7+0
  [dd4b983a] + LZO_jll v2.10.2+0
  [36c8627f] + Pango_jll v1.52.2+0
  [30392449] + Pixman_jll v0.43.4+0
  [935fb764] + Xorg_libXcursor_jll v1.2.0+4
  [d091e8ba] + Xorg_libXfixes_jll v5.0.3+4
  [a51aa0fd] + Xorg_libXi_jll v1.7.10+4
  [d1454406] + Xorg_libXinerama_jll v1.1.4+4
  [1183f4f0] + libdecor_jll v0.2.2+0
  [b53b4c65] + libpng_jll v1.6.43+1
  Activating project at `scripts`
[ Info: include_dependency updated C:\scripts\qmlapp\build/qmlapp-win64/packages\CxxWrap\src\CxxWrap.jl
[ Info: include_dependency skipped C:\scripts\qmlapp\build/qmlapp-win64/packages\Requires\src\Requires.jl

However the precompilation failed

PS C:\scripts\qmlapp\build\qmlapp-win64> .\precompile.ps1
ERROR: LoadError: MethodError: no method matching include_dependency(::String; track_content::Bool)

Closest candidates are:
  include_dependency(::AbstractString) got unsupported keyword argument "track_content"
   @ Base loading.jl:1689

Stacktrace:
 [1] readmodule(so_path_cb::typeof(CxxWrap.StdLib.get_libcxxwrap_julia_stl_path), funcname::Symbol, m::Module, flags::UInt32)
   @ CxxWrap.CxxWrapCore C:\scripts\qmlapp\build\qmlapp-win64\packages\CxxWrap\src\CxxWrap.jl:816
 [2] wrapmodule(so_path_cb::Function, funcname::Symbol, m::Module, flags::UInt32)
   @ CxxWrap.CxxWrapCore C:\scripts\qmlapp\build\qmlapp-win64\packages\CxxWrap\src\CxxWrap.jl:825
 [3] top-level scope
   @ C:\scripts\qmlapp\build\qmlapp-win64\packages\CxxWrap\src\StdLib.jl:22
 [4] include(mod::Module, _path::String)
   @ Base .\Base.jl:495
 [5] include(x::String)
   @ CxxWrap C:\scripts\qmlapp\build\qmlapp-win64\packages\CxxWrap\src\CxxWrap.jl:1
 [6] top-level scope
   @ C:\scripts\qmlapp\build\qmlapp-win64\packages\CxxWrap\src\CxxWrap.jl:933
 [7] include
   @ .\Base.jl:495 [inlined]
 [8] include_package_for_output(pkg::Base.PkgId, input::String, depot_path::Vector{String}, dl_load_path::Vector{String}, load_path::Vector{String}, concrete_deps::Vector{Pair{Base.PkgId, UInt128}}, source::String)
   @ Base .\loading.jl:2222
 [9] top-level scope
   @ stdin:3
in expression starting at C:\scripts\qmlapp\build\qmlapp-win64\packages\CxxWrap\src\StdLib.jl:1
in expression starting at C:\scripts\qmlapp\build\qmlapp-win64\packages\CxxWrap\src\CxxWrap.jl:1
in expression starting at stdin:3
ERROR: LoadError: Failed to precompile CxxWrap [1f15a43c-97ca-5a2a-ae31-89f07a497df4] to "C:\\scripts\\qmlapp\\build\\qmlapp-win64\\compiled\\v1.10\\CxxWrap\\jl_FAC7.tmp".
Stacktrace:
  [1] error(s::String)
    @ Base .\error.jl:35
  [2] compilecache(pkg::Base.PkgId, path::String, internal_stderr::IO, internal_stdout::IO, keep_loaded_modules::Bool)
    @ Base .\loading.jl:2468
  [3] compilecache
    @ .\loading.jl:2340 [inlined]
  [4] (::Base.var"#968#969"{Base.PkgId})()
    @ Base .\loading.jl:1974
  [5] mkpidlock(f::Base.var"#968#969"{Base.PkgId}, at::String, pid::Int32; kwopts::@Kwargs{stale_age::Int64, wait::Bool})
    @ FileWatching.Pidfile C:\scripts\qmlapp\build\qmlapp-win64\julia\share\julia\stdlib\v1.10\FileWatching\src\pidfile.jl:93
  [6] #mkpidlock#6
    @ C:\scripts\qmlapp\build\qmlapp-win64\julia\share\julia\stdlib\v1.10\FileWatching\src\pidfile.jl:88 [inlined]
  [7] trymkpidlock(::Function, ::Vararg{Any}; kwargs::@Kwargs{stale_age::Int64})
    @ FileWatching.Pidfile C:\scripts\qmlapp\build\qmlapp-win64\julia\share\julia\stdlib\v1.10\FileWatching\src\pidfile.jl:111
  [8] #invokelatest#2
    @ .\essentials.jl:894 [inlined]
  [9] invokelatest
    @ .\essentials.jl:889 [inlined]
 [10] maybe_cachefile_lock(f::Base.var"#968#969"{Base.PkgId}, pkg::Base.PkgId, srcpath::String; stale_age::Int64)
    @ Base .\loading.jl:2983
 [11] maybe_cachefile_lock
    @ .\loading.jl:2980 [inlined]
 [12] _require(pkg::Base.PkgId, env::String)
    @ Base .\loading.jl:1970
 [13] __require_prelocked(uuidkey::Base.PkgId, env::String)
    @ Base .\loading.jl:1812
 [14] #invoke_in_world#3
    @ .\essentials.jl:926 [inlined]
 [15] invoke_in_world
    @ .\essentials.jl:923 [inlined]
 [16] _require_prelocked(uuidkey::Base.PkgId, env::String)
    @ Base .\loading.jl:1803
 [17] macro expansion
    @ .\loading.jl:1790 [inlined]
 [18] macro expansion
    @ .\lock.jl:267 [inlined]
 [19] __require(into::Module, mod::Symbol)
    @ Base .\loading.jl:1753
 [20] #invoke_in_world#3
    @ .\essentials.jl:926 [inlined]
 [21] invoke_in_world
    @ .\essentials.jl:923 [inlined]
 [22] require(into::Module, mod::Symbol)
    @ Base .\loading.jl:1746
 [23] include
    @ .\Base.jl:495 [inlined]
 [24] include_package_for_output(pkg::Base.PkgId, input::String, depot_path::Vector{String}, dl_load_path::Vector{String}, load_path::Vector{String}, concrete_deps::Vector{Pair{Base.PkgId, UInt128}}, source::String)
    @ Base .\loading.jl:2222
 [25] top-level scope
    @ stdin:3
in expression starting at C:\scripts\qmlapp\build\qmlapp-win64\packages\QML\src\QML.jl:1
in expression starting at stdin:3
ERROR: LoadError: Failed to precompile QML [2db162a6-7e43-52c3-8d84-290c1c42d82a] to "C:\\scripts\\qmlapp\\build\\qmlapp-win64\\compiled\\v1.10\\QML\\jl_8B9F.tmp".
Stacktrace:
  [1] error(s::String)
    @ Base .\error.jl:35
  [2] compilecache(pkg::Base.PkgId, path::String, internal_stderr::IO, internal_stdout::IO, keep_loaded_modules::Bool)
    @ Base .\loading.jl:2468
  [3] compilecache
    @ .\loading.jl:2340 [inlined]
  [4] (::Base.var"#968#969"{Base.PkgId})()
    @ Base .\loading.jl:1974
  [5] mkpidlock(f::Base.var"#968#969"{Base.PkgId}, at::String, pid::Int32; kwopts::@Kwargs{stale_age::Int64, wait::Bool})
    @ FileWatching.Pidfile C:\scripts\qmlapp\build\qmlapp-win64\julia\share\julia\stdlib\v1.10\FileWatching\src\pidfile.jl:93
  [6] #mkpidlock#6
    @ C:\scripts\qmlapp\build\qmlapp-win64\julia\share\julia\stdlib\v1.10\FileWatching\src\pidfile.jl:88 [inlined]
  [7] trymkpidlock(::Function, ::Vararg{Any}; kwargs::@Kwargs{stale_age::Int64})
    @ FileWatching.Pidfile C:\scripts\qmlapp\build\qmlapp-win64\julia\share\julia\stdlib\v1.10\FileWatching\src\pidfile.jl:111
  [8] #invokelatest#2
    @ .\essentials.jl:894 [inlined]
  [9] invokelatest
    @ .\essentials.jl:889 [inlined]
 [10] maybe_cachefile_lock(f::Base.var"#968#969"{Base.PkgId}, pkg::Base.PkgId, srcpath::String; stale_age::Int64)
    @ Base .\loading.jl:2983
 [11] maybe_cachefile_lock
    @ .\loading.jl:2980 [inlined]
 [12] _require(pkg::Base.PkgId, env::String)
    @ Base .\loading.jl:1970
 [13] __require_prelocked(uuidkey::Base.PkgId, env::String)
    @ Base .\loading.jl:1812
 [14] #invoke_in_world#3
    @ .\essentials.jl:926 [inlined]
 [15] invoke_in_world
    @ .\essentials.jl:923 [inlined]
 [16] _require_prelocked(uuidkey::Base.PkgId, env::String)
    @ Base .\loading.jl:1803
 [17] macro expansion
    @ .\loading.jl:1790 [inlined]
 [18] macro expansion
    @ .\lock.jl:267 [inlined]
 [19] __require(into::Module, mod::Symbol)
    @ Base .\loading.jl:1753
 [20] #invoke_in_world#3
    @ .\essentials.jl:926 [inlined]
 [21] invoke_in_world
    @ .\essentials.jl:923 [inlined]
 [22] require(into::Module, mod::Symbol)
    @ Base .\loading.jl:1746

Any idea why this is the case ?

Thanks!

@JanisErdmanis
Copy link
Member

JanisErdmanis commented Aug 15, 2024

It seems that track content argument got introduced only with Julia 1.11 which is now in release candidate stage. You should use that as it also introduces cache relocability fixes.

@Arryk
Copy link
Author

Arryk commented Aug 15, 2024

Thanks, I will try again on 1.11 when it releases and update the post then

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants