Skip to content

Commit

Permalink
De-duplicate boilerplate by using function to define backend target
Browse files Browse the repository at this point in the history
  • Loading branch information
Krzmbrzl committed Jan 26, 2025
1 parent dc5cb84 commit e0a8d52
Show file tree
Hide file tree
Showing 11 changed files with 364 additions and 568 deletions.
178 changes: 178 additions & 0 deletions cmake/soci_define_backend_target.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
include(soci_utils)

# Defines a CMake target for a database backend.
#
# This function takes care of orchestrating the boilerplate that is needed in order to set up
# a library target as used for different DB backends. Accepted arguments are
#
# ALIAS_NAME <name> Alias to use for the library. The alias name will be prefixed with "SOCI::"
# BACKEND_NAME <name> Name of the backend
# ENABLED_VARIABLE <variable> CMake variable that indicates whether this backend is enabled. Will be set
# to OFF if one of the dependencies are not satisfied.
# MISSING_DEPENDENCY_BEHAVIOR <behavior> What to do if a dependency is not found. Valid values are "ERROR" and "DISABLE"
# TARGET_NAME <target> Name of the CMake target that shall be created for this backend
# DEPENDENCIES <spec1> [... <specN>] List of dependency specifications. Each specification has to be a single
# argument (single string) following the syntax
# <find_spec> YIELDS <targets> [DEFINES <macros>]
# where <find_spec> will be passed to find_package to find the dependency. Upon
# success, all targets defined in <targets> are expected to exist. If provided,
# all defines specified in <macros> will be added as public compile definitions
# to the backend library if the dependency has been found.
# For now, all dependencies are expected to be public and required.
# FIND_PACKAGE_FILES <file1> [... <fileN>] List of files used by find_package to locate one of the dependencies. Specified
# files will be installed alongside SOCI in order to be usable from the install tree.
# HEADER_FILES <file1> [... <fileN>] List of public header files associated with this backend target.
# PRIVATE_INCLUDE_DIRS <dir1> [... <dirN>] List of private include directories
# REQUIRED_COMPONENTS <cmp1> [... <cmpN>] List of SOCI components (full target names) to link this backend target to
# SOURCE_FILES <file1> [... <fileN>] List of source files that shall be part of this backend component
function(soci_define_backend_target)
set(FLAGS "")
set(ONE_VAL_OPTIONS
"ALIAS_NAME"
"BACKEND_NAME"
"ENABLED_VARIABLE"
"MISSING_DEPENDENCY_BEHAVIOR"
"TARGET_NAME"
)
set(MULTI_VAL_OPTIONS
"DEPENDENCIES"
"FIND_PACKAGE_FILES"
"HEADER_FILES"
"PRIVATE_INCLUDE_DIRS"
"REQUIRED_COMPONENTS"
"SOURCE_FILES"
)
cmake_parse_arguments(DEFINE_BACKEND "${FLAGS}" "${ONE_VAL_OPTIONS}" "${MULTI_VAL_OPTIONS}" ${ARGV})

soci_verify_parsed_arguments(
PREFIX "DEFINE_BACKEND"
FUNCTION_NAME "soci_define_backend_target"
REQUIRED "BACKEND_NAME" "SOURCE_FILES" "ENABLED_VARIABLE" "TARGET_NAME" "ALIAS_NAME"
)

if (NOT DEFINE_BACKEND_MISSING_DEPENDENCY_BEHAVIOR)
set(DEFINE_BACKEND_MISSING_DEPENDENCY_BEHAVIOR "ERROR")
else()
string(TOUPPER "${DEFINE_BACKEND_MISSING_DEPENDENCY_BEHAVIOR}" DEFINE_BACKEND_MISSING_DEPENDENCY_BEHAVIOR)
endif()


if (DEFINE_BACKEND_MISSING_DEPENDENCY_BEHAVIOR STREQUAL "ERROR")
set(REQUIRE_FLAG "REQUIRED")
set(ERROR_ON_MISSING_DEPENDENCY ON)
elseif(DEFINE_BACKEND_MISSING_DEPENDENCY_BEHAVIOR STREQUAL "DISABLE")
set(DISABLE_ON_MISSING_DEPENDENCY ON)
else()
message(FATAL_ERROR "Invalid value '${DEFINE_BACKEND_MISSING_DEPENDENCY_BEHAVIOR}' for option 'MISSING_DEPENDENCY_BEHAVIOR'")
endif()


set(PUBLIC_DEP_CALL_ARGS "")

