Antonio Antonio - 22 days ago 5
C++ Question

Cmake cross compiling: finding tools

I am using a standalone toolchain made from the android ndk13b. It works fine, but to find all the tools (linker, archiver etc.) I have a quite verbose section in my toolchain file. Is there a way to make it more condensed?

SET(COMPILER_PATH "<path_to_my_llvm_directory>")

SET(CMAKE_TOOLCHAIN_PREFIX aarch64-linux-android-) #In theory should allow to find minor tools like ar and objdump, see http://stackoverflow.com/a/7032021/2436175
find_program(CMAKE_C_COMPILER clang.cmd PATH ${COMPILER_PATH})
find_program(CMAKE_CXX_COMPILER clang++.cmd PATH ${COMPILER_PATH})
find_program(CMAKE_AR ${CMAKE_TOOLCHAIN_PREFIX}ar.exe PATHS ${COMPILER_PATH})
find_program(CMAKE_RANLIB ${CMAKE_TOOLCHAIN_PREFIX}ranlib.exe PATHS ${COMPILER_PATH})
find_program(CMAKE_LINKER ${CMAKE_TOOLCHAIN_PREFIX}ld.exe PATHS ${COMPILER_PATH})
find_program(CMAKE_NM ${CMAKE_TOOLCHAIN_PREFIX}nm.exe PATHS ${COMPILER_PATH})
find_program(CMAKE_OBJCOPY ${CMAKE_TOOLCHAIN_PREFIX}objcopy.exe PATHS ${COMPILER_PATH})
find_program(CMAKE_OBJDUMP ${CMAKE_TOOLCHAIN_PREFIX}objdump.exe PATHS ${COMPILER_PATH})
find_program(CMAKE_STRIP ${CMAKE_TOOLCHAIN_PREFIX}strip.exe PATHS ${COMPILER_PATH})


What didn't work:


  • Not explicitly using
    find_program
    -> It finds some other tools from some other mingw toolchain I have in my path

  • Setting
    CMAKE_FIND_ROOT_PATH
    to
    ${COMPILER_PATH}
    . It won't even find the compiler at that point. I can workaround that by setting the compiler instead with
    SET(CMAKE_C_COMPILER ${COMPILER_PATH}/clang.cmd)
    (same for clang++), but it still doesn't find the other tools

  • Trying various flags with
    find_program
    , especially
    ONLY_CMAKE_FIND_ROOT_PATH



Note that I found
find_program
to be the only workaround to find the tools, because for example the following won't work:

SET(CMAKE_AR ${COMPILER_PATH}/${CMAKE_TOOLCHAIN_PREFIX}ar.exe


(The archive operation will fail and I can see from cmake-gui that the variable is not set).

Answer

The good new is that Android NDK support got a lot easier with the latest CMake 3.7 release. See Kitware Increases Android Support in CMake 3.7 and Cross Compiling for Android.

I haven't tried it yet, but it sounds simple enough:

set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_ANDROID_STANDALONE_TOOLCHAIN /path/to/android-toolchain)

See build/cmake/android.toolchain.cmake

Simplified Toolchains in General

I've made some good experiences with minimal toolchain files and generally - if you want to specify tool paths specifically - using cached variables in the toolchain file.

See this minimal example from CMake's documentation, which would translate in your case into something like:

set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(CMAKE_C_COMPILER <path_to_my_llvm_directory>/clang.cmd)
set(CMAKE_C_COMPILER_TARGET aarch64-linux-android)
set(CMAKE_CXX_COMPILER <path_to_my_llvm_directory>/clang++.cmd)
set(CMAKE_CXX_COMPILER_TARGET aarch64-linux-android)

Note that specifying CMAKE_SYSTEM_NAME is essential to enable crosscompiling.

Why specifying CMAKE_AR didn't work

Regarding your CMAKE_AR problem please note that CMake itself does use find_program() to find ar.exe. Since find_program() does cache its results, you have to prefill CMAKE_AR also as cached variable (see 0013038: cannot set CMAKE_AR when cross-compiling Fortran-only project).