blob: 5a8fa599ff8ad792b8cfc8184731acb736aa61d8 [file] [log] [blame]
#-------------------------------------------------------------------------------
# Copyright (c) 2019-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
#[===[.rst:
Compiler abstraction for GCC
----------------------------
.. cmake:variable:: CROSS_COMPILE
A ';' separated GCC prefix triplets to use when searching for the cross-compiler.
(i.e. ``aarch64-none-elf;aarch64-elf``).
The variable can be set on the command line with ``-DCROSS_COMPILE=<value>`` or in the
environment. If both is specified, command line takes precedence.
#]===]
include_guard(DIRECTORY)
if(NOT CROSS_COMPILE AND NOT DEFINED ENV{CROSS_COMPILE})
message(FATAL_ERROR "'CROSS_COMPILE' is not defined. Set it to the gcc pferix triplet, ie. cmake <..>-DCROSS_COMPILE=aarch64-elf-")
endif()
set(CROSS_COMPILE $ENV{CROSS_COMPILE} CACHE STRING "Prefix of the cross-compiler commands")
#Generate a list of tool names to look for. Store the result in CMAKE_<lang>_COMPILER.
function(gcc_find_tool NAME LANG)
string(REGEX REPLACE "([^;]+);" "\\1${NAME};\\1${NAME}.exe;" _gcc_names "${CROSS_COMPILE};")
find_program(_cross_compile_gcc NAMES ${_gcc_names} REQUIRED)
if (NOT _cross_compile_gcc)
string(REPLACE ";" " " _msg "${_gcc_names}")
message(FATAL_ERROR "Failed to find ${NAME} with the names: ${_msg}")
endif()
set(CMAKE_${LANG}_COMPILER ${_cross_compile_gcc} CACHE STRING "${LANG} compiler executable.")
endfunction()
gcc_find_tool(gcc C)
gcc_find_tool(g++ CXX)
#Official solution to disable compiler checks
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
#By default when INTERFACE_INCUDES of libraryes linked to an exe are treated
#as system includes. gcc-arm-8.2-2019.01-i686-mingw32-aarch64-elf (gcc 8.2.1) will
#set C linkage o these files, which will result in compilation errors for C++ projects.
#This setting fixes that.
set(CMAKE_NO_SYSTEM_FROM_IMPORTED True)
#[===[.rst:
.. cmake:command:: compiler_preprocess_file
.. code-block:: cmake
compiler_preprocess_file(SRC file.c DST file_pp.c)
compiler_preprocess_file(SRC file.c DST file_pp.c
DEFINES USE_LIB INCLUDES include/lib)
Run the preprocessor on a file and save the output to another file. Optionally
provide defines and include paths to the preprocessor.
Inputs:
``SRC``
Name of the source file to preprocess.
``DST``
Where to write the preprocessed output.
``DEFINES`` (multi, optional)
Definitions for the preprocessor.
``INCLUDES`` (multi, optional)
Include paths for the preprocessor.
#]===]
function(compiler_preprocess_file)
set(_OPTIONS_ARGS)
set(_ONE_VALUE_ARGS SRC DST)
set(_MULTI_VALUE_ARGS DEFINES INCLUDES)
cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
check_args(compiler_preprocess_file SRC DST)
set(_flags "")
if(_MY_PARAMS_DEFINES)
list(TRANSFORM _MY_PARAMS_DEFINES PREPEND -D)
list(APPEND _flags ${_MY_PARAMS_DEFINES})
endif()
if(_MY_PARAMS_INCLUDES)
list(TRANSFORM _MY_PARAMS_INCLUDES PREPEND -I)
list(APPEND _flags ${_MY_PARAMS_INCLUDES})
endif()
add_custom_command(
DEPENDS ${_MY_PARAMS_SRC} OUTPUT ${_MY_PARAMS_DST}
COMMAND ${CMAKE_C_COMPILER} -E -P -x assembler-with-cpp ${_flags}
${_MY_PARAMS_SRC} -o ${_MY_PARAMS_DST}
)
endfunction()
#[===[.rst:
.. cmake:command:: compiler_set_linker_script
.. code-block:: cmake
compiler_set_linker_script(TARGET foo FILE foo.ld.S)
compiler_set_linker_script(TARGET foo FILE foo.ld.S DEF USE_LIB INC include/lib)
Set linker script for a target. The function adds an LDFLAG using the
toolchain specific syntax to the TARGET_linker_script group, which is applied
onto the target by the caller function. FILE will be preprocessed, optionally
defines and/or includes can be provided using DEF/INC arguments.
Inputs:
``TARGET``
Name of the target.
``FILE``
Linker script file for the target.
``DEF`` (multi, optional)
Defines for the linker script preprocessor.
``INC`` (multi, optional)
Include paths for the linker script preprocessor.
#]===]
function(compiler_set_linker_script)
set(_OPTIONS_ARGS)
set(_ONE_VALUE_ARGS TARGET FILE)
set(_MULTI_VALUE_ARGS DEF INC)
cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
check_args(compiler_set_linker_script TARGET FILE)
get_filename_component(_src "${_MY_PARAMS_FILE}" ABSOLUTE)
get_filename_component(_src_ext "${_MY_PARAMS_FILE}" EXT)
set(_dst "${CMAKE_BINARY_DIR}/${_MY_PARAMS_TARGET}.ld")
if(NOT ("${_src_ext}" STREQUAL ".ld" OR "${_src_ext}" STREQUAL ".ld.S"))
message(WARNING "compiler_set_linker_script(): extension mismatch '${_src}'")
endif()
compiler_preprocess_file(
SRC ${_src}
DST ${_dst}
DEFINES ${_MY_PARAMS_DEF} __LINKER__
INCLUDES ${_MY_PARAMS_INC}
)
add_custom_target("${_MY_PARAMS_TARGET}_ld" DEPENDS "${_dst}")
add_dependencies("${_MY_PARAMS_TARGET}" "${_MY_PARAMS_TARGET}_ld")
target_link_options(${_MY_PARAMS_TARGET} PRIVATE "-Wl,--script=${_dst}")
set_target_properties(${_MY_PARAMS_TARGET} PROPERTIES LINK_DEPENDS "${_dst}")
endfunction()
#[===[.rst:
.. cmake:command:: compiler_generate_binary_output
.. code-block:: cmake
compiler_generate_binary_output(TARGET <name> RES <var>)
Generate binary output for the target. The function converts the output
executable into bin file using toolchain specific syntax.
Inputs:
``TARGET``
Name of the target.
Outputs:
``RES``
Full patch to output file.
#]===]
function(compiler_generate_binary_output)
set(options)
set(oneValueArgs TARGET NAME RES)
set(multiValueArgs)
cmake_parse_arguments(MY "${options}" "${oneValueArgs}"
"${multiValueArgs}" ${ARGN} )
add_custom_command(
TARGET ${MY_TARGET} POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -O binary
$<TARGET_FILE:${MY_TARGET}>
$<TARGET_FILE_DIR:${MY_TARGET}>/${MY_NAME})
if (MY_RES)
set(${MY_RES} $<TARGET_FILE_DIR:${MY_TARGET}>/${MY_NAME} PARENT_SCOPE)
endif()
endfunction()
#[===[.rst:
.. cmake:command:: compiler_generate_stripped_elf
.. code-block:: cmake
compiler_generate_stripped_elf(TARGET foo NAME foo.stripped.elf RES var)
Strip all symbols that are not needed for relocation processing and return the location
of the result.
Inputs:
``TARGET``
Name of the target.
``NAME``
Name of output file
Outputs:
``RES``
Name of variable to store the full path of the stripped executable.
#]===]
function(compiler_generate_stripped_elf)
set(options)
set(oneValueArgs TARGET NAME RES)
set(multiValueArgs)
cmake_parse_arguments(MY "${options}" "${oneValueArgs}"
"${multiValueArgs}" ${ARGN} )
add_custom_command(
TARGET ${MY_TARGET} POST_BUILD
COMMAND ${CMAKE_OBJCOPY} --strip-unneeded
$<TARGET_FILE:${MY_TARGET}>
$<TARGET_FILE_DIR:${MY_TARGET}>/${MY_NAME})
if (MY_RES)
set(${MY_RES} $<TARGET_FILE_DIR:${MY_TARGET}>/${MY_NAME} PARENT_SCOPE)
endif()
endfunction()
#[===[.rst:
.. cmake:command:: gcc_get_lib_location
.. code-block:: cmake
gcc_get_lib_location(TARGET foo NAME foo.stripped.elf RES var)
Query the location of a specific library part of the GCC binary release. Can
be used to find built in libraryes like libgcc.a when i.w. -nostdlib option
is used.
Inputs:
``LIBRARY_NAME``
Name of the library to search for.
Outputs:
``RES``
Name of variable to store the full path of the library.
#]===]
function(gcc_get_lib_location)
set(options)
set(oneValueArgs LIBRARY_NAME RES)
set(multiValueArgs)
cmake_parse_arguments(MY "${options}" "${oneValueArgs}"
"${multiValueArgs}" ${ARGN} )
execute_process(
COMMAND ${CMAKE_C_COMPILER} "--print-file-name=${MY_LIBRARY_NAME}"
OUTPUT_VARIABLE _RES
RESULT_VARIABLE _GCC_ERROR_CODE
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(_GCC_ERROR_CODE GREATER 0)
message(WARNING "GCC (${CMAKE_C_COMPILER}) invocation failed, cannot determine location of library \"${MY_LIBRARY_NAME}\".")
set(_RES "${LIBRARY_NAME}-NOTFOUND")
endif()
if (NOT IS_ABSOLUTE "${_RES}")
message(WARNING "GCC (${CMAKE_C_COMPILER}) failed to return the location of file \"${MY_LIBRARY_NAME}\".")
set(_RES "${LIBRARY_NAME}-NOTFOUND")
endif()
set(${MY_RES} ${_RES} PARENT_SCOPE)
endfunction()