Skip to content
Draft
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.idea
190 changes: 164 additions & 26 deletions Arduino-toolchain.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,180 @@
# A toolchain for the Arduino compatile boards.
# Please refer to README.md for the usage.

# If the version of CMake used is below 3.7.0, exit with error.
#
# Intended to support CMake version 3.0.0, but there are limitations which
# requires a minimum CMake version of 3.7.0. However, wherever possible, the
# toolchain remains compatible with 3.0.0, looking for some workarounds for
# the limitations in the future. The limitations are captured below.
#
# Version below 3.2.0 has no support for continue() command. Can be fixed.
#
# Version below 3.4.0 has no support for target properties BINARY_DIR,
# SOURCE_DIR etc. These are required in target command generator expressions.
#
# Version below 3.6.0 has issues in identifying try_compile output for
# static library. So there are some errors during the configuration, but
# may still possibly work.
# If the version of CMake used is below 3.9, exit with error.
# Version below 3.9.0 has no proper support for INTERPROCEDURAL_OPTIMIZATION.
#
# Version below 3.7.0 has no support for CMAKE_SYSTEM_CUSTOM_CODE, which
# is required when there is some dynamic information, like Board options,
# that needs to be included in the toolchain. Here just including the user
# provided path will not work, because the user variables, cache or root
# binary directory path etc. are not passed to try_compile.

if (CMAKE_VERSION VERSION_LESS 3.7.0)
message(FATAL_ERROR "CMake version below 3.7.0 unsupported!!!")
#[[
CLang building works only with llvm toolchain.

todo: CMAKE_<LANG>_FLAGS_INIT¶

USE_CLANG_AS_COMPILER - ON means CLang, OFF means GCC

GCC_COMPILERS_IN_USR_BIN - ON - GCC compilers are in /usr/bin, OFF - GCC compilers are in the dedicated dir
GCC_PREFIX_DOUBLE_USE - ON - gcc compilers name begins with "target double", OFF - doesn't
GCC_SUFFIX_VERSION_USE - ON means the tools will be called like gcc-11, OFF means tools will not have the postfix

LLVM_TOOLS_IN_USR_BIN - ON - LLVM compilers are in /usr/bin, OFF - LLVM compilers are in the dedicated dir
LLVM_SUFFIX_VERSION_USE - ON means the tools will be called like llvm-readelf-14 and clang-14, OFF means tools will not have the postfix
#]]

cmake_minimum_required(VERSION 3.9 FATAL_ERROR)

set(USE_CLANG_AS_COMPILER ON)
#set(REST_OF_TOOLCHAIN_IS_LLVM ON)
set(GCC_PREFIX_DOUBLE_USE ON)
set(GCC_COMPILERS_IN_USR_BIN OFF)
set(GCC_SUFFIX_VERSION_USE OFF)


if(NOT DEFINED CMAKE_HOST_WIN32)
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
set(CMAKE_HOST_WIN32 ON)
else()
set(CMAKE_HOST_WIN32 OFF)
endif()
endif()

if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
if(NOT DEFINED llvm_Version)
set(llvm_Version 14)
endif()

if(NOT DEFINED LLVM_SUFFIX_VERSION_USE)
set(LLVM_SUFFIX_VERSION_USE OFF)
endif()
if(NOT DEFINED GCC_PREFIX_DOUBLE_USE)
set(GCC_PREFIX_DOUBLE_USE OFF)
endif()
if(NOT DEFINED GCC_SUFFIX_VERSION_USE)
set(GCC_SUFFIX_VERSION_USE OFF)
endif()
if(NOT DEFINED GCC_SUFFIX_FLAVOUR_USE)
set(GCC_SUFFIX_FLAVOUR_USE OFF)
endif()

get_filename_component(DUMP_DIR "${CMAKE_CURRENT_LIST_DIR}" DIRECTORY) # CACHE PATH "The dir where we have unpacked CLang"
message(STATUS "DUMP_DIR ${DUMP_DIR}")
else()
if(NOT DEFINED GCC_COMPILERS_IN_USR_BIN)
set(GCC_COMPILERS_IN_USR_BIN ON)
endif()

if(NOT DEFINED LLVM_TOOLS_IN_USR_BIN)
set(LLVM_TOOLS_IN_USR_BIN OFF)
endif()
endif()

