CMake cross compile - c++

I'm having problem with my cmake cross compiler project.
My cross compiler did not find used libraries. I setup my cross compiler with this tutorial Cross Compiler.
Now i need libs they are installed on my RaspberryPi. I have snychronised my /lib and /usr direcotry from Pi to my Computer in /opt/cross/rasp. This is my Toolchain file:
# this one is important
SET(CMAKE_SYSTEM_NAME Linux)
#this one not so much
SET(CMAKE_SYSTEM_VERSION 1)
# specify the cross compiler
SET(CMAKE_C_COMPILER
/opt/cross/x-tools/arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi-gcc)
SET(CMAKE_CXX_COMPILER
/opt/cross/x-tools/arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi-g++)
# where is the target environment
SET(CMAKE_FIND_ROOT_PATH /opt/cross/rasp)
# search for programs in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
But when i try to compile my program i get following Linking Error:
/opt/cross/x-tools/arm-unknown-linux-gnueabi/lib/gcc/arm-unknown-linux-gnueabi/4.9.1/../../../../arm-unknown-linux-gnueabi/bin/ld: warning: libltdl.so.7, needed by /opt/cross/rasp/usr/local/lib/libgphoto2.so, not found (try using -rpath or -rpath-link)
/opt/cross/x-tools/arm-unknown-linux-gnueabi/lib/gcc/arm-unknown-linux-gnueabi/4.9.1/../../../../arm-unknown-linux-gnueabi/bin/ld: warning: libexif.so.12, needed by /opt/cross/rasp/usr/local/lib/libgphoto2.so, not found (try using -rpath or -rpath-link)
On my RaspberrPi is compiling without errors possible.

The problem seems link to a misinterpretation of etc/ld.so.conf see fixing-rpath-link-issues-with-cross-compilers
In order to add the missing rpath-link, you can append to the toolchain cmake file :
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,-rpath-link=/opt/cross/rasp/lib/arm-linux-gnueabihf:/opt/cross/rasp/usr/lib/arm-linux-gnueabihf")

I believe your cross-compile linker needs a --sysroot change. In the toolchain file you can use:
set(CMAKE_SYSROOT "/opt/cross/rasp")
Should anyone be looking for another reference, aside from the original question, I recommend reading through the ARM cross-compile guide I wrote for Takeoff Technical:
https://takeofftechnical.com/x-compile-cpp-bbb

Related

Missing CMAKE_ASM_NASM_COMPILER when compiling gRPC with MS visual studio

