C++QED  v2 Milestone 10
a framework for simulating open quantum dynamics
CPPQEDUse.cmake
1 # Copyright Raimar Sandner 2012–2014. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE.txt)
2 
3 #! \file CPPQEDUse.cmake
4 #! \brief Macros and functions which help to build C++QED projects.
5 
6 #! \addtogroup CPPQEDUse
7 #! @{
8 
9 #! \brief Set common compiler flags for C++QED projects.
10 #!
11 #! \return This function adds flags to the `CMAKE_CXX_FLAGS` and the
12 #! `CMAKE_CXX_FLAGS_DEBUG` variables.
13 #!
14 #! This macro sets `-std=c++11` and otherwise only affects warnings. In Debug mode, warnings are enabled.
15 #! It is automatically called in CPPQED_SETUP().
16 macro(cppqed_cxx_flags)
17  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
18  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -Wextra -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Wno-ignored-qualifiers -Wno-sign-compare -Wno-overloaded-virtual")
19  if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
20  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-local-type-template-args")
21  if(CMAKE_HOST_APPLE AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3)
22  if(XCODE)
23  set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
24  else()
25  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --stdlib=libc++")
26  endif()
27  endif()
28  endif(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
29 endmacro(cppqed_cxx_flags)
30 
31 #! \brief Generate a list of all header files in the current project.
32 #! \param source_dirs <var-name> Variable name of a list containing all source directories (e.g. `SOURCE_DIRS`, not `${SOURCE_DIRS}`)
33 #! \return This function sets the variable `${PROJECT_NAME}_PUBLIC_HEADERS`.
34 #!
35 #! Typically the output of this function is used in the `PUBLIC_HEADER` property of libraries and install targets.
36 function(gather_includes source_dirs)
37  foreach(d ${${source_dirs}})
38  file(GLOB INC ${d}/*.h ${d}/*.tcc)
39  set(${PROJECT_NAME}_PUBLIC_HEADERS ${${PROJECT_NAME}_PUBLIC_HEADERS} ${INC})
40  endforeach(d)
41  foreach(GENERATED_HEADER ${PROJECT_NAME}_config.h ${PROJECT_NAME}_version.h component_versions.h)
42  if(EXISTS ${PROJECT_BINARY_DIR}/${GENERATED_HEADER})
43  set(${PROJECT_NAME}_PUBLIC_HEADERS ${${PROJECT_NAME}_PUBLIC_HEADERS} ${PROJECT_BINARY_DIR}/${GENERATED_HEADER})
44  endif()
45  endforeach()
46  set(${PROJECT_NAME}_PUBLIC_HEADERS ${${PROJECT_NAME}_PUBLIC_HEADERS} PARENT_SCOPE)
47 endfunction()
48 
49 
50 #! \brief Gather all source files in the current directory and create an object target.
51 #! \return This macro sets the variable `OBJ_TARGETS`, which can be used as
52 #! source for library targets.
53 #!
54 #! This macro creates a target `${PROJECT_NAME}_${name}_objs` where `${name}` is the current
55 #! subdirectory and populates it with all source files in this directory. It then adds this
56 #! target to the parent scope variable `OBJ_TARGETS`.
57 #!
58 #! The macro processes the list `${name}_NEEDS`. This list contains the name of all the other
59 #! subdirectories (relative to the top level) from which this subdirectory may include header files.
60 macro(create_object_target)
61  get_filename_component(name ${CMAKE_CURRENT_LIST_DIR} NAME)
62  include_directories(${CMAKE_CURRENT_LIST_DIR})
63  foreach(d ${${name}_NEEDS})
64  include_directories(${PROJECT_SOURCE_DIR}/${d})
65  endforeach(d)
66  aux_source_directory(. ${name}_srcs)
67  add_library(${PROJECT_NAME}_${name}_objs OBJECT ${${name}_srcs})
68  if(BUNDLED_BLITZ)
69  add_dependencies(${PROJECT_NAME}_${name}_objs cppqed-blitz)
70  endif()
71  if(BUNDLED_FLENS)
72  add_dependencies(${PROJECT_NAME}_${name}_objs flens)
73  endif()
74  set_target_properties(${PROJECT_NAME}_${name}_objs PROPERTIES POSITION_INDEPENDENT_CODE On)
75  set(OBJ_TARGETS ${OBJ_TARGETS} "\$<TARGET_OBJECTS:${PROJECT_NAME}_${name}_objs>" PARENT_SCOPE)
76 endmacro()
77 
78 if(NOT ${CPPQED_MONOLITHIC})
79  message(STATUS "Using CPPQED_SETUP macro from ${CMAKE_CURRENT_LIST_DIR}")
80 endif()
81 
82 #! \brief Initialize a C++QED project.
83 #!
84 #! Typical usage:
85 #!
86 #! find_package(CPPQED 2.10 REQUIRED)
87 #! include(${CPPQED_USE})
88 #! CPPQED_SETUP()
89 #!
90 #! This macro makes sure all C++QED sub-projects are initialized in the same way.
91 #! Installation directories are handled by `GNUInstallDirs`, which is automatically included here.
92 #! The following actions are performed:
93 #!
94 #! - Sets the build type to Release if none was specified with `-DCMAKE_BUILD_TYPE`. If an unknown
95 #! build type is encountered this will result in an error.
96 #! - Sets appropriate compiler flags by calling cppqed_cxx_flags() and adding `-DBZ_DEBUG` as
97 #! flag in debug mode, adding ::CPPQED_DEFINITIONS to compiler flags.
98 #! - Adds C++QED core include directories and third-party include directories (boost, blitz etc.)
99 #! to the include path.
100 #! - Handles the libraries rpath: When building, add the full rpath into the libraries which is needed
101 #! to find all dependencies (also outside the build tree). When installing the libraries, keep only those
102 #! paths which are not system paths. See [here](http://www.cmake.org/Wiki/CMake_RPATH_handling) for more
103 #! information.
104 macro(CPPQED_SETUP)
105  include(GNUInstallDirs)
106  include(CMakePackageConfigHelpers)
107  if(DEFINED CPPQED_CMAKE_DIR)
108  include(${CPPQED_CMAKE_DIR}/GetGitRevisionDescription.cmake)
109  else()
110  include(GetGitRevisionDescription)
111  endif()
112 
113  # guard against bad build-type strings
114 
115  if (NOT CMAKE_BUILD_TYPE)
116  message(WARNING "Build type not set, default is \"Release\".")
117  set(CMAKE_BUILD_TYPE "Release")
118  endif()
119 
120  string(TOLOWER "${CMAKE_BUILD_TYPE}" cmake_build_type_tolower)
121  if( NOT cmake_build_type_tolower STREQUAL "debug"
122  AND NOT cmake_build_type_tolower STREQUAL "release")
123  message(FATAL_ERROR "Unknown build type \"${CMAKE_BUILD_TYPE}\". Allowed values are Debug and Release (case-insensitive).")
124  endif()
125 
126  set(CMAKE_DEBUG_POSTFIX "_d")
127 
128  cppqed_cxx_flags()
129 
130  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DBZ_DEBUG")
131  add_definitions(${CPPQED_DEFINITIONS})
132 
133  # use, i.e. don't skip the full RPATH for the build tree
134  SET(CMAKE_SKIP_BUILD_RPATH FALSE)
135 
136  # when building, don't use the install RPATH already
137  # (but later on when installing)
138  SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
139 
140  # add the automatically determined parts of the RPATH
141  # which point to directories outside the build tree to the install RPATH
142  SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
143 
144  # the RPATH to be used when installing, but only if it's not a system directory
145  LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES ${CMAKE_INSTALL_FULL_LIBDIR} isSystemDir)
146  IF("${isSystemDir}" STREQUAL "-1")
147  SET(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR})
148  ENDIF("${isSystemDir}" STREQUAL "-1")
149 
150  include_directories(${CPPQED_INCLUDE_DIRS})
151  include_directories(SYSTEM ${CPPQED_THIRDPARTY_INCLUDE_DIRS})
152 
153 endmacro()
154 
155 #! \brief Initialize an elements project.
156 #!
157 #! This macro expects `ELEMENTS_SOURCE_DIRS` to be set to a list of source directories. Include dependencies between
158 #! subdirectories can be established by setting `<subdir>_NEEDS` variables.
159 #!
160 #! It is used for both the original C++QED elements project and custom element projects. The name of a custom
161 #! elements project may not be "elements", this is checked here. The following actions are performed:
162 #!
163 #! - Find C++QED core, and additionally for custom element projects find C++QED elements and add them as dependencies.
164 #! - Generate version information to compile into the libraries, see generate_version_files() for details.
165 #! - Process all subdirectories listed in `ELEMENTS_SOURCE_DIRS`. The `CMakeLists.txt` file in the subdirectories should
166 #! only have a single call to create_object_target().
167 #! - Create the library target `C++QED${PROJECT_NAME}-${CPPQED_ID}`, e.g. `C++QEDelements-2.10` and link to all dependencies.
168 #! - The version and SONAME is the same as for the C++QED core library.
169 #! - Create an install target to install the libraries and the headers.
170 #! - Generate an appropriate `CPPQED${PROJECT_NAME}ConfigVersion.cmake` and `CPPQED${PROJECT_NAME}Config.cmake` file, which
171 #! ensure that other projects can find the current library by calling, e.g. `find_package(CPPQEDelements)`. Two versions of these
172 #! files are generated, one suitable for the build tree and one which is getting installed along with the library.
173 #! For details, see \ref Config "this" page.
174 #!
175 #! Typical usage in a custom elements project:
176 #!
177 #! project(elements_custom)
178 #! find_package(CPPQED 2.10 REQUIRED)
179 #! include(${CPPQED_USE})
180 #!
181 #! set(ELEMENTS_SOURCE_DIRS utils frees interactions)
182 #! set(frees_NEEDS utils)
183 #! set(interactions_NEEDS utils frees)
184 #!
185 #! elements_project()
186 macro(elements_project)
187  if(${PROJECT_NAME} STREQUAL elements)
188  if(NOT DEFINED ORIGINAL_ELEMENTS_PROJECT)
189  message(FATAL_ERROR "The project cannot be named 'elements', as this is the name of the CPPQED elements project.")
190  endif()
191  else()
192  find_package(CPPQEDelements ${CPPQED_ID} REQUIRED)
193  include_directories(${CPPQEDelements_INCLUDE_DIRS})
194  message(STATUS "Using C++QED elements from ${CPPQEDelements_DIR}.")
195  endif()
196 
197  CPPQED_SETUP()
198 
199  generate_version_files()
200 
201  foreach(d ${ELEMENTS_SOURCE_DIRS})
202  add_subdirectory(${d})
203  endforeach(d)
204 
205  set(ELEMENTS_CMAKE_SUBDIR "cmake/CPPQED${PROJECT_NAME}-${CPPQED_ID}")
206  set(ELEMENTS_INCLUDE_SUBDIR "CPPQED-${CPPQED_ID}/${PROJECT_NAME}")
207 
208  gather_includes(ELEMENTS_SOURCE_DIRS)
209 
210  set(ELEMENTSLIB C++QED${PROJECT_NAME}-${CPPQED_ID})
211  add_library(${ELEMENTSLIB} SHARED ${PROJECT_BINARY_DIR}/${PROJECT_NAME}_version.cc ${${PROJECT_NAME}_PUBLIC_HEADERS} ${OBJ_TARGETS})
212  target_link_libraries(${ELEMENTSLIB} LINK_PRIVATE ${CPPQED_LIBRARIES} ${CPPQEDelements_LIBRARIES})
213 
214  set_target_properties(${ELEMENTSLIB} PROPERTIES
215  PUBLIC_HEADER "${${PROJECT_NAME}_PUBLIC_HEADERS}"
216  INSTALL_NAME_DIR ${CMAKE_INSTALL_FULL_LIBDIR}
217  VERSION ${CPPQED_ABI_MAJOR}.${CPPQED_ABI_MINOR}.${CPPQED_ABI_MICRO}
218  SOVERSION ${CPPQED_ABI_MAJOR}
219  )
220 
221  install(TARGETS ${ELEMENTSLIB}
222  EXPORT CPPQED${PROJECT_NAME}Targets
223  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
224  PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${ELEMENTS_INCLUDE_SUBDIR}
225  COMPONENT shlib
226  )
227 
228  # Add all targets to the build-tree export set
229  if(DEFINED CPPQED_MONOLITHIC)
230  # workaround: use APPEND because we do not want to export ${CPPQED_LIBRARIES} here
231  # otherwise external project would import this target twice
232  file(REMOVE "${PROJECT_BINARY_DIR}/CPPQED${PROJECT_NAME}Targets.cmake")
233  export(TARGETS ${ELEMENTSLIB} FILE "${PROJECT_BINARY_DIR}/CPPQED${PROJECT_NAME}Targets.cmake" APPEND)
234  else(DEFINED CPPQED_MONOLITHIC)
235  export(TARGETS ${ELEMENTSLIB} FILE "${PROJECT_BINARY_DIR}/CPPQED${PROJECT_NAME}Targets.cmake")
236  endif(DEFINED CPPQED_MONOLITHIC)
237 
238  option(REGISTRY "Register build trees in the cmake registry so that other projects can find them." ON)
239  if(REGISTRY)
240  export(PACKAGE CPPQED${PROJECT_NAME})
241  endif(REGISTRY)
242 
243  # Create the CPPQEDConfig.cmake
244  # ... for the build tree
245  set(CONF_INCLUDE_DIRS ${PROJECT_BINARY_DIR})
246  foreach(d ${ELEMENTS_SOURCE_DIRS})
247  set(CONF_INCLUDE_DIRS ${CONF_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/${d})
248  endforeach(d)
249  set(CONF_CMAKE_DIR ${PROJECT_BINARY_DIR})
250  configure_package_config_file(${CPPQED_CMAKE_DIR}/ElementsTemplateConfig.cmake.in "${PROJECT_BINARY_DIR}/CPPQED${PROJECT_NAME}Config.cmake"
251  INSTALL_DESTINATION "${PROJECT_BINARY_DIR}"
252  PATH_VARS CONF_INCLUDE_DIRS CPPQED_THIRDPARTY_INCLUDE_DIRS CONF_CMAKE_DIR
253  )
254  write_basic_package_version_file(${PROJECT_BINARY_DIR}/CPPQED${PROJECT_NAME}ConfigVersion.cmake
255  VERSION ${CPPQED_VERSION_MAJOR}.${CPPQED_VERSION_MINOR}
256  COMPATIBILITY ExactVersion
257  )
258 
259  # ... and for the installation tree
260  set(CONF_INCLUDE_DIRS ${CMAKE_INSTALL_INCLUDEDIR}/${ELEMENTS_INCLUDE_SUBDIR})
261  set(CONF_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/${ELEMENTS_CMAKE_SUBDIR})
262  configure_package_config_file(${CPPQED_CMAKE_DIR}/ElementsTemplateConfig.cmake.in "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CPPQED${PROJECT_NAME}Config.cmake"
263  INSTALL_DESTINATION "${CONF_CMAKE_DIR}"
264  PATH_VARS CONF_INCLUDE_DIRS CPPQED_THIRDPARTY_INCLUDE_DIRS CONF_CMAKE_DIR
265  )
266 
267  # Install the CPPQEDConfig.cmake and CPPQEDConfigVersion.cmake
268  install(FILES
269  "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CPPQED${PROJECT_NAME}Config.cmake"
270  "${PROJECT_BINARY_DIR}/CPPQED${PROJECT_NAME}ConfigVersion.cmake"
271  DESTINATION "${CMAKE_INSTALL_LIBDIR}/${ELEMENTS_CMAKE_SUBDIR}" COMPONENT dev)
272 
273  # Install the export set for use with the install-tree
274  install(EXPORT CPPQED${PROJECT_NAME}Targets DESTINATION
275  "${CMAKE_INSTALL_LIBDIR}/${ELEMENTS_CMAKE_SUBDIR}" COMPONENT dev)
276 
277 endmacro()
278 
279 #! \brief Generate C++ source code containing version information as global variables.
280 #! \return This function sets `CONF_GIT_SHA1` and `CONF_VERSION` (c.f. get_git_head_revision()).
281 #!
282 #! This extracts the current git commit hash by using get_git_head_revision(), and generates two files
283 #! `${PROJECT_NAME}_version.cc` and `${PROJECT_NAME}_version.h`. For example, with a project `elements`, clients including
284 #! `elements_version.h` have access to these global entities:
285 #!
286 #! - `char[] g_CPPQEDelements_GIT_SHA1`: the git commit hash value
287 #! - `char[] g_CPPQEDelements_VERSION[]`: the project version
288 #! - `string cppqed_@PROJECT_NAME@_version()`: a function returning both theses values in a human readable format.
289 #!
290 #! Generated projects (c.f. elements_project() and scripts_project()) automatically call this
291 #! function and link in the generated source file.
292 function(generate_version_files)
293  get_git_head_revision(REFSPEC CONF_GIT_SHA1)
294  if(CONF_GIT_SHA1 STREQUAL "GITDIR-NOTFOUND")
295  set(CONF_GIT_SAH1 "built from source package")
296  endif()
297  set(CONF_VERSION ${CPPQED_VERSION})
298  if(DEFINED CPPQED_CMAKE_DIR)
299  set(_dir ${CPPQED_CMAKE_DIR})
300  elseif(DEFINED CPPQED_CMAKE_MODULE_PATH)
301  set(_dir ${CPPQED_CMAKE_MODULE_PATH})
302  endif()
303  configure_file("${_dir}/version.cc.in" "${PROJECT_BINARY_DIR}/${PROJECT_NAME}_version.cc" @ONLY)
304  configure_file("${_dir}/version.h.in" "${PROJECT_BINARY_DIR}/${PROJECT_NAME}_version.h" @ONLY)
305  set(CONF_GIT_SHA1 ${CONF_GIT_SHA1} PARENT_SCOPE)
306  set(CONF_VERSION ${CONF_VERSION} PARENT_SCOPE)
307 endfunction()
308 
309 #! \brief Initialize a scripts project.
310 #!
311 #! \param ELEMENTS_PROJECT `<proj_name>` (optional) Scripts depend on this custom elements project (C++QED elements project does
312 #! not need to be supplied here). Repeat for several custom elements projects.
313 #!
314 #! Scripts which reside in the top level project directory and have a `.cc` extension are picked up for compilation. The following
315 #! actions are performed:
316 #!
317 #! - Find C++QED core, elements all custom element projects passed into the macro and set them up as dependencies.
318 #! - Generate version information for the scripts project, see generate_version_files() for details.
319 #! - Gather version informations from all C++QED dependencies (core, elements and custom element projects) and compile them in a
320 #! generated source file `component_versions.cc`. Scripts including the header file `component_versions.h` have access to the function
321 #! `std::string cppqed_component_versions()`, which returns the version information of all used components in a human readable form.
322 #! - Create a target for every script found. If the script (without file extension) is listed in
323 #! `EXCLUDE_FROM_ALL_SCRIPTS`, this script will not be built automatically. If it is listed in `EXCLUDE_SCRIPTS`, no target will be created.
324 #! - Exclude all scripts listed in `NEED_FLENS` (without file extension) from compilation, if the current C++QED library does not support FLENS.
325 #! - Create a target `${PROJECT_NAME}_all` which compiles all scripts not listed in `EXCLUDE_FROM_ALL_SCRIPTS`.
326 macro(scripts_project)
327  # find CPPQED elements project
328  find_package(CPPQEDelements ${CPPQED_ID} REQUIRED)
329  include_directories(${CPPQEDelements_INCLUDE_DIRS})
330  set(ALL_ELEMENTS_LIBRARIES ${CPPQEDelements_LIBRARIES})
331 
332  include_directories(${PROJECT_BINARY_DIR})
333 
334  CPPQED_SETUP()
335 
336  generate_version_files()
337 
338  set(CONF_COMPONENT_VERSIONS "\"# \"+cppqed_core_version()+\"# \"+cppqed_elements_version()")
339  set(CONF_COMPONENT_VERSIONS_INCLUDES "#include \"core_version.h\"\n#include \"elements_version.h\"\n")
340 
341  # find additional elements projects
342  foreach(elements ${ARGV})
343  find_package(CPPQED${elements} ${CPPQED_ID} REQUIRED)
344  set(ALL_ELEMENTS_LIBRARIES ${ALL_ELEMENTS_LIBRARIES} ${CPPQED${elements}_LIBRARIES})
345  include_directories(${CPPQED${elements}_INCLUDE_DIRS})
346  set(CONF_COMPONENT_VERSIONS_INCLUDES "${CONF_COMPONENT_VERSIONS_INCLUDES}#include \"${elements}_version.h\"\n")
347  set(CONF_COMPONENT_VERSIONS "${CONF_COMPONENT_VERSIONS}+\"# \"+cppqed_${elements}_version()")
348  endforeach()
349 
350  set(CONF_COMPONENT_VERSIONS_INCLUDES "${CONF_COMPONENT_VERSIONS_INCLUDES}#include \"${PROJECT_NAME}_version.h\"")
351  set(CONF_COMPONENT_VERSIONS "${CONF_COMPONENT_VERSIONS}+\"# \"+cppqed_${PROJECT_NAME}_version()")
352 
353  configure_file(${CPPQED_CMAKE_DIR}/component_versions.cc.in ${PROJECT_BINARY_DIR}/component_versions.cc @ONLY)
354  configure_file(${CPPQED_CMAKE_DIR}/component_versions.h.in ${PROJECT_BINARY_DIR}/component_versions.h @ONLY)
355 
356  add_library(${PROJECT_NAME}_versions_obj OBJECT ${PROJECT_BINARY_DIR}/component_versions.cc ${PROJECT_BINARY_DIR}/${PROJECT_NAME}_version.cc)
357  set_target_properties(${PROJECT_NAME}_versions_obj PROPERTIES POSITION_INDEPENDENT_CODE On)
358 
359  # create all scripts targets
360  file(GLOB SCRIPTS . *.cc)
361  set(EXCLUDE_FROM_ALL_SCRIPTS ${EXCLUDE_FROM_ALL_SCRIPTS} ${CPPQED_EXCLUDE_SCRIPTS})
362  foreach(s ${SCRIPTS})
363  get_filename_component(SCRIPT ${s} NAME_WE)
364  list(FIND NEED_FLENS ${SCRIPT} F)
365  list(FIND EXCLUDE_SCRIPTS ${SCRIPT} EX)
366  list(FIND EXCLUDE_FROM_ALL_SCRIPTS ${SCRIPT} NOT_ALL)
367  set(exclude Off)
368  if(NOT EX EQUAL -1)
369  set(exclude On)
370  endif()
371  if(NOT (CPPQED_FLENS_FOUND OR F EQUAL -1))
372  set(exclude On)
373  endif()
374  if(NOT exclude)
375  add_executable(${SCRIPT} ${s} $<TARGET_OBJECTS:${PROJECT_NAME}_versions_obj>)
376  target_link_libraries(${SCRIPT} ${CPPQED_LIBRARIES} ${ALL_ELEMENTS_LIBRARIES})
377  set_target_properties(${SCRIPT} PROPERTIES DEBUG_POSTFIX _d)
378  if(NOT_ALL EQUAL -1)
379  set(SCRIPTNAMES ${SCRIPTNAMES} ${SCRIPT})
380  install(TARGETS ${SCRIPT}
381  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
382  else()
383  set_target_properties(${SCRIPT} PROPERTIES EXCLUDE_FROM_ALL ON)
384  endif()
385  endif()
386  endforeach(s)
387  # add target "scripts"
388  add_custom_target(${PROJECT_NAME}_all)
389  add_dependencies(${PROJECT_NAME}_all ${SCRIPTNAMES})
390 endmacro()
391 
392 #! \brief Generate a doxygen documentation target for the current project.
393 #!
394 #! \param target_prefix The name of the documentation target will be ${target_prefix}_doc
395 #! \param tagfiles A list with full paths to doxygen tagfiles of other projects.
396 #! \param dependencies (optional) All remaining arguments will be treated as targets
397 #! this document target should depend on.
398 #!
399 #! If doxygen or dot is not found on the system, this macro does nothing.
400 #! Otherwise it sets the variable `TAGFILES` to a list which can be used in the TAGFILES option of a
401 #! Doxyfile. The HTML location corresponding to each tagfile is expected in a html subdirectory of the
402 #! directory where the tagfile resides. All paths will be converted to relative paths so that the
403 #! resulting documentation can be relocated.
404 #!
405 #! The template `doc/Doxyfile` will be copied to `${PROJECT_NAME}_DOC_DIR`, expanding all @-variables within.
406 macro(cppqed_documentation target_prefix tagfiles)
407 
408  find_package(Doxygen 1.8)
409  set(tagfiles ${tagfiles})
410 
411  if(DOXYGEN_FOUND AND DOXYGEN_DOT_FOUND)
412  set(doc_depends ${ARGN})
413  set(DOXYGEN_HEADER_FILE ${cppqed_SOURCE_DIR}/doc/header.html)
414  set(DOXYGEN_CSS_FILE ${cppqed_SOURCE_DIR}/doc/stylesheet.css)
415  file(MAKE_DIRECTORY ${${PROJECT_NAME}_DOC_DIR})
416  while(tagfiles)
417  list(GET tagfiles 0 tagfile)
418  list(REMOVE_AT tagfiles 0)
419  file(RELATIVE_PATH relative_tagfile ${${PROJECT_NAME}_DOC_DIR} ${tagfile})
420  get_filename_component(relative_location ${relative_tagfile} PATH)
421  set(TAGFILES "${TAGFILES} ${relative_tagfile}=../${relative_location}/html")
422  endwhile()
423  set(local_doc_dir ${${PROJECT_NAME}_DOC_DIR})
424  configure_file(${PROJECT_SOURCE_DIR}/doc/Doxyfile.in ${${PROJECT_NAME}_DOC_DIR}/Doxyfile @ONLY)
425  add_custom_target(${target_prefix}doc ${DOXYGEN_EXECUTABLE} ${${PROJECT_NAME}_DOC_DIR}/Doxyfile
426  WORKING_DIRECTORY ${${PROJECT_NAME}_DOC_DIR}
427  COMMENT "Generating APIs documentation with Doxygen"
428  DEPENDS ${doc_depends}
429  )
430  install(DIRECTORY ${${PROJECT_NAME}_DOC_DIR}/html
431  DESTINATION ${CPPQED_DOC_DIR}/${PROJECT_NAME}
432  OPTIONAL
433  )
434  endif()
435 endmacro()
436 
437 #! @}