if(NOT DEFINED USE_CLANG_AS_COMPILER)
message(FATAL_ERROR "Set USE_CLANG_AS_COMPILER into ON if you want to build with CLang(++) and into OFF if you want to build with G(CC|++).")
endif()

if(NOT DEFINED REST_OF_TOOLCHAIN_IS_LLVM)
if(USE_CLANG_AS_COMPILER)
set(REST_OF_TOOLCHAIN_IS_LLVM ON)
else()
set(REST_OF_TOOLCHAIN_IS_LLVM OFF)
endif()
endif()

# Save the policy state. We will restore it at the end.
cmake_policy(PUSH)

# Set policy to above 3.0.0
cmake_policy(VERSION 3.0.0)
if(CMAKE_HOST_WIN32)
set(GCC_COMPILERS_IN_USR_BIN OFF)
set(LLVM_TOOLS_IN_USR_BIN OFF)
else()
if(NOT DEFINED GCC_COMPILERS_IN_USR_BIN)
message(FATAL_ERROR "You must specify GCC_COMPILERS_IN_USR_BIN")
endif()
endif()

# Interpret if() arguments without quotes as variables/keywords
if (NOT CMAKE_VERSION VERSION_LESS 3.1)
cmake_policy(SET CMP0054 NEW)
if(NOT DEFINED LLVM_TOOLS_IN_USR_BIN)
message(FATAL_ERROR "You must specify LLVM_TOOLS_IN_USR_BIN")
endif()

if(GCC_COMPILERS_IN_USR_BIN)
if(NOT DEFINED GCC_PREFIX_DOUBLE_USE)
set(GCC_PREFIX_DOUBLE_USE ON)
endif()
if(NOT DEFINED GCC_SUFFIX_VERSION_USE)
set(GCC_SUFFIX_VERSION_USE OFF)
endif()
endif()

if(NOT DEFINED GCC_PREFIX_DOUBLE_USE)
message(FATAL_ERROR "You must specify GCC_PREFIX_DOUBLE_USE")
endif()

if(NOT DEFINED GCC_SUFFIX_VERSION_USE)
message(FATAL_ERROR "You must specify GCC_SUFFIX_VERSION_USE")
endif()

if(NOT DEFINED TOOLCHAIN_NAME)
set(TOOLCHAIN_NAME "avr")
endif()

if(DEFINED ARDUINO_INSTALL_PATH)
if(NOT DEFINED AVR_GCC_ROOT)
set(AVR_GCC_ROOT "${ARDUINO_INSTALL_PATH}/hardware/tools/${TOOLCHAIN_NAME}")
endif()
endif()
message(STATUS "AVR_GCC_ROOT ${AVR_GCC_ROOT}")

if(REST_OF_TOOLCHAIN_IS_LLVM OR USE_CLANG_AS_COMPILER)
if(NOT DEFINED LLVM_SUFFIX_VERSION_USE)
if(LLVM_TOOLS_IN_USR_BIN)
set(LLVM_SUFFIX_VERSION_USE ON)
else()
set(LLVM_SUFFIX_VERSION_USE OFF)
endif()
endif()

if(NOT DEFINED llvm_Version)
if(CMAKE_HOST_WIN32)
message(FATAL_ERROR "You must specify LLVM version into llvm_Version. It is used to set the right additional flags for clang.")
else()
include("${CMAKE_CURRENT_LIST_DIR}/Arduino/System/DetectInstalledLLVMVersion.cmake")
detect_llvm_version(llvm_Version LLVM_ROOT "/usr/lib")
endif()
endif()

if(CMAKE_HOST_WIN32)
if(NOT DEFINED LLVM_ROOT)
if(DEFINED DUMP_DIR)
set(LLVM_ROOT "${DUMP_DIR}/LLVM-${llvm_Version}.0.0-win32")
else()
message(FATAL_ERROR "You must set DUMP_DIR if you don't specify the full path to CLang base dir in LLVM_ROOT") # CACHE PATH "Path to Clang root"
endif()
endif()
else()
if(NOT DEFINED LLVM_ROOT)
if(LLVM_TOOLS_IN_USR_BIN)
set(LLVM_ROOT "") # CACHE PATH "Path to Clang root"
else()
set(LLVM_ROOT "/usr/lib/llvm-${llvm_Version}") # CACHE PATH "Path to Clang root"
endif()
endif()
endif()

