From 7e9d1bdda4a50dc66b6429739ff487a5bc959476 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Tue, 5 Feb 2019 10:36:22 +0100 Subject: [PATCH] CMake/Kconfig: CMake and Kconfig build integration This commit allows for Zephyr modules to be natively integrated into the build system with CMakeLists.txt and Kconfig files. The sourcing of module files are done in following order: - If /zephyr/module.yml exists, use cmake and kconfig settings for sourcing of additional file - Else if /zephyr/CMakeLists.txt exists, source this file into CMake build tree and add /zephyr/Kconfig as osource If none of the above files are present, the project is considered to not be a Zephyr module Signed-off-by: Torsten Rasmussen --- CMakeLists.txt | 9 ++++ Kconfig.zephyr | 2 + cmake/app/boilerplate.cmake | 1 + cmake/zephyr_module.cmake | 84 +++++++++++++++++++++++++++++++++++++ scripts/yaml_to_cmake.py | 68 ++++++++++++++++++++++++++++++ 5 files changed, 164 insertions(+) create mode 100644 cmake/zephyr_module.cmake create mode 100755 scripts/yaml_to_cmake.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 61e83ba2158..b270fd4f066 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -552,6 +552,15 @@ add_subdirectory(subsys) add_subdirectory(drivers) add_subdirectory(tests) +# Add all zephyr modules subdirectories. +message("Including module(s): ${ZEPHYR_MODULES_NAME}") +set(index 0) +foreach(module_name ${ZEPHYR_MODULES_NAME}) + list(GET ZEPHYR_MODULES_DIR ${index} module_dir) + math(EXPR index "${index} + 1") + add_subdirectory(${module_dir} ${CMAKE_BINARY_DIR}/${module_name}) +endforeach() + set(syscall_macros_h ${ZEPHYR_BINARY_DIR}/include/generated/syscall_macros.h) add_custom_target(${SYSCALL_MACROS_H_TARGET} DEPENDS ${syscall_macros_h}) diff --git a/Kconfig.zephyr b/Kconfig.zephyr index 4891c543c7b..287e9a58d6f 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -40,6 +40,8 @@ source "ext/Kconfig" source "tests/Kconfig" +source "$(PROJECT_BINARY_DIR)/Kconfig.modules" + menu "Build and Link Features" menu "Linker Options" diff --git a/cmake/app/boilerplate.cmake b/cmake/app/boilerplate.cmake index e79c9d54227..b5daa60b05a 100644 --- a/cmake/app/boilerplate.cmake +++ b/cmake/app/boilerplate.cmake @@ -396,6 +396,7 @@ include(${ZEPHYR_BASE}/cmake/host-tools.cmake) # preprocess DT sources, and then, after we have finished processing # both DT and Kconfig we complete the target-specific configuration, # and possibly change the toolchain. +include(${ZEPHYR_BASE}/cmake/zephyr_module.cmake) include(${ZEPHYR_BASE}/cmake/generic_toolchain.cmake) include(${ZEPHYR_BASE}/cmake/dts.cmake) include(${ZEPHYR_BASE}/cmake/kconfig.cmake) diff --git a/cmake/zephyr_module.cmake b/cmake/zephyr_module.cmake new file mode 100644 index 00000000000..203eabe8fbd --- /dev/null +++ b/cmake/zephyr_module.cmake @@ -0,0 +1,84 @@ +# This cmake file provides functionality to import additional out-of-tree, OoT +# CMakeLists.txt and Kconfig files into Zephyr build system. +# It uses -DZEPHYR_MODULES=[;] +# given to CMake for a list of folders to search. +# It looks for: /zephyr/module.yml or +# /zephyr/CMakeLists.txt +# to load the oot-module into Zephyr build system. +# If west is available, it uses `west list` to obtain a list of projects to +# search for zephyr/module.yml + +if(ZEPHYR_MODULES) + set(west_project_list ${ZEPHYR_MODULES}) +elseif(WEST) + ## Use `west list` to fetch all west handled projects. + execute_process( + COMMAND + ${WEST} list --format={posixpath} + OUTPUT_VARIABLE + west_project_output + ) + string(REGEX REPLACE "[\r\n]+" ";" west_project_list "${west_project_output}") +endif() + +if(ZEPHYR_EXTRA_MODULES) + list(APPEND west_project_list ${ZEPHYR_EXTRA_MODULES}) +endif() + +# Clear the Kconfig.modules generated file in case modules has been removed. +# The Kconfig.modules contains a list of additional Kconfig files to be sourced +# based upon /zephyr/module.yml files. +file(WRITE ${PROJECT_BINARY_DIR}/Kconfig.modules + "# NOTE: THIS FILE IS AUTOGENERATED BY CMAKE\n" + ) +# For each west managed project, determine if the project is a zephyr module. +foreach(module ${west_project_list}) + set(cmake_subdir "zephyr") + if(${ZEPHYR_BASE} STREQUAL ${module}) + # Ignore Zephyr project to avoid potential invalid looping + elseif(EXISTS "${module}/zephyr/module.yml") + set(kconfig_osource "osource \"${module}/zephyr/Kconfig\"\n") + get_filename_component(module_name ${module} NAME) + execute_process( + COMMAND + ${PYTHON_EXECUTABLE} + ${ZEPHYR_BASE}/scripts/yaml_to_cmake.py + -i "${module}/zephyr/module.yml" + -o "${CMAKE_CURRENT_BINARY_DIR}/zephyr_module_${module_name}.txt" + -s "build" + ) + file( + STRINGS + "${CMAKE_CURRENT_BINARY_DIR}/zephyr_module_${module_name}.txt" + zephyr_module + ) + + foreach(key_value ${zephyr_module}) + if(${key_value} MATCHES "^cmake=") + string(REGEX REPLACE "^cmake=" "" cmake_subdir ${key_value}) + elseif(${key_value} MATCHES "^kconfig=") + string( + REGEX REPLACE + "^kconfig=" + "osource \"${module}/" + kconfig_osource + ${key_value} "\"\n" + ) + endif() + endforeach() + + list(APPEND ZEPHYR_MODULES_NAME ${module_name}) + list(APPEND ZEPHYR_MODULES_DIR ${module}/${cmake_subdir}) + file(APPEND ${PROJECT_BINARY_DIR}/Kconfig.modules ${kconfig_osource}) + elseif(EXISTS "${module}/${cmake_subdir}/CMakeLists.txt") + set(kconfig_osource "osource \"${module}/zephyr/Kconfig\"\n") + get_filename_component(module_name ${module} NAME) + list(APPEND ZEPHYR_MODULES_NAME ${module_name}) + list(APPEND ZEPHYR_MODULES_DIR ${module}/${cmake_subdir}) + file(APPEND ${PROJECT_BINARY_DIR}/Kconfig.modules ${kconfig_osource}) + else() + # Not a Zephyr module, ignore. + endif() + +endforeach() + diff --git a/scripts/yaml_to_cmake.py b/scripts/yaml_to_cmake.py new file mode 100755 index 00000000000..7da027ec8ee --- /dev/null +++ b/scripts/yaml_to_cmake.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2019, Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +'''Tool for a simple parsing of YAML files and return a ;-list of = +pairs to use within a CMake build file. +''' + +import argparse +import sys +import yaml +import pykwalify.core + + +METADATA_SCHEMA = '''\ +## A pykwalify schema for basic validation of the structure of a +## metadata YAML file. +## +# The zephyr/module.yml file is a simple list of key value pairs to be used by +# the build system. +type: map +mapping: + build: + required: true + type: map + mapping: + cmake: + required: false + type: str + kconfig: + required: false + type: str +''' + + +def main(): + parser = argparse.ArgumentParser(description=''' + Converts YAML to a CMake list''') + + parser.add_argument('-i', '--input', required=True, + help='YAML file with data') + parser.add_argument('-o', '--output', required=True, + help='File to write with CMake data') + parser.add_argument('-s', '--section', required=True, + help='Section in YAML file to parse') + args = parser.parse_args() + + with open(args.input, 'r') as f: + meta = yaml.safe_load(f.read()) + + pykwalify.core.Core(source_data=meta, + schema_data=yaml.safe_load(METADATA_SCHEMA)).validate() + + val_str = '' + + section = meta.get(args.section) + if section is not None: + for key in section: + val_str += '{}={}\n'.format(key, section[key]) + + with open(args.output, 'w') as f: + f.write(val_str) + + +if __name__ == "__main__": + main()