From 1b7663aa22b9d3d4b53561429018d36e70b6fbd9 Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Fri, 8 Mar 2019 20:38:27 +0200 Subject: [PATCH 01/23] Improved header resolving when converting sketches to sources --- .../Sketches/SketchHeadersManager.cmake | 82 ++++++++++++++----- cmake/Platform/System/DefaultsManager.cmake | 7 +- .../Utilities/PlatformLibraryUtils.cmake | 1 + examples/CMakeLists.txt | 6 +- 4 files changed, 72 insertions(+), 24 deletions(-) diff --git a/cmake/Platform/Sketches/SketchHeadersManager.cmake b/cmake/Platform/Sketches/SketchHeadersManager.cmake index e98025a..bc63838 100644 --- a/cmake/Platform/Sketches/SketchHeadersManager.cmake +++ b/cmake/Platform/Sketches/SketchHeadersManager.cmake @@ -1,3 +1,54 @@ +function(_check_header_existance _header_we _dir_list _return_var) + + foreach (include_dir ${_dir_list}) + find_header_files("${include_dir}" include_dir_headers RECURSE) + + foreach (included_header ${include_dir_headers}) + get_name_without_file_extension(${included_header} included_header_we) + if ("${included_header_we}" STREQUAL "${_header_we}") + set(_return_var TRUE PARENT_SCOPE) + return() + endif () + endforeach () + + endforeach () + + set(_return_var FALSE PARENT_SCOPE) + +endfunction() + +function(_is_known_header _header_we _target_name _return_var) + + # Get target's direct include dirs + get_target_property(target_include_dirs ${_target_name} INCLUDE_DIRECTORIES) + + # Get include dirs of targets linked to the given target + get_target_property(target_linked_libs ${_target_name} LINK_LIBRARIES) + + # Explictly add include dirs of all linked libraries (given they're valid cmake targets) + foreach (linked_lib ${target_linked_libs}) + + if (NOT TARGET ${linked_lib}) + continue() + endif () + + get_target_property(lib_include_dirs ${linked_lib} INCLUDE_DIRECTORIES) + if (NOT "${lib_include_dirs}" MATCHES "NOTFOUND") # Library has include dirs + list(APPEND include_dirs ${lib_include_dirs}) + endif () + + endforeach () + + if (NOT "${target_include_dirs}" MATCHES "NOTFOUND") # Target has direct include dirs + list(APPEND include_dirs ${target_include_dirs}) + endif () + + _check_header_existance(${_header_we} ${include_dirs} header_found) + + set(_return_var ${header_found} PARENT_SCOPE) + +endfunction() + #=============================================================================# # Resolves the header files included in a sketch by linking their appropriate library if necessary # or by validating they're included by the sketch target. @@ -14,32 +65,21 @@ function(resolve_sketch_headers _target_name _sketch_file) # So first we should check whether it's a library get_name_without_file_extension("${header}" header_we) - is_platform_library(${header_we} is_header_platform_lib) + # Pass the '3RD_PARTY' option to avoid name-conversion + find_arduino_library(${header_we}_sketch_lib ${header_we} 3RD_PARTY QUIET) - if (is_header_platform_lib) + if (NOT TARGET ${header_we}_sketch_lib OR "${${header_we}_sketch_lib}" MATCHES "NOTFOUND") - string(TOLOWER ${header_we} header_we_lower) + # The header name doesn't conform to a name of a known library, search individual headers instead + _is_known_header(${header_we} ${_target_name} known_header) - link_platform_library(${_target_name} ${header_we_lower}) - - else () - - # Pass the '3RD_PARTY' option to avoid name-conversion - find_arduino_library(${header_we}_sketch_lib ${header_we} 3RD_PARTY QUIET) - - # If library isn't found, display a status since it might be a user library - if (NOT TARGET ${header_we}_sketch_lib OR - "${${header_we}_sketch_lib}" MATCHES "NOTFOUND") - - message(STATUS "The header '${header_we}' is used by the '${_sketch_file}' sketch, " - "but it isn't part of an Arduino nor a Platform library.\n\t" - "However, it may be part of a user library but " - "you'd have to check this manually!") - - else () - link_arduino_library(${_target_name} ${header_we}_sketch_lib) + if (NOT ${known_header}) + message(STATUS "The '${header_we}' header used by the '${_sketch_file}' sketch can't be resolved. " + "It's probably a user-header which location is unknown to the framework.") endif () + else () + link_arduino_library(${_target_name} ${header_we}_sketch_lib) endif () endforeach () diff --git a/cmake/Platform/System/DefaultsManager.cmake b/cmake/Platform/System/DefaultsManager.cmake index 1e22147..30e453b 100644 --- a/cmake/Platform/System/DefaultsManager.cmake +++ b/cmake/Platform/System/DefaultsManager.cmake @@ -5,15 +5,20 @@ function(set_internal_search_patterns) set(ARDUINO_CMAKE_SEMICOLON_REPLACEMENT "!@&#%" CACHE STRING "String replacement for the semicolon char, required when treating lists as code") + set(ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN "^#include.*[<\"]" CACHE STRING "Regex pattern matching header inclusion in a source file") + set(ARDUINO_CMAKE_HEADER_NAME_REGEX_PATTERN "${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}(.+)[>\"]$" CACHE STRING "Regex pattern matching a header's name when wrapped in inclusion line") + set(ARDUINO_CMAKE_HEADER_FILE_EXTENSION_REGEX_PATTERN ".+\\.h.*$" CACHE STRING "Regex pattern matching all header file extensions") - set(ARDUINO_CMAKE_NAME_WE_REGEX_PATTERN "(.+)\\." CACHE STRING + + set(ARDUINO_CMAKE_NAME_WE_REGEX_PATTERN "([^\\/]+)\\." CACHE STRING "Regex pattern matching name without file extension") + set(ARDUINO_CMAKE_FUNCTION_REGEX_PATTERN "^([a-z]|[A-Z])+.*\(([a-z]|[A-Z])*\)" CACHE STRING "Regex pattern matching a function signature in a source file") diff --git a/cmake/Platform/Utilities/PlatformLibraryUtils.cmake b/cmake/Platform/Utilities/PlatformLibraryUtils.cmake index 1056353..0885555 100644 --- a/cmake/Platform/Utilities/PlatformLibraryUtils.cmake +++ b/cmake/Platform/Utilities/PlatformLibraryUtils.cmake @@ -7,6 +7,7 @@ function(is_platform_library _name _return_var) string(TOLOWER "${_name}" name_lower) + if ("${name_lower}" IN_LIST ARDUINO_CMAKE_PLATFORM_LIBRARIES) set(lib_found TRUE) else () diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 4f6216b..fdfd039 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.8.2) project(Examples LANGUAGES C CXX ASM) -add_subdirectory(hello-world) +#[[add_subdirectory(hello-world) add_subdirectory(arduino-library) add_subdirectory(platform-library) add_subdirectory(3rd-party-library) @@ -10,4 +10,6 @@ add_subdirectory(header-only-library) add_subdirectory(blink-example) add_subdirectory(servo-knob-example) add_subdirectory(sketch) -add_subdirectory(misc) +add_subdirectory(misc)]] + +add_subdirectory(sketch) From 1b2c0d598676e4642c1602d273842651d652681d Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Fri, 8 Mar 2019 22:49:31 +0200 Subject: [PATCH 02/23] Separated header insertion process into a macro This is part of the sketch conversion process. --- .../Sketches/SketchSourceConverter.cmake | 88 +++++++------------ .../System/PlatformElementsManager.cmake | 3 + 2 files changed, 37 insertions(+), 54 deletions(-) diff --git a/cmake/Platform/Sketches/SketchSourceConverter.cmake b/cmake/Platform/Sketches/SketchSourceConverter.cmake index a6da3f1..9db9c49 100644 --- a/cmake/Platform/Sketches/SketchSourceConverter.cmake +++ b/cmake/Platform/Sketches/SketchSourceConverter.cmake @@ -8,12 +8,8 @@ function(_write_source_file _sketch_loc _file_path) file(WRITE "${_file_path}" "") # Clear previous file's contents foreach (loc ${_sketch_loc}) - - string(REGEX REPLACE "^(.+)${ARDUINO_CMAKE_SEMICOLON_REPLACEMENT}(.*)$" "\\1;\\2" - original_loc "${loc}") - + string(REGEX REPLACE "^(.+)${ARDUINO_CMAKE_SEMICOLON_REPLACEMENT}(.*)$" "\\1;\\2" original_loc "${loc}") file(APPEND "${_file_path}" "${original_loc}") - endforeach () endfunction() @@ -42,31 +38,52 @@ function(_get_matching_header_insertion_index _sketch_loc _active_index _return_ if ("${previous_loc}" MATCHES "^//") # Simple one-line comment set(matching_index ${_active_index}) - elseif ("${previous_loc}" MATCHES "\\*/$") # End of multi-line comment foreach (index RANGE ${_active_index} 0) - list(GET _sketch_loc ${index} multi_comment_line) if ("${multi_comment_line}" MATCHES "^\\/\\*") # Start of multi-line comment set(matching_index ${index}) break() endif () - endforeach () else () # Previous line isn't a comment - Return original index - increment_integer(_active_index 1) set(matching_index ${_active_index}) - endif () set(${_return_var} ${matching_index} PARENT_SCOPE) endfunction() +#=============================================================================# +# Inline macro which handles the process of inserting a line including the platform header. +# _sketch_lines - List of code lines read from the converted sketch file. +# _insertion_line_index - Index of a code line at which the header should be inserted +#=============================================================================# +macro(_insert_platform_header_include_line _sketch_lines _insertion_line_index) + + _get_matching_header_insertion_index("${_sketch_lines}" ${_insertion_line_index} header_index) + + if (${header_index} LESS ${_insertion_line_index}) + set(formatted_include_line ${ARDUINO_CMAKE_PLATFORM_HEADER_INCLUDE_LINE} "\n\n") + elseif (${header_index} EQUAL 0) + set(formatted_include_line ${ARDUINO_CMAKE_PLATFORM_HEADER_INCLUDE_LINE} "\n") + else () + set(formatted_include_line "\n" ${ARDUINO_CMAKE_PLATFORM_HEADER_INCLUDE_LINE}) + + if (${header_index} GREATER_EQUAL ${_insertion_line_index}) + decrement_integer(header_index 1) + string(APPEND formatted_include_line "\n") + endif () + endif () + + list(INSERT refined_sketch ${header_index} ${formatted_include_line}) + +endmacro() + #=============================================================================# # Converts the given sketch file into a valid 'cpp' source file under the project's working dir. # During the conversion process the platform's main header file is inserted to the source file @@ -78,63 +95,26 @@ function(convert_sketch_to_source _sketch_file _converted_source_path) file(STRINGS "${_sketch_file}" sketch_loc) - list(LENGTH sketch_loc num_of_loc) - decrement_integer(num_of_loc 1) - - set(refined_sketch) + set(header_insert_pattern "${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}|${ARDUINO_CMAKE_FUNCTION_REGEX_PATTERN}") set(header_inserted FALSE) - set(header_insert_pattern - "${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}|${ARDUINO_CMAKE_FUNCTION_REGEX_PATTERN}") - set(include_line "#include <${ARDUINO_CMAKE_PLATFORM_HEADER_NAME}>") + list(LENGTH sketch_loc num_of_loc) + decrement_integer(num_of_loc 1) foreach (loc_index RANGE 0 ${num_of_loc}) list(GET sketch_loc ${loc_index} loc) - if (NOT ${header_inserted}) - - if ("${loc}" MATCHES "${header_insert_pattern}") - - _get_matching_header_insertion_index("${sketch_loc}" ${loc_index} header_index) - - if (${header_index} LESS ${loc_index}) - set(formatted_include_line ${include_line} "\n\n") - - elseif (${header_index} EQUAL 0) - set(formatted_include_line ${include_line} "\n") - - else () - - set(formatted_include_line "\n" ${include_line}) - - if (${header_index} GREATER_EQUAL ${loc_index}) - - decrement_integer(header_index 1) - - string(APPEND formatted_include_line "\n") - - endif () - - endif () - - list(INSERT refined_sketch ${header_index} ${formatted_include_line}) - - set(header_inserted TRUE) - - endif () - + if (NOT ${header_inserted} AND "${loc}" MATCHES "${header_insert_pattern}") + _insert_platform_header_include_line("${sketch_loc}" ${loc_index}) + set(header_inserted TRUE) endif () if ("${loc}" STREQUAL "") list(APPEND refined_sketch "\n") else () - - string(REGEX REPLACE "^(.+);(.*)$" "\\1${ARDUINO_CMAKE_SEMICOLON_REPLACEMENT}\\2" - refined_loc "${loc}") - + string(REGEX REPLACE "^(.+);(.*)$" "\\1${ARDUINO_CMAKE_SEMICOLON_REPLACEMENT}\\2" refined_loc "${loc}") list(APPEND refined_sketch "${refined_loc}\n") - endif () endforeach () diff --git a/cmake/Platform/System/PlatformElementsManager.cmake b/cmake/Platform/System/PlatformElementsManager.cmake index ef3f173..7dcf735 100644 --- a/cmake/Platform/System/PlatformElementsManager.cmake +++ b/cmake/Platform/System/PlatformElementsManager.cmake @@ -165,8 +165,11 @@ function(find_platform_main_header) message(STATUS "Determined Platform Header: ${biggest_header}") # Store both header's name (with extension) and path get_filename_component(platform_header_name "${biggest_header}" NAME) + set(ARDUINO_CMAKE_PLATFORM_HEADER_NAME "${platform_header_name}" CACHE STRING "Platform's main header name (With extension)") + set(ARDUINO_CMAKE_PLATFORM_HEADER_INCLUDE_LINE "#include <${platform_header_name}>" CACHE STRING + "Include line of the platform's main header file to be embedded in source files") set(ARDUINO_CMAKE_PLATFORM_HEADER_PATH "${biggest_header}" CACHE PATH "Path to platform's main header file") From 551a164e95c137a17d1e5bd05c885c06c8b62a39 Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Fri, 8 Mar 2019 23:03:00 +0200 Subject: [PATCH 03/23] Concentrated sketch module under a single file --- cmake/Platform/Arduino.cmake | 4 +++- cmake/Platform/Sketches/SketchManager.cmake | 3 --- cmake/Platform/Sketches/Sketches.cmake | 3 +++ 3 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 cmake/Platform/Sketches/Sketches.cmake diff --git a/cmake/Platform/Arduino.cmake b/cmake/Platform/Arduino.cmake index 5980fc1..76632a1 100644 --- a/cmake/Platform/Arduino.cmake +++ b/cmake/Platform/Arduino.cmake @@ -18,7 +18,9 @@ include(Boards) include(RecipeParser) include(TargetFlagsManager) include(SourcesManager) -include(SketchManager) + +include(Sketches) + include(DefaultsManager) include(ArchitectureSupportQuery) include(CMakeProperties) diff --git a/cmake/Platform/Sketches/SketchManager.cmake b/cmake/Platform/Sketches/SketchManager.cmake index c92e7bf..59313b2 100644 --- a/cmake/Platform/Sketches/SketchManager.cmake +++ b/cmake/Platform/Sketches/SketchManager.cmake @@ -1,6 +1,3 @@ -include(SketchSourceConverter) -include(SketchHeadersManager) - #=============================================================================# # Returns a desired path for sources converted from sketches. # It can't be resolved just by a cache variable since sketches may belong each to a different project, diff --git a/cmake/Platform/Sketches/Sketches.cmake b/cmake/Platform/Sketches/Sketches.cmake new file mode 100644 index 0000000..e192051 --- /dev/null +++ b/cmake/Platform/Sketches/Sketches.cmake @@ -0,0 +1,3 @@ +include(SketchHeadersManager) +include(SketchSourceConverter) +include(SketchManager) From d01a2eb665fdbb3cfa86c563248799148aa16087 Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Tue, 12 Mar 2019 22:11:58 +0200 Subject: [PATCH 04/23] Refactored files structure, added header-retrieving API --- cmake/Platform/Arduino.cmake | 2 +- .../Sketches/FunctionPrototypeGenerator.cmake | 4 + .../Sketches/SketchHeadersManager.cmake | 87 ------------------- .../Sketches/SketchHeadersResolver.cmake | 28 ++++++ .../Sketches/SketchLibrariesResolver.cmake | 26 ++++++ cmake/Platform/Sketches/SketchManager.cmake | 5 +- cmake/Platform/Sketches/Sketches.cmake | 3 +- .../Sources/HeaderExistanceChecker.cmake | 51 +++++++++++ .../Sources/IncludedHeadersRetriever.cmake | 68 +++++++++++++++ cmake/Platform/Sources/Sources.cmake | 5 ++ cmake/Platform/Sources/SourcesManager.cmake | 43 +-------- .../Targets/PlatformLibraryTarget.cmake | 2 +- 12 files changed, 189 insertions(+), 135 deletions(-) create mode 100644 cmake/Platform/Sketches/FunctionPrototypeGenerator.cmake delete mode 100644 cmake/Platform/Sketches/SketchHeadersManager.cmake create mode 100644 cmake/Platform/Sketches/SketchHeadersResolver.cmake create mode 100644 cmake/Platform/Sketches/SketchLibrariesResolver.cmake create mode 100644 cmake/Platform/Sources/HeaderExistanceChecker.cmake create mode 100644 cmake/Platform/Sources/IncludedHeadersRetriever.cmake create mode 100644 cmake/Platform/Sources/Sources.cmake diff --git a/cmake/Platform/Arduino.cmake b/cmake/Platform/Arduino.cmake index 76632a1..63ac4af 100644 --- a/cmake/Platform/Arduino.cmake +++ b/cmake/Platform/Arduino.cmake @@ -17,8 +17,8 @@ include(Boards) include(RecipeParser) include(TargetFlagsManager) -include(SourcesManager) +include(Sources) include(Sketches) include(DefaultsManager) diff --git a/cmake/Platform/Sketches/FunctionPrototypeGenerator.cmake b/cmake/Platform/Sketches/FunctionPrototypeGenerator.cmake new file mode 100644 index 0000000..813b408 --- /dev/null +++ b/cmake/Platform/Sketches/FunctionPrototypeGenerator.cmake @@ -0,0 +1,4 @@ +function(generate_function_prototype _function_line _source_lines _declaration_line_index) + + +endfunction() diff --git a/cmake/Platform/Sketches/SketchHeadersManager.cmake b/cmake/Platform/Sketches/SketchHeadersManager.cmake deleted file mode 100644 index bc63838..0000000 --- a/cmake/Platform/Sketches/SketchHeadersManager.cmake +++ /dev/null @@ -1,87 +0,0 @@ -function(_check_header_existance _header_we _dir_list _return_var) - - foreach (include_dir ${_dir_list}) - find_header_files("${include_dir}" include_dir_headers RECURSE) - - foreach (included_header ${include_dir_headers}) - get_name_without_file_extension(${included_header} included_header_we) - if ("${included_header_we}" STREQUAL "${_header_we}") - set(_return_var TRUE PARENT_SCOPE) - return() - endif () - endforeach () - - endforeach () - - set(_return_var FALSE PARENT_SCOPE) - -endfunction() - -function(_is_known_header _header_we _target_name _return_var) - - # Get target's direct include dirs - get_target_property(target_include_dirs ${_target_name} INCLUDE_DIRECTORIES) - - # Get include dirs of targets linked to the given target - get_target_property(target_linked_libs ${_target_name} LINK_LIBRARIES) - - # Explictly add include dirs of all linked libraries (given they're valid cmake targets) - foreach (linked_lib ${target_linked_libs}) - - if (NOT TARGET ${linked_lib}) - continue() - endif () - - get_target_property(lib_include_dirs ${linked_lib} INCLUDE_DIRECTORIES) - if (NOT "${lib_include_dirs}" MATCHES "NOTFOUND") # Library has include dirs - list(APPEND include_dirs ${lib_include_dirs}) - endif () - - endforeach () - - if (NOT "${target_include_dirs}" MATCHES "NOTFOUND") # Target has direct include dirs - list(APPEND include_dirs ${target_include_dirs}) - endif () - - _check_header_existance(${_header_we} ${include_dirs} header_found) - - set(_return_var ${header_found} PARENT_SCOPE) - -endfunction() - -#=============================================================================# -# Resolves the header files included in a sketch by linking their appropriate library if necessary -# or by validating they're included by the sketch target. -# _target_name - Name of the target to add the sketch file to. -# _sketch_file - Path to a sketch file to add to the target. -#=============================================================================# -function(resolve_sketch_headers _target_name _sketch_file) - - get_source_file_included_headers("${_sketch_file}" sketch_headers) - - foreach (header ${sketch_headers}) - - # Header name without extension (such as '.h') can represent an Arduino/Platform library - # So first we should check whether it's a library - get_name_without_file_extension("${header}" header_we) - - # Pass the '3RD_PARTY' option to avoid name-conversion - find_arduino_library(${header_we}_sketch_lib ${header_we} 3RD_PARTY QUIET) - - if (NOT TARGET ${header_we}_sketch_lib OR "${${header_we}_sketch_lib}" MATCHES "NOTFOUND") - - # The header name doesn't conform to a name of a known library, search individual headers instead - _is_known_header(${header_we} ${_target_name} known_header) - - if (NOT ${known_header}) - message(STATUS "The '${header_we}' header used by the '${_sketch_file}' sketch can't be resolved. " - "It's probably a user-header which location is unknown to the framework.") - endif () - - else () - link_arduino_library(${_target_name} ${header_we}_sketch_lib) - endif () - - endforeach () - -endfunction() diff --git a/cmake/Platform/Sketches/SketchHeadersResolver.cmake b/cmake/Platform/Sketches/SketchHeadersResolver.cmake new file mode 100644 index 0000000..f52cada --- /dev/null +++ b/cmake/Platform/Sketches/SketchHeadersResolver.cmake @@ -0,0 +1,28 @@ +#=============================================================================# +# Resolves the header files included in a sketch by linking their appropriate library if necessary +# or by validating they're included by the sketch target. +# _target_name - Name of the target to add the sketch file to. +# _sketch_file - Path to a sketch file to add to the target. +# _return_var - Name of variable in parent-scope holding the return value. +# Returns - List of all unique header files used by the sketch file, recursively. +#=============================================================================# +function(resolve_sketch_headers _target_name _sketch_file _return_var) + + _get_source_included_headers("${_sketch_file}" sketch_headers) + + foreach (header ${sketch_headers}) + + # Header name without extension (such as '.h') can represent an Arduino/Platform library + # So first we should check whether it's a library + get_name_without_file_extension("${header}" header_we) + + is_header_discoverable_by_target(${header_we} ${_target_name} known_header) + + if (NOT ${known_header}) + message(STATUS "The '${header_we}' header used by the '${_sketch_file}' sketch can't be resolved. " + "It's probably a user-header which location is unknown to the framework.") + endif () + + endforeach () + +endfunction() diff --git a/cmake/Platform/Sketches/SketchLibrariesResolver.cmake b/cmake/Platform/Sketches/SketchLibrariesResolver.cmake new file mode 100644 index 0000000..07d0505 --- /dev/null +++ b/cmake/Platform/Sketches/SketchLibrariesResolver.cmake @@ -0,0 +1,26 @@ +#=============================================================================# +# Resolves the header files included in a sketch by linking their appropriate library if necessary +# or by validating they're included by the sketch target. +# _target_name - Name of the target to add the sketch file to. +# _sketch_file - Path to a sketch file to add to the target. +#=============================================================================# +function(resolve_sketch_libraries _target_name _sketch_file) + + _get_source_included_headers("${_sketch_file}" sketch_headers) + + foreach (header ${sketch_headers}) + + # Header name without extension (such as '.h') can represent an Arduino/Platform library + # So first we should check whether it's a library + get_name_without_file_extension("${header}" header_we) + + # Pass the '3RD_PARTY' option to avoid name-conversion + find_arduino_library(${header_we}_sketch_lib ${header_we} 3RD_PARTY QUIET) + + if (TARGET ${header_we}_sketch_lib) + link_arduino_library(${_target_name} ${header_we}_sketch_lib) + endif () + + endforeach () + +endfunction() diff --git a/cmake/Platform/Sketches/SketchManager.cmake b/cmake/Platform/Sketches/SketchManager.cmake index 59313b2..462c2d1 100644 --- a/cmake/Platform/Sketches/SketchManager.cmake +++ b/cmake/Platform/Sketches/SketchManager.cmake @@ -28,10 +28,9 @@ function(add_sketch_to_target _target_name _sketch_file) _get_converted_source_desired_path(${_sketch_file} sketch_converted_source_path) # Only perform conversion if policy is set or if sketch hasn't been converted yet - if (CONVERT_SKETCHES_IF_CONVERTED_SOURCES_EXISTS OR - NOT EXISTS ${sketch_converted_source_path}) + if (CONVERT_SKETCHES_IF_CONVERTED_SOURCES_EXISTS OR NOT EXISTS ${sketch_converted_source_path}) - resolve_sketch_headers(${_target_name} ${_sketch_file}) + resolve_sketch_libraries(${_target_name} ${_sketch_file}) convert_sketch_to_source(${_sketch_file} ${sketch_converted_source_path}) diff --git a/cmake/Platform/Sketches/Sketches.cmake b/cmake/Platform/Sketches/Sketches.cmake index e192051..1939fe4 100644 --- a/cmake/Platform/Sketches/Sketches.cmake +++ b/cmake/Platform/Sketches/Sketches.cmake @@ -1,3 +1,4 @@ -include(SketchHeadersManager) +include(SketchHeadersResolver) +include(SketchLibrariesResolver) include(SketchSourceConverter) include(SketchManager) diff --git a/cmake/Platform/Sources/HeaderExistanceChecker.cmake b/cmake/Platform/Sources/HeaderExistanceChecker.cmake new file mode 100644 index 0000000..4e643fa --- /dev/null +++ b/cmake/Platform/Sources/HeaderExistanceChecker.cmake @@ -0,0 +1,51 @@ +function(_check_header_existance _header_we _dir_list _return_var) + + foreach (include_dir ${_dir_list}) + + find_header_files("${include_dir}" include_dir_headers RECURSE) + + foreach (included_header ${include_dir_headers}) + get_name_without_file_extension(${included_header} included_header_we) + if ("${included_header_we}" STREQUAL "${_header_we}") + set(_return_var ${included_header} PARENT_SCOPE) + return() + endif () + endforeach () + + endforeach () + + set(_return_var NOTFOUND PARENT_SCOPE) + +endfunction() + +function(is_header_discoverable_by_target _header_we _target_name _return_var) + + # Get target's direct include dirs + get_target_property(target_include_dirs ${_target_name} INCLUDE_DIRECTORIES) + + # Get include dirs of targets linked to the given target + get_target_property(target_linked_libs ${_target_name} LINK_LIBRARIES) + + # Explictly add include dirs of all linked libraries (given they're valid cmake targets) + foreach (linked_lib ${target_linked_libs}) + + if (NOT TARGET ${linked_lib}) + continue() + endif () + + get_target_property(lib_include_dirs ${linked_lib} INCLUDE_DIRECTORIES) + if (NOT "${lib_include_dirs}" MATCHES "NOTFOUND") # Library has include dirs + list(APPEND include_dirs ${lib_include_dirs}) + endif () + + endforeach () + + if (NOT "${target_include_dirs}" MATCHES "NOTFOUND") # Target has direct include dirs + list(APPEND include_dirs ${target_include_dirs}) + endif () + + _check_header_existance(${_header_we} ${include_dirs} header_found) + + set(_return_var ${header_found} PARENT_SCOPE) + +endfunction() diff --git a/cmake/Platform/Sources/IncludedHeadersRetriever.cmake b/cmake/Platform/Sources/IncludedHeadersRetriever.cmake new file mode 100644 index 0000000..12086cd --- /dev/null +++ b/cmake/Platform/Sources/IncludedHeadersRetriever.cmake @@ -0,0 +1,68 @@ +#=============================================================================# +# Retrieves all headers included by a source file. +# Headers are returned by their name, with extension (such as '.h'). +# _source_file - Path to a source file to get its' included headers. +# [WE] - Return headers without extension, just their names. +# _return_var - Name of variable in parent-scope holding the return value. +# Returns - List of headers names with extension that are included by the given source file. +#=============================================================================# +function(_get_source_included_headers _source_file _return_var) + + cmake_parse_arguments(parsed_args "WE" "" "" ${ARGN}) + + file(STRINGS "${_source_file}" source_lines) # Loc = Lines of code + + list(FILTER source_lines INCLUDE REGEX ${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}) + + # Extract header names from inclusion + foreach (loc ${source_lines}) + + string(REGEX MATCH ${ARDUINO_CMAKE_HEADER_NAME_REGEX_PATTERN} match ${loc}) + + if (parsed_args_WE) + get_name_without_file_extension("${CMAKE_MATCH_1}" header_name) + else () + set(header_name ${CMAKE_MATCH_1}) + endif () + + list(APPEND headers ${header_name}) + + endforeach () + + set(${_return_var} ${headers} PARENT_SCOPE) + +endfunction() + +#=============================================================================# +# Retrieves all headers used by a source file, possibly recursively (Headers used by headers). +# _source_file - Path to a source file to get its' used headers. +# [RECURSIVE] - Whether to search for headers recursively. +# _return_var - Name of variable in parent-scope holding the return value. +# Returns - List of full paths to the headers that are used by the given source file. +#=============================================================================# +function(get_source_headers _source_file _include_dirs _return_var) + + cmake_parse_arguments(parsed_args "RECURSIVE" "" "" ${ARGN}) + + _get_source_included_headers(${_source_file} included_headers WE) + + foreach (header ${included_headers}) + + _check_header_existance(${header} ${_include_dirs} header_path) + if ("${header_path}" MATCHES "NOTFOUND") + continue() + endif () + + list(APPEND total_included_headers ${header_path}) + + if (parsed_args_RECURSIVE) + _get_header_internal_headers(${header_path} ${_include_dirs} recursive_included_headers) + endif () + + endforeach () + + list(REMOVE_DUPLICATES total_included_headers) + + set(${_return_var} ${total_included_headers} PARENT_SCOPE) + +endfunction() diff --git a/cmake/Platform/Sources/Sources.cmake b/cmake/Platform/Sources/Sources.cmake new file mode 100644 index 0000000..ecd4e97 --- /dev/null +++ b/cmake/Platform/Sources/Sources.cmake @@ -0,0 +1,5 @@ +include(SourceSeeker) +include(ExampleSourcesSeeker) +include(ArduinoLibrarySourcesSeeker) +include(HeaderExistanceChecker) +include(IncludedHeadersRetriever) diff --git a/cmake/Platform/Sources/SourcesManager.cmake b/cmake/Platform/Sources/SourcesManager.cmake index 6dda993..3cc5947 100644 --- a/cmake/Platform/Sources/SourcesManager.cmake +++ b/cmake/Platform/Sources/SourcesManager.cmake @@ -1,7 +1,3 @@ -include(SourceSeeker) -include(ExampleSourcesSeeker) -include(ArduinoLibrarySourcesSeeker) - #=============================================================================# # Appends all sources and headers under the given directory to the givne target. # This could also be done recursively if the RECURSE option is provided. @@ -90,41 +86,7 @@ function(get_source_file_includes _source_file _return_var) endfunction() #=============================================================================# -# Retrieves all headers includedby a source file. -# Headers are returned by their name, with extension (such as '.h'). -# _source_file - Path to a source file to get its' included headers. -# _return_var - Name of variable in parent-scope holding the return value. -# Returns - List of headers names with extension that are included by the given source file. -#=============================================================================# -function(get_source_file_included_headers _source_file _return_var) - - cmake_parse_arguments(headers "WE" "" "" ${ARGN}) - - file(STRINGS "${_source_file}" source_lines) # Loc = Lines of code - - list(FILTER source_lines INCLUDE REGEX ${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}) - - # Extract header names from inclusion - foreach (loc ${source_lines}) - - string(REGEX MATCH ${ARDUINO_CMAKE_HEADER_NAME_REGEX_PATTERN} match ${loc}) - - if (headers_WE) - get_name_without_file_extension("${CMAKE_MATCH_1}" header_name) - else () - set(header_name ${CMAKE_MATCH_1}) - endif () - - list(APPEND headers ${header_name}) - - endforeach () - - set(${_return_var} ${headers} PARENT_SCOPE) - -endfunction() - -#=============================================================================# -# Gets paths of parent directories from all header files amongst the given sources. +# Gets paths of parent directories of all header files amongst the given sources. # The list of paths is unique (without duplicates). # _sources - List of sources to get include directories from. # _return_var - Name of variable in parent-scope holding the return value. @@ -136,11 +98,8 @@ function(get_headers_parent_directories _sources _return_var) list(FILTER _sources INCLUDE REGEX "${ARDUINO_CMAKE_HEADER_FILE_EXTENSION_REGEX_PATTERN}") foreach (header_source ${_sources}) - get_filename_component(header_parent_dir ${header_source} DIRECTORY) - list(APPEND parent_dirs ${header_parent_dir}) - endforeach () if (parent_dirs) # Check parent dirs, could be none if there aren't any headers amongst sources diff --git a/cmake/Platform/Targets/PlatformLibraryTarget.cmake b/cmake/Platform/Targets/PlatformLibraryTarget.cmake index 4a49842..68f59f1 100644 --- a/cmake/Platform/Targets/PlatformLibraryTarget.cmake +++ b/cmake/Platform/Targets/PlatformLibraryTarget.cmake @@ -8,7 +8,7 @@ function(find_dependent_platform_libraries _sources _return_var) foreach (source ${_sources}) - get_source_file_included_headers(${source} source_includes WE) + _get_source_included_headers(${source} source_includes WE) list(APPEND included_headers_names ${source_includes}) endforeach () From 902c35a881fda3abe0943dc58493530b4ee64f94 Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Fri, 5 Apr 2019 21:49:40 +0300 Subject: [PATCH 05/23] Fixed header retrieval function --- cmake/Platform/Sources/IncludedHeadersRetriever.cmake | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cmake/Platform/Sources/IncludedHeadersRetriever.cmake b/cmake/Platform/Sources/IncludedHeadersRetriever.cmake index 12086cd..70c8b66 100644 --- a/cmake/Platform/Sources/IncludedHeadersRetriever.cmake +++ b/cmake/Platform/Sources/IncludedHeadersRetriever.cmake @@ -49,20 +49,21 @@ function(get_source_headers _source_file _include_dirs _return_var) foreach (header ${included_headers}) _check_header_existance(${header} ${_include_dirs} header_path) - if ("${header_path}" MATCHES "NOTFOUND") + if (NOT header_path OR "${header_path}" MATCHES "NOTFOUND") continue() endif () - list(APPEND total_included_headers ${header_path}) + list(APPEND final_included_headers ${header_path}) if (parsed_args_RECURSIVE) - _get_header_internal_headers(${header_path} ${_include_dirs} recursive_included_headers) + get_source_headers(${header_path} ${_include_dirs} recursive_included_headers RECURSIVE) + list(APPEND final_included_headers ${recursive_included_headers}) endif () endforeach () - list(REMOVE_DUPLICATES total_included_headers) + list(REMOVE_DUPLICATES final_included_headers) - set(${_return_var} ${total_included_headers} PARENT_SCOPE) + set(${_return_var} ${final_included_headers} PARENT_SCOPE) endfunction() From 0934622ed1359c500711ff6835550d01b34d8ac8 Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Fri, 5 Apr 2019 22:07:49 +0300 Subject: [PATCH 06/23] Renamed `check_header_existence` function to `get_header_file` This is because the function returns the path to the header file and not just whether is exists or not. This change also caused separation of the function into a dedicated file --- .../Sources/HeaderExistanceChecker.cmake | 28 +++++------------- cmake/Platform/Sources/HeaderRetriever.cmake | 29 +++++++++++++++++++ ...ver.cmake => SourceHeadersRetriever.cmake} | 2 +- cmake/Platform/Sources/Sources.cmake | 4 ++- cmake/Platform/Utilities/TargetUtils.cmake | 29 +++++++++++++++++++ cmake/Platform/Utilities/Utilities.cmake | 1 + 6 files changed, 71 insertions(+), 22 deletions(-) create mode 100644 cmake/Platform/Sources/HeaderRetriever.cmake rename cmake/Platform/Sources/{IncludedHeadersRetriever.cmake => SourceHeadersRetriever.cmake} (97%) create mode 100644 cmake/Platform/Utilities/TargetUtils.cmake diff --git a/cmake/Platform/Sources/HeaderExistanceChecker.cmake b/cmake/Platform/Sources/HeaderExistanceChecker.cmake index 4e643fa..991acf1 100644 --- a/cmake/Platform/Sources/HeaderExistanceChecker.cmake +++ b/cmake/Platform/Sources/HeaderExistanceChecker.cmake @@ -1,23 +1,11 @@ -function(_check_header_existance _header_we _dir_list _return_var) - - foreach (include_dir ${_dir_list}) - - find_header_files("${include_dir}" include_dir_headers RECURSE) - - foreach (included_header ${include_dir_headers}) - get_name_without_file_extension(${included_header} included_header_we) - if ("${included_header_we}" STREQUAL "${_header_we}") - set(_return_var ${included_header} PARENT_SCOPE) - return() - endif () - endforeach () - - endforeach () - - set(_return_var NOTFOUND PARENT_SCOPE) - -endfunction() - +#=============================================================================# +# Checks whether the given header name is discoverable by the given target, +# i.e. whether it's part of the target's 'INCLUDE_DIRECTORIES' property. +# _header_we - Name of a header to check its' discoverability. +# _target_name - Name of a target to check discoverability against. +# _return_var - Name of variable in parent-scope holding the return value. +# Returns - True if discoverable, false otherwise. +#=============================================================================# function(is_header_discoverable_by_target _header_we _target_name _return_var) # Get target's direct include dirs diff --git a/cmake/Platform/Sources/HeaderRetriever.cmake b/cmake/Platform/Sources/HeaderRetriever.cmake new file mode 100644 index 0000000..05a39a9 --- /dev/null +++ b/cmake/Platform/Sources/HeaderRetriever.cmake @@ -0,0 +1,29 @@ +#=============================================================================# +# Retrieves full path to the file associated with the given header name, +# which should be located under one of the directories in the given list. +# The search is performed recursively (i.e. including sub-dirs) by default. +# If the header can't be found, "NOTFOUND" string is returned. +# _header_we - Name of a header file which should be retrieved. +# _dir_list - List of directories which could contain the searched header file. +# _return_var - Name of variable in parent-scope holding the return value. +# Returns - Full path to the header file associated with the given header name, "NOTFOUND" if can't be found. +#=============================================================================# +function(get_header_file _header_we _dir_list _return_var) + + foreach (include_dir ${_dir_list}) + + find_header_files("${include_dir}" include_dir_headers RECURSE) + + foreach (included_header ${include_dir_headers}) + get_name_without_file_extension(${included_header} included_header_we) + if ("${included_header_we}" STREQUAL "${_header_we}") + set(_return_var ${included_header} PARENT_SCOPE) + return() + endif () + endforeach () + + endforeach () + + set(_return_var NOTFOUND PARENT_SCOPE) + +endfunction() diff --git a/cmake/Platform/Sources/IncludedHeadersRetriever.cmake b/cmake/Platform/Sources/SourceHeadersRetriever.cmake similarity index 97% rename from cmake/Platform/Sources/IncludedHeadersRetriever.cmake rename to cmake/Platform/Sources/SourceHeadersRetriever.cmake index 70c8b66..a915db7 100644 --- a/cmake/Platform/Sources/IncludedHeadersRetriever.cmake +++ b/cmake/Platform/Sources/SourceHeadersRetriever.cmake @@ -48,7 +48,7 @@ function(get_source_headers _source_file _include_dirs _return_var) foreach (header ${included_headers}) - _check_header_existance(${header} ${_include_dirs} header_path) + get_header_file(${header} ${_include_dirs} header_path) if (NOT header_path OR "${header_path}" MATCHES "NOTFOUND") continue() endif () diff --git a/cmake/Platform/Sources/Sources.cmake b/cmake/Platform/Sources/Sources.cmake index ecd4e97..b9ef693 100644 --- a/cmake/Platform/Sources/Sources.cmake +++ b/cmake/Platform/Sources/Sources.cmake @@ -1,5 +1,7 @@ include(SourceSeeker) include(ExampleSourcesSeeker) include(ArduinoLibrarySourcesSeeker) +include(HeaderRetriever) include(HeaderExistanceChecker) -include(IncludedHeadersRetriever) +include(SourceHeadersRetriever) +include(SourcesManager) diff --git a/cmake/Platform/Utilities/TargetUtils.cmake b/cmake/Platform/Utilities/TargetUtils.cmake new file mode 100644 index 0000000..1019175 --- /dev/null +++ b/cmake/Platform/Utilities/TargetUtils.cmake @@ -0,0 +1,29 @@ +function(get_target_include_directories _target_name _return_var) + + # Get target's direct include dirs + get_target_property(target_include_dirs ${_target_name} INCLUDE_DIRECTORIES) + + # Get include dirs of targets linked to the given target + get_target_property(target_linked_libs ${_target_name} LINK_LIBRARIES) + + # Explictly add include dirs of all linked libraries (given they're valid cmake targets) + foreach (linked_lib ${target_linked_libs}) + + if (NOT TARGET ${linked_lib}) # Might be a command-line linked library (such as 'm'/math) + continue() + endif () + + get_target_include_directories(${linked_lib} lib_include_dirs) + set(include_dirs ${lib_include_dirs}) # Update list with recursive call results + + endforeach () + + if (NOT "${target_include_dirs}" MATCHES "NOTFOUND") # Target has direct include dirs + list(APPEND include_dirs ${target_include_dirs}) + endif () + + list(REMOVE_DUPLICATES include_dirs) + + set(${_return_var} ${include_dirs} PARENT_SCOPE) + +endfunction() diff --git a/cmake/Platform/Utilities/Utilities.cmake b/cmake/Platform/Utilities/Utilities.cmake index 92a56c4..da1488d 100644 --- a/cmake/Platform/Utilities/Utilities.cmake +++ b/cmake/Platform/Utilities/Utilities.cmake @@ -4,5 +4,6 @@ include(StringUtils) include(PathUtils) include(PropertyUtils) include(LibraryUtils) +include(TargetUtils) include(PlatformLibraryUtils) include(CMakeArgumentsUtils) From 11399f228fbe77d6e6c6272b311fca4f54cbceec Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Fri, 5 Apr 2019 22:09:24 +0300 Subject: [PATCH 07/23] Upgraded header discoverability (by targets) check --- .../Sources/HeaderExistanceChecker.cmake | 30 ++++--------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/cmake/Platform/Sources/HeaderExistanceChecker.cmake b/cmake/Platform/Sources/HeaderExistanceChecker.cmake index 991acf1..f593259 100644 --- a/cmake/Platform/Sources/HeaderExistanceChecker.cmake +++ b/cmake/Platform/Sources/HeaderExistanceChecker.cmake @@ -8,32 +8,14 @@ #=============================================================================# function(is_header_discoverable_by_target _header_we _target_name _return_var) - # Get target's direct include dirs - get_target_property(target_include_dirs ${_target_name} INCLUDE_DIRECTORIES) + get_target_include_directories(${_target_name} target_include_dirs) - # Get include dirs of targets linked to the given target - get_target_property(target_linked_libs ${_target_name} LINK_LIBRARIES) + get_header_file(${_header_we} ${target_include_dirs} header_found) - # Explictly add include dirs of all linked libraries (given they're valid cmake targets) - foreach (linked_lib ${target_linked_libs}) - - if (NOT TARGET ${linked_lib}) - continue() - endif () - - get_target_property(lib_include_dirs ${linked_lib} INCLUDE_DIRECTORIES) - if (NOT "${lib_include_dirs}" MATCHES "NOTFOUND") # Library has include dirs - list(APPEND include_dirs ${lib_include_dirs}) - endif () - - endforeach () - - if (NOT "${target_include_dirs}" MATCHES "NOTFOUND") # Target has direct include dirs - list(APPEND include_dirs ${target_include_dirs}) + if (NOT header_found OR "${header_found}" MATCHES "NOTFOUND") + set(_return_var FALSE PARENT_SCOPE) + else () + set(_return_var TRUE PARENT_SCOPE) endif () - _check_header_existance(${_header_we} ${include_dirs} header_found) - - set(_return_var ${header_found} PARENT_SCOPE) - endfunction() From 222783553b7c331dfa50aa98741135ac62ae3443 Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Sat, 6 Apr 2019 20:10:42 +0300 Subject: [PATCH 08/23] Added sketch header resolving, updated library resolving to use it --- .../Sketches/SketchHeadersResolver.cmake | 25 ++++--------------- .../Sketches/SketchLibrariesResolver.cmake | 16 ++++++------ cmake/Platform/Sketches/SketchManager.cmake | 4 ++- .../Sources/SourceHeadersRetriever.cmake | 11 +++++--- 4 files changed, 22 insertions(+), 34 deletions(-) diff --git a/cmake/Platform/Sketches/SketchHeadersResolver.cmake b/cmake/Platform/Sketches/SketchHeadersResolver.cmake index f52cada..39319e5 100644 --- a/cmake/Platform/Sketches/SketchHeadersResolver.cmake +++ b/cmake/Platform/Sketches/SketchHeadersResolver.cmake @@ -1,28 +1,13 @@ #=============================================================================# -# Resolves the header files included in a sketch by linking their appropriate library if necessary -# or by validating they're included by the sketch target. -# _target_name - Name of the target to add the sketch file to. -# _sketch_file - Path to a sketch file to add to the target. +# Resolves all headers used by a given sketch file by searching its 'include lines', recursively. +# _target_name - Name of the sketch's target created earlier. +# _sketch_file - Path to the sketch file which its' headers should be resolved. # _return_var - Name of variable in parent-scope holding the return value. # Returns - List of all unique header files used by the sketch file, recursively. #=============================================================================# function(resolve_sketch_headers _target_name _sketch_file _return_var) - _get_source_included_headers("${_sketch_file}" sketch_headers) - - foreach (header ${sketch_headers}) - - # Header name without extension (such as '.h') can represent an Arduino/Platform library - # So first we should check whether it's a library - get_name_without_file_extension("${header}" header_we) - - is_header_discoverable_by_target(${header_we} ${_target_name} known_header) - - if (NOT ${known_header}) - message(STATUS "The '${header_we}' header used by the '${_sketch_file}' sketch can't be resolved. " - "It's probably a user-header which location is unknown to the framework.") - endif () - - endforeach () + get_target_include_directories(${_target_name} target_include_dirs) + get_source_headers("${_sketch_file}" ${target_include_dirs} sketch_headers RECURSIVE) endfunction() diff --git a/cmake/Platform/Sketches/SketchLibrariesResolver.cmake b/cmake/Platform/Sketches/SketchLibrariesResolver.cmake index 07d0505..e8f7131 100644 --- a/cmake/Platform/Sketches/SketchLibrariesResolver.cmake +++ b/cmake/Platform/Sketches/SketchLibrariesResolver.cmake @@ -1,17 +1,15 @@ #=============================================================================# -# Resolves the header files included in a sketch by linking their appropriate library if necessary -# or by validating they're included by the sketch target. -# _target_name - Name of the target to add the sketch file to. -# _sketch_file - Path to a sketch file to add to the target. +# Resolves the libraries used by a sketch file. It's possible that not all libraries will be resolved, +# as the current algorithm relies on the name of the included headers to match a library name. +# _target_name - Name of the sketch's target created earlier. +# _sketch_file - Path to the sketch file which its' libraries should be resolved. +# _sketch_headers - List of headers files used by the sketch, directly or indirectly. #=============================================================================# -function(resolve_sketch_libraries _target_name _sketch_file) +function(resolve_sketch_libraries _target_name _sketch_file _sketch_headers) - _get_source_included_headers("${_sketch_file}" sketch_headers) - - foreach (header ${sketch_headers}) + foreach (header ${_sketch_headers}) # Header name without extension (such as '.h') can represent an Arduino/Platform library - # So first we should check whether it's a library get_name_without_file_extension("${header}" header_we) # Pass the '3RD_PARTY' option to avoid name-conversion diff --git a/cmake/Platform/Sketches/SketchManager.cmake b/cmake/Platform/Sketches/SketchManager.cmake index 462c2d1..a32527b 100644 --- a/cmake/Platform/Sketches/SketchManager.cmake +++ b/cmake/Platform/Sketches/SketchManager.cmake @@ -30,7 +30,9 @@ function(add_sketch_to_target _target_name _sketch_file) # Only perform conversion if policy is set or if sketch hasn't been converted yet if (CONVERT_SKETCHES_IF_CONVERTED_SOURCES_EXISTS OR NOT EXISTS ${sketch_converted_source_path}) - resolve_sketch_libraries(${_target_name} ${_sketch_file}) + resolve_sketch_headers(${_target_name} ${_sketch_file} sketch_headers) + + resolve_sketch_libraries(${_target_name} ${_sketch_file} "${sketch_headers}") convert_sketch_to_source(${_sketch_file} ${sketch_converted_source_path}) diff --git a/cmake/Platform/Sources/SourceHeadersRetriever.cmake b/cmake/Platform/Sources/SourceHeadersRetriever.cmake index a915db7..5a24853 100644 --- a/cmake/Platform/Sources/SourceHeadersRetriever.cmake +++ b/cmake/Platform/Sources/SourceHeadersRetriever.cmake @@ -36,11 +36,12 @@ endfunction() #=============================================================================# # Retrieves all headers used by a source file, possibly recursively (Headers used by headers). # _source_file - Path to a source file to get its' used headers. +# _search_dirs - List of directories where headers should be searched at. # [RECURSIVE] - Whether to search for headers recursively. # _return_var - Name of variable in parent-scope holding the return value. # Returns - List of full paths to the headers that are used by the given source file. #=============================================================================# -function(get_source_headers _source_file _include_dirs _return_var) +function(get_source_headers _source_file _search_dirs _return_var) cmake_parse_arguments(parsed_args "RECURSIVE" "" "" ${ARGN}) @@ -48,7 +49,7 @@ function(get_source_headers _source_file _include_dirs _return_var) foreach (header ${included_headers}) - get_header_file(${header} ${_include_dirs} header_path) + get_header_file(${header} ${_search_dirs} header_path) if (NOT header_path OR "${header_path}" MATCHES "NOTFOUND") continue() endif () @@ -56,13 +57,15 @@ function(get_source_headers _source_file _include_dirs _return_var) list(APPEND final_included_headers ${header_path}) if (parsed_args_RECURSIVE) - get_source_headers(${header_path} ${_include_dirs} recursive_included_headers RECURSIVE) + get_source_headers(${header_path} ${_search_dirs} recursive_included_headers RECURSIVE) list(APPEND final_included_headers ${recursive_included_headers}) endif () endforeach () - list(REMOVE_DUPLICATES final_included_headers) + if (final_included_headers) + list(REMOVE_DUPLICATES final_included_headers) + endif () set(${_return_var} ${final_included_headers} PARENT_SCOPE) From 591ef399132a038c9fc48536b4c4e70048ce83af Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Thu, 25 Apr 2019 13:39:31 +0300 Subject: [PATCH 09/23] Applied new CMake 'newline' cache policy to some regexes --- cmake/Platform/Project/ProjectSetup.cmake | 9 ++++++++ cmake/Platform/System/DefaultsManager.cmake | 23 +++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/cmake/Platform/Project/ProjectSetup.cmake b/cmake/Platform/Project/ProjectSetup.cmake index 732a688..cb9bf35 100644 --- a/cmake/Platform/Project/ProjectSetup.cmake +++ b/cmake/Platform/Project/ProjectSetup.cmake @@ -11,4 +11,13 @@ function(arduino_cmake_project _project_name) setup_project_core_lib(${_project_name}) + set(ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN + "^([A-Za-z0-9_][ \t\r\n]*)+\\(.*\\)$" PARENT_SCOPE) + set(ARDUINO_CMAKE_FUNCTION_DECLARATION_REGEX_PATTERN + "^([A-Za-z0-9_])+.+([A-Za-z0-9_])+[ \t\r\n]*\\((.*)\\);$" PARENT_SCOPE) + set(ARDUINO_CMAKE_FUNCTION_NAME_REGEX_PATTERN "(([A-Za-z0-9_])+)[ \t\r\n]*\\(.*\\)" PARENT_SCOPE) + set(ARDUINO_CMAKE_FUNCTION_ARGS_REGEX_PATTERN "\\((.*)\\)" PARENT_SCOPE) + set(ARDUINO_CMAKE_FUNCTION_SINGLE_ARG_REGEX_PATTERN "([A-Za-z0-9_]+)[^,]*" PARENT_SCOPE) + set(ARDUINO_CMAKE_FUNCTION_ARG_TYPE_REGEX_PATTERN "[A-Za-z0-9_]+.*[ \t\r\n]+" PARENT_SCOPE) + endfunction() diff --git a/cmake/Platform/System/DefaultsManager.cmake b/cmake/Platform/System/DefaultsManager.cmake index 30e453b..7cd9f4e 100644 --- a/cmake/Platform/System/DefaultsManager.cmake +++ b/cmake/Platform/System/DefaultsManager.cmake @@ -19,8 +19,27 @@ function(set_internal_search_patterns) set(ARDUINO_CMAKE_NAME_WE_REGEX_PATTERN "([^\\/]+)\\." CACHE STRING "Regex pattern matching name without file extension") - set(ARDUINO_CMAKE_FUNCTION_REGEX_PATTERN "^([a-z]|[A-Z])+.*\(([a-z]|[A-Z])*\)" CACHE STRING - "Regex pattern matching a function signature in a source file") + #[[set(ARDUINO_CMAKE_FUNCTION_DECLARATION_REGEX_PATTERN "^([A-Za-z0-9_])+.+([A-Za-z0-9_])+[ \t\r\\n]*\((.*)\);$" + CACHE STRING "Regex pattern matching a function signature definition in a source file") + + set(ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN "^([A-Za-z0-9_])+[ \t\r\n]*\(([A-Za-z0-9_])*\)$" + CACHE STRING "Regex pattern matching a function signature definition in a source file") + + set(ARDUINO_CMAKE_FUNCTION_NAME_REGEX_PATTERN "(([A-Za-z0-9_])+)[ \t\r\\n]*\(.*\)" + CACHE STRING + "Regex pattern matching a function's name (and everything following it), can be retrieved by the 1st group") + + set(ARDUINO_CMAKE_FUNCTION_ARGS_REGEX_PATTERN "\((.*)\)" + CACHE STRING + "Regex pattern matching a function's argument list, i.e. What's inside the parentheses") + + set(ARDUINO_CMAKE_FUNCTION_SINGLE_ARG_REGEX_PATTERN "([A-Za-z0-9_]+)[^,]*" + CACHE STRING + "Regex pattern matching a function's argument, requiring maximum matches to get all arguments") + + set(ARDUINO_CMAKE_FUNCTION_ARG_TYPE_REGEX_PATTERN "[A-Za-z0-9_]+.*[ \t\r\\n]+" + CACHE STRING + "Regex pattern matching a function argument type, ommiting it's name")]] endfunction() From 8f95591064f8b31bfcbdf9dbdc3bdcdf81f94226 Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Thu, 25 Apr 2019 13:41:02 +0300 Subject: [PATCH 10/23] Added function definition-declaration matching --- .../Sources/FunctionDeclarationMatcher.cmake | 68 +++++++++++++++++++ .../Sources/FunctionSignatureStripper.cmake | 43 ++++++++++++ .../Sources/SourceFunctionsRetriever.cmake | 13 ++++ cmake/Platform/Sources/Sources.cmake | 3 + 4 files changed, 127 insertions(+) create mode 100644 cmake/Platform/Sources/FunctionDeclarationMatcher.cmake create mode 100644 cmake/Platform/Sources/FunctionSignatureStripper.cmake create mode 100644 cmake/Platform/Sources/SourceFunctionsRetriever.cmake diff --git a/cmake/Platform/Sources/FunctionDeclarationMatcher.cmake b/cmake/Platform/Sources/FunctionDeclarationMatcher.cmake new file mode 100644 index 0000000..60cc8a7 --- /dev/null +++ b/cmake/Platform/Sources/FunctionDeclarationMatcher.cmake @@ -0,0 +1,68 @@ + +function(match_function_declaration _definition_signature _included_headers _return_var) + + # Get function name and list of argument-types + strip_function_signature("${_definition_signature}" original_stripped_function) + + # ToDo: Consider writing a utility function + list(LENGTH original_stripped_function orig_func_list_len) + set(original_function_args_length ${orig_func_list_len}) + decrement_integer(original_function_args_length 1) + + list(GET original_stripped_function 0 original_function_name) + + foreach (included_header ${_included_headers}) + + file(STRINGS "${included_header}" header_lines) + + foreach (line ${header_lines}) + + # Search for function declarations + if ("${line}" MATCHES "${ARDUINO_CMAKE_FUNCTION_DECLARATION_REGEX_PATTERN}") + + # Get function name and list of argument-types + strip_function_signature("${line}" iterated_stripped_function) + + # ToDo: Consider writing a utility function + list(LENGTH iterated_stripped_function iter_func_list_len) + set(iterated_function_args_length ${iter_func_list_len}) + decrement_integer(iterated_function_args_length 1) + + list(GET iterated_stripped_function 0 iterated_function_name) + + if ("${original_function_name}" STREQUAL "${iterated_function_name}") + if (${orig_func_list_len} EQUAL ${iter_func_list_len}) + + set(arg_types_match TRUE) + + if (${iterated_function_args_length} GREATER 0) + foreach (arg_type_index RANGE 1 ${iterated_function_args_length}) + + list(GET original_stripped_function ${arg_type_index} orig_arg_type) + list(GET iterated_stripped_function ${arg_type_index} iter_arg_type) + + if (NOT ${orig_arg_type} EQUAL ${iter_arg_type}) + set(arg_types_match FALSE) + break() + endif () + + endforeach () + endif () + + if (${arg_types_match}) # Signature has been matched + set(${_return_var} ${line} PARENT_SCOPE) + return() + endif () + + endif () + endif () + + endif () + + endforeach () + + endforeach () + + set(${_return_var} "NOTFOUND" PARENT_SCOPE) + +endfunction() diff --git a/cmake/Platform/Sources/FunctionSignatureStripper.cmake b/cmake/Platform/Sources/FunctionSignatureStripper.cmake new file mode 100644 index 0000000..84c16d3 --- /dev/null +++ b/cmake/Platform/Sources/FunctionSignatureStripper.cmake @@ -0,0 +1,43 @@ +#=============================================================================# +# Gets the types of a function's arguments as a list. +# _signature - String representing a full function signature, e.g. 'int main(int argc, char **argv)' +# _return_var - Name of variable in parent-scope holding the return value. +# Returns - List of types, matching the given function-argument string. +#=============================================================================# +function(_get_function_arguments_types _signature _return_var) + + string(REGEX MATCH ${ARDUINO_CMAKE_FUNCTION_ARGS_REGEX_PATTERN} function_args_string "${_signature}") + string(REGEX MATCHALL ${ARDUINO_CMAKE_FUNCTION_SINGLE_ARG_REGEX_PATTERN} + function_arg_list "${_function_args_string}") + + # Iterate through all arguments to extract only their type + foreach (arg ${function_arg_list}) + string(REGEX MATCH ${ARDUINO_CMAKE_FUNCTION_ARG_TYPE_REGEX_PATTERN} arg_type "${arg}") + string(STRIP "${arg_type}" arg_type) # Strip remaining whitespaces + list(APPEND function_args ${arg_type}) + endforeach () + + set(${_return_var} ${function_args} PARENT_SCOPE) + +endfunction() + +#=============================================================================# +# Strips a given function signature to its name and its arguments' types. +# _signature - String representing a full function signature, e.g. 'int main(int argc, char **argv)' +# _return_var - Name of variable in parent-scope holding the return value. +# Returns - List consisting of the function's name and arguments types. +#=============================================================================# +function(strip_function_signature _signature _return_var) + + # Strip function's name + string(REGEX MATCH ${ARDUINO_CMAKE_FUNCTION_NAME_REGEX_PATTERN} function_name_match "${_signature}") + set(function_name ${CMAKE_MATCH_1}) + list(APPEND stripped_signature ${function_name}) + + # Strip arguments types , i.e. without names + _get_function_arguments_types("${_signature}" function_args_types) + list(APPEND stripped_signature ${function_args_types}) + + set(${_return_var} ${stripped_signature} PARENT_SCOPE) + +endfunction() \ No newline at end of file diff --git a/cmake/Platform/Sources/SourceFunctionsRetriever.cmake b/cmake/Platform/Sources/SourceFunctionsRetriever.cmake new file mode 100644 index 0000000..534a58d --- /dev/null +++ b/cmake/Platform/Sources/SourceFunctionsRetriever.cmake @@ -0,0 +1,13 @@ +function(get_source_function_definitions _source_file _return_var) + + file(STRINGS "${_source_file}" source_lines) + + foreach (line ${source_lines}) + if ("${line}" MATCHES "${ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN}") + list(APPEND definitions "${line}") + endif () + endforeach () + + set(${_return_var} ${definitions} PARENT_SCOPE) + +endfunction() \ No newline at end of file diff --git a/cmake/Platform/Sources/Sources.cmake b/cmake/Platform/Sources/Sources.cmake index b9ef693..6c71b2d 100644 --- a/cmake/Platform/Sources/Sources.cmake +++ b/cmake/Platform/Sources/Sources.cmake @@ -1,3 +1,6 @@ +include(FunctionSignatureStripper) +include(FunctionDeclarationMatcher) +include(SourceFunctionsRetriever) include(SourceSeeker) include(ExampleSourcesSeeker) include(ArduinoLibrarySourcesSeeker) From f347ad28154da0125010db1923bcc456c067a957 Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Thu, 25 Apr 2019 13:42:27 +0300 Subject: [PATCH 11/23] Added partial sketch prototype resolving It detects which prototypes need to be generated, based on the def-dec matching ability previously added --- cmake/Platform/Sketches/SketchManager.cmake | 2 +- .../Sketches/SketchPrototypesResolver.cmake | 21 +++++++++++++++++++ .../Sketches/SketchSourceConverter.cmake | 3 ++- cmake/Platform/Sketches/Sketches.cmake | 1 + examples/sketch/sketch2.pde | 3 +++ 5 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 cmake/Platform/Sketches/SketchPrototypesResolver.cmake diff --git a/cmake/Platform/Sketches/SketchManager.cmake b/cmake/Platform/Sketches/SketchManager.cmake index a32527b..6b36e2f 100644 --- a/cmake/Platform/Sketches/SketchManager.cmake +++ b/cmake/Platform/Sketches/SketchManager.cmake @@ -31,8 +31,8 @@ function(add_sketch_to_target _target_name _sketch_file) if (CONVERT_SKETCHES_IF_CONVERTED_SOURCES_EXISTS OR NOT EXISTS ${sketch_converted_source_path}) resolve_sketch_headers(${_target_name} ${_sketch_file} sketch_headers) - resolve_sketch_libraries(${_target_name} ${_sketch_file} "${sketch_headers}") + resolve_sketch_prototypes(${_sketch_file} "${sketch_headers}" sketch_prototypes) convert_sketch_to_source(${_sketch_file} ${sketch_converted_source_path}) diff --git a/cmake/Platform/Sketches/SketchPrototypesResolver.cmake b/cmake/Platform/Sketches/SketchPrototypesResolver.cmake new file mode 100644 index 0000000..c0214f7 --- /dev/null +++ b/cmake/Platform/Sketches/SketchPrototypesResolver.cmake @@ -0,0 +1,21 @@ +function(resolve_sketch_prototypes _sketch_file _resolved_sketch_headers _return_var) + + get_source_function_definitions(${_sketch_file} sketch_func_defines) + if (NOT sketch_func_defines) # Source has no function definitions at all + return() + endif () + + list(APPEND _resolved_sketch_headers "${_sketch_file}") + + foreach (func_def ${sketch_func_defines}) + + match_function_declaration("${func_def}" "${_resolved_sketch_headers}" match) + + if (${match} MATCHES "NOTFOUND") + # ToDo: Append signature to list of prototypes to create + message("Coludn't find a matching declaration for `${func_def}`") + endif () + + endforeach () + +endfunction() \ No newline at end of file diff --git a/cmake/Platform/Sketches/SketchSourceConverter.cmake b/cmake/Platform/Sketches/SketchSourceConverter.cmake index 9db9c49..888fbd5 100644 --- a/cmake/Platform/Sketches/SketchSourceConverter.cmake +++ b/cmake/Platform/Sketches/SketchSourceConverter.cmake @@ -95,7 +95,8 @@ function(convert_sketch_to_source _sketch_file _converted_source_path) file(STRINGS "${_sketch_file}" sketch_loc) - set(header_insert_pattern "${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}|${ARDUINO_CMAKE_FUNCTION_REGEX_PATTERN}") + set(header_insert_pattern + "${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}|${ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN}") set(header_inserted FALSE) list(LENGTH sketch_loc num_of_loc) diff --git a/cmake/Platform/Sketches/Sketches.cmake b/cmake/Platform/Sketches/Sketches.cmake index 1939fe4..1fabae4 100644 --- a/cmake/Platform/Sketches/Sketches.cmake +++ b/cmake/Platform/Sketches/Sketches.cmake @@ -1,4 +1,5 @@ include(SketchHeadersResolver) include(SketchLibrariesResolver) +include(SketchPrototypesResolver) include(SketchSourceConverter) include(SketchManager) diff --git a/examples/sketch/sketch2.pde b/examples/sketch/sketch2.pde index e7c965e..7d33ef7 100644 --- a/examples/sketch/sketch2.pde +++ b/examples/sketch/sketch2.pde @@ -2,7 +2,10 @@ int x = 5; +int bar(short, int b); + void foo() { Serial.print(x); + bar(5, 6); } From b2e3e0147161148704d84600e05897c5745fb327 Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Thu, 25 Apr 2019 14:06:03 +0300 Subject: [PATCH 12/23] Added utility function to get list's max/largest index --- .../Sketches/SketchPrototypesResolver.cmake | 16 +++++++++--- .../Sources/FunctionDeclarationMatcher.cmake | 25 +++++++++---------- cmake/Platform/Utilities/ListUtils.cmake | 21 +++++++++++++++- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/cmake/Platform/Sketches/SketchPrototypesResolver.cmake b/cmake/Platform/Sketches/SketchPrototypesResolver.cmake index c0214f7..529015b 100644 --- a/cmake/Platform/Sketches/SketchPrototypesResolver.cmake +++ b/cmake/Platform/Sketches/SketchPrototypesResolver.cmake @@ -1,15 +1,25 @@ -function(resolve_sketch_prototypes _sketch_file _resolved_sketch_headers _return_var) +#=============================================================================# +# Resolves the given sketch file's prototypes, which are just function declarations, +# by matching all function definitions with their declaration. If a declaration can't be found, +# the definition is added to a list of prototypes to generate, which is then returned. +# _sketch_file - Path to the sketch file which its' libraries should be resolved. +# _sketch_headers - List of headers files used by the sketch, directly or indirectly. +# _return_var - Name of variable in parent-scope holding the return value. +# Returns - List of prototypes to generate, i.e. function definitions without a matching declaration. +#=============================================================================# +function(resolve_sketch_prototypes _sketch_file _sketch_headers _return_var) get_source_function_definitions(${_sketch_file} sketch_func_defines) if (NOT sketch_func_defines) # Source has no function definitions at all return() endif () - list(APPEND _resolved_sketch_headers "${_sketch_file}") + # Add the current file to the list of headers to search in as well - It's the functions' containing file + list(APPEND _sketch_headers "${_sketch_file}") foreach (func_def ${sketch_func_defines}) - match_function_declaration("${func_def}" "${_resolved_sketch_headers}" match) + match_function_declaration("${func_def}" "${_sketch_headers}" match) if (${match} MATCHES "NOTFOUND") # ToDo: Append signature to list of prototypes to create diff --git a/cmake/Platform/Sources/FunctionDeclarationMatcher.cmake b/cmake/Platform/Sources/FunctionDeclarationMatcher.cmake index 60cc8a7..e35d165 100644 --- a/cmake/Platform/Sources/FunctionDeclarationMatcher.cmake +++ b/cmake/Platform/Sources/FunctionDeclarationMatcher.cmake @@ -1,15 +1,19 @@ - +#=============================================================================# +# Attempts to match a given function definition signature to its' declaration, searching in all given headers. +# These headers are usually a list of all headers included by the function's file, recursively. +# Given a match, the declaration is returned, otherwise - "NOTFOUND" string. +# _definition_signature - String representing a full function signature, e.g. 'int main(int argc, char **argv)' +# _included_headers - List of headers to search the declaration in. +# Should include the function's containing file itself. +# _return_var - Name of variable in parent-scope holding the return value. +# Returns - Function's declaration signature if exists, otherwise "NOTFOUND". +#=============================================================================# function(match_function_declaration _definition_signature _included_headers _return_var) # Get function name and list of argument-types strip_function_signature("${_definition_signature}" original_stripped_function) - - # ToDo: Consider writing a utility function - list(LENGTH original_stripped_function orig_func_list_len) - set(original_function_args_length ${orig_func_list_len}) - decrement_integer(original_function_args_length 1) - list(GET original_stripped_function 0 original_function_name) + list_max_index("${original_stripped_function}" original_function_args_length) foreach (included_header ${_included_headers}) @@ -22,13 +26,8 @@ function(match_function_declaration _definition_signature _included_headers _ret # Get function name and list of argument-types strip_function_signature("${line}" iterated_stripped_function) - - # ToDo: Consider writing a utility function - list(LENGTH iterated_stripped_function iter_func_list_len) - set(iterated_function_args_length ${iter_func_list_len}) - decrement_integer(iterated_function_args_length 1) - list(GET iterated_stripped_function 0 iterated_function_name) + list_max_index("${iterated_stripped_function}" iterated_function_args_length) if ("${original_function_name}" STREQUAL "${iterated_function_name}") if (${orig_func_list_len} EQUAL ${iter_func_list_len}) diff --git a/cmake/Platform/Utilities/ListUtils.cmake b/cmake/Platform/Utilities/ListUtils.cmake index 987cb67..0823b37 100644 --- a/cmake/Platform/Utilities/ListUtils.cmake +++ b/cmake/Platform/Utilities/ListUtils.cmake @@ -7,7 +7,6 @@ macro(list_replace _list _index _new_element) list(REMOVE_AT ${_list} ${_index}) - list(INSERT ${_list} ${_index} "${_new_element}") endmacro() @@ -25,3 +24,23 @@ macro(initialize_list _list) endif () endmacro() + +#=============================================================================# +# Gets the maximal index a given list can relate to, i.e. the largest index, zero-counted. +# Usually it's just `length - 1`, but there are edge cases where special treatment must be applied. +# _list - List to get its maximal index. +# _return_var - Name of variable in parent-scope holding the return value. +# Returns - Maximal index the list can relate to (usually `length - 1`). +#=============================================================================# +function(list_max_index _list _return_var) + + list(LENGTH _list list_length) + + set(index ${list_length}) + if (${index} GREATER 0) + decrement_integer(${index} 1) + endif () + + set(${_return_var} ${index} PARENT_SCOPE) + +endfunction() From 64a8afbddaa51e49e7819fd832c7c9f60cb7b617 Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Thu, 25 Apr 2019 17:03:00 +0300 Subject: [PATCH 13/23] Added insertion of sketch prototypes to converted sources Added utility function to escape semicolons in a string and vice-versa Fixed bug in `list_max_index` utility function --- cmake/Platform/Sketches/SketchManager.cmake | 2 +- .../Sketches/SketchPrototypesResolver.cmake | 5 +- .../Sketches/SketchSourceConverter.cmake | 87 ++++++++++++------- cmake/Platform/Utilities/ListUtils.cmake | 4 +- cmake/Platform/Utilities/StringUtils.cmake | 27 +++++- 5 files changed, 86 insertions(+), 39 deletions(-) diff --git a/cmake/Platform/Sketches/SketchManager.cmake b/cmake/Platform/Sketches/SketchManager.cmake index 6b36e2f..91f6ae4 100644 --- a/cmake/Platform/Sketches/SketchManager.cmake +++ b/cmake/Platform/Sketches/SketchManager.cmake @@ -34,7 +34,7 @@ function(add_sketch_to_target _target_name _sketch_file) resolve_sketch_libraries(${_target_name} ${_sketch_file} "${sketch_headers}") resolve_sketch_prototypes(${_sketch_file} "${sketch_headers}" sketch_prototypes) - convert_sketch_to_source(${_sketch_file} ${sketch_converted_source_path}) + convert_sketch_to_source(${_sketch_file} ${sketch_converted_source_path} ${sketch_prototypes}) endif () diff --git a/cmake/Platform/Sketches/SketchPrototypesResolver.cmake b/cmake/Platform/Sketches/SketchPrototypesResolver.cmake index 529015b..62784de 100644 --- a/cmake/Platform/Sketches/SketchPrototypesResolver.cmake +++ b/cmake/Platform/Sketches/SketchPrototypesResolver.cmake @@ -22,10 +22,11 @@ function(resolve_sketch_prototypes _sketch_file _sketch_headers _return_var) match_function_declaration("${func_def}" "${_sketch_headers}" match) if (${match} MATCHES "NOTFOUND") - # ToDo: Append signature to list of prototypes to create - message("Coludn't find a matching declaration for `${func_def}`") + list(APPEND prototypes "${func_def}") endif () endforeach () + set(${_return_var} ${prototypes} PARENT_SCOPE) + endfunction() \ No newline at end of file diff --git a/cmake/Platform/Sketches/SketchSourceConverter.cmake b/cmake/Platform/Sketches/SketchSourceConverter.cmake index 888fbd5..1d072a0 100644 --- a/cmake/Platform/Sketches/SketchSourceConverter.cmake +++ b/cmake/Platform/Sketches/SketchSourceConverter.cmake @@ -1,15 +1,15 @@ #=============================================================================# # Writes the given lines of code belonging to the sketch to the given file path. -# _sketch_loc - List of lines-of-code belonging to the sketch. +# _sketch_lines - List of lines-of-code belonging to the sketch. # _file_path - Full path to the written source file. #=============================================================================# -function(_write_source_file _sketch_loc _file_path) +function(_write_source_file _sketch_lines _file_path) file(WRITE "${_file_path}" "") # Clear previous file's contents - foreach (loc ${_sketch_loc}) - string(REGEX REPLACE "^(.+)${ARDUINO_CMAKE_SEMICOLON_REPLACEMENT}(.*)$" "\\1;\\2" original_loc "${loc}") - file(APPEND "${_file_path}" "${original_loc}") + foreach (line ${_sketch_lines}) + escape_semicolon_in_string("${line}" original_line REVERSE) + file(APPEND "${_file_path}" "${original_line}") endforeach () endfunction() @@ -20,12 +20,12 @@ endfunction() # best fitted the insertion, however, it might need a bit more optimization. Why? # Because above those lines there might be a comment, or a comment block, # all of which should be taken into account in order to minimize the effect on code's readability. -# _sketch_loc - List of lines-of-code belonging to the sketch. -# _active_index - Index that indicates the best-not-optimized loc to insert header to. +# _sketch_lines - List of lines-of-code belonging to the sketch. +# _active_index - Index that indicates the best-not-optimized line to insert header to. # _return_var - Name of variable in parent-scope holding the return value. # Returns - Best fitted index to insert platform's main header '#include' to. #=============================================================================# -function(_get_matching_header_insertion_index _sketch_loc _active_index _return_var) +function(_get_matching_header_insertion_index _sketch_lines _active_index _return_var) if (${_active_index} EQUAL 0) # First line in a file will always result in the 1st index set(${_return_var} 0 PARENT_SCOPE) @@ -34,14 +34,14 @@ function(_get_matching_header_insertion_index _sketch_loc _active_index _return_ decrement_integer(_active_index 1) endif () - list(GET _sketch_loc ${_active_index} previous_loc) + list(GET _sketch_lines ${_active_index} previous_loc) if ("${previous_loc}" MATCHES "^//") # Simple one-line comment set(matching_index ${_active_index}) elseif ("${previous_loc}" MATCHES "\\*/$") # End of multi-line comment foreach (index RANGE ${_active_index} 0) - list(GET _sketch_loc ${index} multi_comment_line) + list(GET _sketch_lines ${index} multi_comment_line) if ("${multi_comment_line}" MATCHES "^\\/\\*") # Start of multi-line comment set(matching_index ${index}) @@ -63,16 +63,16 @@ endfunction() # _sketch_lines - List of code lines read from the converted sketch file. # _insertion_line_index - Index of a code line at which the header should be inserted #=============================================================================# -macro(_insert_platform_header_include_line _sketch_lines _insertion_line_index) +macro(_insert_line _inserted_line _sketch_lines _insertion_line_index) _get_matching_header_insertion_index("${_sketch_lines}" ${_insertion_line_index} header_index) if (${header_index} LESS ${_insertion_line_index}) - set(formatted_include_line ${ARDUINO_CMAKE_PLATFORM_HEADER_INCLUDE_LINE} "\n\n") + set(formatted_include_line ${_inserted_line} "\n\n") elseif (${header_index} EQUAL 0) - set(formatted_include_line ${ARDUINO_CMAKE_PLATFORM_HEADER_INCLUDE_LINE} "\n") + set(formatted_include_line ${_inserted_line} "\n") else () - set(formatted_include_line "\n" ${ARDUINO_CMAKE_PLATFORM_HEADER_INCLUDE_LINE}) + set(formatted_include_line "\n" ${_inserted_line}) if (${header_index} GREATER_EQUAL ${_insertion_line_index}) decrement_integer(header_index 1) @@ -80,7 +80,19 @@ macro(_insert_platform_header_include_line _sketch_lines _insertion_line_index) endif () endif () - list(INSERT refined_sketch ${header_index} ${formatted_include_line}) + list(INSERT converted_source ${header_index} ${formatted_include_line}) + +endmacro() + +macro(_insert_prototypes _prototypes _sketch_lines _insertion_line_index) + + foreach (prototype ${_prototypes}) + # Add semicolon ';' to make it a declaration + escape_semicolon_in_string("${prototype};" formatted_prototype) + + _insert_line("${formatted_prototype}" "${sketch_lines}" ${line_index}) + increment_integer(_insertion_line_index 1) + endforeach () endmacro() @@ -88,38 +100,49 @@ endmacro() # Converts the given sketch file into a valid 'cpp' source file under the project's working dir. # During the conversion process the platform's main header file is inserted to the source file # since it's critical for it to include it - Something that doesn't happen in "Standard" sketches. -# _sketch_file - Full path to the original sketch file (Read from). -# _converted_source_path - Full path to the converted target source file (Written to). +# _sketch_file - Full path to the original sketch file (Read from). +# _converted_source_path - Full path to the converted target source file (Written to). +# _sketch_prototypes - List of prototypes to genereate, i.e. function definitions without a declaration. #=============================================================================# -function(convert_sketch_to_source _sketch_file _converted_source_path) +function(convert_sketch_to_source _sketch_file _converted_source_path _sketch_prototypes) - file(STRINGS "${_sketch_file}" sketch_loc) + file(STRINGS "${_sketch_file}" sketch_lines) + set(function_prototype_pattern + "${ARDUINO_CMAKE_FUNCTION_DECLARATION_REGEX_PATTERN}|${ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN}") set(header_insert_pattern - "${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}|${ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN}") + "${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}|${function_prototype_pattern}") + set(header_inserted FALSE) + set(prototypes_inserted FALSE) - list(LENGTH sketch_loc num_of_loc) - decrement_integer(num_of_loc 1) + list_max_index("${sketch_lines}" lines_count) + #[[list(LENGTH sketch_lines lines_count) + decrement_integer(lines_count 1)]] - foreach (loc_index RANGE 0 ${num_of_loc}) + foreach (line_index RANGE ${lines_count}) - list(GET sketch_loc ${loc_index} loc) + list(GET sketch_lines ${line_index} line) - if (NOT ${header_inserted} AND "${loc}" MATCHES "${header_insert_pattern}") - _insert_platform_header_include_line("${sketch_loc}" ${loc_index}) - set(header_inserted TRUE) + if (NOT ${header_inserted}) + if ("${line}" MATCHES "${header_insert_pattern}") + _insert_line("${ARDUINO_CMAKE_PLATFORM_HEADER_INCLUDE_LINE}" "${sketch_lines}" ${line_index}) + set(header_inserted TRUE) + endif () + elseif (NOT ${prototypes_inserted} AND "${line}" MATCHES "${function_prototype_pattern}") + _insert_prototypes("${_sketch_prototypes}" "${sketch_lines}" ${line_index}) + set(prototypes_inserted TRUE) endif () - if ("${loc}" STREQUAL "") - list(APPEND refined_sketch "\n") + if ("${line}" STREQUAL "") + list(APPEND converted_source "\n") else () - string(REGEX REPLACE "^(.+);(.*)$" "\\1${ARDUINO_CMAKE_SEMICOLON_REPLACEMENT}\\2" refined_loc "${loc}") - list(APPEND refined_sketch "${refined_loc}\n") + escape_semicolon_in_string("${line}" formatted_line) + list(APPEND converted_source "${formatted_line}\n") endif () endforeach () - _write_source_file("${refined_sketch}" "${_converted_source_path}") + _write_source_file("${converted_source}" "${_converted_source_path}") endfunction() diff --git a/cmake/Platform/Utilities/ListUtils.cmake b/cmake/Platform/Utilities/ListUtils.cmake index 0823b37..fe33da8 100644 --- a/cmake/Platform/Utilities/ListUtils.cmake +++ b/cmake/Platform/Utilities/ListUtils.cmake @@ -37,8 +37,8 @@ function(list_max_index _list _return_var) list(LENGTH _list list_length) set(index ${list_length}) - if (${index} GREATER 0) - decrement_integer(${index} 1) + if (${list_length} GREATER 0) + decrement_integer(index 1) endif () set(${_return_var} ${index} PARENT_SCOPE) diff --git a/cmake/Platform/Utilities/StringUtils.cmake b/cmake/Platform/Utilities/StringUtils.cmake index c4b599f..73ced7f 100644 --- a/cmake/Platform/Utilities/StringUtils.cmake +++ b/cmake/Platform/Utilities/StringUtils.cmake @@ -74,7 +74,7 @@ endfunction() #=============================================================================# # Extracts a name symbol without possible file extension (marked usually by a dot ('.'). # _input_string - String containing name symbol and possibly file extension. -# _return_var - Name of a CMake variable that will hold the extraction result. +# _return_var - Name of a CMake variable that will hold the return value. # Returns - String containing input name without possible file extension. #=============================================================================# function(get_name_without_file_extension _input_string _return_var) @@ -89,7 +89,7 @@ endfunction() # Converts a given string to a PascalCase string, converting 1st letter to upper # and remaining to lower. # _input_string - String to convert. -# _return_var - Name of a CMake variable that will hold the extraction result. +# _return_var - Name of a CMake variable that will hold the return value. # Returns - PascalCase converted string. #=============================================================================# function(convert_string_to_pascal_case _input_string _return_var) @@ -108,3 +108,26 @@ function(convert_string_to_pascal_case _input_string _return_var) set(${_return_var} ${combined_string} PARENT_SCOPE) endfunction() + +#=============================================================================# +# Escapes a semicolon in a given string by replacing it with a "magic" string instead, +# which isn't parsed as a list separator by CMake. +# This function can also reverse an escaped semicolon by replacing it back with a semicolon. +# _string - String to escape/re-escape. +# [REVERSE] - Optional flag indicating whether to reverse an already-escaped string back to its original form. +# _return_var - Name of a CMake variable that will hold the return value. +# Returns - Original string if [REVERSE] provided, Semicolon-escaped string otherwise. +#=============================================================================# +function(escape_semicolon_in_string _string _return_var) + + cmake_parse_arguments(parsed_args "REVERSE" "" "" ${ARGN}) + + if (parsed_args_REVERSE) + string(REGEX REPLACE "^(.+)${ARDUINO_CMAKE_SEMICOLON_REPLACEMENT}(.*)$" "\\1;\\2" escaped_line "${_string}") + else () + string(REGEX REPLACE "^(.+);(.*)$" "\\1${ARDUINO_CMAKE_SEMICOLON_REPLACEMENT}\\2" escaped_line "${_string}") + endif () + + set(${_return_var} ${escaped_line} PARENT_SCOPE) + +endfunction() From 02039eb91cad3e18afd1ada764a93f3f58712739 Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Fri, 26 Apr 2019 16:16:40 +0300 Subject: [PATCH 14/23] Completely redesigned sketch-to-source conversion process It now fully supports both platform header & prototypes insertion --- .../Sketches/SketchSourceConverter.cmake | 168 +++++++++--------- cmake/Platform/System/DefaultsManager.cmake | 3 + 2 files changed, 90 insertions(+), 81 deletions(-) diff --git a/cmake/Platform/Sketches/SketchSourceConverter.cmake b/cmake/Platform/Sketches/SketchSourceConverter.cmake index 1d072a0..2e526c9 100644 --- a/cmake/Platform/Sketches/SketchSourceConverter.cmake +++ b/cmake/Platform/Sketches/SketchSourceConverter.cmake @@ -14,92 +14,108 @@ function(_write_source_file _sketch_lines _file_path) endfunction() -#=============================================================================# -# Finds the best line to insert an '#include' of the platform's main header to. -# The function assumes that the initial state of the given 'active index' is set to the line that -# best fitted the insertion, however, it might need a bit more optimization. Why? -# Because above those lines there might be a comment, or a comment block, -# all of which should be taken into account in order to minimize the effect on code's readability. -# _sketch_lines - List of lines-of-code belonging to the sketch. -# _active_index - Index that indicates the best-not-optimized line to insert header to. -# _return_var - Name of variable in parent-scope holding the return value. -# Returns - Best fitted index to insert platform's main header '#include' to. -#=============================================================================# -function(_get_matching_header_insertion_index _sketch_lines _active_index _return_var) +macro(_setup_regex_patterns) + + string(CONCAT function_prototype_pattern + "${ARDUINO_CMAKE_FUNCTION_DECLARATION_REGEX_PATTERN}" + "|${ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN}") + string(CONCAT code_pattern + "${ARDUINO_CMAKE_PREPROCESSOR_REGEX_PATTERN}" + "|${function_prototype_pattern}") + + set(comment_line_pattern "\\/\\/") + set(comment_block_start_pattern "\\/\\*") + set(comment_block_end_pattern "\\*\\/") - if (${_active_index} EQUAL 0) # First line in a file will always result in the 1st index - set(${_return_var} 0 PARENT_SCOPE) - return() +endmacro() + +macro(_insert_platform_header _current_line _line_index) + + if ("${_current_line}" MATCHES "${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}") + set(include_line "${ARDUINO_CMAKE_PLATFORM_HEADER_INCLUDE_LINE}\n") else () - decrement_integer(_active_index 1) + set(include_line "${ARDUINO_CMAKE_PLATFORM_HEADER_INCLUDE_LINE}\n\n") + set(header_inclusion_block FALSE) endif () - list(GET _sketch_lines ${_active_index} previous_loc) + list(INSERT converted_source ${_line_index} "${include_line}") + +endmacro() - if ("${previous_loc}" MATCHES "^//") # Simple one-line comment - set(matching_index ${_active_index}) - elseif ("${previous_loc}" MATCHES "\\*/$") # End of multi-line comment +macro(_handle_platform_header) - foreach (index RANGE ${_active_index} 0) - list(GET _sketch_lines ${index} multi_comment_line) + if ("${line}" MATCHES "${comment_line_pattern}") + set(last_comment_start_index ${line_index}) + set(last_comment_end_index ${line_index}) + elseif ("${line}" MATCHES "${comment_block_start_pattern}") + set(last_comment_start_index ${line_index}) + elseif ("${line}" MATCHES "${comment_block_end_pattern}") + set(last_comment_end_index ${line_index}) + elseif ("${line}" MATCHES "${code_pattern}") - if ("${multi_comment_line}" MATCHES "^\\/\\*") # Start of multi-line comment - set(matching_index ${index}) - break() - endif () - endforeach () + set(header_inclusion_block TRUE) + + # Calculate difference between current line index and last comment's end index + math(EXPR line_index_diff "${line_index} - ${last_comment_end_index}") + + # Comment ends above current line, any lines should be inserted above + if (${line_index_diff} EQUAL 1) + _insert_platform_header("${line}" ${last_comment_start_index}) + else () + _insert_platform_header("${line}" ${line_index}) + endif () + + set(header_inserted TRUE) - else () # Previous line isn't a comment - Return original index - increment_integer(_active_index 1) - set(matching_index ${_active_index}) endif () - set(${_return_var} ${matching_index} PARENT_SCOPE) +endmacro() -endfunction() +macro(_handle_prototype_generation) -#=============================================================================# -# Inline macro which handles the process of inserting a line including the platform header. -# _sketch_lines - List of code lines read from the converted sketch file. -# _insertion_line_index - Index of a code line at which the header should be inserted -#=============================================================================# -macro(_insert_line _inserted_line _sketch_lines _insertion_line_index) + if (NOT "${line}" MATCHES "${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}") + if (NOT "${line}" STREQUAL "") # Not a newline - _get_matching_header_insertion_index("${_sketch_lines}" ${_insertion_line_index} header_index) + if (NOT header_inclusion_block) + # Insert a newline to separate prototypes from the rest of the code + list(INSERT converted_source ${line_index} "\n") + endif () - if (${header_index} LESS ${_insertion_line_index}) - set(formatted_include_line ${_inserted_line} "\n\n") - elseif (${header_index} EQUAL 0) - set(formatted_include_line ${_inserted_line} "\n") - else () - set(formatted_include_line "\n" ${_inserted_line}) + foreach (prototype ${_sketch_prototypes}) + # Add missing semicolon to make a definition a declaration and escape it + escape_semicolon_in_string("${prototype};" escaped_prototype) + list(INSERT converted_source ${line_index} "${escaped_prototype}\n") + endforeach () + + if (header_inclusion_block) + list(INSERT converted_source ${line_index} "\n// Prototypes generated by Arduino-CMake\n") + else () + list(INSERT converted_source ${line_index} "// Prototypes generated by Arduino-CMake\n") + endif () + + set(prototypes_inserted TRUE) + set(header_inclusion_block FALSE) - if (${header_index} GREATER_EQUAL ${_insertion_line_index}) - decrement_integer(header_index 1) - string(APPEND formatted_include_line "\n") endif () endif () - list(INSERT converted_source ${header_index} ${formatted_include_line}) - endmacro() -macro(_insert_prototypes _prototypes _sketch_lines _insertion_line_index) +macro(_handle_simple_lines) - foreach (prototype ${_prototypes}) - # Add semicolon ';' to make it a declaration - escape_semicolon_in_string("${prototype};" formatted_prototype) - - _insert_line("${formatted_prototype}" "${sketch_lines}" ${line_index}) - increment_integer(_insertion_line_index 1) - endforeach () + if ("${line}" STREQUAL "") + list(APPEND converted_source "\n") + else () + escape_semicolon_in_string("${line}" formatted_line) + list(APPEND converted_source "${formatted_line}\n") + endif () endmacro() #=============================================================================# -# Converts the given sketch file into a valid 'cpp' source file under the project's working dir. -# During the conversion process the platform's main header file is inserted to the source file -# since it's critical for it to include it - Something that doesn't happen in "Standard" sketches. +# Converts the given sketch file into a valid '.cpp' source file under the project's working dir. +# During the conversion process the platform's main header file is inserted to the source file, +# as well as any given prototypes, found earlier through a function def-dec matching process. # _sketch_file - Full path to the original sketch file (Read from). # _converted_source_path - Full path to the converted target source file (Written to). # _sketch_prototypes - List of prototypes to genereate, i.e. function definitions without a declaration. @@ -108,38 +124,28 @@ function(convert_sketch_to_source _sketch_file _converted_source_path _sketch_pr file(STRINGS "${_sketch_file}" sketch_lines) - set(function_prototype_pattern - "${ARDUINO_CMAKE_FUNCTION_DECLARATION_REGEX_PATTERN}|${ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN}") - set(header_insert_pattern - "${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}|${function_prototype_pattern}") + _setup_regex_patterns() set(header_inserted FALSE) set(prototypes_inserted FALSE) + set(header_inclusion_block FALSE) + + set(last_comment_start_index 0) + set(last_comment_end_index 0) list_max_index("${sketch_lines}" lines_count) - #[[list(LENGTH sketch_lines lines_count) - decrement_integer(lines_count 1)]] foreach (line_index RANGE ${lines_count}) list(GET sketch_lines ${line_index} line) - if (NOT ${header_inserted}) - if ("${line}" MATCHES "${header_insert_pattern}") - _insert_line("${ARDUINO_CMAKE_PLATFORM_HEADER_INCLUDE_LINE}" "${sketch_lines}" ${line_index}) - set(header_inserted TRUE) - endif () - elseif (NOT ${prototypes_inserted} AND "${line}" MATCHES "${function_prototype_pattern}") - _insert_prototypes("${_sketch_prototypes}" "${sketch_lines}" ${line_index}) - set(prototypes_inserted TRUE) + if (NOT header_inserted) + _handle_platform_header() + elseif (NOT prototypes_inserted) + _handle_prototype_generation() endif () - if ("${line}" STREQUAL "") - list(APPEND converted_source "\n") - else () - escape_semicolon_in_string("${line}" formatted_line) - list(APPEND converted_source "${formatted_line}\n") - endif () + _handle_simple_lines() endforeach () diff --git a/cmake/Platform/System/DefaultsManager.cmake b/cmake/Platform/System/DefaultsManager.cmake index 7cd9f4e..ea1d1ab 100644 --- a/cmake/Platform/System/DefaultsManager.cmake +++ b/cmake/Platform/System/DefaultsManager.cmake @@ -6,6 +6,9 @@ function(set_internal_search_patterns) set(ARDUINO_CMAKE_SEMICOLON_REPLACEMENT "!@&#%" CACHE STRING "String replacement for the semicolon char, required when treating lists as code") + set(ARDUINO_CMAKE_PREPROCESSOR_REGEX_PATTERN "^#([A-Za-z0-9_])+" CACHE STRING + "Regex pattern matching preprocessor directives in source files") + set(ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN "^#include.*[<\"]" CACHE STRING "Regex pattern matching header inclusion in a source file") From d63b448fb3cab480a5975bdade0b282f80183717 Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Fri, 26 Apr 2019 16:21:51 +0300 Subject: [PATCH 15/23] Fixed bug generating only a single prototype in converted source --- cmake/Platform/Sketches/SketchManager.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Platform/Sketches/SketchManager.cmake b/cmake/Platform/Sketches/SketchManager.cmake index 91f6ae4..67c63df 100644 --- a/cmake/Platform/Sketches/SketchManager.cmake +++ b/cmake/Platform/Sketches/SketchManager.cmake @@ -34,7 +34,7 @@ function(add_sketch_to_target _target_name _sketch_file) resolve_sketch_libraries(${_target_name} ${_sketch_file} "${sketch_headers}") resolve_sketch_prototypes(${_sketch_file} "${sketch_headers}" sketch_prototypes) - convert_sketch_to_source(${_sketch_file} ${sketch_converted_source_path} ${sketch_prototypes}) + convert_sketch_to_source(${_sketch_file} ${sketch_converted_source_path} "${sketch_prototypes}") endif () From 777f95e0865224b417209df65ad33f8c18cae6ca Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Fri, 26 Apr 2019 20:46:06 +0300 Subject: [PATCH 16/23] Fixed `resolve_sketch_headers` to actually return headers Fixed small function argument-stripping bug --- cmake/Platform/Sketches/SketchHeadersResolver.cmake | 9 ++++++++- cmake/Platform/Sources/FunctionSignatureStripper.cmake | 10 +++++++--- cmake/Platform/Sources/HeaderRetriever.cmake | 6 +++--- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/cmake/Platform/Sketches/SketchHeadersResolver.cmake b/cmake/Platform/Sketches/SketchHeadersResolver.cmake index 39319e5..d7bd9ce 100644 --- a/cmake/Platform/Sketches/SketchHeadersResolver.cmake +++ b/cmake/Platform/Sketches/SketchHeadersResolver.cmake @@ -8,6 +8,13 @@ function(resolve_sketch_headers _target_name _sketch_file _return_var) get_target_include_directories(${_target_name} target_include_dirs) - get_source_headers("${_sketch_file}" ${target_include_dirs} sketch_headers RECURSIVE) + + get_source_headers("${_sketch_file}" "${target_include_dirs}" sketch_headers RECURSIVE) + get_source_headers("${ARDUINO_CMAKE_PLATFORM_HEADER_PATH}" "${target_include_dirs}" platform_headers RECURSIVE) + + list(APPEND sketch_headers ${platform_headers}) + list(REMOVE_DUPLICATES sketch_headers) + + set(${_return_var} ${sketch_headers} PARENT_SCOPE) endfunction() diff --git a/cmake/Platform/Sources/FunctionSignatureStripper.cmake b/cmake/Platform/Sources/FunctionSignatureStripper.cmake index 84c16d3..0a47f34 100644 --- a/cmake/Platform/Sources/FunctionSignatureStripper.cmake +++ b/cmake/Platform/Sources/FunctionSignatureStripper.cmake @@ -8,13 +8,17 @@ function(_get_function_arguments_types _signature _return_var) string(REGEX MATCH ${ARDUINO_CMAKE_FUNCTION_ARGS_REGEX_PATTERN} function_args_string "${_signature}") string(REGEX MATCHALL ${ARDUINO_CMAKE_FUNCTION_SINGLE_ARG_REGEX_PATTERN} - function_arg_list "${_function_args_string}") - + function_arg_list "${function_args_string}") # Iterate through all arguments to extract only their type foreach (arg ${function_arg_list}) + string(REGEX MATCH ${ARDUINO_CMAKE_FUNCTION_ARG_TYPE_REGEX_PATTERN} arg_type "${arg}") string(STRIP "${arg_type}" arg_type) # Strip remaining whitespaces - list(APPEND function_args ${arg_type}) + + if (NOT "${arg_type}" STREQUAL "void") # Do NOT append 'void' arguments - they're meaningless + list(APPEND function_args ${arg_type}) + endif () + endforeach () set(${_return_var} ${function_args} PARENT_SCOPE) diff --git a/cmake/Platform/Sources/HeaderRetriever.cmake b/cmake/Platform/Sources/HeaderRetriever.cmake index 05a39a9..ee99974 100644 --- a/cmake/Platform/Sources/HeaderRetriever.cmake +++ b/cmake/Platform/Sources/HeaderRetriever.cmake @@ -15,15 +15,15 @@ function(get_header_file _header_we _dir_list _return_var) find_header_files("${include_dir}" include_dir_headers RECURSE) foreach (included_header ${include_dir_headers}) - get_name_without_file_extension(${included_header} included_header_we) + get_name_without_file_extension("${included_header}" included_header_we) if ("${included_header_we}" STREQUAL "${_header_we}") - set(_return_var ${included_header} PARENT_SCOPE) + set(${_return_var} ${included_header} PARENT_SCOPE) return() endif () endforeach () endforeach () - set(_return_var NOTFOUND PARENT_SCOPE) + set(${_return_var} "NOTFOUND" PARENT_SCOPE) endfunction() From 811393411611eb8e30d1425881900de41a7b13fb Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Fri, 26 Apr 2019 22:14:42 +0300 Subject: [PATCH 17/23] Converted all regex from cache variables to global properties --- cmake/Platform/Project/ProjectSetup.cmake | 9 ---- .../Sketches/FunctionPrototypeGenerator.cmake | 4 -- .../Sketches/SketchSourceConverter.cmake | 22 +++++--- .../Sources/FunctionDeclarationMatcher.cmake | 4 +- .../Sources/FunctionSignatureStripper.cmake | 14 +++-- .../Sources/SourceFunctionsRetriever.cmake | 4 +- .../Sources/SourceHeadersRetriever.cmake | 7 ++- cmake/Platform/Sources/SourcesManager.cmake | 9 ++-- cmake/Platform/System/DefaultsManager.cmake | 51 ++++++------------- cmake/Platform/Utilities/StringUtils.cmake | 10 ++-- 10 files changed, 64 insertions(+), 70 deletions(-) delete mode 100644 cmake/Platform/Sketches/FunctionPrototypeGenerator.cmake diff --git a/cmake/Platform/Project/ProjectSetup.cmake b/cmake/Platform/Project/ProjectSetup.cmake index cb9bf35..732a688 100644 --- a/cmake/Platform/Project/ProjectSetup.cmake +++ b/cmake/Platform/Project/ProjectSetup.cmake @@ -11,13 +11,4 @@ function(arduino_cmake_project _project_name) setup_project_core_lib(${_project_name}) - set(ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN - "^([A-Za-z0-9_][ \t\r\n]*)+\\(.*\\)$" PARENT_SCOPE) - set(ARDUINO_CMAKE_FUNCTION_DECLARATION_REGEX_PATTERN - "^([A-Za-z0-9_])+.+([A-Za-z0-9_])+[ \t\r\n]*\\((.*)\\);$" PARENT_SCOPE) - set(ARDUINO_CMAKE_FUNCTION_NAME_REGEX_PATTERN "(([A-Za-z0-9_])+)[ \t\r\n]*\\(.*\\)" PARENT_SCOPE) - set(ARDUINO_CMAKE_FUNCTION_ARGS_REGEX_PATTERN "\\((.*)\\)" PARENT_SCOPE) - set(ARDUINO_CMAKE_FUNCTION_SINGLE_ARG_REGEX_PATTERN "([A-Za-z0-9_]+)[^,]*" PARENT_SCOPE) - set(ARDUINO_CMAKE_FUNCTION_ARG_TYPE_REGEX_PATTERN "[A-Za-z0-9_]+.*[ \t\r\n]+" PARENT_SCOPE) - endfunction() diff --git a/cmake/Platform/Sketches/FunctionPrototypeGenerator.cmake b/cmake/Platform/Sketches/FunctionPrototypeGenerator.cmake deleted file mode 100644 index 813b408..0000000 --- a/cmake/Platform/Sketches/FunctionPrototypeGenerator.cmake +++ /dev/null @@ -1,4 +0,0 @@ -function(generate_function_prototype _function_line _source_lines _declaration_line_index) - - -endfunction() diff --git a/cmake/Platform/Sketches/SketchSourceConverter.cmake b/cmake/Platform/Sketches/SketchSourceConverter.cmake index 2e526c9..e63067b 100644 --- a/cmake/Platform/Sketches/SketchSourceConverter.cmake +++ b/cmake/Platform/Sketches/SketchSourceConverter.cmake @@ -16,12 +16,16 @@ endfunction() macro(_setup_regex_patterns) - string(CONCAT function_prototype_pattern - "${ARDUINO_CMAKE_FUNCTION_DECLARATION_REGEX_PATTERN}" - "|${ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN}") + get_property(function_declaration_regex GLOBAL PROPERTY ARDUINO_CMAKE_FUNCTION_DECLARATION_REGEX_PATTERN) + get_property(function_definition_regex GLOBAL PROPERTY ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN) + get_property(preprocessor_regex GLOBAL PROPERTY ARDUINO_CMAKE_PREPROCESSOR_REGEX_PATTERN) + + string(CONCAT function_prototype_regex + "${function_declaration_regex}" + "|${function_definition_regex}") string(CONCAT code_pattern - "${ARDUINO_CMAKE_PREPROCESSOR_REGEX_PATTERN}" - "|${function_prototype_pattern}") + "${preprocessor_regex}" + "|${function_prototype_regex}") set(comment_line_pattern "\\/\\/") set(comment_block_start_pattern "\\/\\*") @@ -31,7 +35,9 @@ endmacro() macro(_insert_platform_header _current_line _line_index) - if ("${_current_line}" MATCHES "${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}") + get_property(header_include_regex GLOBAL PROPERTY ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN) + + if ("${_current_line}" MATCHES "${header_include_regex}") set(include_line "${ARDUINO_CMAKE_PLATFORM_HEADER_INCLUDE_LINE}\n") else () set(include_line "${ARDUINO_CMAKE_PLATFORM_HEADER_INCLUDE_LINE}\n\n") @@ -73,7 +79,9 @@ endmacro() macro(_handle_prototype_generation) - if (NOT "${line}" MATCHES "${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}") + get_property(header_include_regex GLOBAL PROPERTY ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN) + + if (NOT "${line}" MATCHES "${header_include_regex}") if (NOT "${line}" STREQUAL "") # Not a newline if (NOT header_inclusion_block) diff --git a/cmake/Platform/Sources/FunctionDeclarationMatcher.cmake b/cmake/Platform/Sources/FunctionDeclarationMatcher.cmake index e35d165..0256c3b 100644 --- a/cmake/Platform/Sources/FunctionDeclarationMatcher.cmake +++ b/cmake/Platform/Sources/FunctionDeclarationMatcher.cmake @@ -10,6 +10,8 @@ #=============================================================================# function(match_function_declaration _definition_signature _included_headers _return_var) + get_property(function_declaration_regex GLOBAL PROPERTY ARDUINO_CMAKE_FUNCTION_DECLARATION_REGEX_PATTERN) + # Get function name and list of argument-types strip_function_signature("${_definition_signature}" original_stripped_function) list(GET original_stripped_function 0 original_function_name) @@ -22,7 +24,7 @@ function(match_function_declaration _definition_signature _included_headers _ret foreach (line ${header_lines}) # Search for function declarations - if ("${line}" MATCHES "${ARDUINO_CMAKE_FUNCTION_DECLARATION_REGEX_PATTERN}") + if ("${line}" MATCHES "${function_declaration_regex}") # Get function name and list of argument-types strip_function_signature("${line}" iterated_stripped_function) diff --git a/cmake/Platform/Sources/FunctionSignatureStripper.cmake b/cmake/Platform/Sources/FunctionSignatureStripper.cmake index 0a47f34..4da64cf 100644 --- a/cmake/Platform/Sources/FunctionSignatureStripper.cmake +++ b/cmake/Platform/Sources/FunctionSignatureStripper.cmake @@ -6,13 +6,17 @@ #=============================================================================# function(_get_function_arguments_types _signature _return_var) - string(REGEX MATCH ${ARDUINO_CMAKE_FUNCTION_ARGS_REGEX_PATTERN} function_args_string "${_signature}") - string(REGEX MATCHALL ${ARDUINO_CMAKE_FUNCTION_SINGLE_ARG_REGEX_PATTERN} + get_property(function_args_regex GLOBAL PROPERTY ARDUINO_CMAKE_FUNCTION_ARGS_REGEX_PATTERN) + get_property(function_single_arg_regex GLOBAL PROPERTY ARDUINO_CMAKE_FUNCTION_SINGLE_ARG_REGEX_PATTERN) + get_property(function_arg_type_regex GLOBAL PROPERTY ARDUINO_CMAKE_FUNCTION_ARG_TYPE_REGEX_PATTERN) + + string(REGEX MATCH ${function_args_regex} function_args_string "${_signature}") + string(REGEX MATCHALL ${function_single_arg_regex} function_arg_list "${function_args_string}") # Iterate through all arguments to extract only their type foreach (arg ${function_arg_list}) - string(REGEX MATCH ${ARDUINO_CMAKE_FUNCTION_ARG_TYPE_REGEX_PATTERN} arg_type "${arg}") + string(REGEX MATCH ${function_arg_type_regex} arg_type "${arg}") string(STRIP "${arg_type}" arg_type) # Strip remaining whitespaces if (NOT "${arg_type}" STREQUAL "void") # Do NOT append 'void' arguments - they're meaningless @@ -33,8 +37,10 @@ endfunction() #=============================================================================# function(strip_function_signature _signature _return_var) + get_property(function_name_regex GLOBAL PROPERTY ARDUINO_CMAKE_FUNCTION_NAME_REGEX_PATTERN) + # Strip function's name - string(REGEX MATCH ${ARDUINO_CMAKE_FUNCTION_NAME_REGEX_PATTERN} function_name_match "${_signature}") + string(REGEX MATCH ${function_name_regex} function_name_match "${_signature}") set(function_name ${CMAKE_MATCH_1}) list(APPEND stripped_signature ${function_name}) diff --git a/cmake/Platform/Sources/SourceFunctionsRetriever.cmake b/cmake/Platform/Sources/SourceFunctionsRetriever.cmake index 534a58d..bc1b8d7 100644 --- a/cmake/Platform/Sources/SourceFunctionsRetriever.cmake +++ b/cmake/Platform/Sources/SourceFunctionsRetriever.cmake @@ -1,9 +1,11 @@ function(get_source_function_definitions _source_file _return_var) + get_property(function_definition_regex GLOBAL PROPERTY ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN) + file(STRINGS "${_source_file}" source_lines) foreach (line ${source_lines}) - if ("${line}" MATCHES "${ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN}") + if ("${line}" MATCHES "${function_definition_regex}") list(APPEND definitions "${line}") endif () endforeach () diff --git a/cmake/Platform/Sources/SourceHeadersRetriever.cmake b/cmake/Platform/Sources/SourceHeadersRetriever.cmake index 5a24853..de777ff 100644 --- a/cmake/Platform/Sources/SourceHeadersRetriever.cmake +++ b/cmake/Platform/Sources/SourceHeadersRetriever.cmake @@ -10,14 +10,17 @@ function(_get_source_included_headers _source_file _return_var) cmake_parse_arguments(parsed_args "WE" "" "" ${ARGN}) + get_property(header_include_regex GLOBAL PROPERTY ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN) + get_property(header_name_regex GLOBAL PROPERTY ARDUINO_CMAKE_HEADER_NAME_REGEX_PATTERN) + file(STRINGS "${_source_file}" source_lines) # Loc = Lines of code - list(FILTER source_lines INCLUDE REGEX ${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}) + list(FILTER source_lines INCLUDE REGEX ${header_include_regex}) # Extract header names from inclusion foreach (loc ${source_lines}) - string(REGEX MATCH ${ARDUINO_CMAKE_HEADER_NAME_REGEX_PATTERN} match ${loc}) + string(REGEX MATCH ${header_name_regex} match ${loc}) if (parsed_args_WE) get_name_without_file_extension("${CMAKE_MATCH_1}" header_name) diff --git a/cmake/Platform/Sources/SourcesManager.cmake b/cmake/Platform/Sources/SourcesManager.cmake index 3cc5947..bb55c6b 100644 --- a/cmake/Platform/Sources/SourcesManager.cmake +++ b/cmake/Platform/Sources/SourcesManager.cmake @@ -78,8 +78,9 @@ function(get_source_file_includes _source_file _return_var) endif () file(STRINGS "${_source_file}" source_lines) - - list(FILTER source_lines INCLUDE REGEX "${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}") + + get_property(header_include_regex GLOBAL PROPERTY ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN) + list(FILTER source_lines INCLUDE REGEX "${header_include_regex}") set(${_return_var} ${source_lines} PARENT_SCOPE) @@ -94,8 +95,10 @@ endfunction() #=============================================================================# function(get_headers_parent_directories _sources _return_var) + get_property(header_file_extension_regex GLOBAL PROPERTY ARDUINO_CMAKE_HEADER_FILE_EXTENSION_REGEX_PATTERN) + # Extract header files - list(FILTER _sources INCLUDE REGEX "${ARDUINO_CMAKE_HEADER_FILE_EXTENSION_REGEX_PATTERN}") + list(FILTER _sources INCLUDE REGEX "${header_file_extension_regex}") foreach (header_source ${_sources}) get_filename_component(header_parent_dir ${header_source} DIRECTORY) diff --git a/cmake/Platform/System/DefaultsManager.cmake b/cmake/Platform/System/DefaultsManager.cmake index ea1d1ab..93fcee9 100644 --- a/cmake/Platform/System/DefaultsManager.cmake +++ b/cmake/Platform/System/DefaultsManager.cmake @@ -3,46 +3,25 @@ #=============================================================================# function(set_internal_search_patterns) - set(ARDUINO_CMAKE_SEMICOLON_REPLACEMENT "!@&#%" CACHE STRING - "String replacement for the semicolon char, required when treating lists as code") + set_property(GLOBAL PROPERTY ARDUINO_CMAKE_SEMICOLON_REPLACEMENT "!@&#%") - set(ARDUINO_CMAKE_PREPROCESSOR_REGEX_PATTERN "^#([A-Za-z0-9_])+" CACHE STRING - "Regex pattern matching preprocessor directives in source files") + set_property(GLOBAL PROPERTY ARDUINO_CMAKE_PREPROCESSOR_REGEX_PATTERN "^#([A-Za-z0-9_])+") + set(header_include_regex "^#include.*[<\"]") + set_property(GLOBAL PROPERTY ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN "${header_include_regex}") - set(ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN "^#include.*[<\"]" CACHE STRING - "Regex pattern matching header inclusion in a source file") + set_property(GLOBAL PROPERTY ARDUINO_CMAKE_HEADER_NAME_REGEX_PATTERN "${header_include_regex}(.+)[>\"]$") + set_property(GLOBAL PROPERTY ARDUINO_CMAKE_HEADER_FILE_EXTENSION_REGEX_PATTERN ".+\\.h.*$") + set_property(GLOBAL PROPERTY ARDUINO_CMAKE_NAME_WE_REGEX_PATTERN "([^\\/]+)\\.") - set(ARDUINO_CMAKE_HEADER_NAME_REGEX_PATTERN - "${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}(.+)[>\"]$" CACHE STRING - "Regex pattern matching a header's name when wrapped in inclusion line") + set_property(GLOBAL PROPERTY ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN + "^([A-Za-z0-9_][ \t\r\n]*)+\\(.*\\)$") + set_property(GLOBAL PROPERTY ARDUINO_CMAKE_FUNCTION_DECLARATION_REGEX_PATTERN + "^([A-Za-z0-9_])+.+([A-Za-z0-9_])+[ \t\r\n]*\\((.*)\\);$") - set(ARDUINO_CMAKE_HEADER_FILE_EXTENSION_REGEX_PATTERN ".+\\.h.*$" CACHE STRING - "Regex pattern matching all header file extensions") - - set(ARDUINO_CMAKE_NAME_WE_REGEX_PATTERN "([^\\/]+)\\." CACHE STRING - "Regex pattern matching name without file extension") - - #[[set(ARDUINO_CMAKE_FUNCTION_DECLARATION_REGEX_PATTERN "^([A-Za-z0-9_])+.+([A-Za-z0-9_])+[ \t\r\\n]*\((.*)\);$" - CACHE STRING "Regex pattern matching a function signature definition in a source file") - - set(ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN "^([A-Za-z0-9_])+[ \t\r\n]*\(([A-Za-z0-9_])*\)$" - CACHE STRING "Regex pattern matching a function signature definition in a source file") - - set(ARDUINO_CMAKE_FUNCTION_NAME_REGEX_PATTERN "(([A-Za-z0-9_])+)[ \t\r\\n]*\(.*\)" - CACHE STRING - "Regex pattern matching a function's name (and everything following it), can be retrieved by the 1st group") - - set(ARDUINO_CMAKE_FUNCTION_ARGS_REGEX_PATTERN "\((.*)\)" - CACHE STRING - "Regex pattern matching a function's argument list, i.e. What's inside the parentheses") - - set(ARDUINO_CMAKE_FUNCTION_SINGLE_ARG_REGEX_PATTERN "([A-Za-z0-9_]+)[^,]*" - CACHE STRING - "Regex pattern matching a function's argument, requiring maximum matches to get all arguments") - - set(ARDUINO_CMAKE_FUNCTION_ARG_TYPE_REGEX_PATTERN "[A-Za-z0-9_]+.*[ \t\r\\n]+" - CACHE STRING - "Regex pattern matching a function argument type, ommiting it's name")]] + set_property(GLOBAL PROPERTY ARDUINO_CMAKE_FUNCTION_NAME_REGEX_PATTERN "(([A-Za-z0-9_])+)[ \t\r\n]*\\(.*\\)") + set_property(GLOBAL PROPERTY ARDUINO_CMAKE_FUNCTION_ARGS_REGEX_PATTERN "\\((.*)\\)") + set_property(GLOBAL PROPERTY ARDUINO_CMAKE_FUNCTION_SINGLE_ARG_REGEX_PATTERN "([A-Za-z0-9_]+)[^,]*") + set_property(GLOBAL PROPERTY ARDUINO_CMAKE_FUNCTION_ARG_TYPE_REGEX_PATTERN "[A-Za-z0-9_]+.*[ \t\r\n]+") endfunction() diff --git a/cmake/Platform/Utilities/StringUtils.cmake b/cmake/Platform/Utilities/StringUtils.cmake index 73ced7f..e4a3072 100644 --- a/cmake/Platform/Utilities/StringUtils.cmake +++ b/cmake/Platform/Utilities/StringUtils.cmake @@ -79,7 +79,9 @@ endfunction() #=============================================================================# function(get_name_without_file_extension _input_string _return_var) - string(REGEX MATCH "${ARDUINO_CMAKE_NAME_WE_REGEX_PATTERN}" match "${_input_string}") + get_property(name_we_regex GLOBAL PROPERTY ARDUINO_CMAKE_NAME_WE_REGEX_PATTERN) + + string(REGEX MATCH "${name_we_regex}" match "${_input_string}") set(${_return_var} ${CMAKE_MATCH_1} PARENT_SCOPE) @@ -122,10 +124,12 @@ function(escape_semicolon_in_string _string _return_var) cmake_parse_arguments(parsed_args "REVERSE" "" "" ${ARGN}) + get_property(semicolon_replacement GLOBAL PROPERTY ARDUINO_CMAKE_SEMICOLON_REPLACEMENT) + if (parsed_args_REVERSE) - string(REGEX REPLACE "^(.+)${ARDUINO_CMAKE_SEMICOLON_REPLACEMENT}(.*)$" "\\1;\\2" escaped_line "${_string}") + string(REGEX REPLACE "^(.+)${semicolon_replacement}(.*)$" "\\1;\\2" escaped_line "${_string}") else () - string(REGEX REPLACE "^(.+);(.*)$" "\\1${ARDUINO_CMAKE_SEMICOLON_REPLACEMENT}\\2" escaped_line "${_string}") + string(REGEX REPLACE "^(.+);(.*)$" "\\1${semicolon_replacement}\\2" escaped_line "${_string}") endif () set(${_return_var} ${escaped_line} PARENT_SCOPE) From 77b5642bca712d33b7c508740666bb19631c36ea Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Fri, 26 Apr 2019 22:23:57 +0300 Subject: [PATCH 18/23] Fixed minor bug --- cmake/Platform/Sketches/SketchHeadersResolver.cmake | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmake/Platform/Sketches/SketchHeadersResolver.cmake b/cmake/Platform/Sketches/SketchHeadersResolver.cmake index d7bd9ce..ee89eb1 100644 --- a/cmake/Platform/Sketches/SketchHeadersResolver.cmake +++ b/cmake/Platform/Sketches/SketchHeadersResolver.cmake @@ -13,7 +13,10 @@ function(resolve_sketch_headers _target_name _sketch_file _return_var) get_source_headers("${ARDUINO_CMAKE_PLATFORM_HEADER_PATH}" "${target_include_dirs}" platform_headers RECURSIVE) list(APPEND sketch_headers ${platform_headers}) - list(REMOVE_DUPLICATES sketch_headers) + + if (sketch_headers AND ${sketch_headers}) + list(REMOVE_DUPLICATES sketch_headers) + endif () set(${_return_var} ${sketch_headers} PARENT_SCOPE) From 0e5d73e0fdf49dfe3b3923fe695c3371bbd41114 Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Fri, 26 Apr 2019 22:23:57 +0300 Subject: [PATCH 19/23] Fixed minor bug --- cmake/Platform/Sketches/SketchHeadersResolver.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Platform/Sketches/SketchHeadersResolver.cmake b/cmake/Platform/Sketches/SketchHeadersResolver.cmake index ee89eb1..4edddf4 100644 --- a/cmake/Platform/Sketches/SketchHeadersResolver.cmake +++ b/cmake/Platform/Sketches/SketchHeadersResolver.cmake @@ -14,7 +14,7 @@ function(resolve_sketch_headers _target_name _sketch_file _return_var) list(APPEND sketch_headers ${platform_headers}) - if (sketch_headers AND ${sketch_headers}) + if (sketch_headers) list(REMOVE_DUPLICATES sketch_headers) endif () From 6e060ab4038e2550e45de36fa56c1a36f8906f71 Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Sat, 27 Apr 2019 16:07:10 +0300 Subject: [PATCH 20/23] Updated ignore to ignore CLion + build dir Uncommented examples other than 'sketch' --- .gitignore | 98 ++++++++++++++++++++++++++++++++++++++--- examples/CMakeLists.txt | 6 +-- 2 files changed, 95 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index d4efd4a..d7246b7 100644 --- a/.gitignore +++ b/.gitignore @@ -116,6 +116,93 @@ crashlytics.properties crashlytics-build.properties fabric.properties +# Created by https://www.gitignore.io/api/clion +# Edit at https://www.gitignore.io/?templates=clion + +### CLion ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +# JetBrains templates +**___jb_tmp___ + +### CLion Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/sonarlint + +# End of https://www.gitignore.io/api/clion + ### VisualStudioCode ### .vscode/* !.vscode/tasks.json @@ -129,8 +216,9 @@ fabric.properties ### User-Defined [Aa]ssets/* -/examples/blink-example/Blink.cpp -/examples/servo-knob-example/Knob.cpp -/examples/sketch/sketch1.cpp -/examples/sketch/sketch2.cpp -/docs/wiki +[Bb]uild/ +examples/blink-example/Blink.cpp +examples/servo-knob-example/Knob.cpp +examples/sketch/sketch1.cpp +examples/sketch/sketch2.cpp +docs/wiki diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index fdfd039..4f6216b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.8.2) project(Examples LANGUAGES C CXX ASM) -#[[add_subdirectory(hello-world) +add_subdirectory(hello-world) add_subdirectory(arduino-library) add_subdirectory(platform-library) add_subdirectory(3rd-party-library) @@ -10,6 +10,4 @@ add_subdirectory(header-only-library) add_subdirectory(blink-example) add_subdirectory(servo-knob-example) add_subdirectory(sketch) -add_subdirectory(misc)]] - -add_subdirectory(sketch) +add_subdirectory(misc) From 59f95b3307b61d40c3c114fd3ad2c6cdb581eb3a Mon Sep 17 00:00:00 2001 From: Alexis Jeandet Date: Sun, 5 May 2019 16:41:20 +0200 Subject: [PATCH 21/23] Fix Arduino SDK bin folder search on Linux On Linux CMake might find avr-gcc first inside ccache folder which leads to wrong ar/ranlib detection. On Fedora 30 at least, it leads to link errors because it uses avr-ar/ranlib instead of avr-gcc-ar/ranlib. Signed-off-by: Alexis Jeandet --- cmake/Platform/Other/ArduinoSDKSeeker.cmake | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cmake/Platform/Other/ArduinoSDKSeeker.cmake b/cmake/Platform/Other/ArduinoSDKSeeker.cmake index be65f7a..7ca6cd5 100644 --- a/cmake/Platform/Other/ArduinoSDKSeeker.cmake +++ b/cmake/Platform/Other/ArduinoSDKSeeker.cmake @@ -57,15 +57,16 @@ function(find_arduino_sdk_bin _return_var) set(${_return_var} "${ARDUINO_SDK_PATH}/hardware/tools/avr/bin" PARENT_SCOPE) else () # Some systems like the Arch Linux arduino package install binaries to /usr/bin - find_program(avr_gcc_location avr-gcc) - if ("${avr_gcc_location}" MATCHES "NOTFOUND") + # But gcc can be found first in ccache folder so let's search ar instead + find_program(avr_gcc_ar_location avr-gcc-ar) + if ("${avr_gcc_ar_location}" MATCHES "NOTFOUND") string(CONCAT error_message "Couldn't find Arduino bin path - Is it in a non-standard location?" "\n" "If so, please set the ARDUINO_SDK_BIN_PATH CMake-Variable") message(FATAL_ERROR ${error_message}) else () - get_filename_component(avr_gcc_parent ${avr_gcc_location} DIRECTORY) - set(${_return_var} "${avr_gcc_parent}" PARENT_SCOPE) + get_filename_component(avr_gcc_ar_parent ${avr_gcc_ar_location} DIRECTORY) + set(${_return_var} "${avr_gcc_ar_parent}" PARENT_SCOPE) endif () endif () From 4f20e4fd9a379aa109efdf4791a7a9c519e802df Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Sat, 27 Apr 2019 19:33:13 +0300 Subject: [PATCH 22/23] Fixed function definition regex pattern --- cmake/Platform/System/DefaultsManager.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Platform/System/DefaultsManager.cmake b/cmake/Platform/System/DefaultsManager.cmake index 93fcee9..702b3ad 100644 --- a/cmake/Platform/System/DefaultsManager.cmake +++ b/cmake/Platform/System/DefaultsManager.cmake @@ -14,7 +14,7 @@ function(set_internal_search_patterns) set_property(GLOBAL PROPERTY ARDUINO_CMAKE_NAME_WE_REGEX_PATTERN "([^\\/]+)\\.") set_property(GLOBAL PROPERTY ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN - "^([A-Za-z0-9_][ \t\r\n]*)+\\(.*\\)$") + "^([A-Za-z0-9_][ \t\r\n]*)+\\(.*\\)[ \t\r\n]*[{]*$") set_property(GLOBAL PROPERTY ARDUINO_CMAKE_FUNCTION_DECLARATION_REGEX_PATTERN "^([A-Za-z0-9_])+.+([A-Za-z0-9_])+[ \t\r\n]*\\((.*)\\);$") From 14d1c7bcc238f35033bb44ca3ac65a20ccea6865 Mon Sep 17 00:00:00 2001 From: Timor Gruber Date: Mon, 17 Jun 2019 21:23:42 +0300 Subject: [PATCH 23/23] Fixed cache-related bug in `find_arduino_library` --- cmake/Platform/Libraries/LibrariesFinder.cmake | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cmake/Platform/Libraries/LibrariesFinder.cmake b/cmake/Platform/Libraries/LibrariesFinder.cmake index b9bf4a1..e6bb515 100644 --- a/cmake/Platform/Libraries/LibrariesFinder.cmake +++ b/cmake/Platform/Libraries/LibrariesFinder.cmake @@ -1,4 +1,4 @@ -macro(_cleanup_find_arduino_library) +macro(_clear_find_library_state) unset(library_path CACHE) @@ -18,6 +18,8 @@ endmacro() #=============================================================================# function(find_arduino_library _target_name _library_name) + _clear_find_library_state() + set(argument_options "3RD_PARTY" "HEADER_ONLY" "QUIET") cmake_parse_arguments(parsed_args "${argument_options}" "" "" ${ARGN}) @@ -28,7 +30,7 @@ function(find_arduino_library _target_name _library_name) endif () find_file(library_path - NAMES ${_library_name} + NAMES "${_library_name}" PATHS ${ARDUINO_CMAKE_PLATFORM_LIBRARIES_PATH} ${ARDUINO_SDK_LIBRARIES_PATH} ${ARDUINO_CMAKE_SKETCHBOOK_PATH} ${CMAKE_CURRENT_SOURCE_DIR} ${PROJECT_SOURCE_DIR} PATH_SUFFIXES libraries dependencies @@ -43,7 +45,7 @@ function(find_arduino_library _target_name _library_name) if (NOT library_headers) if (parsed_args_QUIET) - _cleanup_find_arduino_library() + _clear_find_library_state() return() else () message(SEND_ERROR "Couldn't find any header files for the " @@ -57,7 +59,7 @@ function(find_arduino_library _target_name _library_name) if (NOT library_sources) if (parsed_args_QUIET) - _cleanup_find_arduino_library() + _clear_find_library_state() return() else () message(SEND_ERROR "Couldn't find any source files for the " @@ -78,6 +80,6 @@ function(find_arduino_library _target_name _library_name) endif () endif () - _cleanup_find_arduino_library() + _clear_find_library_state() endfunction()