Crosscompiling for rpi3b+, fails on juceaide

Hey.
I’m trying to set up a cross compile environment, for developing a gui app for my rpi3B+ (64 bit), but I’m running into some trouble.
My goal is to use vscode on a virtual machine to develop and build the application.

Here’s what I’ve got, using various guides:
I’ve installed debian11 on a virtual machine.
then I’ve run these commands:
(notice, these instructions are “generalized” - I have written the correct path, instead of “YOUR_PATH_TO/JUCE”, etc…)

sudo apt install ubuntu-dev-tools
wget -qO - https://archive.raspberrypi.org/debian/raspberrypi.gpg.key | gpg --import -
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 82B129927FA3303E
sudo apt update
wget -qO - https://ftp-master.debian.org/keys/release-11.asc | gpg --import -
mk-sbuild --arch=arm64 bullseye --debootstrap-mirror=http://httpredir.debian.org/debian/ --name=rpizero-bullseye --debootstrap-keyring "$HOME/.gnupg/pubring.kbx --merged-usr" --skip-proposed --skip-updates --skip-security
mkdir -p ~/opt
wget -qO- https://github.com/tttapa/docker-arm-cross-toolchain/releases/latest/download/x-tools-aarch64-rpi3-linux-gnu.tar.xz | tar xJ -C ~/opt
echo 'export PATH="$HOME/opt/x-tools/aarch64-rpi3-linux-gnu/bin:$PATH"' >> ~/.profile
sudo reboot
scp ~/opt/x-tools/aarch64-rpi3-linux-gnu/aarch64-rpi3-linux-gnu/sysroot/lib/libstdc++.so.6.0.30 RPi0:~
ssh RPi0 bash << 'EOF'
    sudo mkdir -p /usr/local/lib/aarch64-linux-gnu
    sudo mv libstdc++.so.6.0.30 $_
    sudo ldconfig
EOF
sudo mkdir -p /var/lib/schroot/chroots/rpizero-bullseye-arm64/usr/local/lib/aarch64-linux-gnu
sudo cp ~/opt/x-tools/aarch64-rpi3-linux-gnu/aarch64-rpi3-linux-gnu/sysroot/lib/libstdc++.so.6.0.30 $_
sudo schroot -c source:rpizero-bullseye-arm64 -u root -d / ldconfig

install vscode with extensions clangd and cmake tools
(also, since cmake hasnt been installed yet:
sudo apt install cmake)

in clangd extension settings, add the following as "Argument":
{
    "clangd.arguments": [
        "--compile-commands-dir=build",
        "-I/YOUR_PATH_TO/JUCE",
        "-I/YOUR_PATH_TO/JUCE/modules"
    ]
}

I then installed various libraries, both locally, and in the build environment:


sudo apt install libasound2-dev libjack-jackd2-dev \
    ladspa-sdk \
    libcurl4-openssl-dev  \
    libfreetype6-dev \
    libx11-dev libxcomposite-dev libxcursor-dev libxcursor-dev libxext-dev libxinerama-dev libxrandr-dev libxrender-dev \
    libwebkit2gtk-4.0-dev \
    libglu1-mesa-dev mesa-common-dev
sudo sbuild-apt rpizero-bullseye-arm64 apt-get install libasound2-dev libjack-jackd2-dev \
    ladspa-sdk \
    libcurl4-openssl-dev  \
    libfreetype6-dev \
    libx11-dev libxcomposite-dev libxcursor-dev libxcursor-dev libxext-dev libxinerama-dev libxrandr-dev libxrender-dev \
    libwebkit2gtk-4.0-dev \
    libglu1-mesa-dev mesa-common-dev

I installed vscode on the virtual machine, and installed the clangd extension, and the cmake-tools extension.

I then cloned the JUCE library from github, built Projucer locally on the VM, and used it to create a new project - so far I just tried making a simple gui app, and only created the Main.cpp file, like in the tutorial, since I wanted to simply see if I could get that to compile.

