Zermingore
Zermingore

Reputation: 753

cmake cross-compilation toolchain confusion

TL;DR: Why moving stuff around from the CMakeLists.txt to a dedicated toolchain file plays a role for find_package?

Trying to cross-compile with cmake and compile/link against pthread, I have the following dummy source file and CMakeLists.txt which work as expected together:

main.cc

#include <iostream>
#include <bits/c++config.h> // needed in the real world

int main()
{
  std::cout << "Hello World !\n";

  return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.0.0)

project(test VERSION 0.0.1)
set(CMAKE_BUILD_TYPE Debug)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)


set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)

set(CMAKE_CXX_COMPILER_TARGET arm-linux-gnueabihf)

add_compile_options(-mtune=cortex-a9)
add_compile_definitions(_ARM_GCC_)


# Looking for cross compiler includes; maybe looking for rootfs-like stuff would be better
file(GLOB cross_includes LIST_DIRECTORIES true "/usr/arm-linux-gnueabihf/include/c++/*/arm-linux-gnueabihf/")
include_directories(SYSTEM ${cross_includes})
include_directories(SYSTEM /usr/arm-linux-gnueabihf/include)


find_package(Threads REQUIRED) # Not strictly necessary in this example but needed in the real world


add_executable(test main.cc)

Test:

$> rm -rf build/ && cmake -B build/ && make VERBOSE=1 -C build/

-- The C compiler identification is Clang 11.0.1
-- The CXX compiler identification is Clang 11.0.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/clang - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/clang++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread
-- Looking for pthread_create in pthread - found
-- Found Threads: TRUE  
-- Configuring done
-- Generating done
-- Build files have been written to: /home/jp/sandbox/so/cmake/build
make: Entering directory '/home/jp/sandbox/so/cmake/build'
/usr/bin/cmake -S/home/jp/sandbox/so/cmake -B/home/jp/sandbox/so/cmake/build --check-build-system CMakeFiles/Makefile.cmake 0
/usr/bin/cmake -E cmake_progress_start /home/jp/sandbox/so/cmake/build/CMakeFiles /home/jp/sandbox/so/cmake/build//CMakeFiles/progress.marks
make  -f CMakeFiles/Makefile2 all
make[1]: Entering directory '/home/jp/sandbox/so/cmake/build'
make  -f CMakeFiles/test.dir/build.make CMakeFiles/test.dir/depend
make[2]: Entering directory '/home/jp/sandbox/so/cmake/build'
cd /home/jp/sandbox/so/cmake/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/jp/sandbox/so/cmake /home/jp/sandbox/so/cmake /home/jp/sandbox/so/cmake/build /home/jp/sandbox/so/cmake/build /home/jp/sandbox/so/cmake/build/CMakeFiles/test.dir/DependInfo.cmake --color=
Dependee "/home/jp/sandbox/so/cmake/build/CMakeFiles/test.dir/DependInfo.cmake" is newer than depender "/home/jp/sandbox/so/cmake/build/CMakeFiles/test.dir/depend.internal".
Dependee "/home/jp/sandbox/so/cmake/build/CMakeFiles/CMakeDirectoryInformation.cmake" is newer than depender "/home/jp/sandbox/so/cmake/build/CMakeFiles/test.dir/depend.internal".
Scanning dependencies of target test
make[2]: Leaving directory '/home/jp/sandbox/so/cmake/build'
make  -f CMakeFiles/test.dir/build.make CMakeFiles/test.dir/build
make[2]: Entering directory '/home/jp/sandbox/so/cmake/build'
[ 50%] Building CXX object CMakeFiles/test.dir/main.cc.o
/usr/bin/clang++ --target=arm-linux-gnueabihf -D_ARM_GCC_ -isystem /usr/arm-linux-gnueabihf/include/c++/10/arm-linux-gnueabihf -isystem /usr/arm-linux-gnueabihf/include -g -mtune=cortex-a9 -std=c++17 -o CMakeFiles/test.dir/main.cc.o -c /home/jp/sandbox/so/cmake/main.cc
[100%] Linking CXX executable test
/usr/bin/cmake -E cmake_link_script CMakeFiles/test.dir/link.txt --verbose=1
/usr/bin/clang++ --target=arm-linux-gnueabihf -g -rdynamic CMakeFiles/test.dir/main.cc.o -o test 
make[2]: Leaving directory '/home/jp/sandbox/so/cmake/build'
[100%] Built target test
make[1]: Leaving directory '/home/jp/sandbox/so/cmake/build'
/usr/bin/cmake -E cmake_progress_start /home/jp/sandbox/so/cmake/build/CMakeFiles 0
make: Leaving directory '/home/jp/sandbox/so/cmake/build'

So far, everything works fine.

Now, the tricky part: I'd like to put the cross-compilation specific stuff in a toolchain.cmake file

toolchain.cmake

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)

set(CMAKE_CXX_COMPILER_TARGET arm-linux-gnueabihf)

add_compile_options(-mtune=cortex-a9)
add_compile_definitions(_ARM_GCC_)


