Cross compile for aarch64 on Ubuntu

I’ve got the tool chain file fairly well figured out. The problem I run into is that the sysroot is at /usr/aarch64-linux-gnu, while the arm64 libs and includes are in /usr/lib/aarch64-linux-gnu and /usr/include/aarch64-linux-gnu, where CMake’s find_package doesn’t find them. How do I tell CMake about those? Is Ubuntu just weird in not also putting its arm64 packages into the sysroot?

Thanks!

Is this native compilation? This is an effect of Debian’s MultiArch support so that aarch64 packages don’t conflict with x86_64 packages. We might need some updates for that.

Cc: @kyle.edwards @brad.king

It’s an amd64 system, compiling for arm64/aarch64. I think Ubuntu could just install packages into /usr/aarch64-linux-gnu/{lib, include, bin}, but there’s probably a reason they don’t.

Anything I can do? I am not familiar with the CMake codebase at all.

Any workarounds I could use for now?

Thanks!

For reference, here’s my toolchain file. Setting CMAKE_INCLUDE_PATH et al didn’t work.

#
# CMake Toolchain file for crosscompiling on ARM.
#
# Target operating system name.
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_CROSSCOMPILING TRUE)

# Name of C compiler.
set(CMAKE_C_COMPILER "/usr/bin/aarch64-linux-gnu-gcc-8")
set(CMAKE_CXX_COMPILER "/usr/bin/aarch64-linux-gnu-g++-8")

# Where to look for the target environment. (More paths can be added here)
set(CMAKE_FIND_ROOT_PATH /usr/aarch64-linux-gnu)
set(CMAKE_INCLUDE_PATH  /usr/include/aarch64-linux-gnu)
set(CMAKE_LIBRARY_PATH  /usr/lib/aarch64-linux-gnu)
set(CMAKE_PROGRAM_PATH  /usr/bin/aarch64-linux-gnu)

# Adjust the default behavior of the FIND_XXX() commands:
# search programs in the host environment only.
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)

# Search headers and libraries in the target environment only.
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

This post may be of interest to you.

Thanks! I added the pkg-config option, but with CMAKE_SYSROOT set to /usr/aarch64-linux-gnu, the compiler test wouldn’t even work. Without it, it still can’t find the packages.

Hmm, I’m not sure without investigating more. I don’t have such a setup handy here to test myself. If you do find something, please feel free to report back here with any findings to help others in the future. (Of course, others may also show up here to help as well as their time permits.)

My workaround is to create a single sysroot by copying everything from /usr/{lib,include,bin}/aarch64-linux-gnu (and headers from /usr/include) to /usr/aarch64-linux-gnu. That’s pretty ugly. I was hoping CMake had support for how Ubuntu and Debian organize their multiarch setup.

Thinking out loud here: would it work with pkg-config? Ubuntu does provide it for aarch64, I just haven’t ever needed it for regular CMake builds. How would that work in CMake? Is that a common thing people do?

Alright, I figured it out. Here’s the toolchain file:

#
# CMake Toolchain file for crosscompiling on ARM.
#
# Target operating system name.
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)

# Name of C compiler.
set(CMAKE_C_COMPILER "/usr/bin/aarch64-linux-gnu-gcc-8")
set(CMAKE_CXX_COMPILER "/usr/bin/aarch64-linux-gnu-g++-8")

# Where to look for the target environment. (More paths can be added here)
set(CMAKE_FIND_ROOT_PATH /usr/aarch64-linux-gnu)
#set(CMAKE_SYSROOT /usr/aarch64-linux-gnu)

# Adjust the default behavior of the FIND_XXX() commands:
# search programs in the host environment only.
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)

# Search headers and libraries in the target environment only.
#set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
#set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
#set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE arm64)

I investigated CMAKE_LIBRARY_ARCHITECTURE, since that’s used to access libraries in /usr/lib/<arch>, thinking it hadn’t been set right. But it was set.

Reading the documentation of find_file and find_library, specifically the search strategy, clarified that it’ll search for libraries in the arch-specific directories first. It just didn’t in my case because I told it not to by setting set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY). My libs were obviously not in the root path, so this broke it all. Keeping that setting at its default BOTH, CMake looked in the right place immediately and found my aarch64 libs, and compiled for arm64 correctly.

I hope this is helpful to someone!

1 Like

Hi Christoph,

What I would do is set a variable to your sysroot, and then set definitions and linker flags with that:

set(TOOLCHAIN_SYSROOT ....)
set(TOOLCHAIN_AUXILIARY_PATH ....) # In case you need additional libraries linked

add_definitions("--sysroot=${TOOLCHAIN_SYSROOT}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${TOOLCHAIN_AUXILIARY_PATH} --sysroot=${TOOLCHAIN_SYSROOT}" CACHE INTERNAL "" FORCE)