In the root folder of the project I have this CMakeLists.txt file:

cmake_minimum_required(VERSION 3.12)

if(NOT TARGET juceaide)
  set(JUCE_FORCE_USE_LOCAL_COPY ON)
  set(CMAKE_TOOLCHAIN_FILE_BACKUP ${CMAKE_TOOLCHAIN_FILE})
  set(CMAKE_TOOLCHAIN_FILE "")
  set(CMAKE_C_COMPILER_BACKUP ${CMAKE_C_COMPILER})
  set(CMAKE_C_COMPILER "")
  set(CMAKE_CXX_COMPILER_BACKUP ${CMAKE_CXX_COMPILER})
  set(CMAKE_CXX_COMPILER "")
  add_subdirectory(/path/home/anders/opt/JUCE/extras/Build ${CMAKE_BINARY_DIR}/juceaide)
  set(CMAKE_TOOLCHAIN_FILE ${CMAKE_TOOLCHAIN_FILE_BACKUP})
  set(CMAKE_C_COMPILER ${CMAKE_C_COMPILER_BACKUP})
  set(CMAKE_CXX_COMPILER ${CMAKE_CXX_COMPILER_BACKUP})
endif()


project(tut1 VERSION 0.0.1)

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Set the root path of your chroot environment
set(CHROOT_ROOT_PATH "/var/lib/schroot/chroots/rpizero-bullseye-arm64")
set(CMAKE_FIND_ROOT_PATH "${CHROOT_ROOT_PATH}")

# Include the cross-compilation toolchain
include(toolchain.cmake)

# Replace this path with the path to your JUCE installation
set(JUCE_PATH "/home/anders/opt/JUCE")

# Add the JUCE library
add_subdirectory(${JUCE_PATH} JUCE)

# Add the main.cpp file from the "Source" subfolder
add_executable(${PROJECT_NAME} Source/Main.cpp)

# Add JUCE as a dependency
target_link_libraries(${PROJECT_NAME} PRIVATE
    juce::juce_core
    juce::juce_data_structures
    juce::juce_events
    juce::juce_graphics
    juce::juce_gui_basics
    juce::juce_gui_extra
)

# Add include directories
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/JuceLibraryCode)

# Enable JUCE features
target_compile_definitions(${PROJECT_NAME} PRIVATE
    JUCE_WEB_BROWSER=0
    JUCE_USE_CURL=0
    JUCE_APPLICATION_NAME_STRING="$<TARGET_PROPERTY:${PROJECT_NAME},PROJECT_NAME>"
    JUCE_APPLICATION_VERSION_STRING="$<TARGET_PROPERTY:${PROJECT_NAME},PROJECT_VERSION>"
)

# Set up the binary output directory
set_target_properties(${PROJECT_NAME} PROPERTIES
    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin"
)

and I also have an “aarch64-rpi3-linux-gnu.cmake” file:

# https://cmake.org/cmake/help/book/mastering-cmake/chapter/Cross%20Compiling%20With%20CMake.html

# Cross-compilation system information
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)

# The sysroot contains all the libraries we might need to link against and 
# possibly headers we need for compilation
set(CMAKE_SYSROOT /var/lib/schroot/chroots/rpizero-bullseye-arm64)

include_directories(SYSTEM "${CMAKE_SYSROOT}/usr/include")
include_directories(SYSTEM "${CMAKE_SYSROOT}/usr/include/X11")


set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) 
set(CMAKE_LIBRARY_ARCHITECTURE aarch64-linux-gnu)
set(CMAKE_STAGING_PREFIX $ENV{HOME}/RPi-dev/staging-aarch64-rpi3)

