build system: Initial cmake support, work in progress

This commit is contained in:
Angus Gratton
2018-01-12 13:49:13 +11:00
committed by Angus Gratton
parent a538644560
commit c671a0c3eb
56 changed files with 1115 additions and 5 deletions

View File

@@ -0,0 +1,130 @@
# - Returns a version string from Git
#
# These functions force a re-configure on each git commit so that you can
# trust the values of the variables in your build system.
#
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
#
# Returns the refspec and sha hash of the current head revision
#
# git_describe(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe on the source tree, and adjusting
# the output so that it tests false if an error occurs.
#
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe --exact-match on the source tree,
# and adjusting the output so that it tests false if there was no exact
# matching tag.
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
if(__get_git_revision_description)
return()
endif()
set(__get_git_revision_description YES)
# We must run the following at "include" time, not at function call time,
# to find the path to this module rather than the path to a calling list file
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
function(get_git_head_revision _refspecvar _hashvar)
set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
# We have reached the root directory, we are not in git
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
return()
endif()
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
endwhile()
# check if this is a submodule
if(NOT IS_DIRECTORY ${GIT_DIR})
file(READ ${GIT_DIR} submodule)
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
endif()
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
if(NOT EXISTS "${GIT_DATA}")
file(MAKE_DIRECTORY "${GIT_DATA}")
endif()
if(NOT EXISTS "${GIT_DIR}/HEAD")
return()
endif()
set(HEAD_FILE "${GIT_DATA}/HEAD")
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
"${GIT_DATA}/grabRef.cmake"
@ONLY)
include("${GIT_DATA}/grabRef.cmake")
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
endfunction()
function(git_describe _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
get_git_head_revision(refspec hash)
if(NOT GIT_FOUND)
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif()
if(NOT hash)
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
return()
endif()
# TODO sanitize
#if((${ARGN}" MATCHES "&&") OR
# (ARGN MATCHES "||") OR
# (ARGN MATCHES "\\;"))
# message("Please report the following error to the project!")
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
#endif()
#message(STATUS "Arguments to execute_process: ${ARGN}")
execute_process(COMMAND
"${GIT_EXECUTABLE}"
describe
${hash}
${ARGN}
WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE
res
OUTPUT_VARIABLE
out
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(out "${out}-${res}-NOTFOUND")
endif()
set(${_var} "${out}" PARENT_SCOPE)
endfunction()
function(git_get_exact_tag _var)
git_describe(out --exact-match ${ARGN})
set(${_var} "${out}" PARENT_SCOPE)
endfunction()

View File

@@ -0,0 +1,41 @@
#
# Internal file for GetGitRevisionDescription.cmake
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
set(HEAD_HASH)
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
if(HEAD_CONTENTS MATCHES "ref")
# named branch
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
else()
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
set(HEAD_HASH "${CMAKE_MATCH_1}")
endif()
endif()
else()
# detached HEAD
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
endif()
if(NOT HEAD_HASH)
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
string(STRIP "${HEAD_HASH}" HEAD_HASH)
endif()

View File

@@ -0,0 +1,13 @@
# Glue to build the bootloader subproject binary as an external
# cmake project under this one
#
#
ExternalProject_Add(bootloader_subproject
# TODO: support overriding the bootloader in COMPONENT_PATHS
SOURCE_DIR ${IDF_PATH}/components/bootloader/subproject
BINARY_DIR ${CMAKE_BINARY_DIR}/bootloader_subproject
CMAKE_ARGS -DSDKCONFIG=${SDKCONFIG} -DIDF_PATH=${IDF_PATH}
INSTALL_COMMAND ""
)

View File

@@ -0,0 +1,133 @@
# Search 'component_dirs' for components and return them
# as a list of names in 'component_names' and a list of full paths in
# 'component_paths'
#
# component_paths contains only unique component names. Directories
# earlier in the component_dirs list take precedence.
function(find_all_components component_dirs filter_names component_paths component_names)
# component_dirs entries can be files or lists of files
set(paths "")
set(names "")
# start by expanding the component_dirs list with all subdirectories
foreach(dir ${component_dirs})
# Iterate any subdirectories for values
file(GLOB subdirs LIST_DIRECTORIES true "${dir}/*")
foreach(subdir ${subdirs})
set(component_dirs "${component_dirs};${subdir}")
endforeach()
endforeach()
# Look for a component in each component_dirs entry
foreach(dir ${component_dirs})
file(GLOB component "${dir}/CMakeLists.txt")
if(component)
get_filename_component(component "${component}" DIRECTORY)
get_filename_component(name "${component}" NAME)
if(NOT filter_names OR (name IN_LIST filter_names))
if(NOT name IN_LIST names)
set(names "${names};${name}")
set(paths "${paths};${component}")
endif()
endif()
else() # no CMakeLists.txt file
# test for legacy component.mk and warn
file(GLOB legacy_component "${dir}/component.mk")
if(legacy_component)
get_filename_component(legacy_component "${legacy_component}" DIRECTORY)
message(WARNING "Component ${legacy_component} contains old-style component.mk but no CMakeLists.txt. Component will be skipped.")
endif()
endif(component)
endforeach(dir ${component_dirs})
set(${component_paths} ${paths} PARENT_SCOPE)
set(${component_names} ${names} PARENT_SCOPE)
endfunction()
# Add a component to the build, using the COMPONENT variables defined
# in the parent
#
function(register_component)
get_filename_component(component_dir ${CMAKE_CURRENT_LIST_FILE} DIRECTORY)
get_filename_component(component ${component_dir} NAME)
if(NOT COMPONENT_SRCDIRS)
set(COMPONENT_SRCDIRS ".")
endif()
spaces2list(COMPONENT_SRCDIRS)
if(NOT COMPONENT_ADD_INCLUDEDIRS)
set(COMPONENT_ADD_INCLUDEDIRS "include")
endif()
spaces2list(COMPONENT_ADD_INCLUDEDIRS)
# if not explicit, build COMPONENT_SRCS by globbing in COMPONENT_SRCDIRS
if(NOT COMPONENT_SRCS)
foreach(dir ${COMPONENT_SRCDIRS})
get_filename_component(dir ${dir} ABSOLUTE BASE_DIR ${component_dir})
file(GLOB matches "${dir}/*.[c|S]" "${dir}/*.cpp")
if(matches)
list(SORT matches)
set(COMPONENT_SRCS "${COMPONENT_SRCS};${matches}")
endif(matches)
endforeach()
endif()
# add public includes from other components when building this component
if(COMPONENT_SRCS)
add_library(${component} STATIC ${COMPONENT_SRCS})
set(include_type PUBLIC)
else()
add_library(${component} INTERFACE) # header-only component
set(include_type INTERFACE)
endif(COMPONENT_SRCS)
foreach(include_dir ${COMPONENT_ADD_INCLUDEDIRS})
get_filename_component(include_dir ${include_dir} ABSOLUTE BASE_DIR ${component_dir})
target_include_directories(${component} ${include_type} ${include_dir})
endforeach()
foreach(include_dir ${COMPONENT_PRIV_INCLUDEDIRS})
if (${include_type} STREQUAL INTERFACE)
message(FATAL_ERROR "Component ${component} can't have no source files and COMPONENT_PRIV_INCLUDEDIRS set.")
endif()
get_filename_component(include_dir ${include_dir} ABSOLUTE BASE_DIR ${component_dir})
target_include_directories(${component} PRIVATE ${include_dir})
endforeach()
endfunction()
function(register_config_only_component)
get_filename_component(component_dir ${CMAKE_CURRENT_LIST_FILE} DIRECTORY)
get_filename_component(component ${component_dir} NAME)
# No-op for now...
endfunction()
function(finish_component_registration)
# each component should see the include directories of each other
#
# (we can't do this until all components are registered, because if(TARGET ...) won't work
foreach(a ${COMPONENTS})
if (TARGET ${a})
get_target_property(a_type ${a} TYPE)
if (${a_type} STREQUAL STATIC_LIBRARY)
foreach(b ${COMPONENTS})
if (TARGET ${b} AND NOT ${a} STREQUAL ${b})
target_include_directories(${a} PRIVATE
$<TARGET_PROPERTY:${b},INTERFACE_INCLUDE_DIRECTORIES>
)
endif()
endforeach(b)
endif(${a_type} STREQUAL STATIC_LIBRARY)
set(COMPONENT_LIBRARIES "${COMPONENT_LIBRARIES};${a}")
endif()
endforeach()
# set COMPONENT_LIBRARIES in top-level scope
set(COMPONENT_LIBRARIES "${COMPONENT_LIBRARIES}" PARENT_SCOPE)
endfunction()

82
tools/cmake/kconfig.cmake Normal file
View File

@@ -0,0 +1,82 @@
include(ExternalProject)
add_compile_options("-I${CMAKE_BINARY_DIR}")
set(MCONF ${IDF_PATH}/tools/kconfig/mconf)
set_default(SDKCONFIG ${PROJECT_PATH}/sdkconfig)
set(SDKCONFIG_HEADER ${CMAKE_BINARY_DIR}/sdkconfig.h)
set(SDKCONFIG_CMAKE ${CMAKE_BINARY_DIR}/sdkconfig.cmake)
set(ROOT_KCONFIG ${IDF_PATH}/Kconfig)
# Use the existing Makefile to build mconf when needed
#
# TODO: replace this with something more Windows-friendly
ExternalProject_Add(mconf
SOURCE_DIR ${IDF_PATH}/tools/kconfig
CONFIGURE_COMMAND ""
BUILD_IN_SOURCE 1
BUILD_COMMAND make mconf
BUILD_BYPRODUCTS ${MCONF}
INSTALL_COMMAND ""
EXCLUDE_FROM_ALL 1
)
# Find all Kconfig files for all components
function(build_component_config)
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/include/config")
set(kconfigs )
set(kconfigs_projbuild )
# Find Kconfig and Kconfig.projbuild for each component as applicable
# if any of these change, cmake should rerun
foreach(dir ${COMPONENT_PATHS})
file(GLOB kconfig "${dir}/Kconfig")
if(kconfig)
set(kconfigs "${kconfigs} ${kconfig}")
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${kconfig})
endif()
file(GLOB kconfig ${dir}/Kconfig.projbuild)
if(kconfig)
set(kconfigs_projbuild "${kconfigs_projbuild} ${kconfig}")
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${kconfig})
endif()
endforeach(dir ${COMPONENT_PATHS})
# Generate the menuconfig target (uses C-based mconf tool)
add_custom_target(menuconfig
DEPENDS mconf
COMMAND ${CMAKE_COMMAND} -E env
"COMPONENT_KCONFIGS=${kconfigs}"
"COMPONENT_KCONFIGS_PROJBUILD=${kconfigs_projbuild}"
"KCONFIG_CONFIG=${SDKCONFIG}"
${IDF_PATH}/tools/kconfig/mconf ${ROOT_KCONFIG}
VERBATIM
USES_TERMINAL)
# Generate configuration output via confgen.py
# makes sdkconfig.h and skdconfig.cmake
#
# This happens at cmake runtime not during the build
execute_process(COMMAND python ${IDF_PATH}/tools/kconfig_new/confgen.py
--kconfig ${ROOT_KCONFIG}
--config ${SDKCONFIG}
--env "COMPONENT_KCONFIGS=${kconfigs}"
--env "COMPONENT_KCONFIGS_PROJBUILD=${kconfigs_projbuild}"
--output header ${SDKCONFIG_HEADER}
--output cmake ${SDKCONFIG_CMAKE})
# When sdkconfig file changes in the future, trigger a cmake run
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${SDKCONFIG})
# Ditto if either of the generated files are missing/modified (this is a bit irritating as it means
# you can't edit these manually without them being regenerated, but I don't know of a better way...)
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${SDKCONFIG_HEADER})
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${SDKCONFIG_CMAKE})
# Or if the config generation tool changes
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${IDF_PATH}/tools/kconfig_new/confgen.py)
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${IDF_PATH}/tools/kconfig_new/kconfiglib.py)
endfunction()

