diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..7e50013 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,241 @@ +#.rst +# CMake configuration of libLBFGS project +# --------------------------------------- +# +# This CMakeLists.txt defines some libLBFGS specific configuration variables +# using a custom "subproject_define" command defined in the Subproject.cmake module. +# The default values of these variables can be overridden either on the CMake +# command-line using the -D option of the cmake command or in a super-project +# which includes the libLBFGS source tree by setting the LBFGS_ +# CMake variables before adding the libLBFGS source directory via CMake's +# add_subdirectory command. Only when the non-cached variable LBFGS_IS_SUBPROJECT +# has a value equivalent to FALSE, these configuration variables are added to +# the CMake cache so they can be edited in the CMake GUI. By default, +# LBFGS_IS_SUBPROJECT is set to TRUE when the CMAKE_SOURCE_DIR is not identical +# to the directory of this CMakeLists.txt file, i.e., the top-level directory of +# the libLBFGS project source tree. +# +# Example CMakeLists.txt of user project which requires separate libLBFGS +# installation (possibly requires FindLBFGS.cmake module for distribution +# packages of libLBFGS that do not include a LBFGSConfig.cmake file):: +# +# cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) +# +# project(Foo) +# +# find_package(LBFGS REQUIRED) +# +# add_executable(foo src/foo.cc) +# target_link_libraries(foo LBFGS::lib) +# +# Example CMakeLists.txt of super-project which contains libLBFGS source tree:: +# +# cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) +# +# project(Foo) +# +# set(LBFGS_USE_SSE ON) +# set(LBFGS_lib_TARGET_NAME liblbfgs) +# add_subdirectory(lbfgs) +# set_target_properties(liblbfgs PROPERTIES OUTPUT_NAME foolbfgs) +# +# add_executable(foo src/foo.cc) +# target_link_libraries(foo liblbfgs) +# # or use the usual namespaced ALIAS target: +# #target_link_libraries(foo LBFGS::lib) +# +# Variables to configure the source files:: +# +# LBFGS_USE_DOUBLE - Enable double precision floating point arithmetics. (default: ON) +# LBFGS_USE_SSE - Enable SSE/SSE2 optimiations. (default: OFF) +# LBFGS_USE_IEEE754 - Enable optimization routines for IEEE754 floating point values. (default: ON) +# +# Variables to configure the build:: +# +# LBFGS_BUILD_SHARED_LIBS - Enable build of shared libraries. (default: OFF) +# LBFGS_BUILD_EXAMPLES - Enable build of example programs. (default: OFF) +# LBFGS__TARGET_NAME - Custom target name for target , i.e., "lib" or "sample". +# By default, the target name is prefixed by "lbfgs_" if this project +# is configured as a subproject of another project. +# LBFGS_NO_ALIASES - Do not add ALIAS targets LBFGS::lib and LBFGS::sample. (default: OFF) +# +# Variables to configure the installation:: +# +# LBFGS_INSTALL_STATIC_LIBS - Whether to install static library files. +# Shared libraries are always installed. +# When a library is installed, its public header +# files are installed as well. The default is +# to not install static libraries when this +# project is a subproject of another project. +# LBFGS_INSTALL_HEADERS - Can be used to omit installation of public header files. +# LBFGS_INSTALL_CONFIG - Whether to install CMake configuration files. +# By default, the CMake configuration files are +# installed when the library itself is installed. +# LBFGS_INSTALL_RUNTIME_DIR - Installation directory for runtime files. (default: bin) +# LBFGS_INSTALL_INCLUDE_DIR - Installation directory for public header files. (default: include) +# LBFGS_INSTALL_LIBRARY_DIR - Installation directory for library files. (default: lib) +# LBFGS_INSTALL_CONFIG_DIR - Installation directory for CMake configuration. (default: lib/cmake/liblbfgs) + +# ============================================================================== +# libLBFGS: C library of limited-memory BFGS (L-BFGS) +# +# Copyright (c) 1990, Jorge Nocedal +# Copyright (c) 2007-2010, Naoaki Okazaki +# +# libLBFGS is distributed under the term of the MIT license. +# Please refer to COPYING file in the distribution. +# ============================================================================== + +# ---------------------------------------------------------------------------- +# CMake version and policies +cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) + +if (POLICY CMP0042) + cmake_policy(SET CMP0042 NEW) +endif () + +# ---------------------------------------------------------------------------- +# includes +include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/Subproject.cmake") + +# ---------------------------------------------------------------------------- +# package info +subproject(LBFGS VERSION 1.10.0 LANGUAGES C) + +set(PACKAGE_NAME "libLBFGS") +set(PACKAGE_STRING "${PACKAGE_NAME} ${PROJECT_VERSION}") +set(PACKAGE_TARNAME "liblbfgs-${PROJECT_VERSION}") +set(PACKAGE_BUGREPORT "https://github.com/chokkan/liblbfgs/issues") + +# ---------------------------------------------------------------------------- +# options +subproject_define(BOOL BUILD_SHARED_LIBS "Enable build of shared libraries" OFF) +subproject_define(BOOL BUILD_EXAMPLES "Enable build of sample programs" OFF) +subproject_define(BOOL USE_DOUBLE "Use double precision floating point arithmetics" ON) +subproject_define(BOOL USE_SSE "Use SSE/SSE2 instructions for optimization" OFF) +subproject_define(BOOL USE_IEEE754 "Activate optimization routines for IEEE754 floating point values" ON) + +subproject_set_property(USE_IEEE754 ADVANCED TRUE) + +# ---------------------------------------------------------------------------- +# checks for SSE/SSE2 instructions header files +if (USE_SSE) + include(CheckIncludeFile) + if (USE_DOUBLE) + check_include_file(emmintrin.h HAVE_EMMINTRIN_H) + if (NOT HAVE_EMMINTRIN_H) + message(WARNING "SSE2 instructions header file emmintrin.h not found. Disabled SSE optimizations.") + subproject_set_property(USE_SSE VALUE OFF) + endif () + else () + check_include_file(xmmintrin.h HAVE_XMMINTRIN_H) + if (NOT HAVE_XMMINTRIN_H) + message(WARNING "SSE instructions header file xmmintrin.h not found. Disabled SSE optimizations.") + subproject_set_property(USE_SSE VALUE OFF) + endif () + endif () +endif () + +# ---------------------------------------------------------------------------- +# library +set(HEADERS + "include/lbfgs.h" +) + +set(SOURCES + "lib/lbfgs.c" + "lib/arithmetic_ansi.h" + "lib/arithmetic_sse_float.h" + "lib/arithmetic_sse_double.h" +) + +subproject_add_library(_lib "lib" ${HEADERS} ${SOURCES}) + +set_target_properties(${_lib} PROPERTIES + OUTPUT_NAME lbfgs + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_SOVERSION} + DEBUG_POSTFIX d + POSITION_INDEPENDENT_CODE TRUE +) + +target_include_directories(${_lib} + PUBLIC "$" + PRIVATE "${PROJECT_SOURCE_DIR}/lib" +) + +if (NOT USE_DOUBLE) + target_compile_definitions(${_lib} INTERFACE LBFGS_FLOAT=32) +endif () +if (NOT USE_IEEE754) + target_compile_definitions(${_lib} INTERFACE LBFGS_IEEE_FLOAT=0) +endif () +if (USE_SSE) + if (USE_DOUBLE) + target_compile_definitions(${_lib} PRIVATE HAVE_EMMINTRIN_H=${HAVE_EMMINTRIN_H}) + if (MSVC) + target_compile_definitions(${_lib} PRIVATE __SSE2__) + endif () + else () + target_compile_definitions(${_lib} PRIVATE HAVE_XMMINTRIN_H=${HAVE_XMMINTRIN_H}) + if (MSVC) + target_compile_definitions(${_lib} PRIVATE __SSE__) + endif () + endif () +endif () + +if (CMAKE_COMPILER_IS_GNUC) + target_compile_options(${_lib} PRIVATE "$<$:-ffast-math>") + if (USE_SSE) + if (USE_DOUBLE) + target_compile_options(${_lib} PRIVATE "-msse2") + else () + target_compile_options(${_lib} PRIVATE "-msse") + endif () + endif () +endif () + +subproject_install_library(${_lib} + RUNTIME_DESTINATION "bin" + LIBRARY_DESTINATION "lib" + INCLUDE_DESTINATION "include" + PUBLIC_HEADER_FILES "${HEADERS}" +) + +# ---------------------------------------------------------------------------- +# examples +if (BUILD_EXAMPLES) + subproject_add_executable(_sample "sample" sample/sample.c) + target_link_libraries(${_sample} ${_lib}) +endif () + +# ---------------------------------------------------------------------------- +# configuration +include(CMakePackageConfigHelpers) + +subproject_get_install_config_dir(PROJECT_INSTALL_CONFIG_DIR) + +configure_package_config_file( + "${PROJECT_SOURCE_DIR}/cmake/Config.cmake.in" + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + INSTALL_DESTINATION "${PROJECT_INSTALL_CONFIG_DIR}" + NO_SET_AND_CHECK_MACRO + NO_CHECK_REQUIRED_COMPONENTS_MACRO +) + +write_basic_package_version_file( + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion +) + +subproject_install_config_files( + FILES + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" + DESTINATION + "${PROJECT_INSTALL_CONFIG_DIR}" +) + +subproject_export(TARGETS ${_lib}) +subproject_install_exports(DESTINATION "${PROJECT_INSTALL_CONFIG_DIR}") diff --git a/cmake/Config.cmake.in b/cmake/Config.cmake.in new file mode 100644 index 0000000..2c55a88 --- /dev/null +++ b/cmake/Config.cmake.in @@ -0,0 +1,15 @@ +## @PROJECT_NAME@ CMake configuration file + +# library version information +set(@PROJECT_NAME@_VERSION_STRING "@PROJECT_VERSION@") +set(@PROJECT_NAME@_VERSION_MAJOR @PROJECT_VERSION_MAJOR@) +set(@PROJECT_NAME@_VERSION_MINOR @PROJECT_VERSION_MINOR@) +set(@PROJECT_NAME@_VERSION_PATCH @PROJECT_VERSION_PATCH@) + +# import exported targets +if (NOT TARGET @PROJECT_NAME@::lib) + include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") +endif () + +# project libraries +set(@PROJECT_NAME@_LIBRARIES @PROJECT_NAME@::lib) diff --git a/cmake/Subproject.cmake b/cmake/Subproject.cmake new file mode 100644 index 0000000..f982795 --- /dev/null +++ b/cmake/Subproject.cmake @@ -0,0 +1,360 @@ +# ============================================================================== +# Utility CMake functions for standalone or subproject build configuration. +# +# This CMake source file is released into the public domain. +# +# Author: Andreas Schuh (andreas.schuh.84@gmail.com) +# ============================================================================== + +include(CMakeParseArguments) + +# ---------------------------------------------------------------------------- +## Start (sub-)project +# +# This macro is for CMake versions 2.8.12 which did not have the VERSION +# argument yet. It additionally sets the PROJECT_SOVERSION to either the +# project major version number or ${PROJECT_NAME}_SOVERSION if set. +# When ${PROJECT_NAME}_IS_SUBPROJECT is not defined, PROJECT_IS_SUBPROJECT +# is set to TRUE when the source directory of this project is not the +# top-level source directory, and FALSE otherwise. +# +# Besides the PROJECT_NAME variable, this macro also sets PROJECT_NAME_LOWER +# and PROJECT_NAME_UPPER to the respective all lower- or uppercase strings. +macro (subproject name) + cmake_parse_arguments("" "" "VERSION;SOVERSION" "LANGUAGES" ${ARGN}) + if (_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unrecognized arguments: ${_UNPARSED_ARGUMENTS}") + endif () + if (NOT _VERSION) + set(_VERSION 0.0.0) # invalid version number + endif () + unset(PROJECT_VERSION) + unset(PROJECT_VERSION_MAJOR) + unset(PROJECT_VERSION_MINOR) + unset(PROJECT_VERSION_PATCH) + unset(${name}_VERSION) + unset(${name}_VERSION_MAJOR) + unset(${name}_VERSION_MINOR) + unset(${name}_VERSION_PATCH) + project(${name} ${_LANGUAGES}) + set(PROJECT_VERSION "${_VERSION}") + _subproject_split_version_numbers(${PROJECT_VERSION} + PROJECT_VERSION_MAJOR + PROJECT_VERSION_MINOR + PROJECT_VERSION_PATCH + ) + set(${name}_VERSION ${PROJECT_VERSION}) + set(${name}_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) + set(${name}_VERSION_MINOR ${PROJECT_VERSION_MINOR}) + set(${name}_VERSION_PATCH ${PROJECT_VERSION_PATCH}) + if (NOT _SOVERSION) + set(_SOVERSION ${PROJECT_VERSION_MAJOR}) + endif () + _subproject_set_abi_version(PROJECT_SOVERSION ${_SOVERSION}) + set(${name}_SOVERSION ${PROJECT_SOVERSION}) + _subproject_check_if_subproject() + string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER) + string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPER) + unset(_VERSION) + unset(_SOVERSION) + unset(_LANGUAGES) + unset(_UNPARSED_ARGUMENTS) + if (${PROJECT_NAME}_EXPORT_NAME) + set(PROJECT_EXPORT_NAME ${${PROJECT_NAME}_EXPORT_NAME}) + else () + set(PROJECT_EXPORT_NAME ${PROJECT_NAME}) + endif () + set_property(GLOBAL PROPERTY ${PROJECT_NAME}_HAVE_EXPORT FALSE) +endmacro () + +# ---------------------------------------------------------------------------- +## Add configuration variable +# +# The default value of the (cached) configuration value can be overridden +# either on the CMake command-line or the super-project by setting the +# ${PROJECT_NAME}_${varname} variable. When this project is a subproject +# of another project, i.e., PROJECT_IS_SUBPROJECT is TRUE, the variable +# is not added to the CMake cache and set to the value of +# ${PROJECT_NAME}_${varname} regardless if the parent project defines +# a (cached) variable of the same name. Otherwise, when this project is +# a standalone project, the variable is cached. +macro (subproject_define type varname docstring default) + if (ARGC GREATER 5) + message (FATAL_ERROR "Too many macro arguments") + endif () + if (NOT DEFINED ${PROJECT_NAME}_${varname}) + if (PROJECT_IS_SUBPROJECT AND ARGC EQUAL 5) + set(${PROJECT_NAME}_${varname} "${ARGV4}") + else () + set(${PROJECT_NAME}_${varname} "${default}") + endif () + endif () + if (PROJECT_IS_SUBPROJECT) + set(${varname} "${${PROJECT_NAME}_${varname}}") + else () + set(${varname} "${${PROJECT_NAME}_${varname}}" CACHE ${type} "${docstring}") + endif () +endmacro () + +# ---------------------------------------------------------------------------- +## Set property of (cached) configuration variable +# +# This command does nothing when the previously defined variable was not added +# to the CMake cache because this project is build as subproject unless +# the property to be set is the VALUE of the configuration variable. +# +# @see subproject_define +macro (subproject_set_property varname property value) + _subproject_check_if_cached(_is_cached ${varname}) + if (_is_cached) + if (property STREQUAL ADVANCED) + if (${value}) + mark_as_advanced(FORCE ${varname}) + else () + mark_as_advanced(CLEAR ${varname}) + endif () + else () + set_property(CACHE ${varname} PROPERTY "${property}" "${value}") + endif () + elseif (property STREQUAL VALUE) + set(${varname} "${value}") + endif () + unset(_is_cached) +endmacro () + +# ---------------------------------------------------------------------------- +## Get unique target name +macro (subproject_target_name uid target) + if (${PROJECT_NAME}_${target}_TARGET_NAME) + set(${uid} ${${PROJECT_NAME}_${target}_TARGET_NAME}) + elseif (PROJECT_IS_SUBPROJECT) + set(${uid} "${PROJECT_NAME_LOWER}_${target}") + else () + set(${uid} "${target}") + endif () +endmacro () + +# ---------------------------------------------------------------------------- +## Add executable target +function (subproject_add_executable uid target) + subproject_target_name(_uid ${target}) + add_executable(${_uid} ${ARGN}) + if (NOT ${PROJECT_NAME}_NO_ALIASES) + add_executable(${PROJECT_NAME}::${target} ALIAS ${_uid}) + endif () + set(${uid} "${_uid}" PARENT_SCOPE) +endfunction () + +# ---------------------------------------------------------------------------- +## Add library target +function (subproject_add_library uid target) + subproject_target_name(_uid ${target}) + add_library(${_uid} ${ARGN}) + if (NOT ${PROJECT_NAME}_NO_ALIASES) + add_library(${PROJECT_NAME}::${target} ALIAS ${_uid}) + endif () + set(${uid} "${_uid}" PARENT_SCOPE) +endfunction () + +# ---------------------------------------------------------------------------- +## Install files of library target +function (subproject_install_library target) + # parse arguments + if (NOT TARGET ${target}) + message(FATAL_ERROR "Unknown target: ${target}") + endif () + get_target_property(type ${target} TYPE) + if (NOT PROJECT_IS_SUBPROJECT OR NOT "^${type}$" STREQUAL "^STATIC_LIBRARY$" OR ${PROJECT_NAME}_INSTALL_STATIC_LIBS) + cmake_parse_arguments("" + "" + "INCLUDE_DESTINATION;LIBRARY_DESTINATION;RUNTIME_DESTINATION" + "PUBLIC_HEADER_FILES" + ${ARGN} + ) + if (_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Too many or unrecognized arguments: ${_UNPARSED_ARGUMENTS}") + endif () + # override (default) arguments + if (${PROJECT_NAME}_INSTALL_RUNTIME_DIR) + set(_RUNTIME_DESTINATION "${${PROJECT_NAME}_INSTALL_RUNTIME_DIR}") + elseif (NOT _RUNTIME_DESTINATION) + set(_RUNTIME_DESTINATION bin) + endif () + if (${PROJECT_NAME}_INSTALL_INCLUDE_DIR) + set(_INCLUDE_DESTINATION "${${PROJECT_NAME}_INSTALL_INCLUDE_DIR}") + elseif (NOT _INCLUDE_DESTINATION) + set(_INCLUDE_DESTINATION include) + endif () + if (${PROJECT_NAME}_INSTALL_LIBRARY_DIR) + set(_LIBRARY_DESTINATION "${${PROJECT_NAME}_INSTALL_LIBRARY_DIR}") + elseif (NOT _LIBRARY_DESTINATION) + set(_LIBRARY_DESTINATION lib) + endif () + # skip installation of static subproject library + if (_PUBLIC_HEADER_FILES AND (NOT DEFINED ${PROJECT_NAME}_INSTALL_HEADERS OR ${PROJECT_NAME}_INSTALL_HEADERS)) + install(FILES ${_PUBLIC_HEADER_FILES} DESTINATION ${_INCLUDE_DESTINATION} COMPONENT Development) + target_include_directories(${target} INTERFACE "$") + endif () + install(TARGETS ${target} EXPORT ${PROJECT_EXPORT_NAME} + RUNTIME DESTINATION ${_RUNTIME_DESTINATION} COMPONENT RuntimeLibraries + LIBRARY DESTINATION ${_LIBRARY_DESTINATION} COMPONENT RuntimeLibraries + ARCHIVE DESTINATION ${_LIBRARY_DESTINATION} COMPONENT Development + ) + set_property(GLOBAL PROPERTY ${PROJECT_NAME}_HAVE_EXPORT TRUE) + endif () +endfunction () + +# ---------------------------------------------------------------------------- +## Whether to install package configuration files of (sub-)project +macro (subproject_get_install_config_option var) + if (PROJECT_IS_SUBPROJECT AND ${PROJECT_NAME}_INSTALL_CONFIG) + set (${var} 1) + elseif (NOT PROJECT_IS_SUBPROJECT AND (NOT DEFINED ${PROJECT_NAME}_INSTALL_CONFIG OR ${PROJECT_NAME}_INSTALL_CONFIG)) + set (${var} 1) + else () + set (${var} 0) + endif () +endmacro () + +# ---------------------------------------------------------------------------- +## Get relative path of package configuration installation directory +macro (subproject_get_install_config_dir config_dir) + if (${PROJECT_NAME}_INSTALL_CONFIG_DIR) + set(${config_dir} "${${PROJECT_NAME}_INSTALL_CONFIG_DIR}") + elseif (WIN32 AND NOT MINGW AND NOT CYGWIN) + set(${config_dir} "cmake") + else () + set(${config_dir} "lib/cmake/${PROJECT_NAME_LOWER}") + endif () +endmacro () + +# ---------------------------------------------------------------------------- +## Install package configuration files +function (subproject_install_config_files) + subproject_get_install_config_option (_install_config) + if (_install_config) + # parse arguments + cmake_parse_arguments("" "" "DESTINATION" "FILES" ${ARGN}) + if (_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unrecognized arguments: ${_UNPARSED_ARGUMENTS}") + endif () + if (${PROJECT_NAME}_INSTALL_CONFIG_DIR OR NOT _DESTINATION) + subproject_get_install_config_dir(_DESTINATION) + endif () + # install package configuration files if not overriden + install(FILES ${_FILES} DESTINATION ${_DESTINATION} COMPONENT Development) + endif () +endfunction () + +# ---------------------------------------------------------------------------- +## Generate build tree targets configuration file +function (subproject_export) + cmake_parse_arguments("" "" "" "TARGETS" ${ARGN}) + export(TARGETS ${_TARGETS} ${_UNPARSED_ARGUMENTS} + FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake" + NAMESPACE "${PROJECT_NAME}::" + ) +endfunction () + +# ---------------------------------------------------------------------------- +## Install exported targets configuration files +function (subproject_install_exports) + subproject_get_install_config_option (_install_config) + if (_install_config) + # parse arguments + cmake_parse_arguments("" "" "DESTINATION" "" ${ARGN}) + if (_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unrecognized arguments: ${_UNPARSED_ARGUMENTS}") + endif () + if (${PROJECT_NAME}_INSTALL_CONFIG_DIR OR NOT _DESTINATION) + subproject_get_install_config_dir(_DESTINATION) + endif () + # install export sets + get_property(have_export GLOBAL PROPERTY ${PROJECT_NAME}_HAVE_EXPORT) + if (have_export) + install(EXPORT ${PROJECT_EXPORT_NAME} + FILE "${PROJECT_NAME}Targets.cmake" + NAMESPACE "${PROJECT_NAME}::" + DESTINATION "${_DESTINATION}" + COMPONENT Development + ) + endif () + endif () +endfunction () + +# ============================================================================== +# Private auxiliary functions +# ============================================================================== + +# ---------------------------------------------------------------------------- +# Extract version numbers from version string +function (_subproject_split_version_numbers version major minor patch) + if (version MATCHES "([0-9]+)(\\.[0-9]+)?(\\.[0-9]+)?(rc[1-9][0-9]*|[a-z]+)?") + if (CMAKE_MATCH_1) + set(_major ${CMAKE_MATCH_1}) + else () + set(_major 0) + endif () + if (CMAKE_MATCH_2) + set(_minor ${CMAKE_MATCH_2}) + string (REGEX REPLACE "^\\." "" _minor "${_minor}") + else () + set(_minor 0) + endif () + if (CMAKE_MATCH_3) + set(_patch ${CMAKE_MATCH_3}) + string(REGEX REPLACE "^\\." "" _patch "${_patch}") + else () + set(_patch 0) + endif () + else () + set(_major 0) + set(_minor 0) + set(_patch 0) + endif () + set("${major}" "${_major}" PARENT_SCOPE) + set("${minor}" "${_minor}" PARENT_SCOPE) + set("${patch}" "${_patch}" PARENT_SCOPE) +endfunction () + +# ---------------------------------------------------------------------------- +# Set ABI version number +# +# When the variable ${PROJECT_NAME}_SOVERSION is set, it overrides the ABI +# version number argument. +macro (_subproject_set_abi_version varname number) + if (${PROJECT_NAME}_SOVERSION) + set(${varname} "${${PROJECT_NAME}_SOVERSION}") + else () + set(${varname} "${number}") + endif () +endmacro () + +# ---------------------------------------------------------------------------- +# Determine if project is build as subproject +# +# When included as subproject (e.g., as Git submodule/subtree) in the source +# tree of a project that uses it, no variables should be added to the CMake cache; +# users may set the (non-cached) variable ${PROJECT_NAME}_IS_SUBPROJECT before +# the add_subdirectory command that adds this subdirectory to the build. +# +# @returns Sets PROJECT_IS_SUBPROJECT to either TRUE or FALSE. +macro (_subproject_check_if_subproject) + if (DEFINED ${PROJECT_NAME}_IS_SUBPROJECT) + set(PROJECT_IS_SUBPROJECT ${PROJECT_NAME}_IS_SUBPROJECT) + elseif ("^${CMAKE_SOURCE_DIR}$" STREQUAL "^${PROJECT_SOURCE_DIR}$") + set(PROJECT_IS_SUBPROJECT FALSE) + else () + set(PROJECT_IS_SUBPROJECT TRUE) + endif () +endmacro () + +# ---------------------------------------------------------------------------- +# Determine if cache entry exists +macro (_subproject_check_if_cached retvar varname) + if (DEFINED ${varname}) + get_property(${retvar} CACHE ${varname} PROPERTY TYPE SET) + else () + set(${retvar} FALSE) + endif () +endmacro ()