diff --git a/.editorconfig b/.editorconfig
index 94b3b62..40115a9 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -8,7 +8,8 @@ insert_final_newline = true
indent_style = space
indent_size = 4
-# Editor support is limited. Make your you align multiline statements accordingly, should your editor not honour this attribute
+# Editor support is limited. Make you align multi-line statements accordingly,
+# should your editor not honour this attribute
continuation_indent_size = 8
trim_trailing_whitespace = true
diff --git a/.gitignore b/.gitignore
index f34fb75..6a4ea21 100644
--- a/.gitignore
+++ b/.gitignore
@@ -117,4 +117,7 @@ crashlytics-build.properties
fabric.properties
### User-Defined
-[Aa]ssets/*
\ No newline at end of file
+[Aa]ssets/*
+/examples/blink-example/Blink.cpp
+/examples/servo-knob-example/Knob.cpp
+/examples/sketch/sketch.cpp
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000..30aa626
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..38cc1c8
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 183ab61..b9c5bf0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,41 +1,42 @@
-language: c
+language: cpp
os:
- - linux
- - osx
+- linux
+- osx
env:
- matrix:
- - ARDUINO_SDK_VERSION=1.6.13
- - ARDUINO_SDK_VERSION=1.8.5
+- ARDUINO_SDK_VERSION=1.6.13
+- ARDUINO_SDK_VERSION=1.8.6
addons:
apt:
packages:
- - gcc-avr
- - binutils-avr
- - avr-libc
- - avrdude
+ - gcc-avr
+ - binutils-avr
+ - avr-libc
+ - avrdude
+ - cmake
before_install:
- - |
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
- export ARDUINO_SDK_FILE="arduino-$ARDUINO_SDK_VERSION-linux32.tar.xz"
- else
- export ARDUINO_SDK_FILE="arduino-$ARDUINO_SDK_VERSION-macosx.zip"
- fi
- - wget "https://downloads.arduino.cc/$ARDUINO_SDK_FILE" -O "$ARDUINO_SDK_FILE"
- - mkdir arduino-sdk
- - |
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
- tar xf "$ARDUINO_SDK_FILE" -C arduino-sdk --strip-components 1
- export ARDUINO_SDK_PATH="$(pwd)/arduino-sdk"
- else
- unzip "$ARDUINO_SDK_FILE" "Arduino.app/Contents/Java/*" -d arduino-sdk
- export ARDUINO_SDK_PATH="$(pwd)/arduino-sdk/Arduino.app/Contents/Java"
- fi
+- |
+ if [[ $TRAVIS_OS_NAME == linux ]]; then
+ export ARDUINO_SDK_FILE="arduino-$ARDUINO_SDK_VERSION-linux32.tar.xz"
+ else
+ export ARDUINO_SDK_FILE="arduino-$ARDUINO_SDK_VERSION-macosx.zip"
+ brew install cmake
+ fi
+- wget "https://downloads.arduino.cc/$ARDUINO_SDK_FILE" -O "$ARDUINO_SDK_FILE"
+- mkdir arduino-sdk
+- |
+ if [[ $TRAVIS_OS_NAME == linux ]]; then
+ tar xf "$ARDUINO_SDK_FILE" -C arduino-sdk --strip-components 1
+ export ARDUINO_SDK_PATH="$(pwd)/arduino-sdk"
+ else
+ unzip "$ARDUINO_SDK_FILE" "Arduino.app/Contents/Java/*" -d arduino-sdk
+ export ARDUINO_SDK_PATH="$(pwd)/arduino-sdk/Arduino.app/Contents/Java"
+ fi
install:
- - mkdir build
- - rm -rf build/*
- - cd build/
+- mkdir build
+- rm -rf build/*
+- cd build/
script:
- - cmake -D ARDUINO_SDK_PATH="$ARDUINO_SDK_PATH" ..
- - make
+- cmake -D CMAKE_TOOLCHAIN_FILE="../cmake/Arduino-Toolchain.cmake" ..
+- make
after_script:
- - cat CMakeFiles/CMakeOutput.log
+- cat CMakeFiles/CMakeOutput.log
diff --git a/AUTHORS.md b/AUTHORS.md
index 0536151..feec055 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -1,34 +1,10 @@
# Authors
-This files lists all the authors of this project, which helped its growing by adding code, fixing bugs, etc.
+This files lists all the authors of this project that helped it grow by adding code, fixing bugs, etc.
-- mean00 ([mean00](https://github.com/mean00))
-- Ariel ([aog2000a](https://github.com/aog2000a))
-- Konstantin Gredeskoul ([kigster](https://github.com/kigster))
-- Juan José Herrero Barbosa ([Souler](https://github.com/Souler))
-- Bei Chen Liu ([Baycken](https://github.com/Baycken))
-- Marc Plano-Lesay ([Kernald](https://github.com/Kernald))
-- James Goppert ([jgoppert](https://github.com/jgoppert))
-- Matt Tyler ([matt-tyler](https://github.com/matt-tyler))
-- Andrew Stromme ([astromme](https://github.com/astromme))
-- [johnyb](https://github.com/johnyb)
-- [arunh](https://github.com/arunh)
-- Sebastian Herp ([sebastianherp](https://github.com/sebastianherp))
-- Michael Daffin ([james147](https://github.com/james147))
-- Pavel Ilin ([PIlin](https://github.com/PIlin))
-- Igor Mikolic-Torreira ([igormiktor](https://github.com/igormiktor))
-- Claudio Henrique Fortes Felix ([chffelix](https://github.com/chffelix))
-- Alexandre Tuleu ([atuleu](https://github.com/atuleu))
-- [getSurreal](https://github.com/getSurreal)
-- Sebastian Zaffarano ([szaffarano](https://github.com/szaffarano))
-- [cheshirekow](https://github.com/cheshirekow)
-- Logan Engstrom ([meadowstream](https://github.com/meadowstream))
-- Francisco Ramírez ([franramirez688](https://github.com/franramirez688))
-- Brendan Shillingford ([bshillingford](https://github.com/bshillingford))
-- Mike Purvis ([mikepurvis](https://github.com/mikepurvis))
-- Steffen Hanikel ([hanikesn](https://github.com/hanikesn))
-- Mindaugas Vinkelis ([fraillt - Contributor)
-- noseglasses ([noseglasses - Contributor)
-- Tomasz Bogdal ([queezythegreat - Original author of arduino-cmake)
-- Jonas ([JonasProgrammer](https://github.com/JonasProgrammer) - Maintainer)
-- Timor Gruber ([MrPointer](https://github.com/MrPointer) - Maintainer)
\ No newline at end of file
+- Tomasz Bogdal ([queezythegreat - Original author of **Arduino-CMake**)
+- Timor Gruber ([MrPointer](https://github.com/MrPointer) - Author of **Arduino-CMake 3**, Current Maintainer)
+
+There are many other authors who have contributed to the various forks and versions, work which couldn't be done without them.
+
+To all of you - Thank you very much!
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 75af530..ca23b1f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,29 +1,148 @@
# Change Log
-# Version [2.0.1](https://github.com/arduino-cmake/arduino-cmake/compare/v2.0.0...v2.0.1) (Dec 19th 2017)
+## Version 0.5.2
-### Bug fixes
+This version adds case-insensitive support for examples, forgotten in the last version.
+Fixes a bug in Core-Lib target creation on Debian/Ubuntu systems, and adds support for **AppVeyor** CI.
-* fixed `-DARDUINO` define for Arduino SDK versions between 1.0.0 and 1.5.8. This bug caused to included `WProgram.h` instead of `Arduino.h` for aforementioned versions.
+But most importantly - It changes the way users should supply a custom SDK location.
-# Version 2.0.0 (Dec 13th 2017)
+### New Features
-An epic version which integrates too many changes to be listed and recorded since the latest stable version, which was **1.0.0**. It has been released almost 4 years ago!
+* Example name parameter of the **Example API** functions is now case-insensitive
+* Support for **AppVeyor** continuous integration/CI.
-However, here are some of the most noticeable changes in this version:
+### Changes
+
+* Supplying custom **Arduino SDK** path - Should now set an environment variable in the system named `ARDUINO_SDK_PATH`, instead of passing it as a variable to CMake through `-D`
+* Parameter order in the `add_arduino_library_example` function - `_board_id` becomes 2nd
+
+### Bug Fixes
+
+* Potential bug in Debian/Ubuntu systems when creating Core Library targets
+
+## Version 0.5.1
+
+This version fixes some "invisible" bugs from previous versions, along with general design improvements.
+Moreover, there are even some new minor features.
+
+### New Features
+
+* Library name parameter of the `find_arduino_library` function is now case-insensitive due to a new utility feature to convert strings to *PascalCase*
+
+### Changes
+
+* Refactored many modules previously under the `Other` directory to be each under its' relevant directory
+
+### Bug Fixes
+
+* Sketch conversion was only partially avoided - Now the functionality is optimized
+* Arduino libraries couldn't be linked to the target when resolving a sketch's headers
+* Regex search patterns
+
+## Version 0.5
+
+This version refactored the Sketch API entirely to enhance support for missing features from previous versions. It also organized "*globals*" and default options in a single 'Defaults' module.
+
+### New Features
+
+- Headers included in a sketch file are now resolved to provide better insight
+ - Arduino/Platform libraries that are resolved from a sketch's headers are linked to the target
+- Option/Policy to "forcefully" convert a sketch to a source file when adding it to a target, even if the source file already exists (Usually means that sketch has already been converted).
+ By default it's set to **OFF**.
+
+### Changes
+
+* New Sketch API which resembles CMake's target API - Use `target_sketches` as you would use `target_sources`
+* Various inline search patterns and defaults have been moved to the 'DefaultsManager' module
+
+## Version 0.4.1
+
+This version adds minor feature improvements as well as complete sketch support.
+
+### New Features
+
+* Full sketch support in the API
+ * Sketch targets can be created by calling the `add_sketch_target` function
+* Ability to provide a custom main platform header by setting the `USE_CUSTOM_PLATFORM_HEADER` option on
+
+## Version 0.4
+
+This version mostly added support for examples and sketches.
+
+### New Features
+
+* Arduino examples such as **Blink** can now be used by calling the `add_arduino_example` function
+* Arduino library examples, each being part of an Arduino library, can also be used by calling the `add_arduino_library_example` function
+* Arduino Sketches can be converted into source files under the project's source directory.
+ The API to use them seamlessly as using examples is still missing, however.
+* During platform initialization the main header of the platform gets selected.
+ This is useful for sketch conversion, as sketches usually don't include the header in their source files but depend on the **Arduino IDE** to do so instead.
+ The header is selected based on the number of `#include` lines it has - The header with most includes is selected as platform's main header, as it probably includes many other platform headers.
+
+### Changes
+
+* The API of the utility function `list_replace` now resembles CMake's List API.
+ It's also a macro now instead of a function.
+* Improved logic and performance of utility `increment` and `decrement` math functions
+
+## Version 0.3.1
+
+This version includes a **critical** bug fix.
+
+### Bug Fixes
+
+* Wrong Core Library was used for libraries of the same board - As the Core-Lib is board-specific and board-dependent, it shouldn't be different for targets of the same board
+
+## Version 0.3
+
+This version added support for Arduino libraries and platform libraries.
+
+### New Features
+
+* Arduino libraries can be found by calling `find_arduino_library` and then linked to another target by calling `link_arduino_library`
+ * The library search process is architecture-aware, meaning that only sources that match the platform's architecture will be included in the library target
+* Arduino platform libraries can be simply linked to another target by calling `link_platform_library`.
+ There's no special search process for platform libraries as there is for Arduino libraries.
+
+## Version 0.2
+
+This version added support for the **Core Library** - A static library built from the platform's core sources that must be linked to every single target in the Arduino build system, including libraries in the future.
+This library is also the missing piece for getting correct program sizes, which hasn't been the case up until now.
+
+### New Features
+
+* The Core Library is added once per board (As a board has a single associated core) and linked against every created target.
+ This behavior is internal and not up to the control of the user, much like a Kernel.
+
+### Changes
+
+* The entire codebase has been "cleaned", code-wise. It includes:
+ * Separation of Concerns - Everything has its' own function, preferably also a module (CMake file)
+ * Better control flow
+ * Better use of "Modern CMake" recommendations
+
+## Version 0.1.1
+
+This version added support for displaying a program's size upon build completion.
+
+### New Features
+
+* Program size output for every executable target at the end of each successful build.
+ This is done using Arduino's **avr-size** tool.
+ The tool's output is then reformatted to match the format of Arduino IDE.
+
+## Version 0.1
+
+This is the bare metal version of the framework, adding support for the very basic stuff.
+Although basic, there's a lot that had to be done in order to reach a somewhat "stable" version that can be burned to the board and actually work.
+
+### Features
+
+* Creating Arduino "executables" (Hex files that can be burned/uploaded/flashed to the hardware board) by calling `add_arduino_executable`
+* Uploading created executables/targets to a connected hardware board by calling `upload_arduino_target`, passing it the Serial Port (Such as **COM3**) through which the uploading process will be done
+* Analyzing the SDK by parsing all required information from files such as `platform.txt` and `boards.txt`
+ * Parsing the `platform.txt` file is an entirely new concept that hasn't been used until now in all forks of the old Arduino-CMake. In fact, this is what allows the framework to be truly platform-agnostic, as it defines the platform's core behavior
+
+Many more subtle and internal features have been implemented, but they won't be listed here.
-* Code has been completely refactored:
- * Previously the project has consisted from generally 2 files:
- 1. `ArduinoToolchain.cmake`
- 2. `Platform/Arduino.cmake`
- * All functions and scripts in the `Arduino.cmake` file, which took nearly 3,500 lines of code, have been separated into matching script files, located under matching directories.
- * A script-driven approach has been taken, allowing developers to substitute a functionality simply by referencing a different CMake script file.
-* Arduino SDK version 1.5 and higher is supported:
- * Several changes were introduced in the SDK itself causing the previous version to fail building.
-* Custom hardware platforms and architectures can be defined:
- * Though it has already existed in the previous version, this feature was in a form of a function.
- Now it's a script that can either be replaced or use customized parameters.
- * Ability to define architecture is new.
-* Example generation:
- * Users can generate firmware using one of Arduino's built-in examples, such as the classic **Blink**.
- * Support for example *categories* has also been added, complying with Arduino current example-nesting strategy. For example, the **Blink** example is located under the `01.Basic` directory, which is also considered as its category.
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b6d9841..4cbde0f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,29 +1,25 @@
# Contribution #
-Contribution means helping the project get bigger and better, by any manner.
-If this is what your'e truly looking for, than you've come to the right place!
-
## Short Brief ##
### What is this file? ###
-It is a set of guidence rules for developers who'd like to contribute to this repo.
-API changes, versions go forward but sometimes documentation is not, unfortunately.
+It is a set of guidance rules for developers who'd like to contribute to this repo.
+Versions go forward, new features are added, the API can change, but sometimes - Documentation doesn't keep the pace, unfortunately.
To address those issues and allow developers to contribute good, quality code - This file must exist and always be up to date.
### Dear Contributors ###
-First of all, thank you for taking your time even considering contributing to this repo.
-It is extremely improtant to us that you, simple users or continous collaborators,
+First of all, thank you for taking your time even considering contributing to this repo.
+It is extremely important to us that you, ordinary users or continuous collaborators,
contribute to this project in a combined effort to make it greater, stable than ever before.
## Submitting Issues ##
-Requests for new features and bug reports keep the project moving forward.
+New features and bug reports keep the project moving forward and getting better.
+This is partly your duty, the user, to request those features and report the bugs.
### Before you submit an issue ###
-* Please make sure your'e using the latest version of Arduino CMake.
- Currently it's the one in the [master](https://github.com/arduino-cmake/arduino-cmake) branch,
- but this will be updated once a version-release standard will be applied.
-* Search the [issue list](https://github.com/arduino-cmake/arduino-cmake/issues?utf8=%E2%9C%93&q=is%3Aissue)
- (including closed ones) to make sure it hasn't already been reported.
+* Please make sure your'e using the latest version of **Arduino CMake**.
+ Generally it's the one in the [master](https://github.com/arduino-cmake/arduino-cmake) branch, unless said otherwise by any of the maintainers.
+* Go over the existing issues list (including closed ones) to make sure your issue hasn't already been reported.
### Submitting a good issue ###
Issues can be submitted with a very short description, but that would make the life of the developers addressing it very hard, leading to unresolved issues due to lack of information.
@@ -31,36 +27,48 @@ Issues can be submitted with a very short description, but that would make the l
Here is a set of rules you should apply to **every** issue you submit:
* Give the issue a short, clear title that describes the bug or feature request
-* Include your Arduino SDK version
-* Include your Operating System (No need to specify exact Linux version (Ubuntu, Fedora, etc.) - Linux is just enough)
-* Include steps to reproduce the issue
-* If the issue regards a special behavior, maybe related to a specific board - Please tell us all you know about it
- and put some links to external sources if those exist. Not all of the developers are Arduino experts, and in fact there
- are so many types of boards and platforms that there being an "Arduino Expert" isn't even real.
-* Use markdown formatting as appropriate to make the issue and code more readable.
+* Describe the steps to reproduce the issue
+* If the issue regards a special behavior, maybe related to a specific board - Please tell us all you know about it and put some links to external sources if those exist
+* Use Markdown formatting as appropriate to make the issue and code more readable
+
+#### Issue Signature
+
+At last, you should sign your issue with a special signature, following the next format:
+
+```
+OS: [Windows|OSx/MacOS|Linux]
+Distribution (Linux Only): [Fedora|Debian|Ubuntu|CentOS] etc.
+OS Version: [Version]
+Platform: [Arduino|ESP32|Pinoccio] etc.
+Platform SDK Version: [Version]
+```
+
+**Disclaimers:**
+
+* *etc.* means that there multiple other options.
+* SDK versions usually have the form of [major].[minor].[patch], such as 1.8.5.
+* OS Distribution should be mentioned only for Linux-based OSs
## Code Contribution
### Code Style
-Like pretty much every project, ArduinoCMake uses it'ws own coding style which ensures that everybody can easily read and change files without the hassle of reading 3 different indention styles paired 4 ways of brace spacing.
+Like most projects, **Arduino-CMake** uses its own coding style which ensures that everybody can easily read and change files without the hassle of reading 3 different indentation styles paired 4 ways of brace spacing.
-While we believe, that the coding style you are using benefits you, please try and stick to the current style as close at possible. It is far from perfect (and we ourselves don't like every part that has grown from the project's
-past) but it is sufficient to be a common set of rules we can agree on.
-
-For the most basic part, make sure your editor supports `.editorconfig`.
-It will
-take care of the greatest hassle like indention, new lines and linebreaks at the end of a file. As for spacing, naming conventions etc. look at the existing code to get an idea of the style. If you use an `IDEA` based IDE (for example `CLion`), chances are that the auto formatting functionality will take care of things due to the project's `codeStyleSettings.xml` residing in the repository.
+While we believe that the coding style you are using benefits you, please try and stick to the project's accepted style as close as possible.
+For starters, make sure your editor supports `.editorconfig`.
+It will take care of the some of the greatest hassles like indentation, new lines and such.
+As for spacing, naming conventions, etc. - Please look at existing code to get an idea of the style.
+If you use an Jetbrains `IDEA` based IDE (for example `CLion`), chances are that the auto formatting functionality will take care of things due to the project's `codeStyleSettings.xml` residing in the repository.
### Versioning
-While in the past the project barely had a proper versioning scheme, we're now trying to incorporate [semantic versioning](http://semver.org/spec/v2.0.0.html). That benefits both developers and users, as there are clear rules about when to bump versions and which versions can be considered compatible.
-
-This versioning scheme also allows easy integration with Git's classic [Workflow Model](http://nvie.com/posts/a-successful-git-branching-model), which is described next.
+This project follows [semantic versioning](http://semver.org/spec/v2.0.0.html).
+It also allows easy integration with Git's classic [Workflow Model](http://nvie.com/posts/a-successful-git-branching-model), which is described next.
### Project Workflow
This project follows Git's classic [Workflow Model](http://nvie.com/posts/a-successful-git-branching-model), allowing developers to work on multiple features simultaneously without clashing. This model is a bit different than suggested by **GitHub**, intended mostly for offline Git repositories. However, both models can be easily integrated together to form a single model.
-The parts that consist the model are thoroughly described in the following sections.
+The elements of the model are thoroughly described in the following sections.
#### Bug Fixes
Bug fixes can be found in the *stable* release or in a *developed* feature.
@@ -70,44 +78,53 @@ The way we treat them is different, described in the next sections.
##### Release Bugs/Critical Bugs
-Those are the ones with the highest priority to fix. If you encounter such a bug you should immediately submit a new issue. Before you submit, see [Submitting Issues](#Submitting-Issues). If you'd also like to fix the bug yourself, please state that in the issue.
+Those are the ones with the highest priority to fix. If you encounter such a bug you should immediately submit a new issue. Before you submit, please see [Submitting Issues](#Submitting-Issues).
+If you'd like to fix the bug yourself, please **state that** in the issue.
-Fixes to such bugs should be made on a separate branch named `hotfix/B` where `B` is a short description of the bug being solved, separated with a hyphen (`-`) between every word.
+Fixes to such bugs should be made on a separate branch named `hotfix/B` where `B` is a short description of the bug being solved, separated with a hyphen (`-`) between every word.
Do note that even though it should describe the bug, it's just a name, thus it shouldn't be too long.
-For example the name `hotfix/cmake-not-reloading-when-custom-libraries-are-set` is a bad name, because even though it fits the naming standard and describes the bug, it is way too long for a name.
-A better name would be `hotfix/custom-libraries-reloading`.
+For example the name `hotfix/cmake-not-reloading-when-platform-libraries-are-used` is a bad name, because even though it fits the naming standard and describes the bug, it is way too long for a name.
+A better name would be `hotfix/platform-libraries-reloading`.
-According to our [Workflow model](#Project-Workflow), once the hotfix is finished you should:
+According to our [Workflow model](#Project-Workflow), once the hotfix is finished one should:
-* Merge directly to **master**.
- * Add a tag to the *merge-commit* named after the patched version.
- e.g If the current stable version is v2.1.0, the hotfix should make it v2.1.1 (Bump the patch number).
-* Merge directly to **develop**.
-* Use the `--no-ff` flag when merging.
+1. Merge directly to **master**
+ * Add a tag to the *merge-commit* named after the patched version.
+ e.g If the current stable version is v2.1.0, the hotfix should make it v2.1.1 (Bump the patch number).
+2. Merge directly to **develop**
+3. Use the `--no-ff` flag when merging
-However, **GitHub**'s model support *Pull-Request*s instead of simple *merges*, at least for non-Administrator users (Though should apply for them as well). To comply with the steps listed above, 2 PRs should be made: One to the **master** branch and another to the **develop** branch.
+However, **GitHub**'s model support *Pull-Request*s instead of simple *merges*.
+To comply with the steps listed above, 2 PRs should be made: One to the **master** branch and another to the **develop** branch.
Instead, we accept a single PR to the **master** branch, and will manually merge the rest once the hotfix is finished. Converting that to a list would look like this:
-* Pull-Request directly to **master**.
- * Once accepted, the merging administrator will add a tag to the *merge-commit* and bump the patch version (Further described in the previous list).
-* An administrator will merge to **develop** or **current release** (Note on that below).
-* The `--no-ff` flag will be used when merging.
+1. Pull-Request directly to **master**
+ * Once accepted, the merging maintainer will add a tag to the *merge-commit* and bump the patch version (Further described in the previous list).
+2. A maintainer will merge to **develop** or **current release** (Note on that below)
+3. The `--no-ff` flag will be used when merging
-**Note to Administrators/Collaborators:** If an active **release** branch exists when the hotfix is integrated, meaning there's a planned on-going release, the hotfix should be merged directly to the **release** branch instead of the **develop** branch, unless the hotfix fixes a truly critical bug that affects development as well.
+**Note to Maintainers/Collaborators:**
+If an active **release** branch exists when the hotfix is integrated, meaning there's an on-going release, the hotfix should be merged directly to the **release** branch instead of the **develop** branch, unless the hotfix fixes a truly critical bug that affects development as well.
##### Development Bugs
-Those are easier to find and fix since they exist only in **feature** branches, planned for future releases and considered in development. If you encounter such a bug you can submit a new issue, however it is not necessary if you'd like to fix the bug yourself.
+Those are easier to find and fix since they exist only in **feature** branches, planned for future releases and considered in development. However, these still need to be reported by submitting relevant issues, also specifying if your'e attempting to fix them.
-Fixes to such bugs should be made on a separate branch, preferably in a forked version, named after the bug. Once finished, you should PR it to the appropriate **feature** branch. If the **feature** branch has already been merged to **develop**, the merging administrator will take care of merging the branch to develop again.
+Fixes to such bugs should be made on a separate branch, preferably in a forked version, named after the bug. Once finished, you should PR it to the appropriate **feature** branch.
+If the **feature** branch has already been merged to **develop**, the merging maintainer will take care of merging the branch to develop again.
-#### Feature Additions
-To ensure your contribution makes it into the mainline codebase, always check the **develop** branch for the next targeted release. Make sure your contribution is on par with that branch and PR features back into **develop**. This strategy should be the right one for most users. If you want to make further additions to a feature currently under development, you can also PR into the corresponding **feature** branch.
+#### New Features
+To ensure your contribution makes it into the mainline codebase, always check the **develop** branch for the next targeted release.
+Make sure your contribution is on par with that branch and PR features back into **develop**.
+This strategy should be the right one for most users.
+If you want to make further additions to a feature currently under development, you can also PR into the corresponding **feature** branch.
##### Feature Branch Naming
**Feature** branch names should be short and descriptive, each word separated by a single hyphen (`-`).
-e.g A branch named `feature/blacklisting-libraries-to-avoid-automatic-inclusion-when-reloading-cmake` is a bad branch name because it's too long, even though it's very descriptive. A better name would be `feature/library-blacklist` because it's short and generally descriptive. Any further description would be written in commit messages or the final PR to the **develop** branch.
+e.g A branch named `feature/blacklisting-libraries-to-avoid-automatic-inclusion-when-reloading-cmake` is a bad branch name because it's too long, even though it's very descriptive.
+A better name would be `feature/library-blacklist` because it's short and generally descriptive.
+Any further description would be written in commit messages or the final PR to the **develop** branch.
#### Releases
@@ -116,28 +133,32 @@ According to our [Workflow model](#Project-Workflow), every release should start
There are some strict rules we apply to our releases:
-* At any given moment there should be a single release or no release at all. We're not working Agile on this project, thus there's no need for multiple simultaneous releases.
+* At any given moment there should be a single release **or** no release at all.
+ We're not working Agile on this project, thus there's no need for multiple simultaneous releases.
* Once existing, any hotfix should be merged to the **release** branch instead of the **develop** branch (See [Release Bugs](#Release-Bugs/Critical-Bugs)).
-* Any last-minute bug-fixes should be made directly on the **release** branch. They will be merged later to the **develop** branch once the release is completed.
-* New features developed after the release has been started are intended for the next release.
-* Before completing the release the `CHANGELOG.md` file should be updated accordingly.
+* Any last-minute bug-fixes should be made directly on the **release** branch.
+ They will be merged later to the **develop** branch once the release is completed.
+* New features developed after the release has been started are intended for the **next** release.
+* Before completing the release, the `CHANGELOG.md` file should be updated accordingly.
Once the release is complete it is merged to the **master** branch and to the **develop** branch.
A tag with the final release version is also added to the *merge-commit* on **master**.
### Pull Requests
-As this is GitHub, we support merging by Pull-Requesting. It helps us document code better, as well as discussing and reviewing a change before it gets into the mainline codebase.
-So please - Make a Pull Request for every change you'd like to make, yes, even if your'e an administrator or a collaborator.
+At GitHub we support merging by Pull-Requesting.
+It helps us document code better, as well as discussing and reviewing a change before it gets into the mainline codebase.
+Please make a Pull Request for every change you'd like to make, yes, even if your'e an maintainer or a collaborator.
-Also note that we do have a strict rule about the branch your'e PRing from - Once it gets merged, it will be deleted. This is done to avoid unnecessary cluttering of the project. If you need to keep the branch for some reason, please state it in **bold** in the PR's description, so that the merging user will notice it.
+Also note that we do have a strict rule about the branch your'e PRing from - Once it gets merged, it will be deleted. This is done to avoid unnecessary cluttering of the project.
+If you need to keep the branch for some reason, please state it in **bold** in the PR's description, so that the merging user will notice it.
### Breaking Changes
Breaking changes require the release of a new major version according to *semver* rules.
-So if you are going to make changes to the **public** interface that are not backwards-compatible, make sure it is **absolutely** necessary.
+If your'e making changes to the **public** interface (API) that are not backwards-compatible, make sure it is **absolutely** necessary.
### Changelog
-From v2.0.0 on, we are going to take note of changes in a proper `CHANGELOG.md`.
-For any contribution, please add a corresponding changelog entry.
-Bump the patch version for bug fixes and the minor version for feature additions.
-Don't **ever** bump the major version on your behaf - It should be done only by the owners of the project.
+All project changes, new features and bug fixes are documented in `CHANGELOG.md`.
+For any contribution, please add a corresponding changelog entry.
+Bump the patch version for bug fixes and the minor version for feature additions.
+Don't **ever** bump the major version on your behalf - It should be done only by the maintainers of the project.
diff --git a/README.md b/README.md
index 0a33b6f..ab60f6a 100644
--- a/README.md
+++ b/README.md
@@ -1,62 +1,99 @@
-# Arduino-CMake
+# Arduino-CMake NG
-[](https://travis-ci.org/arduino-cmake/arduino-cmake) [](https://ci.appveyor.com/project/arduino-cmake/arduino-cmake) [](https://github.com/arduino-cmake/arduino-cmake/releases)
+[](https://ci.appveyor.com/project/arduino-cmake-ng/arduino-cmake-ng)
-**Arduino-CMake** is a cmake-based *toolchain* which allows developers to build/compile and upload Arduino programs using any tool which supports cmake.
-In other words, developers no longer need to use the **Arduino IDE** in order to write Arduino code, but instead can use their favorite IDEs or text editors!
+**Arduino-CMake** is a framework which allows developers to write Arduino-based programs using any tool that supports cmake. *Arduino-based*? There are many other frameworks out there built upon Arduino's base, such as ESP32, and **we support that**.
+In other words, developers can use their favorite IDEs or text editors on their favorite OS to develop Arduino programs!
+
+Wait - Hasn't it been possible all this time? Apparently not, as you'll find out by reading further.
## Motivation
-The **Arduino IDE** lacks many features that are expected from a modern IDE or even a text editor.
-However, it's the de-facto for developing Arduino programs.
+Everyone has their favorite IDE or text editor, and would like to continue using it as long as they can.
+Upon encountering a framework that doesn't support it - We get frustrated.
+Unfortunately that's often the case with the Arduino framework, as it offers a custom toolchain that makes it uncomfortable to use outside the dedicated **Arduino IDE**.
+
+**Arduino-CMake** solves it by creating a framework leveraging all of Arduino's features, including its' custom toolchain, by adding a single dependency - The **CMake** build system.
+
+### Project Roots
+
+The original project started back in 2011 by [queezythegreat](https://github.com/queezythegreat) and had been actively developed until 2014, when it had been abandoned due to unknown reasons.
+Since then more than 150 (!) forks have emerged, leading to a "chaos" in the Arduino-CMake sphere.
+The most important moment however was in 2017, when a combined effort by [JonasProgrammer](https://github.com/JonasProgrammer) and [MrPointer](https://github.com/MrPointer) has brought new life to the project in the face of the [arduino-cmake organization](https://github.com/arduino-cmake).
+And yet, it still had its own problems, leading once again to an abandoned state.
+
+Then, in 2018, an extreme effort has been made and the project has been completely rewritten (mostly by [MrPointer](https://github.com/MrPointer)) with a few very clear goals in mind:
-With **Arduino-CMake**, it doesn't have to be this way.
+- **Platform-Independent** - The framework shouldn't assume it works only with the basic Arduino platform, as there are many others out there. Any platform that confront to the design of the basic Arduino SDK is appropriate for use. An example of such a platform is ESP32.
+- **Modern CMake** - All previous projects/forks have been using the fairly old CMake 2.8. CMake itself has transitioned much from version 2 to 3, benefiting from a whole lot of new exciting features. Even the official package managers support CMake 3 versions, so there's no excuse to not use it.
+- **Modern Arduino SDK** - The Arduino SDK, much like CMake, has also undergone several major changes during the years, especially with version 1.6. As this version came out as early as 2016, we consider it's perfectly valid to require users to refer to that version as our minimum requirement.
-Arduino programs are built using `avr-gcc` - A derivative of the **gcc** compiler which makes it perfect for `make` files and thus **cmake**. Once built, it can be uploaded to a serial port over which the Arduino board is connected using `avr-dude`.
-This is what allows **Arduino-CMake** to work out-of-the-box on *every* OS, in *every* IDE.
+### How it works
-### Why is this a fork?
+Arduino programs are simply C/C++ programs which take advantage of a framework which allows them to run on specific hardware devices. It means that those programs need to be compiled somehow.
+Back in the "old days" developers used compilers such as **gcc** directly from the command line. Then came build-tools such as **make**. Then came **CMake**.
+Most of the modern build systems today are managed by CMake and most of the modern IDEs know that and take advantage of it.
+But what's really useful in CMake, at least regarding our Arduino world, is the ability to cross-compile with a toolchain.
+The Arduino SDK, which one usually downloads together with the Arduino IDE, is actually also a toolchain, as it includes the required compilation & linkage tools for cross-compiling.
+Analyzing the SDK allows us to build a framework using this toolchain, and also all of Arduino's other cool features such as *libraries, examples*, etc.
-The original project has started back in 2011 by [queezythegreat](https://github.com/queezythegreat), and had been actively developed until 2014. Since then the project has been somewhat "dead" for 3 years, with various forks spreading over GitHub. Then, in 2017, a combined effort by [JonasProgrammer](https://github.com/JonasProgrammer) and [MrPointer](https://github.com/MrPointer) has brought new life to the project in the face of the [arduino-cmake organization](https://github.com/arduino-cmake). Since then, many great contributions has been made to the project, leading it to where it is today.
+### What is NG?
+
+NG stands for "New Generation".
+Inferred from the written above, it can easily be understood why the project has this name.
+However, if you don't think this name is good enough or it confuses you - Feel free to propose a name of your own, we're open for offers :)
## Features
-**Arduino-CMake** can do anything that the **Arduino IDE** can, *besides*:
+**Arduino-CMake** should do anything that the **Arduino IDE** can!
+Why should? Because currently it's still WIP, meaning there are still some missing features.
+Here's a list of features **already supported** by **Arduino-CMake**:
+
+* Creating Arduino "Executables"/Programs
+* Uploading programs to hardware boards
+* Linking/Using Arduino libraries to programs
+ * Linking/Using custom libraries to programs
+* Creating Arduino example programs
+ * Creating Arduino library example programs
+* Attaching Arduino sketches to programs
+
+Moreover, **Arduino-CMake** allows some things that **Arduino IDE** *doesn't*:
+
+- Developing Arduino programs in any IDE or text editor
+- Completely customizing the build process per user's requirements
-* Supporting "big" platforms other than Arduino, such as **ESP**.
+It also worth mentioning that **Arduino-CMake** is **entirely cross platform**.
-However, it allows some things that **Arduino IDE** doesn't:
+## Requirements
-* Developing Arduino code in any IDE or text editor
-* Completely customizing the build process
+The following list is the basic requirements of the framework in order to use it:
-Additionally, it's worth mentioning that **Arduino-CMake** is entirely cross platform.
+* Windows, OS X or Linux (BSD support is currently unknown, use at your own risk)
+* CMake Version 3.8 or Higher
+* Arduino-Based SDK compatible with Arduino SDK Version 1.6 or Higher
-## Code Example
+## Usage
A very basic example of how **Arduino-CMake** can be used is listed below:
```cmake
-cmake_minimum_required(VERSION 2.8)
-# Include Arduino-CMake Toolchain
-set(CMAKE_TOOLCHAIN_FILE [ARDUINO_CMAKE_PATH]/ArduinoToolchain.cmake)
-#====================================================================#
-# Setup Project #
-#====================================================================#
-project(MyProject C CXX ASM)
-
-#====================================================================#
-# Create Arduino's Executable
-#====================================================================#
-generate_arduino_firmware(${CMAKE_PROJECT_NAME}
- SRCS main.cpp
- BOARD uno
- PORT /dev/ttyACM0)
+# Define CMake's minimum version (must-do) and the project's name and supported languages
+cmake_minimum_required(VERSION 3.8)
+project(Hello_World LANGUAGES C CXX ASM)
+
+# Call a framework utility function, passing it information about the hardware board that will
+# be used - This function returns a structure known only to the framework
+get_board_id(board_id nano atmega328)
+
+# Create an executable suitable for the Arduino firmware using CMake-style target-creation
+add_arduino_executable(Hello_World ${board_id} helloWorld.cpp)
+# Upload the created target through a connected Serial Port (Where your board is connected to)
+upload_arduino_target(Hello_World "${board_id}" COM3)
```
-This is **cmake** code inside the `CMakeLists.txt` file of the `MyProject` project.
+You should then call **CMake** (either through cmd, cmake-gui or an IDE if it supports that) passing it the argument `-DCMAKE_TOOLCHAIN_FILE=[project_path]/cmake/Arduino-Toolchain.cmake` where `[project_path]` is substituted by the project's full path. This is what allows cmake to use our framework.
-Very simple, yet super extensible.
+That's it! It's super simple, yet super extensible :)
## Installation
diff --git a/appveyor.yml b/appveyor.yml
index 7704707..99a4074 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,23 +1,48 @@
version: '{build}'
image: Visual Studio 2017
environment:
+ MINGW_PATH: C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin
matrix:
- - ARDUINO_SDK_VERSION: 1.6.13
- - ARDUINO_SDK_VERSION: 1.8.5
+ # - ARDUINO_SDK_VERSION: 1.6.13
+ - ARDUINO_SDK_VERSION: 1.8.6
install:
- - ps: choco install make unzip
- - ps: $env:ARDUINO_SDK_FILE = "arduino-$env:ARDUINO_SDK_VERSION-windows.zip"
- - ps: $env:ARDUINO_SDK_URI = "https://downloads.arduino.cc/$env:ARDUINO_SDK_FILE"
- - ps: wget "$env:ARDUINO_SDK_URI" -O "$env:ARDUINO_SDK_FILE"
- - ps: unzip "$env:ARDUINO_SDK_FILE" -d "arduino-sdk"
- - ps: $env:ARDUINO_SDK_PATH = "$pwd\arduino-sdk\arduino-$env:ARDUINO_SDK_VERSION"
- # FIXME: Windows path separators (\) need to be changed to "/" for cmake to properly handle it
- - ps: $env:ARDUINO_SDK_PATH = ($env:ARDUINO_SDK_PATH -replace "\\","/")
+- ps: cinst unzip
+- ps: $env:ARDUINO_SDK_FILE = "arduino-$env:ARDUINO_SDK_VERSION-windows.zip"
+- ps: $env:ARDUINO_SDK_URI = "https://downloads.arduino.cc/$env:ARDUINO_SDK_FILE"
+- ps: wget "$env:ARDUINO_SDK_URI" -O "$env:ARDUINO_SDK_FILE"
+- ps: unzip "$env:ARDUINO_SDK_FILE" -d "arduino-sdk"
+- ps: $env:ARDUINO_SDK_PATH = "$pwd\arduino-sdk\arduino-$env:ARDUINO_SDK_VERSION"
+- ps: $env:ARDUINO_SDK_PATH = ($env:ARDUINO_SDK_PATH -replace "\\","/")
+before_build:
+- ps: Copy-Item -Path $env:MINGW_PATH\mingw32-make.exe -Destination $env:MINGW_PATH\make.exe
build_script:
- - ps: mkdir build
- - ps: cd build
- - ps: echo "$env:ARDUINO_SDK_PATH"
- - ps: cmake -G "Unix Makefiles" -D ARDUINO_SDK_PATH="$env:ARDUINO_SDK_PATH" ..
- - cmd: make
-on_finish:
- - ps: cat CMakeFiles/CMakeOutput.log
+# Add the MinGW Path to the system PATH temporarily for this session
+- ps: $env:Path += ";$env:MINGW_PATH"
+- ps: mkdir build
+- ps: cd build
+- ps: echo "$env:ARDUINO_SDK_PATH"
+- ps: >-
+ cmake -G "MinGW Makefiles"
+ -D CMAKE_TOOLCHAIN_FILE="..\cmake\Arduino-Toolchain.cmake"
+ -D CMAKE_SH="CMAKE_SH-NOTFOUND"
+ --no-warn-unused-cli
+ ..\examples
+- ps: |
+ make.exe 2>&1 3>&1
+ if ($LastExitCode -eq 0) { $host.SetShouldExit(0) }
+artifacts:
+- path: cmake
+ name: CMake-Framework
+ type: zip
+deploy:
+- provider: GitHub
+ description: 'ToDo'
+ artifact: CMake-Framework
+ auth_token:
+ secure: rjEnIYWjd3X0jhsAbVKgIOJNpjPY0dBJvvHD3wNB+PbR/F7FvlWlsiwaiQ4EmLBV
+ draft: true
+ on:
+ branch: master
+ appveyor_repo_tag: true
+on_failure:
+- ps: cat CMakeFiles/CMakeOutput.log
diff --git a/cmake/Arduino-Toolchain.cmake b/cmake/Arduino-Toolchain.cmake
new file mode 100644
index 0000000..728026c
--- /dev/null
+++ b/cmake/Arduino-Toolchain.cmake
@@ -0,0 +1,80 @@
+include(${CMAKE_CURRENT_LIST_DIR}/Platform/Other/FindArduinoSDK.cmake)
+
+function(_find_required_programs)
+
+ # Find ASM compiler
+ find_program(CMAKE_ASM_COMPILER avr-gcc
+ PATHS ${ARDUINO_SDK_BIN_PATH}
+ NO_DEFAULT_PATH
+ NO_CMAKE_FIND_ROOT_PATH)
+ # Find C compiler
+ find_program(CMAKE_C_COMPILER avr-gcc
+ PATHS ${ARDUINO_SDK_BIN_PATH}
+ NO_DEFAULT_PATH
+ NO_CMAKE_FIND_ROOT_PATH)
+ # Find C++ compiler
+ find_program(CMAKE_CXX_COMPILER avr-g++
+ PATHS ${ARDUINO_SDK_BIN_PATH}
+ NO_DEFAULT_PATH
+ NO_CMAKE_FIND_ROOT_PATH)
+ # Find AR required for linkage
+ find_program(CMAKE_AR avr-gcc-ar
+ PATHS ${ARDUINO_SDK_BIN_PATH}
+ NO_DEFAULT_PATH
+ NO_CMAKE_FIND_ROOT_PATH)
+ # Find Ranlib required for linkage
+ find_program(CMAKE_RANLIB avr-gcc-ranlib
+ PATHS ${ARDUINO_SDK_BIN_PATH}
+ NO_DEFAULT_PATH
+ NO_CMAKE_FIND_ROOT_PATH)
+ # Find NM
+ find_program(CMAKE_NM avr-gcc-nm
+ PATHS ${ARDUINO_SDK_BIN_PATH}
+ NO_DEFAULT_PATH
+ NO_CMAKE_FIND_ROOT_PATH)
+
+endfunction()
+
+function(_setup_sdk_internal_paths)
+
+ set(ARDUINO_SDK_BIN_PATH "${ARDUINO_SDK_PATH}/hardware/tools/avr/bin" CACHE PATH
+ "Path to Arduino SDK's binaries folder")
+ set(ARDUINO_SDK_ROOT_PATH "${ARDUINO_SDK_PATH}/hardware/tools/avr" CACHE PATH
+ "Path to Arduino SDK's sys-root folder")
+ set(ARDUINO_SDK_LIBRARIES_PATH "${ARDUINO_SDK_PATH}/libraries" CACHE PATH
+ "Path to SDK's libraries directory")
+ set(ARDUINO_SDK_EXAMPLES_PATH "${ARDUINO_SDK_PATH}/examples" CACHE PATH
+ "Path to SDK's examples directory")
+
+endfunction()
+
+set(CMAKE_SYSTEM_NAME Arduino)
+
+# Add current directory to CMake Module path automatically
+if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/Platform/Arduino.cmake)
+ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_LIST_DIR})
+endif ()
+
+set(ARDUINO_CMAKE_TOOLCHAIN_DIR ${CMAKE_CURRENT_LIST_DIR} CACHE PATH
+ "Path to Arduino-CMake's toolchain directory")
+
+if (DEFINED ENV{ARDUINO_SDK_PATH})
+ string(REPLACE "\\" "/" unix_style_sdk_path $ENV{ARDUINO_SDK_PATH})
+ set(ARDUINO_SDK_PATH "${unix_style_sdk_path}" CACHE PATH "Arduino SDK Path")
+else ()
+ # Set default path if none is set
+ find_arduino_sdk(arduino_sdk_path)
+ set(ARDUINO_SDK_PATH "${arduino_sdk_path}" CACHE PATH "Arduino SDK Path")
+endif ()
+
+_setup_sdk_internal_paths()
+_find_required_programs()
+
+# where is the target environment
+set(CMAKE_FIND_ROOT_PATH "${ARDUINO_SDK_ROOT_PATH}")
+
+# search for programs in the build host directories
+SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+# for libraries and headers in the target directories
+SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
diff --git a/cmake/Platform/Arduino.cmake b/cmake/Platform/Arduino.cmake
new file mode 100644
index 0000000..4e77841
--- /dev/null
+++ b/cmake/Platform/Arduino.cmake
@@ -0,0 +1,34 @@
+cmake_minimum_required(VERSION 3.8)
+
+list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/Utilities)
+list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/System)
+list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/Other)
+list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/Properties)
+list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/Sketches)
+list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/Sources)
+list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/Targets)
+
+include(MathUtils)
+include(ListUtils)
+include(StringUtils)
+include(PropertyUtils)
+include(PlatformLibraryUtils)
+
+include(BoardManager)
+include(RecipeParser)
+include(TargetFlagsManager)
+include(SourcesManager)
+include(SketchManager)
+include(DefaultsManager)
+
+include(BuildSystemInitializer)
+
+include(ExecutableTarget)
+include(UploadTarget)
+include(CoreLibTarget)
+include(ArduinoCMakeLibraryTarget)
+include(ArduinoLibraryTarget)
+include(PlatformLibraryTarget)
+include(ArduinoExampleTarget)
+
+initialize_build_system()
diff --git a/cmake/Platform/Other/BoardManager.cmake b/cmake/Platform/Other/BoardManager.cmake
new file mode 100644
index 0000000..f9ecec0
--- /dev/null
+++ b/cmake/Platform/Other/BoardManager.cmake
@@ -0,0 +1,112 @@
+#=============================================================================#
+# Creates a board ID from the given board name and optionally cpu, effectively creating an usable ID.
+# If board has multiple CPUs, and the cpu argument isn't provided or incorrect,
+# fatal error will be invoked.
+#
+# _return_var - Board ID constructed from board's name and CPU.
+# _board_name - name of the board, eg.: nano, uno, etc...
+# _board_cpu - explicit cpu of the board if there are multiple versions of the board.
+# Returns - Board ID in the form of 'Board_Name.Board_CPU'.
+#
+#=============================================================================#
+function(get_board_id _return_var _board_name)
+
+ set(extra_args ${ARGN})
+ list(LENGTH extra_args num_of_extra_args)
+ if (${num_of_extra_args} GREATER 0)
+ list(GET extra_args 0 _board_cpu)
+ endif ()
+
+ list(FIND ARDUINO_CMAKE_BOARDS ${_board_name} board_name_index)
+ if (${board_name_index} LESS 0) # Negative value = not found in list
+ message(FATAL_ERROR "Unknown given board name, not defined in 'boards.txt'. Check your\
+ spelling.")
+ else () # Board is valid and has been found
+ if (DEFINED ${_board_name}_cpu_list) # Board cpu is to be expected
+ if (NOT _board_cpu)
+ message(FATAL_ERROR "Expected board CPU to be provided for the ${_board_name} board")
+ else ()
+ list(FIND ${_board_name}_cpu_list ${_board_cpu} board_cpu_index)
+ if (${board_cpu_index} LESS 0)
+ message(FATAL_ERROR "Unknown given board cpu")
+ endif ()
+ set(board_id "${_board_name}.${_board_cpu}")
+ set(${_return_var} "${board_id}" PARENT_SCOPE)
+ endif ()
+ else () # Board without explicit CPU
+ set(${_return_var} ${_board_name} PARENT_SCOPE)
+ endif ()
+ endif ()
+
+endfunction()
+
+#=============================================================================#
+# Gets the given board property from the given board, identified by a board ID.
+# Properties are name-value pairs that were parsed earlier during platform initialization.
+# If a property isn't found a fatal error is invoked.
+#
+# _board_id - Board ID asociated with the property.
+# _property - Name of the property to get its' value, eg.: bootloader.high_fuses
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - Value of the retrieved property.
+#
+#=============================================================================#
+function(get_board_property _board_id _property _return_var)
+
+ string(REPLACE "." ";" board_id "${_board_id}")
+ string(REPLACE "." "_" property "${_property}")
+
+ # Get the length of the board to determine whether board CPU is to be expected
+ list(LENGTH board_id num_of_board_elements)
+ list(GET board_id 0 board_name) # Get the board name which is mandatory
+
+ if (DEFINED ${board_name}_${property})
+ set(retrieved_property ${${board_name}_${property}})
+ elseif (${num_of_board_elements} EQUAL 1) # Only board name is supplied
+ message(WARNING "Property ${_property} couldn't be found on board ${_board_id}")
+ else ()
+ list(GET board_id 1 board_cpu)
+ if (NOT DEFINED ${board_name}_menu_cpu_${board_cpu}_${property})
+ message(WARNING "Property ${_property} couldn't be found on board ${_board_id}")
+ else ()
+ set(retrieved_property ${${board_name}_menu_cpu_${board_cpu}_${property}})
+ endif ()
+ endif ()
+
+ set(${_return_var} ${retrieved_property} PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Same as 'get_board_property' except it fails gracefully by returning an empty string
+# if a property isn't found, instead of invoking a fatal error.
+#
+# _board_id - Board ID asociated with the property.
+# _property - Name of the property to get its' value, eg.: bootloader.high_fuses
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - Value of the retrieved property.
+#
+#=============================================================================#
+function(try_get_board_property _board_id _property _return_var)
+
+ string(REPLACE "." ";" board_id "${_board_id}")
+ string(REPLACE "." "_" property "${_property}")
+
+ # Get the length of the board to determine whether board CPU is to be expected
+ list(LENGTH board_id num_of_board_elements)
+ list(GET board_id 0 board_name) # Get the board name which is mandatory
+
+ if (DEFINED ${board_name}_${property})
+ set(${_return_var} ${${board_name}_${property}} PARENT_SCOPE)
+ elseif (${num_of_board_elements} EQUAL 1) # Only board name is supplied
+ return()
+ else ()
+ list(GET board_id 1 board_cpu)
+ if (NOT DEFINED ${board_name}_menu_cpu_${board_cpu}_${property})
+ return()
+ else ()
+ set(${_return_var} ${${board_name}_menu_cpu_${board_cpu}_${property}} PARENT_SCOPE)
+ endif ()
+ endif ()
+
+endfunction()
diff --git a/cmake/Platform/Other/FindArduinoSDK.cmake b/cmake/Platform/Other/FindArduinoSDK.cmake
new file mode 100644
index 0000000..ef0b347
--- /dev/null
+++ b/cmake/Platform/Other/FindArduinoSDK.cmake
@@ -0,0 +1,34 @@
+include(${CMAKE_CURRENT_LIST_DIR}/../System/LinuxDistDetector.cmake)
+
+function(find_arduino_sdk _return_var)
+
+ if (${CMAKE_HOST_UNIX})
+ if (${CMAKE_HOST_APPLE})
+ set(platform_search_paths ~/Applications /Applications /Developer/Applications
+ /sw /opt/local)
+ else () # Probably Linux
+ file(GLOB platform_search_paths /usr/share/arduino* /opt/local/arduino* /opt/arduino*
+ /usr/local/share/arduino*)
+ detect_host_linux_distribution()
+ endif ()
+ elseif (${CMAKE_HOST_WIN32})
+ set(platform_search_paths "C:/Program Files (x86)/Arduino" "C:/Program Files/Arduino")
+ endif ()
+
+ find_program(arduino_program_path
+ NAMES arduino
+ HINTS ${platform_search_paths}
+ NO_DEFAULT_PATH
+ NO_CMAKE_FIND_ROOT_PATH)
+ get_filename_component(sdk_path "${arduino_program_path}" DIRECTORY)
+
+ if (NOT sdk_path OR "${sdk_path}" MATCHES "NOTFOUND")
+ string(CONCAT error_message
+ "Couldn't find Arduino SDK path - Is it in a non-standard location?" "\n"
+ "If so, please set the ARDUINO_SDK_PATH CMake-Variable")
+ message(FATAL_ERROR ${error_message})
+ else ()
+ set(${_return_var} "${sdk_path}" PARENT_SCOPE)
+ endif ()
+
+endfunction()
diff --git a/cmake/Platform/Other/FirmwareSizeCalculator.cmake b/cmake/Platform/Other/FirmwareSizeCalculator.cmake
new file mode 100644
index 0000000..dc76e9f
--- /dev/null
+++ b/cmake/Platform/Other/FirmwareSizeCalculator.cmake
@@ -0,0 +1,118 @@
+cmake_minimum_required(VERSION 3.8)
+
+function(parse_list_entry _list _entry_pattern _entry_index _parsed_variables_prefix)
+
+ set(temp_list "${_list}")
+ list(FILTER temp_list INCLUDE REGEX "${_entry_pattern}")
+ list(GET temp_list ${_entry_index} entry_to_parse)
+
+ if ("${entry_to_parse}" MATCHES "([^:]+):[ \t]*([0-9]+)[ \t]*([^ \t]+)[ \t]*[(]([0-9.]+)%.*")
+ set(${_parsed_variables_prefix}_name ${CMAKE_MATCH_1} PARENT_SCOPE)
+ set(${_parsed_variables_prefix}_size ${CMAKE_MATCH_2} PARENT_SCOPE)
+ set(${_parsed_variables_prefix}_size_type ${CMAKE_MATCH_3} PARENT_SCOPE)
+ set(${_parsed_variables_prefix}_percent ${CMAKE_MATCH_4} PARENT_SCOPE)
+ endif ()
+
+endfunction()
+
+function(format_output_message _message_prefix _sections _inner_sections _message_suffix
+ _return_var)
+
+ set(options USE_CUSTOM_CHARACTERS)
+ set(multi_args CUSTOM_CHARACTERS CUSTOM_CHAR_INDICES)
+ cmake_parse_arguments(format_args "${options}" "" "${multi_args}" ${ARGN})
+
+ if (format_args_USE_CUSTOM_CHARACTERS)
+ if (NOT format_args_CUSTOM_CHARACTERS OR NOT format_args_CUSTOM_CHAR_INDICES)
+ set(valid_custom_chars FALSE)
+ string(CONCAT message_str "If custom characters are to be used"
+ "," "they must also be provided" "," "along with their indices")
+ message(WARNING "${message_str}")
+ else ()
+ set(valid_custom_chars TRUE)
+ endif ()
+ endif ()
+
+ set(message "${_message_prefix}")
+
+ # Exclude "name" inner-section as it's treated differently
+ list(FILTER _inner_sections EXCLUDE REGEX "name")
+ # Decrement all custom chars' indices if they should be used since the "name" has been removed
+ if (valid_custom_chars)
+ set(new_custom_char_indices "")
+ foreach (char ${format_args_CUSTOM_CHAR_INDICES})
+ math(EXPR char "${char}-1")
+ list(APPEND new_custom_char_indices ${char})
+ endforeach ()
+ set(format_args_CUSTOM_CHAR_INDICES "${new_custom_char_indices}")
+ endif ()
+
+ foreach (section ${_sections})
+ set(index 0)
+ string(APPEND message "[${${section}_name}: ")
+ foreach (inner_section ${_inner_sections})
+ if (valid_custom_chars AND ${index} IN_LIST format_args_CUSTOM_CHAR_INDICES)
+ string(APPEND message "${${section}_${inner_section}}")
+ string(APPEND message "${format_args_CUSTOM_CHARACTERS} ")
+ else ()
+ string(APPEND message "${${section}_${inner_section}} ")
+ endif ()
+ math(EXPR index "${index}+1")
+ endforeach ()
+ string(APPEND message "] ")
+ endforeach ()
+
+ string(APPEND message "${_message_suffix}")
+
+ set(${_return_var} "${message}" PARENT_SCOPE)
+
+endfunction()
+
+function(_get_image_type_parsing_index _image_type _return_var)
+
+ string(TOLOWER "${_image_type}" image_type)
+
+ if ("${image_type}" MATCHES "firmware")
+ set(parsing_index 0)
+ elseif ("${image_type}" MATCHES "eeprom")
+ set(parsing_index 1)
+ elseif ("${image_type}" MATCHES "flash")
+ set(parsing_index 2)
+ endif ()
+
+ set(${_return_var} ${parsing_index} PARENT_SCOPE)
+
+endfunction()
+
+function(format_image_size _original_size_list _image_type _return_var)
+
+ _get_image_type_parsing_index("${_image_type}" image_index)
+
+ parse_list_entry("${_original_size_list}" "Program:" ${image_index} program_entry)
+ parse_list_entry("${_original_size_list}" "Data:" ${image_index} data_entry)
+
+ set(sections "program_entry" "data_entry")
+ format_output_message("${_image_type} Size: " "${sections}" "${inner_sections}" "on ${MCU}"
+ formatted_message USE_CUSTOM_CHARACTERS CUSTOM_CHARACTERS "%" CUSTOM_CHAR_INDICES 3)
+
+ set(${_return_var} "${formatted_message}" PARENT_SCOPE)
+
+endfunction()
+
+set(avrsize_flags -C --mcu=${MCU})
+execute_process(COMMAND ${AVRSIZE_PROGRAM} ${avrsize_flags} ${FIRMWARE_IMAGE} ${EEPROM_IMAGE}
+ OUTPUT_VARIABLE firmware_size)
+
+# Convert lines into a list
+string(REPLACE "\n" ";" firmware_size_as_list "${firmware_size}")
+list(FILTER firmware_size_as_list INCLUDE REGEX ".+")
+
+set(inner_sections name size size_type percent)
+
+# Process Firmware size
+format_image_size("${firmware_size_as_list}" Firmware firmware_formatted_message)
+# Process EEPROM size
+format_image_size("${firmware_size_as_list}" EEPROM eeprom_formatted_message)
+
+message("${firmware_formatted_message}")
+message("${eeprom_formatted_message}\n")
diff --git a/cmake/Platform/Other/RecipeParser.cmake b/cmake/Platform/Other/RecipeParser.cmake
new file mode 100644
index 0000000..0cbc1cf
--- /dev/null
+++ b/cmake/Platform/Other/RecipeParser.cmake
@@ -0,0 +1,93 @@
+include(RecipePropertyValueResolver)
+
+function(_determine_compiler_language _language _return_var)
+
+ if (NOT _language) # Use default language
+ set(language cpp)
+ else ()
+ # Convert language to expected recipe format
+ get_arduino_compliant_language_name(${_language} language)
+ endif ()
+
+ set(${_return_var} "${language}" PARENT_SCOPE)
+
+endfunction()
+
+function(parse_compiler_recipe_flags _board_id _return_var)
+
+ set(single_args "LANGUAGE")
+ cmake_parse_arguments(recipe_flags "" "${single_args}" "" ${ARGN})
+
+ _determine_compiler_language("${recipe_flags_LANGUAGE}" recipe_language)
+
+ set(original_list "${recipe_${recipe_language}_o_pattern}")
+ set(final_recipe "")
+
+ # Filter unwanted patterns from the recipe, so that only wanted ones will be parsed
+ list(FILTER original_list INCLUDE REGEX "(^[^\"].*[^\"]$)")
+ list(FILTER original_list EXCLUDE REGEX "-o")
+
+ foreach (recipe_element ${original_list})
+ _resolve_recipe_property("${recipe_element}" "${_board_id}" resolved_element)
+ if (NOT "${resolved_element}" STREQUAL "") # Unresolved element, don't append
+ list(APPEND final_recipe "${resolved_element}")
+ endif ()
+ endforeach ()
+
+ set(${_return_var} "${final_recipe} " PARENT_SCOPE)
+
+endfunction()
+
+function(parse_linker_recpie_pattern _board_id _return_var)
+
+ set(original_list "${recipe_c_combine_pattern}")
+ set(final_recipe "")
+
+ # Filter unwanted patterns from the recipe, so that only wanted ones will be parsed
+ list(FILTER original_list INCLUDE REGEX "(^[^\"].*[^\"]$)")
+ list(FILTER original_list EXCLUDE REGEX "-[ol]")
+
+ foreach (recipe_element ${original_list})
+ _resolve_recipe_property("${recipe_element}" "${_board_id}" resolved_element)
+ if (NOT "${resolved_element}" STREQUAL "") # Unresolved element, don't append
+ list(APPEND final_recipe "${resolved_element}")
+ endif ()
+ endforeach ()
+
+ set(${_return_var} "${final_recipe} " PARENT_SCOPE)
+
+endfunction()
+
+function(parse_upload_recipe_pattern _board_id _port _return_var)
+
+ set(original_list "${tools_avrdude_upload_pattern}")
+ set(final_recipe "")
+
+ list(FILTER original_list EXCLUDE REGEX ":|cmd")
+
+ # Upload recipe contains many elements which aren't named correctly
+ # Setting a local variable here will keep it in the resolving function's scope
+ # In other words, it makes the variable resolvable
+ # So if a special elment is met, its' expected variable is locally set with correct value
+ foreach (recipe_element ${original_list})
+ if ("${recipe_element}" MATCHES "config.path")
+ set(config_path "${ARDUINO_CMAKE_AVRDUDE_CONFIG_PATH}")
+ elseif ("${recipe_element}" MATCHES "upload.verbose")
+ set(upload_verbose "${tools_avrdude_upload_params_verbose}")
+ elseif ("${recipe_element}" MATCHES "upload.verify")
+ set(upload_verify "${tools_avrdude_upload_verify}")
+ elseif ("${recipe_element}" MATCHES "protocol")
+ set(protocol "${${_board_id}_upload_protocol}")
+ elseif ("${recipe_element}" MATCHES "serial.port")
+ set(serial_port "${_port}")
+ endif ()
+
+ _resolve_recipe_property("${recipe_element}" "${_board_id}" resolved_element)
+ if (NOT "${resolved_element}" STREQUAL "")
+ list(APPEND final_recipe "${resolved_element}")
+ endif ()
+ endforeach ()
+
+ set(${_return_var} "${final_recipe}" PARENT_SCOPE)
+
+endfunction()
diff --git a/cmake/Platform/Other/TargetFlagsManager.cmake b/cmake/Platform/Other/TargetFlagsManager.cmake
new file mode 100644
index 0000000..0181d8e
--- /dev/null
+++ b/cmake/Platform/Other/TargetFlagsManager.cmake
@@ -0,0 +1,83 @@
+#=============================================================================#
+# Sets compiler flags on the given target, according also to the given board ID.
+# _target_name - Name of the target (Executable or Library) to set flags on.
+# _board_id - Target's bounded board ID.
+#=============================================================================#
+function(set_compiler_target_flags _target_name _board_id)
+
+ set(option_args PRIVATE PUBLIC INTERFACE)
+ set(single_args LANGUAGE)
+ cmake_parse_arguments(compiler "${option_args}" "${single_args}" "" ${ARGN})
+
+ if (compiler_LANGUAGE)
+ if (compiler_PRIVATE)
+ set(scope PRIVATE)
+ elseif (compiler_INTERFACE)
+ set(scope INTERFACE)
+ else ()
+ set(scope PUBLIC)
+ endif ()
+ parse_compiler_recipe_flags("${_board_id}" compiler_recipe_flags
+ LANGUAGE "${compiler_LANGUAGE}")
+ target_compile_options(${_target_name} ${scope}
+ $<$:${compiler_recipe_flags}>)
+ else ()
+ parse_compiler_recipe_flags("${_board_id}" compiler_recipe_flags)
+ target_compile_options(${_target_name} PUBLIC ${compiler_recipe_flags})
+ endif ()
+
+endfunction()
+
+#=============================================================================#
+# Sets linker flags on the given target, according also to the given board ID.
+# _target_name - Name of the target (Executable or Library) to set flags on.
+# _board_id - Target's bounded board ID.
+#=============================================================================#
+function(set_linker_flags _target_name _board_id)
+
+ parse_linker_recpie_pattern("${_board_id}" linker_recipe_flags)
+ string(REPLACE ";" " " cmake_compliant_linker_flags "${linker_recipe_flags}")
+ set(CMAKE_EXE_LINKER_FLAGS "${cmake_compliant_linker_flags}" CACHE STRING "" FORCE)
+
+endfunction()
+
+#=============================================================================#
+# Sets compiler and linker flags on the given Executable target,
+# according also to the given board ID.
+# _target_name - Name of the target (Executable) to set flags on.
+# _board_id - Target's bounded board ID.
+#=============================================================================#
+function(set_executable_target_flags _target_name _board_id)
+
+ set_compiler_target_flags(${_target_name} "${_board_id}")
+ set_linker_flags(${_target_name} "${_board_id}")
+
+ target_link_libraries(${_target_name} PUBLIC m) # Add math library
+
+ # Modify executable's suffix to be '.elf'
+ set_target_properties("${_target_name}" PROPERTIES SUFFIX ".elf")
+
+endfunction()
+
+#=============================================================================#
+# Sets upload/flash flags on the given target, according also to the given board ID.
+# _target_name - Name of the target (Executable) to set flags on.
+# _board_id - Target's bounded board ID.
+#=============================================================================#
+function(set_upload_target_flags _target_name _board_id _upload_port _return_var)
+
+ set(upload_flags "")
+
+ # Parse and append recipe flags
+ parse_upload_recipe_pattern("${_board_id}" "${_upload_port}" upload_recipe_flags)
+ list(APPEND upload_flags "${upload_recipe_flags}")
+
+ set(target_binary_base_path "${CMAKE_CURRENT_BINARY_DIR}/${_target_name}")
+
+ list(APPEND upload_flags "-Uflash:w:\"${target_binary_base_path}.hex\":i")
+ list(APPEND upload_flags "-Ueeprom:w:\"${target_binary_base_path}.eep\":i")
+
+ set(${_return_var} "${upload_flags}" PARENT_SCOPE)
+
+endfunction()
+
diff --git a/cmake/Platform/Properties/BoardPropertiesReader.cmake b/cmake/Platform/Properties/BoardPropertiesReader.cmake
new file mode 100644
index 0000000..35e115b
--- /dev/null
+++ b/cmake/Platform/Properties/BoardPropertiesReader.cmake
@@ -0,0 +1,75 @@
+#=============================================================================#
+# Gets valid board names from the given list of properties, which should be the properties read
+# from the boards properties file.
+# As the boards' names may contain spaces, their property name is returned instead of the value.
+# That way, it's easier to treat them later as Cache variables.
+# _properties - List of properties that contains boards names.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - List of valid board names found in the given property-list.
+#=============================================================================#
+function(_get_boards_names _properties _return_var)
+
+ list(FILTER _properties INCLUDE REGEX "name")
+
+ set(__board_list)
+ foreach (name_property ${_properties})
+ string(REGEX MATCH "[^.]+" board_name "${name_property}")
+ list(APPEND __board_list "${board_name}")
+ endforeach ()
+ list(REMOVE_DUPLICATES __board_list) # Remove possible duplicates
+
+ set(ARDUINO_CMAKE_BOARDS ${__board_list} CACHE STRING "List of platform boards")
+
+ set(${_return_var} ${__board_list} PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Finds CPUs of each existing board that defines explciit ones.
+# It means that boards such as 'nano' that define both the 'atmega168' and the 'atmega328' CPUs
+# will define an appropriate Cache variable that stores the list of those CPUs for the given board.
+# _properties - List of properties that should be read from the boards properties file.
+# _boards - List of existing boards' names, found earlier with '_get_boards_names'
+#=============================================================================#
+function(_find_boards_cpus _properties _boards)
+
+ list(FILTER _properties INCLUDE REGEX "^.+\\.menu\\.cpu\\.[^.]+=")
+ foreach (cpu_property ${_properties})
+ string(REGEX MATCH "^[^.]+" board_name "${cpu_property}")
+
+ string(REGEX MATCH "[^.]+=" cpu_entry "${cpu_property}")
+ string(LENGTH ${cpu_entry} cpu_entry_length)
+ decrement_integer(cpu_entry_length 1)
+ string(SUBSTRING ${cpu_entry} 0 ${cpu_entry_length} cpu)
+
+ if (DEFINED __${board_name}_cpu_list)
+ list(APPEND __${board_name}_cpu_list ${cpu})
+ else ()
+ set(__${board_name}_cpu_list ${cpu})
+ endif ()
+ endforeach ()
+
+ foreach (board ${_boards})
+ if (DEFINED __${board}_cpu_list)
+ set(${board}_cpu_list ${__${board}_cpu_list} CACHE STRING "")
+ endif ()
+ endforeach ()
+
+endfunction()
+
+#=============================================================================#
+# Property-reader function designed exclusively for the boards properties file.
+# It's different since there are some processes which must be done in order to completely initialize
+# the boards' properties.
+# _boards_properties_file - Full path to the boards properties file,
+# usually located under the platform directory.
+#=============================================================================#
+function(read_boards_properties _boards_properties_file)
+
+ file(STRINGS ${_boards_properties_file} properties)
+ read_properties("${properties}")
+
+ _get_boards_names("${properties}" board_list)
+ _find_boards_cpus("${properties}" "${board_list}")
+
+endfunction()
diff --git a/cmake/Platform/Properties/PropertiesReader.cmake b/cmake/Platform/Properties/PropertiesReader.cmake
new file mode 100644
index 0000000..6e1766d
--- /dev/null
+++ b/cmake/Platform/Properties/PropertiesReader.cmake
@@ -0,0 +1,28 @@
+function(read_properties _properties_list)
+
+ list(FILTER _properties_list INCLUDE REGEX "^[^#]+=.*")
+
+ foreach (property ${_properties_list})
+ _get_property_name(${property} property_name)
+ if ("${property_name}" MATCHES "name") # Property contains 'name' string
+ continue() # Don't process further - Unnecessary information
+ endif ()
+
+ _get_property_value(${property} property_value)
+ # Create a list if values are separated by spaces
+ string(REPLACE " " ";" property_value "${property_value}")
+ _resolve_value("${property_value}" resolved_property_value)
+
+ string(REPLACE "." "_" property_cache_name ${property_name})
+ set(${property_cache_name} ${resolved_property_value} CACHE STRING "")
+
+ endforeach ()
+
+endfunction()
+
+function(read_properties_from_file _properties_file_path)
+
+ file(STRINGS ${_properties_file_path} properties)
+ read_properties("${properties}")
+
+endfunction()
diff --git a/cmake/Platform/Properties/PropertyValueResolver.cmake b/cmake/Platform/Properties/PropertyValueResolver.cmake
new file mode 100644
index 0000000..c012a4b
--- /dev/null
+++ b/cmake/Platform/Properties/PropertyValueResolver.cmake
@@ -0,0 +1,101 @@
+#=============================================================================#
+# Resolves the given value by trying to find a variable with the same name.
+# The variable can be a Cache variable or a board property.
+# The original, given value is then replaced with the resolved one.
+# _value - Value to resolve, enclosed in curly-brackets ('{}')
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - Resolved value if one is found, nothing otherwise.
+#=============================================================================#
+function(_resolve_single_value _value _return_var)
+
+ set(extra_args ${ARGN})
+
+ string(REGEX REPLACE "^{(.+)}$" "\\1" value "${_value}") # Get only the value
+ string(REPLACE "." "_" value_as_var "${value}")
+ if (DEFINED ${value_as_var}) # Value is a variable (Probably cache)
+ set(${_return_var} "${${value_as_var}}" PARENT_SCOPE)
+ else ()
+ # Get extra arguments
+ list(LENGTH extra_args num_of_extra_args)
+ if (${num_of_extra_args} EQUAL 0) # No extra arguments
+ return() # Link simply not found, it's probably desired
+ elseif (${num_of_extra_args} EQUAL 1)
+ list(GET extra_args 0 board_id)
+ endif ()
+
+ # Maybe value is a board property?
+ try_get_board_property("${board_id}" "${value}" value_as_board_property)
+ if (NOT "${value_as_board_property}" STREQUAL "") # Value is indeed a board property
+ set(${_return_var} ${value_as_board_property} PARENT_SCOPE)
+ endif ()
+ endif ()
+
+endfunction()
+
+#=============================================================================#
+# Resolves the given value by trying to find a variable with the same name for each 'inner-value'.
+# _value - Value to resolve as a list of 'inner-values', enclosed in curly-brackets ('{}')
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - Resolved list of values. If nothing is resolved, simply the original list.
+#=============================================================================#
+function(_resolve_list_value _value _return_var)
+
+ set(index 0)
+ set(temp_list "${_value}")
+
+ foreach (value_entry ${_value})
+ set(index_inc 1) # Always reset incrementation to 1
+ if ("${value_entry}" MATCHES "^{.+}$") # Wrapped with brackets - resolvable
+ _resolve_single_value(${value_entry} resolved_entry "${ARGN}")
+ if (DEFINED resolved_entry) # Entry has been resolved
+ if ("${resolved_entry}" STREQUAL "") # Resolved entry is an empty string
+ list(REMOVE_AT temp_list ${index}) # Remove the entry completely
+ decrement_integer(index 1)
+ else ()
+ # Replace old value with new resolved value
+ list_replace(temp_list ${index} "${resolved_entry}")
+ # Also enlrage the index incrementation if resolved entry is a list
+ list(LENGTH resolved_entry num_of_inner_resolved_entries)
+ if (${num_of_inner_resolved_entries} GREATER 1)
+ set(index_inc ${num_of_inner_resolved_entries})
+ endif ()
+ endif ()
+ endif ()
+ endif ()
+ increment_integer(index ${index_inc})
+ endforeach ()
+
+ set(${_return_var} "${temp_list}" PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Resolves the given value by trying to find a variable with the same name.
+# The value can be a single value or a list value, and is resolved accordingly.
+# _value - Value to resolve.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - Resolved value if one is found, original value otherwise.
+#=============================================================================#
+function(_resolve_value _value _return_var)
+
+ # Don't resolve empty values - There's nothing to resolve
+ if ("${_value}" STREQUAL "")
+ set(${_return_var} "" PARENT_SCOPE)
+ return()
+ endif ()
+
+ # Treat value as if it were a list and get its length to know if it's actually a list or not
+ list(LENGTH _value value_list_length)
+ if (${value_list_length} GREATER 1)
+ _resolve_list_value("${_value}" resolved_var "${ARGN}")
+ else ()
+ if (NOT "${_value}" MATCHES "^{.+}$") # No wrapping brackets, shouldn't be resolved
+ set(resolved_var "${_value}")
+ else ()
+ _resolve_single_value("${_value}" resolved_var "${ARGN}")
+ endif ()
+ endif ()
+
+ set(${_return_var} "${resolved_var}" PARENT_SCOPE)
+
+endfunction()
diff --git a/cmake/Platform/Properties/RecipePropertyValueResolver.cmake b/cmake/Platform/Properties/RecipePropertyValueResolver.cmake
new file mode 100644
index 0000000..8ba1344
--- /dev/null
+++ b/cmake/Platform/Properties/RecipePropertyValueResolver.cmake
@@ -0,0 +1,53 @@
+function(_get_recipe_property_name _property _return_var)
+
+ string(REGEX MATCH "^[^{]+" property_name "${_property}")
+ set(${_return_var} "${property_name}" PARENT_SCOPE)
+
+endfunction()
+
+function(_get_recipe_property_value _property _return_var)
+
+ string(STRIP "${_property}" stripped_property)
+ string(REGEX MATCH "{.+}$" property_value "${stripped_property}")
+ set(${_return_var} "${property_value}" PARENT_SCOPE)
+
+endfunction()
+
+function(_resolve_recipe_property _property _board_id _return_var)
+
+ string(REGEX MATCH "=" normal_property "${_property}")
+ if ("${normal_property}" STREQUAL "") # Recipe property, doesn't have '='
+ if ("${_property}" MATCHES "^\".+\"$") # Property enclosed with qutoes
+ string(REPLACE "\"" "" _property "${_property}") # Omit quotes for now
+ set(quoted_property TRUE)
+ endif ()
+ _get_recipe_property_name("${_property}" property_name)
+ _get_recipe_property_value("${_property}" property_value)
+
+ # If property has no value and can't be resolved, it probably has been already resolved
+ if ("${property_value}" STREQUAL "" AND "${property_name}" STREQUAL "${_property}")
+ set(resolved_property_value 0)
+ set(resolved_property "${_property}")
+ else ()
+ _resolve_value("${property_value}" resolved_property_value "${_board_id}")
+ if (quoted_property)
+ set(resolved_property "\"${property_name}${resolved_property_value}\"")
+ else ()
+ set(resolved_property "${property_name}${resolved_property_value}")
+ endif ()
+ endif ()
+ else ()
+ _get_property_name("${_property}" property_name)
+ _get_property_value("${_property}" property_value)
+ _resolve_value("${property_value}" resolved_property_value "${_board_id}")
+ set(resolved_property "${property_name}=${resolved_property_value}")
+ endif ()
+
+ # If value couldn't been resolved, return empty string
+ if ("${resolved_property_value}" STREQUAL "")
+ set(${_return_var} "" PARENT_SCOPE)
+ else ()
+ set(${_return_var} "${resolved_property}" PARENT_SCOPE)
+ endif ()
+
+endfunction()
diff --git a/cmake/Platform/Sketches/SketchHeadersManager.cmake b/cmake/Platform/Sketches/SketchHeadersManager.cmake
new file mode 100644
index 0000000..cb26509
--- /dev/null
+++ b/cmake/Platform/Sketches/SketchHeadersManager.cmake
@@ -0,0 +1,60 @@
+#=============================================================================#
+# Validates a header file is included by the given target.
+# i.e The header is located under one of the target's include directories.
+# _target_name - Name of the target to add the sketch file to.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - True if header is included by the target, false otherwise.
+#=============================================================================#
+function(_validate_target_includes_header _target_name _header _return_var)
+
+ get_target_property(target_include_dirs ${_target_name} INCLUDE_DIRECTORIES)
+ foreach (include_dir ${target_include_dirs})
+ find_header_files("${include_dir}" include_dir_headers)
+ if (${_header} IN_LIST include_dir_headers) # Header is included in the target
+ set(${_return_var} True)
+ return()
+ endif ()
+ endforeach ()
+
+ set(${_return_var} False)
+
+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.
+# _board_id - ID of the board to bind to the target (Each target can have a single board).
+# _sketch_file - Path to a sketch file to add to the target.
+#=============================================================================#
+function(resolve_sketch_headers _target_name _board_id _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)
+
+ is_platform_library(${header_we} is_header_platform_lib)
+ if (is_header_platform_lib)
+ string(TOLOWER ${header_we} header_we_lower)
+ link_platform_library(${_target_name} ${header_we_lower} ${_board_id})
+ else ()
+ find_arduino_library(${header_we}_sketch_lib ${header_we} ${_board_id})
+ # If library isn't found, display a wraning since it might be a user library
+ if (NOT TARGET ${header_we}_sketch_lib OR "${${header_we}_sketch_lib}" MATCHES "NOTFOUND")
+ _validate_target_includes_header(${_target_name} ${header} is_header_validated)
+ if (NOT is_header_validated)
+ # Header hasn't been found in any of the target's include directories, Display warning
+ message(WARNING "The header '${header_we}' is used by the \
+ '${_sketch_file}' sketch \
+ but it isn't a Arduino/Platform library, nor it's linked \
+ to the target manually!")
+ endif ()
+ else ()
+ link_arduino_library(${_target_name} ${header_we}_sketch_lib ${_board_id})
+ endif ()
+ endif ()
+ endforeach ()
+
+endfunction()
diff --git a/cmake/Platform/Sketches/SketchManager.cmake b/cmake/Platform/Sketches/SketchManager.cmake
new file mode 100644
index 0000000..ac5bab4
--- /dev/null
+++ b/cmake/Platform/Sketches/SketchManager.cmake
@@ -0,0 +1,55 @@
+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,
+# thus having different path to be returned.
+# _sketch_file - Path to a sketch file to find the desired path to its converted source.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - Desired path for the source file converted from the given sketch
+#=============================================================================#
+function(_get_converted_source_desired_path _sketch_file _return_var)
+
+ get_filename_component(sketch_file_name "${_sketch_file}" NAME_WE)
+ set(desired_source_path "${CMAKE_CURRENT_SOURCE_DIR}/${sketch_file_name}.cpp")
+ set(${_return_var} ${desired_source_path} PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Adds the sketch file to the given target with the given board ID.
+# Each sketch is converted to a valid '.cpp' source file under the project's source directory.
+# The function also finds and links any libraries the sketch uses to the target.
+# _target_name - Name of the target to add the sketch file to.
+# _board_id - ID of the board to bind to the target (Each target can have a single board).
+# _sketch_file - Path to a sketch file to add to the target.
+#=============================================================================#
+function(add_sketch_to_target _target_name _board_id _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}")
+ resolve_sketch_headers(${_target_name} ${_board_id} "${_sketch_file}")
+ convert_sketch_to_source("${_sketch_file}" "${sketch_converted_source_path}")
+ endif ()
+
+ target_sources(${_target_name} PRIVATE "${sketch_converted_source_path}")
+
+endfunction()
+
+#=============================================================================#
+# Adds a list of sketch files as converted sources to the given target.
+# _target_name - Name of the target to add the sketch file to.
+# _board_id - ID of the board to bind to the target (Each target can have a single board).
+# _sketch_files - List of paths to sketch files to add to the target.
+#=============================================================================#
+function(target_sketches _target_name _board_id _sketch_files)
+
+ foreach (sketch_file ${_sketch_files})
+ add_sketch_to_target(${_target_name} ${_board_id} "${sketch_file}")
+ endforeach ()
+
+endfunction()
diff --git a/cmake/Platform/Sketches/SketchSourceConverter.cmake b/cmake/Platform/Sketches/SketchSourceConverter.cmake
new file mode 100644
index 0000000..5659a36
--- /dev/null
+++ b/cmake/Platform/Sketches/SketchSourceConverter.cmake
@@ -0,0 +1,96 @@
+#=============================================================================#
+# 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.
+# _file_path - Full path to the written source file.
+#=============================================================================#
+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}")
+ file(APPEND "${_file_path}" "${original_loc}")
+ endforeach ()
+
+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_loc - List of lines-of-code belonging to the sketch.
+# _active_index - Index that indicates the best-not-optimized loc 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)
+
+ decrement_integer(_active_index 1)
+ list(GET _sketch_loc ${_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)
+ 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()
+
+#=============================================================================#
+# 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).
+#=============================================================================#
+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)
+
+ 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} GREATER_EQUAL ${loc_index})
+ decrement_integer(header_index 1)
+ set(include_line "\n#include <${ARDUINO_CMAKE_PLATFORM_HEADER_NAME}>")
+ else ()
+ set(include_line "#include <${ARDUINO_CMAKE_PLATFORM_HEADER_NAME}>\n\n")
+ endif ()
+ list(INSERT refined_sketch ${header_index} ${include_line})
+ set(header_inserted TRUE)
+ endif ()
+ endif ()
+ if ("${loc}" STREQUAL "")
+ list(APPEND refined_sketch "\n")
+ else ()
+ string(REGEX REPLACE "^(.+);(.*)$" "\\1${ARDUINO_CMAKE_SEMICOLON_REPLACEMENT}\\2"
+ refined_loc "${loc}")
+ list(APPEND refined_sketch "${refined_loc}\n")
+ endif ()
+ endforeach ()
+
+ _write_source_file("${refined_sketch}" "${_converted_source_path}")
+
+endfunction()
diff --git a/cmake/Platform/Sources/ExampleSourcesSeeker.cmake b/cmake/Platform/Sources/ExampleSourcesSeeker.cmake
new file mode 100644
index 0000000..8ede553
--- /dev/null
+++ b/cmake/Platform/Sources/ExampleSourcesSeeker.cmake
@@ -0,0 +1,56 @@
+#=============================================================================#
+# Finds all sources under the given base path conforming to the given extension.
+# Found sources represent Arduino sketches, which in turn are also examples.
+# _base_path - Top-Directory path to search source files in.
+# _example_name - Name of the example to find its' sources.
+# _search_extension - File extension of the target example, marking an example as 'found'.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - List of sources representing the requested example.
+#=============================================================================#
+function(_find_example_sources _base_path _example_name _search_extension _return_var)
+
+ if (example_CATEGORY)
+ set(search_path "${_base_path}/${example_CATEGORY}/${_example_name}.${_search_extension}")
+ else ()
+ set(search_path "${_base_path}/${_example_name}.${_search_extension}")
+ endif ()
+ file(GLOB_RECURSE example_description_file "${search_path}")
+ get_filename_component(example_dir "${example_description_file}" DIRECTORY)
+
+ find_sketch_files("${example_dir}" example_sketches)
+
+ set(${_return_var} ${example_sketches} PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Finds all sources under the given base path conforming to the given extension.
+# Found sources represent Arduino sketches, which in turn are also examples.
+# _base_path - Top-Directory path to search source files in.
+# _example_name - Name of the example to find its' sources.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - List of sources representing the requested example.
+#=============================================================================#
+function(find_arduino_example_sources _base_path _example_name _return_var)
+
+ # Example directories contain a '.txt' file along with all other sources
+ _find_example_sources("${_base_path}" ${_example_name} "txt" sources)
+ set(${_return_var} ${sources} PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Finds all sources under the given base path conforming to the given extension.
+# Found sources represent Arduino sketches, which in turn are also examples.
+# _base_path - Top-Directory path to search source files in.
+# _example_name - Name of the example to find its' sources.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - List of sources representing the requested example.
+#=============================================================================#
+function(find_arduino_library_example_sources _base_path _example_name _return_var)
+
+ # Library example directories contain only '.ino' files
+ _find_example_sources("${_base_path}" ${_example_name} "ino" sources)
+ set(${_return_var} ${sources} PARENT_SCOPE)
+
+endfunction()
diff --git a/cmake/Platform/Sources/SourceSeeker.cmake b/cmake/Platform/Sources/SourceSeeker.cmake
new file mode 100644
index 0000000..3ffc61f
--- /dev/null
+++ b/cmake/Platform/Sources/SourceSeeker.cmake
@@ -0,0 +1,71 @@
+#=============================================================================#
+# Finds source files matching the given pattern under the given path.
+# Search could also be recursive (With sub-directories) if the optional 'RECURSE' option is passed.
+# _base_path - Top-Directory path to search source files in.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - List of sources in the given path
+#=============================================================================#
+function(_find_sources _base_path _pattern _return_var)
+
+ cmake_parse_arguments(source_file_search "RECURSE" "" "" ${ARGN})
+
+ # Adapt the source files pattern to the given base dir
+ set(current_pattern "")
+ foreach (pattern_part ${_pattern})
+ list(APPEND current_pattern "${_base_path}/${pattern_part}")
+ endforeach ()
+
+ if (${source_file_search_RECURSE})
+ file(GLOB_RECURSE source_files ${current_pattern})
+ else ()
+ file(GLOB source_files LIST_DIRECTORIES FALSE ${current_pattern})
+ endif ()
+
+ set(${_return_var} "${source_files}" PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Finds source files matching the pre-defined source-file pattern under the given path.
+# This functions searchs explicitly for source-files such as '*.c'.
+# Search could also be recursive (With sub-directories) if the optional 'RECURSE' option is passed.
+# _base_path - Top-Directory path to search source files in.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - List of source files in the given path
+#=============================================================================#
+function(find_source_files _base_path _return_var)
+
+ _find_sources("${_base_path}" "${ARDUINO_CMAKE_SOURCE_FILES_PATTERN}" sources ${ARGN})
+ set(${_return_var} "${sources}" PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Finds header files matching the pre-defined header-file pattern under the given path.
+# This functions searchs explicitly for header-files such as '*.h'.
+# Search could also be recursive (With sub-directories) if the optional 'RECURSE' option is passed.
+# _base_path - Top-Directory path to search source files in.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - List of header files in the given path
+#=============================================================================#
+function(find_header_files _base_path _return_var)
+
+ _find_sources("${_base_path}" "${ARDUINO_CMAKE_HEADER_FILES_PATTERN}" headers ${ARGN})
+ set(${_return_var} "${headers}" PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Finds sketch files matching the pre-defined sketch-file pattern under the given path.
+# This functions searchs explicitly for sketch-files such as '*.ino'.
+# Search could also be recursive (With sub-directories) if the optional 'RECURSE' option is passed.
+# _base_path - Top-Directory path to search source files in.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - List of header files in the given path
+#=============================================================================#
+function(find_sketch_files _base_path _return_var)
+
+ _find_sources("${_base_path}" "${ARDUINO_CMAKE_SKETCH_FILES_PATTERN}" sketches ${ARGN})
+ set(${_return_var} "${sketches}" PARENT_SCOPE)
+
+endfunction()
diff --git a/cmake/Platform/Sources/SourcesManager.cmake b/cmake/Platform/Sources/SourcesManager.cmake
new file mode 100644
index 0000000..db41d16
--- /dev/null
+++ b/cmake/Platform/Sources/SourcesManager.cmake
@@ -0,0 +1,71 @@
+include(SourceSeeker)
+include(ExampleSourcesSeeker)
+
+#=============================================================================#
+# Gets all '#include' lines of the given source file.
+# _source_file - Source file to get its' includes.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - List of found include lines, if any.
+#=============================================================================#
+function(get_source_file_includes _source_file _return_var)
+
+ if (NOT EXISTS "${_source_file}")
+ message(SEND_ERROR "Can't find '#includes', source file doesn't exist: ${_source_file}")
+ endif ()
+
+ file(STRINGS "${_source_file}" source_lines)
+ list(FILTER source_lines INCLUDE REGEX "${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}")
+
+ set(${_return_var} ${source_lines} PARENT_SCOPE)
+
+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.
+# 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.
+# Returns - List of directories representing the parent directories of all given headers.
+#=============================================================================#
+function(get_headers_parent_directories _sources _return_var)
+
+ # Extract header files
+ 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 ()
+ list(REMOVE_DUPLICATES parent_dirs)
+
+ set(${_return_var} ${parent_dirs} PARENT_SCOPE)
+
+endfunction()
diff --git a/cmake/Platform/System/AvrToolsFinder.cmake b/cmake/Platform/System/AvrToolsFinder.cmake
new file mode 100644
index 0000000..cc87e2a
--- /dev/null
+++ b/cmake/Platform/System/AvrToolsFinder.cmake
@@ -0,0 +1,61 @@
+#=============================================================================#
+# Finds 'avr-objcopy' tool in Arduino's SDK path.
+#=============================================================================#
+function(find_tool_avr_objcopy)
+
+ find_program(ARDUINO_CMAKE_AVROBJCOPY_PROGRAM
+ NAMES avr-objcopy
+ PATHS ${ARDUINO_SDK_BIN_PATH}
+ DOC "Path to avr's objcopy program")
+ if (NOT ARDUINO_CMAKE_AVROBJCOPY_PROGRAM OR ${ARDUINO_CMAKE_AVROBJCOPY_PROGRAM} STREQUAL "")
+ message(FATAL_ERROR "avr-objcopy program is required by the toolchain but can't be found")
+ endif ()
+ set(CMAKE_OBJCOPY ${ARDUINO_CMAKE_AVROBJCOPY_PROGRAM})
+
+endfunction()
+
+#=============================================================================#
+# Finds 'avrdude' tool in Arduino's SDK path.
+#=============================================================================#
+function(find_tool_avrdude)
+
+ find_program(ARDUINO_CMAKE_AVRDUDE_PROGRAM
+ NAMES avrdude
+ PATHS ${ARDUINO_SDK_BIN_PATH}
+ DOC "Path to avrdude program (Code Uploader)")
+ if (NOT ARDUINO_CMAKE_AVRDUDE_PROGRAM OR ${ARDUINO_CMAKE_AVRDUDE_PROGRAM} STREQUAL "")
+ message(FATAL_ERROR "avrdude program is required by the toolchain but can't be found")
+ endif ()
+
+endfunction()
+
+#=============================================================================#
+# Finds 'avrdude' tool's configuration file in Arduino's SDK path.
+#=============================================================================#
+function(find_tool_avrdude_configuration)
+
+ find_file(ARDUINO_CMAKE_AVRDUDE_CONFIG_PATH
+ NAMES avrdude.conf
+ PATHS ${ARDUINO_SDK_ROOT_PATH}
+ PATH_SUFFIXES /etc /etc/avrdude
+ DOC "Path to avrdude's programmer configuration file")
+ if (NOT ARDUINO_CMAKE_AVRDUDE_CONFIG_PATH OR ${ARDUINO_CMAKE_AVRDUDE_CONFIG_PATH} STREQUAL "")
+ message(FATAL_ERROR "avrdude program is required by the toolchain but can't be found")
+ endif ()
+
+endfunction()
+
+#=============================================================================#
+# Finds 'avr-size' tool in Arduino's SDK path.
+#=============================================================================#
+function(find_tool_avrsize)
+
+ find_program(ARDUINO_CMAKE_AVRSIZE_PROGRAM
+ NAMES avr-size
+ PATHS ${ARDUINO_SDK_BIN_PATH}
+ DOC "Path to avr-size program (Size Calculator)")
+ if (NOT ARDUINO_CMAKE_AVRSIZE_PROGRAM OR ${ARDUINO_CMAKE_AVRSIZE_PROGRAM} STREQUAL "")
+ message(FATAL_ERROR "avrdude program is required by the toolchain but can't be found")
+ endif ()
+
+endfunction()
diff --git a/cmake/Platform/System/BuildSystemInitializer.cmake b/cmake/Platform/System/BuildSystemInitializer.cmake
new file mode 100644
index 0000000..cfe81c3
--- /dev/null
+++ b/cmake/Platform/System/BuildSystemInitializer.cmake
@@ -0,0 +1,25 @@
+include(AvrToolsFinder)
+include(VersionDetector)
+include(PlatformInitializer)
+
+function(find_required_platform_tools)
+
+ find_tool_avr_objcopy()
+ find_tool_avrdude()
+ find_tool_avrdude_configuration()
+ find_tool_avrsize()
+
+endfunction()
+
+#=============================================================================#
+# Initializes build system by setting defaults, finding tools and initializing the hardware-platform.
+#=============================================================================#
+function(initialize_build_system)
+
+ set_arduino_cmake_defaults()
+ find_required_platform_tools()
+ detect_sdk_version()
+
+ initialize_arduino_platform()
+
+endfunction()
diff --git a/cmake/Platform/System/DefaultsManager.cmake b/cmake/Platform/System/DefaultsManager.cmake
new file mode 100644
index 0000000..2ec1a79
--- /dev/null
+++ b/cmake/Platform/System/DefaultsManager.cmake
@@ -0,0 +1,63 @@
+#=============================================================================#
+# Sets search patterns used internaly by the platform for searching purposes.
+#=============================================================================#
+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
+ "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")
+
+endfunction()
+
+#=============================================================================#
+# Sets globb patterns for various types of source files, used mostly for searching purposes.
+#=============================================================================#
+function(set_source_files_patterns)
+
+ set(ARDUINO_CMAKE_SOURCE_FILES_PATTERN *.c *.cc *.cpp *.cxx *.[Ss] CACHE STRING
+ "Source Files Pattern")
+ set(ARDUINO_CMAKE_HEADER_FILES_PATTERN *.h *.hh *.hpp *.hxx CACHE STRING
+ "Header Files Pattern")
+ set(ARDUINO_CMAKE_SKETCH_FILES_PATTERN *.ino *.pde CACHE STRING
+ "Sketch Files Pattern")
+
+endfunction()
+
+#=============================================================================#
+# Sets various options specific for the Arduino-CMake platform.
+#=============================================================================#
+function(set_default_arduino_cmake_options)
+
+ option(USE_DEFAULT_PLATFORM_IF_NONE_EXISTING
+ "Whether to use Arduino as default platform if none is supplied" ON)
+ option(USE_CUSTOM_PLATFORM_HEADER
+ "Whether to expect and use a custom-supplied platform header, \
+ skipping the selection algorithm" OFF)
+ option(USE_ARCHLINUX_BUILTIN_SUPPORT
+ "Whether to use Arduino CMake's built-in support for the archlinux distribution" ON)
+ option(CONVERT_SKETCHES_IF_CONVERTED_SOURCES_EXISTS
+ "Whether to convert sketches to source files even if converted sources already exist"
+ OFF)
+
+endfunction()
+
+#=============================================================================#
+# Sets various defaults used throughout the platform.
+#=============================================================================#
+function(set_arduino_cmake_defaults)
+
+ set_internal_search_patterns()
+ set_source_files_patterns()
+ set_default_arduino_cmake_options()
+
+endfunction()
diff --git a/cmake/Platform/System/LinuxDistDetector.cmake b/cmake/Platform/System/LinuxDistDetector.cmake
new file mode 100644
index 0000000..5fbee5b
--- /dev/null
+++ b/cmake/Platform/System/LinuxDistDetector.cmake
@@ -0,0 +1,17 @@
+function(detect_host_linux_distribution)
+
+ if (NOT ${CMAKE_HOST_UNIX})
+ message(AUTHOR_WARNING "Linux distribution detection called on non-Unix platform")
+ elseif (${CMAKE_HOST_APPLE})
+ message(AUTHOR_WARNING "Linux distribution detection called on Apple platform")
+ else () # Linux host
+ find_program(lsb_release_exec lsb_release)
+ execute_process(COMMAND ${lsb_release_exec} -is
+ OUTPUT_VARIABLE lsb_release_id_short
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ string(TOUPPER dist ${lsb_release_id_short})
+ set(CMAKE_HOST_${dist} TRUE CACHE BOOL
+ "Whether host system is ${lsb_release_id_short}" ADVANCED)
+ endif ()
+
+endfunction()
diff --git a/cmake/Platform/System/PlatformElementsManager.cmake b/cmake/Platform/System/PlatformElementsManager.cmake
new file mode 100644
index 0000000..4e4b985
--- /dev/null
+++ b/cmake/Platform/System/PlatformElementsManager.cmake
@@ -0,0 +1,151 @@
+function(find_platform_cores)
+
+ find_file(ARDUINO_CMAKE_PLATFORM_CORES_PATH
+ NAMES cores
+ PATHS ${ARDUINO_CMAKE_PLATFORM_PATH}
+ DOC "Path to directory containing the Platform's core sources"
+ NO_CMAKE_FIND_ROOT_PATH)
+
+ set(core_list "")
+
+ file(GLOB sub-dir ${ARDUINO_CMAKE_PLATFORM_CORES_PATH}/*)
+ foreach (dir ${sub-dir})
+ if (IS_DIRECTORY ${dir})
+ get_filename_component(core ${dir} NAME)
+ string(TOLOWER ${core} core)
+ set(ARDUINO_CMAKE_CORE_${core}_PATH "${dir}" CACHE INTERNAL "Path to ${core} core")
+ list(APPEND core_list ${core})
+ endif ()
+ endforeach ()
+
+ set(ARDUINO_CMAKE_PLATFORM_CORES "${core_list}" CACHE STRING "List of existing platform cores")
+
+endfunction()
+
+function(find_platform_variants)
+
+ find_file(ARDUINO_CMAKE_PLATFORM_VARIANTS_PATH
+ NAMES variants
+ PATHS ${ARDUINO_CMAKE_PLATFORM_PATH}
+ DOC "Path to directory containing the Platform's variant sources"
+ NO_CMAKE_FIND_ROOT_PATH)
+ file(GLOB sub-dir ${ARDUINO_CMAKE_PLATFORM_VARIANTS_PATH}/*)
+
+ set(variant_list "")
+
+ foreach (dir ${sub-dir})
+ if (IS_DIRECTORY ${dir})
+ get_filename_component(variant ${dir} NAME)
+ string(TOLOWER ${variant} variant)
+ set(ARDUINO_CMAKE_VARIANT_${variant}_PATH ${dir} CACHE INTERNAL
+ "Path to ${variant} variant")
+ list(APPEND variant_list ${variant})
+ endif ()
+ endforeach ()
+
+ set(ARDUINO_CMAKE_PLATFORM_VARIANTS "${variant_list}" CACHE STRING
+ "List of existing platform variants")
+
+endfunction()
+
+function(find_platform_bootloaders)
+
+ find_file(ARDUINO_CMAKE_PLATFORM_BOOTLOADERS_PATH
+ NAMES bootloaders
+ PATHS ${ARDUINO_CMAKE_PLATFORM_PATH}
+ DOC "Path to directory containing the Platform's bootloader images and sources"
+ NO_CMAKE_FIND_ROOT_PATH)
+
+endfunction()
+
+function(find_platform_programmers)
+
+ find_file(ARDUINO_CMAKE_PLATFORM_PROGRAMMERS_PATH
+ NAMES programmers.txt
+ PATHS ${ARDUINO_CMAKE_PLATFORM_PATH}
+ DOC "Path to Platform's programmers definition file"
+ NO_CMAKE_FIND_ROOT_PATH)
+
+endfunction()
+
+function(find_platform_boards)
+
+ find_file(ARDUINO_CMAKE_PLATFORM_BOARDS_PATH
+ NAMES boards.txt
+ PATHS ${ARDUINO_CMAKE_PLATFORM_PATH}
+ DOC "Path to Platform's boards definition file"
+ NO_CMAKE_FIND_ROOT_PATH)
+
+endfunction()
+
+function(find_platform_properties_file)
+
+ find_file(ARDUINO_CMAKE_PLATFORM_PROPERTIES_FILE_PATH
+ NAMES platform.txt
+ PATHS ${ARDUINO_CMAKE_PLATFORM_PATH}
+ DOC "Path to Platform's properties file"
+ NO_CMAKE_FIND_ROOT_PATH)
+
+endfunction()
+
+function(find_platform_libraries)
+
+ find_file(ARDUINO_CMAKE_PLATFORM_LIBRARIES_PATH
+ NAMES libraries
+ PATHS ${ARDUINO_CMAKE_PLATFORM_PATH}
+ DOC "Path to platform directory containing the Arduino libraries"
+ NO_CMAKE_FIND_ROOT_PATH)
+
+ file(GLOB sub-dir "${ARDUINO_CMAKE_PLATFORM_LIBRARIES_PATH}/*")
+ set(platform_lib_list)
+ foreach (dir ${sub-dir})
+ if (IS_DIRECTORY ${dir})
+ get_filename_component(platform_lib ${dir} NAME)
+ string(TOLOWER ${platform_lib} platform_lib)
+ set(ARDUINO_CMAKE_LIBRARY_${platform_lib}_PATH ${dir} CACHE INTERNAL
+ "Path to ${platform_lib} platform library")
+ list(APPEND platform_lib_list ${platform_lib})
+ endif ()
+ endforeach ()
+
+ set(ARDUINO_CMAKE_PLATFORM_LIBRARIES "${platform_lib_list}" CACHE STRING
+ "List of existing platform libraries")
+
+endfunction()
+
+#=============================================================================#
+# Finds platform's main header file by iterating over all headers under all core directories,
+# looking for the one with the most '#include' lines as it can be presumed as the main header.
+# The header is stored in cache in 2 variants:
+# 1. ARDUINO_CMAKE_PLATFORM_HEADER_NAME - Header's name with its' file extension
+# 2. ARDUINO_CMAKE_PLATFORM_HEADER_PATH - Full path to the header file
+#=============================================================================#
+function(find_platform_main_header)
+
+ set(max_includes 0) # Track the biggest number of include lines to perform quick swap
+
+ foreach (core ${ARDUINO_CMAKE_PLATFORM_CORES})
+ find_header_files("${ARDUINO_CMAKE_CORE_${core}_PATH}" core_headers)
+ foreach (header ${core_headers})
+ file(STRINGS "${header}" header_content)
+ list(FILTER header_content INCLUDE REGEX "^#include")
+ # Count the number of includes
+ list(LENGTH header_content num_of_includes)
+ # Check if current number is bigger than the known maximum, swap if it is
+ if (${num_of_includes} GREATER ${max_includes})
+ set(biggest_header ${header})
+ set(max_includes ${num_of_includes})
+ endif ()
+ endforeach ()
+ endforeach ()
+
+ # Platform's header is probably the one with the biggest number of include lines
+ 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_PATH "${biggest_header}" CACHE PATH
+ "Path to platform's main header file")
+
+endfunction()
diff --git a/cmake/Platform/System/PlatformFlagsSetter.cmake b/cmake/Platform/System/PlatformFlagsSetter.cmake
new file mode 100644
index 0000000..c3c13be
--- /dev/null
+++ b/cmake/Platform/System/PlatformFlagsSetter.cmake
@@ -0,0 +1,22 @@
+#=============================================================================#
+# Setups any remaining Arduino platform-related flags which haven't been set
+# when platform file has been read
+#=============================================================================#
+function(setup_remaining_platform_flags)
+
+ set(ARDUINO_CMAKE_AVRDUDE_FLAGS ${tools_avrdude_upload_params_verbose})
+
+ # Set AR flags based on the platform file
+ if (compiler_ar_flags)
+ set(CMAKE_ASM_ARCHIVE_CREATE
+ " ${compiler_ar_flags} "
+ CACHE STRING "" FORCE)
+ set(CMAKE_C_ARCHIVE_CREATE
+ " ${compiler_ar_flags} "
+ CACHE STRING "" FORCE)
+ set(CMAKE_CXX_ARCHIVE_CREATE
+ " ${compiler_ar_flags} "
+ CACHE STRING "" FORCE)
+ endif ()
+
+endfunction()
diff --git a/cmake/Platform/System/PlatformInitializer.cmake b/cmake/Platform/System/PlatformInitializer.cmake
new file mode 100644
index 0000000..19ba5db
--- /dev/null
+++ b/cmake/Platform/System/PlatformInitializer.cmake
@@ -0,0 +1,63 @@
+include(PlatformElementsManager)
+include(PropertiesReader)
+include(BoardPropertiesReader)
+include(PlatformFlagsSetter)
+
+function(find_required_platform_elements)
+
+ find_platform_cores()
+ find_platform_variants()
+ find_platform_bootloaders()
+ find_platform_programmers()
+ find_platform_properties_file()
+ find_platform_boards()
+ find_platform_libraries()
+ if (NOT USE_CUSTOM_PLATFORM_HEADER)
+ find_platform_main_header()
+ endif ()
+
+endfunction()
+
+#=============================================================================#
+# Initializes platform-related properties by parsing all property files.
+#=============================================================================#
+function(initialize_platform_properties)
+
+ read_properties_from_file(${ARDUINO_CMAKE_PLATFORM_PROPERTIES_FILE_PATH})
+ read_properties_from_file(${ARDUINO_CMAKE_PLATFORM_PROGRAMMERS_PATH})
+ read_boards_properties(${ARDUINO_CMAKE_PLATFORM_BOARDS_PATH})
+
+endfunction()
+
+#=============================================================================#
+# Initializes the Arduino-platform by defining the platform's path,
+# parsing property files and setupping any remaining flags.
+#=============================================================================#
+function(initialize_arduino_platform)
+
+ if (NOT DEFINED ARDUINO_CMAKE_PLATFORM_NAME OR NOT DEFINED ARDUINO_CMAKE_PLATFORM_PATH)
+ if (USE_DEFAULT_PLATFORM_IF_NONE_EXISTING)
+ if (CMAKE_HOST_ARCHLINUX AND ${USE_ARCHLINUX_BUILTIN_SUPPORT})
+ set(ARDUINO_CMAKE_PLATFORM_NAME "archlinux-arduino" CACHE STRING "")
+ else ()
+ set(ARDUINO_CMAKE_PLATFORM_NAME "arduino" CACHE STRING "")
+ endif ()
+ set(ARDUINO_CMAKE_PLATFORM_ARCHITECTURE "avr" CACHE STRING "")
+ string(CONCAT platform_path "${ARDUINO_SDK_PATH}"
+ /hardware/
+ "${ARDUINO_CMAKE_PLATFORM_NAME}/"
+ "${ARDUINO_CMAKE_PLATFORM_ARCHITECTURE}")
+ set(ARDUINO_CMAKE_PLATFORM_PATH "${platform_path}" CACHE PATH "")
+ else ()
+ message(FATAL_ERROR "Arduino Platform must be defined through name and path")
+ endif ()
+ elseif (NOT DEFINED ARDUINO_CMAKE_PLATFORM_ARCHITECTURE) # Platform defined without architecture
+ set(ARDUINO_CMAKE_PLATFORM_ARCHITECTURE "avr" CACHE STRING "")
+ endif ()
+
+ # Find all platform elements
+ find_required_platform_elements()
+ initialize_platform_properties()
+ setup_remaining_platform_flags()
+
+endfunction()
diff --git a/cmake/Platform/System/VersionDetector.cmake b/cmake/Platform/System/VersionDetector.cmake
new file mode 100644
index 0000000..e99b0d9
--- /dev/null
+++ b/cmake/Platform/System/VersionDetector.cmake
@@ -0,0 +1,91 @@
+#=============================================================================#
+# Appends a suffic zero to the given version part if it's below than the given limit.
+# Otherwise, the version part is returned as it is.
+#
+# _version_part - Version to check and possibly append to.
+# Must be a version part - Major, Minor or Patch.
+# _version_limit - Append limit. For a version greater than this number
+# a zero will NOT be appended.
+# _return_var - Returned variable storing the normalized version.
+#
+#=============================================================================#
+function(_append_suffix_zero _version_part _return_var)
+ set(${_return_var} "${_version_part}0" PARENT_SCOPE)
+endfunction()
+
+#=============================================================================#
+# _get_normalized_sdk_version
+# [PRIVATE/INTERNAL]
+#
+# _get_normalized_sdk_version(_return_var)
+#
+# _return_var - Returned variable storing the normalized version
+#
+# Normalizes SDK's version for a proper use of the '-DARDUINO' compile flag.
+# Note that there are differences between normalized versions in specific SDK versions:
+# e.g Version 1.6.5 will be normalized as 10605
+#
+#=============================================================================#
+function(_get_normalized_sdk_version _return_var)
+
+ # -DARDUINO format has changed since 1.6.0 by appending zeros when required
+ _append_suffix_zero(${ARDUINO_CMAKE_SDK_VERSION_MAJOR} major_version)
+ _append_suffix_zero(${ARDUINO_CMAKE_SDK_VERSION_MINOR} minor_version)
+ set(normalized_version "${major_version}${minor_version}${ARDUINO_CMAKE_SDK_VERSION_PATCH}")
+
+ set(${_return_var} "${normalized_version}" PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Detects the Arduino SDK Version based on the dedicated version 1file.
+# The following variables will be generated:
+#
+# ${ARDUINO_CMAKE_SDK_VERSION} -> the full version (major.minor.patch)
+# ${ARDUINO_CMAKE_SDK_VERSION}_MAJOR -> the major version
+# ${ARDUINO_CMAKE_SDK_VERSION}_MINOR -> the minor version
+# ${ARDUINO_CMAKE_SDK_VERSION}_PATCH -> the patch version
+#
+#=============================================================================#
+function(detect_sdk_version)
+
+ find_file(ARDUINO_CMAKE_VERSION_FILE_PATH
+ NAMES version.txt
+ PATHS "${ARDUINO_SDK_PATH}"
+ PATH_SUFFIXES lib
+ DOC "Path to Arduino's version file"
+ NO_CMAKE_FIND_ROOT_PATH)
+
+ if (NOT ARDUINO_CMAKE_VERSION_FILE_PATH)
+ message(FATAL_ERROR "Couldn't find SDK's version file, aborting.")
+ endif ()
+
+ file(READ ${ARDUINO_CMAKE_VERSION_FILE_PATH} raw_version)
+
+ if ("${raw_version}" STREQUAL "")
+ message(FATAL_ERROR "Version file is found but its empty")
+ endif ()
+
+ string(REPLACE "." ";" split_version ${raw_version})
+ list(GET split_version 0 split_version_major)
+ list(GET split_version 1 split_version_minor)
+ list(GET split_version 2 split_version_patch)
+
+ set(ARDUINO_CMAKE_SDK_VERSION "${raw_version}" CACHE STRING "Arduino SDK Version")
+ set(ARDUINO_CMAKE_SDK_VERSION_MAJOR ${split_version_major} CACHE STRING
+ "Arduino SDK Major Version")
+ set(ARDUINO_CMAKE_SDK_VERSION_MINOR ${split_version_minor} CACHE STRING
+ "Arduino SDK Minor Version")
+ set(ARDUINO_CMAKE_SDK_VERSION_PATCH ${split_version_patch} CACHE STRING
+ "Arduino SDK Patch Version")
+
+ if (ARDUINO_CMAKE_SDK_VERSION VERSION_LESS 1.6.0)
+ message(FATAL_ERROR "Unsupported Arduino SDK (requires version 1.6 or higher)")
+ endif ()
+
+ _get_normalized_sdk_version(normalized_sdk_version)
+ set(runtime_ide_version "${normalized_sdk_version}" CACHE STRING "")
+
+ message(STATUS "Arduino SDK version ${ARDUINO_CMAKE_SDK_VERSION}: ${ARDUINO_SDK_PATH}")
+
+endfunction()
diff --git a/cmake/Platform/Targets/ArduinoCMakeLibraryTarget.cmake b/cmake/Platform/Targets/ArduinoCMakeLibraryTarget.cmake
new file mode 100644
index 0000000..132e5e4
--- /dev/null
+++ b/cmake/Platform/Targets/ArduinoCMakeLibraryTarget.cmake
@@ -0,0 +1,100 @@
+#=============================================================================#
+# Sets compiler and linker flags on the given library target.
+# Changes are kept even outside the scope of the function since they apply on a target.
+# _library_target - Name of the library target.
+# _board_id - Board ID associated with the library. Some flags require it.
+#=============================================================================#
+function(_set_library_flags _library_target _board_id)
+
+ # Set C++ compiler flags
+ get_cmake_compliant_language_name(cpp flags_language)
+ set_compiler_target_flags(${_library_target} "${_board_id}" PUBLIC LANGUAGE ${flags_language})
+
+ # Set linker flags
+ set_linker_flags(${_library_target} "${_board_id}")
+
+endfunction()
+
+#=============================================================================#
+# Creates a library target compliant with the Arduino library standard.
+# One can also specify an architecture for the library, which will result in a special parsing
+# of the sources, ommiting non-compliant sources.
+# _target_name - Name of the library target to be created. Usually library's real name.
+# _board_id - Board ID associated with the linked Core Lib.
+# _sources - Source and header files to create library target from.
+# [ARCH] - Optional library architecture (Such as 'avr', 'nrf52', etc.)
+#=============================================================================#
+function(_add_arduino_cmake_library _target_name _board_id _sources)
+
+ cmake_parse_arguments(library "" "ARCH" "" ${ARGN})
+
+ if (library_ARCH) # Treat architecture-specific libraries differently
+ # Filter any sources that aren't supported by the platform's architecture
+ list(LENGTH library_ARCH num_of_libs_archs)
+ if (${num_of_libs_archs} GREATER 1)
+ # Exclude all unsupported architectures, request filter in regex mode
+ _get_unsupported_architectures("${library_ARCH}" arch_filter REGEX)
+ set(filter_type EXCLUDE)
+ else ()
+ set(arch_filter "src\\/[^/]+\\.|${library_ARCH}")
+ set(filter_type INCLUDE)
+ endif ()
+ list(FILTER _sources ${filter_type} REGEX ${arch_filter})
+ endif ()
+
+ add_library(${_target_name} STATIC "${_sources}")
+ # Treat headers' parent directories as include directories of the target
+ get_headers_parent_directories("${_sources}" include_dirs)
+ target_include_directories(${_target_name} PUBLIC ${include_dirs})
+
+ _set_library_flags(${_target_name} ${_board_id})
+
+ if (library_ARCH)
+ string(TOUPPER ${library_ARCH} upper_arch)
+ set(arch_definition "ARDUINO_ARCH_${upper_arch}")
+ target_compile_definitions(${_target_name} PUBLIC ${arch_definition})
+ endif ()
+
+endfunction()
+
+#=============================================================================#
+# Links the given library target to the given target, be it an executable or another library.
+# The function first adds the includes of the Core Lib to the given library,
+# then links it to the library.
+# _target_name - Name of the target to link against.
+# _library_name - Name of the library target to link.
+# [PRIVATE|PUBLIC|INTERFACE] - Optional link scope.
+# [BOARD_CORE_TARGET] - Optional target name of the Core Lib to use.
+# Use when the target is a library.
+#=============================================================================#
+function(_link_arduino_cmake_library _target_name _library_name)
+
+ if (NOT TARGET ${_target_name})
+ message(FATAL_ERROR "Target doesn't exist - It must be created first!")
+ endif ()
+
+ set(scope_options "PRIVATE" "PUBLIC" "INTERFACE")
+ cmake_parse_arguments(link_library "${scope_options}" "BOARD_CORE_TARGET" "" ${ARGN})
+
+ # First, include core lib's directories in library as well
+ if (link_library_BOARD_CORE_TARGET)
+ set(core_target ${link_library_BOARD_CORE_TARGET})
+ else ()
+ set(core_target ${${_target_name}_CORE_LIB_TARGET})
+ endif ()
+
+ get_target_property(core_lib_includes ${core_target} INCLUDE_DIRECTORIES)
+ target_include_directories(${_library_name} PUBLIC "${core_lib_includes}")
+ target_link_libraries(${_library_name} PUBLIC ${core_target})
+
+ # Now, link library to executable
+ if (link_library_PUBLIC)
+ set(scope PUBLIC)
+ elseif (link_library_INTERFACE)
+ set(scope INTERFACE)
+ else ()
+ set(scope PRIVATE)
+ endif ()
+ target_link_libraries(${_target_name} ${scope} ${_library_name})
+
+endfunction()
diff --git a/cmake/Platform/Targets/ArduinoExampleTarget.cmake b/cmake/Platform/Targets/ArduinoExampleTarget.cmake
new file mode 100644
index 0000000..4cb4ff7
--- /dev/null
+++ b/cmake/Platform/Targets/ArduinoExampleTarget.cmake
@@ -0,0 +1,51 @@
+#=============================================================================#
+# Adds/Creates an Arduino-Example executable target with the given name,
+# using the given board ID and example's sources.
+# _target_name - Name of the target (Executable) to create.
+# _board_id - ID of the board to bind to the target (Each target can have a single board).
+# _example_name - Name of the example to use, such as 'Blink'.
+# [CATEGORY cat] - Optional argument representing the category of the Example to use.
+# e.g The 'Blink' example is under the '01.Basics' category.
+# Generally, all this does is improving search performance by narrowing.
+#=============================================================================#
+function(add_arduino_example _target_name _board_id _example_name)
+
+ convert_string_to_pascal_case(${_example_name} arduino_compliant_example_name)
+ find_arduino_example_sources("${ARDUINO_SDK_EXAMPLES_PATH}"
+ ${arduino_compliant_example_name} example_sketches ${ARGN})
+ # First create the target (Without sources), then add sketches as converted sources
+ add_arduino_executable(${_target_name} ${_board_id} "")
+ target_sketches(${_target_name} ${_board_id} "${example_sketches}")
+
+endfunction()
+
+#=============================================================================#
+# Adds/Creates an Arduino-Library-Example executable target with the given name,
+# using the given board ID and library example's sources.
+# _target_name - Name of the target (Executable) to create.
+# _board_id - ID of the board to bind to the target (Each target can have a single board).
+# _library_target_name - Name of an already-existing library target.
+# This means the library should first be found by the user.
+# _library_name - Name of the library the example belongs to, such as 'Servo'.
+# _example_name - Name of the example to use, such as 'Knob'.
+# [CATEGORY cat] - Optional argument representing the category of the Example to use.
+# e.g The 'Blink' example is under the '01.Basics' category.
+# Generally, all this does is improving search performance by narrowing.
+#=============================================================================#
+function(add_arduino_library_example _target_name _board_id
+ _library_target_name _library_name _example_name)
+
+ convert_string_to_pascal_case(${_example_name} arduino_compliant_example_name)
+ convert_string_to_pascal_case(${_library_name} arduino_compliant_library_name)
+
+ if (NOT TARGET ${_library_target_name})
+ message(SEND_ERROR "Library target doesn't exist - It must be created first!")
+ endif ()
+
+ find_arduino_library_example_sources("${ARDUINO_SDK_LIBRARIES_PATH}/${arduino_compliant_library_name}"
+ ${arduino_compliant_example_name} example_sketches ${ARGN})
+ add_arduino_executable(${_target_name} ${_board_id} "")
+ target_sketches(${_target_name} ${_board_id} "${example_sketches}")
+ link_arduino_library(${_target_name} ${_library_target_name} ${_board_id})
+
+endfunction()
\ No newline at end of file
diff --git a/cmake/Platform/Targets/ArduinoLibraryTarget.cmake b/cmake/Platform/Targets/ArduinoLibraryTarget.cmake
new file mode 100644
index 0000000..fe1bf2c
--- /dev/null
+++ b/cmake/Platform/Targets/ArduinoLibraryTarget.cmake
@@ -0,0 +1,164 @@
+#=============================================================================#
+# Gets the library architecure if any, read from the given library properties file
+# which includes this information.
+# _library_properties_file - Full path to a library's properties file.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - If library is architecure neutral, nothing is returned.
+# If library doesn't support the current platform's architecture,
+# "UNSUPPORTED" string is returned.
+# Otherwise, the platform's architecture is returned.
+#=============================================================================#
+function(_get_library_architecture _library_properties_file _return_var)
+
+ file(STRINGS ${_library_properties_file} library_properties)
+
+ list(FILTER library_properties INCLUDE REGEX "arch")
+ _get_property_value("${library_properties}" arch_list)
+ string(REPLACE "," ";" arch_list ${arch_list}) # Turn into a valid list
+
+ if ("${arch_list}" MATCHES "\\*")
+ return() # Any architecture is supported, return nothing
+ else ()
+ list(LENGTH arch_list num_of_supported_archs)
+ if (${num_of_supported_archs} GREATER 1) # Number of architectures is supported
+ list(FIND arch_list ${ARDUINO_CMAKE_PLATFORM_ARCHITECTURE} platform_arch_index)
+ if (${platform_arch_index} LESS 0) # Our arch isn't supported
+ set(__arch "UNSUPPORTED")
+ else () # Our arch is indeed supported
+ set(__arch ${arch_list})
+ endif ()
+ else ()
+ list(GET arch_list 0 __arch)
+ if (NOT "${__arch}" STREQUAL "${ARDUINO_CMAKE_PLATFORM_ARCHITECTURE}")
+ set(__arch "UNSUPPORTED") # Our arch isn't supported
+ endif ()
+ endif ()
+ endif ()
+
+ set(${_return_var} ${__arch} PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Gets a filtered list of architectures that aren't compliant with the platform's architecture.
+# For example: If a list contains 'avr' and 'nrf52', while our arch is 'avr', 'nrf52' will be returned.
+# _arch_list - List of all architectures probably read from a library's properties file
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - Filtered list of architectures.
+#=============================================================================#
+function(_get_unsupported_architectures _arch_list _return_var)
+
+ cmake_parse_arguments(unsupported_archs "REGEX" "" "" ${ARGN})
+
+ list(FILTER _arch_list EXCLUDE REGEX
+ "${ARDUINO_CMAKE_PLATFORM_ARCHITECTURE}")
+ if (unsupported_archs_REGEX) # Return in regex format
+ list(LENGTH _arch_list num_of_unsupported_archs)
+ set(unsupported_arch_list "")
+ set(arch_index 1)
+ foreach (unsupported_arch ${_arch_list})
+ string(APPEND unsupported_arch_list "${unsupported_arch}")
+ if (${arch_index} LESS ${num_of_unsupported_archs})
+ string(APPEND unsupported_arch_list "|")
+ endif ()
+ increment_integer(arch_index 1)
+ endforeach ()
+ endif ()
+
+ set(${_return_var} ${unsupported_arch_list} PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Creates a library target for the given name and sources.
+# As it's an Arduino library, it also finds and links all dependent platform libraries (if any).
+# _target_name - Name of the library target to be created. Usually library's real name.
+# _board_id - Board ID associated with the linked Core Lib.
+# _sources - Source and header files to create target from.
+#=============================================================================#
+function(_add_arduino_library _target_name _board_id _sources)
+
+ _add_arduino_cmake_library(${_target_name} ${_board_id} "${_sources}" "${ARGN}")
+ find_dependent_platform_libraries("${_sources}" lib_platform_libs)
+ foreach (platform_lib ${lib_platform_libs})
+ link_platform_library(${_target_name} ${platform_lib} ${_board_id})
+ endforeach ()
+
+endfunction()
+
+#=============================================================================#
+# Finds an Arduino library with the given library name and creates a library target from it
+# with the given target name.
+# The search process also resolves library's architecture to check if it even can be built
+# using the current platform architecture.
+# _target_name - Name of the library target to be created. Usually library's real name.
+# _library_name - Name of the Arduino library to find.
+# _board_id - Board ID associated with the linked Core Lib.
+#=============================================================================#
+function(find_arduino_library _target_name _library_name _board_id)
+
+ convert_string_to_pascal_case(${_library_name} arduino_compliant_library_name)
+ set(library_path "${ARDUINO_SDK_LIBRARIES_PATH}/${arduino_compliant_library_name}")
+ set(library_properties_path "${library_path}/library.properties")
+
+ if (NOT EXISTS "${library_properties_path}")
+ message(SEND_ERROR "Couldn't find library named ${arduino_compliant_library_name}")
+ else () # Library is found
+ _get_library_architecture("${library_properties_path}" lib_arch)
+ if (lib_arch)
+ if ("${lib_arch}" MATCHES "UNSUPPORTED")
+ string(CONCAT error_message
+ "${arduino_compliant_library_name} "
+ "library isn't supported on the platform's architecture "
+ "${ARDUINO_CMAKE_PLATFORM_ARCHITECTURE}")
+ message(SEND_ERROR ${error_message})
+ endif ()
+ endif ()
+
+ find_header_files("${library_path}/src" library_headers RECURSE)
+
+ if (NOT library_headers)
+ set(error_message
+ "${_library_name} doesn't have any header files under the 'src' directory")
+ message(SEND_ERROR "${error_message}")
+ else ()
+ find_source_files("${library_path}/src" library_sources RECURSE)
+
+ if (NOT library_sources)
+ set(error_message
+ "${arduino_compliant_library_name} doesn't have any source files \
+ under the 'src' directory")
+ message(SEND_ERROR "${error_message}")
+ else ()
+ set(sources ${library_headers} ${library_sources})
+ _add_arduino_library(${_target_name} ${_board_id} "${sources}" ARCH ${lib_arch})
+ endif ()
+ endif ()
+ endif ()
+
+endfunction()
+
+#=============================================================================#
+# Links the given library target to the given "executable" target, but first,
+# it adds core lib's include directories to the libraries include directories.
+# _target_name - Name of the "executable" target.
+# _library_target_name - Name of the library target.
+# _board_id - Board ID associated with the linked Core Lib.
+#=============================================================================#
+function(link_arduino_library _target_name _library_target_name _board_id)
+
+ get_core_lib_target_name(${_board_id} core_lib_target)
+
+ if (NOT TARGET ${_target_name})
+ message(FATAL_ERROR "Target doesn't exist - It must be created first!")
+ elseif (NOT TARGET ${_library_target_name})
+ message(FATAL_ERROR "Library target doesn't exist - It must be created first!")
+ elseif (NOT TARGET ${core_lib_target})
+ message(FATAL_ERROR "Core Library target doesn't exist. This is bad and should be reported")
+ endif ()
+
+ _link_arduino_cmake_library(${_target_name} ${_library_target_name}
+ PUBLIC
+ BOARD_CORE_TARGET ${core_lib_target})
+
+endfunction()
diff --git a/cmake/Platform/Targets/CoreLibTarget.cmake b/cmake/Platform/Targets/CoreLibTarget.cmake
new file mode 100644
index 0000000..56480a8
--- /dev/null
+++ b/cmake/Platform/Targets/CoreLibTarget.cmake
@@ -0,0 +1,131 @@
+#=============================================================================#
+# Checks whether the given core is valid by searching it in the list of known cores.
+# The function doesn't return on failure but fails generation completely instead.
+#=============================================================================#
+function(_is_board_core_valid _board_core _board_id)
+
+ list(FIND ARDUINO_CMAKE_PLATFORM_CORES "${board_core}" index)
+ if (${index} LESS 0)
+ message(FATAL_ERROR "Unknown board core \"${board_core}\" for the ${_board_id} board")
+ endif ()
+
+endfunction()
+
+#=============================================================================#
+# Checks whether the given variant is valid by searching it in the list of known variants.
+# The function doesn't return on failure but fails generation completely instead.
+#=============================================================================#
+function(_is_board_variant_valid _board_variant _board_id)
+
+ list(FIND ARDUINO_CMAKE_PLATFORM_VARIANTS "${board_variant}" index)
+ if (${index} LESS 0)
+ message(FATAL_ERROR "Unknown board variant \"${board_variant}\" for the ${_board_id} board")
+ endif ()
+
+endfunction()
+
+#=============================================================================#
+# Gets the core property of the given board, and returns it if it's a valid core.
+# _board_id - Board to get its' core represented by its' ID
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - Retrieved board core, if valid. Otherwise, generation stops completely.
+#=============================================================================#
+function(_get_board_core _board_id _return_var)
+
+ get_board_property(${_board_id} "build.core" board_core)
+ string(TOLOWER ${board_core} board_core)
+ _is_board_core_valid(${board_core} ${_board_id})
+
+ set(${_return_var} ${board_core} PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Gets the variant property of the given board, and returns it if it's a valid variant.
+# _board_id - Board to get its' variant represented by its' ID
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - Retrieved board variant, if valid. Otherwise, generation stops completely.
+#=============================================================================#
+function(_get_board_variant _board_id _return_var)
+
+ get_board_property(${_board_id} "build.variant" board_variant)
+ string(TOLOWER ${board_variant} board_variant)
+ _is_board_variant_valid(${board_variant} ${_board_id})
+
+ set(${_return_var} ${board_variant} PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Sets compiler and linker flags on the given Core-Lib target.
+# Changes are kept even outside the scope of the function since they apply on a target.
+# _core_target_name - Name of the Core-Lib target.
+# _board_id - Board ID associated with the library. Some flags require it.
+#=============================================================================#
+function(_set_core_lib_flags _core_target_name _board_id)
+
+ # Set Assembly compiler flags
+ get_cmake_compliant_language_name(asm flags_language)
+ set_compiler_target_flags(${_core_target_name} "${_board_id}" PRIVATE
+ LANGUAGE ${flags_language})
+ # Set C compiler flags
+ get_cmake_compliant_language_name(c flags_language)
+ set_compiler_target_flags(${_core_target_name} "${_board_id}" PRIVATE
+ LANGUAGE ${flags_language})
+ # Set C++ compiler flags
+ get_cmake_compliant_language_name(cpp flags_language)
+ set_compiler_target_flags(${_core_target_name} "${_board_id}" PRIVATE
+ LANGUAGE ${flags_language})
+
+ # Set linker flags
+ set_linker_flags(${_core_target_name} "${_board_id}")
+
+endfunction()
+
+#=============================================================================#
+# Adds/Creates a static library target for Arduino's core library (Core-Lib),
+# required by every standard Arduino Application/Executable.
+# The library is then linked against the given executable target
+# (Which also means is has to be created first).
+# _target_name - Name of the Application/Executable target created earlier.
+# _board_id - Board to create the core library for.
+# Note that each board has a unique version of the library.
+#=============================================================================#
+function(add_arduino_core_lib _target_name _board_id)
+
+ get_core_lib_target_name(${_board_id} core_lib_target)
+
+ if (TARGET ${core_lib_target}) # Core-lib target already created for the given board
+ if (TARGET ${_target_name}) # Executable/Firmware target also exists
+ target_link_libraries(${_target_name} PUBLIC ${core_lib_target})
+ endif ()
+ else () # Core-Lib target needs to be created
+ _get_board_core(${_board_id} board_core) # Get board's core
+ _get_board_variant(${_board_id} board_variant) # Get board's variant
+
+ # Find sources in core directory and add the library target
+ find_source_files("${ARDUINO_CMAKE_CORE_${board_core}_PATH}" core_sources)
+ if (${CMAKE_HOST_UNIX})
+ if (CMAKE_HOST_UBUNTU OR CMAKE_HOST_DEBIAN)
+ set(core_sources_temp_copy ${core_sources})
+ list(FILTER core_sources_temp_copy INCLUDE REGEX "[Mm]ain\\.c.*")
+ message("Temp Copy: ${core_sources_temp_copy}")
+ endif ()
+ endif ()
+ add_library(${core_lib_target} STATIC "${core_sources}")
+
+ # Include platform's core and variant directories
+ target_include_directories(${core_lib_target} PUBLIC
+ "${ARDUINO_CMAKE_CORE_${board_core}_PATH}")
+ target_include_directories(${core_lib_target} PUBLIC
+ "${ARDUINO_CMAKE_VARIANT_${board_variant}_PATH}")
+
+ _set_core_lib_flags(${core_lib_target} ${_board_id})
+
+ # Link Core-Lib to executable target
+ if (TARGET ${_target_name})
+ target_link_libraries(${_target_name} PUBLIC "${core_lib_target}")
+ endif ()
+ endif ()
+
+endfunction()
diff --git a/cmake/Platform/Targets/ExecutableTarget.cmake b/cmake/Platform/Targets/ExecutableTarget.cmake
new file mode 100644
index 0000000..31f4209
--- /dev/null
+++ b/cmake/Platform/Targets/ExecutableTarget.cmake
@@ -0,0 +1,50 @@
+#=============================================================================#
+# Adds/Creates an Arduino-Executable target with the given name,
+# using the given board ID and source files.
+# _target_name - Name of the target (Executable) to create.
+# _board_id - ID of the board to bind to the target (Each target can have a single board).
+# _src_files - List of source file (Could also be headers for code-inspection in some IDEs)
+# to create the executable from, just like it's done with a standard executable.
+#=============================================================================#
+function(add_arduino_executable _target_name _board_id _src_files)
+
+ add_executable(${_target_name} "${_src_files}")
+ # Always add board's core lib
+ add_arduino_core_lib(${_target_name} "${_board_id}")
+ # Add compiler and linker flags
+ set_executable_target_flags(${_target_name} "${_board_id}")
+
+ set(target_path "${CMAKE_CURRENT_BINARY_DIR}/${_target_name}")
+
+ # Create EEP object file from build's ELF object file
+ add_custom_command(TARGET ${_target_name} POST_BUILD
+ COMMAND ${CMAKE_OBJCOPY}
+ ARGS ${compiler_objcopy_eep_flags}
+ ${target_path}.elf
+ ${target_path}.eep
+ COMMENT "Generating EEP image"
+ VERBATIM)
+
+ # Convert firmware image to ASCII HEX format
+ add_custom_command(TARGET ${_target_name} POST_BUILD
+ COMMAND ${CMAKE_OBJCOPY}
+ ARGS ${compiler_elf2hex_flags}
+ ${target_path}.elf
+ ${target_path}.hex
+ COMMENT "Generating HEX image"
+ VERBATIM)
+
+ # Required for avr-size
+ get_board_property("${_board_id}" build.mcu board_mcu)
+ set(avr_size_script
+ "${ARDUINO_CMAKE_TOOLCHAIN_DIR}/Platform/Other/FirmwareSizeCalculator.cmake")
+
+ add_custom_command(TARGET ${_target_name} POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -DFIRMWARE_IMAGE=${target_path}.elf -DEEPROM_IMAGE=${target_path}.eep
+ -DMCU=${board_mcu} -DAVRSIZE_PROGRAM=${ARDUINO_CMAKE_AVRSIZE_PROGRAM}
+ -P "${avr_size_script}"
+ COMMENT "Calculating ${_target_name} size"
+ VERBATIM)
+
+endfunction()
diff --git a/cmake/Platform/Targets/PlatformLibraryTarget.cmake b/cmake/Platform/Targets/PlatformLibraryTarget.cmake
new file mode 100644
index 0000000..262d8e3
--- /dev/null
+++ b/cmake/Platform/Targets/PlatformLibraryTarget.cmake
@@ -0,0 +1,57 @@
+#=============================================================================#
+# Looks for any platform libraries (Resolved earlier when platform has been initialized)
+# within the given sources and returns them in a list.
+# _sources - Source and header files to search dependent platform libraries in.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - List of found dependent platform libraries.
+#=============================================================================#
+function(find_dependent_platform_libraries _sources _return_var)
+
+ foreach (source ${_sources})
+ get_source_file_included_headers(${source} source_includes WE)
+ list(APPEND included_headers_names ${source_includes})
+ endforeach ()
+ list(REMOVE_DUPLICATES included_headers_names)
+
+ get_platform_libraries_from_names("${included_headers_names}" dependent_libs)
+ set(${_return_var} ${dependent_libs} PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Creates a platform library target with the given name.
+# _library_name - Name of the library target to create, usually the platform library name.
+# _board_id - Board ID associated with the linked Core Lib.
+#=============================================================================#
+function(_add_platform_library _library_name _board_id)
+
+ find_header_files("${ARDUINO_CMAKE_PLATFORM_LIBRARIES_PATH}/${_library_name}/src" lib_headers)
+ find_source_files("${ARDUINO_CMAKE_PLATFORM_LIBRARIES_PATH}/${_library_name}/src" lib_source_files)
+ set(lib_sources ${lib_headers} ${lib_source_files})
+
+ _add_arduino_cmake_library(${_library_name} ${_board_id} "${lib_sources}")
+
+endfunction()
+
+#=============================================================================#
+# Links the given platform library target to the given target, be it an executable or another library.
+# _target_name - Name of the target to link against.
+# _library_name - Name of the library target to create, usually the platform library name.
+# _board_id - Board ID associated with the linked Core Lib.
+#=============================================================================#
+function(link_platform_library _target_name _library_name _board_id)
+
+ if (NOT TARGET ${_target_name})
+ message(FATAL_ERROR "Target ${_target_name} doesn't exist - It must be created first!")
+ endif ()
+
+ if (NOT TARGET ${_library_name})
+ _add_platform_library(${_library_name} ${_board_id})
+ endif ()
+
+ get_core_lib_target_name(${_board_id} core_lib_target)
+ _link_arduino_cmake_library(${_target_name} ${_library_name}
+ PUBLIC
+ BOARD_CORE_TARGET ${core_lib_target})
+
+endfunction()
diff --git a/cmake/Platform/Targets/UploadTarget.cmake b/cmake/Platform/Targets/UploadTarget.cmake
new file mode 100644
index 0000000..aeee595
--- /dev/null
+++ b/cmake/Platform/Targets/UploadTarget.cmake
@@ -0,0 +1,21 @@
+#=============================================================================#
+# Uploads the given target to te connected Arduino board using the given board ID and port.
+# _target_name - Name of the target (Executable) to upload.
+# _board_id - Target's bounded board ID.
+# _port - Serial port on the host system used to upload/flash the connected Arduino board.
+#=============================================================================#
+function(upload_arduino_target _target_name _board_id _port)
+
+ if ("${_target_name}" STREQUAL "")
+ message(FATAL_ERROR "Can't create upload target for an invalid target ${_target_name}")
+ endif ()
+
+ set_upload_target_flags("${_target_name}" "${_board_id}" "${_port}" upload_args)
+
+ add_custom_command(TARGET ${_target_name} POST_BUILD
+ COMMAND ${ARDUINO_CMAKE_AVRDUDE_PROGRAM}
+ ARGS ${upload_args}
+ COMMENT "Uploading ${_target_name} target"
+ DEPENDS ${_target_name})
+
+endfunction()
\ No newline at end of file
diff --git a/cmake/Platform/Utilities/ListUtils.cmake b/cmake/Platform/Utilities/ListUtils.cmake
new file mode 100644
index 0000000..75359dc
--- /dev/null
+++ b/cmake/Platform/Utilities/ListUtils.cmake
@@ -0,0 +1,10 @@
+#=============================================================================#
+# Replaces an element at the given index with another element in the given list.
+# _list - List to replace one its' elements.
+# _index - Index of the element to replace.
+# Must not be negative or greater than 'list_length'-1.
+#=============================================================================#
+macro(list_replace _list _index _new_element)
+ list(REMOVE_AT ${_list} ${_index})
+ list(INSERT ${_list} ${_index} "${_new_element}")
+endmacro()
diff --git a/cmake/Platform/Utilities/MathUtils.cmake b/cmake/Platform/Utilities/MathUtils.cmake
new file mode 100644
index 0000000..f3cbc1c
--- /dev/null
+++ b/cmake/Platform/Utilities/MathUtils.cmake
@@ -0,0 +1,21 @@
+#=============================================================================#
+# Increments the given integer by the requested amount.
+# Note that this is a macro so it applies directly on the calling scope.
+# _integer_var - Name of the integer variable to increment.
+# _increment - Amount to increment the given integer by.
+# Returns - Incremented integer. Return value isn't required since it's a macro.
+#=============================================================================#
+macro(increment_integer _integer_var _increment)
+ math(EXPR ${_integer_var} "${${_integer_var}}+${_increment}")
+endmacro()
+
+#=============================================================================#
+# Decrements the given integer by the requested amount.
+# Note that this is a macro so it applies directly on the calling scope.
+# _integer_var - Name of the integer variable to decrement.
+# _decrement - Amount to decrement the given integer by.
+# Returns - Decremented integer. Return value isn't required since it's a macro.
+#=============================================================================#
+macro(decrement_integer _integer_var _decrement)
+ math(EXPR ${_integer_var} "${${_integer_var}}-${_decrement}")
+endmacro()
diff --git a/cmake/Platform/Utilities/PlatformLibraryUtils.cmake b/cmake/Platform/Utilities/PlatformLibraryUtils.cmake
new file mode 100644
index 0000000..1056353
--- /dev/null
+++ b/cmake/Platform/Utilities/PlatformLibraryUtils.cmake
@@ -0,0 +1,40 @@
+#=============================================================================#
+# Checks whether the given name resolves to one of the platform libraries' names.
+# _name - Name to check.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - True if name resolves to a platform library's name, false otherwise.
+#=============================================================================#
+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 ()
+ set(lib_found FALSE)
+ endif ()
+
+ set(${_return_var} ${lib_found} PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Retrieves all registered platform library names from the given list of names,
+# which usually resolves to names of headers included by a source file.
+# _names - List of names that possibly contain a registered platform library's name.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - List of retrieved platform libraries names.
+#=============================================================================#
+function(get_platform_libraries_from_names _names _return_var)
+
+ foreach (name ${_names})
+ # Can't use `is_platform_library` function since it returns just a boolean
+ string(TOLOWER "${name}" name_lower)
+ if ("${name_lower}" IN_LIST ARDUINO_CMAKE_PLATFORM_LIBRARIES)
+ list(APPEND platform_libs "${name}")
+ endif ()
+ endforeach ()
+
+ set(${_return_var} ${platform_libs} PARENT_SCOPE)
+
+endfunction()
+
diff --git a/cmake/Platform/Utilities/PropertyUtils.cmake b/cmake/Platform/Utilities/PropertyUtils.cmake
new file mode 100644
index 0000000..2adc96c
--- /dev/null
+++ b/cmake/Platform/Utilities/PropertyUtils.cmake
@@ -0,0 +1,31 @@
+include(PropertyValueResolver)
+
+#=============================================================================#
+# Gets the name of the property from the given property-line (Combining both name and value).
+# Name of the property is the string usually located before the '=' char.
+# _property - Full property as a property-line.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - Extracted property name from the given property-line.
+#=============================================================================#
+function(_get_property_name _property _return_var)
+
+ string(REGEX MATCH "^[^=]+" property_name "${_property}")
+ set(${_return_var} "${property_name}" PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Gets the value of the property from the given property-line (Combining both name and value).
+# Value of the property is the string usually located after the '=' char.
+# _property - Full property as a property-line.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - Extracted property value from the given property-line.
+#=============================================================================#
+function(_get_property_value _property _return_var)
+
+ string(REGEX REPLACE "^[^=]+=(.*)" "\\1" property_value "${_property}")
+ string(STRIP "${property_value}" property_value)
+
+ set(${_return_var} "${property_value}" PARENT_SCOPE)
+
+endfunction()
diff --git a/cmake/Platform/Utilities/StringUtils.cmake b/cmake/Platform/Utilities/StringUtils.cmake
new file mode 100644
index 0000000..08a9de2
--- /dev/null
+++ b/cmake/Platform/Utilities/StringUtils.cmake
@@ -0,0 +1,104 @@
+#=============================================================================#
+# Converts the given language string to a format recognized by CMake, thus 'compliant'.
+# Language means programming language, such as 'C++', which gets converted to 'CXX'.
+# _language - Language to get its' CMake-Compliant version.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - CMake-Compliant version of the given language.
+# If input language is invalid, an error is printed.
+#=============================================================================#
+function(get_cmake_compliant_language_name _language _return_var)
+
+ string(TOLOWER "${_language}" language)
+ if ("${language}" STREQUAL "s" OR "${language}" STREQUAL "asm")
+ set(language ASM)
+ elseif ("${language}" STREQUAL "cpp" OR "${language}" STREQUAL "cxx" OR
+ "${language}" STREQUAL "c++")
+ set(language CXX)
+ elseif ("${language}" STREQUAL "c")
+ set(language C)
+ else ()
+ message(SEND_ERROR "Invalid language given, must be C, C++ or ASM")
+ endif ()
+
+ set(${_return_var} ${language} PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Converts the given language string to a format recognized by Arduino, thus 'compliant'.
+# Language means programming language, such as 'C++', which gets converted to 'cpp'.
+# _language - Language to get its' Arduino-Compliant version.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - Arduino-Compliant version of the given language.
+# If input language is invalid, an error is printed.
+#=============================================================================#
+function(get_arduino_compliant_language_name _language _return_var)
+
+ string(TOLOWER "${_language}" language)
+ if ("${language}" STREQUAL "s" OR "${language}" STREQUAL "asm")
+ set(language S) # Intentionally upper-case
+ elseif ("${language}" STREQUAL "cpp" OR "${language}" STREQUAL "cxx" OR
+ "${language}" STREQUAL "c++")
+ set(language cpp)
+ elseif ("${language}" STREQUAL "c")
+ set(language c)
+ else ()
+ message(SEND_ERROR "Invalid language given, must be C, C++ or ASM")
+ endif ()
+
+ set(${_return_var} ${language} PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Creates a name valid for Core libraries using the given board ID.
+# The created name is lower-case 'Board-ID_core_lib'.
+# _board_id - Board ID to create core library target for.
+# _return_var - Name of variable in parent-scope holding the return value.
+# Returns - Name of the core library target for the given board.
+#=============================================================================#
+function(get_core_lib_target_name _board_id _return_var)
+
+ string(REPLACE "." "_" board_id "${_board_id}")
+ set(core_lib_target_name "${board_id}_core_lib")
+ string(TOLOWER "${core_lib_target_name}" core_lib_target_name)
+
+ set(${_return_var} ${core_lib_target_name} PARENT_SCOPE)
+
+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.
+# Returns - String containing input name without possible file extension.
+#=============================================================================#
+function(get_name_without_file_extension _input_string _return_var)
+
+ string(REGEX MATCH "${ARDUINO_CMAKE_NAME_WE_REGEX_PATTERN}" match "${_input_string}")
+ set(${_return_var} ${CMAKE_MATCH_1} PARENT_SCOPE)
+
+endfunction()
+
+#=============================================================================#
+# Converts a given string 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.
+# Returns - PascalCase converted string.
+#=============================================================================#
+function(convert_string_to_pascal_case _input_string _return_var)
+
+ # Convert 1st letter to upper case
+ string(SUBSTRING ${_input_string} 0 1 first_letter)
+ string(TOUPPER ${first_letter} first_letter_upper)
+
+ # Convert remaining letters to lower case
+ string(SUBSTRING ${_input_string} 1 -1 remaining_letters)
+ string(TOLOWER ${remaining_letters} remaining_letters_lower)
+
+ # Combine first letter with remaining letters
+ string(APPEND combined_string ${first_letter_upper} ${remaining_letters_lower})
+
+ set(${_return_var} ${combined_string} PARENT_SCOPE)
+
+endfunction()
diff --git a/docs/Getting Started/Building Project.md b/docs/Getting Started/Building Project.md
new file mode 100644
index 0000000..36adb92
--- /dev/null
+++ b/docs/Getting Started/Building Project.md
@@ -0,0 +1,17 @@
+As detailed in [[Generating CMake]], the project binaries are built using a **build tool** correspondent to the CMake generator used.
+
+Each tool has its own usage so to fully utilize the tool at your hand please refer to its' documentation.
+However, since **make** is the most popular tool at the moment (**ninja** is extremely recommended to use instead), our docs include a section dedicated to **make** - [[Building With Make]].
+
+Although different, most of the tools can be executed from the command-line by simply executing their binary in the appropriate *working directory*. Where is that directory? Generally it's the build directory used by CMake to output generated files to.
+
+### Uploading Program
+
+Building the project is an important step but probably not the one with the most impact.
+
+Unlike desktop applications, Arduino programs can't be run directly on the host PC, but intend to run on specific hardware boards instead.
+To make that happen, an **"Upload"** process should occur, where the built program binary is uploaded/transferred to the hardware board, usually through a USB.
+
+**Arduino-CMake** takes care of that by exposing an API for uploading the program.
+It should be **the last CMake instruction** in the `CMakeLists.txt` file, **after** the instruction to create the program's executable. This instruction will initiate an upload process at the end of each build.
+The complete docs on how to use the API can be found in [[Uploading Program]].
\ No newline at end of file
diff --git a/docs/Getting Started/Creating First Program.md b/docs/Getting Started/Creating First Program.md
new file mode 100644
index 0000000..67fb32f
--- /dev/null
+++ b/docs/Getting Started/Creating First Program.md
@@ -0,0 +1,51 @@
+Creating a program with **Arduino-CMake** is ridiculously easy.
+
+First make sure you've fulfilled the requirements for your OS by installing all necessary programs.
+Then download the source/assets and extract them to a directory on your file system.
+
+It's important to understand that **Arduino-CMake** is simply a CMake toolchain.
+What that means to the user is that it should only include a single `.cmake` file in order to use the framework.
+However, the framework itself is not that simple and consists of many additional CMake scripts required for it to work, so to fully setup the toolchain you should do one of the followings:
+
+* Copy the directory extracted earlier to your project's directory
+* Have the path (absolute or relative) to the extracted directory "at hand"
+
+Then, you should create a `CMakeLists.txt` file in your project's main directory.
+A simple example of such file could be:
+
+```cmake
+# Define CMake's minimum version (must-do) and the project's name and supported languages
+cmake_minimum_required(VERSION 3.8)
+project(Hello_World LANGUAGES C CXX ASM)
+
+# Call a framework utility function, passing it information about the hardware board that will
+# be used - This function returns a structure known only to the framework
+get_board_id(board_id [BOARD])
+
+# Create an executable suitable for the Arduino firmware using CMake-style target-creation
+add_arduino_executable(Hello_World ${board_id} helloWorld.cpp)
+# Upload the created target through a connected Serial Port (Where your board is connected to)
+upload_arduino_target(Hello_World "${board_id}" [PORT])
+```
+
+Where:
+
+* `helloWorld.cpp` is a **C++** source file which looks exactly like the main `.ini` file used by **Arduino IDE**.
+* `[BOARD]` is the name of the Arduino board used to run the program.
+* `[PORT]` is the port at which your Arduino micro-controller is connected to accept uploads.
+
+Next step is to run cmake, passing it the following argument: `-DCMAKE_TOOLCHAIN_FILE=[ARDUINO_CMAKE_PATH]/Arduino-Toolchain.cmake`.
+`[ARDUINO_CMAKE_PATH]` is the path to the framework's directory (Absolute or Relative).
+
+More information on CMake and how to use it is available in the [[Generating CMake]] section.
+
+Running CMake has generated build-ready output, so the only thing's left is to actually build it.
+For this you'll use a build tool matching the generator you've ran CMake with, such as **make** if your generator was **Unix Makefiles**.
+Building the project can be as simple as calling **make** from the project's binary directory using a cmd, clicking a 'Build' button in the IDE, or something more complicated - depending on your tool of choice.
+
+More information on the build process is available in [[Building Project]].
+
+Once built, the program might also be uploaded to the connected hardware board - Depending on whether a call to the `upload_arduino_target` function exists.
+If it doesn't, the program will simply be built, creating the appropriate `.hex` file.
+
+**That's it!**
\ No newline at end of file
diff --git a/docs/Getting Started/Generating CMake.md b/docs/Getting Started/Generating CMake.md
new file mode 100644
index 0000000..602482c
--- /dev/null
+++ b/docs/Getting Started/Generating CMake.md
@@ -0,0 +1,45 @@
+CMake generation is the process that generates build-ready files that could later be built by the build toolchain. It occurs on every CMake run.
+The process can be triggered directly by the user by running a cmake tool (such as cmake), or by the build toolchain when it detects changes in the source tree.
+
+### Generators
+
+The input of a generation process is the generator to use.
+There's a variety of generators available, each having it's unique output type.
+For example, the **Unix Makefiles** generator will generate make-files, whereas the **Ninja** generator will generate ninja build files.
+
+However, not all generators can be used on all OSs.
+While technically it's still possible and the output will be valid and "buildable", some generators just don't make sense to use on such platforms as there's no supported toolchain available for that OS.
+A good example is Microsoft Windows, as you'll read next.
+
+#### Windows Generators
+
+The default generator on Microsoft Windows is the **Visual Studio xx** generator, where `xx` is a version of **Visual Studio**. It's equivalent to the C++ versions supported by the **Microsoft Visual C++ Compiler**.
+This generator creates **Visual Studio** solution files, which can later be used in the **Visual Studio** IDE and built by the **Microsoft Visual C++ Compiler**.
+
+However, the Arduino toolchain is based on a derivative of the **gcc** compiler, which theoretically exists only for Unix systems. To use **gcc** on Windows, one should use toolchains like **MinGW**.
+
+So to use the **Arduino-CMake** framework on Microsoft Windows, you'll need to be equipped with an appropriate toolchain and use one of the following generators:
+
+* `MSYS Makefiles` - Generates MSYS `make` files
+* `Unix Makefiles` - Generates standard UNIX `make` files
+* `MinGW Makefiles` - Generates MinGW `make` files (best fit for **Windows**).
+* `Ninja` - Generates ninja build files (Same as `MinGW Makefiles` but uses the **ninja** build tool instead)
+* `CodeBlocks - Unix Makefiles` - Generates CodeBlocks project files (for the **CodeBlocks** IDE).
+* `Eclipse CDT4 - Unix Makefiles` - Generates Eclipse CDT 4.0 project files (for the **Eclipse** IDE).
+
+#### MinGW Generator
+
+Even though it's probably the best generator to use on Microsoft Windows, it has a drawback which must be addressed before using it.
+
+The MinGW generator encounters an error when the `sh.exe` binary exists in the `System Path`.
+In order to solve this issue, you should do the following:
+
+1. Remove `${ARDUINO_SDK_PATH}/hardware/tools/avr/utils/bin` from the `System Path`.
+
+2. Run CMake with the following argument:
+
+ ```
+ -DCMAKE_MAKE_PROGRAM=${ARDIUNO_SDK_PATH}/hardware/tools/avr/utils/bin/make.exe
+ ```
+
+Then cmake will be generated as expected.
diff --git a/docs/Getting Started/Installation.md b/docs/Getting Started/Installation.md
new file mode 100644
index 0000000..aef08ab
--- /dev/null
+++ b/docs/Getting Started/Installation.md
@@ -0,0 +1,83 @@
+Suggested by its' name, **Arduino-CMake** requires **Arduino** and **CMake** to be installed on your system.
+There may be additional requirements depending on your OS of choice.
+
+Listed below are the steps required to install **Arduino-CMake** for each supported OS:
+
+### Linux
+
+Manually install the following packages, preferably with your package manager:
+
+* `gcc-avr` - AVR GNU GCC compiler
+* `binutils-avr` - AVR binary tools
+* `avr-libc` - AVR C library
+* `avrdude` - Firmware uploader
+
+Then, download and install the [Arduino SDK](https://www.arduino.cc/en/Main/Software).
+It's considered best practice to install it to `/usr/share` as this is where **Arduino-CMake** looks for it by default, however, it is not mandatory.
+
+At last, install [CMake](https://cmake.org/download/) if it's not already installed.
+
+### OS X
+
+Though similar to **Linux** since it's also a *nix system, installing **Arduino-CMake** on **Mac** is much easier.
+The **Arduino SDK** bundles everything required to setup the environment, including the toolchains.
+
+Start with downloading the [Arduino SDK](https://www.arduino.cc/en/Main/Software) and copying it to `Applications`.
+Then, also install the `FTDIUSBSerial` (for FTDI USB Serial) driver.
+
+Now download **CMake** if it's not already installed, and install `cmake-*.pkg`.
+
+> Note: Make sure to click on `Install Command Line Links`
+
+### Windows
+
+First, download and install the [Arduino SDK](https://www.arduino.cc/en/Main/Software).
+It's considered best practice to install it to `Program Files` as suggested by the installer as this is where **Arduino-CMake** searches for it by default, however, it is not mandatory.
+
+Next, install [CMake](https://cmake.org/download/) if it's not already installed.
+
+At last you need to make sure you have a build tool to build cmake's generated output with, such as **make**.
+Most of these tools belong to the GNU and work only on Linux, but ports to Windows are available as well.
+So, for example, if your build tool is **make**, it will require you to install either:
+
+1. MinGW
+2. Cygwin
+
+If you're not familiar with these, they are ports of the **GNU Make** toolchain for the Windows OS (Cygwin is a lot more than that but it doesn't matter in this context).
+
+**Note:** Make sure to add **make** to the system's path, otherwise you'll have trouble building programs.
+
+### Preparing Environment
+
+After installing all required prerequisites as described in the sections above, you should ensure your environment is ready for **Arduino-CMake**.
+
+#### Arduino SDK Path
+
+Assuming you've already set required paths (such as **gcc** or **MinGW**) in the environmental variable `PATH`, the next thing you must do is to find the path of the Arduino SDK.
+By default, **Arduino-CMake** looks for the Arduino SDK in the following paths, divided by OSs:
+
+##### Linux
+
+* `/usr/share/arduino*`
+* `/opt/local/arduino*`
+* `/opt/arduino*`
+* `/usr/local/share/arduino*`
+
+##### OS X/MacOS
+
+* `~/Applications`
+* `/Applications`
+* `/Developer/Applications`
+* `/sw`
+* `/opt/local`
+
+##### Windows
+
+* `C:/Program Files (x86)/Arduino`
+* `C:/Program Files/Arduino`
+
+##### Setting Custom Path
+
+If your SDK isn't located in any of the above paths, you should set an environment variable with the name of `ARDUINO_SDK_PATH`, pointing to the desired custom location.
+
+> Note that in order to persist your environmental variables you may have to perform some extra steps, depending on your OS.
\ No newline at end of file
diff --git a/docs/Home.md b/docs/Home.md
new file mode 100644
index 0000000..3490b53
--- /dev/null
+++ b/docs/Home.md
@@ -0,0 +1,15 @@
+Arduino-CMake, as the name suggests, combines the best of both worlds:
+
+1. [Arduino](https://www.arduino.cc/)
+2. [CMake](https://cmake.org/)
+
+It is a simple solution to enable developers develop **Arduino** programs using their favorite IDEs.
+
+While there's nothing wrong with the **Arduino IDE** that comes along with the **Arduino SDK**, many developers feel like it's missing some valuable features other IDEs do have.
+As it turns out, the **Arduino SDK** also includes the Arduino toolchain - meaning it could be built using a build system that respects that, such as **CMake**.
+
+Why CMake?
+Because it's entirely cross-platform, it's modern, but most importantly - It's extremely extensible yet so easy to learn and use!
+
+If that's your first time here, you probably should head to the **Getting Started** section.
+If you want to read further about the API or even the internals of the framework - Documentation is available under the **Usage** and **Developers** sections.
\ No newline at end of file
diff --git a/docs/LICENSE.md b/docs/LICENSE.md
new file mode 100644
index 0000000..6df7f8b
--- /dev/null
+++ b/docs/LICENSE.md
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Arduino CMake
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/docs/Troubleshooting/Other.md b/docs/Troubleshooting/Other.md
new file mode 100644
index 0000000..343ab02
--- /dev/null
+++ b/docs/Troubleshooting/Other.md
@@ -0,0 +1,17 @@
+This page refers to various issues that don't have any specific category.
+
+### Error: attempt to use poisoned "SIG_USART0_RECV"
+
+If you get the following error:
+
+```
+/usr/share/arduino/hardware/arduino/cores/arduino/HardwareSerial.cpp:91:41: error: attempt to use poisoned "SIG_USART0_RECV"
+/usr/share/arduino/hardware/arduino/cores/arduino/HardwareSerial.cpp:101:15: error: attempt to use poisoned "SIG_USART0_RECV"
+/usr/share/arduino/hardware/arduino/cores/arduino/HardwareSerial.cpp:132:15: error: attempt to use poisoned "SIG_USART1_RECV"
+/usr/share/arduino/hardware/arduino/cores/arduino/HardwareSerial.cpp:145:15: error: attempt to use poisoned "SIG_USART2_RECV"
+/usr/share/arduino/hardware/arduino/cores/arduino/HardwareSerial.cpp:158:15: error: attempt to use poisoned "SIG_USART3_RECV"
+
+```
+
+You've probably recently upgraded **avr-libc** to the latest version, which has deprecated the use of these symbols. There is an [Arduino Patch](http://arduino.googlecode.com/issues/attachment?aid=9550004000&name=sig-patch.diff&token=R2RWB0LZXQi8OpPLsyAdnMATDNU%3A1351021269609) which fixes these error.
+You can read more about this bug here: [Arduino Bug ISSUE 955](http://code.google.com/p/arduino/issues/detail?id=955).
\ No newline at end of file
diff --git a/docs/Troubleshooting/Undefined References.md b/docs/Troubleshooting/Undefined References.md
new file mode 100644
index 0000000..e93633b
--- /dev/null
+++ b/docs/Troubleshooting/Undefined References.md
@@ -0,0 +1,16 @@
+This page lists all known issues regarding the `undefined references` issue which occurs during project linkage.
+
+### undefined reference to '`__cxa_pure_virtual`'
+
+An easy fix is to add the following to your program's main source file:
+
+```c
+extern "C" void __cxa_pure_virtual(void);
+void __cxa_pure_virtual(void) { while(1); }
+```
+
+The contents of the `__cxa_pure_virtual` function can be any error handling code.
+This function will be called whenever a pure virtual function is called.
+
+Also see [What is the purpose of cxa_pure_virtual](http://stackoverflow.com/questions/920500/what-is-the-purpose-of-cxa-pure-virtual)
+
diff --git a/docs/Usage/Advanced/Options.md b/docs/Usage/Advanced/Options.md
new file mode 100644
index 0000000..9dbb27c
--- /dev/null
+++ b/docs/Usage/Advanced/Options.md
@@ -0,0 +1,10 @@
+Options in CMake are structures that represent boolean values, indicating whether something is `ON` or `OFF`.
+The following table describes all the options supported by **Arduino-CMake**, and their meaning:
+
+| Option Name | Description | Default Value |
+| -------------------------------------------- | ------------------------------------------------------------ | ------------- |
+| USE_DEFAULT_PLATFORM_IF_NONE_SET | Whether to use Arduino as default platform if none is manually set | ON |
+| USE_CUSTOM_PLATFORM_HEADER | Whether to expect and use a custom-supplied platform header, skipping the selection algorithm | OFF |
+| USE_ARCHLINUX_BUILTIN_SUPPORT | Whether to use Arduino CMake's built-in support for the arch Linux distribution | ON |
+| CONVERT_SKETCHES_IF_CONVERTED_SOURCES_EXISTS | Whether to convert sketches to source files even if converted sources already exist - Force conversion | OFF |
+
diff --git a/docs/Usage/Build Flags.md b/docs/Usage/Build Flags.md
new file mode 100644
index 0000000..5e71515
--- /dev/null
+++ b/docs/Usage/Build Flags.md
@@ -0,0 +1,26 @@
+The CMake build system has many ways to set build flags (compiler and/or linker flags), which can help drive the build. However, we generally recommends not to do so. Why?
+
+**Arduino-CMake** analyzes the platform's properties files internally, which usually specify the build flags that should be used in every build, as recommended by the platform's vendors (Arduino themselves when using the original Arduino platform).
+Moreover, the build flags are often separated to flags per language, meaning that `.c` files don't get the same flags as `.cpp` flags.
+What it means is that the framework already does all the heavy lifting for you, covering all recommended build flags - Users shouldn't modify those flags, nor add new ones, unless they really know what they're doing.
+
+### Setting Custom Flags
+
+**Warning:** Before reading this, **please** carefully read the **passage above**.
+
+#### Compiler Flags
+
+In modern CMake we set compiler flags on targets, not globally as it used to be.
+To do so, we have number of ways:
+
+1. Use CMake's `target_compile_options` function, passing it an existing target's name and a list of options, which are in fact build flags.
+2. Combine `target_compile_options` with CMake's [generator expressions](https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html) to set flags per language, just as **Arduino-CMake** does.
+
+However, if you still desire to set flags globally, it can be done by forcefully setting the `CMAKE_[LANG]_BUILD_FLAGS` cache variable, where `LANG` is the specific language to set flags for.
+e.g `set(CMAKE_[LANG]_BUILD_FLAGS "-g" CACHE STRING "" FORCE)`
+
+#### Linker Flags
+
+Despite CMake's modern way to set compile flags on specific targets, linker flags don't enjoy such feature.
+To set linker flags, one should forcefully set the `CMAKE_EXE_LINKER_FLAGS` cache variable.
+Since there can be only a single instance of linker flags, it's recommended to either leave them as set by **Arduino-CMake** (Platform's vendors more accurately) or use only a single executable target in the project.
\ No newline at end of file
diff --git a/docs/Usage/Building With Make.md b/docs/Usage/Building With Make.md
new file mode 100644
index 0000000..c6559e3
--- /dev/null
+++ b/docs/Usage/Building With Make.md
@@ -0,0 +1,22 @@
+**make** is a famous build tool used to build `makefiles`.
+It is a part of **gnu**, specifically **gcc** (or **MinGW** if you're on Microsoft Windows), so you must have that installed first in order to use it.
+
+The example below demonstrates how **make** can be used to build your project's binaries, along with creating a dedicated build directory and generating CMake:
+
+```bash
+mkdir build
+cd build
+cmake -GUnix-Makefiles ..
+make
+```
+
+Where:
+
+* `build` is a sub-directory under the project's main directory, created to store CMake's output/artifacts.
+* The `cmake ..` command generates project's output (called on the project's main directory), which is actually `makefiles` used later by make.
+* The `make` command builds the project using the `makefiles` in the `build` directory.
+
+> Note: The example above is written for *nix systems, mostly Linux.
+> Syntax on Microsoft Windows is similar, yet may differ at some points, depending on the terminal at hand.
+
+For more info on the **make** tool please see [make docs](https://www.gnu.org/software/make/manual/make.html).
\ No newline at end of file
diff --git a/docs/Usage/Creating Program.md b/docs/Usage/Creating Program.md
new file mode 100644
index 0000000..7f60be3
--- /dev/null
+++ b/docs/Usage/Creating Program.md
@@ -0,0 +1,25 @@
+Creating a program or an *executable* is probably the most important thing in any programming context, and Arduino isn't different.
+
+> Some may refer to an Arduino executable as a *Firmware*, since that's the only code that lives on the board
+
+Doing so in **Arduino-CMake** is quite easy, requiring just a call to a single function: `add_arduino_executable`.
+The function has the nature of CMake-target functions, such as `add_executable` (Which creates an executable runnable by the host OS), so for those familiar with the syntax - It's practically the same.
+It accepts the following parameters:
+
+| Order | Name | Description | Required? |
+| ----- | ------------ | ------------------------------------------------------------ | --------- |
+| 1st | _target_name | Target's name as it will be registered by CMake. | Yes |
+| 2nd | _board_id | Hardware Board's ID as retrieved by the `get_board_id` function. | Yes |
+| 3rd | _srcs | List of source files to include in the executable target. | Yes |
+
+Let's look at an example which creates an executable/program consisting of 2 source files and a header:
+
+```cmake
+get_board_id(board_id uno)
+add_arduino_executable(my_target_name ${board_id} my_source.cpp SomeClass.h SomeClass.cpp)
+```
+
+Note that a call to `get_board_id` is required to pass a valid `_board_id` to the function!
+For those that aren't familiar with CMake - Also note how you can pass an infinite list of source files separated by a whitespace (Might be a line-feed as well as a space). This is because it's the last argument of the function.
+
+The next step is to learn how to upload the executable to the hardware board - See [[Uploading Program]].
\ No newline at end of file
diff --git a/docs/Usage/Examples.md b/docs/Usage/Examples.md
new file mode 100644
index 0000000..1351760
--- /dev/null
+++ b/docs/Usage/Examples.md
@@ -0,0 +1,70 @@
+## Arduino Examples
+
+One of Arduino SDK's most attractive features is examples.
+Examples provide an easy way to learn Arduino programming, having the form of a complete, valid Arduino executable that could be uploaded to a hardware board.
+
+### Overview
+
+An Arduino Example consists of at least one source file, usually a sketch.
+
+All SDK's built-in examples reside under the `${ARDUINO_SDK_PATH}/examples` directory.
+Built-in examples are also divided into **Categories**, each prefixed with an indexing-number. e.g `01.Basics`.
+The example itself is actually a directory named after the example, containing all other files required by an example. These directories reside under the matching **Category**.
+
+For example, the **Blink** example has the following path: `${ARDUINO_SDK_PATH}/examples/01.Basics/Blink`
+Inside this directory, there's `Blink.ino` - The example's sketch.
+
+### Using Examples
+
+To use an example one should call the `add_arduino_example` function.
+It accepts the following parameters:
+
+| Order | Name | Description | Required? |
+| ----- | ------------- | ------------------------------------------------------------ | --------- |
+| 1st | _target_name | Target's name as it will be registered by CMake. | Yes |
+| 2nd | _board_id | Hardware Board's ID as retrieved by the `get_board_id` function. | Yes |
+| 3rd | _example_name | Name of the Arduino Example to use, case-insensitive. Name is expected to be a valid, existing example. | Yes |
+| - | CATEGORY _cat | Name of the category the example belongs to. It helps optimizing the search process to find the example in the SDK. Use only if name is accurate. | No |
+
+The example below shows how to use the **Blink** example:
+
+```cmake
+add_arduino_example(my_example_target_name ${board_id} Blink)
+```
+
+Assume that the board ID has been retrieved earlier and the executable target has already been created.
+
+### Arduino Library Examples
+
+Arduino libraries usually also have examples bundled with them, which are the same as Arduino Examples.
+There are a few differences between the 2 though:
+
+1. Arduino Library examples reside under the library's directory, usually under a sub-directory named **examples**.
+2. A library example will have more than one source file most of the times.
+
+Note that not all libraries have examples, and those that do can have more than one.
+
+The **Servo** library for example defines an example named **Knob**, which has the following path: `${ARDUINO_SDK_PATH}/libraries/Servo/examples/Knob`
+
+### Usage
+
+Arduino library examples are used the same as "standard" examples, except they define a different function.
+To use a library example, one should call the `add_arduino_library_example`, passing it the name of the library which the example belongs to and the example name itself.
+
+The function accepts following parameters:
+
+| Order | Name | Description |
+| ----- | --------------------- | ------------------------------------------------------------ |
+| 1st | _target_name | Target's name as it will be registered by CMake. |
+| 2nd | _board_id | Hardware Board's ID as retrieved by the `get_board_id` function. |
+| 3rd | _library_target_name | Name of an existing target registered to the library the example belongs to. It means the library should first be found by calling `find_arduino_library`. |
+| 4th | _library_name | Name of the library the example belongs to, case-insensitive. Name is expected to be a valid, existing example. |
+| 5th | _library_example_name | Name of the library example to use, case-insensitive. Name is expected to be a valid, existing example. |
+
+The example below shows how to use the **Knob** example of the **Servo** library:
+
+```cmake
+add_arduino_library_example(my_library_example_target Servo ${board_id} Knob)
+```
+
+Assume that the board ID has been retrieved earlier and the executable target has already been created.
\ No newline at end of file
diff --git a/docs/Usage/Libraries.md b/docs/Usage/Libraries.md
new file mode 100644
index 0000000..8347a23
--- /dev/null
+++ b/docs/Usage/Libraries.md
@@ -0,0 +1,102 @@
+One of Arduino's most important features, as with any development system, are libraries.
+Arduino has 3 different types of libraries, which can be merged just to 2:
+
+1. **Built-in Libraries** - Libraries included as part of the SDK or a custom platform.
+ These libraries conform to a certain format/standard determined by Arduino. For that reason they're also called "**Arduino Libraries**" in the **Arduino-CMake** terminology.
+ Besides, they consist of only sources - There are no pre-built binaries whatsoever.
+2. **User Libraries** - Libraries that were created by users, either directly or as a 3rd party.
+ These libraries don't have to conform to any standard. Although they can expose pre-built binaries, it's really not recommended to do so, but provide sources instead.
+
+Some of you have already noticed that **Arduino-CMake** takes an approach similar to CMake itself regarding the targets API, that is of course to ease the use of the framework.
+Libraries are no different. How?
+In general, to use a certain library in your CMake project you must follow the following procedure:
+
+1. Either find the library or create it yourself.
+ Finding a library *usually* means finding a pre-built binary matching the requirements of the host OS.
+2. Link the library target to some other target.
+
+> We've emphasized *usually* because as described earlier, Arduino libraries are almost always unbuilt sources. In our case, the library target will always be created and built by the project itself.
+
+**Arduino-CMake** takes a similar approach.
+The following passages relate to the different types of libraries and how to use them:
+
+### Built-in/Arduino Libraries
+
+These libraries have to be found at first, then linked to another target, preferably the executable target.
+The following example shows how the **Stepper, Servo** and **Ethernet** libraries are included in a project:
+
+```cmake
+find_arduino_library(stepper_lib Stepper ${board_id})
+link_arduino_library(my_target stepper_lib ${board_id})
+
+find_arduino_library(servo_lib Servo ${board_id})
+link_arduino_library(my_target servo_lib ${board_id})
+
+find_arduino_library(ethernet_lib Ethernet ${board_id})
+link_arduino_library(my_target ethernet_lib ${board_id})
+```
+
+Note that the example above assumes the `my_target` target has already been created earlier.
+Also, board's ID has been retrieved as well.
+
+### User/3rd Party Libraries
+
+These libraries have to be found at fist as well, however, the search "process" is done manually by the user.
+This is because there's nothing special that defines a user library, unlike Arduino Libraries.
+It's considered good practice to keep a user library's sources under the project's scope, especially if that library is created especially for the project. It also makes it easy to "find" it.
+
+Once found, the library should be ***created***. As explained above, the library isn't found like an Arduino library, thus no library target is created.
+Creating a library target is really straightforward since it requires just the CMake library API!
+To create a library, one would call the `add_library` function. Further info can be found at the CMake docs.
+
+Since the library is manually created using CMake's API, it also requires the user to manually specify include directories, so that other targets linking the library will have access to its' headers.
+This is done by calling the `target_include_directories` function, passing the name of the library target created earlier with `add_library`, a `PUBLIC` scope (So it will have effect during linkage) and the header directories themselves.
+e.g `target_include_directories(my_library_target PUBLIC include)` where `include` is the directory containing all public headers.
+
+At last, the library target should be linked to an existing target, just as you would with an Arduino library.
+
+The following is a list of common and recommended places where 3rd party libraries should be stored:
+
+1. Inside the project's root directory, under a sub-directory named after the library.
+ Example:
+
+ ```
+ |-Project Root
+ |-Library
+ |-include
+ |-Library.h
+ |-src
+ |-Library.c
+ ```
+
+2. Inside Arduino's built-in libraries directory, located at `${ARDUINO_SDK_PATH}/libraries`.
+ **Warning:** This is recommended only for libraries that follow the Arduino library format/standard!
+
+3. Inside the project's root directory, under a sun-directory named *dependencies* where all other 3rd party libraries are located.
+ **Note:** This is recommended only for 3rd party libraries.
+
+The following example shows how a 3rd party library named **Robotics** is included in the project:
+
+```cmake
+set(Robotics_lib_path ${CMAKE_SOURCE_DIR}/dependencies/Robotics-1.2)
+add_library(Robotics_lib STATIC ${Robotics_lib_path}/src/Robotics.c)
+target_include_directories(Robotics_lib PUBLIC ${Robotics_lib_path}/include)
+link_arduino_library(my_target Robotics_lib ${board_id})
+```
+
+Where `${CMAKE_SOURCE_DIR}` is the parent directory of the project's main `CMakeLists.txt` file.
+The directory structure of the example is as follows:
+
+```
+|-Project Root
+ |-dependencies
+ |-include
+ |-Robotics.h
+ |-src
+ |-Robotics.c
+ |-src
+ |-CMakeLists.txt
+```
+
+Note that the example above assumes the `my_target` target has already been created earlier.
+Also, board's ID has been retrieved as well.
\ No newline at end of file
diff --git a/docs/Usage/Sketches.md b/docs/Usage/Sketches.md
new file mode 100644
index 0000000..c90a6cb
--- /dev/null
+++ b/docs/Usage/Sketches.md
@@ -0,0 +1,48 @@
+**Arduino** has introduced a concept named **Sketches** - Meta-Projects that combine both the source file(s) and any info about used libraries or platform headers into a single structure, usually even a single file (Having the `.pde` or `.ino` extension).
+
+**Arduino-CMake** treats all source files as standard **C++** files (usually having the `.cpp` extension), as this is the nature of CMake.
+It means of course that Sketches can't be supported out-of-the-box in their natural form.
+Nevertheless, **Arduino-CMake** **does** support sketches by converting them into `.cpp` source files, along with some extra missing information embedded in them.
+The converted source files are created within the project's source directory as detected by CMake (If required, further info can be found at CMake docs), and are automatically added to the target that required them.
+From the above, we can also infer that sketches can only be *used*, not *created*.
+
+### Using Sketches
+
+Sketches are used behind the scenes when working with [[Examples]], but can also be specified manually for a certain target.
+To do so, one would first create a target, usually an executable, and then should call the `target_sketches` function, which accepts the following parameters:
+
+| Order | Name | Description |
+| ----- | ------------- | ------------------------------------------------------------ |
+| 1st | _target_name | An existing target's name. |
+| 2nd | _board_id | Hardware Board's ID as retrieved by the `get_board_id` function. |
+| 3rd | _sketch_files | List of paths to sketch files which their converted sources should be added to the given target. |
+
+Let's see an example which adds 2 sketch files under our project's source directory to an executable target:
+
+```cmake
+add_arduino_executable(my_target_name ${_board_id} "") # Create an empty target
+target_sketches(my_target_name ${_board_id} sketch1.ino sketch2.pde)
+```
+
+Assume that the board ID has been retrieved earlier and the executable target has already been created.
+
+It's also important to note that the `target_sketches` API is really similar to CMake's `target_sources` API.
+
+#### Skipping Sketch Conversion
+
+The process of converting a sketch to a source can be lengthy in time, depending on the host PC, but more importantly - Will **override any changes** made to the converted source manually.
+To avoid this, **Arduino-CMake** does 2 things:
+
+1. Checks whether the converted source already exists - If it does, sketch isn't converted.
+2. Exports a CMake-Option to the user named `CONVERT_SKETCHES_IF_CONVERTED_SOURCES_EXISTS` which controls whether sketches should always be converted to sources, even if those exists. By default this options is set to **OFF**.
+
+### Header Resolving
+
+Sketches are quite a complex structure since they may include headers outside the scope of the project, maybe even an Arduino library, without any meta-information about them - It's all managed by the Arduino IDE internally.
+This makes things quite complicated for **Arduino-CMake**, as it must resolve those headers when adding a sketch to a target, providing the same functionality offered by Arduino IDE.
+
+Indeed, there's a resolving process executed for each sketch that should be added to a target:
+
+1. For a given sketch file - Iterate over all of its `#include` lines, extracting the header name (with extension such as `.h`).
+2. If the iterated header name matches any Arduino/Platform library - Find and link it to the target.
+3. Otherwise, validate the header is included in the target by searching for it in all of the target's include directories. If not found, a warning is displayed.
\ No newline at end of file
diff --git a/docs/Usage/Uploading Program.md b/docs/Usage/Uploading Program.md
new file mode 100644
index 0000000..1ff3458
--- /dev/null
+++ b/docs/Usage/Uploading Program.md
@@ -0,0 +1,68 @@
+After creating the program/executable, one would probably upload it to a specific hardware board.
+To upload a program in **Arduino-CMake** you should do several things:
+
+1. Find the port where the system thinks your board is connected to, such as `COMx` on Microsoft Windows or `/dev/ttyACMx` on Linux.
+
+2. Call the `upload_arduino_target` function.
+
+ > Although the target is always an executable, theoretically the function supports every CMake target.
+
+ The function accepts the following parameters:
+
+ | Order | Name | Description | Required? |
+ | ----- | ------------ | ------------------------------------------------------------ | --------- |
+ | 1st | _target_name | Name of the executable target to upload | Yes |
+ | 2nd | _board_id | Hardware Board's ID as retrieved by the `get_board_id` function. | Yes |
+ | 3rd | _port | Hardware board's port as identified in step 1 | Yes |
+
+Now let's see some examples of how to use it on different OSs, using the info above:
+
+**Linux:**
+
+```cmake
+upload_arduino_target(my_target_name "${board_id}" /dev/ttyACM0)
+```
+
+**Windows:**
+
+```cmake
+upload_arduino_target(my_target_name "${board_id}" COM3)
+```
+Assume that the board ID has been retrieved earlier and the executable target has already been created.
+
+### Uploading Multiple Targets
+
+**Arduino-CMake** allows uploading multiple targets simultaneously from a single project due to the scripted nature of CMake.
+This can be done by creating multiple executable targets, then uploading each to a different port.
+It can be useful for example to upload both **Client** and **Server** programs to separate boards in one go.
+
+### Serial Ports on Different OSs
+
+Each OS has its' own set of serial terminals, named differently.
+Below is the list of known serial terminals on each supported OS:
+
+#### Linux
+
+On Linux the serial device/port is named as follows:
+
+* `/dev/ttyUSBX`
+* `/dev/ttyACMX`
+
+Where `X` is the device number.
+
+`/dev/ttyACMX` is used for new **Uno** and **Mega** Arduinos, while `/dev/ttyUSBX` for the old ones.
+
+#### Mac OS X
+
+Similar to Linux, there are 2 names for device/ports in Mac:
+
+* `/dev/tty.usbmodemXXX`
+* `/dev/tty.usbserialXXX`
+
+Where `XXX` is the device ID.
+
+`tty.usbmodemXXX` is used for new **Uno** and **Mega** Arduinos, while `tty.usbserialXXX` for the old ones.
+
+#### Microsoft Windows
+
+Microsoft Windows names all of its serial devices/ports as `COMx`, where `x` is the device number.
\ No newline at end of file
diff --git a/docs/_Sidebar.md b/docs/_Sidebar.md
new file mode 100644
index 0000000..82dd232
--- /dev/null
+++ b/docs/_Sidebar.md
@@ -0,0 +1,29 @@
+### Arduino CMake Project Docs
+
+- **[[Arduino CMake|Home]]**
+ - **[[License|LICENSE]]**
+ - **Getting Started**
+ - [[Installation]]
+ - [[Creating First Program]]
+ - [[Building Project]]
+ - [[Generating CMake]]
+ - **Usage**
+ - [[Creating Firmware]]
+ - [[Uploading Program]]
+ - [[Connecting Serial Terminal]]
+ - [[Arduino Libraries]]
+ - [[Arduino Sketches]]
+ - [[Custom Libraries]]
+ - [[Examples]]
+ - [[Bootloaders]]
+ - [[Setting Build Flags]]
+ - [[Building With Make]]
+ - [[Using CMake Tools]]
+ - **Advanced**
+ - [[3rd Party Platforms]]
+ - [[Printing]]
+ - [[Setting Defaults]]
+ - **Troubleshooting**
+ - [[Undefined References]]
+ - [[Other]]
+
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
new file mode 100644
index 0000000..0fed09e
--- /dev/null
+++ b/examples/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.8)
+
+project(Examples LANGUAGES C CXX ASM)
+
+add_subdirectory(hello-world)
+add_subdirectory(arduino-library)
+add_subdirectory(blink-example)
+add_subdirectory(servo-knob-example)
+add_subdirectory(sketch)
diff --git a/examples/arduino-library/CMakeLists.txt b/examples/arduino-library/CMakeLists.txt
new file mode 100644
index 0000000..d2c2e55
--- /dev/null
+++ b/examples/arduino-library/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 3.8)
+
+project(Arduino_Library LANGUAGES C CXX ASM)
+get_board_id(board_id nano atmega328)
+
+add_arduino_executable(Arduino_Library ${board_id} test.cpp)
+
+# Find and link the Stepper library
+find_arduino_library(stepper_lib stePpEr ${board_id}) # Library name is case-insensitive to the user
+link_arduino_library(Arduino_Library stepper_lib ${board_id})
+
+# Find and link the Servo library - Custom implementation for many architectures,
+# 'avr' is used by default
+find_arduino_library(servo_lib Servo ${board_id})
+link_arduino_library(Arduino_Library servo_lib ${board_id})
+
+# Find and link the Ethernet library - Depends on the SPI avr-platform library
+find_arduino_library(ethernet_lib Ethernet ${board_id})
+link_arduino_library(Arduino_Library ethernet_lib ${board_id})
+
+#upload_arduino_target(Arduino_Library "${board_id}" COM3)
diff --git a/examples/arduino-library/test.cpp b/examples/arduino-library/test.cpp
new file mode 100644
index 0000000..691e4cf
--- /dev/null
+++ b/examples/arduino-library/test.cpp
@@ -0,0 +1,18 @@
+#include
+#include
+#include
+#include
+
+Stepper stepper{1, 7, 6};
+Servo servo;
+EthernetClient client{};
+
+void setup()
+{
+ stepper.version();
+}
+
+void loop()
+{
+
+}
diff --git a/examples/blink-example/CMakeLists.txt b/examples/blink-example/CMakeLists.txt
new file mode 100644
index 0000000..378b1e4
--- /dev/null
+++ b/examples/blink-example/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.8)
+
+project(Blink_Example LANGUAGES C CXX ASM)
+
+get_board_id(board_id nano atmega328)
+
+add_arduino_example(Blink_Example ${board_id} Blink)
diff --git a/examples/hello-world/CMakeLists.txt b/examples/hello-world/CMakeLists.txt
new file mode 100644
index 0000000..4818212
--- /dev/null
+++ b/examples/hello-world/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.8)
+
+project(Hello_World LANGUAGES C CXX ASM)
+get_board_id(board_id nano atmega328)
+
+add_arduino_executable(Hello_World ${board_id} helloWorld.cpp)
+
+#upload_arduino_target(Hello_World "${board_id}" COM3)
diff --git a/examples/hello-world/helloWorld.cpp b/examples/hello-world/helloWorld.cpp
new file mode 100644
index 0000000..6e2ce7e
--- /dev/null
+++ b/examples/hello-world/helloWorld.cpp
@@ -0,0 +1,14 @@
+#include
+
+void setup()
+{
+ pinMode(LED_BUILTIN, OUTPUT);
+}
+
+void loop()
+{
+ digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
+ delay(1000); // wait for a second
+ digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
+ delay(1000); // wait for a second
+}
diff --git a/examples/servo-knob-example/CMakeLists.txt b/examples/servo-knob-example/CMakeLists.txt
new file mode 100644
index 0000000..2e68290
--- /dev/null
+++ b/examples/servo-knob-example/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.8)
+
+project(Knob_Example LANGUAGES C CXX ASM)
+
+get_board_id(board_id nano atmega328)
+
+find_arduino_library(servo_example_lib Servo ${board_id})
+add_arduino_library_example(Knob_Example ${board_id} servo_example_lib Servo Knob)
+
diff --git a/examples/sketch/CMakeLists.txt b/examples/sketch/CMakeLists.txt
new file mode 100644
index 0000000..fda193d
--- /dev/null
+++ b/examples/sketch/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.8)
+
+project(Sketch LANGUAGES C CXX ASM)
+get_board_id(board_id nano atmega328)
+
+add_arduino_executable(Sketch ${board_id} "")
+target_sketches(Sketch ${board_id} sketch.ino)
diff --git a/examples/sketch/sketch.ino b/examples/sketch/sketch.ino
new file mode 100644
index 0000000..20fa1bf
--- /dev/null
+++ b/examples/sketch/sketch.ino
@@ -0,0 +1,14 @@
+// This is a sketch
+
+void setup()
+{
+ pinMode(LED_BUILTIN, OUTPUT);
+}
+
+void loop()
+{
+ digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
+ delay(1000); // wait for a second
+ digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
+ delay(1000); // wait for a second
+}