# Looking for cross compiler includes; maybe looking for rootfs-like stuff would be better
file(GLOB cross_includes LIST_DIRECTORIES true "/usr/arm-linux-gnueabihf/include/c++/*/arm-linux-gnueabihf/")
include_directories(SYSTEM ${cross_includes})
include_directories(SYSTEM /usr/arm-linux-gnueabihf/include)

new CMakeLists.txt

cmake_minimum_required(VERSION 3.0.0)

project(test VERSION 0.0.1)
set(CMAKE_BUILD_TYPE Debug)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)


find_package(Threads REQUIRED) # Not strictly necessary in this example but needed in the real world

add_executable(test main.cc)

Test:

$> rm -rf build/ && cmake -B build/ -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake && make VERBOSE=1 -C build/

-- The C compiler identification is Clang 11.0.1
-- The CXX compiler identification is Clang 11.0.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/clang - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/clang++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Looking for pthread.h
-- Looking for pthread.h - not found
CMake Error at /usr/share/cmake-3.18/Modules/FindPackageHandleStandardArgs.cmake:165 (message):
  Could NOT find Threads (missing: Threads_FOUND)
Call Stack (most recent call first):
  /usr/share/cmake-3.18/Modules/FindPackageHandleStandardArgs.cmake:458 (_FPHSA_FAILURE_MESSAGE)
  /usr/share/cmake-3.18/Modules/FindThreads.cmake:234 (FIND_PACKAGE_HANDLE_STANDARD_ARGS)
  CMakeLists.txt:11 (find_package)


-- Configuring incomplete, errors occurred!
See also "/home/jp/sandbox/so/cmake/build/CMakeFiles/CMakeOutput.log".
See also "/home/jp/sandbox/so/cmake/build/CMakeFiles/CMakeError.log".

Actually, cmake finds pthread.h but clang cannot compile it (wrong floating point abi used; stubs-hard.h should be included)

build/CMakeFiles/CMakeError.log

Determining if the include file pthread.h exists failed with the following output:
Change Dir: /home/jp/sandbox/so/cmake/build/CMakeFiles/CMakeTmp

Run Build Command(s):/usr/bin/gmake cmTC_76e89/fast && /usr/bin/gmake  -f CMakeFiles/cmTC_76e89.dir/build.make CMakeFiles/cmTC_76e89.dir/build
gmake[1]: Entering directory '/home/jp/sandbox/so/cmake/build/CMakeFiles/CMakeTmp'
Building C object CMakeFiles/cmTC_76e89.dir/CheckIncludeFile.c.o
/usr/bin/clang -D_ARM_GCC_ -isystem /usr/arm-linux-gnueabihf/include/c++/10/arm-linux-gnueabihf -isystem /usr/arm-linux-gnueabihf/include/gnu -isystem /usr/arm-linux-gnueabihf/include -mtune=cortex-a9 -o CMakeFiles/cmTC_76e89.dir/CheckIncludeFile.c.o -c /home/jp/sandbox/so/cmake/build/CMakeFiles/CMakeTmp/CheckIncludeFile.c
In file included from /home/jp/sandbox/so/cmake/build/CMakeFiles/CMakeTmp/CheckIncludeFile.c:1:
In file included from /usr/arm-linux-gnueabihf/include/pthread.h:21:
In file included from /usr/arm-linux-gnueabihf/include/features.h:485:
/usr/arm-linux-gnueabihf/include/gnu/stubs.h:7:11: fatal error: 'gnu/stubs-soft.h' file not found
# include <gnu/stubs-soft.h>
          ^~~~~~~~~~~~~~~~~~
1 error generated.
gmake[1]: *** [CMakeFiles/cmTC_76e89.dir/build.make:85: CMakeFiles/cmTC_76e89.dir/CheckIncludeFile.c.o] Error 1
gmake[1]: Leaving directory '/home/jp/sandbox/so/cmake/build/CMakeFiles/CMakeTmp'
gmake: *** [Makefile:140: cmTC_76e89/fast] Error 2

Some more Info:

I made sure the toolchain.cmake is considered (triggered a parse error to check)

$> cat toolchain.cmake CMakeLists.txt

produces the same output as the "original" CMakeLists.txt

pthread.h can be found on my System at the following locations:

$> find /usr/ -name pthread.h
/usr/arm-linux-gnueabi/include/pthread.h
/usr/arm-linux-gnueabihf/include/pthread.h
/usr/include/newlib/pthread.h /usr/include/pthread.h

Upvotes: 1

Views: 1702

Answers (1)

Zermingore
Zermingore

Reputation: 753

As @Tsyvarev pointed out, the CMakeError.log contained useful information (the question was edited with its content).

The issue: cmake finds pthread.h but clang cannot compile it

...
/usr/arm-linux-gnueabihf/include/gnu/stubs.h:7:11: fatal error: 'gnu/stubs-soft.h' file not found
...

The clang invocation is interesting because of "/usr/bin/clang" (expected clang++) and no -target flag used

The solution: Tell cmake to also use a specific -target flag for C cross-compilers supoorting it:

Add the following in target.cmake

set(CMAKE_C_COMPILER_TARGET arm-linux-gnueabihf)

(Same target as CMAKE_CXX_COMPILER_TARGET)

Upvotes: 1

Related Questions