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:
- Cross-compile the target CPU architecture (32-bit or 64-bit).
- The operating system on which the cross-compilation occurs.