foreach(CURRENT_DEP_SPEC IN LISTS DEFINE_BACKEND_DEPENDENCIES)
if (NOT "${CURRENT_DEP_SPEC}" MATCHES "^([a-zA-Z0-9_:-;]+) YIELDS ([a-zA-Z0-9_:-;]+)( DEFINES [a-zA-Z0-9_;])?$")
message(FATAL_ERROR "Invalid format for dependency specification in '${CURRENT_DEP_SPEC}'")
endif()
set(CURRENT_DEP_SEARCH ${CMAKE_MATCH_1})
set(CURRENT_DEP_TARGETS ${CMAKE_MATCH_2})
set(CURRENT_DEP_DEFINES ${CMAKE_MATCH_3})

list(GET CURRENT_DEP_SEARCH 0 CURRENT_DEP)

find_package(${CURRENT_DEP_SEARCH} ${REQUIRE_FLAG})

if (NOT ${CURRENT_DEP}_FOUND)
if (ERROR_ON_MISSING_DEPENDENCY)
message(FATAL_ERROR "Expected find_package to error due to unmet dependency '${CURRENT_DEP}'")
elseif(DISABLE_ON_MISSING_DEPENDENCY)
message(STATUS "Disabling SOCI backend '${DEFINE_BACKEND_BACKEND_NAME}' due to unsatisfied dependency on '${CURRENT_DEP}'")

# Set this backend to disabled by overwriting the corresponding cache variable
# (without overwriting its description)
get_property(DESCRIPTION CACHE "${DEFINE_BACKEND_ENABLED_VARIABLE}" PROPERTY HELPSTRING)
set(${DEFINE_BACKEND_ENABLED_VARIABLE} OFF CACHE STRING "${DESCRIPTION}" FORCE)
return()
else()
message(FATAL_ERROR "Unspecified handling of unmet dependency")
endif()
endif()

foreach (CURRENT IN LISTS CURRENT_DEP_TARGETS)
if (NOT TARGET "${CURRENT}")
message(FATAL_ERROR "Expected successful find_package call with '${CURRENT_DEP_SEARCH}' to define target '${CURRENT}'")
endif()
endforeach()
if (CURRENT_DEP_DEFINES)
set(MACRO_NAMES_ARG "MACRO_NAMES ${CURRENT_DEP_DEFINES}")
endif()
list(APPEND PUBLIC_DEP_CALL_ARGS
"NAME ${CURRENT_DEP} DEP_TARGETS ${CURRENT_DEP_TARGETS} TARGET SOCI::${DEFINE_BACKEND_ALIAS_NAME} ${MACRO_NAMES_ARG} REQUIRED"
)
endforeach()


add_library(${DEFINE_BACKEND_TARGET_NAME} ${SOCI_LIB_TYPE} ${DEFINE_BACKEND_SOURCE_FILES})
add_library(SOCI::${DEFINE_BACKEND_ALIAS_NAME} ALIAS ${DEFINE_BACKEND_TARGET_NAME})

foreach(CURRENT_ARG_SET IN LISTS PUBLIC_DEP_CALL_ARGS)
# Convert space-separated string to list
string(REPLACE " " ";" CURRENT_ARG_SET "${CURRENT_ARG_SET}")
soci_public_dependency(${CURRENT_ARG_SET})
endforeach()
foreach (CURRENT_DEP IN LISTS DEFINE_BACKEND_REQUIRED_COMPONENTS)
target_link_libraries(${DEFINE_BACKEND_TARGET_NAME} PUBLIC "${CURRENT_DEP}")
endforeach()

target_include_directories(${DEFINE_BACKEND_TARGET_NAME} PRIVATE ${DEFINE_BACKEND_PRIVATE_INCLUDE_DIRS})

set_target_properties(${DEFINE_BACKEND_TARGET_NAME}
PROPERTIES
SOVERSION ${PROJECT_VERSION_MAJOR}
VERSION ${PROJECT_VERSION}
EXPORT_NAME ${DEFINE_BACKEND_ALIAS_NAME}
)

if (DEFINE_BACKEND_HEADER_FILES)
target_sources(${DEFINE_BACKEND_TARGET_NAME}
PUBLIC
FILE_SET headers TYPE HEADERS
BASE_DIRS "${PROJECT_SOURCE_DIR}/include/"
FILES ${DEFINE_BACKEND_HEADER_FILES}
)
endif()


target_link_libraries(soci_interface INTERFACE SOCI::${DEFINE_BACKEND_ALIAS_NAME})


