Adapting your software to run at the edge
Something important while designing an edge computing system is to choose the processor architecture to build your software. One popular architecture because of the lower consumption for computing is ARM, but if ARM is the selected architecture, it is necessary to transform your current code in most of the cases from x86_64 (Intel) to ARM (ARMv7 such as RI and ARM such as AWS Graviton2 instances). The following subsections include short guides to perform the process to convert from one platform to another; this process is called cross-compiling. With this, you will be able to run your software on ARM devices using Go, Python, Rust, and Java. So, let’s get started.
Adapting Go to run on ARM
First, it’s necessary to install Go on your system. Here are a couple of ways to install Go.
Installing Go on Linux
To install Go on Linux, execute the following steps:
- Download and untar the Go official binaries:
$ wget https://golang.org/dl/go1.15.linux-amd64.tar.gz $ tar -C /usr/local -xzf go1.15.linux-amd64.tar.gz
- Set the environment variables to run Go:
$ mkdir $HOME/go
- Set your
GOPATH
in the configuration file of your terminal with the following lines.~/.profile
is a common file to set these environment variables; let’s modify the.profile
file:$ export PATH=$PATH:/usr/local/go/bin $ export GOPATH=$HOME/go
- Load the new configuration using the following command:
$ . ~/.profile $ mkdir $GOPATH/src
- (Optional). If you want to, you can set these environment variables temporarily in your terminal using the following commands:
$ export PATH=$PATH:/usr/local/go/bin $ export GOPATH=$HOME/go
- To check whether
GOPATH
is configured, run the following command:$ go env GOPATH
Now, you are ready to use Go on Linux. Let’s move to this installation using a Mac.
Installing Go on a Mac
To install Go on a Mac, execute the following steps:
- Install Homebrew (called
brew
) with the following command:$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
- Once it is installed, install Go with
brew
:$ brew install go
Important Note
To find out how to install brew
, you can check the official page at https://brew.sh.
Cross-compiling from x86_64 to ARM with Go
To cross-compile from x86_64 to ARM, execute the following steps:
- Create a folder to store your code:
$ cd ~/ $ mkdir goproject $ cd goproject
- Create an initial Go configuration to install external Go libraries outside the
GOPATH
command; for this, execute the next command:$ go mod init main
- Create the
example.go
file withHello World
as its contents:$ cat << EOF > example.go package main import "fmt" func main() { fmt.Println("Hello World") } EOF
- Assuming that your environment is under x86_64 and you want to cross-compile for ARMv7 support, execute the following commands:
$ env GOOS=linux GOARM=7 GOARCH=arm go build example.go
Use the next line for ARMv8 64-bit support:
$ env GOOS=linux GOARCH=arm64 go build example.go
Important Note
If you want to see other options for cross-compiling, see https://github.com/golang/go/wiki/GoArm.
Set the execution permissions for the generated binary:
$ chmod 777 example $ ./example
- Copy the generated binary to your ARM device and test if it works.
In the next section, we will learn how to adapt Rust to run on ARM.
Adapting Rust to run on ARM
First, it’s necessary to install Rust on your system. Here are a couple of ways to install Rust.
Installing Rust on Linux
To install Rust on Linux, execute the following steps:
- Install Rust by executing the following command in the terminal:
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
- Set the path for Rust in the configuration file of your terminal. For example, if you are using Bash, add the following line to your
.bashrc
:$ export PATH=$PATH:$HOME/.cargo/bin
Installing Rust on a Mac
To install Rust on a Mac, execute the following steps:
- Install Homebrew with the following command:
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
- Once it is installed, install
rustup
withbrew
:$ brew install rustup-init
- Run the
rustup
command to install Rust and all the necessary tools for Rust with the following command:$ rustup-init
- Set your terminal environment variables by adding the following line to your terminal configuration file:
$ export PATH=$PATH:$HOME/.cargo/bin
Important Note
Mac users often use the ZSH terminal, so they have to use .zshrc
. If you are using another terminal, look for the proper configuration file or the generic /etc/profile
.
Cross-compiling from x86_64 to ARMv7 with Rust on a Mac
To cross-compile from x86_64 to ARM, execute the following steps:
- Install the complements to match the compiler and environment variables for ARMv7 architecture on your Mac; for this, execute the following command:
$ brew tap messense/macos-cross-toolchains
- Download the support for ARMv7 for cross-compiling by executing the following command:
$ brew install armv7-unknown-linux-gnueabihf
- Now set the environment variables:
$ export CC_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-gcc $ export CXX_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-g++ $ export AR_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-ar $ export CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=armv7-unknown-linux-gnueabihf-gcc
- Create a folder to store your code:
$ cd ~/ $ mkdir rustproject $ cd rustproject
- Create an initial
Hello World
project with Rust:$ cargo new hello-rust $ cd hello-rust
The generated Rust code will look like this:
fn main() { println!("Hello, world!"); }
The source code will be located at src/main.rs
.
- Add the support for ARMv7:
$ rustup target add armv7-unknown-linux-gnueabi
- Build your software:
$ cargo build --target=armv7-unknown-linux-gnueabi
- Copy the binary file into your device and test whether it works:
$ cargo build --target=armv7-unknown-linux-gnueabi
- The generated binary will be inside the
target/armv7-unknown-linux-gnueabi/hello-rust
folder. - Now copy your binary into your device and test whether it works.
Important Note
For more options for cross-compiling with Rust, check out https://doc.rust-lang.org/nightly/rustc/platform-support.html and https://rust-lang.github.io/rustup/cross-compilation.html. For the toolchain for Mac and AArch64 (64-bit ARMv8), check out aarch64-unknown-linux-gnu
inside the repository at https://github.com/messense/homebrew-macos-cross-toolchains.
Adapting Python to run on ARM
First, it is necessary to install Python on your system. There are a couple of ways of doing this.
Installing Python on Linux
To install Python, execute the following steps:
- Update your repositories:
$ sudo apt-get update
- Install Python 3:
$ sudo apt-get install -y python3
Install Python on a Mac
To install Python on a Mac using Homebrew, execute the following steps:
- Check for your desired Python version on brew’s available version list:
$ brew search python
- Let’s say that you choose Python 3.8; you have to install it by executing the following command:
$ brew install python@3.8
- Test your installation:
$ python3 --version
Cross-compiling from x86_64 to ARM with Python
Python is very important and one of the most popular languages now, and it is commonly used for AI and ML applications. Python is an interpreted language; it needs a runtime environment (such as Java) to run the code. In this case, you must install Python as the runtime environment. It has similar challenges running code as Java but has other challenges too. Sometimes, you need to compile libraries from scratch to use it. The standard Python libraries currently support ARM, but the issue is when you want something outside those standard libraries.
As a basic example, let’s run Python code across different platforms by executing the following steps:
- Create a basic file called
example.py
:def main(): print("hello world") if __name__ == "__main__": main()
- Copy
example.py
to your ARM device. - Install Python 3 on your ARM device by running the following command:
$ sudo apt-get install -y python3
- Run your code:
$ python3 example.py
Adapting Java to run on ARM
When talking about Java to run on ARM devices, it is a little bit different. Java uses a hybrid compiler – in other words, a two-phase compiler. This means that it generates an intermediate code called bytecode and is interpreted by a Java Virtual Machine (JVM). This bytecode is a cross-platform code and, following the Java philosophy of compile once and run everywhere, it means that you can compile using the platform you want, and it will run on any other platform without modifications. So, let’s see how to perform cross-compiling for a basic Java program that can run on an ARMv7 and an ARMv8 64-bit device.
Installing Java JDK on Linux
To install Java on Linux, execute the following commands:
- Update the current repositories of Ubuntu:
$ sudo apt-get update
- Install the official JDK 8:
$ sudo apt-get install openjdk-8-jre
- Test whether
javac
runs:$ javac
Installing Java JDK on a Mac
If you don’t have Java installed on your Mac, follow the next steps:
- (Optional) Download Java JDK from the following link and choose the architecture that you need, such as Linux, Mac, or Windows: https://www.oracle.com/java/technologies/javase-downloads.html.
- (Optional) Download and run the installer.
To test whether Java exists or whether it was installed correctly, run the following command:
$ java -version
- Test whether the compiler is installed by executing the following command:
$ javac -v
Cross-compiling from x86_64 to ARM with Java
Java is a language that generates an intermediate code called bytecode, which runs on the JVM. Let’s say that you have a basic code in a file called Example.java
:
class Example { public static void main(String[] args) { System.out.println("Hello world!"); } }
To execute your code, follow these steps:
- To compile it, use the following command:
$ javac Example.java
This will generate the intermediate code in a file called Example.class
, which can be executed by the JVM. Let’s do this in the next step.
- To run the bytecode, execute the following command:
$ java Example
- Now, copy
Example.class
to another device and run it with the proper JVM using thejava
command.