View File

@@ -0,0 +1,60 @@
# set_default
#
# Define a variable to a default value if otherwise unset.
#
# Priority for new value is:
# - Existing cmake value (ie set with cmake -D, or already set in CMakeLists)
# - Value of any non-empty environment variable of the same name
# - Default value as provided to function
#
function(set_default variable default_value)
if(NOT ${variable})
if($ENV{${variable}})
set(${variable} $ENV{${variable}} PARENT_SCOPE)
else()
set(${variable} ${default_value} PARENT_SCOPE)
endif()
endif()
endfunction()
# spaces2list
#
# Take a variable whose value was space-delimited values, convert to a cmake
# list (semicolon-delimited)
#
# Note: if using this for directories, keeps the issue in place that
# directories can't contain spaces...
function(spaces2list variable_name)
string(REPLACE " " ";" tmp "${${variable_name}}")
set("${variable_name}" "${tmp}" PARENT_SCOPE)
endfunction()
# move_if_different
#
# If 'source' has different md5sum to 'destination' (or destination
# does not exist, move it across.
#
# If 'source' has the same md5sum as 'destination', delete 'source'.
#
# Avoids timestamp updates for re-generated files where content hasn't
# changed.
function(move_if_different source destination)
set(do_copy 1)
file(GLOB dest_exists ${destination})
if(dest_exists)
file(MD5 ${source} source_md5)
file(MD5 ${destination} dest_md5)
if(source_md5 STREQUAL dest_md5)
set(do_copy "")
endif()
endif()
if(do_copy)
message("Moving ${source} -> ${destination}")
file(RENAME ${source} ${destination})
else()
message("Not moving ${source} -> ${destination}")
file(REMOVE ${source})
endif()
endfunction()