julia on raspbian buster – raspberry pi 4b

According to Wikipedia, “Julia is a high-level general-purpose dynamic programming language designed for high-performance numerical analysis and computational science. It is also useful for low-level systems programming, as a specification language, and for web programming: both for server web use and for web client programming.”

As a consequence of that definition I’ve been trying to get Julia to run on the Raspberry Pi 4b/2GB under Raspbian Buster. I’ve succeeded. It’s been an interesting challenge. The version I’m using right now is 1.2.0 RC3. How I got to running that version is an interesting tale…

I started trying to run the latest Julia release, 1.1.1. I looked on the Julia website (https://julialang.org/), but discovered that there was no version of 1.1.1 for 32-bit ARM, only 64-bit. I tried to build a native copy, first by downloading the source tar file, then by cloning a copy of 1.1.1 from Julia’s GitHub repository. Both times I ran into issues.

The first issue was the lack of a ‘-latomic’ linker switch in the last Makefile of the build sequence that would have created the executable. That was something of a head scratcher until I found the right Makefile to add the necessary linker switch modification to, and then the build job finished and produced an executable.

The second issue, and the last straw, was running ‘make test’ to execute a full suite of SWITs. Tests seemed to succeed at first, then tests started to fail because certain library entry points couldn’t be found, and then all the tests after that seemed to fail completely with no real reason being printed out. (In hindsight I’m wondering if this is an issue with Julia 1.1.1 in general, and that’s why there is no official ARM 32-bit version on the Julia website).

This happened with both the tarball as well as the Git cloned repo sources. After the SWIT failures I wiped away the build areas and went looking back on the Julia site for any other pre-built binaries. That’s when I found ARM 32-bit releases for the long term support version, 1.0.4, and an early release candidate for the next Julia release, 1.2.0 RC3. I grabbed both and untarred both and started to work directly with both.

At this point you’re correct to ask why I didn’t install Julia from the Raspbian Buster repo. The answer is that the version in the repo is 1.0.3, which isn’t even the latest LTS release. It’s another example of why I stay away from the Debian repos in general; many software tools are notoriously behind the regular upstream releases. The Raspbian/Debian Buster release has made strong strides to “keep up” version wise with applications, especially with Python and GCC. With Python, Buster released version 3.7.3, which at the time of release was the most current. And GCC on Buster is at version 8.3, which is quite remarkable considering what was available on Stretch. In particular, GCC 8.3 supports up to the C++17 standard, and on the C side, its back-end ARM binary generation appears to be much better than any prior release. This efficient code generation has manifested itself in Buster on ARM as faster to much faster execution. Those are considered first tier languages, while Julia isn’t a first tier language, not yet. So I go out hunting. Fortunately, installing Julia (as well as Go and Rust) means a simple local install (un-tar) and execution in-place.

Once in place and added to my path, I then started to write Julia code. I’m certainly no Julia coding expert, so don’t expect any blazing insights. To get me going I’ve been looking at Julia By Example (https://juliabyexample.helpmanual.io/), where I’m downloading examples and then editing them inside of Vim with Julia plugins.

I was forced to use Vim with plugins because when I tried to follow directions and install the Jupyter/IJulia notebook extension, it never worked. Every time I tried to use IJulia in a web-based notebook, it insisted on downloaded the x86 version of Python and execute that instead of using the system ARM version, and of course it failed. To add insult to injury IJulia wanted to use an older Python release, 3.7.1. I couldn’t find anything on the web that told me how to stop this behavior, so I’ve given that up as well, using Vim. As a side note I even tried to use Visual Studio Code and then Atom with Juno, but they required building from sources on Raspbian, and of course following those directions led to many lost hours and many tears on my end. And so I use Vim because it just works.

What follows are some of the examples from Julia By Example, because even the examples didn’t work out-of-the box and required some tweaking to work with both versions 1.0.4 and 1.2.0 RC3 on Raspbian.

For functions.jl I added line 1 and then set the execution bit so that the script would execute like every other script under Linux. I had to add line 3 to import Printf to support the macro @printf, and then in line 28 I had to fully reference @printf. That’s nothing special, per se, as full qualification for functions are in many language. But it’s interesting, and I had to do it everywhere.

#!/usr/bin/env julia#import Printf# [function](http://docs.julialang.org:8000/en/latest/manual/functions/#functions) to calculate the volume of a spherefunction sphere_vol(r)# julia allows [Unicode names](http://docs.julialang.org/en/latest/manual/unicode-input/) (in UTF-8 encoding)# so either "pi" or the symbol π can be usedreturn 4/3*pi*r^3end# functions can also be defined more succinctlyquadratic(a, sqr_term, b) = (-b + sqr_term) / 2a# calculates x for 0 = a*x^2+b*x+c, [arguments types](TODO: links) can be defined in function definitionsfunction quadratic2(a::Float64, b::Float64, c::Float64)# unlike other languages 2a is equivalent to 2*a# a^2 is used instead of a**2 or pow(a,2)sqr_term = sqrt(b^2-4a*c)r1 = quadratic(a, sqr_term, b)r2 = quadratic(a, -sqr_term, b)# multiple values can be returned from a function using tuples# if the [return](http://docs.julialang.org:8000/en/latest/manual/functions/#the-return-keyword) keyword is omitted, the last term is returnedr1, r2endvol = sphere_vol(3)# @printf allows number formatting but does not automatically append the \n to statements, see belowPrintf.@printf "volume = %0.3f\n" vol #> volume = 113.097quad1, quad2 = quadratic2(2.0, -2.0, -12.0)println("result 1: ", quad1)#> result 1: 3.0println("result 2: ", quad2)#> result 2: -2.0

The file formatting_converting_strings.jl builds on the first script, with line 1 setting it up as a stand-alone script and line 4 importing Printf. Line 8 is interesting, where a string representation of e is converted into a float. The original script called a float function, but in order to make it work I used parse, which is the same interestingly for line 11 converting a string representation into an integer. The rest of the highlighted lines are the use of @printf, especially line 19, where I had to again fully qualify @sprintf.

Quite frankly these are minor issues, and probably represent changes between the pre-release 1.0 versions of Julia and 1.0 and later. I say this because I had to do the same changes for both 1.0.4 and 1.2.0 RC3. I’m going back to try these on my MacBook which has Anaconda installed and working, and add Julia into the mix.

#!/usr/bin/env julia## strings can be converted using [float](http://julia.readthedocs.org/en/latest/stdlib/base/#Base.float) and [int](http://julia.readthedocs.org/en/latest/stdlib/base/#Base.int):import Printfe_str1 = "2.718"# e = float(e_str1)e = parse(Float64, e_str1)println(5e)#> 13.5914num_15 = parse(Int, "15")println(3num_15)#> 45# numbers can be converted to strings and formatted using [printf](http://julia.readthedocs.org/en/latest/stdlib/base/#Base.@printf)Printf.@printf "e = %0.2f\n" e#> 2.718# or to create another string [sprintf](http://julia.readthedocs.org/en/latest/stdlib/base/#Base.@sprintf)e_str2 = Printf.@sprintf("%0.3f", e)# to show that the 2 strings are the sameprintln("e_str1 == e_str2: $(e_str1 == e_str2)")#> e_str1 == e_str2: true# available number format characters are [f, e, g, c, s, p, d](https://github.com/JuliaLang/julia/blob/master/base/printf.jl#L15):# (pi is a predefined constant; however, since its type is # "MathConst" it has to be converted to a float to be formatted)Printf.@printf "fix trailing precision: %0.3f\n" float(pi)#> fix trailing precision: 3.142Printf.@printf "scientific form: %0.6e\n" 1000pi#> scientific form: 3.141593e+03# g is not implemented yetPrintf.@printf "a character: %c\n" 'α'#> a character: αPrintf.@printf "a string: %s\n" "look I'm a string!"#> a string: look I'm a string!Printf.@printf "right justify a string: %50s\n" "width 50, text right justified!"#> right justify a string:width 50, text right justified!Printf.@printf "a pointer: %p\n" 100000000#> a pointer: 0x0000000005f5e100Printf.@printf "print a integer: %d\n" 1e10#> print an integer: 10000000000

I will admit that Julia is a lot faster now than it was when 1.0 was first released. That release was so slow I deleted it and stopped using on the Raspberry Pi 3B+ under Raspbian Stretch. That was last year. Who knows what has transpired since that initial release. But if I’m going to determine what the promise is of Julia on the Raspberry Pi, then the convergence of the Raspberry Pi 4B with Raspbian Buster makes that a much better platform to explore, let alone run, Julia.