0

I'm building an application for which I'd like to support a certain proprietary platform. It uses a modified version of ARMCC which CMake doesn't seem to like - no matter what I do, it keeps trying to provide strange flags to armlink where it should not, ignoring attempts to override its behavior.

Is it possible to essentially provide an all-new definition of how CMake should deal with a particular compiler? i.e. specify the binary and flags used for compilation, linking, etc., the expected file extensions, etc. throughout the whole process such that CMake doesn't do anything nasty? CMake seems to make custom compiler definitions an incredibly obscure thing to accomplish.

Edit: I've made it provide most of the right flags, but now I'm realizing I can't change the CMake test program - programs for this platform will fail to build if a certain atypical set of symbols (alternative entry point, not main) don't exist.

Edit 2: I've skipped the test program, but now it's failing while trying to get compiler information (why bother? I've given it everything it needs to know for the situation...) with this error:

Error: C9912E: No --cpu selected

To make it abundantly clear, the command it presents on the line above this clearly has the --cpu flag provided to a valid value:

armcc.exe -xc++ --cpu=MPCore -fpch-preprocess -v -dD -E

Though I'm entirely unsure as to what it's trying to do with the rest of it - I can't seem to override this part.

Ethan McTague
  • 2,236
  • 3
  • 21
  • 53
  • Have you tried setting up a cross-compiler toolchain? It's not perfect, but should be flexible enough to support everything you're asking for here. – Stephen Newell Apr 04 '20 at 02:39
  • 2
    `ignoring attempts to override its behavior.` - please post what have you tried. `s it possible to essentially provide an all-new definition of how CMake should deal with a particular compiler?` Yes. Basically for starters `CMAKE_TOOLCHAIN_FILE`, for non-starters proper file in `Modules/Compiler/`. Just add a toolchain file with `set(CMAKE_C_COMPILER my-amazing-compiler) (CMAKE_C_FLAGS_INIT "-my-amazing-cflag")` – KamilCuk Apr 04 '20 at 02:40
  • @StephenNewell The docs for cmake toolchains don't seem to go into detail on how to do this other than for specific known platforms (plus, a lot of the variables it suggests changing, such as cflags etc, didn't have any impact when I tried them). Any suggestions? – Ethan McTague Apr 04 '20 at 02:41
  • Configure a project with your default system compiler (you don't have to build, just configure) and open the cache file. You'll see tons of variables that specify flags, an each of those variables can be specified in your toolchain file. – Stephen Newell Apr 04 '20 at 02:43
  • As stated by commenters above, supporting new platform/compiler is performed with toolchain files or an additional compiler CMake module. It is true that documentation for both of these approaches is not very detailed. But what do you want from us (Stack Overflow)? We definitely won't write a detailed documentation about toolchains. We could help you in a **specific problem**, like "CMake generates a compiler/linker command line `aaa bbb ccc` but I want it to be `aaa bbb ddd`". But for that you need to state this problem. – Tsyvarev Apr 04 '20 at 10:14
  • @Tsyvarev The challenge here is I can't really explicitly explain this toolchain in detail without violating an NDA - I've tried to expose as much as I can to describe the problem. – Ethan McTague Apr 04 '20 at 23:20

1 Answers1

2

First, you need a toolchain.cmake file. Here, you provide the paths to your armcc compiler, linker, etc.

SET(CMAKE_SYSTEM_NAME Generic)
SET(CMAKE_SYSTEM_VERSION 1)

# this one is important
SET( CMAKE_SYSTEM_PROCESSOR  arm )

SET(MCU_ARCH Cortex-M4) #MCU architecture

SET(TOOLCHAIN_BIN_DIR "C:/Keil_v5/ARM/ARMCC/bin/")
set(LINKER_SCATTER_SCRIPT ${PROJECT_SOURCE_DIR}/Scatter_file.sct)

SET(CMAKE_C_COMPILER            ${TOOLCHAIN_BIN_DIR}/armcc.exe      CACHE FILEPATH "C compiler")
SET(CMAKE_CXX_COMPILER          ${TOOLCHAIN_BIN_DIR}/armcc.exe      CACHE FILEPATH "C++ compiler")
SET(CMAKE_LINKER                ${TOOLCHAIN_BIN_DIR}/armlink.exe    CACHE FILEPATH "linker")
SET(CMAKE_AR                    ${TOOLCHAIN_BIN_DIR}/armar.exe      CACHE FILEPATH "Archiver")
SET(CMAKE_ASM_COMPILER          ${TOOLCHAIN_BIN_DIR}/armasm.exe     CACHE FILEPATH "Assembler")
SET(CMAKE_FROMELF               ${TOOLCHAIN_BIN_DIR}/fromelf.exe    CACHE FILEPATH "From ELF tool")

SET(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

SET(CMAKE_EXE_LINKER_FLAGS_INIT "--cpu ${MCU_ARCH} --myFlag1 --myFlag2 ${LINKER_SCATTER_SCRIPT}")

Next, within the CMakeLists.txt file, you can pass the compiler and linker flags:

cmake_minimum_required(VERSION 3.10)
SET(CMAKE_VERBOSE_MAKEFILE ON)
project (MyProject C CXX ASM)


#Source Files -> Let CMake know your source files
SET(SRC_FILES       ${CMAKE_SOURCE_DIR}/Dir/main.c) 

add_executable(
        ${PROJECT_NAME}
        ${SRC_FILES})

#Defining compiler preprocessor directives
target_compile_definitions(${PROJECT_NAME} PRIVATE
        $<$<COMPILE_LANGUAGE:C>:  DEFINE_1;__DEBUG;>
        $<$<COMPILE_LANGUAGE:CXX>:DEFINE_2;__DEBUG;>)

#Defining compiler flags
target_compile_options(${PROJECT_NAME} PRIVATE
        $<$<COMPILE_LANGUAGE:C>:    --c99 -c -O0 --cpu ${MCU_ARCH};>
        $<$<COMPILE_LANGUAGE:CXX>:--cpp11 -c -O0 --cpu ${MCU_ARCH};>
        $<$<COMPILE_LANGUAGE:ASM>:--cpu ${MCU_ARCH} -g>)

SET(CMAKE_ASM_FLAGS         "--pd \"DEFINE_3"")
target_link_libraries(${PROJECT_NAME} ${CMAKE_SOURCE_DIR}/SomeLibFile.lib --flagForLibFile)
target_link_options(${PROJECT_NAME} PRIVATE --linkerFlags)

target_include_directories(${PROJECT_NAME} PUBLIC
        ${CMAKE_SOURCE_DIR})

For the necessary flags, have a look at what Keil is using.

Then you can build your application by passing the toolchain.cmake file as -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake

EDIT: Updated based on the feedback from KamilCuk

mmcblk1
  • 158
  • 1
  • 3
  • 10
  • 1
    `SET(CMAKE_EXE_LINKER_FLAGS` would be `add_link_options`/`target_link_options` in newer cmake. `--cpp11; -c; -O0; --cpu ${MCU_ARCH};` I think we could just remove the `;` in those lines. This is a good template to setup CMake in embedded world. – KamilCuk Apr 28 '20 at 06:52
  • @KamilCuk Yes, I guess we can use the `add_link_options/target_link_options` instead of the `SET(CMAKE_EXE_LINKER_FLAGS`. I did try that yesterday, but I had some flags which were so, `--info summarysizes`, and the space between the two words were creating an issue for me. I will figure it out soon. As for the `;`, you were right, I just compiled my application, without them. It does work! – mmcblk1 Apr 28 '20 at 06:58