Newer
Older
Martin Christoph Hierholzer
committed
#######################################################################################################################
#
# cmake module for finding DOOCS
#
# By default, only the client API is included. If the component "server" is specified, also the
# server library will be used. If the component "zmq" is specified, the DOOCSdzmq library will be used as well.
# Currently support components: api, server, zmq, dapi, ddaq, daqreader, daqsndlib, timinglib
#
# returns:
# DOOCS_FOUND : true or false, depending on whether the package was found
# DOOCS_VERSION : the package version
# DOOCS_LIBRARIES : list of libraries to link against
# DOOCS_DIR : doocs library dir
#
# Also returns following for compatibility, however imported targets should be preferred for usage:
# DOOCS_INCLUDE_DIRS : path to the include directory
# DOOCS_LIBRARY_DIRS : path to the library directory
# DOOCS_CXX_FLAGS : Flags needed to be passed to the c++ compiler
# DOOCS_LINK_FLAGS : Flags needed to be passed to the linker
#
# For each component <c>, an imported target DOOCS::<c> is returned.
# We support calling find_package(DOOCS COMPONENTS <cs>) several times, for adding in different components <cs>.
# DOOCS_LIBRARIES will be updated to include all requested components as imported targets.
Martin Christoph Hierholzer
committed
#######################################################################################################################
#######################################################################################################################
#
# IMPORTANT NOTE:
#
# DO NOT MODIFY THIS FILE inside a project. Instead update the project-template repository and pull the change from
# there. Make sure to keep the file generic, since it will be used by other projects, too.
#
# If you have modified this file inside a project despite this warning, make sure to cherry-pick all your changes
# into the project-template repository immediately.
#
#######################################################################################################################
Martin Christoph Hierholzer
committed
# if set, include the --no-as-needed linker flag which helps if inner dependencies between libs are not properly
# set inside the library binaries
set(DOOCS_noAsNeededFlag 1)
Martin Christoph Hierholzer
committed
# note, helper functions and variables should also be prefixed with DOOCS_, since everything is exported to
# project calling find_package(DOOCS)
function (DOOCS_addToPkgConfPath newPath)
if (NOT (":$ENV{PKG_CONFIG_PATH}:" MATCHES ":${newPath}:"))
set(ENV{PKG_CONFIG_PATH} $ENV{PKG_CONFIG_PATH}:${newPath})
endif()
endfunction()
if(DOOCS_DIR)
DOOCS_addToPkgConfPath(${DOOCS_DIR}/pkgconfig)
DOOCS_addToPkgConfPath(/export/doocs/lib/pkgconfig)
if (NOT DOOCS_FIND_QUIETLY)
message("FindDOOCS: Using PKG_CONFIG_PATH=$ENV{PKG_CONFIG_PATH}")
Martin Christoph Hierholzer
committed
# We add the always - required API component
if (NOT (";${DOOCS_FIND_COMPONENTS};" MATCHES ";api;"))
list(PREPEND DOOCS_FIND_COMPONENTS "api")
Martin Christoph Hierholzer
committed
endif()
Martin Christoph Hierholzer
committed
function(expandDoocsComponentName longName shortName)
if (";${shortName};" MATCHES ";api;")
set(${longName} "doocs-doocsapi" PARENT_SCOPE)
elseif (";${shortName};" MATCHES ";zmq;")
set(${longName} "doocs-doocsdzmq" PARENT_SCOPE)
elseif (";${shortName};" MATCHES ";dapi;")
set(${longName} "doocs-doocsdapi" PARENT_SCOPE)
elseif (";${shortName};" MATCHES ";server;")
set(${longName} "doocs-serverlib" PARENT_SCOPE)
elseif (";${shortName};" MATCHES ";ddaq;")
set(${longName} "doocs-doocsddaq" PARENT_SCOPE)
elseif (";${shortName};" MATCHES ";daqreader;")
set(${longName} "doocs-daqreaderlib" PARENT_SCOPE)
elseif (";${shortName};" MATCHES ";daqsndlib;")
set(${longName} "doocs-daqsndlib" PARENT_SCOPE)
elseif (";${shortName};" MATCHES ";timinglib;")
# we define it as alias to doocs-doocsapi and check additional requirements
set(${longName} "doocs-doocsapi" PARENT_SCOPE)
else()
set(${longName} "${shortName}" PARENT_SCOPE)
endif()
endfunction()
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
# thread libraries are required by DOOCS but seem not to be added through pkgconfig...
find_package(Threads REQUIRED)
# We expect that find_package will be called more than once, with different components.
# Since imported targets cannot be replaced, the only clean solution is to define an imported component per pkgconfig component.
# pkg_check_modules can be called more than once, with different components.
# We define DOOCS_FIND_COMPONENTS_ALL to collect all asked-for components
foreach(component ${DOOCS_FIND_COMPONENTS})
expandDoocsComponentName(componentLongName ${component})
if (NOT ";${DOOCS_FIND_COMPONENTS_ALL};" MATCHES ";${componentLongName};")
list(APPEND DOOCS_FIND_COMPONENTS_ALL ${componentLongName})
# IMPORTED_TARGET means also imported target PkgConfig::DOOCS will be defined. GLOBAL so we can alias.
pkg_check_modules(DOOCS_${component} REQUIRED IMPORTED_TARGET GLOBAL ${componentLongName})
if (DOOCS_${component}_FOUND)
set(importedTarget PkgConfig::DOOCS_${component})
if (NOT DOOCS_FIND_QUIETLY)
message(STATUS "FindDOOCS: imported target is ${importedTarget}. Defining alias DOOCS::${component}")
endif()
add_library(DOOCS::${component} ALIAS ${importedTarget})
Martin Christoph Hierholzer
committed
set(DOOCS_LIBRARIES ${DOOCS_LIBRARIES} "DOOCS::${component}")
Martin Christoph Hierholzer
committed
if (${component} STREQUAL "api")
# add Threads lib only if not yet in
get_target_property(doocsLinkLibs ${importedTarget} INTERFACE_LINK_LIBRARIES)
if (NOT (";${doocsLinkLibs};" MATCHES ";Threads::Threads;"))
set_target_properties(${importedTarget} PROPERTIES INTERFACE_LINK_LIBRARIES "${doocsLinkLibs};Threads::Threads" )
endif()
if(DOOCS_noAsNeededFlag)
get_target_property(doocsLinkFlags ${importedTarget} INTERFACE_LINK_OPTIONS)
string(REGEX REPLACE ".*-NOTFOUND" "" doocsLinkFlags "${doocsLinkFlags}")
set_target_properties(${importedTarget} PROPERTIES INTERFACE_LINK_OPTIONS "-Wl,--no-as-needed;${doocsLinkFlags}")
endif()
else()
# since we did some changes on DOOCS::api, add that as implicit dependency of the other components
# This makes sure projects not explicitly linking to DOOCS::api have the changes
get_target_property(doocsLinkLibs ${importedTarget} INTERFACE_LINK_LIBRARIES)
string(REGEX REPLACE ".*-NOTFOUND" "" doocsLinkLibs "${doocsLinkLibs}")
set_target_properties(${importedTarget} PROPERTIES INTERFACE_LINK_LIBRARIES "DOOCS::api;${doocsLinkLibs}")
endif()
Martin Christoph Hierholzer
committed
# strip the RPATH from the INTERFACE_LINK_OPTIONS of the imported target
# cmake will handle the RPATH properly itself when using imported targets. Adding the rpath linker flags
# explicitly will not only add the directories to the RPATH twice but also destroy the proper ordering,
# since the directories from the linker flags will be added first and e.g. the build directory will end up
# too late in the list. As a consequence, test executables might use the installed libraries instead of the
# library under test from the build directory - even for tests and libraries quite unrelated to DOOCS, as
# long as they have a DOOCS library as a (direct or indirect) dependency.
get_target_property(MY_LINK_OPTIONS ${importedTarget} INTERFACE_LINK_OPTIONS)
string(REGEX REPLACE "-Wl,-rpath,[^;]*" "" MY_LINK_OPTIONS "${MY_LINK_OPTIONS}")
string(REGEX REPLACE ";;" ";" MY_LINK_OPTIONS "${MY_LINK_OPTIONS}")
string(REGEX REPLACE "^;" "" MY_LINK_OPTIONS "${MY_LINK_OPTIONS}")
string(REGEX REPLACE ";$" "" MY_LINK_OPTIONS "${MY_LINK_OPTIONS}")
set_target_properties(${importedTarget} PROPERTIES INTERFACE_LINK_OPTIONS "${MY_LINK_OPTIONS}")
# print some info about targets
get_target_property(doocsIncDirs ${importedTarget} INTERFACE_INCLUDE_DIRECTORIES)
message(VERBOSE " include dirs: ${doocsIncDirs}")
get_target_property(doocsCxxFlags ${importedTarget} INTERFACE_COMPILE_OPTIONS)
message(VERBOSE " compile options: ${doocsCxxFlags}")
get_target_property(doocsLinkFlags ${importedTarget} INTERFACE_LINK_OPTIONS)
message(VERBOSE " link options: ${doocsLinkFlags}")
get_target_property(doocsLinkLibs ${importedTarget} INTERFACE_LINK_LIBRARIES)
message(VERBOSE " link libs: ${doocsLinkLibs}")
get_target_property(doocsLinkDirs ${importedTarget} INTERFACE_LINK_DIRECTORIES)
message(VERBOSE " link dirs: ${doocsLinkDirs}")
Martin Christoph Hierholzer
committed
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
else()
message(FATAL_ERROR "DOOCS component ${component} not found!")
endif()
endif()
if(${component} STREQUAL "timinglib")
# Find doocs/TimingWord.h from dev-doocs-doocstiminglib
# which unfortunately does not provide pkgconfig
find_path(DOOCS_timingLib_INCLUDE_DIRS doocs/TimingWord.h REQUIRED PATHS ${DOOCS_api_INCLUDE_DIRS})
if (NOT DOOCS_timingLib_INCLUDE_DIRS)
message(FATAL_ERROR "FindDOOCS: Failed to find TimingWord.h")
set(DOOCS_timingLib_FOUND FALSE)
else()
if (NOT DOOCS_FIND_QUIETLY)
message(STATUS "FindDOOCS: Found timinglib, include dirs: ${DOOCS_timingLib_INCLUDE_DIRS}")
endif()
set(DOOCS_timingLib_FOUND TRUE)
# include dir is always same as for api component, so alias is sufficient
add_library(DOOCS::${component} ALIAS PkgConfig::DOOCS_api)
endif()
endif()
endforeach()
#message(DEBUG "complete list of searched components: ${DOOCS_FIND_COMPONENTS_ALL}")
# append to list (arg) to space-separated list, only include not yet existing elements
macro(DOOCS_appendListToList list arg)
foreach(DOOCS_appendListToList_arg ${arg})
string(FIND " ${${list}} " " ${DOOCS_appendListToList_arg} " DOOCS_appendListToList_pos)
if (${DOOCS_appendListToList_pos} EQUAL -1)
string(APPEND ${list} " ${DOOCS_appendListToList_arg}")
# strip leading spaces since they might cause problems
string(REGEX REPLACE "^[ \t]+" "" ${list} "${${list}}")
endif()
endforeach()
endmacro()
Martin Christoph Hierholzer
committed
# note, pkg_check_modules output variables <prefix>_VERSION and <prefix>_LIBDIR are different,
# depending on length of given module list!
set(DOOCS_DIR "${DOOCS_api_LIBDIR}")
set(DOOCS_VERSION "${DOOCS_api_VERSION}")
set(DOOCS_LIBRARIES ${DOOCS_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
# following lines are compatibiliy layer, required only if using project does not make use of imported targets
# here we should gather from all components
set(DOOCS_CFLAGS "")
set(DOOCS_LDFLAGS "")
if(DOOCS_noAsNeededFlag)
set(DOOCS_LDFLAGS "-Wl,--no-as-needed")
endif()
set(DOOCS_INCLUDE_DIRS "")
set(DOOCS_LIBRARY_DIRS "")
foreach(component api zmq server ddaq daqreader daqsndlib)
DOOCS_appendListToList(DOOCS_CFLAGS "${DOOCS_${component}_CFLAGS}")
DOOCS_appendListToList(DOOCS_LDFLAGS "${DOOCS_${component}_LDFLAGS}")
DOOCS_appendListToList(DOOCS_INCLUDE_DIRS "${DOOCS_${component}_INCLUDE_DIRS}")
DOOCS_appendListToList(DOOCS_LIBRARY_DIRS "${DOOCS_${component}_LIBRARY_DIRS}")
endforeach()
set(DOOCS_CXX_FLAGS ${DOOCS_CFLAGS})
set(DOOCS_LINKER_FLAGS ${DOOCS_LDFLAGS})
set(DOOCS_LINK_FLAGS ${DOOCS_LINKER_FLAGS})
# use a macro provided by CMake to check if all the listed arguments are valid and set DOOCS_FOUND accordingly
include(FindPackageHandleStandardArgs)
Martin Christoph Hierholzer
committed
FIND_PACKAGE_HANDLE_STANDARD_ARGS(DOOCS REQUIRED_VARS DOOCS_DIR VERSION_VAR DOOCS_VERSION)