mirror of
https://github.com/SOCI/soci.git
synced 2026-05-04 10:19:53 -05:00
a84dade103
The new function does not pass value through colormsg which eats semi-colon and other CMake control characters. [ci skip]
427 lines
14 KiB
CMake
427 lines
14 KiB
CMake
################################################################################
|
|
# SociUtilities.cmake - part of CMake configuration of SOCI library
|
|
#
|
|
# Based on BoostUtilities.cmake from CMake configuration for Boost
|
|
################################################################################
|
|
# Copyright (C) 2007 Douglas Gregor <doug.gregor@gmail.com>
|
|
# Copyright (C) 2007 Troy Straszheim
|
|
# Copyright (C) 2010-2013 Mateusz Loskot <mateusz@loskot.net>
|
|
#
|
|
# 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
|
|
################################################################################
|
|
# Macros in this module:
|
|
#
|
|
# list_contains: Determine whether a string value is in a list.
|
|
#
|
|
# car: Return the first element in a list
|
|
#
|
|
# cdr: Return all but the first element in a list
|
|
#
|
|
# parse_arguments: Parse keyword arguments for use in other macros.
|
|
#
|
|
# soci_check_package_found: Test varname-FOUND for case-insensitive varname
|
|
#
|
|
################################################################################
|
|
|
|
# This utility macro determines whether a particular string value
|
|
# occurs within a list of strings:
|
|
#
|
|
# list_contains(result string_to_find arg1 arg2 arg3 ... argn)
|
|
#
|
|
# This macro sets the variable named by result equal to TRUE if
|
|
# string_to_find is found anywhere in the following arguments.
|
|
macro(list_contains var value)
|
|
set(${var})
|
|
foreach (value2 ${ARGN})
|
|
if (${value} STREQUAL ${value2})
|
|
set(${var} TRUE)
|
|
endif (${value} STREQUAL ${value2})
|
|
endforeach (value2)
|
|
endmacro(list_contains)
|
|
|
|
# This utility macro extracts the first argument from the list of
|
|
# arguments given, and places it into the variable named var.
|
|
#
|
|
# car(var arg1 arg2 ...)
|
|
macro(car var)
|
|
set(${var} ${ARGV1})
|
|
endmacro(car)
|
|
|
|
# This utility macro extracts all of the arguments given except the
|
|
# first, and places them into the variable named var.
|
|
#
|
|
# car(var arg1 arg2 ...)
|
|
macro(cdr var junk)
|
|
set(${var} ${ARGN})
|
|
endmacro(cdr)
|
|
|
|
# The parse_arguments macro will take the arguments of another macro and
|
|
# define several variables. The first argument to parse_arguments is a
|
|
# prefix to put on all variables it creates. The second argument is a
|
|
# list of names, and the third argument is a list of options. Both of
|
|
# these lists should be quoted. The rest of parse_arguments are
|
|
# arguments from another macro to be parsed.
|
|
#
|
|
# parse_arguments(prefix arg_names options arg1 arg2...)
|
|
#
|
|
# For each item in options, parse_arguments will create a variable with
|
|
# that name, prefixed with prefix_. So, for example, if prefix is
|
|
# MY_MACRO and options is OPTION1;OPTION2, then parse_arguments will
|
|
# create the variables MY_MACRO_OPTION1 and MY_MACRO_OPTION2. These
|
|
# variables will be set to true if the option exists in the command line
|
|
# or false otherwise.
|
|
#
|
|
# For each item in arg_names, parse_arguments will create a variable
|
|
# with that name, prefixed with prefix_. Each variable will be filled
|
|
# with the arguments that occur after the given arg_name is encountered
|
|
# up to the next arg_name or the end of the arguments. All options are
|
|
# removed from these lists. parse_arguments also creates a
|
|
# prefix_DEFAULT_ARGS variable containing the list of all arguments up
|
|
# to the first arg_name encountered.
|
|
macro(parse_arguments prefix arg_names option_names)
|
|
set(DEFAULT_ARGS)
|
|
foreach(arg_name ${arg_names})
|
|
set(${prefix}_${arg_name})
|
|
endforeach(arg_name)
|
|
foreach(option ${option_names})
|
|
set(${prefix}_${option} FALSE)
|
|
endforeach(option)
|
|
|
|
set(current_arg_name DEFAULT_ARGS)
|
|
set(current_arg_list)
|
|
foreach(arg ${ARGN})
|
|
list_contains(is_arg_name ${arg} ${arg_names})
|
|
if (is_arg_name)
|
|
set(${prefix}_${current_arg_name} ${current_arg_list})
|
|
set(current_arg_name ${arg})
|
|
set(current_arg_list)
|
|
else (is_arg_name)
|
|
list_contains(is_option ${arg} ${option_names})
|
|
if (is_option)
|
|
set(${prefix}_${arg} TRUE)
|
|
else (is_option)
|
|
set(current_arg_list ${current_arg_list} ${arg})
|
|
endif (is_option)
|
|
endif (is_arg_name)
|
|
endforeach(arg)
|
|
set(${prefix}_${current_arg_name} ${current_arg_list})
|
|
endmacro(parse_arguments)
|
|
|
|
# Perform a reverse topological sort on the given LIST.
|
|
#
|
|
# topological_sort(my_list "MY_" "_EDGES")
|
|
#
|
|
# LIST is the name of a variable containing a list of elements to be
|
|
# sorted in reverse topological order. Each element in the list has a
|
|
# set of outgoing edges (for example, those other list elements that
|
|
# it depends on). In the resulting reverse topological ordering
|
|
# (written back into the variable named LIST), an element will come
|
|
# later in the list than any of the elements that can be reached by
|
|
# following its outgoing edges and the outgoing edges of any vertices
|
|
# they target, recursively. Thus, if the edges represent dependencies
|
|
# on build targets, for example, the reverse topological ordering is
|
|
# the order in which one would build those targets.
|
|
#
|
|
# For each element E in this list, the edges for E are contained in
|
|
# the variable named ${PREFIX}${E}${SUFFIX}, where E is the
|
|
# upper-cased version of the element in the list. If no such variable
|
|
# exists, then it is assumed that there are no edges. For example, if
|
|
# my_list contains a, b, and c, one could provide a dependency graph
|
|
# using the following variables:
|
|
#
|
|
# MY_A_EDGES b
|
|
# MY_B_EDGES
|
|
# MY_C_EDGES a b
|
|
#
|
|
# With the involcation of topological_sort shown above and these
|
|
# variables, the resulting reverse topological ordering will be b, a,
|
|
# c.
|
|
function(topological_sort LIST PREFIX SUFFIX)
|
|
# Clear the stack and output variable
|
|
set(VERTICES "${${LIST}}")
|
|
set(STACK)
|
|
set(${LIST})
|
|
|
|
# Loop over all of the vertices, starting the topological sort from
|
|
# each one.
|
|
foreach(VERTEX ${VERTICES})
|
|
string(TOUPPER ${VERTEX} UPPER_VERTEX)
|
|
|
|
# If we haven't already processed this vertex, start a depth-first
|
|
# search from where.
|
|
if (NOT FOUND_${UPPER_VERTEX})
|
|
# Push this vertex onto the stack with all of its outgoing edges
|
|
string(REPLACE ";" " " NEW_ELEMENT
|
|
"${VERTEX};${${PREFIX}${UPPER_VERTEX}${SUFFIX}}")
|
|
list(APPEND STACK ${NEW_ELEMENT})
|
|
|
|
# We've now seen this vertex
|
|
set(FOUND_${UPPER_VERTEX} TRUE)
|
|
|
|
# While the depth-first search stack is not empty
|
|
list(LENGTH STACK STACK_LENGTH)
|
|
while(STACK_LENGTH GREATER 0)
|
|
# Remove the vertex and its remaining out-edges from the top
|
|
# of the stack
|
|
list(GET STACK -1 OUT_EDGES)
|
|
list(REMOVE_AT STACK -1)
|
|
|
|
# Get the source vertex and the list of out-edges
|
|
separate_arguments(OUT_EDGES)
|
|
list(GET OUT_EDGES 0 SOURCE)
|
|
list(REMOVE_AT OUT_EDGES 0)
|
|
|
|
# While there are still out-edges remaining
|
|
list(LENGTH OUT_EDGES OUT_DEGREE)
|
|
while (OUT_DEGREE GREATER 0)
|
|
# Pull off the first outgoing edge
|
|
list(GET OUT_EDGES 0 TARGET)
|
|
list(REMOVE_AT OUT_EDGES 0)
|
|
|
|
string(TOUPPER ${TARGET} UPPER_TARGET)
|
|
if (NOT FOUND_${UPPER_TARGET})
|
|
# We have not seen the target before, so we will traverse
|
|
# its outgoing edges before coming back to our
|
|
# source. This is the key to the depth-first traversal.
|
|
|
|
# We've now seen this vertex
|
|
set(FOUND_${UPPER_TARGET} TRUE)
|
|
|
|
# Push the remaining edges for the current vertex onto the
|
|
# stack
|
|
string(REPLACE ";" " " NEW_ELEMENT
|
|
"${SOURCE};${OUT_EDGES}")
|
|
list(APPEND STACK ${NEW_ELEMENT})
|
|
|
|
# Setup the new source and outgoing edges
|
|
set(SOURCE ${TARGET})
|
|
string(TOUPPER ${SOURCE} UPPER_SOURCE)
|
|
set(OUT_EDGES
|
|
${${PREFIX}${UPPER_SOURCE}${SUFFIX}})
|
|
endif(NOT FOUND_${UPPER_TARGET})
|
|
|
|
list(LENGTH OUT_EDGES OUT_DEGREE)
|
|
endwhile (OUT_DEGREE GREATER 0)
|
|
|
|
# We have finished all of the outgoing edges for
|
|
# SOURCE; add it to the resulting list.
|
|
list(APPEND ${LIST} ${SOURCE})
|
|
|
|
# Check the length of the stack
|
|
list(LENGTH STACK STACK_LENGTH)
|
|
endwhile(STACK_LENGTH GREATER 0)
|
|
endif (NOT FOUND_${UPPER_VERTEX})
|
|
endforeach(VERTEX)
|
|
|
|
set(${LIST} ${${LIST}} PARENT_SCOPE)
|
|
endfunction(topological_sort)
|
|
|
|
# Small little hack that tweaks a component name (as used for CPack)
|
|
# to make sure to avoid certain names that cause problems. Sets the
|
|
# variable named varname to the "sanitized" name.
|
|
#
|
|
# FIXME: This is a complete hack. We probably need to fix the CPack
|
|
# generators (NSIS in particular) to get rid of the need for this.
|
|
macro(fix_cpack_component_name varname name)
|
|
if (${name} STREQUAL "foreach")
|
|
set(${varname} "boost_foreach")
|
|
else()
|
|
set(${varname} ${name})
|
|
endif()
|
|
endmacro()
|
|
|
|
|
|
#
|
|
# A big shout out to the cmake gurus @ compiz
|
|
#
|
|
function (colormsg)
|
|
string (ASCII 27 _escape)
|
|
set(WHITE "29")
|
|
set(GRAY "30")
|
|
set(RED "31")
|
|
set(GREEN "32")
|
|
set(YELLOW "33")
|
|
set(BLUE "34")
|
|
set(MAG "35")
|
|
set(CYAN "36")
|
|
|
|
foreach (color WHITE GRAY RED GREEN YELLOW BLUE MAG CYAN)
|
|
set(HI${color} "1\;${${color}}")
|
|
set(LO${color} "2\;${${color}}")
|
|
set(_${color}_ "4\;${${color}}")
|
|
set(_HI${color}_ "1\;4\;${${color}}")
|
|
set(_LO${color}_ "2\;4\;${${color}}")
|
|
endforeach()
|
|
|
|
set(str "")
|
|
set(coloron FALSE)
|
|
foreach(arg ${ARGV})
|
|
if (NOT ${${arg}} STREQUAL "")
|
|
if (CMAKE_COLOR_MAKEFILE)
|
|
set(str "${str}${_escape}[${${arg}}m")
|
|
set(coloron TRUE)
|
|
endif()
|
|
else()
|
|
set(str "${str}${arg}")
|
|
if (coloron)
|
|
set(str "${str}${_escape}[0m")
|
|
set(coloron FALSE)
|
|
endif()
|
|
set(str "${str} ")
|
|
endif()
|
|
endforeach()
|
|
message(STATUS ${str})
|
|
endfunction()
|
|
|
|
# colormsg("Colors:"
|
|
# WHITE "white" GRAY "gray" GREEN "green"
|
|
# RED "red" YELLOW "yellow" BLUE "blue" MAG "mag" CYAN "cyan"
|
|
# _WHITE_ "white" _GRAY_ "gray" _GREEN_ "green"
|
|
# _RED_ "red" _YELLOW_ "yellow" _BLUE_ "blue" _MAG_ "mag" _CYAN_ "cyan"
|
|
# _HIWHITE_ "white" _HIGRAY_ "gray" _HIGREEN_ "green"
|
|
# _HIRED_ "red" _HIYELLOW_ "yellow" _HIBLUE_ "blue" _HIMAG_ "mag" _HICYAN_ "cyan"
|
|
# HIWHITE "white" HIGRAY "gray" HIGREEN "green"
|
|
# HIRED "red" HIYELLOW "yellow" HIBLUE "blue" HIMAG "mag" HICYAN "cyan"
|
|
# "right?")
|
|
|
|
#
|
|
# pretty-prints the value of a variable so that the
|
|
# equals signs align
|
|
#
|
|
function(boost_report_value NAME)
|
|
string(LENGTH "${NAME}" varlen)
|
|
# LOG
|
|
#message(STATUS "boost_report_value: NAME=${NAME} (${varlen})")
|
|
#message(STATUS "boost_report_value: \${NAME}=${${NAME}}")
|
|
math(EXPR padding_len 40-${varlen})
|
|
string(SUBSTRING " "
|
|
0 ${padding_len} varpadding)
|
|
colormsg("${NAME}${varpadding} = ${${NAME}}")
|
|
endfunction()
|
|
|
|
function(boost_message_value NAME)
|
|
string(LENGTH "${NAME}" varlen)
|
|
math(EXPR padding_len 40-${varlen})
|
|
string(SUBSTRING " "
|
|
0 ${padding_len} varpadding)
|
|
message(STATUS "${NAME}${varpadding} = ${${NAME}}")
|
|
endfunction()
|
|
|
|
function(trace NAME)
|
|
if(BOOST_CMAKE_TRACE)
|
|
string(LENGTH "${NAME}" varlen)
|
|
math(EXPR padding_len 40-${varlen})
|
|
string(SUBSTRING "........................................"
|
|
0 ${padding_len} varpadding)
|
|
message("${NAME} ${varpadding} ${${NAME}}")
|
|
endif()
|
|
endfunction()
|
|
|
|
#
|
|
# pretty-prints the value of a variable so that the
|
|
# equals signs align
|
|
#
|
|
function(boost_report_pretty PRETTYNAME VARNAME)
|
|
string(LENGTH "${PRETTYNAME}" varlen)
|
|
math(EXPR padding_len 30-${varlen})
|
|
string(SUBSTRING " "
|
|
0 ${padding_len} varpadding)
|
|
message(STATUS "${PRETTYNAME}${varpadding} = ${${VARNAME}}")
|
|
endfunction()
|
|
|
|
#
|
|
# assert that ARG is actually a library target
|
|
#
|
|
macro(dependency_check ARG)
|
|
trace(ARG)
|
|
if (NOT "${ARG}" STREQUAL "")
|
|
get_target_property(deptype ${ARG} TYPE)
|
|
if(NOT deptype MATCHES ".*_LIBRARY$")
|
|
set(DEPENDENCY_OKAY FALSE)
|
|
list(APPEND DEPENDENCY_FAILURES ${ARG})
|
|
endif()
|
|
endif()
|
|
endmacro()
|
|
|
|
#
|
|
# Tests package-FOUND for varname in three cases as given, lowercase and
|
|
# uppercase.
|
|
#
|
|
macro(soci_check_package_found NAME SUCCESS)
|
|
|
|
set(${SUCCESS} FALSE)
|
|
set(VARNAME ${NAME})
|
|
set(VARNAME_SUCCESS ${${VARNAME}_FOUND})
|
|
|
|
# Test both, given original name and uppercase version too
|
|
if(VARNAME_SUCCESS)
|
|
set(${SUCCESS} TRUE)
|
|
else()
|
|
string(TOUPPER ${NAME} VARNAME)
|
|
set(VARNAME_SUCCESS ${${VARNAME}_FOUND})
|
|
if(VARNAME_SUCCESS)
|
|
set(${SUCCESS} TRUE)
|
|
endif()
|
|
endif()
|
|
|
|
#message(STATUS "soci_check_package_found: ${SUCCESS}=${${SUCCESS}}")
|
|
endmacro()
|
|
|
|
#
|
|
# Pretty-print of given property of current directory.
|
|
#
|
|
function(soci_report_directory_property PROPNAME)
|
|
get_directory_property(${PROPNAME} ${PROPNAME})
|
|
boost_report_value(${PROPNAME})
|
|
endfunction()
|
|
|
|
#
|
|
# Scans the current directory and returns a list of subdirectories.
|
|
# Author: Robert Fleming
|
|
# Source: http://www.cmake.org/pipermail/cmake/2008-February/020114.html
|
|
#
|
|
# Third parameter is 1 if you want relative paths returned.
|
|
# Usage: list_subdirectories(the_list_is_returned_here /path/to/project TRUE)
|
|
#
|
|
macro(list_subdirectories retval curdir return_relative)
|
|
file(GLOB sub-dir RELATIVE ${curdir} *)
|
|
set(list_of_dirs "")
|
|
foreach(dir ${sub-dir})
|
|
if(IS_DIRECTORY ${curdir}/${dir})
|
|
if (${return_relative})
|
|
set(list_of_dirs ${list_of_dirs} ${dir})
|
|
else()
|
|
set(list_of_dirs ${list_of_dirs} ${curdir}/${dir})
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
set(${retval} ${list_of_dirs})
|
|
endmacro()
|
|
|
|
#
|
|
# Generates output name for given target depending on platform and version.
|
|
# For instance, on Windows, libraries get ABI version suffix soci_coreXY.{dll|lib}.
|
|
#
|
|
function(soci_target_output_name TARGET_NAME OUTPUT_NAME)
|
|
if(NOT DEFINED TARGET_NAME)
|
|
message(SEND_ERROR "Error, the variable TARGET_NAME is not defined!")
|
|
endif()
|
|
|
|
if(NOT DEFINED ${PROJECT_NAME}_VERSION)
|
|
message(SEND_ERROR "Error, the variable ${${PROJECT_NAME}_VERSION} is not defined!")
|
|
endif()
|
|
|
|
# On Windows, ABI version is specified using binary file name suffix.
|
|
# On Unix, suffix is empty and SOVERSION is used instead.
|
|
if (WIN32)
|
|
string(LENGTH "${${PROJECT_NAME}_ABI_VERSION}" abilen)
|
|
if(abilen GREATER 0)
|
|
set(SUFFIX "_${${PROJECT_NAME}_ABI_VERSION}")
|
|
endif()
|
|
endif()
|
|
|
|
set(${OUTPUT_NAME} ${TARGET_NAME}${SUFFIX} PARENT_SCOPE)
|
|
endfunction()
|