Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CMake FindThreads.cmake won't find my pthreads.h header

Tags:

android

cmake

I'm using android-cmake to compile an application for Android. This essentially creates a CMake toolchain file for using the toolchain provided with Android's NDK.

As with this related question, I'm having problems with the following line in my CMakeLists.txt file:

find_package(Threads REQUIRED)

The header file is located at

~/Android/android-ndk-r7/platforms/android-8/arch-arm/usr/include/pthread.h

The library file is located at

~/Android/android-ndk-r7/platforms/android-8/arch-arm/usr/lib/libthread_db.so

The problem is that FindThreads.cmake calls CHECK_INCLUDE_FILES("pthread.h", CMAKE_HAVE_PTHREAD_H) and this seems to not bother to check in that directory.

According to CMake's Useful Variables wiki page CMAKE_INCLUDE_PATH allows the setting of the header search path, CMAKE_LIBRARY_PATH allows setting of the library search path, and CMAKE_PREFIX_PATH seems provide both for find_package.

However, despite whether I set environment variables before running cmake...

export CMAKE_INCLUDE_PATH=~/Android/android-ndk-r7/platforms/android-8/arch-arm/usr:~/Android/android-ndk-r7/platforms/android-8/arch-arm/usr/include

... or whether I set them directly in CMakeLists.txt...

if(ANDROID)
    set(CMAKE_INCLUDE_PATH
        ${ANDROID_NDK_SYSROOT}/usr
        ${ANDROID_NDK_SYSROOT}/usr/include
        ${CMAKE_INCLUDE_PATH}
    )

    set(CMAKE_LIBRARY_PATH
        ${ANDROID_NDK_SYSROOT}/usr
        ${ANDROID_NDK_SYSROOT}/usr/lib
        ${CMAKE_LIBRARY_PATH})

    set(CMAKE_PREFIX_PATH
        ${ANDROID_NDK_SYSROOT}
        ${CMAKE_PREFIX_PATH})

    message(${ANDROID_NDK_SYSROOT})
    message(${CMAKE_INCLUDE_PATH})

endif()

find_package(Threads REQUIRED)

... (and this does get executed, the messages are printed), and where ${ANDROID_NDK_SYSROOT} contains

/Users/martin/Android/android-ndk-r7/platforms/android-8/arch-arm

I still get the message

Could NOT find Threads (missing: Threads_FOUND)

Does anybody have any suggestions as to what I am doing wrong?

like image 706
Martin Foot Avatar asked Dec 05 '11 14:12

Martin Foot


2 Answers

Setting CMAKE_INCLUDE_PATH will only affect the CMake find_file and find_path commands. The CHECK_INCLUDE_FILES function called by FindThreads.cmake does not honor that variable. For CHECK_INCLUDE_FILES you can set the variable CMAKE_REQUIRED_INCLUDES instead:

set(CMAKE_REQUIRED_INCLUDES 
  ${ANDROID_NDK_SYSROOT}/usr 
  ${ANDROID_NDK_SYSROOT}/usr/include)
like image 23
sakra Avatar answered Sep 27 '22 20:09

sakra


I found the solution to this problem after a lot of debugging and it's quite strange. Essentially, FindThreads.cmake calls a macro called CHECK_INCLUDE_FILES which tries to TRY_COMPILE a source file which simply includes the headers that the CHECK_INCLUDE_FILES macro is provided with.

Note that it does use CMAKE_REQUIRED_INCLUDES as suggested by @sakra so that's useful.

Using android-cmake, the TRY_COMPILE macro tries to compile with the arm-linux-androideabi-gcc compiler from the NDK with all of the specified compile flags. The android.toolchain.cmake file contains the following lines that set some of these compile flags:

if( BUILD_WITH_ANDROID_NDK )
 set( CMAKE_CXX_FLAGS "--sysroot=\"${ANDROID_NDK_SYSROOT}\" ${CMAKE_CXX_FLAGS}" )
 set( CMAKE_C_FLAGS "--sysroot=\"${ANDROID_NDK_SYSROOT}\" ${CMAKE_C_FLAGS}" )

The TRY_COMPILE macro fails and as per the CMakeError.log file contains the following:

Run Build Command:/opt/local/bin/gmake "cmTryCompileExec/fast"
/opt/local/bin/gmake -f CMakeFiles/cmTryCompileExec.dir/build.make CMakeFiles/cmTryCompileExec.dir/build
gmake[1]: Entering directory '/Users/martin/Repositories/Delta/build/android/CMakeFiles/CMakeTmp'
"/Applications/CMake 2.8-4.app/Contents/bin/cmake" -E cmake_progress_report /Users/martin/Repositories/Delta/build/android/CMakeFiles/CMakeTmp/CMakeFiles 1
Building C object CMakeFiles/cmTryCompileExec.dir/CheckIncludeFiles.c.o
/Users/martin/Android/android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-gcc   --sysroot=;/Users/martin/Android/android-ndk-r7/platforms/android-8/arch-arm" -fPIC -DANDROID -Wno-psabi -fsigned-char -mthumb -march=armv7-a -mfloat-abi=softfp  " -I/Users/martin/Android/android-ndk-r7/sources/cxx-stl/gnu-libstdc++/include -I/Users/martin/Android/android-ndk-r7/sources/cxx-stl/gnu-libstdc++/libs/armeabi-v7a/include -I/Users/martin/Android/android-ndk-r7/platforms/android-8/arch-arm/usr -I/Users/martin/Android/android-ndk-r7/platforms/android-8/arch-arm/usr/include   -o CMakeFiles/cmTryCompileExec.dir/CheckIncludeFiles.c.o   -c /Users/martin/Repositories/Delta/build/android/CMakeFiles/CMakeTmp/CheckIncludeFiles.c
arm-linux-androideabi-gcc: no input files

If you scroll to the right on the actual compiler line (second from the bottom) you can see the --sysroot=;/... section. Even though the CMake lines above use escaped strings, CMake has turned this first escaped quotation into a semicolon and left the second as a normal quotation, resulting in a semicolon in the sysroot line and then a string literal containing all the CMAKE_CXX_FLAGS afterwards (easy to see with SO's syntax highlighting).

The solution to this is to modify android.toolchain.cmake to remove the escaped quotations as they are unnecessary.

if( BUILD_WITH_ANDROID_NDK )
 set( CMAKE_CXX_FLAGS "--sysroot=${ANDROID_NDK_SYSROOT} ${CMAKE_CXX_FLAGS}" )
 set( CMAKE_C_FLAGS "--sysroot=${ANDROID_NDK_SYSROOT} ${CMAKE_C_FLAGS}" )
like image 74
Martin Foot Avatar answered Sep 27 '22 22:09

Martin Foot