Possible bugs with armclang toolchain

I have a project to cross compile firmware for ARM Cortex A53 platform. At the very beginning of my CMakeLists.txt, I defined armclang toolchain by:

cmake_minimum_required(VERSION 3.10)

set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR cortex-a53)
set(CMAKE_C_COMPILER armclang)
set(CMAKE_CXX_COMPILER armclang)
set(CMAKE_CROSSCOMPILING true)
add_compile_options(–target=aarch64-arm-none-eabi)

Then when I ran “cmake ”, cmake reported failure on compiler checking:

The C compiler

"/opt/arm/DS-5_v5.29.2/sw/ARMCompiler6.10.1/bin/armclang"

is not able to compile a simple test program.

It fails with the following output:

Change Dir: /home/oscarh/data/temp/fooPrj/build/CMakeFiles/CMakeTmp

Run Build Command(s):/usr/bin/make cmTC_4a0d6/fast && /usr/bin/make -f CMakeFiles/cmTC_4a0d6.dir/build.make CMakeFiles/cmTC_4a0d6.dir/build
make[1]: Entering directory '/home/oscarh/data/temp/fooPrj/build/CMakeFiles/CMakeTmp'
Building C object CMakeFiles/cmTC_4a0d6.dir/testCCompiler.o
/opt/arm/DS-5_v5.29.2/sw/ARMCompiler6.10.1/bin/armclang --target=arm-arm-none-eabi   -mcpu=cortex-a53    -o CMakeFiles/cmTC_4a0d6.dir/testCCompiler.o   -c /home/oscarh/data/temp/fooPrj/build/CMakeFiles/CMakeTmp/testCCompiler.c
Linking C executable cmTC_4a0d6.elf
/opt/cmake-3.16.0-rc3/bin/cmake -E cmake_link_script CMakeFiles/cmTC_4a0d6.dir/link.txt --verbose=1
/opt/arm/DS-5_v5.29.2/sw/ARMCompiler6.10.1/bin/armlink --cpu=cortex-a53    CMakeFiles/cmTC_4a0d6.dir/testCCompiler.o -o cmTC_4a0d6.elf --list cmTC_4a0d6.map
Fatal error: L3903U: Argument 'cortex-a53' not permitted for option 'cpu'.
Finished: 0 information, 0 warning, 0 error and 1 fatal error messages.
CMakeFiles/cmTC_4a0d6.dir/build.make:86: recipe for target 'cmTC_4a0d6.elf' failed

I think the problem is, cmake passed ${CMAKE_SYSTEM_PROCESSOR} directly to the --cpu option of armlink, which is unfortunately unregonized in this case. Why not use the driver program armclang for linking? In many cases, armlink even cannot have a --cpu option, see this statement from armlink’s documentation:

You cannot specify targets with Armv8.4-A or later architectures on the armlink command-line. To link
for such targets, you must not specify the --cpu option when invoking armlink directly

Those settings should go in a toolchain file passed via CMAKE_TOOLCHAIN_FILE See also the cmake-toolchains(7) manual.

The aarch64-arm-none-eabi target can be set via CMAKE_{C,CXX}_COMPILER_TARGET in the toolchain file.

@brad.king,I moved those lines into a separate toochain file, and defined CMAKE_{C,CXX}_COMPILER_TARGET in it, but it does not help. I still see the same error. The compiler checking step can pass if I comment out this line from the file share/cmake-3.16/Modules/Compiler/ARMClang.cmake:

string(APPEND CMAKE_${lang}_LINK_FLAGS “–cpu=${CMAKE_SYSTEM_PROCESSOR}”)

By the way, I didn’t use a toolchain file because I don’t want to type a long command line when invoking cmake command. I thought it was ok to define my toolchain at the beginning of CMakeLists.txt prior to the project() command. Any pitfalls with my approach?

It seems there is another problem. When compiling ASM files, cmake does not get the --target option from CMAKE_ASM_COMPILER_TARGET. Consequently, ARMClang complains that --target is not defined.

The toolchain file must be defined separately and used via CMAKE_TOOLCHAIN_FILE. Defining the settings at the top of CMakeLists.txt is not sufficient because they won’t be included in try_compile projects and such.

The Modules/Compiler/ARMClang.cmake support is relatively new so it may need to mature a bit. Please open an issue in the CMake Issue Tracker to report these problems.

Thanks for your promt response, Brad.
cmake tests the compiler designated by compiling a small c file. Is that done by calling try_compile? If yes, it seems it does pick up the toolchain defined at the top of CMakeLists.txt. Myself won’d do try_compile.

Just curious, why does cmake leave some options to command line which must be defined on command line by -D option, such as CMAKE_TOOLCHAIN_FILE? Isn’t it more consistent and unified if everything can be done in CMakeLists.txt? Then from command line, I only need to run cmake mySourceDir.

The compiler identification does not use try_compile because it is a bootstrapping step that occurs before we have enough information to run a generator for try_compile. The compiler id step can see settings from CMakeLists.txt, but try_compile projects use their own generated temporary CMakeLists.txt file that does not see the main one. The toolchain file is included in both.

CMAKE_TOOLCHAIN_FILE was designed for the use case in which a project does not always cross-compile with a specific toolchain. Instead the project has generic build rules and the user chooses to cross-compile with a specific toolchain by configuring the project with -DCMAKE_TOOLCHAIN_FILE=....

If you want to hard-code a specific toolchain in CMakeLists.txt, try this (untested):

cmake_minimum_required(VERSION 3.10)
set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/toolchain.cmake" CACHE PATH "")
project(MyProj)

If CMAKE_TOOLCHAIN_FILE is added to the cache before the first project() or enable_language call then it should be used without having to specify it on the command line.

I see CMake issue 19962 and CMake issue 19963, thanks.