How to distribute julia software to the general public

Which is the best way to distribute a software developed in Julia for the general public? I mean, assuming the installation of the Julia interpreter is out of question.

Most specifically, I have a software that performs some heavy calculations, written in Julia, and that is used as a backend in another software that has a simple GUI for Windows.

Normally, I would distribute an executable with static libraries. I understand that this is not possible (yet) with Julia.

I wander if there is a way to package all the functions and routines used by my package and distribute it as a “minimal” Julia interpreter with the package. Even if it is not an executable, this solution would be good enough and could be hidden from the user.

Thank you for your thoughts.
Leandro.

1 Like

Why? A Bash script that

  1. downloads a given version of Julia, then extracts it in a subdirectory,
  2. sets up another subdirectory as your depot path,
  3. extracts/downloads your project and instantiates the dependencies, and perhaps compiles them into the image

is reasonably simple.

The other solution would be a container, eg with Docker. I guess this is fine too, especially the backend can operate through a local network connection.

1 Like

There’s also ApplicationBuilder.jl and a nice talk on it from JuliaCon 2018. It might not be the easiest to get working though; I haven’t used it myself actually.

4 Likes

I suppose something like that could be included as part of a Setup wizard for Windows, but it would still generate a ton of data for a package which, statically linked, would occupy 1MB.

Sadly, there really aren’t any solutions right now for having reasonably sized binaries. It does require ~ 600 MB at least to run any Julia code. The only way around that (in principle) is building static binaries with PackageCompiler, but I don’t know if anyone has managed to get the total binary size much smaller than that.

I don’t think that 1MB is a reasonable expectation for a language like Julia. You may never get binaries the size of C, but for a desktop/productivity program that does something genuinely useful, people should not balk at 1GB these days (for which SSD storage costs about 10 cents, and download takes a few minutes on a wired connection).

Or you can set it up as a service on a website.

In this specific case my contribution to the code is one number crunching application which is important but would not take much space. The UI etc takes about 100MB and is developed by other people.

I will probably just translate the code to Fortran or C at the end, which is not terrible for this application, but not what we would like to do, of course.

Thank you for all your comments.

Another alternative is a web application and run the Julia part on your own servers.

3 Likes

I disagree with this sentiment. There isn’t anything (other than explicit calls to eval at runtime) that should stop Julia code from being static compiled to a very small binary. Take a look at the size of CUDAnative kernels; they’re tiny and they can do tons of number crunching. Adapting this approach to native binaries with init logic and a C-callable interface is really all the OP would need to make their project feasible.

Also, let’s please not encourage software bloat just because disk space is getting cheaper. There is no reason why 1GB should be needed for a very small program which is only doing basic number crunching.

12 Likes

I am not sure about this. The complete universe of (parametric) types used is perhaps fixed for some programs in theory, but deriving this in a foolproof manner in practice is a very hard problem. So you need the whole machinery.

Eg consider

struct Bar{T}
    x::T
end

f(z::Bar) = rand() > 0.9 ? z : f(Bar(z))

f(Bar(1))

While this is a contrived example, higher-level logic may not be type stable even in well-written Julia programs, especially if they use external input.

People have been complaining about this since the early days of eg Common Lisp (“you need 10MB to do what?”), but as disks are getting cheaper and programmer time remains expensive, expect this trend to continue.

Eg if it takes me an afternoon to shave off 50MB from a program that will run on less than 1000 machines, then working on this would make sense only if I put a very low value on my time.

2 Likes

I won’t disagree with the example you posted; something like that will be hard to deal with, unless we’re somehow able to construct and work with types without doing any codegen (which may be possible by interpreting until we get back to compiled code paths). I’ll keep this example in mind :heart:

I get that this has always been the case, but I still find 1GB to be absolutely absurd for a very small program, even by today’s standard. And the fact that static languages like C can make amazingly small binaries with a modern compiler urges me to figure out how to do the same in Julia.

I also place a high value on my time, but I’m also hoping that once written, a Julia static compiler would be able to do this automatically without the developer having to spend any time working on it at all. I certainly wouldn’t want smaller and smaller binaries to require more and more developer time!

I think a prerequisite for that is a set of dynamically linked libs that are always available no matter where the executable is run. Julia obviously does not have that.

But, if you absolutely don’t need to hide your source code, distributing a small package is as good (or even better) than a small binary, I think.

2 Likes

Sure, and so we’ll probably need, at a minimum, libc and possibly libjulia for each program. Other than that, there shouldn’t be any required dependencies for very simple programs that don’t make heavy use of the task runtime, BLAS, etc. An example I like to think of is an email filter (milter) that does very simple text wrangling of emails as they are received by a mail server. All that would probably need (in terms of shared libraries) is libc, libjulia, and PCRE.

I feel that it wouldn’t hurt much if the compiler asked the developer which are the types of the parameters for the function calls it couldn’t strictly determine. In static languages we do that while coding, I don’t see why that would be a big issue if one wants a static compiled code.

Is there such a thing as a small Julia-built binary? Even without static linking, my binaries are huge - minimum of about 160MB for trivial ones. For simple short-running tools, it’s far from ideal.

You’re referring to PackageCompiler binaries, which simply compile your code on top of the sysimage - and that sysimage is, by default, ~170MB on the typical Linux machine. I’m aiming for static compilation like what CUDAnative does for its kernels. Those kernels can be arbitrarily small, probably down to below a single page of memory (4KB) if the kernel doesn’t do anything too complicated. That’s the approach that I plan on taking.

4 Likes