How to Cross-compile the GO Program with ARM Architecture on Ubuntu

Keywords: Operation & Maintenance Linux Ubuntu sudo SHA1

We all know that when CGO is not involved, cross-compilation of Go s is very simple and requires only the corresponding GOOS and GOARCH to be set, but when CGO is involved, the problem becomes a bit complicated because you need to specify a specific GCC.

For example, if you want to cross-compile a dynamic library with CGO on Ubuntu and the target CPU architecture is arm, what should we do?

Sample Code

# shared.go
package main

import "C"

//export Sum
func Sum(a, b int) int {
    return a + b
}

func main(){}

This code uses CGO and then exposes a Sum method to add two integers together.

Compile 32-bit arm

Because CGO compilation is turned on by setting CGO_ENABLED=1, the following commands are executed:

CGO_ENABLED=1 GOOS=linux GOARCH=arm go build -buildmode=c-shared -o share.so 

Unfortunately, the command failed: gcc: error: unrecognized command line option'-marm'.

As I mentioned at the beginning, cross-compiling CGO requires selecting a specific arm cross-compilation tool, whereas 32-bit arms compiled on Ubuntu can use gcc-arm-linux-gnueabihf with the following installation commands:

sudo apt-get update
sudo apt-get install gcc-arm-linux-gnueabihf

After installation, specify CC recompile:

CGO_ENABLED=1 GOOS=linux GOARCH=arm CC=arm-linux-gnueabihf-gcc go build -buildmode=c-shared -o share.so 

The command ran successfully, and a file called share.so was generated in the directory. Viewing its properties with the file command, you can confirm that it is indeed arm 32.

share.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, BuildID[sha1]=7b23579ddcbebdfc8f4b68512859661a45d66996, not stripped

Compile 64-bit arm

When cross-compiling, not only GCC is chosen for the platform, but also for the number of bits in the operating system. Therefore, 64-bit GCC needs to be selected differently. Here, gcc-linaro-5.3-2016.02-x86_64_aarch64-linux-gnu.tar.xz is recommended.

Installation command:

wget https://releases.linaro.org/components/toolchain/binaries/5.3-2016.02/aarch64-linux-gnu/gcc-linaro-5.3-2016.02-x86_64_aarch64-linux-gnu.tar.xz 

tar xvf gcc-linaro-5.3-2016.02-x86_64_aarch64-linux-gnu.tar.xz -C /usr/lib/

echo 'export PATH="$PATH:/usr/lib/gcc-linaro-5.3-2016.02-x86_64_aarch64-linux-gnu/bin"' >> ~/.bashrc

source ~/.bashrc

Installation is complete and the compile command is re-executed:

CGO_ENABLED=1 GOOS=linux GOARCH=arm64 CC=aarch64-linux-gnu-gcc-5.3.1 go build -buildmode=c-shared -o share.so 

The compilation was successful and resulted in a share.so file, which we also used to view meta-information as:

share.so: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, BuildID[sha1]=5b0e7ff7c3af178039a7b934df8ca3e7572ab5b5, not stripped

So far, we have successfully cross-compiled arm and arm64 versions of CGO programs on Ubuntu systems.

summary

When Go cross-compilation involves CGO, specifying only GOOS and GOARCH is not enough, and the corresponding GCC version needs to be specified through the CC parameter, which in turn depends on the current system and the target architecture:

  1. Cross-compile the target CPU architecture (32-bit or 64-bit).
  2. The operating system on which the cross-compilation occurs.

Posted by Deadman2 on Wed, 27 Nov 2019 15:29:44 -0800