# Setup installation rules for this backend
install(
TARGETS ${DEFINE_BACKEND_TARGET_NAME}
EXPORT SOCI${DEFINE_BACKEND_BACKEND_NAME}Targets
RUNTIME DESTINATION "${SOCI_INSTALL_BINDIR}"
COMPONENT soci_runtime
LIBRARY DESTINATION "${SOCI_INSTALL_LIBDIR}"
COMPONENT soci_runtime
NAMELINK_COMPONENT soci_development
ARCHIVE DESTINATION "${SOCI_INSTALL_LIBDIR}"
COMPONENT soci_development
FILE_SET headers DESTINATION "${SOCI_INSTALL_INCLUDEDIR}"
COMPONENT soci_development
)
# Generate and install a targets file
install(
EXPORT SOCI${DEFINE_BACKEND_BACKEND_NAME}Targets
DESTINATION "${SOCI_INSTALL_CMAKEDIR}"
FILE SOCI${DEFINE_BACKEND_BACKEND_NAME}Targets.cmake
NAMESPACE SOCI::
COMPONENT soci_development
)

foreach(FIND_FILE IN LISTS DEFINE_BACKEND_FIND_PACKAGE_FILES)
install(
FILES "${FIND_FILE}"
DESTINATION "${SOCI_INSTALL_CMAKEDIR}/find_package_files/"
COMPONENT soci_development
)
endforeach()
endfunction()
7 changes: 7 additions & 0 deletions soci-config.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ set(__dep_macro_names "@SOCI_DEPENDENCY_MACRO_NAMES@")
set(__dep_components "@SOCI_DEPENDENCY_COMPONENTS@")


set(__prev_module_path "${CMAKE_MODULE_PATH}")
list(APPEND CMAKE_MODULE_PATH "$CMAKE_CURRENT_LIST_DIR}/find_package_files/")


if (NOT DEFINED SOCI_FIND_COMPONENTS OR SOCI_FIND_COMPONENTS STREQUAL "")
# Use all available SOCI components
set(SOCI_FIND_COMPONENTS "${__dep_soci_comps}")
Expand Down Expand Up @@ -152,3 +156,6 @@ if (NOT DEFINED SOCI_FOUND OR SOCI_FOUND)
message(STATUS "Found SOCI: ${CMAKE_CURRENT_LIST_FILE} (found version \"@PROJECT_VERSION@\") found components: ${__components}")
endif()
endif()

set(CMAKE_MODULE_PATH "${__prev_module_path}")
unset(__prev_module_path)
1 change: 0 additions & 1 deletion src/backends/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ foreach(CURRENT_BACKEND IN LISTS SOCI_EXISTING_BACKENDS)

# Verify that the backend hasn't been disabled (happens if include mode is AUTO and there are
# unmet dependencies.
message(STATUS "${CURRENT_ENABLED_VAR}=${${CURRENT_ENABLED_VAR}}")
if (${CURRENT_ENABLED_VAR})
list(APPEND ENABLED_BACKENDS "${CURRENT_BACKEND}")
endif()
Expand Down
92 changes: 22 additions & 70 deletions src/backends/db2/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
include(soci_define_backend_target)

if (SOCI_DB2_AUTO)
set(REQUIRED_FLAG "")
set(DEPENDENCY_MODE "DISABLE")
else()
set(REQUIRED_FLAG "REQUIRED")
endif()

find_package(DB2 ${REQUIRED_FLAG})

if (NOT DB2_FOUND)
message(STATUS "Disabling DB2 backend as the required dependencies were not found")
set(SOCI_DB2 OFF CACHE BOOL "" FORCE)
return()
set(DEPENDENCY_MODE "ERROR")
endif()

