From a724f47ce0a6b413437b7094e86fe2129f5de87b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20K=C3=B6gl?= Date: Tue, 2 Oct 2012 02:16:19 +0200 Subject: [PATCH] cmake contrib --- cmake/ArduinoToolchain.cmake | 65 ++ cmake/Platform/Arduino.cmake | 1763 ++++++++++++++++++++++++++++++++++ 2 files changed, 1828 insertions(+) create mode 100644 cmake/ArduinoToolchain.cmake create mode 100644 cmake/Platform/Arduino.cmake diff --git a/cmake/ArduinoToolchain.cmake b/cmake/ArduinoToolchain.cmake new file mode 100644 index 0000000..042bce3 --- /dev/null +++ b/cmake/ArduinoToolchain.cmake @@ -0,0 +1,65 @@ +#=============================================================================# +# Author: Tomasz Bogdal (QueezyTheGreat) +# Home: https://github.com/queezythegreat/arduino-cmake +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. +#=============================================================================# +set(CMAKE_SYSTEM_NAME Arduino) + +set(CMAKE_C_COMPILER avr-gcc) +set(CMAKE_CXX_COMPILER avr-g++) + +# Add current directory to CMake Module path automatically +if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/Platform/Arduino.cmake) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_LIST_DIR}) +endif() + +#=============================================================================# +# System Paths # +#=============================================================================# +if(UNIX) + include(Platform/UnixPaths) + if(APPLE) + list(APPEND CMAKE_SYSTEM_PREFIX_PATH ~/Applications + /Applications + /Developer/Applications + /sw # Fink + /opt/local) # MacPorts + endif() +elseif(WIN32) + include(Platform/WindowsPaths) +endif() + + +#=============================================================================# +# Detect Arduino SDK # +#=============================================================================# +if(NOT ARDUINO_SDK_PATH) + set(ARDUINO_PATHS) + foreach(VERSION 22 1) + list(APPEND ARDUINO_PATHS arduino-00${VERSION}) + endforeach() + + file(GLOB SDK_PATH_HINTS /usr/share/arduino* + /opt/local/ardiuno* + /usr/local/share/arduino*) + list(SORT SDK_PATH_HINTS) + list(REVERSE SDK_PATH_HINTS) +endif() + +find_path(ARDUINO_SDK_PATH + NAMES lib/version.txt + PATH_SUFFIXES share/arduino + Arduino.app/Contents/Resources/Java/ + ${ARDUINO_PATHS} + HINTS ${SDK_PATH_HINTS} + DOC "Arduino SDK path.") + +if(ARDUINO_SDK_PATH) + list(APPEND CMAKE_SYSTEM_PREFIX_PATH ${ARDUINO_SDK_PATH}/hardware/tools/avr/bin) + list(APPEND CMAKE_SYSTEM_PREFIX_PATH ${ARDUINO_SDK_PATH}/hardware/tools/avr/utils/bin) +else() + message(FATAL_ERROR "Could not find Arduino SDK (set ARDUINO_SDK_PATH)!") +endif() diff --git a/cmake/Platform/Arduino.cmake b/cmake/Platform/Arduino.cmake new file mode 100644 index 0000000..58f3bf3 --- /dev/null +++ b/cmake/Platform/Arduino.cmake @@ -0,0 +1,1763 @@ +#=============================================================================# +# generate_arduino_firmware(name +# [BOARD board_id] +# [SKETCH sketch_path | +# SRCS src1 src2 ... srcN] +# [HDRS hdr1 hdr2 ... hdrN] +# [LIBS lib1 lib2 ... libN] +# [PORT port] +# [SERIAL serial_cmd] +# [PROGRAMMER programmer_id] +# [AFLAGS flags] +# [NO_AUTOLIBS]) +#=============================================================================# +# +# generaters firmware and libraries for Arduino devices +# +# The arguments are as follows: +# +# name # The name of the firmware target [REQUIRED] +# BOARD # Board name (such as uno, mega2560, ...) [REQUIRED] +# SKETCH # Arduino sketch [must have SRCS or SKETCH] +# SRCS # Sources [must have SRCS or SKETCH] +# HDRS # Headers +# LIBS # Libraries to link +# PORT # Serial port (enables upload support) +# SERIAL # Serial command for serial target +# PROGRAMMER # Programmer id (enables programmer support) +# AFLAGS # Avrdude flags for target +# NO_AUTOLIBS # Disables Arduino library detection +# +# Here is a short example for a target named test: +# +# generate_arduino_firmware( +# NAME test +# SRCS test.cpp +# test2.cpp +# HDRS test.h test2.h +# BOARD uno) +# +# Alternatively you can specify the option by variables: +# +# set(test_SRCS test.cpp test2.cpp) +# set(test_HDRS test.h test2.h +# set(test_BOARD uno) +# +# generate_arduino_firmware(test) +# +# All variables need to be prefixed with the target name (${TARGET_NAME}_${OPTION}). +# +#=============================================================================# +# generate_arduino_library(name +# [BOARD board_id] +# [SRCS src1 src2 ... srcN] +# [HDRS hdr1 hdr2 ... hdrN] +# [LIBS lib1 lib2 ... libN] +# [NO_AUTOLIBS]) +#=============================================================================# +# generaters firmware and libraries for Arduino devices +# +# The arguments are as follows: +# +# name # The name of the firmware target [REQUIRED] +# BOARD # Board name (such as uno, mega2560, ...) [REQUIRED] +# SRCS # Sources [REQUIRED] +# HDRS # Headers +# LIBS # Libraries to link +# NO_AUTOLIBS # Disables Arduino library detection +# +# Here is a short example for a target named test: +# +# generate_arduino_library( +# NAME test +# SRCS test.cpp +# test2.cpp +# HDRS test.h test2.h +# BOARD uno) +# +# Alternatively you can specify the option by variables: +# +# set(test_SRCS test.cpp test2.cpp) +# set(test_HDRS test.h test2.h +# set(test_BOARD uno) +# +# generate_arduino_library(test) +# +# All variables need to be prefixed with the target name (${TARGET_NAME}_${OPTION}). +# +#=============================================================================# +# generate_arduino_example(LIBRARY_NAME EXAMPLE_NAME BOARD_ID [PORT] [SERIAL]) +#=============================================================================# +# +# BOARD_ID - Board ID +# LIBRARY_NAME - Library name +# EXAMPLE_NAME - Example name +# PORT - Serial port [optional] +# SERIAL - Serial command [optional] +# Creates a example from the specified library. +# +# +#=============================================================================# +# print_board_list() +#=============================================================================# +# +# Print list of detected Arduino Boards. +# +#=============================================================================# +# print_programmer_list() +#=============================================================================# +# +# Print list of detected Programmers. +# +#=============================================================================# +# print_programmer_settings(PROGRAMMER) +#=============================================================================# +# +# PROGRAMMER - programmer id +# +# Print the detected Programmer settings. +# +#=============================================================================# +# print_board_settings(ARDUINO_BOARD) +#=============================================================================# +# +# ARDUINO_BOARD - Board id +# +# Print the detected Arduino board settings. +# +#=============================================================================# +# Configuration Options +#=============================================================================# +# +# ARDUINO_SDK_PATH - Arduino SDK Path +# ARDUINO_AVRDUDE_PROGRAM - Full path to avrdude programmer +# ARDUINO_AVRDUDE_CONFIG_PATH - Full path to avrdude configuration file +# +# ARDUINO_C_FLAGS - C compiler flags +# ARDUINO_CXX_FLAGS - C++ compiler flags +# ARDUINO_LINKER_FLAGS - Linker flags +# +# ARDUINO_DEFAULT_BOARD - Default Arduino Board ID when not specified. +# ARDUINO_DEFAULT_PORT - Default Arduino port when not specified. +# ARDUINO_DEFAULT_SERIAL - Default Arduino Serial command when not specified. +# ARDUINO_DEFAULT_PROGRAMMER - Default Arduino Programmer ID when not specified. +# +# +# ARDUINO_FOUND - Set to True when the Arduino SDK is detected and configured. +# ARDUINO_SDK_VERSION - Set to the version of the detected Arduino SDK (ex: 1.0) + +#=============================================================================# +# Author: Tomasz Bogdal (QueezyTheGreat) +# Home: https://github.com/queezythegreat/arduino-cmake +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. +#=============================================================================# +cmake_minimum_required(VERSION 2.8.5) +include(CMakeParseArguments) + + + + + + +#=============================================================================# +# User Functions +#=============================================================================# + +#=============================================================================# +# [PUBLIC/USER] +# +# print_board_list() +# +# see documentation at top +#=============================================================================# +function(PRINT_BOARD_LIST) + message(STATUS "Arduino Boards:") + print_list(ARDUINO_BOARDS) + message(STATUS "") +endfunction() + +#=============================================================================# +# [PUBLIC/USER] +# +# print_programmer_list() +# +# see documentation at top +#=============================================================================# +function(PRINT_PROGRAMMER_LIST) + message(STATUS "Arduino Programmers:") + print_list(ARDUINO_PROGRAMMERS) + message(STATUS "") +endfunction() + +#=============================================================================# +# [PUBLIC/USER] +# +# print_programmer_settings(PROGRAMMER) +# +# see documentation at top +#=============================================================================# +function(PRINT_PROGRAMMER_SETTINGS PROGRAMMER) + if(${PROGRAMMER}.SETTINGS) + message(STATUS "Programmer ${PROGRAMMER} Settings:") + print_settings(${PROGRAMMER}) + endif() +endfunction() + +# [PUBLIC/USER] +# +# print_board_settings(ARDUINO_BOARD) +# +# see documentation at top +function(PRINT_BOARD_SETTINGS ARDUINO_BOARD) + if(${ARDUINO_BOARD}.SETTINGS) + message(STATUS "Arduino ${ARDUINO_BOARD} Board:") + print_settings(${ARDUINO_BOARD}) + endif() +endfunction() + +#=============================================================================# +# [PUBLIC/USER] +# see documentation at top +#=============================================================================# +function(GENERATE_ARDUINO_LIBRARY INPUT_NAME) + message(STATUS "Generating ${INPUT_NAME}") + parse_generator_arguments(${INPUT_NAME} INPUT + "NO_AUTOLIBS" # Options + "BOARD" # One Value Keywords + "SRCS;HDRS;LIBS" # Multi Value Keywords + ${ARGN}) + + if(NOT INPUT_BOARD) + set(INPUT_BOARD ${ARDUINO_DEFAULT_BOARD}) + endif() + required_variables(VARS INPUT_SRCS INPUT_BOARD MSG "must define for target ${INPUT_NAME}") + + set(ALL_LIBS) + set(ALL_SRCS ${INPUT_SRCS} ${INPUT_HDRS}) + + setup_arduino_core(CORE_LIB ${INPUT_BOARD}) + + find_arduino_libraries(TARGET_LIBS "${ALL_SRCS}") + set(LIB_DEP_INCLUDES) + foreach(LIB_DEP ${TARGET_LIBS}) + set(LIB_DEP_INCLUDES "${LIB_DEP_INCLUDES} -I${LIB_DEP}") + endforeach() + + if(NOT ${INPUT_NO_AUTOLIBS}) + setup_arduino_libraries(ALL_LIBS ${INPUT_BOARD} "${ALL_SRCS}" "${LIB_DEP_INCLUDES}" "") + endif() + + list(APPEND ALL_LIBS ${CORE_LIB} ${INPUT_LIBS}) + + add_library(${INPUT_NAME} ${ALL_SRCS}) + + get_arduino_flags(ARDUINO_COMPILE_FLAGS ARDUINO_LINK_FLAGS ${INPUT_BOARD}) + + set_target_properties(${INPUT_NAME} PROPERTIES + COMPILE_FLAGS "${ARDUINO_COMPILE_FLAGS} ${COMPILE_FLAGS} ${LIB_DEP_INCLUDES}" + LINK_FLAGS "${ARDUINO_LINK_FLAGS} ${LINK_FLAGS}") + + target_link_libraries(${INPUT_NAME} ${ALL_LIBS} "-lc -lm") +endfunction() + +#=============================================================================# +# [PUBLIC/USER] +# see documentation at top +#=============================================================================# +function(GENERATE_ARDUINO_FIRMWARE INPUT_NAME) + message(STATUS "Generating ${INPUT_NAME}") + parse_generator_arguments(${INPUT_NAME} INPUT + "NO_AUTOLIBS" # Options + "BOARD;PORT;SKETCH;SERIAL;PROGRAMMER" # One Value Keywords + "SRCS;HDRS;LIBS;AFLAGS" # Multi Value Keywords + ${ARGN}) + + if(NOT INPUT_BOARD) + set(INPUT_BOARD ${ARDUINO_DEFAULT_BOARD}) + endif() + if(NOT INPUT_PORT) + set(INPUT_PORT ${ARDUINO_DEFAULT_PORT}) + endif() + if(NOT INPUT_SERIAL) + set(INPUT_SERIAL ${ARDUINO_DEFAULT_SERIAL}) + endif() + if(NOT INPUT_PROGRAMMER) + set(INPUT_SERIAL ${ARDUINO_DEFAULT_PROGRAMMER}) + endif() + required_variables(VARS INPUT_BOARD MSG "must define for target ${INPUT_NAME}") + + set(ALL_LIBS) + set(ALL_SRCS ${INPUT_SRCS} ${INPUT_HDRS}) + set(LIB_DEP_INCLUDES) + + setup_arduino_core(CORE_LIB ${INPUT_BOARD}) + + if(NOT "${INPUT_SKETCH}" STREQUAL "") + get_filename_component(INPUT_SKETCH "${INPUT_SKETCH}" ABSOLUTE) + setup_arduino_sketch(${INPUT_NAME} ${INPUT_SKETCH} ALL_SRCS) + set(LIB_DEP_INCLUDES "${LIB_DEP_INCLUDES} -I${INPUT_SKETCH}") + endif() + + required_variables(VARS ALL_SRCS MSG "must define SRCS or SKETCH for target ${INPUT_NAME}") + + find_arduino_libraries(TARGET_LIBS "${ALL_SRCS}") + foreach(LIB_DEP ${TARGET_LIBS}) + set(LIB_DEP_INCLUDES "${LIB_DEP_INCLUDES} -I${LIB_DEP}") + endforeach() + + if(NOT INPUT_NO_AUTOLIBS) + setup_arduino_libraries(ALL_LIBS ${INPUT_BOARD} "${ALL_SRCS}" "${LIB_DEP_INCLUDES}" "") + endif() + + list(APPEND ALL_LIBS ${CORE_LIB} ${INPUT_LIBS}) + + setup_arduino_target(${INPUT_NAME} ${INPUT_BOARD} "${ALL_SRCS}" "${ALL_LIBS}" "${LIB_DEP_INCLUDES}" "") + + if(INPUT_PORT) + setup_arduino_upload(${INPUT_BOARD} ${INPUT_NAME} ${INPUT_PORT} "${INPUT_PROGRAMMER}" "${INPUT_AFLAGS}") + endif() + + if(INPUT_SERIAL) + setup_serial_target(${INPUT_NAME} "${INPUT_SERIAL}") + endif() + +endfunction() + +#=============================================================================# +# [PUBLIC/USER] +# +# generate_arduino_example(LIBRARY_NAME EXAMPLE_NAME BOARD_ID [PORT] [SERIAL] [PORGRAMMER]) +# +# see documentation at top +#=============================================================================# +function(GENERATE_ARDUINO_EXAMPLE LIBRARY_NAME EXAMPLE_NAME) + #TODO: Add support for options like generate_arduino_* + + set(TARGET_NAME "example-${LIBRARY_NAME}-${EXAMPLE_NAME}") + + message(STATUS "Generating example ${LIBRARY_NAME}-${EXAMPLE_NAME}") + + set(ALL_LIBS) + set(ALL_SRCS) + + set(INPUT_BOARD ${ARGV2}) + set(INPUT_PORT ${ARGV3}) + set(INPUT_SERIAL ${ARGV4}) + set(INPUT_PROGRAMMER ${ARGV5}) + + if(NOT INPUT_BOARD) + set(INPUT_BOARD ${ARDUINO_DEFAULT_BOARD}) + endif() + if(NOT INPUT_PORT) + set(INPUT_PORT ${ARDUINO_DEFAULT_PORT}) + endif() + if(NOT INPUT_SERIAL) + set(INPUT_SERIAL ${ARDUINO_DEFAULT_SERIAL}) + endif() + if(NOT INPUT_PROGRAMMER) + set(INPUT_SERIAL ${ARDUINO_DEFAULT_PROGRAMMER}) + endif() + + setup_arduino_core(CORE_LIB ${INPUT_BOARD}) + + setup_arduino_example("${TARGET_NAME}" "${LIBRARY_NAME}" "${EXAMPLE_NAME}" ALL_SRCS) + + if(NOT ALL_SRCS) + message(FATAL_ERROR "Missing sources for example, aborting!") + endif() + + find_arduino_libraries(TARGET_LIBS "${ALL_SRCS}") + set(LIB_DEP_INCLUDES) + foreach(LIB_DEP ${TARGET_LIBS}) + set(LIB_DEP_INCLUDES "${LIB_DEP_INCLUDES} -I${LIB_DEP}") + endforeach() + + setup_arduino_libraries(ALL_LIBS ${INPUT_BOARD} "${ALL_SRCS}" "${LIB_DEP_INCLUDES}" "") + + list(APPEND ALL_LIBS ${CORE_LIB} ${INPUT_LIBS}) + + setup_arduino_target(${TARGET_NAME} ${INPUT_BOARD} "${ALL_SRCS}" "${ALL_LIBS}" "${LIB_DEP_INCLUDES}" "") + + if(INPUT_PORT) + #TODO fill in options (AFLAGS) + setup_arduino_upload(${INPUT_BOARD} ${TARGET_NAME} ${INPUT_PORT} "${INPUT_PROGRAMMER}" "") + endif() + + if(INPUT_SERIAL) + setup_serial_target(${TARGET_NAME} "${INPUT_SERIAL}") + endif() +endfunction() + +#=============================================================================# +# Internal Functions +#=============================================================================# + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# parse_generator_arguments(TARGET_NAME PREFIX OPTIONS ARGS MULTI_ARGS [ARG1 ARG2 .. ARGN]) +# +# PREFIX - Parsed options prefix +# OPTIONS - List of options +# ARGS - List of one value keyword arguments +# MULTI_ARGS - List of multi value keyword arguments +# [ARG1 ARG2 .. ARGN] - command arguments [optional] +# +# Parses generator options from either variables or command arguments +# +#=============================================================================# +macro(PARSE_GENERATOR_ARGUMENTS TARGET_NAME PREFIX OPTIONS ARGS MULTI_ARGS) + cmake_parse_arguments(${PREFIX} "${OPTIONS}" "${ARGS}" "${MULTI_ARGS}" ${ARGN}) + error_for_unparsed(${PREFIX}) + load_generator_settings(${TARGET_NAME} ${PREFIX} ${OPTIONS} ${ARGS} ${MULTI_ARGS}) +endmacro() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# load_board_settings() +# +# Load the Arduino SDK board settings from the boards.txt file. +# +#=============================================================================# +function(LOAD_BOARD_SETTINGS) + load_arduino_style_settings(ARDUINO_BOARDS "${ARDUINO_BOARDS_PATH}") +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +#=============================================================================# +function(LOAD_PROGRAMMERS_SETTINGS) + load_arduino_style_settings(ARDUINO_PROGRAMMERS "${ARDUINO_PROGRAMMERS_PATH}") +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# load_generator_settings(TARGET_NAME PREFIX [SUFFIX_1 SUFFIX_2 .. SUFFIX_N]) +# +# TARGET_NAME - The base name of the user settings +# PREFIX - The prefix name used for generator settings +# SUFFIX_XX - List of suffixes to load +# +# Loads a list of user settings into the generators scope. User settings have +# the following syntax: +# +# ${BASE_NAME}${SUFFIX} +# +# The BASE_NAME is the target name and the suffix is a specific generator settings. +# +# For every user setting found a generator setting is created of the follwoing fromat: +# +# ${PREFIX}${SUFFIX} +# +# The purpose of loading the settings into the generator is to not modify user settings +# and to have a generic naming of the settings within the generator. +# +#=============================================================================# +function(LOAD_GENERATOR_SETTINGS TARGET_NAME PREFIX) + foreach(GEN_SUFFIX ${ARGN}) + if(${TARGET_NAME}_${GEN_SUFFIX} AND NOT ${PREFIX}_${GEN_SUFFIX}) + set(${PREFIX}_${GEN_SUFFIX} ${${TARGET_NAME}_${GEN_SUFFIX}} PARENT_SCOPE) + endif() + endforeach() +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# get_arduino_flags(COMPILE_FLAGS LINK_FLAGS BOARD_ID) +# +# COMPILE_FLAGS_VAR -Variable holding compiler flags +# LINK_FLAGS_VAR - Variable holding linker flags +# BOARD_ID - The board id name +# +# Configures the the build settings for the specified Arduino Board. +# +#=============================================================================# +function(get_arduino_flags COMPILE_FLAGS_VAR LINK_FLAGS_VAR BOARD_ID) + set(BOARD_CORE ${${BOARD_ID}.build.core}) + if(BOARD_CORE) + if(ARDUINO_SDK_VERSION MATCHES "([0-9]+)[.]([0-9]+)") + string(REPLACE "." "" ARDUINO_VERSION_DEFINE "${ARDUINO_SDK_VERSION}") # Normalize version (remove all periods) + set(ARDUINO_VERSION_DEFINE "") + if(CMAKE_MATCH_1 GREATER 0) + set(ARDUINO_VERSION_DEFINE "${CMAKE_MATCH_1}") + endif() + if(CMAKE_MATCH_2 GREATER 10) + set(ARDUINO_VERSION_DEFINE "${ARDUINO_VERSION_DEFINE}${CMAKE_MATCH_2}") + else() + set(ARDUINO_VERSION_DEFINE "${ARDUINO_VERSION_DEFINE}0${CMAKE_MATCH_2}") + endif() + else() + message("Invalid Arduino SDK Version (${ARDUINO_SDK_VERSION})") + endif() + + # output + set(COMPILE_FLAGS "-DF_CPU=${${BOARD_ID}.build.f_cpu} -DARDUINO=${ARDUINO_VERSION_DEFINE} -mmcu=${${BOARD_ID}.build.mcu} -I${ARDUINO_CORES_PATH}/${BOARD_CORE} -I${ARDUINO_LIBRARIES_PATH}") + set(LINK_FLAGS "-mmcu=${${BOARD_ID}.build.mcu}") + if(ARDUINO_SDK_VERSION VERSION_GREATER 1.0 OR ARDUINO_SDK_VERSION VERSION_EQUAL 1.0) + set(PIN_HEADER ${${BOARD_ID}.build.variant}) + set(COMPILE_FLAGS "${COMPILE_FLAGS} -I${ARDUINO_VARIANTS_PATH}/${PIN_HEADER}") + endif() + + # output + set(${COMPILE_FLAGS_VAR} "${COMPILE_FLAGS}" PARENT_SCOPE) + set(${LINK_FLAGS_VAR} "${LINK_FLAGS}" PARENT_SCOPE) + + else() + message(FATAL_ERROR "Invalid Arduino board ID (${BOARD_ID}), aborting.") + endif() +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# setup_arduino_core(VAR_NAME BOARD_ID) +# +# VAR_NAME - Variable name that will hold the generated library name +# BOARD_ID - Arduino board id +# +# Creates the Arduino Core library for the specified board, +# each board gets it's own version of the library. +# +#=============================================================================# +function(setup_arduino_core VAR_NAME BOARD_ID) + set(CORE_LIB_NAME ${BOARD_ID}_CORE) + set(BOARD_CORE ${${BOARD_ID}.build.core}) + if(BOARD_CORE) + if(NOT TARGET ${CORE_LIB_NAME}) + set(BOARD_CORE_PATH ${ARDUINO_CORES_PATH}/${BOARD_CORE}) + find_sources(CORE_SRCS ${BOARD_CORE_PATH} True) + # Debian/Ubuntu fix + list(REMOVE_ITEM CORE_SRCS "${BOARD_CORE_PATH}/main.cxx") + add_library(${CORE_LIB_NAME} ${CORE_SRCS}) + get_arduino_flags(ARDUINO_COMPILE_FLAGS ARDUINO_LINK_FLAGS ${BOARD_ID}) + set_target_properties(${CORE_LIB_NAME} PROPERTIES + COMPILE_FLAGS "${ARDUINO_COMPILE_FLAGS}" + LINK_FLAGS "${ARDUINO_LINK_FLAGS}") + endif() + set(${VAR_NAME} ${CORE_LIB_NAME} PARENT_SCOPE) + endif() +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# find_arduino_libraries(VAR_NAME SRCS) +# +# VAR_NAME - Variable name which will hold the results +# SRCS - Sources that will be analized +# +# returns a list of paths to libraries found. +# +# Finds all Arduino type libraries included in sources. Available libraries +# are ${ARDUINO_SDK_PATH}/libraries and ${CMAKE_CURRENT_SOURCE_DIR}. +# +# A Arduino library is a folder that has the same name as the include header. +# For example, if we have a include "#include " then the following +# directory structure is considered a Arduino library: +# +# LibraryName/ +# |- LibraryName.h +# `- LibraryName.c +# +# If such a directory is found then all sources within that directory are considred +# to be part of that Arduino library. +# +#=============================================================================# +function(find_arduino_libraries VAR_NAME SRCS) + set(ARDUINO_LIBS ) + foreach(SRC ${SRCS}) + if(NOT (EXISTS ${SRC} OR + EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${SRC} OR + EXISTS ${CMAKE_CURRENT_BINARY_DIR}/${SRC})) + message(FATAL_ERROR "Invalid source file: ${SRC}") + endif() + file(STRINGS ${SRC} SRC_CONTENTS) + foreach(SRC_LINE ${SRC_CONTENTS}) + if("${SRC_LINE}" MATCHES "^ *#include *[<\"](.*)[>\"]") + get_filename_component(INCLUDE_NAME ${CMAKE_MATCH_1} NAME_WE) + get_property(LIBRARY_SEARCH_PATH + DIRECTORY # Property Scope + PROPERTY LINK_DIRECTORIES) + foreach(LIB_SEARCH_PATH ${LIBRARY_SEARCH_PATH} ${ARDUINO_LIBRARIES_PATH} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/libraries ${ARDUINO_EXTRA_LIBRARIES_PATH}) + if(EXISTS ${LIB_SEARCH_PATH}/${INCLUDE_NAME}/${CMAKE_MATCH_1}) + list(APPEND ARDUINO_LIBS ${LIB_SEARCH_PATH}/${INCLUDE_NAME}) + break() + endif() + endforeach() + endif() + endforeach() + endforeach() + if(ARDUINO_LIBS) + list(REMOVE_DUPLICATES ARDUINO_LIBS) + endif() + set(${VAR_NAME} ${ARDUINO_LIBS} PARENT_SCOPE) +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# setup_arduino_library(VAR_NAME BOARD_ID LIB_PATH COMPILE_FLAGS LINK_FLAGS) +# +# VAR_NAME - Vairable wich will hold the generated library names +# BOARD_ID - Board ID +# LIB_PATH - Path of the library +# COMPILE_FLAGS - Compile flags +# LINK_FLAGS - Link flags +# +# Creates an Arduino library, with all it's library dependencies. +# +# ${LIB_NAME}_RECURSE controls if the library will recurse +# when looking for source files. +# +#=============================================================================# + +# For known libraries can list recurse here +set(Wire_RECURSE True) +set(Ethernet_RECURSE True) +set(SD_RECURSE True) +function(setup_arduino_library VAR_NAME BOARD_ID LIB_PATH COMPILE_FLAGS LINK_FLAGS) + set(LIB_TARGETS) + + get_filename_component(LIB_NAME ${LIB_PATH} NAME) + set(TARGET_LIB_NAME ${BOARD_ID}_${LIB_NAME}) + if(NOT TARGET ${TARGET_LIB_NAME}) + string(REGEX REPLACE ".*/" "" LIB_SHORT_NAME ${LIB_NAME}) + + # Detect if recursion is needed + if (NOT DEFINED ${LIB_SHORT_NAME}_RECURSE) + set(${LIB_SHORT_NAME}_RECURSE False) + endif() + + find_sources(LIB_SRCS ${LIB_PATH} ${${LIB_SHORT_NAME}_RECURSE}) + if(LIB_SRCS) + + arduino_debug_msg("Generating Arduino ${LIB_NAME} library") + add_library(${TARGET_LIB_NAME} STATIC ${LIB_SRCS}) + + get_arduino_flags(ARDUINO_COMPILE_FLAGS ARDUINO_LINK_FLAGS ${BOARD_ID}) + + find_arduino_libraries(LIB_DEPS "${LIB_SRCS}") + + foreach(LIB_DEP ${LIB_DEPS}) + setup_arduino_library(DEP_LIB_SRCS ${BOARD_ID} ${LIB_DEP} "${COMPILE_FLAGS}" "${LINK_FLAGS}") + list(APPEND LIB_TARGETS ${DEP_LIB_SRCS}) + endforeach() + + set_target_properties(${TARGET_LIB_NAME} PROPERTIES + COMPILE_FLAGS "${ARDUINO_COMPILE_FLAGS} -I${LIB_PATH} -I${LIB_PATH}/utility ${COMPILE_FLAGS}" + LINK_FLAGS "${ARDUINO_LINK_FLAGS} ${LINK_FLAGS}") + + target_link_libraries(${TARGET_LIB_NAME} ${BOARD_ID}_CORE ${LIB_TARGETS}) + list(APPEND LIB_TARGETS ${TARGET_LIB_NAME}) + + endif() + else() + # Target already exists, skiping creating + list(APPEND LIB_TARGETS ${TARGET_LIB_NAME}) + endif() + if(LIB_TARGETS) + list(REMOVE_DUPLICATES LIB_TARGETS) + endif() + set(${VAR_NAME} ${LIB_TARGETS} PARENT_SCOPE) +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# setup_arduino_libraries(VAR_NAME BOARD_ID SRCS COMPILE_FLAGS LINK_FLAGS) +# +# VAR_NAME - Vairable wich will hold the generated library names +# BOARD_ID - Board ID +# SRCS - source files +# COMPILE_FLAGS - Compile flags +# LINK_FLAGS - Linker flags +# +# Finds and creates all dependency libraries based on sources. +# +#=============================================================================# +function(setup_arduino_libraries VAR_NAME BOARD_ID SRCS COMPILE_FLAGS LINK_FLAGS) + set(LIB_TARGETS) + find_arduino_libraries(TARGET_LIBS "${SRCS}") + foreach(TARGET_LIB ${TARGET_LIBS}) + # Create static library instead of returning sources + setup_arduino_library(LIB_DEPS ${BOARD_ID} ${TARGET_LIB} "${COMPILE_FLAGS}" "${LINK_FLAGS}") + list(APPEND LIB_TARGETS ${LIB_DEPS}) + endforeach() + set(${VAR_NAME} ${LIB_TARGETS} PARENT_SCOPE) +endfunction() + + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# setup_arduino_target(TARGET_NAME ALL_SRCS ALL_LIBS COMPILE_FLAGS LINK_FLAGS) +# +# TARGET_NAME - Target name +# BOARD_ID - Arduino board ID +# ALL_SRCS - All sources +# ALL_LIBS - All libraries +# COMPILE_FLAGS - Compile flags +# LINK_FLAGS - Linker flags +# +# Creates an Arduino firmware target. +# +#=============================================================================# +function(setup_arduino_target TARGET_NAME BOARD_ID ALL_SRCS ALL_LIBS COMPILE_FLAGS LINK_FLAGS) + + add_executable(${TARGET_NAME} ${ALL_SRCS}) + set_target_properties(${TARGET_NAME} PROPERTIES SUFFIX ".elf") + + get_arduino_flags(ARDUINO_COMPILE_FLAGS ARDUINO_LINK_FLAGS ${BOARD_ID}) + + set_target_properties(${TARGET_NAME} PROPERTIES + COMPILE_FLAGS "${ARDUINO_COMPILE_FLAGS} ${COMPILE_FLAGS}" + LINK_FLAGS "${ARDUINO_LINK_FLAGS} ${LINK_FLAGS}") + target_link_libraries(${TARGET_NAME} ${ALL_LIBS} "-lc -lm") + + set(TARGET_PATH ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}) + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD + COMMAND ${CMAKE_OBJCOPY} + ARGS ${ARDUINO_OBJCOPY_EEP_FLAGS} + ${TARGET_PATH}.elf + ${TARGET_PATH}.eep + COMMENT "Generating EEP image" + VERBATIM) + + # Convert firmware image to ASCII HEX format + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD + COMMAND ${CMAKE_OBJCOPY} + ARGS ${ARDUINO_OBJCOPY_HEX_FLAGS} + ${TARGET_PATH}.elf + ${TARGET_PATH}.hex + COMMENT "Generating HEX image" + VERBATIM) + + # Display target size + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} + ARGS -DFIRMWARE_IMAGE=${TARGET_PATH}.hex + -P ${ARDUINO_SIZE_SCRIPT} + COMMENT "Calculating image size" + VERBATIM) + + # Create ${TARGET_NAME}-size target + add_custom_target(${TARGET_NAME}-size + COMMAND ${CMAKE_COMMAND} + -DFIRMWARE_IMAGE=${TARGET_PATH}.hex + -P ${ARDUINO_SIZE_SCRIPT} + DEPENDS ${TARGET_NAME} + COMMENT "Calculating ${TARGET_NAME} image size") +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# setup_arduino_upload(BOARD_ID TARGET_NAME PORT) +# +# BOARD_ID - Arduino board id +# TARGET_NAME - Target name +# PORT - Serial port for upload +# PROGRAMMER_ID - Programmer ID +# AVRDUDE_FLAGS - avrdude flags +# +# Create an upload target (${TARGET_NAME}-upload) for the specified Arduino target. +# +#=============================================================================# +function(setup_arduino_upload BOARD_ID TARGET_NAME PORT PROGRAMMER_ID AVRDUDE_FLAGS) + setup_arduino_bootloader_upload(${TARGET_NAME} ${BOARD_ID} ${PORT} "${AVRDUDE_FLAGS}") + + # Add programmer support if defined + if(PROGRAMMER_ID AND ${PROGRAMMER_ID}.protocol) + setup_arduino_programmer_burn(${TARGET_NAME} ${BOARD_ID} ${PROGRAMMER_ID} ${PORT} "${AVRDUDE_FLAGS}") + setup_arduino_bootloader_burn(${TARGET_NAME} ${BOARD_ID} ${PROGRAMMER_ID} ${PORT} "${AVRDUDE_FLAGS}") + endif() +endfunction() + + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# setup_arduino_bootloader_upload(TARGET_NAME BOARD_ID PORT) +# +# TARGET_NAME - target name +# BOARD_ID - board id +# PORT - serial port +# AVRDUDE_FLAGS - avrdude flags (override) +# +# Set up target for upload firmware via the bootloader. +# +# The target for uploading the firmware is ${TARGET_NAME}-upload . +# +#=============================================================================# +function(setup_arduino_bootloader_upload TARGET_NAME BOARD_ID PORT AVRDUDE_FLAGS) + set(UPLOAD_TARGET ${TARGET_NAME}-upload) + set(AVRDUDE_ARGS) + + setup_arduino_bootloader_args(${BOARD_ID} ${TARGET_NAME} ${PORT} "${AVRDUDE_FLAGS}" AVRDUDE_ARGS) + + if(NOT AVRDUDE_ARGS) + message("Could not generate default avrdude bootloader args, aborting!") + return() + endif() + + list(APPEND AVRDUDE_ARGS "-Uflash:w:${TARGET_NAME}.hex") + message("\n") + message(${AVRDUDE_ARGS}) + message("\n") + add_custom_target(${UPLOAD_TARGET} + ${ARDUINO_AVRDUDE_PROGRAM} + ${AVRDUDE_ARGS} + DEPENDS ${TARGET_NAME}) +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# setup_arduino_programmer_burn(TARGET_NAME BOARD_ID PROGRAMMER PORT AVRDUDE_FLAGS) +# +# TARGET_NAME - name of target to burn +# BOARD_ID - board id +# PROGRAMMER - programmer id +# PORT - serial port +# AVRDUDE_FLAGS - avrdude flags (override) +# +# Sets up target for burning firmware via a programmer. +# +# The target for burning the firmware is ${TARGET_NAME}-burn . +# +#=============================================================================# +function(setup_arduino_programmer_burn TARGET_NAME BOARD_ID PROGRAMMER PORT AVRDUDE_FLAGS) + set(PROGRAMMER_TARGET ${TARGET_NAME}-burn) + + set(AVRDUDE_ARGS) + + setup_arduino_programmer_args(${BOARD_ID} ${PROGRAMMER} ${TARGET_NAME} ${PORT} "${AVRDUDE_FLAGS}" AVRDUDE_ARGS) + + if(NOT AVRDUDE_ARGS) + message("Could not generate default avrdude programmer args, aborting!") + return() + endif() + + list(APPEND AVRDUDE_ARGS "-Uflash:w:${TARGET_NAME}.hex") + + add_custom_target(${PROGRAMMER_TARGET} + ${ARDUINO_AVRDUDE_PROGRAM} + ${AVRDUDE_ARGS} + DEPENDS ${TARGET_NAME}) +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# setup_arduino_bootloader_burn(TARGET_NAME BOARD_ID PROGRAMMER PORT AVRDUDE_FLAGS) +# +# TARGET_NAME - name of target to burn +# BOARD_ID - board id +# PROGRAMMER - programmer id +# PORT - serial port +# AVRDUDE_FLAGS - avrdude flags (override) +# +# Create a target for burning a bootloader via a programmer. +# +# The target for burning the bootloader is ${TARGET_NAME}-burn-bootloader +# +#=============================================================================# +function(setup_arduino_bootloader_burn TARGET_NAME BOARD_ID PROGRAMMER PORT AVRDUDE_FLAGS) + set(BOOTLOADER_TARGET ${TARGET_NAME}-burn-bootloader) + + set(AVRDUDE_ARGS) + + setup_arduino_programmer_args(${BOARD_ID} ${PROGRAMMER} ${TARGET_NAME} ${PORT} "${AVRDUDE_FLAGS}" AVRDUDE_ARGS) + + if(NOT AVRDUDE_ARGS) + message("Could not generate default avrdude programmer args, aborting!") + return() + endif() + + foreach( ITEM unlock_bits high_fuses low_fuses path file) + if(NOT ${BOARD_ID}.bootloader.${ITEM}) + message("Missing ${BOARD_ID}.bootloader.${ITEM}, not creating bootloader burn target ${BOOTLOADER_TARGET}.") + return() + endif() + endforeach() + + if(NOT EXISTS "${ARDUINO_BOOTLOADERS_PATH}/${${BOARD_ID}.bootloader.path}/${${BOARD_ID}.bootloader.file}") + message("${ARDUINO_BOOTLOADERS_PATH}/${${BOARD_ID}.bootloader.path}/${${BOARD_ID}.bootloader.file}") + message("Missing bootloader image, not creating bootloader burn target ${BOOTLOADER_TARGET}.") + return() + endif() + + # Erase the chip + list(APPEND AVRDUDE_ARGS "-e") + + # Set unlock bits and fuses (because chip is going to be erased) + list(APPEND AVRDUDE_ARGS "-Ulock:w:${${BOARD_ID}.bootloader.unlock_bits}:m") + if(${BOARD_ID}.bootloader.extended_fuses) + list(APPEND AVRDUDE_ARGS "-Uefuse:w:${${BOARD_ID}.bootloader.extended_fuses}:m") + endif() + list(APPEND AVRDUDE_ARGS + "-Uhfuse:w:${${BOARD_ID}.bootloader.high_fuses}:m" + "-Ulfuse:w:${${BOARD_ID}.bootloader.low_fuses}:m") + + # Set bootloader image + list(APPEND AVRDUDE_ARGS "-Uflash:w:${${BOARD_ID}.bootloader.file}:i") + + # Set lockbits + list(APPEND AVRDUDE_ARGS "-Ulock:w:${${BOARD_ID}.bootloader.lock_bits}:m") + + # Create burn bootloader target + add_custom_target(${BOOTLOADER_TARGET} + ${ARDUINO_AVRDUDE_PROGRAM} + ${AVRDUDE_ARGS} + WORKING_DIRECTORY ${ARDUINO_BOOTLOADERS_PATH}/${${BOARD_ID}.bootloader.path} + DEPENDS ${TARGET_NAME}) +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# setup_arduino_programmer_args(BOARD_ID PROGRAMMER TARGET_NAME PORT AVRDUDE_FLAGS OUTPUT_VAR) +# +# BOARD_ID - board id +# PROGRAMMER - programmer id +# TARGET_NAME - target name +# PORT - serial port +# AVRDUDE_FLAGS - avrdude flags (override) +# OUTPUT_VAR - name of output variable for result +# +# Sets up default avrdude settings for burning firmware via a programmer. +#=============================================================================# +function(setup_arduino_programmer_args BOARD_ID PROGRAMMER TARGET_NAME PORT AVRDUDE_FLAGS OUTPUT_VAR) + set(AVRDUDE_ARGS ${${OUTPUT_VAR}}) + + if(NOT AVRDUDE_FLAGS) + set(AVRDUDE_FLAGS ${ARDUINO_AVRDUDE_FLAGS}) + endif() + + list(APPEND AVRDUDE_ARGS "-C${ARDUINO_AVRDUDE_CONFIG_PATH}") + + #TODO: Check mandatory settings before continuing + if(NOT ${PROGRAMMER}.protocol) + message(FATAL_ERROR "Missing ${PROGRAMMER}.protocol, aborting!") + endif() + + list(APPEND AVRDUDE_ARGS "-c${${PROGRAMMER}.protocol}") # Set programmer + + if(${PROGRAMMER}.communication STREQUAL "usb") + list(APPEND AVRDUDE_ARGS "-Pusb") # Set USB as port + elseif(${PROGRAMMER}.communication STREQUAL "serial") + list(APPEND AVRDUDE_ARGS "-P${PORT}") # Set port + if(${PROGRAMMER}.speed) + list(APPEND AVRDUDE_ARGS "-b${${PROGRAMMER}.speed}") # Set baud rate + endif() + endif() + + if(${PROGRAMMER}.force) + list(APPEND AVRDUDE_ARGS "-F") # Set force + endif() + + if(${PROGRAMMER}.delay) + list(APPEND AVRDUDE_ARGS "-i${${PROGRAMMER}.delay}") # Set delay + endif() + + list(APPEND AVRDUDE_ARGS "-p${${BOARD_ID}.build.mcu}") # MCU Type + + list(APPEND AVRDUDE_ARGS ${AVRDUDE_FLAGS}) + + set(${OUTPUT_VAR} ${AVRDUDE_ARGS} PARENT_SCOPE) +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# setup_arduino_bootloader_args(BOARD_ID TARGET_NAME PORT AVRDUDE_FLAGS OUTPUT_VAR) +# +# BOARD_ID - board id +# TARGET_NAME - target name +# PORT - serial port +# AVRDUDE_FLAGS - avrdude flags (override) +# OUTPUT_VAR - name of output variable for result +# +# Sets up default avrdude settings for uploading firmware via the bootloader. +#=============================================================================# +function(setup_arduino_bootloader_args BOARD_ID TARGET_NAME PORT AVRDUDE_FLAGS OUTPUT_VAR) + set(AVRDUDE_ARGS ${${OUTPUT_VAR}}) + + if(NOT AVRDUDE_FLAGS) + set(AVRDUDE_FLAGS ${ARDUINO_AVRDUDE_FLAGS}) + endif() + + list(APPEND AVRDUDE_ARGS + "-C${ARDUINO_AVRDUDE_CONFIG_PATH}" # avrdude config + "-p${${BOARD_ID}.build.mcu}" # MCU Type + ) + + # Programmer + if(${BOARD_ID}.upload.protocol STREQUAL "stk500") + list(APPEND AVRDUDE_ARGS "-cstk500v1") + else() + list(APPEND AVRDUDE_ARGS "-c${${BOARD_ID}.upload.protocol}") + endif() + + list(APPEND AVRDUDE_ARGS + "-b${${BOARD_ID}.upload.speed}" # Baud rate + "-P${PORT}" # Serial port + "-D" # Dont erase + ) + + list(APPEND AVRDUDE_ARGS ${AVRDUDE_FLAGS}) + + set(${OUTPUT_VAR} ${AVRDUDE_ARGS} PARENT_SCOPE) +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# find_sources(VAR_NAME LIB_PATH RECURSE) +# +# VAR_NAME - Variable name that will hold the detected sources +# LIB_PATH - The base path +# RECURSE - Whether or not to recurse +# +# Finds all C/C++ sources located at the specified path. +# +#=============================================================================# +function(find_sources VAR_NAME LIB_PATH RECURSE) + set(FILE_SEARCH_LIST + ${LIB_PATH}/*.cpp + ${LIB_PATH}/*.c + ${LIB_PATH}/*.cc + ${LIB_PATH}/*.cxx + ${LIB_PATH}/*.h + ${LIB_PATH}/*.hh + ${LIB_PATH}/*.hxx) + + if(RECURSE) + file(GLOB_RECURSE LIB_FILES ${FILE_SEARCH_LIST}) + else() + file(GLOB LIB_FILES ${FILE_SEARCH_LIST}) + endif() + + if(LIB_FILES) + set(${VAR_NAME} ${LIB_FILES} PARENT_SCOPE) + endif() +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# setup_serial_target(TARGET_NAME CMD) +# +# TARGET_NAME - Target name +# CMD - Serial terminal command +# +# Creates a target (${TARGET_NAME}-serial) for launching the serial termnial. +# +#=============================================================================# +function(setup_serial_target TARGET_NAME CMD) + string(CONFIGURE "${CMD}" FULL_CMD @ONLY) + add_custom_target(${TARGET_NAME}-serial + ${FULL_CMD}) +endfunction() + + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# detect_arduino_version(VAR_NAME) +# +# VAR_NAME - Variable name where the detected version will be saved +# +# Detects the Arduino SDK Version based on the revisions.txt file. +# +#=============================================================================# +function(detect_arduino_version VAR_NAME) + if(ARDUINO_VERSION_PATH) + file(READ ${ARDUINO_VERSION_PATH} ARD_VERSION) + if("${ARD_VERSION}" MATCHES " *[0]+([0-9]+)") + set(${VAR_NAME} 0.${CMAKE_MATCH_1} PARENT_SCOPE) + elseif("${ARD_VERSION}" MATCHES "[ ]*([0-9]+[.][0-9]+)") + set(${VAR_NAME} ${CMAKE_MATCH_1} PARENT_SCOPE) + endif() + endif() +endfunction() + + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# load_arduino_style_settings(SETTINGS_LIST SETTINGS_PATH) +# +# SETTINGS_LIST - Variable name of settings list +# SETTINGS_PATH - File path of settings file to load. +# +# Load a Arduino style settings file into the cache. +# +# Examples of this type of settings file is the boards.txt and +# programmers.txt files located in ${ARDUINO_SDK}/hardware/arduino. +# +# Settings have to following format: +# +# entry.setting[.subsetting] = value +# +# where [.subsetting] is optional +# +# For example, the following settings: +# +# uno.name=Arduino Uno +# uno.upload.protocol=stk500 +# uno.upload.maximum_size=32256 +# uno.build.mcu=atmega328p +# uno.build.core=arduino +# +# will generate the follwoing equivalent CMake variables: +# +# set(uno.name "Arduino Uno") +# set(uno.upload.protocol "stk500") +# set(uno.upload.maximum_size "32256") +# set(uno.build.mcu "atmega328p") +# set(uno.build.core "arduino") +# +# set(uno.SETTINGS name upload build) # List of settings for uno +# set(uno.upload.SUBSETTINGS protocol maximum_size) # List of sub-settings for uno.upload +# set(uno.build.SUBSETTINGS mcu core) # List of sub-settings for uno.build +# +# The ${ENTRY_NAME}.SETTINGS variable lists all settings for the entry, while +# ${ENTRY_NAME}.SUBSETTINGS variables lists all settings for a sub-setting of +# a entry setting pair. +# +# These variables are generated in order to be able to programatically traverse +# all settings (for a example see print_board_settings() function). +# +#=============================================================================# +function(LOAD_ARDUINO_STYLE_SETTINGS SETTINGS_LIST SETTINGS_PATH) + + if(NOT ${SETTINGS_LIST} AND EXISTS ${SETTINGS_PATH}) + file(STRINGS ${SETTINGS_PATH} FILE_ENTRIES) # Settings file split into lines + + foreach(FILE_ENTRY ${FILE_ENTRIES}) + if("${FILE_ENTRY}" MATCHES "^[^#]+=.*") + string(REGEX MATCH "^[^=]+" SETTING_NAME ${FILE_ENTRY}) + string(REGEX MATCH "[^=]+$" SETTING_VALUE ${FILE_ENTRY}) + string(REPLACE "." ";" ENTRY_NAME_TOKENS ${SETTING_NAME}) + string(STRIP "${SETTING_VALUE}" SETTING_VALUE) + + list(LENGTH ENTRY_NAME_TOKENS ENTRY_NAME_TOKENS_LEN) + + # Add entry to settings list if it does not exist + list(GET ENTRY_NAME_TOKENS 0 ENTRY_NAME) + list(FIND ${SETTINGS_LIST} ${ENTRY_NAME} ENTRY_NAME_INDEX) + if(ENTRY_NAME_INDEX LESS 0) + # Add entry to main list + list(APPEND ${SETTINGS_LIST} ${ENTRY_NAME}) + endif() + + # Add entry setting to entry settings list if it does not exist + set(ENTRY_SETTING_LIST ${ENTRY_NAME}.SETTINGS) + list(GET ENTRY_NAME_TOKENS 1 ENTRY_SETTING) + list(FIND ${ENTRY_SETTING_LIST} ${ENTRY_SETTING} ENTRY_SETTING_INDEX) + if(ENTRY_SETTING_INDEX LESS 0) + # Add setting to entry + list(APPEND ${ENTRY_SETTING_LIST} ${ENTRY_SETTING}) + set(${ENTRY_SETTING_LIST} ${${ENTRY_SETTING_LIST}} + CACHE INTERNAL "Arduino ${ENTRY_NAME} Board settings list") + endif() + + set(FULL_SETTING_NAME ${ENTRY_NAME}.${ENTRY_SETTING}) + + # Add entry sub-setting to entry sub-settings list if it does not exists + if(ENTRY_NAME_TOKENS_LEN GREATER 2) + set(ENTRY_SUBSETTING_LIST ${ENTRY_NAME}.${ENTRY_SETTING}.SUBSETTINGS) + list(GET ENTRY_NAME_TOKENS 2 ENTRY_SUBSETTING) + list(FIND ${ENTRY_SUBSETTING_LIST} ${ENTRY_SUBSETTING} ENTRY_SUBSETTING_INDEX) + if(ENTRY_SUBSETTING_INDEX LESS 0) + list(APPEND ${ENTRY_SUBSETTING_LIST} ${ENTRY_SUBSETTING}) + set(${ENTRY_SUBSETTING_LIST} ${${ENTRY_SUBSETTING_LIST}} + CACHE INTERNAL "Arduino ${ENTRY_NAME} Board sub-settings list") + endif() + set(FULL_SETTING_NAME ${FULL_SETTING_NAME}.${ENTRY_SUBSETTING}) + endif() + + # Save setting value + set(${FULL_SETTING_NAME} ${SETTING_VALUE} + CACHE INTERNAL "Arduino ${ENTRY_NAME} Board setting") + + + endif() + endforeach() + set(${SETTINGS_LIST} ${${SETTINGS_LIST}} + CACHE STRING "List of detected Arduino Board configurations") + mark_as_advanced(${SETTINGS_LIST}) + endif() +endfunction() + +#=============================================================================# +# print_settings(ENTRY_NAME) +# +# ENTRY_NAME - name of entry +# +# Print the entry settings (see load_arduino_syle_settings()). +# +#=============================================================================# +function(PRINT_SETTINGS ENTRY_NAME) + if(${ENTRY_NAME}.SETTINGS) + + foreach(ENTRY_SETTING ${${ENTRY_NAME}.SETTINGS}) + if(${ENTRY_NAME}.${ENTRY_SETTING}) + message(STATUS " ${ENTRY_NAME}.${ENTRY_SETTING}=${${ENTRY_NAME}.${ENTRY_SETTING}}") + endif() + if(${ENTRY_NAME}.${ENTRY_SETTING}.SUBSETTINGS) + foreach(ENTRY_SUBSETTING ${${ENTRY_NAME}.${ENTRY_SETTING}.SUBSETTINGS}) + if(${ENTRY_NAME}.${ENTRY_SETTING}.${ENTRY_SUBSETTING}) + message(STATUS " ${ENTRY_NAME}.${ENTRY_SETTING}.${ENTRY_SUBSETTING}=${${ENTRY_NAME}.${ENTRY_SETTING}.${ENTRY_SUBSETTING}}") + endif() + endforeach() + endif() + message(STATUS "") + endforeach() + endif() +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# print_list(SETTINGS_LIST) +# +# SETTINGS_LIST - Variables name of settings list +# +# Print list settings and names (see load_arduino_syle_settings()). +#=============================================================================# +function(PRINT_LIST SETTINGS_LIST) + if(${SETTINGS_LIST}) + set(MAX_LENGTH 0) + foreach(ENTRY_NAME ${${SETTINGS_LIST}}) + string(LENGTH "${ENTRY_NAME}" CURRENT_LENGTH) + if(CURRENT_LENGTH GREATER MAX_LENGTH) + set(MAX_LENGTH ${CURRENT_LENGTH}) + endif() + endforeach() + foreach(ENTRY_NAME ${${SETTINGS_LIST}}) + string(LENGTH "${ENTRY_NAME}" CURRENT_LENGTH) + math(EXPR PADDING_LENGTH "${MAX_LENGTH}-${CURRENT_LENGTH}") + set(PADDING "") + foreach(X RANGE ${PADDING_LENGTH}) + set(PADDING "${PADDING} ") + endforeach() + message(STATUS " ${PADDING}${ENTRY_NAME}: ${${ENTRY_NAME}.name}") + endforeach() + endif() +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# setup_arduino_example(TARGET_NAME LIBRARY_NAME EXAMPLE_NAME OUTPUT_VAR) +# +# TARGET_NAME - Target name +# LIBRARY_NAME - Library name +# EXAMPLE_NAME - Example name +# OUTPUT_VAR - Variable name to save sketch path. +# +# Creates a Arduino example from a the specified library. +#=============================================================================# +function(SETUP_ARDUINO_EXAMPLE TARGET_NAME LIBRARY_NAME EXAMPLE_NAME OUTPUT_VAR) + set(EXAMPLE_SKETCH_PATH ) + + get_property(LIBRARY_SEARCH_PATH + DIRECTORY # Property Scope + PROPERTY LINK_DIRECTORIES) + foreach(LIB_SEARCH_PATH ${LIBRARY_SEARCH_PATH} ${ARDUINO_LIBRARIES_PATH} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/libraries) + if(EXISTS "${LIB_SEARCH_PATH}/${LIBRARY_NAME}/examples/${EXAMPLE_NAME}") + set(EXAMPLE_SKETCH_PATH "${LIB_SEARCH_PATH}/${LIBRARY_NAME}/examples/${EXAMPLE_NAME}") + break() + endif() + endforeach() + + if(EXAMPLE_SKETCH_PATH) + setup_arduino_sketch(${TARGET_NAME} ${EXAMPLE_SKETCH_PATH} SKETCH_CPP) + set("${OUTPUT_VAR}" ${${OUTPUT_VAR}} ${SKETCH_CPP} PARENT_SCOPE) + else() + message(FATAL_ERROR "Could not find example ${EXAMPLE_NAME} from library ${LIBRARY_NAME}") + endif() +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# setup_arduino_sketch(TARGET_NAME SKETCH_PATH OUTPUT_VAR) +# +# TARGET_NAME - Target name +# SKETCH_PATH - Path to sketch directory +# OUTPUT_VAR - Variable name where to save generated sketch source +# +# Generates C++ sources from Arduino Sketch. +#=============================================================================# +function(SETUP_ARDUINO_SKETCH TARGET_NAME SKETCH_PATH OUTPUT_VAR) + get_filename_component(SKETCH_NAME "${SKETCH_PATH}" NAME) + get_filename_component(SKETCH_PATH "${SKETCH_PATH}" ABSOLUTE) + + if(EXISTS "${SKETCH_PATH}") + set(SKETCH_CPP ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}_${SKETCH_NAME}.cpp) + set(MAIN_SKETCH ${SKETCH_PATH}/${SKETCH_NAME}) + + if(EXISTS "${MAIN_SKETCH}.pde") + set(MAIN_SKETCH "${MAIN_SKETCH}.pde") + elseif(EXISTS "${MAIN_SKETCH}.ino") + set(MAIN_SKETCH "${MAIN_SKETCH}.ino") + else() + message(FATAL_ERROR "Could not find main sketch (${SKETCH_NAME}.pde or ${SKETCH_NAME}.ino) at ${SKETCH_PATH}!") + endif() + arduino_debug_msg("sketch: ${MAIN_SKETCH}") + + # Find all sketch files + file(GLOB SKETCH_SOURCES ${SKETCH_PATH}/*.pde ${SKETCH_PATH}/*.ino) + list(REMOVE_ITEM SKETCH_SOURCES ${MAIN_SKETCH}) + list(SORT SKETCH_SOURCES) + + generate_cpp_from_sketch("${MAIN_SKETCH}" "${SKETCH_SOURCES}" "${SKETCH_CPP}") + + # Regenerate build system if sketch changes + add_custom_command(OUTPUT ${SKETCH_CPP} + COMMAND ${CMAKE_COMMAND} ${CMAKE_SOURCE_DIR} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + DEPENDS ${MAIN_SKETCH} ${SKETCH_SOURCES} + COMMENT "Regnerating ${SKETCH_NAME} Sketch") + set_source_files_properties(${SKETCH_CPP} PROPERTIES GENERATED TRUE) + + set("${OUTPUT_VAR}" ${${OUTPUT_VAR}} ${SKETCH_CPP} PARENT_SCOPE) + else() + message(FATAL_ERROR "Sketch does not exist: ${SKETCH_PDE}") + endif() +endfunction() + + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# generate_cpp_from_sketch(MAIN_SKETCH_PATH SKETCH_SOURCES SKETCH_CPP) +# +# MAIN_SKETCH_PATH - Main sketch file path +# SKETCH_SOURCES - Setch source paths +# SKETCH_CPP - Name of file to generate +# +# Generate C++ source file from Arduino sketch files. +#=============================================================================# +function(GENERATE_CPP_FROM_SKETCH MAIN_SKETCH_PATH SKETCH_SOURCES SKETCH_CPP) + file(WRITE ${SKETCH_CPP} "// automatically generated by arduino-cmake\n") + file(READ ${MAIN_SKETCH_PATH} MAIN_SKETCH) + + # remove comments + remove_comments(MAIN_SKETCH MAIN_SKETCH_NO_COMMENTS) + + # find first statement + string(REGEX MATCH "[\n][_a-zA-Z0-9]+[^\n]*" FIRST_STATEMENT "${MAIN_SKETCH_NO_COMMENTS}") + string(FIND "${MAIN_SKETCH}" "${FIRST_STATEMENT}" HEAD_LENGTH) + if ("${HEAD_LENGTH}" STREQUAL "-1") + set(HEAD_LENGTH 0) + endif() + #message(STATUS "FIRST STATEMENT: ${FIRST_STATEMENT}") + #message(STATUS "FIRST STATEMENT POSITION: ${HEAD_LENGTH}") + string(LENGTH "${MAIN_SKETCH}" MAIN_SKETCH_LENGTH) + + string(SUBSTRING "${MAIN_SKETCH}" 0 ${HEAD_LENGTH} SKETCH_HEAD) + #arduino_debug_msg("SKETCH_HEAD:\n${SKETCH_HEAD}") + + # find the body of the main pde + math(EXPR BODY_LENGTH "${MAIN_SKETCH_LENGTH}-${HEAD_LENGTH}") + string(SUBSTRING "${MAIN_SKETCH}" "${HEAD_LENGTH}+1" "${BODY_LENGTH}-1" SKETCH_BODY) + #arduino_debug_msg("BODY:\n${SKETCH_BODY}") + + # write the file head + file(APPEND ${SKETCH_CPP} "#line 1 \"${MAIN_SKETCH_PATH}\"\n${SKETCH_HEAD}") + + # add arduino include header + file(APPEND ${SKETCH_CPP} "\n#line 1 \"autogenerated\"\n") + if(ARDUINO_SDK_VERSION VERSION_LESS 1.0) + file(APPEND ${SKETCH_CPP} "#include \"WProgram.h\"\n") + else() + file(APPEND ${SKETCH_CPP} "#include \"Arduino.h\"\n") + endif() + + # add function prototypes + foreach(SKETCH_SOURCE_PATH ${SKETCH_SOURCES} ${MAIN_SKETCH_PATH}) + arduino_debug_msg("Sketch: ${SKETCH_SOURCE_PATH}") + file(READ ${SKETCH_SOURCE_PATH} SKETCH_SOURCE) + remove_comments(SKETCH_SOURCE SKETCH_SOURCE) + + set(ALPHA "a-zA-Z") + set(NUM "0-9") + set(ALPHANUM "${ALPHA}${NUM}") + set(WORD "_${ALPHANUM}") + set(LINE_START "(^|[\n])") + set(QUALIFIERS "([${ALPHA}]+[ ])*") + set(TYPE "[${WORD}]+([ ]*[\n][\t]*|[ ])") + set(FNAME "[${WORD}]+[ ]?[\n]?[\t]*[ ]*") + set(FARGS "[(]([\t]*[ ]*[*&]?[ ]?[${WORD}](\\[([${NUM}]+)?\\])*[,]?[ ]*[\n]?)*([,]?[ ]*[\n]?)?[)]") + set(BODY_START "([ ]*[\n][\t]*|[ ]|[\n])*{") + set(PROTOTYPE_PATTERN "${LINE_START}${QUALIFIERS}${TYPE}${FNAME}${FARGS}${BODY_START}") + + string(REGEX MATCHALL "${PROTOTYPE_PATTERN}" SKETCH_PROTOTYPES "${SKETCH_SOURCE}") + + # Write function prototypes + file(APPEND ${SKETCH_CPP} "\n//=== START Forward: ${SKETCH_SOURCE_PATH}\n") + foreach(SKETCH_PROTOTYPE ${SKETCH_PROTOTYPES}) + string(REPLACE "\n" " " SKETCH_PROTOTYPE "${SKETCH_PROTOTYPE}") + string(REPLACE "{" "" SKETCH_PROTOTYPE "${SKETCH_PROTOTYPE}") + arduino_debug_msg("\tprototype: ${SKETCH_PROTOTYPE};") + file(APPEND ${SKETCH_CPP} "${SKETCH_PROTOTYPE};\n") + endforeach() + file(APPEND ${SKETCH_CPP} "//=== END Forward: ${SKETCH_SOURCE_PATH}\n") + endforeach() + + # Write Sketch CPP source + get_num_lines("${SKETCH_HEAD}" HEAD_NUM_LINES) + file(APPEND ${SKETCH_CPP} "#line ${HEAD_NUM_LINES} \"${MAIN_SKETCH_PATH}\"\n") + file(APPEND ${SKETCH_CPP} "\n${SKETCH_BODY}") + foreach (SKETCH_SOURCE_PATH ${SKETCH_SOURCES}) + file(READ ${SKETCH_SOURCE_PATH} SKETCH_SOURCE) + file(APPEND ${SKETCH_CPP} "\n//=== START : ${SKETCH_SOURCE_PATH}\n") + file(APPEND ${SKETCH_CPP} "#line 1 \"${SKETCH_SOURCE_PATH}\"\n") + file(APPEND ${SKETCH_CPP} "${SKETCH_SOURCE}") + file(APPEND ${SKETCH_CPP} "\n//=== END : ${SKETCH_SOURCE_PATH}\n") + endforeach() +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# setup_arduino_size_script(OUTPUT_VAR) +# +# OUTPUT_VAR - Output variable that will contain the script path +# +# Generates script used to display the firmware size. +#=============================================================================# +function(SETUP_ARDUINO_SIZE_SCRIPT OUTPUT_VAR) + set(ARDUINO_SIZE_SCRIPT_PATH ${CMAKE_BINARY_DIR}/CMakeFiles/FirmwareSize.cmake) + + file(WRITE ${ARDUINO_SIZE_SCRIPT_PATH} " + set(AVRSIZE_PROGRAM ${AVRSIZE_PROGRAM}) + set(AVRSIZE_FLAGS --target=ihex -d) + + execute_process(COMMAND \${AVRSIZE_PROGRAM} \${AVRSIZE_FLAGS} \${FIRMWARE_IMAGE} + OUTPUT_VARIABLE SIZE_OUTPUT) + + string(STRIP \"\${SIZE_OUTPUT}\" SIZE_OUTPUT) + + # Convert lines into a list + string(REPLACE \"\\n\" \";\" SIZE_OUTPUT \"\${SIZE_OUTPUT}\") + + list(GET SIZE_OUTPUT 1 SIZE_ROW) + + if(SIZE_ROW MATCHES \"[ \\t]*[0-9]+[ \\t]*[0-9]+[ \\t]*[0-9]+[ \\t]*([0-9]+)[ \\t]*([0-9a-fA-F]+).*\") + message(\"Total size \${CMAKE_MATCH_1} bytes\") + endif()") + + set(${OUTPUT_VAR} ${ARDUINO_SIZE_SCRIPT_PATH} PARENT_SCOPE) +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# arduino_debug_on() +# +# Enables Arduino module debugging. +#=============================================================================# +function(ARDUINO_DEBUG_ON) + set(ARDUINO_DEBUG True PARENT_SCOPE) +endfunction() + + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# arduino_debug_off() +# +# Disables Arduino module debugging. +#=============================================================================# +function(ARDUINO_DEBUG_OFF) + set(ARDUINO_DEBUG False PARENT_SCOPE) +endfunction() + + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# arduino_debug_msg(MSG) +# +# MSG - Message to print +# +# Print Arduino debugging information. In order to enable printing +# use arduino_debug_on() and to disable use arduino_debug_off(). +#=============================================================================# +function(ARDUINO_DEBUG_MSG MSG) + if(ARDUINO_DEBUG) + message("## ${MSG}") + endif() +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# remove_comments(SRC_VAR OUT_VAR) +# +# SRC_VAR - variable holding sources +# OUT_VAR - variable holding sources with no comments +# +# Removes all comments from the source code. +#=============================================================================# +function(REMOVE_COMMENTS SRC_VAR OUT_VAR) + string(REGEX REPLACE "[\\./\\\\]" "_" FILE "${NAME}") + + set(SRC ${${SRC_VAR}}) + + #message(STATUS "removing comments from: ${FILE}") + #file(WRITE "${CMAKE_BINARY_DIR}/${FILE}_pre_remove_comments.txt" ${SRC}) + #message(STATUS "\n${SRC}") + + # remove all comments + string(REGEX REPLACE "([/][/][^\n]*)|([/][\\*]([^\\*]|([\\*]+[^/\\*]))*[\\*]+[/])" "" OUT "${SRC}") + + #file(WRITE "${CMAKE_BINARY_DIR}/${FILE}_post_remove_comments.txt" ${SRC}) + #message(STATUS "\n${SRC}") + + set(${OUT_VAR} ${OUT} PARENT_SCOPE) + +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# get_num_lines(DOCUMENT OUTPUT_VAR) +# +# DOCUMENT - Document contents +# OUTPUT_VAR - Variable which will hold the line number count +# +# Counts the line number of the document. +#=============================================================================# +function(GET_NUM_LINES DOCUMENT OUTPUT_VAR) + string(REGEX MATCHALL "[\n]" MATCH_LIST "${DOCUMENT}") + list(LENGTH MATCH_LIST NUM) + set(${OUTPUT_VAR} ${NUM} PARENT_SCOPE) +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# required_variables(MSG msg VARS var1 var2 .. varN) +# +# MSG - Message to be displayed in case of error +# VARS - List of variables names to check +# +# Ensure the specified variables are not empty, otherwise a fatal error is emmited. +#=============================================================================# +function(REQUIRED_VARIABLES) + cmake_parse_arguments(INPUT "" "MSG" "VARS" ${ARGN}) + error_for_unparsed(INPUT) + foreach(VAR ${INPUT_VARS}) + if ("${${VAR}}" STREQUAL "") + message(FATAL_ERROR "${VAR} not set: ${INPUT_MSG}") + endif() + endforeach() +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# error_for_unparsed(PREFIX) +# +# PREFIX - Prefix name +# +# Emit fatal error if there are unparsed argument from cmake_parse_arguments(). +#=============================================================================# +function(ERROR_FOR_UNPARSED PREFIX) + set(ARGS "${${PREFIX}_UNPARSED_ARGUMENTS}") + if (NOT ( "${ARGS}" STREQUAL "") ) + message(FATAL_ERROR "unparsed argument: ${ARGS}") + endif() +endfunction() + + + + + + +#=============================================================================# +# C Flags +#=============================================================================# +set(ARDUINO_C_FLAGS "-mcall-prologues -ffunction-sections -fdata-sections") +set(CMAKE_C_FLAGS "-Os ${ARDUINO_C_FLAGS}" CACHE STRING "") +set(CMAKE_C_FLAGS_DEBUG "${ARDUINO_C_FLAGS}" CACHE STRING "") +set(CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG ${ARDUINO_C_FLAGS}" CACHE STRING "") +set(CMAKE_C_FLAGS_RELEASE "-Os -DNDEBUG -w ${ARDUINO_C_FLAGS}" CACHE STRING "") +set(CMAKE_C_FLAGS_RELWITHDEBINFO "-Os -w ${ARDUINO_C_FLAGS}" CACHE STRING "") + +#=============================================================================# +# C++ Flags +#=============================================================================# +set(ARDUINO_CXX_FLAGS "${ARDUINO_C_FLAGS} -fno-exceptions") +set(CMAKE_CXX_FLAGS "-Os ${ARDUINO_CXX_FLAGS}" CACHE STRING "") +set(CMAKE_CXX_FLAGS_DEBUG "${ARDUINO_CXX_FLAGS}" CACHE STRING "") +set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG ${ARDUINO_CXX_FLAGS}" CACHE STRING "") +set(CMAKE_CXX_FLAGS_RELEASE "-Os -DNDEBUG ${ARDUINO_CXX_FLAGS}" CACHE STRING "") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-Os ${ARDUINO_CXX_FLAGS}" CACHE STRING "") + +#=============================================================================# +# Executable Linker Flags # +#=============================================================================# +set(ARDUINO_LINKER_FLAGS "-Wl,--gc-sections -lm") +set(CMAKE_EXE_LINKER_FLAGS "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") +set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") +set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") +set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") +set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") + +#=============================================================================# +#=============================================================================# +# Shared Lbrary Linker Flags # +#=============================================================================# +set(CMAKE_SHARED_LINKER_FLAGS "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") +set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") +set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") +set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") +set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") + +set(CMAKE_MODULE_LINKER_FLAGS "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") +set(CMAKE_MODULE_LINKER_FLAGS_DEBUG "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") +set(CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") +set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") +set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") + + +#=============================================================================# +# Arduino Settings +#=============================================================================# +set(ARDUINO_OBJCOPY_EEP_FLAGS -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load + --no-change-warnings --change-section-lma .eeprom=0 CACHE STRING "") +set(ARDUINO_OBJCOPY_HEX_FLAGS -O ihex -R .eeprom CACHE STRING "") +set(ARDUINO_AVRDUDE_FLAGS -V CACHE STRING "") + +#=============================================================================# +# Initialization +#=============================================================================# +if(NOT ARDUINO_FOUND AND ARDUINO_SDK_PATH) + find_file(ARDUINO_CORES_PATH + NAMES cores + PATHS ${ARDUINO_SDK_PATH} + PATH_SUFFIXES hardware/arduino + DOC "Path to directory containing the Arduino core sources.") + + find_file(ARDUINO_VARIANTS_PATH + NAMES variants + PATHS ${ARDUINO_SDK_PATH} + PATH_SUFFIXES hardware/arduino + DOC "Path to directory containing the Arduino variant sources.") + + find_file(ARDUINO_BOOTLOADERS_PATH + NAMES bootloaders + PATHS ${ARDUINO_SDK_PATH} + PATH_SUFFIXES hardware/arduino + DOC "Path to directory containing the Arduino bootloader images and sources.") + + find_file(ARDUINO_LIBRARIES_PATH + NAMES libraries + PATHS ${ARDUINO_SDK_PATH} + DOC "Path to directory containing the Arduino libraries.") + + find_file(ARDUINO_BOARDS_PATH + NAMES boards.txt + PATHS ${ARDUINO_SDK_PATH} + PATH_SUFFIXES hardware/arduino + DOC "Path to Arduino boards definition file.") + + find_file(ARDUINO_PROGRAMMERS_PATH + NAMES programmers.txt + PATHS ${ARDUINO_SDK_PATH} + PATH_SUFFIXES hardware/arduino + DOC "Path to Arduino programmers definition file.") + + find_file(ARDUINO_VERSION_PATH + NAMES lib/version.txt + PATHS ${ARDUINO_SDK_PATH} + DOC "Path to Arduino version file.") + + find_program(ARDUINO_AVRDUDE_PROGRAM + NAMES avrdude + PATHS ${ARDUINO_SDK_PATH} + PATH_SUFFIXES hardware/tools + NO_DEFAULT_PATH) + + find_program(ARDUINO_AVRDUDE_PROGRAM + NAMES avrdude + DOC "Path to avrdude programmer binary.") + + find_program(AVRSIZE_PROGRAM + NAMES avr-size) + + find_file(ARDUINO_AVRDUDE_CONFIG_PATH + NAMES avrdude.conf + PATHS ${ARDUINO_SDK_PATH} /etc/avrdude + PATH_SUFFIXES hardware/tools + hardware/tools/avr/etc + DOC "Path to avrdude programmer configuration file.") + + set(ARDUINO_DEFAULT_BOARD uno CACHE STRING "Default Arduino Board ID when not specified.") + set(ARDUINO_DEFAULT_PORT CACHE STRING "Default Arduino port when not specified.") + set(ARDUINO_DEFAULT_SERIAL CACHE STRING "Default Arduino Serial command when not specified.") + set(ARDUINO_DEFAULT_PROGRAMMER CACHE STRING "Default Arduino Programmer ID when not specified.") + + # Ensure that all required paths are found + required_variables(VARS + ARDUINO_CORES_PATH + ARDUINO_BOOTLOADERS_PATH + ARDUINO_LIBRARIES_PATH + ARDUINO_BOARDS_PATH + ARDUINO_PROGRAMMERS_PATH + ARDUINO_VERSION_PATH + ARDUINO_AVRDUDE_FLAGS + ARDUINO_AVRDUDE_PROGRAM + ARDUINO_AVRDUDE_CONFIG_PATH + AVRSIZE_PROGRAM + MSG "Invalid Arduino SDK path (${ARDUINO_SDK_PATH}).\n") + + detect_arduino_version(ARDUINO_SDK_VERSION) + set(ARDUINO_SDK_VERSION ${ARDUINO_SDK_VERSION} CACHE STRING "Arduino SDK Version") + + if(ARDUINO_SDK_VERSION VERSION_LESS 0.19) + message(FATAL_ERROR "Unsupported Arduino SDK (require verion 0.19 or higher)") + endif() + + message(STATUS "Arduino SDK version ${ARDUINO_SDK_VERSION}: ${ARDUINO_SDK_PATH}") + + setup_arduino_size_script(ARDUINO_SIZE_SCRIPT) + set(ARDUINO_SIZE_SCRIPT ${ARDUINO_SIZE_SCRIPT} CACHE INTERNAL "Arduino Size Script") + + load_board_settings() + load_programmers_settings() + + #print_board_list() + #print_programmer_list() + + set(ARDUINO_FOUND True CACHE INTERNAL "Arduino Found") + mark_as_advanced( + ARDUINO_CORES_PATH + ARDUINO_VARIANTS_PATH + ARDUINO_BOOTLOADERS_PATH + ARDUINO_LIBRARIES_PATH + ARDUINO_BOARDS_PATH + ARDUINO_PROGRAMMERS_PATH + ARDUINO_VERSION_PATH + ARDUINO_AVRDUDE_FLAGS + ARDUINO_AVRDUDE_PROGRAM + ARDUINO_AVRDUDE_CONFIG_PATH + ARDUINO_OBJCOPY_EEP_FLAGS + ARDUINO_OBJCOPY_HEX_FLAGS + AVRSIZE_PROGRAM) +endif() +