Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CMake cross-compile with specific linker doesn't pass arguments to armlink

I am trying to cross-compile a project for embedded ARM Cortex builds, but I am unable to get the linker working. I want to use armlink, but no files are passed to armlink and hence no .elf file is produced.

My CMakeLists.txt is pretty simple and given below. The failure is shown after that which shows that armlink was invoked by the makefile without any arguments.

Any pointers will help - I searched and read many posts, but they all seem to have more involved requirements.

cmake_minimum_required(VERSION 2.8)

project(test_arm)
enable_language(C ASM)

# Cross-compilation for ARM
SET(CMAKE_C_COMPILER armcc)
SET(CMAKE_LINKER armlink)
SET(CMAKE_C_LINK_EXECUTABLE armlink)

SET(CMAKE_C_FLAGS "--cpu=Cortex-M3")
SET(LINK_FLAGS "--map --ro-base=0x0 --rw-base=0x0008000 --first='boot.o(RESET)' --datacompressor=off")
SET(CMAKE_EXE_LINKER_FLAGS "--map --ro-base=0x0 --rw-base=0x0008000 --first='boot.o(RESET)' --datacompressor=off")

include_directories(../include)

add_executable(blinky blinky.c)
set_target_properties(blinky PROPERTIES LINKER_LANGUAGE C)

The failure is as follows, but I guess it would be obvious to someone given that I have some stupid issue in my CMakeLists:

$ make VERBOSE=1
[100%] Building C object CMakeFiles/blinky.dir/blinky.c.o
/usr/bin/cmake -E cmake_link_script CMakeFiles/blinky.dir/link.txt --verbose=1
armlink
Linking C executable blinky
Product: DS-5 Professional 5.21.0 [5210017]
Component: ARM Compiler 5.05 update 1 (build 106)
Tool: armlink [4d0efa]
For support see http://www.arm.com/support/
Software supplied by: ARM Limited
Usage: armlink option-list input-file-list
where
....

I was expecting the CMake generated Makefile to invoke armlink with something like:

armlink --map --ro-base=0x0 --rw-base=0x0008000 \
  --first='boot.o(RESET)' --datacompressor=off \
  CMakeFiles/blinky.dir/blinky.c.o -o blinky.elf
like image 918
guraaf Avatar asked May 18 '15 21:05

guraaf


2 Answers

A toolchain file may be a good idea. Here is what I've came up the last time I tried CMake 2.8.10 with the DS-5 toolchain (it could still be optimized, but it should give you a starting point):

INCLUDE(CMakeForceCompiler)

# This one is important
SET(CMAKE_SYSTEM_NAME Generic)
SET(CMAKE_SYSTEM_PROCESSOR arm)

# Specify the cross compiler
SET(CMAKE_C_COMPILER "C:/Program Files (x86)/DS-5/bin/armcc.exe")
SET(CMAKE_CXX_COMPILER "C:/Program Files (x86)/DS-5/bin/armcc.exe")
SET(CMAKE_AR "C:/Program Files (x86)/DS-5/bin/armar.exe" CACHE FILEPATH "Archiver")

#CMAKE_FORCE_C_COMPILER("C:/Program Files (x86)/DS-5/sw/gcc/bin/arm-linux-gnueabihf-gcc.exe" GNU)
#CMAKE_FORCE_CXX_COMPILER("C:/Program Files (x86)/DS-5/sw/gcc/bin/arm-linux-gnueabihf-g++.exe" GNU)

UNSET(CMAKE_C_FLAGS CACHE)
SET(CMAKE_C_FLAGS "--cpu=Cortex-A9 --thumb -Ospace" CACHE STRING "" FORCE)
UNSET(CMAKE_CXX_FLAGS CACHE)
SET(CMAKE_CXX_FLAGS ${CMAKE_C_FLAGS} CACHE STRING "" FORCE)
UNSET(CMAKE_EXE_LINKER_FLAGS CACHE)
SET(CMAKE_EXE_LINKER_FLAGS "" CACHE STRING "" FORCE)
UNSET(CMAKE_AR_FLAGS CACHE)
SET(CMAKE_AR_FLAGS "-p -armcc,-Ospace" CACHE STRING "" FORCE)

# set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> cr <TARGET> <LINK_FLAGS> <OBJECTS>")
SET(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> ${CMAKE_AR_FLAGS} -o <TARGET> <OBJECTS>" CACHE STRING "C Archive Create")
# set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> cr <TARGET> <LINK_FLAGS> <OBJECTS>")
SET(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> ${CMAKE_AR_FLAGS} -o <TARGET> <OBJECTS>" CACHE STRING "CXX Archive Create")

include_directories("C:/Program Files (x86)/DS-5/include")
#include_directories("C:/Program Files (x86)/DS-5/sw/gcc/arm-linux-gnueabihf/libc/usr/include/arm-linux-gnueabi")

# Where is the target environment
SET(CMAKE_FIND_ROOT_PATH "C:/Program Files (x86)/DS-5")

# Search for programs in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)

# For libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

Regarding your question

Some failure analysis

What you have tried should work (see also e.g. How do I add a linker or compile flag in a CMake file?). But it seems something goes wrong during the configuration step.

I don't know your command line call for CMake's configuration/generation steps, so some general tips to find the root cause:

You could try calling

cmake.exe --trace ...

to see what went wrong with your CMAKE_EXE_LINKER_FLAGS variable. This will generate a lot of output, so here are some basics on what CMake does:

  • The project() command will trigger the compiler evaluation
  • This will write CMAKE_EXE_LINKER_FLAGS into your CMakeCache.txt
  • You are overwriting it with a local variable (see variable scope docu here)

If you look into share\cmake-2.8\Modules\CMakeCommonLanguageInclude.cmake:

set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS_INIT} $ENV{LDFLAGS}"
     CACHE STRING "Flags used by the linker.")

You could use CMAKE_EXE_LINKER_FLAGS_INIT, but you have to set it before the project() command or in the toolchain file.

Because you set the link language to C take a look into share\cmake-2.8\Modules\CMakeCInformation.cmake:

if(NOT CMAKE_C_LINK_EXECUTABLE)
  set(CMAKE_C_LINK_EXECUTABLE
    "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>")
endif()

So you can use CMAKE_C_LINK_EXECUTABLE to overwrite the complete linker call or you could use CMAKE_C_LINK_FLAGS to set additional flags.

The "official" way

The official way to set the target's linker and compiler flags would be (before CMake 2.8.12):

set_property(TARGET blinky APPEND_STRING PROPERTY COMPILE_FLAGS "--cpu=Cortex-M3")
set_property(TARGET blinky APPEND_STRING PROPERTIES LINK_FLAGS "--map --ro-base=0x0 --rw-base=0x0008000 --first='boot.o(RESET)' --datacompressor=off")

Starting with CMake 2.8.12 it would be something like:

add_compile_options("--cpu=Cortex-M3")
like image 77
Florian Avatar answered Nov 05 '22 05:11

Florian


From my experience, you cannot set CMAKE_EXE_LINKER_FLAGS in a CMakeLists.txt file. It has to be passed via a CMAKE_TOOLCHAIN_FILE when CMake is invoked the very first time in a build directory.

I don't find any documentation regarding this problem, but there is the cross-compilation with CMake page which you should use it if you do cross-compilation.

For a start, just put your set-calls in a toolchain file and run

cmake -DCMAKE_TOOLCHAIN_FILE=<yourfile.toolchain>

in a clean build directory.

like image 1
Patrick B. Avatar answered Nov 05 '22 05:11

Patrick B.