add_library(soci_db2
${SOCI_LIB_TYPE}
soci_define_backend_target(
BACKEND_NAME "DB2"
TARGET_NAME "soci_db2"
ALIAS_NAME "DB2"
DEPENDENCIES
"DB2 YIELDS DB2::DB2"
REQUIRED_COMPONENTS SOCI::Core
SOURCE_FILES
"blob.cpp"
"factory.cpp"
"row-id.cpp"
Expand All @@ -23,65 +23,17 @@ add_library(soci_db2
"statement.cpp"
"vector-into-type.cpp"
"vector-use-type.cpp"
)

add_library(SOCI::DB2 ALIAS soci_db2)

set_target_properties(
soci_db2 PROPERTIES
SOVERSION ${PROJECT_VERSION_MAJOR}
VERSION ${PROJECT_VERSION}
EXPORT_NAME DB2
)

target_sources(soci_db2
PUBLIC
FILE_SET headers TYPE HEADERS
BASE_DIRS "${PROJECT_SOURCE_DIR}/include"
FILES
"${PROJECT_SOURCE_DIR}/include/soci/db2/soci-db2.h"
)

soci_public_dependency(
NAME DB2
DEP_TARGETS DB2::DB2
TARGET SOCI::DB2
REQUIRED
)
soci_public_dependency(
NAME SOCI::Core
DEP_TARGETS SOCI::Core
TARGET SOCI::DB2
REQUIRED
)

target_include_directories(soci_db2
PRIVATE
HEADER_FILES
"${PROJECT_SOURCE_DIR}/include/soci/db2/soci-db2.h"
PRIVATE_INCLUDE_DIRS
"${PROJECT_SOURCE_DIR}/include/private"
"${PROJECT_SOURCE_DIR}/include/soci"
FIND_PACKAGE_FILES
"${PROJECT_SOURCE_DIR}/cmake/find_modules/FindDB2.cmake"
MISSING_DEPENDENCY_BEHAVIOR "${DEPENDENCY_MODE}"
ENABLED_VARIABLE "SOCI_DB2"
)

target_link_libraries(soci_interface INTERFACE SOCI::DB2)

if (NOT SOCI_DB2)
return()
endif()

install(
TARGETS soci_db2
EXPORT SOCIDB2Targets
RUNTIME DESTINATION "${SOCI_INSTALL_BINDIR}"
COMPONENT soci_runtime
LIBRARY DESTINATION "${SOCI_INSTALL_LIBDIR}"
COMPONENT soci_runtime
NAMELINK_COMPONENT soci_development
ARCHIVE DESTINATION "${SOCI_INSTALL_LIBDIR}"
COMPONENT soci_development
FILE_SET headers DESTINATION "${SOCI_INSTALL_INCLUDEDIR}"
COMPONENT soci_development
)
# Generate and install a targets file
install(
EXPORT SOCIDB2Targets
DESTINATION "${SOCI_INSTALL_CMAKEDIR}"
FILE SOCIDB2Targets.cmake
NAMESPACE SOCI::
COMPONENT soci_development
)
76 changes: 19 additions & 57 deletions src/backends/empty/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@

add_library(soci_empty
${SOCI_LIB_TYPE}
include(soci_define_backend_target)

if (SOCI_EMPTY_AUTO)
set(DEPENDENCY_MODE "DISABLE")
else()
set(DEPENDENCY_MODE "ERROR")
endif()

soci_define_backend_target(
BACKEND_NAME "Empty"
TARGET_NAME "soci_empty"
ALIAS_NAME "Empty"
REQUIRED_COMPONENTS SOCI::Core
SOURCE_FILES
"blob.cpp"
"factory.cpp"
"row-id.cpp"
Expand All @@ -10,59 +21,10 @@ add_library(soci_empty
"statement.cpp"
"vector-into-type.cpp"
"vector-use-type.cpp"
MISSING_DEPENDENCY_BEHAVIOR "${DEPENDENCY_MODE}"
ENABLED_VARIABLE "SOCI_EMPTY"
)

add_library(SOCI::Empty ALIAS soci_empty)

set_target_properties(
soci_empty PROPERTIES
SOVERSION ${PROJECT_VERSION_MAJOR}
VERSION ${PROJECT_VERSION}
EXPORT_NAME Empty
)

target_sources(soci_empty
PUBLIC
FILE_SET headers TYPE HEADERS
BASE_DIRS "${PROJECT_SOURCE_DIR}/include"
FILES
"${PROJECT_SOURCE_DIR}/include/soci/empty/soci-empty.h"
)

soci_public_dependency(
NAME SOCI::Core
DEP_TARGETS SOCI::Core
TARGET SOCI::Empty
REQUIRED
)

target_include_directories(soci_empty
PRIVATE
"${PROJECT_SOURCE_DIR}/include/private"
"${PROJECT_SOURCE_DIR}/include/soci"
)

target_link_libraries(soci_interface INTERFACE SOCI::Empty)


install(
TARGETS soci_empty
EXPORT SOCIEmptyTargets
RUNTIME DESTINATION "${SOCI_INSTALL_BINDIR}"
COMPONENT soci_runtime
LIBRARY DESTINATION "${SOCI_INSTALL_LIBDIR}"
COMPONENT soci_runtime
NAMELINK_COMPONENT soci_development
ARCHIVE DESTINATION "${SOCI_INSTALL_LIBDIR}"
COMPONENT soci_development
FILE_SET headers DESTINATION "${SOCI_INSTALL_INCLUDEDIR}"
COMPONENT soci_development
)
# Generate and install a targets file
install(
EXPORT SOCIEmptyTargets
DESTINATION "${SOCI_INSTALL_CMAKEDIR}"
FILE SOCIEmptyTargets.cmake
NAMESPACE SOCI::
COMPONENT soci_development
)
if (NOT SOCI_EMPTY)
return()
endif()
Loading

0 comments on commit e0a8d52

Please sign in to comment.