Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented building with clang and transferred control on compilation flags back to CMake #60

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
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