diff --git a/Modules/AVREeprom2Hex.cmake b/Modules/AVREeprom2Hex.cmake new file mode 100644 index 0000000..6de56b3 --- /dev/null +++ b/Modules/AVREeprom2Hex.cmake @@ -0,0 +1,64 @@ +#============================================================================= +# Copyright 2016 Sam Hanes +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file COPYING.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake-Microchip, +# substitute the full License text for the above reference.) + + +function(avr_eeprom2hex target) + find_program(AVR_EEPROM2HEX + NAMES ${_CMAKE_TOOLCHAIN_PREFIX}avr-objcopy avr-objcopy + HINTS ${_CMAKE_TOOLCHAIN_LOCATION} + ) + + if(NOT AVR_EEPROM2HEX) + message(SEND_ERROR "No avr-objcopy program was found") + endif() + + function(get_target_property_fallback var target) + set(result NOTFOUND) + foreach(property ${ARGN}) + get_target_property(result ${target} ${property}) + if(result) + break() + endif() + endforeach() + set(${var} ${result} PARENT_SCOPE) + endfunction() + + get_target_property_fallback(in_f ${target} + RUNTIME_OUTPUT_NAME + OUTPUT_NAME + NAME + ) + + get_target_property_fallback(dir ${target} + RUNTIME_OUTPUT_DIRECTORY + BINARY_DIR + ) + + get_filename_component(out_f ${in_f} NAME_WE) + set(out_f "${out_f}$<$:${CMAKE_DEBUG_POSTFIX}>.eep") + + add_custom_command( + TARGET ${target} POST_BUILD + WORKING_DIRECTORY ${dir}/$ + COMMAND "${AVR_EEPROM2HEX}" -j .eeprom --set-section-flags=.eeprom=alloc,load --change-section-lma .eeprom=0 --no-change-warnings ${ARGN} -O ihex "${in_f}$<$:${CMAKE_DEBUG_POSTFIX}>.elf" "${out_f}" + BYPRODUCTS ${dir}/$/${out_f} + VERBATIM + ) + + set_property(DIRECTORY APPEND + PROPERTY ADDITIONAL_MAKE_CLEAN_FILES + ${dir}/$/${out_f} + ) + + install(FILES ${dir}/$/${out_f} TYPE BIN) +endfunction() diff --git a/Modules/AVRObj2Hex.cmake b/Modules/AVRObj2Hex.cmake new file mode 100644 index 0000000..5cb255a --- /dev/null +++ b/Modules/AVRObj2Hex.cmake @@ -0,0 +1,64 @@ +#============================================================================= +# Copyright 2016 Sam Hanes +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file COPYING.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake-Microchip, +# substitute the full License text for the above reference.) + + +function(avr_obj2hex target) + find_program(AVR_OBJ2HEX + NAMES ${_CMAKE_TOOLCHAIN_PREFIX}avr-objcopy avr-objcopy + HINTS ${_CMAKE_TOOLCHAIN_LOCATION} + ) + + if(NOT AVR_OBJ2HEX) + message(SEND_ERROR "No avr-objcopy program was found") + endif() + + function(get_target_property_fallback var target) + set(result NOTFOUND) + foreach(property ${ARGN}) + get_target_property(result ${target} ${property}) + if(result) + break() + endif() + endforeach() + set(${var} ${result} PARENT_SCOPE) + endfunction() + + get_target_property_fallback(in_f ${target} + RUNTIME_OUTPUT_NAME + OUTPUT_NAME + NAME + ) + + get_target_property_fallback(dir ${target} + RUNTIME_OUTPUT_DIRECTORY + BINARY_DIR + ) + + get_filename_component(out_f ${in_f} NAME_WE) + set(out_f "${out_f}$<$:${CMAKE_DEBUG_POSTFIX}>.hex") + + add_custom_command( + TARGET ${target} POST_BUILD + WORKING_DIRECTORY ${dir}/$ + COMMAND "${AVR_OBJ2HEX}" -O ihex ${ARGN} "${in_f}$<$:${CMAKE_DEBUG_POSTFIX}>.elf" "${out_f}" + BYPRODUCTS ${dir}/$/${out_f} + VERBATIM + ) + + set_property(DIRECTORY APPEND + PROPERTY ADDITIONAL_MAKE_CLEAN_FILES + ${dir}/$/${out_f} + ) + + install(FILES ${dir}/$/${out_f} TYPE BIN) +endfunction() diff --git a/Modules/Compiler/AVRGCC-C.cmake b/Modules/Compiler/AVRGCC-C.cmake new file mode 100644 index 0000000..4e9de0c --- /dev/null +++ b/Modules/Compiler/AVRGCC-C.cmake @@ -0,0 +1,44 @@ +#============================================================================= +# Copyright 2019 Sam Hanes +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file COPYING.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake-Microchip, +# substitute the full License text for the above reference.) + +# called by `CMakeCInformation` +# to configure the AVR GCC compiler interface for C files + +string(TOLOWER ${MICROCHIP_MCU_MODEL} MMCU) + +string(APPEND CMAKE_C_FLAGS_INIT + # build for the configured MCU model + " -mmcu=${MMCU}" +) + +set(CMAKE_C_OUTPUT_EXTENSION ".p1") +set(CMAKE_EXECUTABLE_SUFFIX ".elf") + +set(CMAKE_C_COMPILE_OBJECT) +string(APPEND CMAKE_C_COMPILE_OBJECT + " " + " -o -c " +) + +set(CMAKE_C_LINK_EXECUTABLE) +string(APPEND CMAKE_C_LINK_EXECUTABLE + " " + " " + " -o " +) + +set(CMAKE_C_CREATE_STATIC_LIBRARY) +string(APPEND CMAKE_C_CREATE_STATIC_LIBRARY + " -r " + " " +) diff --git a/Modules/Compiler/AVRGCC-CXX.cmake b/Modules/Compiler/AVRGCC-CXX.cmake new file mode 100644 index 0000000..3cbbaee --- /dev/null +++ b/Modules/Compiler/AVRGCC-CXX.cmake @@ -0,0 +1,44 @@ +#============================================================================= +# Copyright 2019 Sam Hanes +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file COPYING.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake-Microchip, +# substitute the full License text for the above reference.) + +# called by `CMakeCInformation` +# to configure the AVR GCC compiler interface for C files + +string(TOLOWER ${MICROCHIP_MCU_MODEL} MMCU) + +string(APPEND CMAKE_CXX_FLAGS_INIT + # build for the configured MCU model + " -mmcu=${MMCU}" +) + +set(CMAKE_CXX_OUTPUT_EXTENSION ".p1") +set(CMAKE_EXECUTABLE_SUFFIX ".elf") + +set(CMAKE_CXX_COMPILE_OBJECT) +string(APPEND CMAKE_CXX_COMPILE_OBJECT + " " + " -o -c " +) + +set(CMAKE_CXX_LINK_EXECUTABLE) +string(APPEND CMAKE_CXX_LINK_EXECUTABLE + " " + " " + " -o " +) + +set(CMAKE_CXX_CREATE_STATIC_LIBRARY) +string(APPEND CMAKE_CXX_CREATE_STATIC_LIBRARY + " -r " + " " +) diff --git a/Modules/Compiler/XC8-C.cmake b/Modules/Compiler/XC8-C.cmake index 79c81a5..8c2bff6 100644 --- a/Modules/Compiler/XC8-C.cmake +++ b/Modules/Compiler/XC8-C.cmake @@ -13,6 +13,8 @@ # called by `CMakeCInformation` # to configure the XC8 compiler interface for C files +# this supports the `xc8` CLI driver in XC8 1.x +# and the equivalent legacy CLI driver in XC8 2.x set(MICROCHIP_XC8_MODE "free" @@ -28,7 +30,10 @@ string(APPEND CMAKE_C_FLAGS_INIT " --chip=${MICROCHIP_MCU_MODEL}" ) + set(CMAKE_C_OUTPUT_EXTENSION ".p1") +set(CMAKE_STATIC_LIBRARY_SUFFIX_C ".lpp") + set(CMAKE_C_COMPILE_OBJECT) string(APPEND CMAKE_C_COMPILE_OBJECT @@ -42,3 +47,10 @@ string(APPEND CMAKE_C_LINK_EXECUTABLE " " " -o" ) + +set(CMAKE_C_CREATE_STATIC_LIBRARY) +string(APPEND CMAKE_C_CREATE_STATIC_LIBRARY + " " + " " + " --output=lpp -o" +) diff --git a/Modules/Compiler/XC8CC-C.cmake b/Modules/Compiler/XC8CC-C.cmake new file mode 100644 index 0000000..cd20287 --- /dev/null +++ b/Modules/Compiler/XC8CC-C.cmake @@ -0,0 +1,50 @@ +#============================================================================= +# Copyright 2019 Sam Hanes +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file COPYING.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake-Microchip, +# substitute the full License text for the above reference.) + +# called by `CMakeCInformation` +# to configure the XC8CC compiler interface for C files +# this supports the xc8-cc CLI driver from XC8 v2.x + + +string(APPEND CMAKE_C_FLAGS_INIT + # build for the configured MCU model + " -mcpu=${MICROCHIP_MCU_MODEL}" +) +if(CMAKE_SYSTEM_PROCESSOR STREQUAL "PIC_8") + string(APPEND CMAKE_C_FLAGS_INIT + # fail if the requested optimization level is forbidden by the license + " --nofallback" + ) +endif() + +set(CMAKE_C_OUTPUT_EXTENSION ".p1") +set(CMAKE_EXECUTABLE_SUFFIX ".elf") + +set(CMAKE_C_COMPILE_OBJECT) +string(APPEND CMAKE_C_COMPILE_OBJECT + " " + " -o -c " +) + +set(CMAKE_C_LINK_EXECUTABLE) +string(APPEND CMAKE_C_LINK_EXECUTABLE + " " + " " + " -o " +) + +set(CMAKE_C_CREATE_STATIC_LIBRARY) +string(APPEND CMAKE_C_CREATE_STATIC_LIBRARY + " -r " + " " +) diff --git a/Modules/Platform/MicrochipMCU-C-XC8.cmake b/Modules/Platform/MicrochipMCU-C-XC8.cmake index 9eae357..8c16885 100644 --- a/Modules/Platform/MicrochipMCU-C-XC8.cmake +++ b/Modules/Platform/MicrochipMCU-C-XC8.cmake @@ -27,19 +27,85 @@ if(NOT MICROCHIP_XC8_PATH) ) endif() - set(CMAKE_FIND_ROOT_PATH "${MICROCHIP_XC8_PATH}") +set(CMAKE_PREFIX_PATH "${MICROCHIP_XC8_PATH}") -# skip compiler search and just use XC8 -find_program(CMAKE_C_COMPILER "xc8" - PATHS "${MICROCHIP_XC8_PATH}" - PATH_SUFFIXES "bin" +if(NOT MICROCHIP_XC8_CLI) + set(MICROCHIP_XC8_CLI "xc8-cc") + set(_xc8_cli_default TRUE CACHE INTERNAL "" FORCE) +endif() +set(MICROCHIP_XC8_CLI "${MICROCHIP_XC8_CLI}" + CACHE STRING "the XC8 CLI driver to use ('xc8-cc', 'xc8' or 'avr-gcc')" ) +if(MICROCHIP_XC8_CLI STREQUAL "xc8-cc") + find_program(CMAKE_C_COMPILER "xc8-cc" + PATHS "${MICROCHIP_XC8_PATH}" + PATH_SUFFIXES "bin" + ) + find_program(CMAKE_AR "xc8-ar" + PATHS "${MICROCHIP_XC8_PATH}" + PATH_SUFFIXES "bin" + ) + set(_xc8_version_flag "--version") + set(CMAKE_C_COMPILER_ID "XC8CC") + +elseif(MICROCHIP_XC8_CLI STREQUAL "xc8") + find_program(CMAKE_C_COMPILER "xc8" + PATHS "${MICROCHIP_XC8_PATH}" + PATH_SUFFIXES "bin" + ) + set(_xc8_version_flag "--ver") + set(CMAKE_C_COMPILER_ID "XC8") + +elseif(MICROCHIP_XC8_CLI STREQUAL "avr-gcc") + find_program(CMAKE_C_COMPILER "avr-gcc" + PATHS "${MICROCHIP_XC8_PATH}" + PATH_SUFFIXES "avr/bin" + ) + find_program(CMAKE_CXX_COMPILER "avr-gcc" + PATHS "${MICROCHIP_XC8_PATH}" + PATH_SUFFIXES "avr/bin" + ) + find_program(CMAKE_AR "avr-ar" + PATHS "${MICROCHIP_XC8_PATH}" + PATH_SUFFIXES "avr/bin" + ) + set(_xc8_version_flag "--version") + set(CMAKE_C_COMPILER_ID "AVRGCC") + set(CMAKE_CXX_COMPILER_ID "AVRGCC") + +else() + message(FATAL_ERROR + "Invalid choice '${MICROCHIP_XC8_CLI}' for MICROCHIP_XC8_CLI." + " Please choose either 'xc8-cc' (recommended), 'xc8' or 'avr-gcc'." + " See docs/xc8.md in your cmake-microchip installation for" + " details on this option." + ) +endif() + if(NOT CMAKE_C_COMPILER) + if(_xc8_cli_default) + message(WARNING + "The XC8 command-line driver was not explicitly selected," + " so the newer 'xc8-cc' driver is being used. This requires" + " XC8 version 2.00 or newer. If you want to use older versions" + " of XC8, or if you want to use the legacy 'xc8' driver in XC8" + " 2.00 or newer, add this line to your CMakeLists.txt before" + " the 'project' command:\n" + " set(MICROCHIP_XC8_CLI xc8)\n" + "To suppress this message when XC8 is not found but continue" + " using the newer 'xc8-cc' driver, add this line to your" + " CMakeLists.txt before the 'project' command:\n" + " set(MICROCHIP_XC8_CLI xc8-cc)\n" + "For more information on selecting a command-line driver" + " see docs/xc8.md in your cmake-microchip installation." + ) + endif() + message(FATAL_ERROR - "The XC8 compiler executable was not found, but what looks" - " like an XC8 installation was found at:\n" + "The XC8 compiler executable ${MICROCHIP_XC8_CLI} was not found," + " but what looks like an XC8 installation was found at:\n" " ${MICROCHIP_XC8_PATH}\n" "Please provide the path to a working XC8 installation on the" " command line, for example:\n" @@ -49,28 +115,31 @@ endif() # skip compiler ID since XC8 isn't supported by CMake's test file set(CMAKE_C_COMPILER_ID_RUN 1) -set(CMAKE_C_COMPILER_ID "XC8") +set(CMAKE_CXX_COMPILER_ID_RUN 1) # call the compiler to check its version function(_xc8_get_version) execute_process( - COMMAND "${CMAKE_C_COMPILER}" "--ver" + COMMAND "${CMAKE_C_COMPILER}" "${_xc8_version_flag}" OUTPUT_VARIABLE output ERROR_VARIABLE output RESULT_VARIABLE result ) - + if(result) message(FATAL_ERROR - "Calling '${CMAKE_C_COMPILER} --ver' failed." + "Calling '${CMAKE_C_COMPILER} ${_xc8_version_flag}' failed." ) endif() if(output MATCHES "XC8 C Compiler V([0-9]+\.[0-9]+)") set(CMAKE_C_COMPILER_VERSION ${CMAKE_MATCH_1} PARENT_SCOPE) + elseif(output MATCHES "(avr-gcc)(.*\\)) ([0-9]+.[0-9]+.[0-9]+)") + set(CMAKE_C_COMPILER_VERSION ${CMAKE_MATCH_3} PARENT_SCOPE) + set(CMAKE_CXX_COMPILER_VERSION ${CMAKE_MATCH_3} PARENT_SCOPE) else() message(FATAL_ERROR - "Failed to parse output of '${CMAKE_C_COMPILER} --ver'." + "Failed to parse output of '${CMAKE_C_COMPILER} ${_xc8_version_flag}'." ) endif() endfunction() diff --git a/Modules/Platform/MicrochipMCU-C.cmake b/Modules/Platform/MicrochipMCU-C.cmake index f173a88..b55ece3 100644 --- a/Modules/Platform/MicrochipMCU-C.cmake +++ b/Modules/Platform/MicrochipMCU-C.cmake @@ -14,7 +14,7 @@ # This module is loaded during the search for a C compiler # to provide the information necessary to find one. -if(CMAKE_SYSTEM_PROCESSOR STREQUAL "PIC_8") +if(CMAKE_SYSTEM_PROCESSOR STREQUAL "PIC_8" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "AVR") include(Platform/MicrochipMCU-C-XC8) elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "PIC_16") include(Platform/MicrochipMCU-C-XC16) diff --git a/Modules/Platform/MicrochipMCU.cmake b/Modules/Platform/MicrochipMCU.cmake index ebd1bdd..00b19e5 100644 --- a/Modules/Platform/MicrochipMCU.cmake +++ b/Modules/Platform/MicrochipMCU.cmake @@ -22,4 +22,6 @@ set(CMAKE_SYSTEM_INCLUDE_PATH /include) set(CMAKE_SYSTEM_LIBRARY_PATH /lib) set(CMAKE_SYSTEM_PROGRAM_PATH /bin) +include(AVREeprom2Hex) +include(AVRObj2Hex) include(MicrochipBin2Hex) diff --git a/README.rst b/README.rst index ca4edfb..794fb32 100644 --- a/README.rst +++ b/README.rst @@ -3,8 +3,7 @@ CMake for the Microchip Toolchain ################################# This project provides toolchains and other support modules to enable -using `CMake`_ with the `Microchip compilers`_, although presently only -XC16 is supported. +using `CMake`_ with the `Microchip compilers`_. .. _CMake: https://cmake.org/ .. _Microchip compilers: http://www.microchip.com/mplab/compilers diff --git a/docs/xc8.md b/docs/xc8.md new file mode 100644 index 0000000..de0f183 --- /dev/null +++ b/docs/xc8.md @@ -0,0 +1,56 @@ + +## Versions + +In XC8 version 2.00, Microchip switched from their proprietary HI-TECH C +frontend to Clang in order to support C99. Rather than implement PIC +code generation in LLVM, they translate LLVM's IR to p-code (the HI-TECH +IR), which is then run through the same code generator used with the old +HI-TECH frontend. Although they use Clang by default, current versions +of XC8 still include the HI-TECH C frontend to support older projects. +They've also bundled in AVR-GCC to support AVR parts. + +### Command-line Driver + +Since they now need to support multiple compilers, Microchip also +introduced a new command-line driver, `xc8-cc`, in XC8 2.00. `xc8-cc` +is completely custom, but it uses GCC-style options for compatibility +with XC16 and XC32. The old command-line driver `xc8` was retained for +backwards compatibility. + +You can select which command-line driver to use by setting +`MICROCHIP_XC8_CLI` to either `xc8-cc`, `xc8` or `avr-gcc` in your `CMakeLists.txt` +before calling the `project` command (which is when compiler resolution +occurs). For example: + +```cmake +# set up the Microchip cross toolchain +set(CMAKE_TOOLCHAIN_FILE external/cmake-microchip/toolchain.cmake) + +# set the default MCU model +set(MICROCHIP_MCU PIC18F87J50) + +# use the new command-line driver +set(MICROCHIP_XC8_CLI xc8-cc) + + +project(example C) +``` + +`MICROCHIP_XC8_CLI` may also be set on the command line as a cache +variable, although doing so may break your project if you use +command-line flags in your configuration that are specific to one of the +drivers. For example: + +```plain +cmake -DMICROCHIP_XC8_CLI=xc8 -DMICROCHIP_XC8_PATH=/opt/microchip/xc8/v1.45 . +``` + +For new projects it is recommended to use `xc8-cc`, which is the default +in cmake-microchip as of version 0.3. Using `xc8-cc` is required if you +want to use Clang (for C99) or AVR-GCC. + +Using the legacy `xc8` command-line driver is only recommended if you +need to support versions of XC8 before 2.00, or if you have a significant +number of command-line flags for `xc8` already and don't want to port +them. It is *not* necessary to use `xc8` in order to use the old HI-TECH +C frontend. diff --git a/toolchain.cmake b/toolchain.cmake index 86a1429..9021973 100644 --- a/toolchain.cmake +++ b/toolchain.cmake @@ -21,7 +21,8 @@ # CMP0057 (IN_LIST operator) since 3.3 -cmake_minimum_required(VERSION 3.3) +# CMP0058 (BYPRODUCTS option for add_costum_command) since 3.2 but starting with 3.20 it supports generator expressions +cmake_minimum_required(VERSION 3.20) # record the directory containing this script @@ -56,12 +57,15 @@ set(MICROCHIP_MCU "${MICROCHIP_MCU}" CACHE STRING "full model number of the target Microchip MCU" ) - # known 8-bit MCU families list(APPEND MICROCHIP_FAMILIES_8 PIC12F PIC16F PIC18F + ATtiny + ATxmega + ATmega + AVRDA ) # known 16-bit MCU families @@ -112,7 +116,28 @@ elseif(MICROCHIP_MCU MATCHES "^(dsPIC|PIC)(32M[XZ]|[0-9]+[A-Z])([A-Z0-9]+)$") "Unsupported MCU family '${MICROCHIP_MCU_FAMILY}'." ) endif() - + +elseif(MICROCHIP_MCU MATCHES "^(AT)(tiny|mega|xmega)([a-zA-Z0-9]+)$") + set(MICROCHIP_MCU_FAMILY "${CMAKE_MATCH_1}${CMAKE_MATCH_2}") + set(MICROCHIP_MCU_MODEL "${MICROCHIP_MCU}") + if(MICROCHIP_MCU_FAMILY IN_LIST MICROCHIP_FAMILIES_8) + set(CMAKE_SYSTEM_PROCESSOR "AVR") + else() + message(FATAL_ERROR + "Unsupported MCU family '${MICROCHIP_MCU_FAMILY}'." + ) + endif() + +elseif(MICROCHIP_MCU MATCHES "^(AVR)([0-9]+)(DA)([0-9]+)$") + set(MICROCHIP_MCU_FAMILY "${CMAKE_MATCH_1}${CMAKE_MATCH_3}") + set(MICROCHIP_MCU_MODEL "${MICROCHIP_MCU}") + if(MICROCHIP_MCU_FAMILY IN_LIST MICROCHIP_FAMILIES_8) + set(CMAKE_SYSTEM_PROCESSOR "AVR") + else() + message(FATAL_ERROR + "Unsupported MCU family '${MICROCHIP_MCU_FAMILY}'." + ) + endif() else() message(FATAL_ERROR "Invalid MICROCHIP_MCU value '${MICROCHIP_MCU}'."