# Set the compilers for C, C++ and Fortran
set(RPI_GCC_TRIPLE "aarch64-rpi3-linux-gnu")
set(CMAKE_C_COMPILER ${RPI_GCC_TRIPLE}-gcc CACHE FILEPATH "C compiler")
set(CMAKE_CXX_COMPILER ${RPI_GCC_TRIPLE}-g++ CACHE FILEPATH "C++ compiler")
set(CMAKE_Fortran_COMPILER ${RPI_GCC_TRIPLE}-gfortran CACHE FILEPATH "Fortran compiler")

# Set the architecture-specific compiler flags
set(ARCH_FLAGS "-mcpu=cortex-a53+crc+simd")
set(CMAKE_C_FLAGS_INIT ${ARCH_FLAGS})
set(CMAKE_CXX_FLAGS_INIT ${ARCH_FLAGS})
set(CMAKE_Fortran_FLAGS_INIT ${ARCH_FLAGS})

# Don't look for programs in the sysroot (these are ARM programs, they won't run
# on the build machine)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# Only look for libraries, headers and packages in the sysroot, don't look on 
# the build machine
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)

and then in a “.vscode” folder, I have this “settings.json” file:

{
    "cmake.configureSettings": {
        "CMAKE_EXPORT_COMPILE_COMMANDS": "TRUE",
        "CMAKE_BUILD_TYPE": "Debug",
        "CMAKE_TOOLCHAIN_FILE": "${workspaceFolder}/aarch64-rpi3-linux-gnu.cmake"
    }
}

Now when I try to configure the project, using the cmake-tools (ctrl + shift + p → CMake: Configure), I get an error when it tries to build juceaide, saying it can’t find X11/Xlib.h:

[cmake]   [ 30%] Building CXX object
[cmake]   extras/Build/juceaide/CMakeFiles/juceaide.dir/__/__/__/modules/juce_gui_basics/juce_gui_basics.cpp.o
[cmake] 
[cmake] 
[cmake]   In file included from
[cmake]   /home/anders/opt/JUCE/modules/juce_gui_basics/juce_gui_basics.cpp:46:
[cmake] 
[cmake]   /home/anders/opt/JUCE/modules/juce_gui_basics/juce_gui_basics.h:326:12:
[cmake]   fatal error: X11/Xlib.h: No such file or directory
[cmake] 
[cmake]     326 |   #include <X11/Xlib.h>
[cmake]         |            ^~~~~~~~~~~~
[cmake] 
[cmake]   compilation terminated.
[cmake] 
[cmake]   gmake[2]: ***
[cmake]   [extras/Build/juceaide/CMakeFiles/juceaide.dir/build.make:108:
[cmake]   extras/Build/juceaide/CMakeFiles/juceaide.dir/__/__/__/modules/juce_gui_basics/juce_gui_basics.cpp.o]
[cmake]   Error 1
[cmake] 
[cmake]   gmake[1]: *** [CMakeFiles/Makefile2:181:
[cmake]   extras/Build/juceaide/CMakeFiles/juceaide.dir/all] Error 2
[cmake] 
[cmake]   gmake: *** [Makefile:149: all] Error 2

However, the library is installed, both locally, and in the build environment.

I am not very well aquainted with cmake, so I need some help here.

Regards.
Anders

This CMake directive:

… means that this error will happen because the path the compiler will end up using to find the header is going to be something like “/usr/include/X11/X11/XLib.h” …

So - either you can remove the “X11/” part from the code on line 326 of juice_gui_basics.h and you should be able to proceed.

OR:

Add this line to your “aarch64-rpi3-linux-gnu.cmake” file:

include_directories(SYSTEM "${CMAKE_SYSROOT}/usr/include/")

Note that there are some gotchas with paths to the X11 development headers when dealing with ARM vs. X86 Linux-based systems, its a fairly common issue for CMake files to get confused by this … just add the path above and things should compile. (BTW, I’ve built on rpi3b+ fine in the past, and had exactly this issue…)

EDIT: I just saw that indeed that path is already included in the aarch64-rpi3-linux-gnu.cmake file, so the next thing I’d check is that the CMAKE_SYSROOT is what you expect it to be …