2

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).

Antonio
  • 19,451
  • 13
  • 99
  • 197
  • `... I can see from cmake-gui that the variable is not set` - `cmake-gui` shows only *cached* variables. You may use `SET(CMAKE_AR ... CACHE PATH "Archiver")`. – Tsyvarev Nov 16 '16 at 19:38
  • "Is there a way to make it more condensed?" good luck with that. Cmake is a great tool, but the syntax and language behaviour is garbage. It's a real shame (IMHO) that kitware didn't write it in python :( – Richard Hodges Nov 16 '16 at 20:09
  • @RichardHodges I do have python, but asking all my colleagues to install it just for being able to build our software wouldn't have made our life easier. And making a "complete independent" program out of python is not trivial. – Antonio Nov 17 '16 at 09:47
  • @Tsyvarev There are exceptions, like if you set `CMAKE_C_COMPILER`. – Antonio Nov 17 '16 at 09:48

1 Answers1

3

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.

Edit: I have successfully run a test with CMake 3.7 (e.g. installed ADK to root on my Windows PC):

toolchain.cmake

set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSROOT "C:/android-ndk-r13b/platforms/android-24/arch-arm64")

And used e.g. the Ninja makefile generator:

> cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake -G "Ninja" ..
-- Android: Targeting API '24' with architecture 'arm64', ABI 'arm64-v8a', and processor 'aarch64'
-- Android: Selected GCC toolchain 'aarch64-linux-android-4.9'
-- The C compiler identification is GNU 4.9.0
-- The CXX compiler identification is GNU 4.9.0

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).

Florian
  • 39,996
  • 9
  • 133
  • 149
  • The release of CMake 3.7 seems to be synchronized with my question :). Thank you for this very relevant answer, setting those variables the tools are indeed found but I cannot find a way to convince CMake to use llvm: even this is not sufficient: `set(CMAKE_C_COMPILER CACHE PATH "C compiler")`. In all cases, it will try use the gcc/g++ available in the standalone toolchain. – Antonio Nov 17 '16 at 09:43
  • In the specific workaround I tried, CMake will say `You have changed variables that require your cache to be deleted. Configure will be re-run and you may have to reset some variables. The following variables have changed: CMAKE_C_COMPILER= CMAKE_CXX_COMPILER= `, independently from whatever order I choose for the variable definition. – Antonio Nov 17 '16 at 09:44
  • @Antonio I've to run some tests with the latest ADK and CMake versions to see if I can reproduce your problem. I'll update my answer accordingly later today. But I'm familiar with the last error message you got: if you change `CMAKE_C_COMPILER` or `CMAKE_CXX_COMPILER` you best start from an empty binary output directory again (it's more or less the same as if you would have changed the generator to be used). – Florian Nov 17 '16 at 09:51
  • I had also to revert my CMake installation: my "old" toolchain file won't work anymore!! With CMake 3.6.3 everything is fine. Probably it's better to wait until they polish the 3.7 release. – Antonio Nov 17 '16 at 10:26
  • Tested on 3.6.3: `Using SET(CMAKE_C_COMPILER_TARGET aarch64-linux-android)` and `SET(CMAKE_CXX_COMPILER_TARGET aarch64-linux-android)` removes the necessity of the `find_program` commands for all tools! I think for the moment that should be the first part of your answer. – Antonio Nov 17 '16 at 10:26
  • @Antonio Glad I could help. I've just run a few tests and with setting the `CMAKE_SYSROOT` variable it did work for me. See my updated answer. – Florian Nov 17 '16 at 21:01