From ef3c19066ccc1cce7a2e6d896e4923f70d79d5ab Mon Sep 17 00:00:00 2001 From: Carlos Pereira Atencio Date: Fri, 26 Apr 2024 11:52:14 +0100 Subject: [PATCH] Add basic CODAL hello world project. --- .github/workflows/build.yml | 36 ++ .gitignore | 13 + CMakeLists.txt | 269 +++++++++++++++ README.md | 40 ++- build.py | 171 ++++++++++ codal.json | 20 ++ source/main.cpp | 11 + utils/__init__.py | 0 utils/cmake/JSONParser.cmake | 309 ++++++++++++++++++ utils/cmake/buildtools/codal.cmake | 85 +++++ utils/cmake/buildtools/yotta.cmake | 23 ++ utils/cmake/colours.cmake | 19 ++ .../toolchains/ARM_GCC/bin-generator.cmake | 9 + .../toolchains/ARM_GCC/compiler-flags.cmake | 49 +++ .../toolchains/ARM_GCC/hex-generator.cmake | 9 + .../toolchains/ARM_GCC/platform_includes.h | 10 + .../cmake/toolchains/ARM_GCC/toolchain.cmake | 29 ++ .../toolchains/AVR_GCC/bin-generator.cmake | 9 + .../toolchains/AVR_GCC/compiler-flags.cmake | 43 +++ .../toolchains/AVR_GCC/hex-generator.cmake | 9 + .../toolchains/AVR_GCC/platform_includes.h | 14 + .../cmake/toolchains/AVR_GCC/toolchain.cmake | 29 ++ .../toolchains/XTENSA_GCC/bin-generator.cmake | 9 + .../XTENSA_GCC/compiler-flags.cmake | 43 +++ .../toolchains/XTENSA_GCC/hex-generator.cmake | 9 + .../toolchains/XTENSA_GCC/platform_includes.h | 10 + .../toolchains/XTENSA_GCC/toolchain.cmake | 26 ++ utils/cmake/util.cmake | 156 +++++++++ utils/generate_libraries.py | 159 +++++++++ utils/python/__init__.py | 0 utils/python/codal_utils.py | 216 ++++++++++++ utils/targets.json | 105 ++++++ 32 files changed, 1937 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/build.yml create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100755 build.py create mode 100644 codal.json create mode 100644 source/main.cpp create mode 100644 utils/__init__.py create mode 100644 utils/cmake/JSONParser.cmake create mode 100644 utils/cmake/buildtools/codal.cmake create mode 100644 utils/cmake/buildtools/yotta.cmake create mode 100644 utils/cmake/colours.cmake create mode 100644 utils/cmake/toolchains/ARM_GCC/bin-generator.cmake create mode 100644 utils/cmake/toolchains/ARM_GCC/compiler-flags.cmake create mode 100644 utils/cmake/toolchains/ARM_GCC/hex-generator.cmake create mode 100644 utils/cmake/toolchains/ARM_GCC/platform_includes.h create mode 100644 utils/cmake/toolchains/ARM_GCC/toolchain.cmake create mode 100644 utils/cmake/toolchains/AVR_GCC/bin-generator.cmake create mode 100644 utils/cmake/toolchains/AVR_GCC/compiler-flags.cmake create mode 100644 utils/cmake/toolchains/AVR_GCC/hex-generator.cmake create mode 100644 utils/cmake/toolchains/AVR_GCC/platform_includes.h create mode 100644 utils/cmake/toolchains/AVR_GCC/toolchain.cmake create mode 100644 utils/cmake/toolchains/XTENSA_GCC/bin-generator.cmake create mode 100644 utils/cmake/toolchains/XTENSA_GCC/compiler-flags.cmake create mode 100644 utils/cmake/toolchains/XTENSA_GCC/hex-generator.cmake create mode 100644 utils/cmake/toolchains/XTENSA_GCC/platform_includes.h create mode 100644 utils/cmake/toolchains/XTENSA_GCC/toolchain.cmake create mode 100644 utils/cmake/util.cmake create mode 100644 utils/generate_libraries.py create mode 100644 utils/python/__init__.py create mode 100644 utils/python/codal_utils.py create mode 100644 utils/targets.json diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..fe2f152 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,36 @@ +name: Build project + +on: + push: + branches: '*' + pull_request: + branches: '*' + +jobs: + build-py-script: + runs-on: ubuntu-20.04 + name: Build project + steps: + - uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Setup arm-none-eabi-gcc ${{ matrix.gcc }} + uses: carlosperate/arm-none-eabi-gcc-action@v1 + with: + release: 10.3-2021.10 + - name: Install Cmake via PyPI + run: python -m pip install cmake==3.28.3 + - name: Check Versions + run: | + arm-none-eabi-gcc --version + cmake --version + python --version + - name: Build default project using build.py + run: python build.py + - name: Upload hex file + uses: actions/upload-artifact@v1 + with: + name: build-py-${{ matrix.os }} + path: MICROBIT.hex diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..951662b --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +build +libraries +*.swp +*~ +Makefile +*.hex +*.DS_Store +.vscode +*.uf2 +*.bin +pxtapp +buildcache.json +*.pyc diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..1532c35 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,269 @@ +# The MIT License (MIT) + +# Copyright (c) 2017 Lancaster University. + +# 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. +cmake_minimum_required(VERSION 3.6) + +# include additional cmake +include(utils/cmake/JSONParser.cmake) +include(utils/cmake/util.cmake) +include(utils/cmake/colours.cmake) + +if (NOT "${BUILD_TOOL}" STRGREATER "") + set(BUILD_TOOL "CODAL") +endif() + +# +# Supress unecessary (and often inaccurate) validity check of the toolchain +# +set(CMAKE_C_COMPILER_WORKS 1) +set(CMAKE_CXX_COMPILER_WORKS 1) + + +#read our config file... +file(READ "./codal.json" codal_json) +sbeParseJson(codal codal_json) + +set(CODAL_APP_OUTPUT_DIR ".") +set(CODAL_APP_SOURCE_DIR "source") + +if("${codal.application}" STRGREATER "") + set(CODAL_APP_SOURCE_DIR "${codal.application}") +endif() + +if("${codal.output_folder}" STRGREATER "") + set(CODAL_APP_OUTPUT_DIR "${codal.output_folder}") +endif() + +if(NOT "${codal.target.name}" STRGREATER "") + message(FATAL_ERROR "${BoldRed}INVALID TARGET.${ColourReset}") +endif() + +set(CODAL_DEPS "") +set(LIB_DEST "libraries") + +#install the target +INSTALL_DEPENDENCY(${LIB_DEST} ${codal.target.name} ${codal.target.url} ${codal.target.branch} ${codal.target.type}) +message("${BoldMagenta}Set target: ${codal.target.name} ${ColourReset}") +list(APPEND CODAL_DEPS ${codal.target.name}) + +if("${codal.target.dev}" STRGREATER "") + file(READ "./${LIB_DEST}/${codal.target.name}/target.json" device_json) + message("${BoldMagenta}Using target.json (dev version) ${ColourReset}") +else() + file(READ "./${LIB_DEST}/${codal.target.name}/target-locked.json" device_json) + message("${BoldMagenta}Using target-locked.json${ColourReset}") +endif() + +message("${BoldBlue}Targeting ${codal.target.name}${ColourReset}") + +sbeParseJson(device device_json) + +SET(CODAL_TARGET_NAME ${device.target.name}) +SET(CODAL_OUTPUT_NAME ${device.device}) +SET(CODAL_TARGET_PROCESSOR ${device.processor}) +SET(CODAL_TARGET_CPU_ARCHITECTURE ${device.architecture}) + +# if this is the first build, lets copy a sample main.cpp from the target if available. +if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/${CODAL_APP_SOURCE_DIR} AND EXISTS ${CMAKE_CURRENT_LIST_DIR}/${LIB_DEST}/${codal.target.name}/samples/main.cpp) + FILE(COPY ${CMAKE_CURRENT_LIST_DIR}/${LIB_DEST}/${codal.target.name}/samples/main.cpp DESTINATION ${CMAKE_CURRENT_LIST_DIR}/${CODAL_APP_SOURCE_DIR}) +endif() + +#copy samples and remove main.cpp +if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/samples AND EXISTS ${CMAKE_CURRENT_LIST_DIR}/${LIB_DEST}/${codal.target.name}/samples/) + FILE(COPY ${CMAKE_CURRENT_LIST_DIR}/${LIB_DEST}/${codal.target.name}/samples DESTINATION ${CMAKE_CURRENT_LIST_DIR}) + FILE(REMOVE ${CMAKE_CURRENT_LIST_DIR}/samples/main.cpp) +endif() + +#################### + +SET(TOOLCHAIN ${device.toolchain}) +SET(TOOLCHAIN_FOLDER "./utils/cmake/toolchains/${device.toolchain}") + +# include toolchain file +set(CMAKE_TOOLCHAIN_FILE "${TOOLCHAIN_FOLDER}/toolchain.cmake" CACHE PATH "toolchain file") + +# required to force TOOLCHAIN settings... +project(codal) +enable_language(ASM) + +# include compiler flags overrides +include(${TOOLCHAIN_FOLDER}/compiler-flags.cmake) +set(PLATFORM_INCLUDES_PATH "${PROJECT_SOURCE_DIR}/utils/cmake/toolchains/${device.toolchain}") + +file(MAKE_DIRECTORY "${PROJECT_SOURCE_DIR}/build") + +# configure output directories +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/build") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/build") + +SET(CODAL_DEFINITIONS "") + +EXTRACT_JSON_ARRAY(codal "codal\.config\." CODAL_FIELDS CODAL_VALUES) +EXTRACT_JSON_ARRAY(device "device\.config\." DEVICE_FIELDS DEVICE_VALUES) +UNIQUE_JSON_KEYS(CODAL_FIELDS CODAL_VALUES DEVICE_FIELDS DEVICE_VALUES FINAL_FIELDS FINAL_VALUES) +FORM_DEFINITIONS(FINAL_FIELDS FINAL_VALUES CODAL_DEFINITIONS) + +# extract any CMAKE definitions specified in the target.json object, and set as native cmake vars +# cmake definitions require special handling as types are not safe in cmake, any semi-colon would need escaped, which would be ugly. +foreach(var ${device}) + #if it is not prefixed by codal.cmake_definitions, do not consider the key. + + if(NOT "${var}" MATCHES "device\.cmake_definitions\.") + continue() + endif() + + string(REGEX MATCH "[^device\.cmake_definitions\.]([A-Z,a-z,0-9,_,]+)" CODAL_CMAKE_DEFINITION "${var}") + + set(${CODAL_CMAKE_DEFINITION} ${${var}}) +endforeach() + +#define any additional symbols specified by the target. +if("${device.definitions}" STRGREATER "") + add_definitions("${device.definitions}") +endif() + +#################### +# optional JSON flags for compilation + assembly +################### +if("${device.cpu_opts}" STRGREATER "") + set(_CPU_COMPILATION_OPTIONS "${device.cpu_opts}") + set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} ${device.cpu_opts}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${device.cpu_opts}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${device.cpu_opts}") + set(CMAKE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} ${device.cpu_opts}") +endif() + +set(_C_FAMILY_FLAGS_INIT "-fno-exceptions -fno-unwind-tables -ffunction-sections -fdata-sections -Wall -Wextra -Wno-unused-parameter") + +# asm +if("${device.asm_flags}" STRGREATER "") + set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} ${device.asm_flags}") +endif() + +# c +if("${device.c_flags}" STRGREATER "") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_C_FAMILY_FLAGS_INIT} ${device.c_flags}") + set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} ${device.c_flags}") +endif() + +# cpp +if("${device.cpp_flags}" STRGREATER "") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_C_FAMILY_FLAGS_INIT} ${device.cpp_flags}") + set(CMAKE_CXX_LINK_FLAGS "${device.cpp_flags}") +endif() + +# linker opts +if("${device.linker_flags}" STRGREATER "") + set(CMAKE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} ${device.linker_flags}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${device.linker_flags}") +endif() + +# create a header file from the definitions specified in JSON +if("${CODAL_DEFINITIONS}" STRGREATER "") + set(EXTRA_INCLUDES_NEW_PATH "${PROJECT_SOURCE_DIR}/build/codal_extra_definitions_new.h") + set(EXTRA_INCLUDES_PATH "${PROJECT_SOURCE_DIR}/build/codal_extra_definitions.h") + file(WRITE "${EXTRA_INCLUDES_NEW_PATH}" ${CODAL_DEFINITIONS}) + configure_file(${EXTRA_INCLUDES_NEW_PATH} ${EXTRA_INCLUDES_PATH} COPYONLY) + + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -include \"${EXTRA_INCLUDES_PATH}\"") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -include \"${EXTRA_INCLUDES_PATH}\"") +endif() + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I\"${PLATFORM_INCLUDES_PATH}\"") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I\"${PLATFORM_INCLUDES_PATH}\"") + +# a define for cmake if statements to detect if within the CODAL build environment +set(CODAL_BUILD_SYSTEM TRUE) + +# a define specificying common utils used in codal +set(CODAL_UTILS_LOCATION "${PROJECT_SOURCE_DIR}/utils/cmake/util.cmake") + +# this variable is used in the linking step of the final binary. +set(LIB_FOLDERS "") + +# Add the root of the libraries folder as a search path. Useful for disambiguating header files with duplicated names. +MESSAGE (STATUS "Adding library path: (${PROJECT_SOURCE_DIR}/${LIB_DEST})") +include_directories(${PROJECT_SOURCE_DIR}/${LIB_DEST}) + +#add_subdirectory("${PROJECT_SOURCE_DIR}/${LIB_DEST}/${dep}") + +# "import" and add any specified libraries to the build list +if("${device.libraries}" STRGREATER "") + message("Installing dependencies...") + set(DEVICE_LIBS ${device.libraries}) + + foreach(i ${DEVICE_LIBS}) + SET(BRANCH "NONE") + SET(URL "${device.libraries_${i}.url}") + if("${device.libraries_${i}.branch}" STRGREATER "") + SET(BRANCH "${device.libraries_${i}.branch}") + endif() + if("${codal.target.branches.${URL}}" STRGREATER "") + SET(BRANCH "${codal.target.branches.${URL}}") + MESSAGE (STATUS "Override branch: ${BRANCH}") + endif() + + INSTALL_DEPENDENCY(${LIB_DEST} ${device.libraries_${i}.name} ${URL} ${BRANCH} ${device.libraries_${i}.type}) + list(APPEND CODAL_DEPS "${device.libraries_${i}.name}") + endforeach() + + foreach(dep ${CODAL_DEPS}) + message("${BoldGreen}Using library: ${dep}${ColourReset}") + add_subdirectory("${PROJECT_SOURCE_DIR}/${LIB_DEST}/${dep}") + endforeach() +endif() + +#finally, find sources and includes of the application, and create a target. +RECURSIVE_FIND_DIR(INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/${CODAL_APP_SOURCE_DIR}" "*.h") +RECURSIVE_FIND_DIR(HPP_DIRS "${PROJECT_SOURCE_DIR}/${CODAL_APP_SOURCE_DIR}" "*.hpp") +list(APPEND INCLUDE_DIRS ${HPP_DIRS}) + +# *.c?? only catches .cpp, not .c, so let's be precise +RECURSIVE_FIND_FILE(SOURCE_FILES "${PROJECT_SOURCE_DIR}/${CODAL_APP_SOURCE_DIR}" "*.cpp") +RECURSIVE_FIND_FILE(S_FILES "${PROJECT_SOURCE_DIR}/${CODAL_APP_SOURCE_DIR}" "*.s") +RECURSIVE_FIND_FILE(C_FILES "${PROJECT_SOURCE_DIR}/${CODAL_APP_SOURCE_DIR}" "*.c") +RECURSIVE_FIND_FILE(CC_FILES "${PROJECT_SOURCE_DIR}/${CODAL_APP_SOURCE_DIR}" "*.cc") +list(APPEND SOURCE_FILES ${S_FILES}) +list(APPEND SOURCE_FILES ${C_FILES}) +list(APPEND SOURCE_FILES ${CC_FILES}) + +if("${SOURCE_FILES}" STREQUAL "") + message(FATAL_ERROR "${BoldRed}No user application to build, please add a main.cpp at: ${PROJECT_SOURCE_DIR}/${CODAL_APP_SOURCE_DIR}${ColourReset}") +endif() + +if ("${BUILD_TOOL}" STRGREATER "") + string(COMPARE EQUAL "${BUILD_TOOL}" "YOTTA" YOTTA_BUILD) + if (${YOTTA_BUILD}) + include("${PROJECT_SOURCE_DIR}/utils/cmake/buildtools/yotta.cmake") + endif () + + string(COMPARE EQUAL "${BUILD_TOOL}" "CODAL" CODAL_BUILD) + if (${CODAL_BUILD}) + include("${PROJECT_SOURCE_DIR}/utils/cmake/buildtools/codal.cmake") + endif() +endif() + +# +# Supress the addition of implicit linker flags (such as -rdynamic) +# +set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") +set(CMAKE_EXE_EXPORTS_C_FLAG "") +set(CMAKE_EXE_EXPORTS_CXX_FLAG "") diff --git a/README.md b/README.md index 6943d03..2642902 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,38 @@ -# microbit-v2-battery-voltage -A C++ example project showing how to measure the battery voltage with a BBC micro:bit V2 +# BBC micro:bit V2 Battery Voltage Project + +A C++ example project showing how to measure the BBC micro:bit V2 battery +voltage. + +## Building the project + +### Dependencies + +- [GNU Arm Embedded Toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads) +- [Git](https://git-scm.com) +- [CMake](https://cmake.org/download/) +- [Python 3](https://www.python.org/downloads/) + +For example, on Ubuntu: + +``` +sudo apt install gcc +sudo apt install git +sudo apt install cmake +sudo apt install gcc-arm-none-eabi binutils-arm-none-eabi +``` + +### Building + +- Install the dependencies +- Clone this repository + ``` + git clone https://github.com/microbit-foundation/microbit-v2-battery-voltage.git + ``` +- In the root of this repository run the `build.py` script + ``` + cd microbit-v2-battery-voltage + python build.py + ``` +- The `MICROBIT.hex` hex file will be built and placed in the root folder. +- Copy the `MICROBIT.hex` file into the `MICORBIT` USB drive to flash the + micro:bit diff --git a/build.py b/build.py new file mode 100755 index 0000000..9b1019d --- /dev/null +++ b/build.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python3 + +# The MIT License (MIT) + +# Copyright (c) 2017 Lancaster University. + +# 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. + +import os +import sys +import optparse +import platform +import json +import shutil +import re +from utils.python.codal_utils import system, build, read_json, checkgit, read_config, update, revision, printstatus, status, get_next_version, lock, delete_build_folder, generate_docs + +parser = optparse.OptionParser(usage="usage: %prog target-name-or-url [options]", description="This script manages the build system for a codal device. Passing a target-name generates a codal.json for that devices, to list all devices available specify the target-name as 'ls'.") +parser.add_option('-c', '--clean', dest='clean', action="store_true", help='Whether to clean before building. Applicable only to unix based builds.', default=False) +parser.add_option('-t', '--test-platforms', dest='test_platform', action="store_true", help='Specify whether the target platform is a test platform or not.', default=False) +parser.add_option('-l', '--lock', dest='lock_target', action="store_true", help='Create target-lock.json, updating patch version', default=False) +parser.add_option('-b', '--branch', dest='branch', action="store_true", help='With -l, use vX.X.X-BRANCH.Y', default=False) +parser.add_option('-m', '--minor', dest='update_minor', action="store_true", help='With -l, update minor version', default=False) +parser.add_option('-M', '--major', dest='update_major', action="store_true", help='With -l, update major version', default=False) +parser.add_option('-V', '--version', dest='version', metavar="VERSION", help='With -l, set the version; use "-V v0.0.1" to bootstrap', default=False) +parser.add_option('-v', '--verbose', dest='verbose', action="store_true", help='Increases verbosity)', default=False) +parser.add_option('-u', '--update', dest='update', action="store_true", help='git pull target and libraries, use with "-d/--dev" to update all libraries to their latest master' , default=False) +parser.add_option('-s', '--status', dest='status', action="store_true", help='git status target and libraries', default=False) +parser.add_option('-r', '--revision', dest='revision', action="store", help='Checkout a specific revision of the target', default=False) +parser.add_option('-d', '--dev', dest='dev', action="store_true", help='enable developer mode (does not use target-locked.json)', default=False) +parser.add_option('-g', '--generate-docs', dest='generate_docs', action="store_true", help='generate documentation for the current target', default=False) +parser.add_option('-j', '--parallelism', dest='parallelism', action="store", help='Set the number of parallel threads to build with, if supported', default=10) +parser.add_option('-n', '--lines', dest='detail_lines', action="store", help="Sets the number of detail lines to output (only relevant to --status)", default=3 ) + +(options, args) = parser.parse_args() + +if not os.path.exists("build"): + os.mkdir("build") + +if options.lock_target: + lock(options) + exit(0) + +if options.update: + update(sync_dev = options.dev) + exit(0) + +if options.status: + status(logLines=options.detail_lines, detail=options.verbose, libs=args) + exit(0) + +if options.revision: + revision(options.revision) + exit(0) + +# out of source build! +os.chdir("build") + +test_json = read_json("../utils/targets.json") + +# configure the target a user has specified: +if len(args) == 1: + + target_name = args[0] + target_config = None + + # list all targets + if target_name == "ls": + for json_obj in test_json: + s = "%s: %s" % (json_obj["name"], json_obj["info"]) + if "device_url" in json_obj.keys(): + s += "(%s)" % json_obj["device_url"] + print(s) + exit(0) + + # cycle through out targets and check for a match + for json_obj in test_json: + if json_obj["name"] != target_name: + continue + + del json_obj["device_url"] + del json_obj["info"] + + target_config = json_obj + break + + if target_config == None and target_name.startswith("http"): + target_config = { + "name": re.sub("^.*/", "", target_name), + "url": target_name, + "branch": "master", + "type": "git" + } + + if target_config == None: + print("'" + target_name + "'" + " is not a valid target.") + exit(1) + + # developer mode is for users who wish to contribute, it will clone and checkout commitable branches. + if options.dev: + target_config["dev"] = True + + config = { + "target":target_config + } + + with open("../codal.json", 'w') as codal_json: + json.dump(config, codal_json, indent=4) + + # remove the build folder, a user could be swapping targets. + delete_build_folder() + + +elif len(args) > 1: + print("Too many arguments supplied, only one target can be specified.") + exit(1) + +if not options.test_platform: + + if not os.path.exists("../codal.json"): + print("No target specified in codal.json, does codal.json exist?") + exit(1) + + if options.generate_docs: + generate_docs() + exit(0) + + build(options.clean, verbose=options.verbose, parallelism=options.parallelism) + exit(0) + +for json_obj in test_json: + + # some platforms aren't supported by travis, ignore them when testing. + if "test_ignore" in json_obj: + print("ignoring: " + json_obj["name"]) + continue + + # ensure we have a clean build tree. + delete_build_folder() + + # clean libs + if os.path.exists("../libraries"): + shutil.rmtree('../libraries') + + # configure the target and tests... + config = { + "target":json_obj, + "output":".", + "application":"libraries/"+json_obj["name"]+"/tests/" + } + + with open("../codal.json", 'w') as codal_json: + json.dump(config, codal_json, indent=4) + + build(True, True, options.parallelism) diff --git a/codal.json b/codal.json new file mode 100644 index 0000000..5ab5d5c --- /dev/null +++ b/codal.json @@ -0,0 +1,20 @@ +{ + "target": { + "name": "codal-microbit-v2", + "url": "https://github.com/lancaster-university/codal-microbit-v2", + "branch": "master", + "type": "git" + } , + "config":{ + "DEVICE_BLE": 1, + "MICROBIT_BLE_ENABLED" : 1, + "MICROBIT_BLE_PAIRING_MODE": 1, + "MICROBIT_BLE_DFU_SERVICE": 1, + "MICROBIT_BLE_DEVICE_INFORMATION_SERVICE": 1, + "MICROBIT_BLE_UTILITY_SERVICE": 1, + "MICROBIT_BLE_UTILITY_SERVICE_PAIRING": 1, + "MICROBIT_BLE_EVENT_SERVICE" : 1, + "MICROBIT_BLE_PARTIAL_FLASHING" : 0, + "MICROBIT_BLE_SECURITY_LEVEL": "SECURITY_MODE_ENCRYPTION_NO_MITM" + } +} diff --git a/source/main.cpp b/source/main.cpp new file mode 100644 index 0000000..04297f1 --- /dev/null +++ b/source/main.cpp @@ -0,0 +1,11 @@ +#include "MicroBit.h" + +MicroBit uBit; + +int main() { + uBit.init(); + + while (true) { + uBit.display.scroll("Hello world!"); + } +} diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/utils/cmake/JSONParser.cmake b/utils/cmake/JSONParser.cmake new file mode 100644 index 0000000..0efc84e --- /dev/null +++ b/utils/cmake/JSONParser.cmake @@ -0,0 +1,309 @@ +# The MIT License (MIT) + +# Copyright (c) 2015 Stefan Bellus + +# 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. + +cmake_minimum_required(VERSION 3.6) + +if (DEFINED JSonParserGuard) + return() +endif() + +set(JSonParserGuard yes) + +macro(sbeParseJson prefix jsonString) + cmake_policy(PUSH) + + set(json_string "${${jsonString}}") + string(LENGTH "${json_string}" json_jsonLen) + set(json_index 0) + set(json_AllVariables ${prefix}) + set(json_ArrayNestingLevel 0) + set(json_MaxArrayNestingLevel 0) + + _sbeParse(${prefix}) + + unset(json_index) + unset(json_AllVariables) + unset(json_jsonLen) + unset(json_string) + unset(json_value) + unset(json_inValue) + unset(json_name) + unset(json_inName) + unset(json_newPrefix) + unset(json_reservedWord) + unset(json_arrayIndex) + unset(json_char) + unset(json_end) + unset(json_ArrayNestingLevel) + foreach(json_nestingLevel RANGE ${json_MaxArrayNestingLevel}) + unset(json_${json_nestingLevel}_arrayIndex) + endforeach() + unset(json_nestingLevel) + unset(json_MaxArrayNestingLevel) + + cmake_policy(POP) +endmacro() + +macro(sbeClearJson prefix) + foreach(json_var ${${prefix}}) + unset(${json_var}) + endforeach() + + unset(${prefix}) + unset(json_var) +endmacro() + +macro(sbePrintJson prefix) + foreach(json_var ${${prefix}}) + message("${json_var} = ${${json_var}}") + endforeach() +endmacro() + +macro(_sbeParse prefix) + + while(${json_index} LESS ${json_jsonLen}) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + if("\"" STREQUAL "${json_char}") + _sbeParseNameValue(${prefix}) + elseif("{" STREQUAL "${json_char}") + _sbeMoveToNextNonEmptyCharacter() + _sbeParseObject(${prefix}) + elseif("[" STREQUAL "${json_char}") + _sbeMoveToNextNonEmptyCharacter() + _sbeParseArray(${prefix}) + endif() + + if(${json_index} LESS ${json_jsonLen}) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + else() + break() + endif() + + if ("}" STREQUAL "${json_char}" OR "]" STREQUAL "${json_char}") + break() + endif() + + _sbeMoveToNextNonEmptyCharacter() + endwhile() +endmacro() + +macro(_sbeParseNameValue prefix) + set(json_name "") + set(json_inName no) + + while(${json_index} LESS ${json_jsonLen}) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + # check if name ends + if("\"" STREQUAL "${json_char}" AND json_inName) + set(json_inName no) + _sbeMoveToNextNonEmptyCharacter() + if(NOT ${json_index} LESS ${json_jsonLen}) + break() + endif() + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + set(json_newPrefix ${prefix}.${json_name}) + set(json_name "") + + if(":" STREQUAL "${json_char}") + _sbeMoveToNextNonEmptyCharacter() + if(NOT ${json_index} LESS ${json_jsonLen}) + break() + endif() + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + if("\"" STREQUAL "${json_char}") + _sbeParseValue(${json_newPrefix}) + break() + elseif("{" STREQUAL "${json_char}") + _sbeMoveToNextNonEmptyCharacter() + _sbeParseObject(${json_newPrefix}) + break() + elseif("[" STREQUAL "${json_char}") + _sbeMoveToNextNonEmptyCharacter() + _sbeParseArray(${json_newPrefix}) + break() + else() + # reserved word starts + _sbeParseReservedWord(${json_newPrefix}) + break() + endif() + else() + # name without value + list(APPEND ${json_AllVariables} ${json_newPrefix}) + set(${json_newPrefix} "") + break() + endif() + endif() + + if(json_inName) + # remove escapes + if("\\" STREQUAL "${json_char}") + math(EXPR json_index "${json_index} + 1") + if(NOT ${json_index} LESS ${json_jsonLen}) + break() + endif() + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + endif() + + set(json_name "${json_name}${json_char}") + endif() + + # check if name starts + if("\"" STREQUAL "${json_char}" AND NOT json_inName) + set(json_inName yes) + endif() + + _sbeMoveToNextNonEmptyCharacter() + endwhile() +endmacro() + +macro(_sbeParseReservedWord prefix) + set(json_reservedWord "") + set(json_end no) + while(${json_index} LESS ${json_jsonLen} AND NOT json_end) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + if("," STREQUAL "${json_char}" OR "}" STREQUAL "${json_char}" OR "]" STREQUAL "${json_char}") + set(json_end yes) + else() + set(json_reservedWord "${json_reservedWord}${json_char}") + math(EXPR json_index "${json_index} + 1") + endif() + endwhile() + + list(APPEND ${json_AllVariables} ${prefix}) + string(STRIP "${json_reservedWord}" json_reservedWord) + set(${prefix} ${json_reservedWord}) +endmacro() + +macro(_sbeParseValue prefix) + cmake_policy(SET CMP0054 NEW) # turn off implicit expansions in if statement + + set(json_value "") + set(json_inValue no) + + while(${json_index} LESS ${json_jsonLen}) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + # check if json_value ends, it is ended by " + if("\"" STREQUAL "${json_char}" AND json_inValue) + set(json_inValue no) + + set(${prefix} ${json_value}) + list(APPEND ${json_AllVariables} ${prefix}) + _sbeMoveToNextNonEmptyCharacter() + break() + endif() + + if(json_inValue) + # if " is escaped consume + if("\\" STREQUAL "${json_char}") + math(EXPR json_index "${json_index} + 1") + if(NOT ${json_index} LESS ${json_jsonLen}) + break() + endif() + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + if(NOT "\"" STREQUAL "${json_char}") + # if it is not " then copy also escape character + set(json_char "\\${json_char}") + endif() + endif() + + _sbeAddEscapedCharacter("${json_char}") + endif() + + # check if value starts + if("\"" STREQUAL "${json_char}" AND NOT json_inValue) + set(json_inValue yes) + endif() + + math(EXPR json_index "${json_index} + 1") + endwhile() +endmacro() + +macro(_sbeAddEscapedCharacter char) + string(CONCAT json_value "${json_value}" "${char}") +endmacro() + +macro(_sbeParseObject prefix) + _sbeParse(${prefix}) + _sbeMoveToNextNonEmptyCharacter() +endmacro() + +macro(_sbeParseArray prefix) + math(EXPR json_ArrayNestingLevel "${json_ArrayNestingLevel} + 1") + set(json_${json_ArrayNestingLevel}_arrayIndex 0) + + set(${prefix} "") + list(APPEND ${json_AllVariables} ${prefix}) + + while(${json_index} LESS ${json_jsonLen}) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + if("\"" STREQUAL "${json_char}") + # simple value + list(APPEND ${prefix} ${json_${json_ArrayNestingLevel}_arrayIndex}) + _sbeParseValue(${prefix}_${json_${json_ArrayNestingLevel}_arrayIndex}) + elseif("{" STREQUAL "${json_char}") + # object + _sbeMoveToNextNonEmptyCharacter() + list(APPEND ${prefix} ${json_${json_ArrayNestingLevel}_arrayIndex}) + _sbeParseObject(${prefix}_${json_${json_ArrayNestingLevel}_arrayIndex}) + else() + list(APPEND ${prefix} ${json_${json_ArrayNestingLevel}_arrayIndex}) + _sbeParseReservedWord(${prefix}_${json_${json_ArrayNestingLevel}_arrayIndex}) + endif() + + if(NOT ${json_index} LESS ${json_jsonLen}) + break() + endif() + + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + if("]" STREQUAL "${json_char}") + _sbeMoveToNextNonEmptyCharacter() + break() + elseif("," STREQUAL "${json_char}") + math(EXPR json_${json_ArrayNestingLevel}_arrayIndex "${json_${json_ArrayNestingLevel}_arrayIndex} + 1") + endif() + + _sbeMoveToNextNonEmptyCharacter() + endwhile() + + if(${json_MaxArrayNestingLevel} LESS ${json_ArrayNestingLevel}) + set(json_MaxArrayNestingLevel ${json_ArrayNestingLevel}) + endif() + math(EXPR json_ArrayNestingLevel "${json_ArrayNestingLevel} - 1") +endmacro() + +macro(_sbeMoveToNextNonEmptyCharacter) + math(EXPR json_index "${json_index} + 1") + if(${json_index} LESS ${json_jsonLen}) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + while(${json_char} MATCHES "[ \t\n\r]" AND ${json_index} LESS ${json_jsonLen}) + math(EXPR json_index "${json_index} + 1") + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + endwhile() + endif() +endmacro() diff --git a/utils/cmake/buildtools/codal.cmake b/utils/cmake/buildtools/codal.cmake new file mode 100644 index 0000000..ea8b23c --- /dev/null +++ b/utils/cmake/buildtools/codal.cmake @@ -0,0 +1,85 @@ +add_executable( + ${device.device} + ${SOURCE_FILES} +) + +if("${INCLUDE_DIRS}" STRGREATER "") + target_include_directories(${device.device} PUBLIC "${INCLUDE_DIRS}") +endif() + +set_target_properties(${device.device} PROPERTIES SUFFIX "" ENABLE_EXPORTS ON) + +# link the executable with supporting libraries. +target_link_libraries( + ${device.device} + ${CODAL_DEPS} +) + +# import toolchain bin generation command +if(${device.generate_bin}) + include(${TOOLCHAIN_FOLDER}/bin-generator.cmake) +endif() + +# import toolchain hex generation command +if(${device.generate_hex}) + include(${TOOLCHAIN_FOLDER}/hex-generator.cmake) +endif() + +# post process command hook, depends on the hex file generated by the build system. +if("${device.post_process.command}" STRGREATER "" OR "${device.post_process}" STRGREATER "") + + if("${device.post_process}" STRGREATER "") + set(POST_PROCESS_COMMAND ${device.post_process}) + else() + set(POST_PROCESS_COMMAND ${device.post_process.command}) + endif() + + set(POST_PROCESS_DEPENDS "${device.post_process.depends}") + + # replace specific strings in the command, this gives users flexibility, they don't have to manually specify the location of files + string(REPLACE "" ${PROJECT_SOURCE_DIR}/${CODAL_APP_OUTPUT_DIR}/${device.device}.hex CODAL_POSTPROCESS_COMMAND ${POST_PROCESS_COMMAND}) + string(REPLACE "" ${PROJECT_SOURCE_DIR}/${CODAL_APP_OUTPUT_DIR} CODAL_POSTPROCESS_COMMAND ${CODAL_POSTPROCESS_COMMAND}) + string(REPLACE "" ${device.device} CODAL_POSTPROCESS_COMMAND ${CODAL_POSTPROCESS_COMMAND}) + + string(REPLACE "" ${PROJECT_SOURCE_DIR}/${CODAL_APP_OUTPUT_DIR}/${device.device}.bin CODAL_POSTPROCESS_COMMAND ${CODAL_POSTPROCESS_COMMAND}) + string(REPLACE "" ${PROJECT_SOURCE_DIR}/${CODAL_APP_OUTPUT_DIR} CODAL_POSTPROCESS_COMMAND ${CODAL_POSTPROCESS_COMMAND}) + string(REPLACE "" ${device.device}.bin CODAL_POSTPROCESS_COMMAND ${CODAL_POSTPROCESS_COMMAND}) + + string(REPLACE "" ${PROJECT_SOURCE_DIR}/build/${device.device} CODAL_POSTPROCESS_COMMAND ${CODAL_POSTPROCESS_COMMAND}) + string(REPLACE "" ${PROJECT_SOURCE_DIR}/${CODAL_APP_OUTPUT_DIR} CODAL_POSTPROCESS_COMMAND ${CODAL_POSTPROCESS_COMMAND}) + string(REPLACE "" ${device.device} CODAL_POSTPROCESS_COMMAND ${CODAL_POSTPROCESS_COMMAND}) + + string(REPLACE "" ${PROJECT_SOURCE_DIR}/${CODAL_APP_OUTPUT_DIR} CODAL_POSTPROCESS_COMMAND ${CODAL_POSTPROCESS_COMMAND}) + + #convert to a command + separate_arguments(FINAL_COMMAND UNIX_COMMAND ${CODAL_POSTPROCESS_COMMAND}) + + # execute + if(POST_PROCESS_DEPENDS STREQUAL "ELF") + add_custom_command( + TARGET ${device.device} + COMMAND ${FINAL_COMMAND} + DEPENDS ${device.device} + WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" + COMMENT "Executing post process command" + ) + elseif(POST_PROCESS_DEPENDS STREQUAL "HEX") + add_custom_command( + TARGET ${device.device}_hex + COMMAND ${FINAL_COMMAND} + DEPENDS ${device.device} + WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" + COMMENT "Executing post process command" + ) + else() + #by default post process should depend on hex + add_custom_command( + TARGET ${device.device}_bin + COMMAND ${FINAL_COMMAND} + DEPENDS ${device.device} + WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" + COMMENT "Executing post process command" + ) + endif() + +endif() \ No newline at end of file diff --git a/utils/cmake/buildtools/yotta.cmake b/utils/cmake/buildtools/yotta.cmake new file mode 100644 index 0000000..8002006 --- /dev/null +++ b/utils/cmake/buildtools/yotta.cmake @@ -0,0 +1,23 @@ +if("${INCLUDE_DIRS}" STRGREATER "") + target_include_directories(codal PUBLIC "${INCLUDE_DIRS}") +endif() + +add_library(codal "${SOURCE_FILES}") +set_target_properties(codal PROPERTIES SUFFIX "" ENABLE_EXPORTS ON) + +target_compile_definitions(codal PUBLIC "${device.definitions}") +target_include_directories(codal PUBLIC ${PLATFORM_INCLUDES_PATH}) +target_compile_options(codal PUBLIC -include ${EXTRA_INCLUDES_PATH}) + +set(STRIPPED "") +string(STRIP "${CMAKE_LINKER_FLAGS}" STRIPPED) +# link the executable with supporting libraries. +target_link_libraries(codal "${CODAL_DEPS};${STRIPPED}") + +# +# Supress the addition of implicit linker flags (such as -rdynamic) +# +set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") +set(CMAKE_EXE_EXPORTS_C_FLAG "") +set(CMAKE_EXE_EXPORTS_CXX_FLAG "") \ No newline at end of file diff --git a/utils/cmake/colours.cmake b/utils/cmake/colours.cmake new file mode 100644 index 0000000..2786b49 --- /dev/null +++ b/utils/cmake/colours.cmake @@ -0,0 +1,19 @@ +if(NOT WIN32) + string(ASCII 27 Esc) + set(ColourReset "${Esc}[m") + set(ColourBold "${Esc}[1m") + set(Red "${Esc}[31m") + set(Green "${Esc}[32m") + set(Yellow "${Esc}[33m") + set(Blue "${Esc}[34m") + set(Magenta "${Esc}[35m") + set(Cyan "${Esc}[36m") + set(White "${Esc}[37m") + set(BoldRed "${Esc}[1;31m") + set(BoldGreen "${Esc}[1;32m") + set(BoldYellow "${Esc}[1;33m") + set(BoldBlue "${Esc}[1;34m") + set(BoldMagenta "${Esc}[1;35m") + set(BoldCyan "${Esc}[1;36m") + set(BoldWhite "${Esc}[1;37m") +endif() diff --git a/utils/cmake/toolchains/ARM_GCC/bin-generator.cmake b/utils/cmake/toolchains/ARM_GCC/bin-generator.cmake new file mode 100644 index 0000000..d18d098 --- /dev/null +++ b/utils/cmake/toolchains/ARM_GCC/bin-generator.cmake @@ -0,0 +1,9 @@ +add_custom_command( + OUTPUT "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.bin" + COMMAND "${ARM_NONE_EABI_OBJCOPY}" -O binary "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${device.device}" "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.bin" + DEPENDS ${device.device} + COMMENT "converting to bin file." +) + +#specify a dependency on the elf file so that bin is automatically rebuilt when elf is changed. +add_custom_target(${device.device}_bin ALL DEPENDS "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.bin") diff --git a/utils/cmake/toolchains/ARM_GCC/compiler-flags.cmake b/utils/cmake/toolchains/ARM_GCC/compiler-flags.cmake new file mode 100644 index 0000000..16aacaa --- /dev/null +++ b/utils/cmake/toolchains/ARM_GCC/compiler-flags.cmake @@ -0,0 +1,49 @@ +set(EXPLICIT_INCLUDES "") +if((CMAKE_VERSION VERSION_GREATER "3.4.0") OR (CMAKE_VERSION VERSION_EQUAL "3.4.0")) + # from CMake 3.4 are separate to in the + # CMAKE__COMPILE_OBJECT, CMAKE__CREATE_ASSEMBLY_SOURCE, and + # CMAKE__CREATE_PREPROCESSED_SOURCE commands + set(EXPLICIT_INCLUDES " ") +endif() + +# Override the link rules: +set(CMAKE_C_CREATE_SHARED_LIBRARY "echo 'shared libraries not supported' && 1") +set(CMAKE_C_CREATE_SHARED_MODULE "echo 'shared modules not supported' && 1") +set(CMAKE_C_CREATE_STATIC_LIBRARY " -cr ") +set(CMAKE_C_COMPILE_OBJECT " ${EXPLICIT_INCLUDES} -o -c ") + +set(CMAKE_C_LINK_EXECUTABLE " -Wl,-Map,.map -Wl,--start-group -lm -lc -lgcc -lm -lc -lgcc -Wl,--end-group --specs=nano.specs -o ") + +set(CMAKE_CXX_OUTPUT_EXTENSION ".o") +set(CMAKE_DEPFILE_FLAGS_CXX "-MMD -MT -MF ") +set(CMAKE_C_OUTPUT_EXTENSION ".o") +set(CMAKE_DEPFILE_FLAGS_C "-MMD -MT -MF ") + +set(CMAKE_C_FLAGS_DEBUG_INIT "-g -gdwarf-3") +set(CMAKE_C_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") +set(CMAKE_C_FLAGS_RELEASE_INIT "-Os -DNDEBUG") +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-Os -g -gdwarf-3 -DNDEBUG") +set(CMAKE_INCLUDE_SYSTEM_FLAG_C "-isystem ") + + +set(CMAKE_ASM_FLAGS_DEBUG_INIT "-g -gdwarf-3") +set(CMAKE_ASM_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") +set(CMAKE_ASM_FLAGS_RELEASE_INIT "-Os -DNDEBUG") +set(CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT "-Os -g -gdwarf-3 -DNDEBUG") +set(CMAKE_INCLUDE_SYSTEM_FLAG_ASM "-isystem ") + +set(CMAKE_CXX_CREATE_STATIC_LIBRARY " -cr ") + +set(CMAKE_CXX_LINK_EXECUTABLE " -Wl,-Map,.map -Wl,--start-group -lnosys -lstdc++ -lsupc++ -lm -lc -lgcc -lstdc++ -lsupc++ -lm -lc -lgcc -Wl,--end-group --specs=nano.specs -o ") + +set(CMAKE_CXX_FLAGS_DEBUG_INIT "-g -gdwarf-3") +set(CMAKE_CXX_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") +set(CMAKE_CXX_FLAGS_RELEASE_INIT "-Os -DNDEBUG") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-Os -g -gdwarf-3 -DNDEBUG") +set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-isystem ") + +if (CMAKE_C_COMPILER_VERSION VERSION_GREATER "7.1.0" OR CMAKE_C_COMPILER_VERSION VERSION_EQUAL "7.1.0") + message("${BoldRed}Supressing -Wexpansion-to-defined.${ColourReset}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-expansion-to-defined") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-expansion-to-defined") +endif () \ No newline at end of file diff --git a/utils/cmake/toolchains/ARM_GCC/hex-generator.cmake b/utils/cmake/toolchains/ARM_GCC/hex-generator.cmake new file mode 100644 index 0000000..4948935 --- /dev/null +++ b/utils/cmake/toolchains/ARM_GCC/hex-generator.cmake @@ -0,0 +1,9 @@ +add_custom_command( + OUTPUT "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.hex" + COMMAND "${ARM_NONE_EABI_OBJCOPY}" -O ihex "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${device.device}" "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.hex" + DEPENDS ${device.device} + COMMENT "converting to hex file." +) + +#specify a dependency on the elf file so that hex is automatically rebuilt when elf is changed. +add_custom_target(${device.device}_hex ALL DEPENDS "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.hex") diff --git a/utils/cmake/toolchains/ARM_GCC/platform_includes.h b/utils/cmake/toolchains/ARM_GCC/platform_includes.h new file mode 100644 index 0000000..3417ef3 --- /dev/null +++ b/utils/cmake/toolchains/ARM_GCC/platform_includes.h @@ -0,0 +1,10 @@ +#ifndef PLATFORM_INCLUDES +#define PLATFORM_INCLUDES + +#include +#include +#include +#include +#include + +#endif diff --git a/utils/cmake/toolchains/ARM_GCC/toolchain.cmake b/utils/cmake/toolchains/ARM_GCC/toolchain.cmake new file mode 100644 index 0000000..ad68a6a --- /dev/null +++ b/utils/cmake/toolchains/ARM_GCC/toolchain.cmake @@ -0,0 +1,29 @@ +find_program(ARM_NONE_EABI_RANLIB arm-none-eabi-ranlib) +find_program(ARM_NONE_EABI_AR arm-none-eabi-ar) +find_program(ARM_NONE_EABI_GCC arm-none-eabi-gcc) +find_program(ARM_NONE_EABI_GPP arm-none-eabi-g++) +find_program(ARM_NONE_EABI_OBJCOPY arm-none-eabi-objcopy) + +set(CMAKE_OSX_SYSROOT "/") +set(CMAKE_OSX_DEPLOYMENT_TARGET "") + +set(CMAKE_SYSTEM_NAME "Generic") +set(CMAKE_SYSTEM_VERSION "2.0.0") + +set(CODAL_TOOLCHAIN "ARM_GCC") + +if(CMAKE_VERSION VERSION_LESS "3.5.0") + include(CMakeForceCompiler) + cmake_force_c_compiler("${ARM_NONE_EABI_GCC}" GNU) + cmake_force_cxx_compiler("${ARM_NONE_EABI_GPP}" GNU) +else() + # from 3.5 the force_compiler macro is deprecated: CMake can detect + # arm-none-eabi-gcc as being a GNU compiler automatically + set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") + set(CMAKE_C_COMPILER "${ARM_NONE_EABI_GCC}") + set(CMAKE_CXX_COMPILER "${ARM_NONE_EABI_GPP}") +endif() + +SET(CMAKE_AR "${ARM_NONE_EABI_AR}" CACHE FILEPATH "Archiver") +SET(CMAKE_RANLIB "${ARM_NONE_EABI_RANLIB}" CACHE FILEPATH "rlib") +set(CMAKE_CXX_OUTPUT_EXTENSION ".o") diff --git a/utils/cmake/toolchains/AVR_GCC/bin-generator.cmake b/utils/cmake/toolchains/AVR_GCC/bin-generator.cmake new file mode 100644 index 0000000..a3a1c01 --- /dev/null +++ b/utils/cmake/toolchains/AVR_GCC/bin-generator.cmake @@ -0,0 +1,9 @@ +add_custom_command( + OUTPUT "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.bin" + COMMAND "${AVR_OBJCOPY}" -O binary "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${device.device}" "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.bin" + DEPENDS ${device.device} + COMMENT "converting to bin file." +) + +#specify a dependency on the elf file so that bin is automatically rebuilt when elf is changed. +add_custom_target(${device.device}_bin ALL DEPENDS "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.bin") diff --git a/utils/cmake/toolchains/AVR_GCC/compiler-flags.cmake b/utils/cmake/toolchains/AVR_GCC/compiler-flags.cmake new file mode 100644 index 0000000..c6dcfc7 --- /dev/null +++ b/utils/cmake/toolchains/AVR_GCC/compiler-flags.cmake @@ -0,0 +1,43 @@ +set(EXPLICIT_INCLUDES "") +if((CMAKE_VERSION VERSION_GREATER "3.4.0") OR (CMAKE_VERSION VERSION_EQUAL "3.4.0")) + # from CMake 3.4 are separate to in the + # CMAKE__COMPILE_OBJECT, CMAKE__CREATE_ASSEMBLY_SOURCE, and + # CMAKE__CREATE_PREPROCESSED_SOURCE commands + set(EXPLICIT_INCLUDES " ") +endif() + +# Override the link rules: +set(CMAKE_C_CREATE_SHARED_LIBRARY "echo 'shared libraries not supported' && 1") +set(CMAKE_C_CREATE_SHARED_MODULE "echo 'shared modules not supported' && 1") +set(CMAKE_C_CREATE_STATIC_LIBRARY " rcs ") +set(CMAKE_C_COMPILE_OBJECT " ${EXPLICIT_INCLUDES} -o -c ") + +set(CMAKE_C_LINK_EXECUTABLE " -Wl,-Map,.map -Wl,--start-group -lm -lc -lgcc -lm -lc -lgcc -Wl,--end-group --specs=nano.specs -o ") + +set(CMAKE_CXX_OUTPUT_EXTENSION ".o") +set(CMAKE_DEPFILE_FLAGS_CXX "-MMD -MT -MF ") +set(CMAKE_C_OUTPUT_EXTENSION ".o") +set(CMAKE_DEPFILE_FLAGS_C "-MMD -MT -MF ") + +set(CMAKE_C_FLAGS_DEBUG_INIT "-g -gdwarf-3") +set(CMAKE_C_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") +set(CMAKE_C_FLAGS_RELEASE_INIT "-Os -DNDEBUG") +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-Os -g -gdwarf-3 -DNDEBUG") +set(CMAKE_INCLUDE_SYSTEM_FLAG_C "-isystem ") + + +set(CMAKE_ASM_FLAGS_DEBUG_INIT "-g -gdwarf-3") +set(CMAKE_ASM_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") +set(CMAKE_ASM_FLAGS_RELEASE_INIT "-Os -DNDEBUG") +set(CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT "-Os -g -gdwarf-3 -DNDEBUG") +set(CMAKE_INCLUDE_SYSTEM_FLAG_ASM "-isystem ") + +set(CMAKE_CXX_CREATE_STATIC_LIBRARY " rcs ") + +set(CMAKE_CXX_LINK_EXECUTABLE " -Wl,-Map,.map -Wl,--start-group -lm -lc -lgcc -Wl,--end-group -o ") + +set(CMAKE_CXX_FLAGS_DEBUG_INIT "-g -gdwarf-3") +set(CMAKE_CXX_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") +set(CMAKE_CXX_FLAGS_RELEASE_INIT "-Os -DNDEBUG") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-Os -g -gdwarf-3 -DNDEBUG") +set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-isystem ") diff --git a/utils/cmake/toolchains/AVR_GCC/hex-generator.cmake b/utils/cmake/toolchains/AVR_GCC/hex-generator.cmake new file mode 100644 index 0000000..5be3c67 --- /dev/null +++ b/utils/cmake/toolchains/AVR_GCC/hex-generator.cmake @@ -0,0 +1,9 @@ +add_custom_command( + OUTPUT "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.hex" + COMMAND "${AVR_OBJCOPY}" -O ihex "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${device.device}" "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.hex" + DEPENDS ${device.device} + COMMENT "converting to hex file." +) + +#specify a dependency on the elf file so that hex is automatically rebuilt when elf is changed. +add_custom_target(${device.device}_hex ALL DEPENDS "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.hex") diff --git a/utils/cmake/toolchains/AVR_GCC/platform_includes.h b/utils/cmake/toolchains/AVR_GCC/platform_includes.h new file mode 100644 index 0000000..ac788a5 --- /dev/null +++ b/utils/cmake/toolchains/AVR_GCC/platform_includes.h @@ -0,0 +1,14 @@ +#ifndef PLATFORM_INCLUDES +#define PLATFORM_INCLUDES + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/utils/cmake/toolchains/AVR_GCC/toolchain.cmake b/utils/cmake/toolchains/AVR_GCC/toolchain.cmake new file mode 100644 index 0000000..891aff2 --- /dev/null +++ b/utils/cmake/toolchains/AVR_GCC/toolchain.cmake @@ -0,0 +1,29 @@ +find_program(AVR_GCC_RANLIB avr-gcc-ranlib) +find_program(AVR_AR avr-ar) +find_program(AVR_AS avr-as) +find_program(AVR_GCC avr-gcc) +find_program(AVR_GPP avr-g++) +find_program(AVR_OBJCOPY avr-objcopy) + +set(CMAKE_OSX_SYSROOT "/") +set(CMAKE_OSX_DEPLOYMENT_TARGET "") + +set(CODAL_TOOLCHAIN "AVR_GCC") + +if(CMAKE_VERSION VERSION_LESS "3.5.0") + include(CMakeForceCompiler) + cmake_force_c_compiler("${AVR_GCC}" GNU) + cmake_force_cxx_compiler("${AVR_GPP}" GNU) +else() + #-Wl,-flto -flto -fno-fat-lto-objects + # from 3.5 the force_compiler macro is deprecated: CMake can detect + # arm-none-eabi-gcc as being a GNU compiler automatically + set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") + set(CMAKE_C_COMPILER "${AVR_GCC}") + set(CMAKE_CXX_COMPILER "${AVR_GPP}") +endif() + +SET(CMAKE_ASM_COMPILER "${AVR_GCC}") +SET(CMAKE_AR "${AVR_AR}" CACHE FILEPATH "Archiver") +SET(CMAKE_RANLIB "${AVR_GCC_RANLIB}" CACHE FILEPATH "rlib") +set(CMAKE_CXX_OUTPUT_EXTENSION ".o") diff --git a/utils/cmake/toolchains/XTENSA_GCC/bin-generator.cmake b/utils/cmake/toolchains/XTENSA_GCC/bin-generator.cmake new file mode 100644 index 0000000..74fdb35 --- /dev/null +++ b/utils/cmake/toolchains/XTENSA_GCC/bin-generator.cmake @@ -0,0 +1,9 @@ +add_custom_command( + OUTPUT "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.bin" + COMMAND "${XTENSA_OBJCOPY}" -O binary "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${device.device}" "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.bin" + DEPENDS ${device.device} + COMMENT "converting to bin file." +) + +#specify a dependency on the elf file so that bin is automatically rebuilt when elf is changed. +add_custom_target(${device.device}_bin ALL DEPENDS "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.bin") diff --git a/utils/cmake/toolchains/XTENSA_GCC/compiler-flags.cmake b/utils/cmake/toolchains/XTENSA_GCC/compiler-flags.cmake new file mode 100644 index 0000000..e0f7e2d --- /dev/null +++ b/utils/cmake/toolchains/XTENSA_GCC/compiler-flags.cmake @@ -0,0 +1,43 @@ +set(EXPLICIT_INCLUDES "") +if((CMAKE_VERSION VERSION_GREATER "3.4.0") OR (CMAKE_VERSION VERSION_EQUAL "3.4.0")) + # from CMake 3.4 are separate to in the + # CMAKE__COMPILE_OBJECT, CMAKE__CREATE_ASSEMBLY_SOURCE, and + # CMAKE__CREATE_PREPROCESSED_SOURCE commands + set(EXPLICIT_INCLUDES " ") +endif() + +# Override the link rules: +set(CMAKE_C_CREATE_SHARED_LIBRARY "echo 'shared libraries not supported' && 1") +set(CMAKE_C_CREATE_SHARED_MODULE "echo 'shared modules not supported' && 1") +set(CMAKE_C_CREATE_STATIC_LIBRARY " -cr ") +set(CMAKE_C_COMPILE_OBJECT " ${EXPLICIT_INCLUDES} -o -c ") + +set(CMAKE_C_LINK_EXECUTABLE " -nostdlib -Wl,-Map,.map -Wl,--start-group -lupgrade -lssl -lmesh -lwpa2 -lsmartconfig -lespnow -lpp -lmain -lwpa -llwip -lnet80211 -lwps -lcrypto -lphy -lhal -lgcc -ldriver -lm -lat -lc -lstdc++ -Wl,--end-group -lgcc -o ") + +set(CMAKE_CXX_OUTPUT_EXTENSION ".o") +set(CMAKE_DEPFILE_FLAGS_CXX "-MMD -MT -MF ") +set(CMAKE_C_OUTPUT_EXTENSION ".o") +set(CMAKE_DEPFILE_FLAGS_C "-MMD -MT -MF ") + +set(CMAKE_C_FLAGS_DEBUG_INIT "-g -gdwarf-3") +set(CMAKE_C_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") +set(CMAKE_C_FLAGS_RELEASE_INIT "-Os -DNDEBUG") +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-Os -g -gdwarf-3 -DNDEBUG") +set(CMAKE_INCLUDE_SYSTEM_FLAG_C "-isystem ") + + +set(CMAKE_ASM_FLAGS_DEBUG_INIT "-g -gdwarf-3") +set(CMAKE_ASM_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") +set(CMAKE_ASM_FLAGS_RELEASE_INIT "-Os -DNDEBUG") +set(CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT "-Os -g -gdwarf-3 -DNDEBUG") +set(CMAKE_INCLUDE_SYSTEM_FLAG_ASM "-isystem ") + +set(CMAKE_CXX_CREATE_STATIC_LIBRARY " -cr ") +set(CMAKE_CXX_LINK_EXECUTABLE " -nostdlib -Wl,-Map,.map -Wl,--start-group -lupgrade -lssl -lmesh -lwpa2 -lsmartconfig -lespnow -lpp -lmain -lwpa -llwip -lnet80211 -lwps -lcrypto -ldriver -lat -lphy -lhal -lgcc -lm -lc -lstdc++ -o ") +#set(CMAKE_CXX_LINK_EXECUTABLE " -nostdlib -Wl,-Map,.map -Wl,--start-group -lpwm -lupgrade -lssl -lgcc -lhal -lphy -lpp -lnet80211 -lwpa -lmain -llwip -lcrypto -lm -lc -o ") + +set(CMAKE_CXX_FLAGS_DEBUG_INIT "-g -gdwarf-3") +set(CMAKE_CXX_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") +set(CMAKE_CXX_FLAGS_RELEASE_INIT "-Os -DNDEBUG") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-Os -g -gdwarf-3 -DNDEBUG") +set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-isystem ") diff --git a/utils/cmake/toolchains/XTENSA_GCC/hex-generator.cmake b/utils/cmake/toolchains/XTENSA_GCC/hex-generator.cmake new file mode 100644 index 0000000..4948935 --- /dev/null +++ b/utils/cmake/toolchains/XTENSA_GCC/hex-generator.cmake @@ -0,0 +1,9 @@ +add_custom_command( + OUTPUT "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.hex" + COMMAND "${ARM_NONE_EABI_OBJCOPY}" -O ihex "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${device.device}" "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.hex" + DEPENDS ${device.device} + COMMENT "converting to hex file." +) + +#specify a dependency on the elf file so that hex is automatically rebuilt when elf is changed. +add_custom_target(${device.device}_hex ALL DEPENDS "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.hex") diff --git a/utils/cmake/toolchains/XTENSA_GCC/platform_includes.h b/utils/cmake/toolchains/XTENSA_GCC/platform_includes.h new file mode 100644 index 0000000..3417ef3 --- /dev/null +++ b/utils/cmake/toolchains/XTENSA_GCC/platform_includes.h @@ -0,0 +1,10 @@ +#ifndef PLATFORM_INCLUDES +#define PLATFORM_INCLUDES + +#include +#include +#include +#include +#include + +#endif diff --git a/utils/cmake/toolchains/XTENSA_GCC/toolchain.cmake b/utils/cmake/toolchains/XTENSA_GCC/toolchain.cmake new file mode 100644 index 0000000..6789edd --- /dev/null +++ b/utils/cmake/toolchains/XTENSA_GCC/toolchain.cmake @@ -0,0 +1,26 @@ +find_program(XTENSA_RANLIB xtensa-lx106-elf-gcc-ranlib) +find_program(XTENSA_AR xtensa-lx106-elf-gcc-ar) +find_program(XTENSA_GCC xtensa-lx106-elf-gcc) +find_program(XTENSA_GPP xtensa-lx106-elf-g++) +find_program(XTENSA_OBJCOPY xtensa-lx106-elf-objcopy) + +set(CMAKE_OSX_SYSROOT "/") +set(CMAKE_OSX_DEPLOYMENT_TARGET "") + +set(CODAL_TOOLCHAIN "XTENSA_GCC") + +if(CMAKE_VERSION VERSION_LESS "3.5.0") + include(CMakeForceCompiler) + cmake_force_c_compiler("${XTENSA_GCC}" GNU) + cmake_force_cxx_compiler("${XTENSA_GPP}" GNU) +else() + # from 3.5 the force_compiler macro is deprecated: CMake can detect + # arm-none-eabi-gcc as being a GNU compiler automatically + set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") + set(CMAKE_C_COMPILER "${XTENSA_GCC}") + set(CMAKE_CXX_COMPILER "${XTENSA_GPP}") +endif() + +SET(CMAKE_AR "${XTENSA_AR}" CACHE FILEPATH "Archiver") +SET(CMAKE_RANLIB "${XTENSA_RANLIB}" CACHE FILEPATH "rlib") +set(CMAKE_CXX_OUTPUT_EXTENSION ".o") diff --git a/utils/cmake/util.cmake b/utils/cmake/util.cmake new file mode 100644 index 0000000..6e3a815 --- /dev/null +++ b/utils/cmake/util.cmake @@ -0,0 +1,156 @@ +MACRO(RECURSIVE_FIND_DIR return_list dir pattern) + FILE(GLOB_RECURSE new_list "${dir}/${pattern}") + SET(dir_list "") + FOREACH(file_path ${new_list}) + GET_FILENAME_COMPONENT(dir_path ${file_path} PATH) + SET(dir_list ${dir_list} ${dir_path}) + ENDFOREACH() + LIST(REMOVE_DUPLICATES dir_list) + SET(${return_list} ${dir_list}) +ENDMACRO() + +MACRO(RECURSIVE_FIND_FILE return_list dir pattern) + FILE(GLOB_RECURSE new_list "${dir}/${pattern}") + SET(dir_list "") + FOREACH(file_path ${new_list}) + SET(dir_list ${dir_list} ${file_path}) + ENDFOREACH() + LIST(REMOVE_DUPLICATES dir_list) + SET(${return_list} ${dir_list}) +ENDMACRO() + +MACRO(SOURCE_FILES return_list dir pattern) + FILE(GLOB new_list "${dir}/${pattern}") + SET(dir_list "") + FOREACH(file_path ${new_list}) + LIST(APPEND dir_list ${file_path}) + ENDFOREACH() + LIST(REMOVE_DUPLICATES dir_list) + SET(${return_list} ${dir_list}) +ENDMACRO() + +function(EXTRACT_JSON_ARRAY json_file json_field_path fields values) + + set(VALUES "") + set(FIELDS "") + + foreach(var ${${json_file}}) + # extract any cmd line definitions specified in the json object, and add them + # if it is not prefixed by json_field_path, do not consider the key. + if("${var}" MATCHES "${json_field_path}") + string(REGEX MATCH "[^${json_field_path}]([A-Z,a-z,0-9,_,]+)" VALUE "${var}") + + # never quote the value - gives more flexibility + list(APPEND FIELDS ${VALUE}) + list(APPEND VALUES "${${var}}") + endif() + endforeach() + + set(${fields} ${FIELDS} PARENT_SCOPE) + set(${values} ${VALUES} PARENT_SCOPE) +endfunction() + +function(FORM_DEFINITIONS fields values definitions) + + set(DEFINITIONS "") + list(LENGTH ${fields} LEN) + + # - 1 for for loop index... + MATH(EXPR LEN "${LEN}-1") + + foreach(i RANGE ${LEN}) + list(GET ${fields} ${i} DEFINITION) + list(GET ${values} ${i} VALUE) + + set(DEFINITIONS "${DEFINITIONS} #define ${DEFINITION}\t ${VALUE}\n") + endforeach() + + set(${definitions} ${DEFINITIONS} PARENT_SCOPE) +endfunction() + +function(UNIQUE_JSON_KEYS priority_fields priority_values secondary_fields secondary_values merged_fields merged_values) + + # always keep the first fields and values + set(MERGED_FIELDS ${${priority_fields}}) + set(MERGED_VALUES ${${priority_values}}) + + # measure the second set... + list(LENGTH ${secondary_fields} LEN) + # - 1 for for loop index... + MATH(EXPR LEN "${LEN}-1") + + # iterate, dropping any duplicate fields regardless of the value + foreach(i RANGE ${LEN}) + list(GET ${secondary_fields} ${i} FIELD) + list(GET ${secondary_values} ${i} VALUE) + + list(FIND MERGED_FIELDS ${FIELD} INDEX) + + if (${INDEX} GREATER -1) + continue() + endif() + + list(APPEND MERGED_FIELDS ${FIELD}) + list(APPEND MERGED_VALUES ${VALUE}) + endforeach() + + set(${merged_fields} ${MERGED_FIELDS} PARENT_SCOPE) + set(${merged_values} ${MERGED_VALUES} PARENT_SCOPE) +endfunction() + +MACRO(HEADER_FILES return_list dir) + FILE(GLOB new_list "${dir}/*.h") + SET(${return_list} ${new_list}) +ENDMACRO() + +function(INSTALL_DEPENDENCY dir name url branch type) + if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/${dir}") + message("Creating libraries folder") + FILE(MAKE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/${dir}") + endif() + + if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${dir}/${name}") + message("${name} is already installed") + return() + endif() + + if(${type} STREQUAL "git") + message("Cloning into: ${url}") + # git clone -b doesn't work with SHAs + execute_process( + COMMAND git clone --recurse-submodules ${url} ${name} + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/${dir} + ) + + if(NOT "${branch}" STREQUAL "") + message("Checking out branch: ${branch}") + execute_process( + COMMAND git -c advice.detachedHead=false checkout ${branch} + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/${dir}/${name} + ) + execute_process( + COMMAND git submodule update --init + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/${dir}/${name} + ) + execute_process( + COMMAND git submodule sync + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/${dir}/${name} + ) + execute_process( + COMMAND git submodule update + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/${dir}/${name} + ) + endif() + else() + message("No mechanism exists to install this library.") + endif() +endfunction() + +MACRO(SUB_DIRS return_dirs dir) + FILE(GLOB list "${PROJECT_SOURCE_DIR}/${dir}/*") + SET(dir_list "") + FOREACH(file_path ${list}) + SET(dir_list ${dir_list} ${file_path}) + ENDFOREACH() + set(${return_dirs} ${dir_list}) +ENDMACRO() diff --git a/utils/generate_libraries.py b/utils/generate_libraries.py new file mode 100644 index 0000000..45db25c --- /dev/null +++ b/utils/generate_libraries.py @@ -0,0 +1,159 @@ +import os +import git +from git import Actor +import optparse +import fnmatch +import glob +import shutil +import ntpath +import json + +def make_cmake(lib_name, lib_file_name, include_path, dest): + print "LIB NAME " + lib_name + with open(dest + "/CMakeLists.txt", 'w') as f: + lines = [ + "project(" + lib_name + ")\r\n" + "add_library(" + lib_name + " STATIC " + lib_file_name + ")\r\n", + "set_target_properties(" + lib_name +" PROPERTIES LINKER_LANGUAGE CXX)\r\n", + "target_include_directories(" + lib_name + " PUBLIC \"" + include_path + "\")\r\n", + ] + print "LINES : " + str(lines) + f.writelines(lines) + f.close() + +def copytree(src, dst, symlinks=False, ignore=None): + if not os.path.exists(dst): + os.makedirs(dst) + for item in os.listdir(src): + s = os.path.join(src, item) + d = os.path.join(dst, item) + if os.path.isdir(s): + copytree(s, d, symlinks, ignore) + else: + if not os.path.exists(d) or os.stat(s).st_mtime - os.stat(d).st_mtime > 1: + shutil.copy2(s, d) + +def path_leaf(path): + head, tail = ntpath.split(path) + return tail or ntpath.basename(head) + +def recursive_glob(treeroot, pattern): + results = [] + for base, dirs, files in os.walk(treeroot): + goodfiles = fnmatch.filter(files, pattern) + results.extend(os.path.join(base, f) for f in goodfiles) + return results + +parser = optparse.OptionParser() +parser.add_option('-c', '--clean', dest='clean', action="store_true", help='Whether to clean before building.', default=False) + +(options, args) = parser.parse_args() + +os.chdir("..") + +if not os.path.exists("build"): + os.mkdir("build") + +# out of source build! +os.chdir("build") + +# configure os.system("cmake ..") +os.system("cmake .. -DCODAL_HEADER_EXTRACTION:BOOL=TRUE") + +if options.clean: + os.system("make clean") + +# build +os.system("make -j 10") + +with open('../codal.json') as data_file: + codal = json.load(data_file) + +#ntpath.basename(f) +folders = [path_leaf(f) for f in glob.glob("../libraries/*/")] +header_folders = [path_leaf(f) for f in glob.glob("./build/*/")] + +print folders +print header_folders + +mapping = [] + +#note for next time, need to copy all lib files to their appropriate build/lib place otherwise they get auto cleaned. + +valid_libs = [] + +for folder in header_folders: + lib_file_name = "lib" + folder + ".a" + if not os.path.exists("./"+lib_file_name): + print "No library exists, skipping: " + lib_file_name + continue + + shutil.copy("./" + lib_file_name, "./build/"+folder) + valid_libs = valid_libs + [folder] + + +for folder in valid_libs: + lib_name = folder + lib_file_name = "lib" + folder + ".a" + folder_path = '../libraries/' + folder + header_folder = "./build/" + folder + header_ext = "includes" + + with open(folder_path + "CMakeLists.txt") as cmake: + + "target_link_libraries\((?:\s*(.+))+\s*\)" + + for line in cmake.lines(): + if "target_link_libraries" in line + + + + # get the repo + try: + repo = git.Repo('../libraries/' + folder) + except: + print folder + " is not a valid git repository." + continue + + active_branch = repo.active_branch.name + + # check for any uncommitted changes + if len(repo.index.diff(None)) > 0 : + print folder + " has uncommitted changes, skipping." + continue; + + branch_names = [b.name for b in repo.branches] + + lib_branch_name = "lib_" + codal["target"]["processor"] + codal["target"]["device"] + + # tag using above + version specified in target.json + + # swap to an orphaned branch if none exists + if lib_branch_name not in branch_names: + repo.active_branch.checkout(orphan=lib_branch_name) + + for f in glob.glob(folder_path + "/*/"): + shutil.rmtree(f) + + files = [f for f in os.listdir('.') if os.path.isfile(f)] + + for file in files: + os.remove(file) + else: + repo.active_branch.checkout(lib_branch_name) + + repo.index.remove("*", r=True) + + copytree(header_folder, folder_path + "/") + + make_cmake(lib_name, lib_file_name, header_ext, folder_path + "/") + + repo.index.add("*") + + author = Actor("codal", "codal@example.com") + + repo.index.commit("Library generated", author=author, committer=author) + + #repo.git.checkout(active_branch) + + #break diff --git a/utils/python/__init__.py b/utils/python/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/utils/python/codal_utils.py b/utils/python/codal_utils.py new file mode 100644 index 0000000..636f3a8 --- /dev/null +++ b/utils/python/codal_utils.py @@ -0,0 +1,216 @@ +import os +import sys +import optparse +import platform +import json +import shutil +import re + +import os, re, json, xml.etree.ElementTree +from optparse import OptionParser +import subprocess + + +def system(cmd): + if os.system(cmd) != 0: + sys.exit(1) + +def build(clean, verbose = False, parallelism = 10): + if platform.system() == "Windows": + # configure + system("cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -G \"Ninja\"") + + if clean: + system("ninja clean") + + # build + if verbose: + system("ninja -j {} --verbose".format(parallelism)) + else: + system("ninja -j {}".format(parallelism)) + else: + # configure + system("cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -G \"Unix Makefiles\"") + + if clean: + system("make clean") + + # build + if verbose: + system("make -j {} VERBOSE=1".format(parallelism)) + else: + system("make -j {}".format(parallelism)) + +def read_json(fn): + json_file = "" + with open(fn) as f: + json_file = f.read() + return json.loads(json_file) + +def checkgit(): + stat = os.popen('git status --porcelain').read().strip() + if stat != "": + print("Missing checkin in", os.getcwd(), "\n" + stat) + exit(1) + +def read_config(): + codal = read_json("codal.json") + targetdir = codal['target']['name'] + target = read_json("libraries/" + targetdir + "/target.json") + return (codal, targetdir, target) + +def update(allow_detached=False, sync_dev=False): + (codal, targetdir, target) = read_config() + dirname = os.getcwd() + for ln in target['libraries']: + os.chdir(dirname + "/libraries/" + ln['name']) + if sync_dev: + default_branch = list(filter( lambda v: v.strip().startswith('HEAD'), str(subprocess.check_output( ["git", "remote", "show", "origin"] ), "utf8").splitlines()))[0].split(":")[1].strip() + system("git checkout " + default_branch) + else: + system("git checkout " + ln['branch']) + system("git pull") + os.chdir(dirname + "/libraries/" + targetdir) + if ("HEAD detached" in os.popen('git branch').read().strip() and + allow_detached == False): + system("git checkout master") + system("git pull") + os.chdir(dirname) + +def revision(rev): + (codal, targetdir, target) = read_config() + dirname = os.getcwd() + os.chdir("libraries/" + targetdir) + system("git checkout " + rev) + os.chdir(dirname) + update(True) + +def printstatus( logLines = 3, detail = False ): + print("\n***%s" % os.getcwd()) + branch = str(subprocess.check_output( [ "git", "branch", "--show-current"] ), "utf8").strip() + hash = str(subprocess.check_output( [ "git", "rev-parse", "HEAD" ] ), "utf8").strip() + tag = "..." + try: + tag = str(subprocess.check_output( [ "git", "describe", "--tags", "--abbrev=0" ], stderr=subprocess.STDOUT ), "utf8").strip() + except subprocess.CalledProcessError as e: + tag = "~none~" + + print( "Branch: {branch}, Nearest Tag: {tag} ({hash})".format(branch=branch, tag=tag, hash=hash) ) + if detail: + system( "git --no-pager log -n {} --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit".format(logLines) ) + print( "" ) + + system("git status -sb") + print( "" ) + + +def status( logLines = 3, detail = True, libs = [] ): + (codal, targetdir, target) = read_config() + dirname = os.getcwd() + + if len(libs) == 0: + for ln in target['libraries']: + os.chdir(dirname + "/libraries/" + ln['name']) + printstatus( logLines, detail ) + os.chdir(dirname + "/libraries/" + targetdir) + printstatus( logLines, detail ) + os.chdir(dirname) + printstatus( logLines, detail ) + else: + for lib in libs: + os.chdir(dirname + "/libraries/" + lib) + printstatus( logLines, detail ) + +def get_next_version(options): + if options.version: + return options.version + log = os.popen('git log -n 100').read().strip() + m = re.search('Snapshot v(\d+)\.(\d+)\.(\d+)(-([\w\-]+).(\d+))?', log) + if m is None: + print("Cannot determine next version from git log") + exit(1) + v0 = int(m.group(1)) + v1 = int(m.group(2)) + v2 = int(m.group(3)) + vB = -1 + branchName = os.popen('git rev-parse --abbrev-ref HEAD').read().strip() + if not options.branch and branchName not in ["master","main"]: + print("On feature branch use -l -b") + exit(1) + suff = "" + if options.branch: + if m.group(4) and branchName == m.group(5): + vB = int(m.group(6)) + suff = "-%s.%d" % (branchName, vB + 1) + elif options.update_major: + v0 += 1 + v1 = 0 + v2 = 0 + elif options.update_minor: + v1 += 1 + v2 = 0 + else: + v2 += 1 + return "v%d.%d.%d%s" % (v0, v1, v2, suff) + +def lock(options): + (codal, targetdir, target) = read_config() + dirname = os.getcwd() + for ln in target['libraries']: + os.chdir(dirname + "/libraries/" + ln['name']) + checkgit() + stat = os.popen('git status --porcelain -b').read().strip() + if "ahead" in stat: + print("Missing push in", os.getcwd()) + exit(1) + sha = os.popen('git rev-parse HEAD').read().strip() + ln['branch'] = sha + print(ln['name'], sha) + os.chdir(dirname + "/libraries/" + targetdir) + ver = get_next_version(options) + print("Creating snaphot", ver) + system("git checkout target-locked.json") + checkgit() + target["snapshot_version"] = ver + with open("target-locked.json", "w") as f: + f.write(json.dumps(target, indent=4, sort_keys=True)) + system("git commit -am \"Snapshot %s\"" % ver) # must match get_next_version() regex + sha = os.popen('git rev-parse HEAD').read().strip() + system("git tag %s" % ver) + system("git pull") + system("git push") + system("git push --tags") + os.chdir(dirname) + print("\nNew snapshot: %s [%s]" % (ver, sha)) + +def delete_build_folder(in_folder = True): + if in_folder: + os.chdir("..") + + shutil.rmtree('./build') + os.mkdir("./build") + + if in_folder: + os.chdir("./build") + +def generate_docs(): + from doc_gen.doxygen_extractor import DoxygenExtractor + from doc_gen.md_converter import MarkdownConverter + from doc_gen.system_utils import SystemUtils + from doc_gen.doc_gen import generate_mkdocs + + os.chdir("..") + (codal, targetdir, target) = read_config() + + lib_dir = os.getcwd() + "/libraries/" + + libraries = [lib_dir + targetdir] + + for l in target["libraries"]: + libraries = libraries + [ lib_dir + l["name"]] + + os.chdir(lib_dir + targetdir) + + generate_mkdocs(libraries) + + diff --git a/utils/targets.json b/utils/targets.json new file mode 100644 index 0000000..3b485db --- /dev/null +++ b/utils/targets.json @@ -0,0 +1,105 @@ +[ + { + "name":"codal-arduino-uno", + "info":"This target specifies the arduino uno which is driven by an atmega328p.", + "device_url":"https://store.arduino.cc/arduino-uno-rev3", + "url":"https://github.com/lancaster-university/codal-arduino-uno", + "branch":"master", + "type":"git" + }, + { + "name":"codal-circuit-playground", + "info":"This target specifies the circuit playground which is driven by a SAMD21.", + "device_url":"https://www.adafruit.com/product/3333", + "url":"https://github.com/lancaster-university/codal-circuit-playground", + "branch":"master", + "type":"git" + }, + { + "name":"codal-microbit", + "info":"This target specifies the microbit, which uses the nordic NRF51822.", + "device_url":"https://microbit.org", + "url":"https://github.com/lancaster-university/codal-microbit", + "test_ignore":true, + "branch":"codal-microbit-mbed", + "type":"git" + }, + { + "name":"codal-huzzah", + "info":"This target specifies the HUZZAH which is driven by a ESP8266.", + "device_url":"https://www.adafruit.com/product/3405", + "url":"https://github.com/lancaster-university/codal-huzzah", + "test_ignore":true, + "branch":"master", + "type":"git" + }, + { + "name":"codal-brainpad", + "info":"This target specifies the BRAINPAD which is driven by a STM32f.", + "device_url":"https://brainpad.com", + "url":"https://github.com/lancaster-university/codal-brainpad", + "branch":"master", + "type":"git" + }, + { + "name":"codal-microbit-next", + "info":"version 1.4 revision of the BBC micro:bit.", + "device_url":"https://www.microbit.org", + "url":"https://github.com/microbit-foundation/codal-microbit-next", + "test_ignore":true, + "branch":"nrf52833-mbedos", + "type":"git" + }, + { + "name":"codal-ble-nano", + "info":"This target specifies the ble-nano by RedBear which is driven by a NRF52.", + "device_url":"https://redbear.cc/product/ble-nano-kit-2.html", + "url":"https://github.com/lancaster-university/codal-ble-nano", + "branch":"master", + "type":"git" + }, + { + "name":"codal-stm32-iot-node", + "info":"This target specifies the STM32 IoT Node board which is driven by a STM32L475.", + "device_url":"http://www.st.com/en/evaluation-tools/b-l475e-iot01a.html", + "url":"https://github.com/LabAixBidouille-STM32/codal-stm32-iot-node", + "test_ignore":true, + "branch":"master", + "type":"git" + }, + { + "name":"codal-big-brainpad", + "info":"This target specifies the stm32f401re (The big brain pad).", + "device_url":"", + "url":"https://github.com/lancaster-university/codal-big-brainpad", + "branch":"master", + "type":"git", + "test_ignore":true + }, + { + "name":"codal-mkr1300", + "info":"This target specifies the arduino mkr1300 variant.", + "device_url":"", + "url":"https://github.com/ElectronicCats/codal-mkr1300", + "branch":"master", + "type":"git", + "test_ignore":true + }, + { + "name":"codal-jacdac-feather", + "info":"This target specifies the jacdac-feather board based on the stmf103", + "device_url":"", + "url":"https://github.com/lancaster-university/codal-jacdac-feather", + "branch":"master", + "type":"git", + "test_ignore":true + }, + { + "name":"codal-itsybitsy-m4", + "info":"This target specifies the adafruit itsybitsy board.", + "device_url":"", + "url":"https://github.com/lancaster-university/codal-itsybitsy-m4", + "branch":"master", + "type":"git" + } +]