Your code using include
already works for me, if I correct the brackets in invokelatest
to Base.invokelatest(p.b[1], 3)
and remove the string_to_funct
line. To create an app, you should of course also move the “inputs.jl” argument into ARGS
.
Full program
Folder structure
Tester
│ Manifest.toml
│ precompile_app.jl
│ Project.toml
│
├───compiled
│ ├───bin
│ │ julia.exe
│ │ ...
│ │ Tester.exe
│ │
│ └───share
│ └───julia
│ cert.pem
│ LocalPreferences.toml
│ Project.toml
│
├───inputs
│ inputs.jl
│ inputs2.jl
│
└───src
Tester.jl
Most of these files are created by Pkg
using Pkg
Pkg.generate("Tester")
and PackageCompiler
(see below).
Manually added files are Tester.jl
, which corresponds to your main.jl
,
Tester.jl
module Tester
# Load parameters from file and call solver
module Tester
# Load parameters from file and call solver
function julia_main()::Cint
include(ARGS[1]) # Loads in p
# Run solver with input parameters
solver(p)
return 0
end
function solver(p)
println("Running solver with p = ",p)
println("a = ",p.a) # 1 for inputs1.jl, 3 for inputs2.jl
println("p.b[1] = ", p.b[1])
println("b[1](3) = ", Base.invokelatest(p.b[1], 3)) # 3^2 = 9 for inputs1.jl, 3^3 = 27 for inputs2.jl
end
end
the input files
inputs1.jl
p = (
a = 1,
b = [(t) -> t^2]
)
which is your inputs.jl
inputs2.jl
p = (
a = 3,
b = [(t) -> t^3]
)
and the optional precompilation script precompile_app.jl
, which is not really useful for this small example, but could be for your full program.
precompile_app.jl
using Tester
push!(ARGS, "./inputs/inputs1.jl")
Tester.julia_main()
(cf. PackageCompiler.jl/examples/MyApp/precompile_app.jl at master · JuliaLang/PackageCompiler.jl · GitHub and PackageCompiler.jl how to specify ARGS for create_app? - #2 by jsjie)
To compile, I opened Julia in the parent directory of Tester, and used
]activate Tester
using PackageCompiler
create_app("Tester", "Tester/compiled")
# or: create_app("Tester", "Tester/compiled", precompile_execution_file="Tester/precompile_app.jl")
(assuming ./Tester/compiled does not already exist). As output I get
> .\Tester\compiled\bin\Tester.exe .\Tester\inputs\inputs1.jl
Running solver with p = (a = 1, b = [Tester.var"#1#2"()])
a = 1
p.b[1] = #1
b[1](3) = 9
> .\Tester\compiled\bin\Tester.exe .\Tester\inputs\inputs2.jl
Running solver with p = (a = 3, b = [Tester.var"#1#2"()])
a = 3
p.b[1] = #1
b[1](3) = 27
You will notice that this is on Windows. If relevant, here’s my full versioninfo()
:
versioninfo
Julia Version 1.10.4
Commit 48d4fd4843 (2024-06-04 10:41 UTC)
Build Info:
Official https://julialang.org/ release
Platform Info:
OS: Windows (x86_64-w64-mingw32)
CPU: 8 × Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-15.0.7 (ORCJIT, skylake)
Threads: 8 default, 0 interactive, 4 GC (on 8 virtual cores)
Environment:
JULIA_NUM_THREADS = auto
and I am using PackageCompiler v2.1.17.
I kind of like the include
approach you suggest, due to the amount of freedom it brings (you can just ‘import’ any object produced by Julia code), but I cannot say if there are any downsides, or what the idiomatic approach would be.