255 lines
8.7 KiB
CMake
255 lines
8.7 KiB
CMake
# 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(DEFINED ENV{${variable}} AND NOT "$ENV{${variable}}" STREQUAL "")
|
|
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...
|
|
#
|
|
# TODO: look at cmake separate_arguments, which is quote-aware
|
|
function(spaces2list variable_name)
|
|
string(REPLACE " " ";" tmp "${${variable_name}}")
|
|
set("${variable_name}" "${tmp}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# lines2list
|
|
#
|
|
# Take a variable with multiple lines of output in it, convert it
|
|
# to a cmake list (semicolon-delimited), one line per item
|
|
#
|
|
function(lines2list variable_name)
|
|
string(REGEX REPLACE "\r?\n" ";" tmp "${${variable_name}}")
|
|
string(REGEX REPLACE ";;" ";" tmp "${tmp}")
|
|
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()
|
|
|
|
# target_add_binary_data adds binary data into the built target,
|
|
# by converting it to a generated source file which is then compiled
|
|
# to a binary object as part of the build
|
|
function(target_add_binary_data target embed_file embed_type)
|
|
idf_build_get_property(build_dir BUILD_DIR)
|
|
idf_build_get_property(idf_path IDF_PATH)
|
|
|
|
get_filename_component(embed_file "${embed_file}" ABSOLUTE)
|
|
|
|
get_filename_component(name "${embed_file}" NAME)
|
|
set(embed_srcfile "${build_dir}/${name}.S")
|
|
|
|
add_custom_command(OUTPUT "${embed_srcfile}"
|
|
COMMAND "${CMAKE_COMMAND}"
|
|
-D "DATA_FILE=${embed_file}"
|
|
-D "SOURCE_FILE=${embed_srcfile}"
|
|
-D "FILE_TYPE=${embed_type}"
|
|
-P "${idf_path}/tools/cmake/scripts/data_file_embed_asm.cmake"
|
|
MAIN_DEPENDENCY "${embed_file}"
|
|
DEPENDS "${idf_path}/tools/cmake/scripts/data_file_embed_asm.cmake"
|
|
WORKING_DIRECTORY "${build_dir}"
|
|
VERBATIM)
|
|
|
|
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${embed_srcfile}")
|
|
|
|
target_sources("${target}" PRIVATE "${embed_srcfile}")
|
|
endfunction()
|
|
|
|
macro(include_if_exists path)
|
|
if(EXISTS "${path}")
|
|
include("${path}")
|
|
endif()
|
|
endmacro()
|
|
|
|
# Append a single line to the file specified
|
|
# The line ending is determined by the host OS
|
|
function(file_append_line file line)
|
|
if(DEFINED ENV{MSYSTEM} OR CMAKE_HOST_WIN32)
|
|
set(line_ending "\r\n")
|
|
else() # unix
|
|
set(line_ending "\n")
|
|
endif()
|
|
file(READ ${file} existing)
|
|
string(FIND ${existing} ${line_ending} last_newline REVERSE)
|
|
string(LENGTH ${existing} length)
|
|
math(EXPR length "${length}-1")
|
|
if(NOT length EQUAL last_newline) # file doesn't end with a newline
|
|
file(APPEND "${file}" "${line_ending}")
|
|
endif()
|
|
file(APPEND "${file}" "${line}${line_ending}")
|
|
endfunction()
|
|
|
|
# Add one or more linker scripts to the target, including a link-time dependency
|
|
#
|
|
# Automatically adds a -L search path for the containing directory (if found),
|
|
# and then adds -T with the filename only. This allows INCLUDE directives to be
|
|
# used to include other linker scripts in the same directory.
|
|
function(target_linker_script target scriptfiles)
|
|
cmake_parse_arguments(_ "PROCESS" "" "" ${ARGN})
|
|
foreach(scriptfile ${scriptfiles})
|
|
get_filename_component(abs_script "${scriptfile}" ABSOLUTE)
|
|
message(STATUS "Adding linker script ${abs_script}")
|
|
|
|
if(__PROCESS)
|
|
__ldgen_process_template(output ${abs_script})
|
|
set(abs_script ${output})
|
|
endif()
|
|
|
|
get_filename_component(search_dir "${abs_script}" DIRECTORY)
|
|
get_filename_component(scriptname "${abs_script}" NAME)
|
|
|
|
get_target_property(type ${target} TYPE)
|
|
if(type STREQUAL "INTERFACE_LIBRARY")
|
|
set(is_interface "INTERFACE")
|
|
endif()
|
|
|
|
if(is_interface)
|
|
get_target_property(link_libraries "${target}" INTERFACE_LINK_LIBRARIES)
|
|
else()
|
|
get_target_property(link_libraries "${target}" LINK_LIBRARIES)
|
|
endif()
|
|
|
|
list(FIND "${link_libraries}" "-L ${search_dir}" found_search_dir)
|
|
if(found_search_dir EQUAL "-1") # not already added as a search path
|
|
target_link_libraries("${target}" "${is_interface}" "-L ${search_dir}")
|
|
endif()
|
|
|
|
target_link_libraries("${target}" "${is_interface}" "-T ${scriptname}")
|
|
|
|
# Note: In ESP-IDF, most targets are libraries and libary LINK_DEPENDS don't propagate to
|
|
# executable(s) the library is linked to. Attach manually to executable once it is known.
|
|
#
|
|
# Property INTERFACE_LINK_DEPENDS is available in CMake 3.13 which should propagate link
|
|
# dependencies.
|
|
if(NOT __PROCESS)
|
|
if(is_interface)
|
|
set_property(TARGET ${target} APPEND PROPERTY INTERFACE_LINK_DEPENDS ${abs_script})
|
|
else()
|
|
set_property(TARGET ${target} APPEND PROPERTY LINK_DEPENDS ${abs_script})
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
endfunction()
|
|
|
|
# Convert a CMake list to a JSON list and store it in a variable
|
|
function(make_json_list list variable)
|
|
string(REPLACE ";" "\", \"" result "[ \"${list}\" ]")
|
|
set("${variable}" "${result}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# add_prefix
|
|
#
|
|
# Adds a prefix to each item in the specified list.
|
|
#
|
|
function(add_prefix var prefix)
|
|
foreach(elm ${ARGN})
|
|
list(APPEND newlist "${prefix}${elm}")
|
|
endforeach()
|
|
set(${var} "${newlist}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# fail_at_build_time
|
|
#
|
|
# Creates a phony target which fails the build and touches CMakeCache.txt to cause a cmake run next time.
|
|
#
|
|
# This is used when a missing file is required at CMake runtime, but we can't fail the build if it is not found,
|
|
# because the "menuconfig" target may be required to fix the problem.
|
|
#
|
|
# We cannot use CMAKE_CONFIGURE_DEPENDS instead because it only works for files which exist at CMake runtime.
|
|
#
|
|
function(fail_at_build_time target_name message_line0)
|
|
idf_build_get_property(idf_path IDF_PATH)
|
|
set(message_lines COMMAND ${CMAKE_COMMAND} -E echo "${message_line0}")
|
|
foreach(message_line ${ARGN})
|
|
set(message_lines ${message_lines} COMMAND ${CMAKE_COMMAND} -E echo "${message_line}")
|
|
endforeach()
|
|
add_custom_target(${target_name} ALL
|
|
${message_lines}
|
|
COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_BINARY_DIR}/CMakeCache.txt"
|
|
COMMAND ${CMAKE_COMMAND} -P ${idf_path}/tools/cmake/scripts/fail.cmake
|
|
VERBATIM)
|
|
endfunction()
|
|
|
|
function(check_exclusive_args args prefix)
|
|
set(_args ${args})
|
|
spaces2list(_args)
|
|
set(only_arg 0)
|
|
foreach(arg ${_args})
|
|
if(${prefix}_${arg} AND only_arg)
|
|
message(FATAL_ERROR "${args} are exclusive arguments")
|
|
endif()
|
|
|
|
if(${prefix}_${arg})
|
|
set(only_arg 1)
|
|
endif()
|
|
endforeach()
|
|
endfunction()
|
|
|
|
|
|
# add_compile_options variant for C++ code only
|
|
#
|
|
# This adds global options, set target properties for
|
|
# component-specific flags
|
|
function(add_cxx_compile_options)
|
|
foreach(option ${ARGV})
|
|
# note: the Visual Studio Generator doesn't support this...
|
|
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:${option}>)
|
|
endforeach()
|
|
endfunction()
|
|
|
|
# add_compile_options variant for C code only
|
|
#
|
|
# This adds global options, set target properties for
|
|
# component-specific flags
|
|
function(add_c_compile_options)
|
|
foreach(option ${ARGV})
|
|
# note: the Visual Studio Generator doesn't support this...
|
|
add_compile_options($<$<COMPILE_LANGUAGE:C>:${option}>)
|
|
endforeach()
|
|
endfunction()
|