blob: b0f931f11c9b3f563179b49249a7f9fe6fa984b0 [file] [log] [blame]
################################################################################################
# Exclude and prepend functionalities
function (exclude OUTPUT INPUT)
set(EXCLUDES ${ARGN})
foreach(EXCLUDE ${EXCLUDES})
list(REMOVE_ITEM INPUT "${EXCLUDE}")
endforeach()
set(${OUTPUT} ${INPUT} PARENT_SCOPE)
endfunction(exclude)
function (prepend OUTPUT PREPEND)
set(OUT "")
foreach(ITEM ${ARGN})
list(APPEND OUT "${PREPEND}${ITEM}")
endforeach()
set(${OUTPUT} ${OUT} PARENT_SCOPE)
endfunction(prepend)
################################################################################################
# Clears variables from list
# Usage:
# caffe_clear_vars(<variables_list>)
macro(caffe_clear_vars)
foreach(_var ${ARGN})
unset(${_var})
endforeach()
endmacro()
################################################################################################
# Prints list element per line
# Usage:
# caffe_print_list(<list>)
function(caffe_print_list)
foreach(e ${ARGN})
message(STATUS ${e})
endforeach()
endfunction()
################################################################################################
# Reads set of version defines from the header file
# Usage:
# caffe_parse_header(<file> <define1> <define2> <define3> ..)
macro(caffe_parse_header FILENAME FILE_VAR)
set(vars_regex "")
set(__parnet_scope OFF)
set(__add_cache OFF)
foreach(name ${ARGN})
if("${name}" STREQUAL "PARENT_SCOPE")
set(__parnet_scope ON)
elseif("${name}" STREQUAL "CACHE")
set(__add_cache ON)
elseif(vars_regex)
set(vars_regex "${vars_regex}|${name}")
else()
set(vars_regex "${name}")
endif()
endforeach()
if(EXISTS "${FILENAME}")
file(STRINGS "${FILENAME}" ${FILE_VAR} REGEX "#define[ \t]+(${vars_regex})[ \t]+[0-9]+" )
else()
unset(${FILE_VAR})
endif()
foreach(name ${ARGN})
if(NOT "${name}" STREQUAL "PARENT_SCOPE" AND NOT "${name}" STREQUAL "CACHE")
if(${FILE_VAR})
if(${FILE_VAR} MATCHES ".+[ \t]${name}[ \t]+([0-9]+).*")
string(REGEX REPLACE ".+[ \t]${name}[ \t]+([0-9]+).*" "\\1" ${name} "${${FILE_VAR}}")
else()
set(${name} "")
endif()
if(__add_cache)
set(${name} ${${name}} CACHE INTERNAL "${name} parsed from ${FILENAME}" FORCE)
elseif(__parnet_scope)
set(${name} "${${name}}" PARENT_SCOPE)
endif()
else()
unset(${name} CACHE)
endif()
endif()
endforeach()
endmacro()
################################################################################################
# Reads single version define from the header file and parses it
# Usage:
# caffe_parse_header_single_define(<library_name> <file> <define_name>)
function(caffe_parse_header_single_define LIBNAME HDR_PATH VARNAME)
set(${LIBNAME}_H "")
if(EXISTS "${HDR_PATH}")
file(STRINGS "${HDR_PATH}" ${LIBNAME}_H REGEX "^#define[ \t]+${VARNAME}[ \t]+\"[^\"]*\".*$" LIMIT_COUNT 1)
endif()
if(${LIBNAME}_H)
string(REGEX REPLACE "^.*[ \t]${VARNAME}[ \t]+\"([0-9]+).*$" "\\1" ${LIBNAME}_VERSION_MAJOR "${${LIBNAME}_H}")
string(REGEX REPLACE "^.*[ \t]${VARNAME}[ \t]+\"[0-9]+\\.([0-9]+).*$" "\\1" ${LIBNAME}_VERSION_MINOR "${${LIBNAME}_H}")
string(REGEX REPLACE "^.*[ \t]${VARNAME}[ \t]+\"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" ${LIBNAME}_VERSION_PATCH "${${LIBNAME}_H}")
set(${LIBNAME}_VERSION_MAJOR ${${LIBNAME}_VERSION_MAJOR} ${ARGN} PARENT_SCOPE)
set(${LIBNAME}_VERSION_MINOR ${${LIBNAME}_VERSION_MINOR} ${ARGN} PARENT_SCOPE)
set(${LIBNAME}_VERSION_PATCH ${${LIBNAME}_VERSION_PATCH} ${ARGN} PARENT_SCOPE)
set(${LIBNAME}_VERSION_STRING "${${LIBNAME}_VERSION_MAJOR}.${${LIBNAME}_VERSION_MINOR}.${${LIBNAME}_VERSION_PATCH}" PARENT_SCOPE)
# append a TWEAK version if it exists:
set(${LIBNAME}_VERSION_TWEAK "")
if("${${LIBNAME}_H}" MATCHES "^.*[ \t]${VARNAME}[ \t]+\"[0-9]+\\.[0-9]+\\.[0-9]+\\.([0-9]+).*$")
set(${LIBNAME}_VERSION_TWEAK "${CMAKE_MATCH_1}" ${ARGN} PARENT_SCOPE)
endif()
if(${LIBNAME}_VERSION_TWEAK)
set(${LIBNAME}_VERSION_STRING "${${LIBNAME}_VERSION_STRING}.${${LIBNAME}_VERSION_TWEAK}" ${ARGN} PARENT_SCOPE)
else()
set(${LIBNAME}_VERSION_STRING "${${LIBNAME}_VERSION_STRING}" ${ARGN} PARENT_SCOPE)
endif()
endif()
endfunction()
################################################################################################
# Parses a version string that might have values beyond major, minor, and patch
# and set version variables for the library.
# Usage:
# caffe2_parse_version_str(<library_name> <version_string>)
function(caffe2_parse_version_str LIBNAME VERSIONSTR)
string(REGEX REPLACE "^([0-9]+).*$" "\\1" ${LIBNAME}_VERSION_MAJOR "${VERSIONSTR}")
string(REGEX REPLACE "^[0-9]+\\.([0-9]+).*$" "\\1" ${LIBNAME}_VERSION_MINOR "${VERSIONSTR}")
string(REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" ${LIBNAME}_VERSION_PATCH "${VERSIONSTR}")
set(${LIBNAME}_VERSION_MAJOR ${${LIBNAME}_VERSION_MAJOR} ${ARGN} PARENT_SCOPE)
set(${LIBNAME}_VERSION_MINOR ${${LIBNAME}_VERSION_MINOR} ${ARGN} PARENT_SCOPE)
set(${LIBNAME}_VERSION_PATCH ${${LIBNAME}_VERSION_PATCH} ${ARGN} PARENT_SCOPE)
set(${LIBNAME}_VERSION "${${LIBNAME}_VERSION_MAJOR}.${${LIBNAME}_VERSION_MINOR}.${${LIBNAME}_VERSION_PATCH}" PARENT_SCOPE)
endfunction()
###
# Removes common indentation from a block of text to produce code suitable for
# setting to `python -c`, or using with pycmd. This allows multiline code to be
# nested nicely in the surrounding code structure.
#
# This function respsects PYTHON_EXECUTABLE if it defined, otherwise it uses
# `python` and hopes for the best. An error will be thrown if it is not found.
#
# Args:
# outvar : variable that will hold the stdout of the python command
# text : text to remove indentation from
#
function(dedent outvar text)
# Use PYTHON_EXECUTABLE if it is defined, otherwise default to python
if ("${PYTHON_EXECUTABLE}" STREQUAL "")
set(_python_exe "python")
else()
set(_python_exe "${PYTHON_EXECUTABLE}")
endif()
set(_fixup_cmd "import sys; from textwrap import dedent; print(dedent(sys.stdin.read()))")
file(WRITE "${CMAKE_BINARY_DIR}/indented.txt" "${text}")
execute_process(
COMMAND "${_python_exe}" -c "${_fixup_cmd}"
INPUT_FILE "${CMAKE_BINARY_DIR}/indented.txt"
RESULT_VARIABLE _dedent_exitcode
OUTPUT_VARIABLE _dedent_text)
if(NOT ${_dedent_exitcode} EQUAL 0)
message(ERROR " Failed to remove indentation from: \n\"\"\"\n${text}\n\"\"\"
Python dedent failed with error code: ${_dedent_exitcode}")
message(FATAL_ERROR " Python dedent failed with error code: ${_dedent_exitcode}")
endif()
# Remove supurflous newlines (artifacts of print)
string(STRIP "${_dedent_text}" _dedent_text)
set(${outvar} "${_dedent_text}" PARENT_SCOPE)
endfunction()
function(pycmd_no_exit outvar exitcode cmd)
# Use PYTHON_EXECUTABLE if it is defined, otherwise default to python
if ("${PYTHON_EXECUTABLE}" STREQUAL "")
set(_python_exe "python")
else()
set(_python_exe "${PYTHON_EXECUTABLE}")
endif()
# run the actual command
execute_process(
COMMAND "${_python_exe}" -c "${cmd}"
RESULT_VARIABLE _exitcode
OUTPUT_VARIABLE _output)
# Remove supurflous newlines (artifacts of print)
string(STRIP "${_output}" _output)
set(${outvar} "${_output}" PARENT_SCOPE)
set(${exitcode} "${_exitcode}" PARENT_SCOPE)
endfunction()
###
# Helper function to run `python -c "<cmd>"` and capture the results of stdout
#
# Runs a python command and populates an outvar with the result of stdout.
# Common indentation in the text of `cmd` is removed before the command is
# executed, so the caller does not need to worry about indentation issues.
#
# This function respsects PYTHON_EXECUTABLE if it defined, otherwise it uses
# `python` and hopes for the best. An error will be thrown if it is not found.
#
# Args:
# outvar : variable that will hold the stdout of the python command
# cmd : text representing a (possibly multiline) block of python code
#
function(pycmd outvar cmd)
dedent(_dedent_cmd "${cmd}")
pycmd_no_exit(_output _exitcode "${_dedent_cmd}")
if(NOT ${_exitcode} EQUAL 0)
message(ERROR " Failed when running python code: \"\"\"\n${_dedent_cmd}\n\"\"\"")
message(FATAL_ERROR " Python command failed with error code: ${_exitcode}")
endif()
# Remove supurflous newlines (artifacts of print)
string(STRIP "${_output}" _output)
set(${outvar} "${_output}" PARENT_SCOPE)
endfunction()
###
# Helper function to print out everything that cmake knows about a target
#
# Copied from https://stackoverflow.com/questions/32183975/how-to-print-all-the-properties-of-a-target-in-cmake
# This isn't called anywhere, but it's very useful when debugging cmake
# NOTE: This doesn't work for INTERFACE_LIBRARY or INTERFACE_LINK_LIBRARY targets
function(print_target_properties tgt)
if(NOT TARGET ${tgt})
message("There is no target named '${tgt}'")
return()
endif()
# Get a list of all cmake properties TODO cache this lazily somehow
execute_process(COMMAND cmake --help-property-list OUTPUT_VARIABLE CMAKE_PROPERTY_LIST)
STRING(REGEX REPLACE ";" "\\\\;" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}")
STRING(REGEX REPLACE "\n" ";" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}")
foreach (prop ${CMAKE_PROPERTY_LIST})
string(REPLACE "<CONFIG>" "${CMAKE_BUILD_TYPE}" prop ${prop})
get_property(propval TARGET ${tgt} PROPERTY ${prop} SET)
if (propval)
get_target_property(propval ${tgt} ${prop})
message ("${tgt} ${prop} = ${propval}")
endif()
endforeach(prop)
endfunction(print_target_properties)