I am trying to build gRPC C++ (1.48.0) with Visual Studio 2022 on Windows 10. It's a CMake build (cmake 3.22.22011901-MSVC_2)
I was able to build everything else but am stuck at BoringSSL. The relevant CMakeList is trying to enable_language(ASM_NASM). Context below:
if(NOT OPENSSL_NO_ASM)
if(UNIX)
enable_language(ASM)
# Clang's integerated assembler does not support debug symbols.
if(NOT CMAKE_ASM_COMPILER_ID MATCHES "Clang")
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Wa,-g")
endif()
# CMake does not add -isysroot and -arch flags to assembly.
if(APPLE)
if(CMAKE_OSX_SYSROOT)
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -isysroot \"${CMAKE_OSX_SYSROOT}\"")
endif()
foreach(arch ${CMAKE_OSX_ARCHITECTURES})
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -arch ${arch}")
endforeach()
endif()
else()
set(CMAKE_ASM_NASM_FLAGS "${CMAKE_ASM_NASM_FLAGS} -gcv8")
enable_language(ASM_NASM)
endif()
endif()
It gives me CMake Error: "No CMAKE_ASM_NASM_COMPILER could be found."
I don't know enough about compilers / assemblers, and why boringSSL would need a specific one (which none of the other modules needed including gRPC).
What is the recommended way to fix this?
To answer at least some of my questions for my future self, and others who are at a similar point in the journey.
NASM is an assembly compiler (assembler). BoringSSL has some assembly language code, which is why it needs an assembly compiler (and gRPC or other modules don't). I'll let someone else opine on why NASM and not some other assembler.
To fix the issue, you have to download/install the relevant NASM executable from here. I found it easier to download the exe, place it in a folder, add that folder to the PATH and set another env variable ASM_NASM with the name of nasm.exe.
Once I did that, boringSSL and the whole gRPC compiled quite smoothly.

CMake find_* not searching subdirectories

I have been trying for quite some time to get my cross-compile toolchain from my WSL Ubuntu to RasberryPi working.
Since the GCC Version of my RaspberryPi 4B is 8.3.0, I have most recently tried using the Buster toolchain from here.
My current folder structure looks like this:
Test
-> CMakeLists.txt
-> main.cpp
Toolchain
-> arm-linux-gnueabihf
-> bin
-> include
-> lib
-> libexec
-> share
raspi_root
-> lib
-> usr
The Test folder contains a simple test project to get the toolchain working. The real target project is a bit larger. The toolchain is the cross-compiler toolchain downloaded from the repository and finally the raspi_root folder is a copy from the lib and usr folders from the Raspberry Pi.
The main.cpp looks pretty basic:
#include <iostream>
#include <bluetooth>
int main(int argc, char** argv)
{
std::cout << "Hello World" << std::endl;
}
Note that it includes the bluetooth header as this is one of the libraries I am having troubles with.
My CMakeLists.txt looks like this:
set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
SET(CMAKE_SYSTEM_NAME Linux)
set(COMPILER_PREF "/home/user/workspace/toolchain/bin/arm-linux-gnueabihf-")
SET(CMAKE_C_COMPILER "${COMPILER_PREF}gcc")
set(CMAKE_CXX_COMPILER "${COMPILER_PREF}g++")
set(SYSROOT "${SOURCE_DIR}/../raspi_root")
set(CMAKE_FIND_ROOT_PATH "${SYSROOT}")
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
cmake_minimum_required(VERSION 3.0) # setting this is required
set(project_target Test)
project(${project_target}) # this sets the project name
set(SOURCES main.cpp)
find_library(BLUETOOTH bluetooth REQUIRED)
add_executable(${project_target} ${SOURCES})
set_property(TARGET ${project_target} PROPERTY CXX_STANDARD 17)
target_link_libraries(${project_target} PUBLIC
# ${SYSROOT}/usr/lib/arm-linux-gnueabihf/libbluetooth.so
${BLUETOOTH}
)
I tried to keep it as simple as possible to only get it to compile my hello world program with the toolchain and link the bluetooth library to get it working on my Raspberry Pi.
Now the following problem occurs:
Wenn I do cmake . it does not find the bluetooth library files:
Please set them or make sure they are set and tested correctly in the CMake files:
BLUETOOTH
linked by target "Test" in directory /home/user/workspace/Test
They are there right under ${SYSROOT}/usr/lib/arm-linux-gnueabihf
Only libraries in traditional directories like ${SYSROOT}/usr/lib or ${SYSROOT}/lib are found. When I create a symlink from one of those directories to libbluetooth.so, cmake appears to find the library although later on when linking I get additional errors.
I also tried replacing find_library by putting the complete library path under target_link_libraries but then the library is found but the headers of course are missing. Those would have to be included seperately I suppose.
However, my question is, why is CMake's find_* function not browsing through further subdirectories? This also happens when linking boost-libraries. find_package(boost) finds the headers but does not link the libraries.
___ EDIT: ___
Thanks to Tsyvarev I could successfully compile and execute my hello world programm. Now for the next step I wanted to include the boost thread library which caused the most problems in my other project.
So I added #include <boost/thread.hpp> to my main.cpp and find_package(Boost COMPONENTS thread REQUIRED), ${Boost_INCLUDE_DIRS} to the target_include_directories and ${Boost_LIBRARIES} to the target_link_libraries in my CMakeLists.txt. Now it finds my libraries with cmake . -DCMAKE_TOOLCHAIN_FILE=Toolchain and generates build files. But with make I get the following linking errors:
<path to toolchain linker>/ld: warning: librt.so.1, needed by ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so, not found (try using -rpath or -rpath-link)
<path to toolchain linker>/ld: warning: libpthread.so.0, needed by ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so, not found (try using -rpath or -rpath-link)
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_setspecific#GLIBC_2.4'
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_condattr_setclock#GLIBC_2.4'
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_key_create#GLIBC_2.4'
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_join#GLIBC_2.4'
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_detach#GLIBC_2.4'
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_getspecific#GLIBC_2.4'
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_create#GLIBC_2.4'
<path to toolchain linker>/ld: /home/felix/workspace/raspi_root/usr/lib/arm-linux-gnueabihf/libboost_chrono.so: undefined reference to `clock_gettime#GLIBC_2.4'
I figure the undefined references will be resolved once the libraries are found correctly? CMakeCache.txt says the found thread library is libpthread.a not libpthread.so. Also when running make VERBOSE=1 this is the linking command (with breaks for readability):
/home/felix/workspace/toolchain/bin/arm-linux-gnueabihf-g++
-rdynamic CMakeFiles/Test.dir/main.cpp.o
-o Test
-Wl,-rpath,/home/felix/workspace/Test/../raspi_root/usr/lib/arm-linux-gnueabihf:/home/felix/workspace/raspi_root/usr/lib/arm-linux-gnueabihf
../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so
/home/felix/workspace/raspi_root/usr/lib/arm-linux-gnueabihf/libboost_chrono.so
/home/felix/workspace/raspi_root/usr/lib/arm-linux-gnueabihf/libboost_system.so
/home/felix/workspace/raspi_root/usr/lib/arm-linux-gnueabihf/libboost_date_time.so
/home/felix/workspace/raspi_root/usr/lib/arm-linux-gnueabihf/libboost_atomic.so
../raspi_root/usr/lib/arm-linux-gnueabihf/libpthread.a
../raspi_root/usr/lib/arm-linux-gnueabihf/libbluetooth.so
Do I need to make CMake search for the shared libraries instead of the static ones? How would I do that? If not, what am I missing?
Thank you for your help.
Okay thanks to Tsyvarev for the quick hints to what I was missing. Turns out the answer is more obvious than I thought.
As Tsyvarev mentioned in the comments CMake does not search recursively through the specified root directory for libraries. Instead it searches the standard paths such as /usr/lib, /lib, etc. Further search paths can be added by appending them to CMAKE_LIBRARY_PATH as stated in the documentation. So to fix my errors I did the following:
I appended my desired library paths to the search path.
...
set(SOURCES main.cpp)
set(CMAKE_LIBRARY_PATH
${CMAKE_LIBRARY_PATH}
"/lib/arm-linux-gnueabihf"
"/usr/lib/arm-linux-gnueabihf"
)
add_executable(${project_target} ${SOURCES})
...
I then saw that I forgot to add any include directories:
target_include_directories(${project_target} PUBLIC
${SYSROOT}/usr/include/bluetooth
${SYSROOT}/usr/include/arm-linux-gnueabihf
)
And I was able to compile the main.cpp.
As for the EDIT:
To properly link the boost thread library I also had to link its dependencies. So I put:
find_package(Boost COMPONENTS thread REQUIRED)
...
target_include_directories(${project_target} PUBLIC
${SYSROOT}/usr/include/bluetooth
${SYSROOT}/usr/include/arm-linux-gnueabihf
${Boost_INCLUDE_DIRS}
)
target_link_libraries(${project_target} PUBLIC
rt
Threads::Threads
${Boost_LIBRARIES}
${BLUETOOTH}
)

CMake : /usr/include not used to find fftw3.h

I'm working on a personal project to cross compile for a Raspberry Pi with CMake. This is the first time I build a project with it.
One of the file I compile include the fftw3.h header. This file is present in the /usr/include folder as shown by the following output :
$ ls /usr/include/fftw3*
/usr/include/fftw3.f
/usr/include/fftw3.f03
/usr/include/fftw3.h
/usr/include/fftw3l.f03
/usr/include/fftw3q.f03
The file is successfully found by cmake with find_path(FFTW_FOLDER NAMES fftw3.h) and even if cmake looks in this path by default, I add it explicitly when constructing my target with target_include_directories(${LIB_NAME} PUBLIC /usr/include).
However, when comes the compilation, I have the classic error message telling me that fftw3.h is not found.
If I copy the file and put it in my home folder and add my home folder in the include list there is no problem and the compilation works.
Any thoughts ?
Thanks,
Damien
Edit 1 to answer #Pablo and #hikerjobs:
This is how my compile line looks like:
/home/littlemonster/projects/rpi-workspace/rpi-tools/arm-bcm2708/gcc-
linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-g++
-Dmatrix_hal_EXPORTS -I/home/littlemonster/projects/rpi-
workspace/lib/matrix-hal/matrix-creator-hal -fPIC -Wall -Werror -
Wextra -Wdouble-promotion -std=gnu++11 -o CMakeFiles/matrix-
hal.dir/matrix-creator-hal/cpp/driver/cross_correlation.cpp.o -c
/home/littlemonster/projects/rpi-workspace/lib/matrix-hal/matrix-
creator-hal/cpp/driver/cross_correlation.cpp
In file included from /home/littlemonster/projects/rpi-
workspace/lib/matrix-hal/matrix-creator-
hal/cpp/driver/cross_correlation.cpp:18:0:
/home/littlemonster/projects/rpi-workspace/lib/matrix-hal/matrix-
creator-hal/cpp/driver/cross_correlation.h:21:19: fatal error:
fftw3.h: No such file or directory
#include <fftw3.h>
^
compilation terminated.
Because I am cross compiling and the library is present on the Raspberry Pi I don't link the library.
Edit 2 to answer #Bartłomiej :
The following lines are located in my rpi-toolchain.cmake file which is used when invoking cmake with the following : -DCMAKE_TOOLCHAIN_FILE=rpi-toolchain.cmake. When I try to specify the sysroot by setting CMAKE_SYSROOT the compiler is not even able to compile a test file.
# Define our host system
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
SET(CMAKE_SYSTEM_VERSION 1)
SET(rpi-tools-dir ${CMAKE_SOURCE_DIR}/rpi-tools)
# Define the C cross compiler location
SET(CMAKE_C_COMPILER ${rpi-tools-dir}/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-gcc)
# Define the CXX cross compiler location
SET(CMAKE_CXX_COMPILER ${rpi-tools-dir}/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-g++)
# Define the sysroot path for the RaspberryPi distribution in our tools folder
SET(CMAKE_FIND_ROOT_PATH ${rpi-tools-dir}/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/arm-linux-gnueabihf/sysroot/)
# Only use binaries from the host and not from the toolchain sysroot
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# Search for libraries only in the target sysroot
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
# Search for the headers in the target and host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)

Compiling for iOS with CMake

I've compiled a C++ static library by using CMake as my building tool and I want to link it to my iOS app.
I created a simple 'Empty' application in Xcode and linked my library called libengine.a to it.
I tried to compile my iOS project and the linker gave me this warning:
ignoring file /Users/.../build/engine/libengine.a,
file was built for archive which is not the architecture being linked (i386):
/Users/.../build/engine/libengine.a
As I understand it, I need to compile my library for ARM processors. The problem is I don't know how.
I think CMake really lacks good tutorials.
Anyways, my CMake scripts are attached below.
Any help would be greatly appreciated.
Thanks, Tal.
Here is my main CMake script:
cmake_minimum_required(VERSION 2.8)
project(movie-night)
if (DEFINED PLATFORM)
include(toolchains/ios.cmake)
endif()
add_definitions(-Wall)
set(DEBUG)
if (DEFINED DEBUG)
add_definitions(-g)
endif()
if (DEFINED RELEASE)
add_definitions(-O3)
endif()
add_subdirectory(engine)
add_subdirectory(ui)
add_subdirectory(test)
Here is my toolchains/ios.cmake file:
set(CMAKE_SYSTEM_NAME Darwin)
set(CMAKE_SYSTEM_PROCESSOR arm)
Just use this toolchain file: http://code.google.com/p/ios-cmake/ and use it as
cmake -DCMAKE_TOOLCHAIN_FILE=path_to_your_toolchain_file
Then, in CMakeLists.txt:
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -arch armv7")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -arch armv7")
By following cmake-toolchains documentation I did like below:
cmake -G Xcode -B build \
-DCMAKE_SYSTEM_NAME=iOS \
-DCMAKE_Swift_COMPILER_FORCED=true \
-DCMAKE_OSX_DEPLOYMENT_TARGET=11.0
Note: That assignment CMAKE_OSX_DEPLOYMENT_TARGET=11.0 is not a mistake when targeting iOS.
I've been using an updated version of the iOS CMake toolchain for quite a while: https://github.com/leetal/ios-cmake
This creates an Xcode project which you can drag into an existing iOS project if necessary.
I wrote a blog post with more details: https://blog.tomtasche.at/2019/05/how-to-include-cmake-project-in-xcode.html
There is a second version of iOS.cmake located at:
https://ceres-solver.googlesource.com
Note: You may find that both versions of iOS.cmake will only build x86 versions of your project. CMake now sets CMAKE_OSX_SYSROOT to the (latest) Mac OS X SDK available on your system. You can fix this by modifying your copy of iOS.cmake to always set CMAKE_OSX_SYSROOT. You can do this by commenting out a couple of lines your copy of iOS.cmake:
# -- Under CMake 3.4.2, CMAKE_OSX_SYSROOT is automatically defined to point to the latest Mac OS X SDK. --
# -- So, the iOS SDK is never found. Grab the correct CMAKE_OS_SYSROOT and ignore any prior setting. --
# If user did not specify the SDK root to use, then query xcodebuild for it.
# if (NOT CMAKE_OSX_SYSROOT)
execute_process(COMMAND xcodebuild -version -sdk ${XCODE_IOS_PLATFORM} Path
OUTPUT_VARIABLE CMAKE_OSX_SYSROOT
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
message (STATUS "Using SDK: ${CMAKE_OSX_SYSROOT} for platform: ${IOS_PLATFORM}")
message (STATUS "be sure the previous line points to the correct SDK")
# endif ( )

What must I do with C++ libraries on cross compilation?

Here is my compiler part of my config:
IF(UNIX)
## Compiler flags
# specify the cross compiler
SET(CMAKE_C_COMPILER /home/username/projects/buildroot/output/host/usr/bin/arm-linux-gcc)
SET(CMAKE_CXX_COMPILER /home/username/projects/buildroot/output/host/usr/bin/arm-linux-g++)
if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "-O3")
set(CMAKE_EXE_LINKER_FLAGS "-lsqlite3 -lrt -lpthread")
endif()
target_link_libraries(complex
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY})
ENDIF(UNIX)
There are 3 problems : -lsqlite3 -lrt -lpthread
How must I to make them for my architecture and specify here? How to set (using set?) the path of compiled libraries after I will get them recompiled for my architecture somehow?
If you want to do cross-compilation with CMake you really should use a toolchain file for that. See the CMake Wiki for an introduction. In order to use third-party libraries (i.e. not included by the cross-compilation toolchain) you need to cross-compile them too.
Edit: Since you are using the buildroot toolchain, you can use the already included CMake toolchain file. Just pass -DCMAKE_TOOLCHAIN_FILE=/home/username/projects/buildroot/output/toolchainfile.cmake when invoking CMake. No need to set CMAKE_C_COMPILER and CMAKE_CXX_COMPILER in your CMakeLists.txt file. Also, setting CMAKE_CXX_FLAGS and CMAKE_EXE_LINKER_FLAGS is considered to be very bad practice.
Presumably you have built sqlite3 while building the buildroot toolchain, so you can use it just like any other library. I.e:
find_path(SQLITE3_INCLUDE_DIR sqlite3.h)
find_library(SQLITE3_LIBRARY sqlite3)
if(NOT SQLITE3_INCLUDE_DIR)
message(SEND_ERROR "Failed to find sqlite3.h")
endif()
if(NOT SQLITE3_LIBRARY)
message(SEND_ERROR "Failed to find the sqlite3 library")
endif()
find_package(Threads REQUIRED)
# ...
target_link_libraries(complex
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY}
${SQLITE3_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
rt)
Lastly, do not set CMAKE_CXX_FLAGS to -O3. The user should pass -DCMAKE_BUILD_TYPE=Release when configuring the project instead.
You'll have to cross-compile the dependencies as well. The path depends on where you install them.
Btw., using -lpthread is not the safe way of getting POSIX threads. You should give the option -pthread to both the compiler and the linker.