if(NOT DEFINED LLVM_SUFFIX_VERSION_USE)
message(FATAL_ERROR "You must specify LLVM_SUFFIX_VERSION_USE")
endif()

if(NOT DEFINED AVR_GCC_ROOT)
set(AVR_GCC_ROOT "/usr/${double}")
endif()# CACHE PATH "Path to MinGW root"

message(STATUS "CLang root: ${LLVM_ROOT}")
message(STATUS "AVR GCC root: ${AVR_GCC_ROOT}")
endif()


#*****************************************************************************
# Set system name and basic information
set(CMAKE_SYSTEM_NAME "Arduino")
Expand Down Expand Up @@ -91,8 +228,9 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

# Workaround for CMAKE_TRY_COMPILE_TARGET_TYPE. For later ESP32 cores this file is missing
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/build_opt.h" "")

# Do not try to link during the configure time, due to the dependency on the
# core, which we do not have a target yet.
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

cmake_policy(POP)
24 changes: 17 additions & 7 deletions Arduino/System/BoardBuildTargets.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,7 @@ function(_link_ard_lib_list target_name lib_list_var link_type

# Finally link the target with all the libraries
# message("target_link_libraries(\"${target_name}\" ${link_type} ${_link_targets})")
message(STATUS "_link_targets ${_link_targets}")
if (_link_targets)
target_link_libraries("${target_name}" ${link_type}
${_link_targets})
Expand Down Expand Up @@ -736,6 +737,7 @@ function(_add_internal_arduino_library target lib)
set(lib_sources "${CMAKE_CURRENT_BINARY_DIR}/${target}_dummy.cpp")
endif()

message(STATUS "lib target ${target}" )
add_library("${target}" STATIC ${lib_headers} ${lib_sources})
# message("\"${include_dirs}\"")
target_include_directories(${target} PUBLIC ${include_dirs})
Expand Down Expand Up @@ -769,6 +771,7 @@ function(_add_internal_arduino_core target)
# get_headers_parent_directories("${core_headers};${variant_headers}" include_dirs)

# Add the library and set the include directories
message(STATUS "core lib target ${target} ${core_sources}")
add_library("${target}" STATIC ${core_headers} ${core_sources}
${variant_headers} ${variant_sources})
# target_include_directories(${target} PUBLIC ${include_dirs})
Expand Down Expand Up @@ -861,8 +864,8 @@ function(_library_search_process lib search_paths_var search_suffixes_var return
# message("Folder match ${lib}:${dir}:${folder_name_priority}")

# Check for architecture match
file(STRINGS "${dir}/library.properties" arch_str REGEX "architectures=.*")
string(REGEX MATCH "architectures=(.*)" arch_list "${arch_str}")
file(STRINGS "${dir}/library.properties" arch_str REGEX "^architectures=.*")
string(REGEX MATCH "^architectures=(.*)" arch_list "${arch_str}")
string(REPLACE "," ";" arch_list "${CMAKE_MATCH_1}")
string(TOUPPER "${ARDUINO_BOARD_BUILD_ARCH}" board_arch)

Expand Down Expand Up @@ -916,11 +919,18 @@ function(_library_search_process lib search_paths_var search_suffixes_var return
endif()

# Although we got the match, let us search for the required header within the folder
file(GLOB_RECURSE lib_header_path "${matched_lib_path}/${lib}.h*")
if (NOT lib_header_path)
set ("${return_var}" "${lib}-NOTFOUND" PARENT_SCOPE)
return()
endif()
file(STRINGS "${matched_lib_path}/library.properties" incl_list REGEX "^includes=.*")
string(REGEX MATCH "^includes=(.*)" incl_list "${arch_str}")
string(REPLACE "," ";" incl_list "${CMAKE_MATCH_1}")

foreach(h ${incl_list})
file(GLOB_RECURSE lib_header_path "${matched_lib_path}/${h}.h*")
if (NOT lib_header_path)
message(STATUS "Header ${h} for ${lib} is not found.")
set ("${return_var}" "${lib}-NOTFOUND" PARENT_SCOPE)
return()
endif()
endforeach()

set ("${return_var}" "${matched_lib_path}" PARENT_SCOPE)

Expand Down
Loading