How to create an app from a Julia code that is writing and using other Julia files inside itself?

I will explain my question in details using a super simple toy example in below.

The structure of the code is as the following. Everything is in a folder called “Test_making_app”. This folder contains two julia files and a subfoler called “Temp”. The main Julia file is called “Test_making_app.jl” with the following content.

module Test_making_app

function julia_main()::Cint
  try
    file_name=ARGS[1]
    multiplier=parse(Int,ARGS[2])
    input_file=open(joinpath(pwd(),file_name),"r")
    input_text=readline(input_file)
    close(input_file)
    input_source=open(joinpath(pwd(),"Temp","input.jl"),"w")
    write(input_source,"input_list=[$input_text]")
    close(input_source)
    include(joinpath(pwd(),"Task.jl"))
    output_result=task(multiplier)
    output_file=open(joinpath(pwd(),"output.txt"),"w")
    write(output_file,"The user input:\n$input_text\n\nThe app output:\n$output_result")
    close(output_file)
  catch
        Base.invokelatest(Base.display_error, Base.catch_stack())
        return 1
  end
  return 0 # if things finished successfully
end

end # module

The second julia file is called “Task.jl” and has the following content.

include(joinpath(pwd(),"Temp","input.jl"))
x=input_list[1]
y=input_list[2]
function task(z)
    return x+z*y
end

The subfolder is empty.

What is this app going to do?

First you write an input file. Let’s say a txt file with the name “input1.txt” and you write two numbers with a comma between. Let’s say I wrote 1,3, you save it and put it in this folder (Test_making_app). In your windows cmd or your own terminal you cd to this folder, then type the follwowing;

Julia Test_making_app.jl <argument1> <argument2>

Where instead of <argument1> you type name of your input file, here “input1.txt”. Instead of <argument2> you type a number, let’s say “2”. So it will be like the following;

Julia Test_making_app.jl input1.txt 2

Then you press enter. The app reads your input, then creates a new julia file in the temp folder called “input.jl”. Then passes the second argument to the Task.jl file. Task.jl file receives the second argument and some other values from input.jl file, does a computation and then returns the result back to the main julia file. At the end a report is written in a new txt file saved in Test_making_app folder which is supposed to be the output for the user.

Everything works fine. This is a simple example. Of course I could write the above code in a single julia file, but I’m not going to simplify any steps above because my goal is to learn how to make something with a structure like above to become an application.

Why to make it an application?

The real examples (not this simple example) may be written in a specific version of Julia and hence later when syntax of some parts of the code are changed in newer versions of Julia, the user can’t use it as it is without going over all the files and codes and change stuff.

Now the questions!

What I could understand is that I have to use “PackageCompiler” and before using it I have to give a project style to my code in a Julia sense. To do that I have to use Pkg. Following what I understand from reading the documentations of these two (link:Pkg, link:PackageCompiler) I did the following steps.
1- Going to an empty directory. Here in my case D:\\.
2- In Julia doing the following

(@v1.4) Pkg> generate Test_making_app
Julia> cd("Test_making_app")
(@v1.4) pkg> activate .
 Activating environment at `D:\Test_making_app\Project.toml`

(Test_making_app) pkg> st
Project Test_making_app v0.1.0
Status `D:\Test_making_app\Project.toml`
  (empty environment)

Then I replaced all content of my old folder “Test_making_app” (the two julia files and empty temp folder) into the src folder of this project. Then

(Test_making_app) pkg> precompile
Precompiling project...
[ Info: Precompiling Test_making_app [8f396c06-8ec7-49f7-a929-b1265c672a0b]

(Test_making_app) pkg> st
Project Test_making_app v0.1.0
Status `D:\Test_making_app\Project.toml`
  (empty environment)

Now I use the PackageCompiler.

D:\>Julia -q --project
julia> using PackageCompiler
[ Info: Precompiling PackageCompiler [9b87118b-4619-50d2-8e1e-99f35a4d4d9d]

julia> create_app("Test_making_app","Test_making_app_compiled")
┌ Warning: it is not recommended to create an app without a preexisting manifest
└ @ PackageCompiler C:\Users\Amir\.julia\packages\PackageCompiler\vsMJE\src\PackageCompiler.jl:593
   Updating registry at `C:\Users\Amir\.julia\registries\General`
   Updating git-repo `https://github.com/JuliaRegistries/General.git`
   Updating `D:\Test_making_app\Project.toml`
 [no changes]
   Updating `D:\Test_making_app\Manifest.toml`
 [no changes]
[ Info: PackageCompiler: creating base system image (incremental=false)...
[ Info: PackageCompiler: creating system image object file, this might take a while...
[ Info: PackageCompiler: creating system image object file, this might take a while...

julia> 

It seems it made an application. However, I put the input1.txt file in the bin folder next to the exe file and in cmd I do the following.

D:\>cd "D:\Test_making_app_compiled\bin"

D:\Test_making_app_compiled\bin>Test_making_spp input1.txt 2
'Test_making_spp' is not recognized as an internal or external command,
operable program or batch file.

D:\Test_making_app_compiled\bin>Test_making_app input1.txt 2
ERROR: SystemError: opening file "D:\\Test_making_app_compiled\\bin\\Temp\\input.jl": No such file or directory
Stacktrace:
 [1] systemerror(::String, ::Int32; extrainfo::Nothing) at .\error.jl:168
 [2] #systemerror#50 at .\error.jl:167 [inlined]
 [3] systemerror at .\error.jl:167 [inlined]
 [4] open(::String; read::Nothing, write::Nothing, create::Nothing, truncate::Bool, append::Nothing) at .\iostream.jl:254
 [5] open(::String, ::String) at .\iostream.jl:310
 [6] julia_main() at D:\Test_making_app\src\Test_making_app.jl:10
 [7] julia_main() at .\none:29

D:\Test_making_app_compiled\bin>

As you see it doesn’t make the input.jl file. There is no subfolder called “Temp” in bin folder as well. Instead I have a mysterious subfolder called “Tabriz”! I like this city, but I don’t remember using its name anywhere in the process I explained in details above :slight_smile:

So what did I miss in the process or what am I doing wrong?

I also wonder why the application folder is so huge. It is 317 MB. I’m using only read and write, converting string to integer, simple addition and multiplication in the code.

2 Likes

Amir,

I am pretty sure Package compiler bundles all of the code needed to run Julia into the compiled executable/dependancies. That’s why it’s 317mb.

That being said there are some mysteries in this thread I don’t have an answer too. Such as the folder Tabriz

1 Like

Yes,

and more code potentially needed, but not actually needed in your case. You may look into, filtering, e.g. you know you’ve not using LinearAlgebra: https://julialang.github.io/PackageCompiler.jl/dev/apps/#Filtering-stdlibs-1

I’ve only tried compiling once, then without filtering, I guess it could that way or does actually filter out OpenBLAS that’s rather huge. At least in theory it should be possible, and even the compiler itself (LLVM a dependency of it is also huge), Julia. Currently it’s included, [and Julia also has an interpreter available, with --compile=min, using binaries compiled without that, and noting else, or possibly with the interpreter handling some parts, is a theoretical possibility, I think we’re not yet there.]

1 Like