TargetTools.cmake
Go to the documentation of this file.
1 # ============================================================================
2 # Copyright (c) 2011-2012 University of Pennsylvania
3 # Copyright (c) 2013-2016 Andreas Schuh
4 # All rights reserved.
5 #
6 # See COPYING file for license information or visit
7 # https://cmake-basis.github.io/download.html#license
8 # ============================================================================
9 
10 ##############################################################################
11 # @file TargetTools.cmake
12 # @brief Functions and macros to add executable and library targets.
13 #
14 # @ingroup CMakeTools
15 ##############################################################################
16 
18  return ()
19 else ()
21 endif ()
22 
23 
24 ## @addtogroup CMakeUtilities
25 # @{
26 
27 
28 # ============================================================================
29 # properties
30 # ============================================================================
31 
32 # ----------------------------------------------------------------------------
33 ## @brief Set properties on a target.
34 #
35 # This function replaces CMake's
36 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_target_properties">
37 # set_target_properties()</a> command and extends its functionality.
38 # In particular, it maps the given target names to the corresponding target UIDs.
39 #
40 # @note If @c BASIS_USE_TARGET_UIDS is @c OFF and is not required by a project,
41 # it is recommended to use set_target_properties() instead (note that
42 # set_target_properties is overriden by the ImportTools.cmake module of BASIS).
43 # This will break the build configuration scripts when @c BASIS_USE_TARGET_UIDS
44 # is set to @c ON later. It should thus only be used if the project will
45 # never use the target UID feature of BASIS. A project can possibly define
46 # a global macro which either calls set_target_properties or
47 # basis_set_target_properties. But be aware of the related CMake bugs
48 # which prevent basis_set_target_properties to do the same already.
49 # ARGV/ARGN do not preserve empty arguments nor list arguments!
50 #
51 # @note Due to a bug in CMake (http://www.cmake.org/Bug/view.php?id=12303),
52 # except of the first property given directly after the @c PROPERTIES keyword,
53 # only properties listed in @c BASIS_PROPERTIES_ON_TARGETS can be set.
54 #
55 # @param [in] ARGN List of arguments. See
56 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_target_properties">
57 # set_target_properties()</a>.
58 #
59 # @returns Sets the specified properties on the given target.
60 #
61 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_target_properties
62 #
63 # @ingroup CMakeAPI
65  # convert target names to UIDs
66  set (TARGET_UIDS)
67  list (LENGTH ARGN N)
68  if (N EQUAL 0)
69  message (FATAL_ERROR "basis_set_target_properties(): Missing arguments!")
70  endif ()
71  list (GET ARGN 0 ARG)
72  while (NOT ARG MATCHES "^PROPERTIES$")
73  basis_get_target_uid (TARGET_UID "${ARG}")
74  list (APPEND TARGET_UIDS "${TARGET_UID}")
75  list (REMOVE_AT ARGN 0)
76  list (LENGTH ARGN N)
77  if (N EQUAL 0)
78  break ()
79  else ()
80  list (GET ARGN 0 ARG)
81  endif ()
82  endwhile ()
83  if (NOT ARG MATCHES "^PROPERTIES$")
84  message (FATAL_ERROR "Missing PROPERTIES argument!")
85  elseif (NOT TARGET_UIDS)
86  message (FATAL_ERROR "No target specified!")
87  endif ()
88  # remove PROPERTIES keyword
89  list (REMOVE_AT ARGN 0)
90  math (EXPR N "${N} - 1")
91  # set targets properties
92  #
93  # Note: By iterating over the properties, the empty property values
94  # are correctly passed on to CMake's set_target_properties()
95  # command, while
96  # _set_target_properties(${TARGET_UIDS} PROPERTIES ${ARGN})
97  # (erroneously) discards the empty elements in ARGN.
98  if (BASIS_DEBUG)
99  message ("** basis_set_target_properties:")
100  message ("** Target(s): ${TARGET_UIDS}")
101  message ("** Properties: [${ARGN}]")
102  endif ()
103  while (N GREATER 1)
104  list (GET ARGN 0 PROPERTY)
105  list (GET ARGN 1 VALUE)
106  list (REMOVE_AT ARGN 0 1)
107  list (LENGTH ARGN N)
108  # The following loop is only required b/c CMake's ARGV and ARGN
109  # lists do not support arguments which are themselves lists.
110  # Therefore, we need a way to decide when the list of values for a
111  # property is terminated. Hence, we only allow known properties
112  # to be set, except for the first property where the name follows
113  # directly after the PROPERTIES keyword.
114  while (N GREATER 0)
115  list (GET ARGN 0 ARG)
116  if (ARG MATCHES "${BASIS_PROPERTIES_ON_TARGETS_RE}")
117  break ()
118  endif ()
119  list (APPEND VALUE "${ARG}")
120  list (REMOVE_AT ARGN 0)
121  list (LENGTH ARGN N)
122  endwhile ()
123  if (BASIS_DEBUG)
124  message ("** -> ${PROPERTY} = [${VALUE}]")
125  endif ()
126  # check property name
127  if (PROPERTY MATCHES "^$") # remember: STREQUAL is buggy and evil!
128  message (FATAL_ERROR "Empty property name given!")
129  endif ()
130  # set target property
131  if (COMMAND _set_target_properties) # i.e. ImportTools.cmake included
132  _set_target_properties (${TARGET_UIDS} PROPERTIES ${PROPERTY} "${VALUE}")
133  else ()
134  set_target_properties (${TARGET_UIDS} PROPERTIES ${PROPERTY} "${VALUE}")
135  endif ()
136  endwhile ()
137  # make sure that every property had a corresponding value
138  if (NOT N EQUAL 0)
139  message (FATAL_ERROR "No value given for target property ${ARGN}")
140  endif ()
141 endfunction ()
142 
143 # ----------------------------------------------------------------------------
144 ## @brief Get value of property set on target.
145 #
146 # This function replaces CMake's
147 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_target_properties">
148 # get_target_properties()</a> command and extends its functionality.
149 # In particular, it maps the given @p TARGET_NAME to the corresponding target UID.
150 #
151 # @param [out] VAR Name of output variable.
152 # @param [in] TARGET_NAME Name of build target.
153 # @param [in] ARGN Remaining arguments for
154 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_target_properties">
155 # get_target_properties()</a>.
156 #
157 # @returns Sets @p VAR to the value of the requested property.
158 #
159 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_target_property
160 #
161 # @ingroup CMakeAPI
162 function (basis_get_target_property VAR TARGET_NAME)
163  basis_get_target_uid (TARGET_UID "${TARGET_NAME}")
164  get_target_property (VALUE "${TARGET_UID}" ${ARGN})
165  set (${VAR} "${VALUE}" PARENT_SCOPE)
166 endfunction ()
167 
168 # ============================================================================
169 # definitions
170 # ============================================================================
171 
172 # ----------------------------------------------------------------------------
173 ## @brief Add compile definitions.
174 #
175 # This function replaces CMake's
176 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_definitions">
177 # add_definitions()</a> command.
178 #
179 # @param [in] ARGN List of arguments for
180 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_definitions">
181 # add_definitions()</a>.
182 #
183 # @returns Adds the given definitions.
184 #
185 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_definitions
186 #
187 # @ingroup CMakeAPI
188 function (basis_add_definitions)
189  add_definitions (${ARGN})
190 endfunction ()
191 
192 # ----------------------------------------------------------------------------
193 ## @brief Remove previously added compile definitions.
194 #
195 # This function replaces CMake's
196 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:remove_definitions">
197 # remove_definitions()</a> command.
198 #
199 # @param [in] ARGN List of arguments for
200 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:remove_definitions">
201 # remove_definitions()</a>.
202 #
203 # @returns Removes the specified definitions.
204 #
205 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:remove_definition
206 #
207 # @ingroup CMakeAPI
208 function (basis_remove_definitions)
209  remove_definitions (${ARGN})
210 endfunction ()
211 
212 # ============================================================================
213 # directories
214 # ============================================================================
215 
216 # ----------------------------------------------------------------------------
217 ## @brief Add directories to search path for include files.
218 #
219 # Overwrites CMake's
220 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories">
221 # include_directories()</a> command. This is required because the
222 # basis_include_directories() function is not used by other projects in their
223 # package use files. Therefore, this macro is an alias for
224 # basis_include_directories().
225 #
226 # @param [in] ARGN List of arguments for basis_include_directories().
227 #
228 # @returns Adds the given paths to the search path for include files.
229 #
230 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories
231 macro (include_directories)
232  basis_include_directories (${ARGN})
233 endmacro ()
234 
235 # ----------------------------------------------------------------------------
236 ## @brief Add directories to search path for include files.
237 #
238 # This function replaces CMake's
239 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories">
240 # include_directories()</a> command. Besides invoking CMake's internal command
241 # with the given arguments, it updates the @c PROJECT_INCLUDE_DIRECTORIES
242 # property on the current project (see basis_set_project_property()). This list
243 # contains a list of all include directories used by a project, regardless of
244 # the directory in which the basis_include_directories() function was used.
245 #
246 # @param ARGN List of arguments for
247 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories">
248 # include_directories()</a> command.
249 #
250 # @returns Nothing.
251 #
252 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories
253 #
254 # @ingroup CMakeAPI
255 function (basis_include_directories)
256  # CMake's include_directories ()
257  _include_directories (${ARGN})
258 
259  # parse arguments
260  CMAKE_PARSE_ARGUMENTS (ARGN "AFTER;BEFORE;SYSTEM" "" "" ${ARGN})
261 
262  # make relative paths absolute
263  set (DIRS)
264  foreach (P IN LISTS ARGN_UNPARSED_ARGUMENTS)
265  if (NOT P MATCHES "^\\$<") # preserve generator expressions
266  get_filename_component (P "${P}" ABSOLUTE)
267  endif ()
268  list (APPEND DIRS "${P}")
269  endforeach ()
270 
271  if (DIRS)
272  # append directories to "global" list of include directories
273  basis_get_project_property (INCLUDE_DIRS PROPERTY PROJECT_INCLUDE_DIRS)
274  if (BEFORE)
275  list (INSERT INCLUDE_DIRS 0 ${DIRS})
276  else ()
277  list (APPEND INCLUDE_DIRS ${DIRS})
278  endif ()
279  if (INCLUDE_DIRS)
280  list (REMOVE_DUPLICATES INCLUDE_DIRS)
281  endif ()
282  if (BASIS_DEBUG)
283  message ("** basis_include_directories():")
284  if (BEFORE)
285  message ("** Add before: ${DIRS}")
286  else ()
287  message ("** Add after: ${DIRS}")
288  endif ()
289  if (BASIS_VERBOSE)
290  message ("** Directories: ${INCLUDE_DIRS}")
291  endif ()
292  endif ()
293  basis_set_project_property (PROPERTY PROJECT_INCLUDE_DIRS ${INCLUDE_DIRS})
294  endif ()
295 endfunction ()
296 
297 # ----------------------------------------------------------------------------
298 ## @brief Add directories to search path for libraries.
299 #
300 # Overwrites CMake's
301 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:link_directories">
302 # link_directories()</a> command. This is required because the
303 # basis_link_directories() function is not used by other projects in their
304 # package use files. Therefore, this macro is an alias for
305 # basis_link_directories().
306 #
307 # @param [in] ARGN List of arguments for basis_link_directories().
308 #
309 # @returns Adds the given paths to the search path for libraries.
310 #
311 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:link_directories
312 macro (link_directories)
313  basis_link_directories (${ARGN})
314 endmacro ()
315 
316 # ----------------------------------------------------------------------------
317 ## @brief Add directories to search path for libraries.
318 #
319 # This function replaces CMake's
320 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:link_directories">
321 # link_directories()</a> command. Even though this function yet only invokes
322 # CMake's internal command, it should be used in BASIS projects to enable the
323 # extension of this command's functionality as part of BASIS if required.
324 #
325 # @param [in] ARGN List of arguments for
326 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:link_directories">
327 # link_directories()</a>.
328 #
329 # @returns Adds the given paths to the search path for libraries.
330 #
331 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:link_directories
332 #
333 # @ingroup CMakeAPI
334 function (basis_link_directories)
335  # CMake's link_directories() command
336  _link_directories (${ARGN})
337  # make relative paths absolute
338  set (DIRS)
339  foreach (P IN LISTS ARGN)
340  if (NOT P MATCHES "^\\$<") # preserve generator expressions
341  get_filename_component (P "${P}" ABSOLUTE)
342  endif ()
343  list (APPEND DIRS "${P}")
344  endforeach ()
345  if (DIRS)
346  # append directories to "global" list of link directories
347  basis_get_project_property (LINK_DIRS PROPERTY PROJECT_LINK_DIRS)
348  list (APPEND LINK_DIRS ${DIRS})
349  if (LINK_DIRS)
350  list (REMOVE_DUPLICATES LINK_DIRS)
351  endif ()
352  if (BASIS_DEBUG)
353  message ("** basis_link_directories():")
354  message ("** Add: [${DIRS}]")
355  if (BASIS_VERBOSE)
356  message ("** Directories: [${LINK_DIRS}]")
357  endif ()
358  endif ()
359  basis_set_project_property (PROPERTY PROJECT_LINK_DIRS "${LINK_DIRS}")
360  # if the directories are added by an external project's <Pkg>Use.cmake
361  # file which is part of the same superbuild as this project, add the
362  # directories further to the list of directories that may be added to
363  # the RPATH. see basis_set_target_install_rpath().
364  if (BUNDLE_PROJECT) # set in basis_use_package()
365  basis_get_project_property (LINK_DIRS PROPERTY BUNDLE_LINK_DIRS)
366  list (APPEND LINK_DIRS ${DIRS})
367  if (LINK_DIRS)
368  list (REMOVE_DUPLICATES LINK_DIRS)
369  endif ()
370  basis_set_project_property (PROPERTY BUNDLE_LINK_DIRS "${LINK_DIRS}")
371  endif ()
372  endif ()
373 endfunction ()
374 
375 # ============================================================================
376 # dependencies
377 # ============================================================================
378 
379 # ----------------------------------------------------------------------------
380 ## @brief Add dependencies to build target.
381 #
382 # This function replaces CMake's
383 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_dependencies">
384 # add_dependencies()</a> command and extends its functionality.
385 # In particular, it maps the given target names to the corresponding target UIDs.
386 #
387 # @param [in] ARGN Arguments for
388 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_dependencies">
389 # add_dependencies()</a>.
390 #
391 # @returns Adds the given dependencies of the specified build target.
392 #
393 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_dependencies
394 #
395 # @ingroup CMakeAPI
396 if (BASIS_USE_TARGET_UIDS)
397  function (basis_add_dependencies)
398  set (ARGS)
399  foreach (ARG ${ARGN})
400  basis_get_target_uid (UID "${ARG}")
401  if (TARGET "${UID}")
402  list (APPEND ARGS "${UID}")
403  else ()
404  list (APPEND ARGS "${ARG}")
405  endif ()
406  endforeach ()
407  add_dependencies (${ARGS})
408  endfunction ()
409 else ()
410  macro (basis_add_dependencies)
411  add_dependencies (${ARGV})
412  endmacro ()
413 endif ()
414 
415 # ----------------------------------------------------------------------------
416 ## @brief Add link dependencies to build target.
417 #
418 # This function replaces CMake's
419 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:target_link_libraries">
420 # target_link_libraries()</a> command.
421 #
422 # The main reason for replacing this function is to treat libraries such as
423 # MEX-files which are supposed to be compiled into a MATLAB executable added
424 # by basis_add_executable() special. In this case, these libraries are added
425 # to the LINK_DEPENDS property of the given MATLAB Compiler target. Similarly,
426 # executable scripts and modules written in a scripting language may depend
427 # on other modules.
428 #
429 # Another reason is the mapping of build target names to fully-qualified
430 # build target names as used by BASIS (see basis_get_target_uid()).
431 #
432 # Only link dependencies added with this function are considered for the setting
433 # of the INSTALL_RPATH of executable targets (see basis_set_target_install_rpath()).
434 #
435 # Example:
436 # @code
437 # basis_add_library (MyMEXFunc MEX myfunc.c)
438 # basis_add_executable (MyMATLABApp main.m)
439 # basis_target_link_libraries (MyMATLABApp MyMEXFunc OtherMEXFunc.mexa64)
440 # @endcode
441 #
442 # @param [in] TARGET_NAME Name of the target.
443 # @param [in] ARGN Link libraries.
444 #
445 # @returns Adds link dependencies to the specified build target.
446 # For custom targets, the given libraries are added to the
447 # @c LINK_DEPENDS property of these targets, in particular.
448 #
449 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:target_link_libraries
450 #
451 # @ingroup CMakeAPI
452 function (basis_target_link_libraries TARGET_NAME)
453  basis_get_target_uid (TARGET_UID "${TARGET_NAME}")
454  if (NOT TARGET "${TARGET_UID}")
455  message (FATAL_ERROR "basis_target_link_libraries(): Unknown target ${TARGET_UID}.")
456  endif ()
457  # get type of named target
458  get_target_property (BASIS_TYPE ${TARGET_UID} BASIS_TYPE)
459  # substitute non-fully qualified target names
460  set (ARGS)
461  foreach (ARG ${ARGN})
462  if ("^${ARG}$" STREQUAL "^basis$")
463  get_target_property (LANGUAGE ${TARGET_UID} LANGUAGE)
464  if (NOT LANGUAGE OR "^${LANGUAGE}$" STREQUAL "^UNKNOWN$")
465  message (FATAL_ERROR "Target ${TARGET_UID} is of unknown LANGUAGE! Cannot add dependency on \"basis\" utilities.")
466  endif ()
467  basis_add_utilities_library (BASIS_UTILITIES_TARGET ${LANGUAGE})
468  list (APPEND ARGS ${BASIS_UTILITIES_TARGET})
469  set_target_properties (${TARGET_UID} PROPERTIES BASIS_UTILITIES TRUE)
470  else ()
471  basis_get_target_uid (UID "${ARG}")
472  if (TARGET "${UID}")
473  if ("^${UID}$" STREQUAL "^${TARGET_UID}$")
474  message (FATAL_ERROR "Cannot add link library ${UID} as dependency of itself!")
475  endif ()
476  list (APPEND ARGS "${UID}")
477  else ()
478  list (APPEND ARGS "${ARG}")
479  endif ()
480  endif ()
481  endforeach ()
482  # get current link libraries
483  if (BASIS_TYPE MATCHES "^EXECUTABLE$|^(SHARED|STATIC|MODULE)_LIBRARY$")
484  get_target_property (DEPENDS ${TARGET_UID} BASIS_LINK_DEPENDS)
485  else ()
486  get_target_property (DEPENDS ${TARGET_UID} LINK_DEPENDS)
487  endif ()
488  if (NOT DEPENDS)
489  set (DEPENDS)
490  endif ()
491  # note that MCC does itself a dependency check and in case of scripts
492  # the basis_get_target_link_libraries() function is used
493  if (BASIS_TYPE MATCHES "MCC|SCRIPT")
494  list (APPEND DEPENDS ${ARGS})
495  # otherwise
496  else ()
497  list (APPEND DEPENDS ${ARGS})
498  # pull implicit dependencies (e.g., ITK uses this)
499  set (DEPENDENCY_ADDED 1)
500  while (DEPENDENCY_ADDED)
501  set (DEPENDENCY_ADDED 0)
502  foreach (LIB IN LISTS DEPENDS)
503  foreach (LIB_DEPEND IN LISTS ${LIB}_LIB_DEPENDS)
504  if (NOT LIB_DEPEND MATCHES "^$|^general$")
505  string (REGEX REPLACE "^-l" "" LIB_DEPEND "${LIB_DEPEND}")
506  list (FIND DEPENDS ${LIB_DEPEND} IDX)
507  if (IDX EQUAL -1)
508  list (APPEND DEPENDS ${LIB_DEPEND})
509  set (DEPENDENCY_ADDED 1)
510  endif ()
511  endif ()
512  endforeach ()
513  endforeach ()
514  endwhile ()
515  endif ()
516  # update LINK_DEPENDS
517  if (BASIS_TYPE MATCHES "^EXECUTABLE$|^(SHARED|STATIC|MODULE)_LIBRARY$")
518  set_target_properties (${TARGET_UID} PROPERTIES BASIS_LINK_DEPENDS "${DEPENDS}")
519  target_link_libraries (${TARGET_UID} ${ARGS})
520  else ()
521  # FIXME cannot use LINK_DEPENDS for CMake targets as these depends are
522  # otherwise added as is to the Makefile. therefore, consider renaming
523  # LINK_DEPENDS in general to BASIS_LINK_DEPENDS.
524  set_target_properties (${TARGET_UID} PROPERTIES LINK_DEPENDS "${DEPENDS}")
525  endif ()
526 endfunction ()
527 
528 # ============================================================================
529 # add targets
530 # ============================================================================
531 
532 # ----------------------------------------------------------------------------
533 ## @brief Add custom target.
534 macro (basis_add_custom_target TARGET_NAME)
535  basis_check_target_name ("${TARGET_NAME}")
536  basis_make_target_uid (_UID "${TARGET_NAME}")
537  add_custom_target (${_UID} ${ARGN})
538  unset (_UID)
539 endmacro ()
540 
541 # ----------------------------------------------------------------------------
542 ## @brief Determine language of source files.
543 # @sa basis_add_executable(), basis_add_library()
544 macro (_basis_target_source_language)
545  if (NOT ARGN_LANGUAGE)
546  basis_get_source_language (ARGN_LANGUAGE ${SOURCES})
547  if (ARGN_LANGUAGE MATCHES "AMBIGUOUS|UNKNOWN")
548  set (_FILES)
549  foreach (SOURCE IN LISTS SOURCES)
550  set (_FILES "${_FILES}\n ${SOURCE}")
551  endforeach ()
552  if (ARGN_LANGUAGE MATCHES "AMBIGUOUS")
553  message (FATAL_ERROR "Target ${TARGET_UID}: Ambiguous source code files! Try to set LANGUAGE manually and make sure that no unknown option was given:${_FILES}")
554  elseif (ARGN_LANGUAGE MATCHES "UNKNOWN")
555  message (FATAL_ERROR "Target ${TARGET_UID}: Unknown source code language! Try to set LANGUAGE manually and make sure that no unknown option was given:${_FILES}")
556  endif ()
557  endif ()
558  else ()
559  string (TOUPPER "${ARGN_LANGUAGE}" ARGN_LANGUAGE)
560  endif ()
561 endmacro ()
562 
563 # ----------------------------------------------------------------------------
564 ## @brief Add executable target.
565 #
566 # This is the main function to add an executable target to the build system,
567 # where an executable can be a binary file or a script written in a scripting
568 # language. In general we refer to any output file which is part of the software
569 # (i.e., excluding configuration files) and which can be executed
570 # (e.g., a binary file in the ELF format) or interpreted (e.g., a Python script)
571 # directly, as executable file. Natively, CMake supports only executables built
572 # from C/C++ source code files. This function extends CMake's capabilities
573 # by adding custom build commands for non-natively supported programming
574 # languages and further standardizes the build of executable targets.
575 # For example, by default, it is not necessary to specify installation rules
576 # separately as these are added by this function already (see below).
577 #
578 # @par Programming languages
579 # Besides adding usual executable targets build by the set <tt>C/CXX</tt>
580 # language compiler, this function inspects the list of source files given and
581 # detects whether this list contains sources which need to be build using a
582 # different compiler. In particular, it supports the following languages:
583 # @n
584 # <table border="0">
585 # <tr>
586 # @tp @b CXX @endtp
587 # <td>The default behavior, adding an executable target build from C/C++
588 # source code. The target is added via CMake's add_executable() command.</td>
589 # </tr>
590 # <tr>
591 # @tp <b>PYTHON</b>|<b>JYTHON</b>|<b>PERL</b>|<b>BASH</b> @endtp
592 # <td>Executables written in one of the named scripting languages are built by
593 # configuring and/or copying the script files to the build tree and
594 # installation tree, respectively. During the build step, certain strings
595 # of the form \@VARIABLE\@ are substituted by the values set during the
596 # configure step. How these CMake variables are set is specified by a
597 # so-called script configuration, which itself is either a CMake script
598 # file or a string of CMake code set as value of the @c SCRIPT_DEFINITIONS
599 # property of the executable target.</td>
600 # </tr>
601 # <tr>
602 # @tp @b MATLAB @endtp
603 # <td>Standalone application built from MATLAB sources using the
604 # MATLAB Compiler (mcc). This language option is used when the list
605 # of source files contains one or more *.m files. A custom target is
606 # added which depends on custom command(s) that build the executable.</td>
607 # @n@n
608 # Attention: The *.m file with the entry point/main function of the
609 # executable has to be given before any other *.m file.
610 # </tr>
611 # </table>
612 #
613 # @par Helper functions
614 # If the programming language of the input source files is not specified
615 # explicitly by providing the @p LANGUAGE argument, the extensions of the
616 # source files and if necessary the first line of script files are inspected
617 # by the basis_get_source_language() function. Once the programming language is
618 # known, this function invokes the proper subcommand which adds the respective
619 # build target. In particular, it calls basis_add_executable_target() for C++
620 # sources (.cxx), basis_add_mcc_target() for MATLAB scripts (.m), and
621 # basis_add_script() for all other source files.
622 #
623 # @note DO NOT use the mentioned subcommands directly. Always use
624 # basis_add_executable() to add an executable target to your project.
625 # Only refer to the documentation of the subcommands to learn about the
626 # available options of the particular subcommand and considered target
627 # properties.
628 #
629 # @par Output directories
630 # The built executable file is output to the @c BINARY_RUNTIME_DIR or
631 # @c BINARY_LIBEXEC_DIR if the @p LIBEXEC option is given.
632 # If this function is used within the @c PROJECT_TESTING_DIR, however,
633 # the built executable is output to the @c TESTING_RUNTIME_DIR or
634 # @c TESTING_LIBEXEC_DIR instead.
635 #
636 # @par Installation
637 # An install command for the added executable target is added by this function
638 # as well. The executable will be installed as part of the specified @p COMPONENT
639 # in the directory @c INSTALL_RUNTIME_DIR or @c INSTALL_LIBEXEC_DIR if the option
640 # @p LIBEXEC is given. Executable targets are exported by default such that they
641 # can be imported by other CMake-aware projects by including the CMake
642 # configuration file of this package (&lt;Package&gt;Config.cmake file).
643 # No installation rules are added, however, if this function is used within the
644 # @c PROJECT_TESTING_DIR or if "none" (case-insensitive) is given as
645 # @p DESTINATION. Test executables are further only exported as part of the
646 # build tree, but not the installation as they are by default not installed.
647 #
648 # @param [in] TARGET_NAME Name of the target. If an existing source file is given
649 # as first argument, it is added to the list of source files
650 # and the build target name is derived from the name of this file.
651 # @param [in] ARGN This argument list is parsed and the following
652 # arguments are extracted, all other arguments are passed
653 # on to add_executable() or the respective custom
654 # commands used to add an executable build target.
655 # @par
656 # <table border="0">
657 # <tr>
658 # @tp @b COMPONENT name @endtp
659 # <td>Name of component as part of which this executable will be installed
660 # if the specified @c DESTINATION is not "none".
661 # (default: @c BASIS_RUNTIME_COMPONENT)</td>
662 # </tr>
663 # <tr>
664 # @tp @b DESTINATION dir @endtp
665 # <td>Installation directory relative to @c CMAKE_INSTALL_PREFIX.
666 # If "none" (case-insensitive) is given as argument, no default
667 # installation rules are added for this executable target.
668 # (default: @c INSTALL_RUNTIME_DIR or @c INSTALL_LIBEXEC_DIR
669 # if the @p LIBEXEC option is given)</td>
670 # </tr>
671 # <tr>
672 # @tp @b LANGUAGE lang @endtp
673 # <td>Programming language in which source files are written (case-insensitive).
674 # If not specified, the programming language is derived from the file name
675 # extensions of the source files and, if applicable, the shebang directive
676 # on the first line of the script file. If the programming language could
677 # not be detected automatically, check the file name extensions of the
678 # source files and whether no unrecognized additional arguments were given
679 # or specify the programming language using this option.
680 # (default: auto-detected)</td>
681 # </tr>
682 # <tr>
683 # @tp @b LIBEXEC @endtp
684 # <td>Specifies that the built executable is an auxiliary executable which
685 # is only called by other executables. (default: @c FALSE)</td>
686 # </tr>
687 # <tr>
688 # @tp @b [NO]EXPORT @endtp
689 # <td>Whether to export this target. (default: @c TRUE)</td>
690 # </tr>
691 # <tr>
692 # @tp @b NO_BASIS_UTILITIES @endtp
693 # <td>Specify that the BASIS utilities are not used by this executable and hence
694 # no link dependency on the BASIS utilities shall be added.
695 # (default: @c NOT @c BASIS_UTILITIES)</td>
696 # </tr>
697 # <tr>
698 # @tp @b USE_BASIS_UTILITIES @endtp
699 # <td>Specify that the BASIS utilities are used and required by this executable
700 # and hence a link dependency on the BASIS utilities has to be added.
701 # (default: @c BASIS_UTILITIES)</td>
702 # </tr>
703 # <tr>
704 # @tp @b FINAL @endtp
705 # <td>Finalize custom targets immediately. Any following target property changes
706 # will have no effect. When this option is used, the custom target which
707 # executes the custom build command is added in the current working directory.
708 # Otherwise it will be added in the top-level source directory of the project.
709 # Which with the Visual Studio generators adds the corresponding Visual Studio
710 # Project files directly to the top-level build directory. This can be avoided
711 # using this option or calling basis_finalize_targets() at the end of each
712 # CMakeLists.txt file.</td>
713 # </tr>
714 # </table>
715 #
716 # @returns Adds an executable build target. In case of an executable which is
717 # not build from C++ source files, the function basis_finalize_targets()
718 # has to be invoked to finalize the addition of the custom build target.
719 # This is done by the basis_project_end() macro.
720 #
721 # @sa basis_add_executable_target()
722 # @sa basis_add_script()
723 # @sa basis_add_mcc_target()
724 #
725 # @ingroup CMakeAPI
726 function (basis_add_executable TARGET_NAME)
727  # --------------------------------------------------------------------------
728  # parse arguments
729  CMAKE_PARSE_ARGUMENTS (
730  ARGN
731  "EXECUTABLE;LIBEXEC;NO_BASIS_UTILITIES;USE_BASIS_UTILITIES;EXPORT;NOEXPORT;FINAL"
732  "COMPONENT;DESTINATION;LANGUAGE"
733  ""
734  ${ARGN}
735  )
736  # derive target name from path if existing source path is given as first argument instead
737  # and get list of library source files
738  get_filename_component (S "${TARGET_NAME}" ABSOLUTE)
739  if (IS_DIRECTORY "${S}" AND NOT ARGN_UNPARSED_ARGUMENTS)
740  set (SOURCES "${S}")
741  basis_get_source_target_name (TARGET_NAME "${TARGET_NAME}" NAME_WE)
742  elseif (EXISTS "${S}" AND NOT IS_DIRECTORY "${S}" OR (NOT S MATCHES "\\.in$" AND EXISTS "${S}.in" AND NOT IS_DIRECTORY "${S}.in"))
743  set (SOURCES "${S}")
744  basis_get_source_target_name (TARGET_NAME "${TARGET_NAME}" NAME_WE)
745  else ()
746  set (SOURCES)
747  endif ()
748  if (ARGN_UNPARSED_ARGUMENTS)
749  list (APPEND SOURCES ${ARGN_UNPARSED_ARGUMENTS})
750  endif ()
751  if (NOT SOURCES)
752  message (FATAL_ERROR "basis_add_executable called with only one argument which does however not"
753  " appear to be a file name. Note that the filename extension must be"
754  " included if the target name should be derived from the base filename"
755  " of the source file.")
756  endif ()
757  # --------------------------------------------------------------------------
758  # make target UID
759  basis_check_target_name ("${TARGET_NAME}")
760  basis_make_target_uid (TARGET_UID "${TARGET_NAME}")
761  # --------------------------------------------------------------------------
762  # process globbing expressions to get complete list of source files
763  basis_add_glob_target (${TARGET_UID} SOURCES ${SOURCES})
764  # --------------------------------------------------------------------------
765  # determine programming language
766  _basis_target_source_language ()
767  # --------------------------------------------------------------------------
768  # prepare arguments for subcommand
769  foreach (ARG IN LISTS ARGN_UNPARSED_ARGUMENTS)
770  list (REMOVE_ITEM ARGN "${ARG}")
771  endforeach ()
772  list (APPEND ARGN ${SOURCES})
773  # --------------------------------------------------------------------------
774  # C++
775  if (ARGN_LANGUAGE MATCHES "CXX")
776  basis_add_executable_target (.${TARGET_UID} ${ARGN})
777  # --------------------------------------------------------------------------
778  # MATLAB
779  elseif (ARGN_LANGUAGE MATCHES "MATLAB")
780  if (ARGN_LIBEXEC)
781  list (REMOVE_ITEM ARGN LIBEXEC)
782  basis_add_mcc_target (.${TARGET_UID} LIBEXEC ${ARGN})
783  else ()
784  list (REMOVE_ITEM ARGN EXECUTABLE)
785  basis_add_mcc_target (.${TARGET_UID} EXECUTABLE ${ARGN})
786  endif ()
787  # --------------------------------------------------------------------------
788  # others
789  else ()
790  if (ARGN_LIBEXEC)
791  list (REMOVE_ITEM ARGN LIBEXEC)
792  basis_add_script (.${TARGET_UID} LIBEXEC ${ARGN})
793  else ()
794  list (REMOVE_ITEM ARGN EXECUTABLE)
795  basis_add_script (.${TARGET_UID} EXECUTABLE ${ARGN})
796  endif ()
797  endif ()
798  # --------------------------------------------------------------------------
799  # re-glob source files before each build (if necessary)
800  if (TARGET __${TARGET_UID})
801  if (TARGET _${TARGET_UID})
802  add_dependencies (_${TARGET_UID} __${TARGET_UID})
803  endif ()
804  add_dependencies (${TARGET_UID} __${TARGET_UID})
805  endif ()
806 endfunction ()
807 
808 # ----------------------------------------------------------------------------
809 ## @brief Add library target.
810 #
811 # This is the main function to add a library target to the build system, where
812 # a library can be a binary archive, shared library, a MEX-file or module(s)
813 # written in a scripting language. In general we refer to any output file which
814 # is part of the software (i.e., excluding configuration files), but cannot be
815 # executed (e.g., a binary file in the ELF format) or interpreted
816 # (e.g., a Python module) directly, as library file. Natively, CMake supports only
817 # libraries built from C/C++ source code files. This function extends CMake's
818 # capabilities by adding custom build commands for non-natively supported
819 # programming languages and further standardizes the build of library targets.
820 # For example, by default, it is not necessary to specify installation rules
821 # separately as these are added by this function already (see below).
822 #
823 # @par Programming languages
824 # Besides adding usual library targets built from C/C++ source code files,
825 # this function can also add custom build targets for libraries implemented
826 # in other programming languages. It therefore tries to detect the programming
827 # language of the given source code files and delegates the addition of the
828 # build target to the proper helper functions. It in particular supports the
829 # following languages:
830 # @n
831 # <table border="0">
832 # <tr>
833 # @tp @b CXX @endtp
834 # <td>Source files written in C/C++ are by default built into either
835 # @p STATIC, @p SHARED, or @p MODULE libraries. If the @p MEX option
836 # is given, however, a MEX-file (a shared library) is build using
837 # the MEX script instead of using the default C++ compiler directly.</td>
838 # </tr>
839 # <tr>
840 # @tp <b>PYTHON</b>|<b>JYTHON</b>|<b>PERL</b>|<b>BASH</b> @endtp
841 # <td>Modules written in one of the named scripting languages are built similar
842 # to executable scripts except that the file name extension is preserved
843 # and no executable file permission is set on Unix. These modules are
844 # intended for import/inclusion in other modules or executables written
845 # in the particular scripting language only.</td>
846 # </tr>
847 # <tr>
848 # @tp @b MATLAB @endtp
849 # <td>Libraries of M-files or shared libraries built using the MATLAB Compiler (mcc).
850 # This language option is used when the list of source files contains one or
851 # more *.m files. A custom target is added which depends on custom command(s)
852 # that build the library. If the type of the library is @c SHARED, a shared
853 # library is build using the MATLAB Compiler. Otherwise, the M-files are
854 # configured and installed such that they can be used in MATLAB.</td>
855 # </tr>
856 # </table>
857 #
858 # @par Helper functions
859 # If the programming language of the input source files is not specified
860 # explicitly by providing the @p LANGUAGE argument, the extensions of the
861 # source files are inspected using basis_get_source_language(). Once the
862 # programming language is known, this function invokes the proper subcommand.
863 # In particular, it calls basis_add_library_target() for C++ sources (.cxx)
864 # if the target is not a MEX-file target, basis_add_mex_file() for C++ sources
865 # if the @p MEX option is given, basis_add_mcc_target() for MATLAB scripts (.m),
866 # and basis_add_script_library() for all other source files.
867 #
868 # @note DO NOT use the mentioned subcommands directly. Always use
869 # basis_add_library() to add a library target to your project. Only refer
870 # to the documentation of the subcommands to learn about the available
871 # options of the particular subcommand and the considered target properties.
872 #
873 # @par Output directories
874 # In case of modules written in a scripting language, the libraries are output to
875 # the <tt>BINARY_&lt;LANGUAGE&gt;_LIBRARY_DIR</tt> if defined. Otherwise,
876 # the built libraries are output to the @c BINARY_RUNTIME_DIR, @c BINARY_LIBRARY_DIR,
877 # and/or @c BINARY_ARCHIVE_DIR. If this command is used within the @c PROJECT_TESTING_DIR,
878 # however, the files are output to the corresponding directories in the testing tree,
879 # instead.
880 #
881 # @par Installation
882 # An installation rule for the added library target is added by this function
883 # if the destination is not "none" (case-insensitive). Runtime libraries are
884 # installed as part of the @p RUNTIME_COMPONENT to the @p RUNTIME_DESTINATION.
885 # Library components are installed as part of the @p LIBRARY_COMPONENT to the
886 # @p LIBRARY_DESTINATION. Library targets are further exported such that they
887 # can be imported by other CMake-aware projects by including the CMake
888 # configuration file of this package (&lt;Package&gt;Config.cmake file).
889 # If this function is used within the @c PROJECT_TESTING_DIR, however, no
890 # installation rules are added. Test library targets are further only exported
891 # as part of the build tree.
892 #
893 # @par Example
894 # @code
895 # basis_add_library (MyLib1 STATIC mylib.cxx)
896 # basis_add_library (MyLib2 STATIC mylib.cxx COMPONENT dev)
897 #
898 # basis_add_library (
899 # MyLib3 SHARED mylib.cxx
900 # RUNTIME_COMPONENT bin
901 # LIBRARY_COMPONENT dev
902 # )
903 #
904 # basis_add_library (MyMex MEX mymex.cxx)
905 # basis_add_library (PythonModule MyModule.py.in)
906 # basis_add_library (ShellModule MODULE MyModule.sh.in)
907 # @endcode
908 #
909 # @param [in] TARGET_NAME Name of build target. If an existing file is given as
910 # argument, it is added to the list of source files and
911 # the target name is derived from the name of this file.
912 # @param [in] ARGN This argument list is parsed and the following
913 # arguments are extracted. All unparsed arguments are
914 # treated as source files.
915 # @par
916 # <table border="0">
917 # <tr>
918 # @tp <b>STATIC</b>|<b>SHARED</b>|<b>MODULE</b>|<b>MEX</b> @endtp
919 # <td>Type of the library. (default: @c SHARED for C++ libraries if
920 # @c BUILD_SHARED_LIBS evaluates to true or @c STATIC otherwise,
921 # and @c MODULE in all other cases)</td>
922 # </tr>
923 # <tr>
924 # @tp @b COMPONENT name @endtp
925 # <td>Name of component as part of which this library will be installed
926 # if the @c RUNTIME_DESTINATION or @c LIBRARY_DESTINATION is not "none".
927 # Used only if @p RUNTIME_COMPONENT or @p LIBRARY_COMPONENT not specified.
928 # (default: see @p RUNTIME_COMPONENT and @p LIBRARY_COMPONENT)</td>
929 # </tr>
930 # <tr>
931 # @tp @b DESTINATION dir @endtp
932 # <td>Installation directory for runtime and library component relative
933 # to @c CMAKE_INSTALL_PREFIX. Used only if @p RUNTIME_DESTINATION or
934 # @p LIBRARY_DESTINATION not specified. If "none" (case-insensitive)
935 # is given as argument, no default installation rules are added.
936 # (default: see @p RUNTIME_DESTINATION and @p LIBRARY_DESTINATION)</td>
937 # </tr>
938 # <tr>
939 # @tp @b LANGUAGE lang @endtp
940 # <td>Programming language in which source files are written (case-insensitive).
941 # If not specified, the programming language is derived from the file name
942 # extensions of the source files and, if applicable, the shebang directive
943 # on the first line of the script file. If the programming language could
944 # not be detected automatically, check the file name extensions of the
945 # source files and whether no unrecognized additional arguments were given
946 # or specify the programming language using this option.
947 # (default: auto-detected)</td>
948 # </tr>
949 # <tr>
950 # @tp @b LIBRARY_COMPONENT name @endtp
951 # <td>Name of component as part of which import/static library will be intalled
952 # if @c LIBRARY_DESTINATION is not "none".
953 # (default: @c COMPONENT if specified or @c BASIS_LIBRARY_COMPONENT otherwise)</td>
954 # </tr>
955 # <tr>
956 # @tp @b LIBRARY_DESTINATION dir @endtp
957 # <td>Installation directory of the library component relative to
958 # @c CMAKE_INSTALL_PREFIX. If "none" (case-insensitive) is given as argument,
959 # no installation rule for the library component is added.
960 # (default: @c INSTALL_ARCHIVE_DIR)</td>
961 # </tr>
962 # <tr>
963 # @tp @b RUNTIME_COMPONENT name @endtp
964 # <td>Name of component as part of which runtime library will be installed
965 # if @c RUNTIME_DESTINATION is not "none".
966 # (default: @c COMPONENT if specified or @c BASIS_RUNTIME_COMPONENT otherwise)</td>
967 # </tr>
968 # <tr>
969 # @tp @b RUNTIME_DESTINATION dir @endtp
970 # <td>Installation directory of the runtime component relative to
971 # @c CMAKE_INSTALL_PREFIX. If "none" (case-insensitive) is given as argument,
972 # no installation rule for the runtime library is added.
973 # (default: @c INSTALL_LIBRARY_DIR on Unix or @c INSTALL_RUNTIME_DIR Windows)</td>
974 # </tr>
975 # <tr>
976 # @tp @b [NO]EXPORT @endtp
977 # <td>Whether to export this target. (default: @c TRUE)</td>
978 # </tr>
979 # <tr>
980 # @tp @b NO_BASIS_UTILITIES @endtp
981 # <td>Specify that the BASIS utilities are not used by this executable and hence
982 # no link dependency on the BASIS utilities shall be added.
983 # (default: @c NOT @c BASIS_UTILITIES)</td>
984 # </tr>
985 # <tr>
986 # @tp @b USE_BASIS_UTILITIES @endtp
987 # <td>Specify that the BASIS utilities are used and required by this executable
988 # and hence a link dependency on the BASIS utilities has to be added.
989 # (default: @c BASIS_UTILITIES)</td>
990 # </tr>
991 # <tr>
992 # @tp @b FINAL @endtp
993 # <td>Finalize custom targets immediately. Any following target property changes
994 # will have no effect. When this option is used, the custom target which
995 # executes the custom build command is added in the current working directory.
996 # Otherwise it will be added in the top-level source directory of the project.
997 # Which with the Visual Studio generators adds the corresponding Visual Studio
998 # Project files directly to the top-level build directory. This can be avoided
999 # using this option or calling basis_finalize_targets() at the end of each
1000 # CMakeLists.txt file.</td>
1001 # </tr>
1002 # </table>
1003 #
1004 # @returns Adds a library build target. In case of a library not written in C++
1005 # or MEX-file targets, basis_finalize_targets() has to be invoked
1006 # to finalize the addition of the build target(s). This is done
1007 # by the basis_project_end() macro.
1008 #
1009 # @sa basis_add_library_target()
1010 # @sa basis_add_script_library()
1011 # @sa basis_add_mex_file()
1012 # @sa basis_add_mcc_target()
1013 #
1014 # @ingroup CMakeAPI
1015 function (basis_add_library TARGET_NAME)
1016  # --------------------------------------------------------------------------
1017  # parse arguments
1018  CMAKE_PARSE_ARGUMENTS (
1019  ARGN
1020  "STATIC;SHARED;MODULE;MEX;USE_BASIS_UTILITIES;NO_BASIS_UTILITIES;EXPORT;NOEXPORT;FINAL"
1021  "COMPONENT;RUNTIME_COMPONENT;LIBRARY_COMPONENT;DESTINATION;RUNTIME_DESTINATION;LIBRARY_DESTINATION;LANGUAGE"
1022  ""
1023  ${ARGN}
1024  )
1025  # derive target name from path if existing source path is given as first argument instead
1026  # and get list of library source files
1027  get_filename_component (S "${TARGET_NAME}" ABSOLUTE)
1028  if (IS_DIRECTORY "${S}" AND NOT ARGN_UNPARSED_ARGUMENTS)
1029  set (SOURCES "${S}")
1030  basis_get_source_target_name (TARGET_NAME "${TARGET_NAME}" NAME)
1031  elseif (EXISTS "${S}" AND NOT IS_DIRECTORY "${S}" OR (NOT S MATCHES "\\.in$" AND EXISTS "${S}.in" AND NOT IS_DIRECTORY "${S}.in"))
1032  set (SOURCES "${S}")
1033  if (ARGN_MEX)
1034  basis_get_source_target_name (TARGET_NAME "${TARGET_NAME}" NAME_WE)
1035  else ()
1036  _basis_target_source_language ()
1037  if ("$${ARGN_LANGUAGE}" STREQUAL "$CXX")
1038  basis_get_source_target_name (TARGET_NAME "${TARGET_NAME}" NAME_WE)
1039  else ()
1040  basis_get_source_target_name (TARGET_NAME "${TARGET_NAME}" NAME)
1041  endif ()
1042  endif ()
1043  else ()
1044  set (SOURCES)
1045  endif ()
1046  if (ARGN_UNPARSED_ARGUMENTS)
1047  list (APPEND SOURCES ${ARGN_UNPARSED_ARGUMENTS})
1048  endif ()
1049  # --------------------------------------------------------------------------
1050  # make target UID
1051  basis_check_target_name ("${TARGET_NAME}")
1052  basis_make_target_uid (TARGET_UID "${TARGET_NAME}")
1053  # --------------------------------------------------------------------------
1054  # process globbing expressions to get complete list of source files
1055  basis_add_glob_target (${TARGET_UID} SOURCES ${SOURCES})
1056  # --------------------------------------------------------------------------
1057  # determine programming language
1058  _basis_target_source_language ()
1059  # --------------------------------------------------------------------------
1060  # prepare arguments for subcommand
1061  foreach (ARG IN LISTS ARGN_UNPARSED_ARGUMENTS)
1062  list (REMOVE_ITEM ARGN "${ARG}")
1063  endforeach ()
1064  list (APPEND ARGN ${SOURCES})
1065  # --------------------------------------------------------------------------
1066  # C++
1067  if (ARGN_LANGUAGE MATCHES "CXX")
1068  # MEX-file
1069  if (ARGN_MEX)
1070  if (ARGN_STATIC)
1071  message (FATAL_ERROR "Target ${TARGET_UID}: Invalid library type! Only modules or shared libraries can be built by the MEX script.")
1072  endif ()
1073  list (REMOVE_ITEM ARGN MODULE)
1074  list (REMOVE_ITEM ARGN SHARED)
1075  list (REMOVE_ITEM ARGN MEX)
1076  basis_add_mex_file (.${TARGET_UID} ${ARGN})
1077  # library
1078  else ()
1079  basis_add_library_target (.${TARGET_UID} ${ARGN})
1080  endif ()
1081  # --------------------------------------------------------------------------
1082  # MATLAB
1083  elseif (ARGN_LANGUAGE MATCHES "MATLAB")
1084  if (ARGN_STATIC OR ARGN_MEX)
1085  message (FATAL_ERROR "Target ${TARGET_UID}: Invalid library type! Only shared libraries can be built by the MATLAB Compiler.")
1086  endif ()
1087  if (ARGN_SHARED)
1088  list (REMOVE_ITEM ARGN SHARED)
1089  basis_add_mcc_target (.${TARGET_UID} SHARED ${ARGN})
1090  else ()
1091  list (REMOVE_ITEM ARGN MODULE) # optional
1092  basis_add_script_library (.${TARGET_UID} ${ARGN})
1093  endif ()
1094  # --------------------------------------------------------------------------
1095  # other
1096  else ()
1097  if (ARGN_STATIC OR ARGN_SHARED OR ARGN_MEX)
1098  message (FATAL_ERROR "Target ${TARGET_UID}: Invalid library type! Only modules can be built from scripts.")
1099  endif ()
1100  list (REMOVE_ITEM ARGN MODULE)
1101  basis_add_script_library (.${TARGET_UID} ${ARGN})
1102  endif ()
1103  # --------------------------------------------------------------------------
1104  # re-glob source files before each build (if necessary)
1105  if (TARGET __${TARGET_UID})
1106  if (TARGET _${TARGET_UID})
1107  add_dependencies (_${TARGET_UID} __${TARGET_UID})
1108  endif ()
1109  add_dependencies (${TARGET_UID} __${TARGET_UID})
1110  endif ()
1111 endfunction ()
1112 
1113 # ----------------------------------------------------------------------------
1114 ## @brief Add single arbitrary or executable script.
1115 #
1116 # @note This function should not be used directly for executable scripts or
1117 # module libraries. Use basis_add_executable() or basis_add_library()
1118 # in such (most) cases instead.
1119 #
1120 # This function can be used to add a single arbitrary script file (i.e., any
1121 # text file which is input to a program), such as a CTest script for example,
1122 # to the build if neither basis_add_executable() nor basis_add_library() are
1123 # appropriate choices. In all other cases, either basis_add_executable() or
1124 # basis_add_library() should be used. Note that the script file is by default
1125 # not considered to be an executable. Instead it is assumed that the program
1126 # which interprets/processes the script must be executed explicitly with this
1127 # script as argument. Only scripts built with the @p EXECUTABLE or @p LIBEXEC
1128 # type option are treated as executable files, where in case of Unix a shebang
1129 # directive implicitly states the program used by the shell to interpret the
1130 # script and on Windows a Windows Command which imitates the behavior of Unix
1131 # shells is generated by BASIS. Do not use these type options, however, but
1132 # only use the default @p MODULE option. The basis_add_executable() function
1133 # should be used instead to add an executable script. The basis_add_script()
1134 # function shall only be used for none-executable arbitrary script files which
1135 # cannot be built by basis_add_executable() or basis_add_library().
1136 #
1137 # If the script name ends in <tt>.in</tt>, the <tt>.in</tt> suffix is removed
1138 # from the output name. Further, in case of executable scripts, the file name
1139 # extension is removed from the output file name. Instead, a shebang directive
1140 # is added on Unix to the built script. In order to enable the convenient
1141 # execution of Python and Perl scripts also on Windows without requiring the
1142 # user to setup a proper associate between the filename extension with the
1143 # corresponding interpreter executable, a few lines of Batch code are added at
1144 # the top and bottom of executable Python and Perl scripts. This Batch code
1145 # invokes the configured interpreter with the script file and the given script
1146 # arguments as command-line arguments. Note that both the original script source
1147 # code and the Batch code are stored within the single file. The file name
1148 # extension of such modified scripts is by default set to <tt>.cmd</tt>, the
1149 # common extension for Windows NT Command Scripts. Scripts in other languages
1150 # are not modified and the extension of the original scripts script file is
1151 # preserved on Windows in this case. In case of non-executable scripts, the
1152 # file name extension is kept in any case.
1153 #
1154 # Certain CMake variables within the source file are replaced during the
1155 # built of the script. See the
1156 # <a href="https://cmake-basis.github.io/scripttargets/>
1157 # Build System Standard</a> for details.
1158 # Note, however, that source files are only configured if the file name
1159 # ends in the <tt>.in</tt> suffix.
1160 #
1161 # A custom CMake build target with the following properties is added by this
1162 # function to the build system. These properties are used by basis_build_script()
1163 # to generate a build script written in CMake code which is executed by a custom
1164 # CMake command. Before the invokation of basis_build_script(), the target
1165 # properties can be modified using basis_set_target_properties().
1166 #
1167 # @note Custom BASIS build targets are finalized by BASIS using basis_project_end(),
1168 # i.e., the end of the root CMake configuration file of the (sub-)project.
1169 #
1170 # @par Properties on script targets
1171 # <table border=0>
1172 # <tr>
1173 # @tp @b BASIS_TYPE @endtp
1174 # <td>Read-only property with value "SCRIPT_FILE" for arbitrary scripts,
1175 # "SCRIPT_EXECUTABLE" for executable scripts, and "SCRIPT_LIBEXEC" for
1176 # auxiliary executable scripts.
1177 # (default: see @p MODULE, @p EXECUTABLE, @p LIBEXEC options)</td>
1178 # </tr>
1179 # <tr>
1180 # @tp @b BASIS_UTILITIES @endtp
1181 # <td>Whether the BASIS utilities are used by this script. For the supported
1182 # scripting languages for which BASIS utilities are implemented, BASIS
1183 # will in most cases automatically detect whether these utilities are
1184 # used by a script or not. Otherwise, set this property manually or use
1185 # either the @p USE_BASIS_UTILITIES or the @p NO_BASIS_UTILITIES option
1186 # when adding the script target. (default: auto-detected or @c UNKNOWN)</td>
1187 # </tr>
1188 # <tr>
1189 # @tp @b BINARY_DIRECTORY @endtp
1190 # <td>Build tree directory of this target. (default: @c CMAKE_CURRENT_BINARY_DIR)</td>
1191 # </tr>
1192 # <tr>
1193 # @tp @b COMPILE @endtp
1194 # <td>Whether to compile the script if the programming language allows such
1195 # pre-compilation as in case of Python, for example. If @c TRUE, only the
1196 # compiled file is installed. (default: @c BASIS_COMPILE_SCRIPTS)</td>
1197 # </tr>
1198 # <tr>
1199 # @tp @b SCRIPT_DEFINITIONS @endtp
1200 # <td>CMake code which is evaluated after the inclusion of the default script
1201 # configuration files. This code can be used to set the replacement text of the
1202 # CMake variables ("@VAR@" patterns) used in the source file.
1203 # See <a href="https://cmake-basis.github.io/standard/scripttargets.html#script-configuration">
1204 # Build System Standard</a> for details. (default: "")</td>
1205 # </tr>
1206 # <tr>
1207 # @tp @b SCRIPT_DEFINITIONS_FILE @endtp
1208 # <td>CMake script file with compile definitions, also referred to as script
1209 # configuration file. The named files are included after the default BASIS
1210 # script configuration and before the @c SCRIPT_DEFINITIONS code is being
1211 # evaluated. (default: @c BINARY_CONFIG_DIR/ScriptConfig.cmake)</td>
1212 # </tr>
1213 # <tr>
1214 # @tp @b COMPONENT @endtp
1215 # <td>Name of component as part of which this script is installed if
1216 # @c INSTALL_DIRECTORY is not set to "none".
1217 # (default: see @p COMPONENT argument)</td>
1218 # </tr>
1219 # <tr>
1220 # @tp @b EXPORT @endtp
1221 # <td>Whether to export this build target in which case an import library
1222 # target is added to the custom exports file with the path to the
1223 # built/installed script set as @c IMPORT_LOCATION. (default: @c TRUE)</td>
1224 # </tr>
1225 # <tr>
1226 # @tp @b INSTALL_DIRECTORY @endtp
1227 # <td>Installation directory of script file configured for use in installation tree
1228 # relative to @c CMAKE_INSTALL_PREFIX. Set to "none" (case-insensitive) to skip the
1229 # addition of an installation rule. (default: see @p DESTINATION argument)</td>
1230 # </tr>
1231 # <tr>
1232 # @tp @b LANGUAGE @endtp
1233 # <td>Read-only property of programming language of script file in uppercase letters.
1234 # (default: see @p LANGUAGE argument)</td>
1235 # </tr>
1236 # <tr>
1237 # @tp @b LINK_DEPENDS @endtp
1238 # <td>Paths or target names of script modules and libraries used by this script.
1239 # In case of an (auxiliary) executable script, the directories of these modules
1240 # are added to the search path for modules of the given programming language
1241 # if such search paths are supported by the language and BASIS knows how to set
1242 # these (as in case of Python/Jython, Perl, and MATLAB, in particular).
1243 # Moreover, for each listed build target a dependency is added between this
1244 # script target and the named build targets. Use basis_target_link_libraries()
1245 # to add additional link dependencies.
1246 # (default: BASIS utilities module if used or empty list otherwise)</td>
1247 # </tr>
1248 # <tr>
1249 # @tp @b OUTPUT_DIRECTORY @endtp
1250 # <td>Output directory for built script file configured for use in build tree.
1251 # (default: @c BINARY_LIBRARY_DIR for arbitrary scripts, @c BINARY_RUNTIME_DIR
1252 # for executable scripts, and @c BINARY_LIBEXEC_DIR for auxiliary executables)</td>
1253 # </tr>
1254 # <tr>
1255 # @tp @b OUTPUT_NAME @endtp
1256 # <td>Name of built script file including file name extension (if any).
1257 # (default: basename of script file for arbitrary scripts, without extension
1258 # for executable scripts on Unix, and <tt>.cmd</tt> extension on Windows
1259 # in case of executable Python/Jython or Perl script)</td>
1260 # </tr>
1261 # <tr>
1262 # @tp @b SOURCE_DIRECTORY @endtp
1263 # <td>Source directory of this target. (default: @c CMAKE_CURRENT_SOURCE_DIR)</td>
1264 # </tr>
1265 # <tr>
1266 # @tp @b SOURCES @endtp
1267 # <td>Read-only property which lists the source file of this script target.
1268 # Note that the first element in this list actually names a directory
1269 # in the build, the one where the build script for this target is located
1270 # instead of a source file and thus should be ignored. The second entry
1271 # corresponds to the source file of this script target.</td>
1272 # </tr>
1273 # </table>
1274 #
1275 # @attention Properties documented as read-only must not be modified.
1276 #
1277 # @note If this function is used within the @c PROJECT_TESTING_DIR, the built
1278 # executable is output to the @c BINARY_TESTING_DIR directory tree instead.
1279 # Moreover, no installation rules are added. Test executables are further
1280 # not exported, regardless of the @c EXPORT property.
1281 #
1282 # @param [in] TARGET_NAME Name of build target. If an existing file is given as
1283 # argument, it is added to the list of source files and
1284 # the target name is derived from the name of this file.
1285 # @param [in] ARGN The remaining arguments are parsed and the following arguments
1286 # recognized. All unparsed arguments are treated as source files,
1287 # where in particular exactly one source file is required if the
1288 # @p TARGET_NAME argument does not name an existing source file.
1289 # @par
1290 # <table border=0>
1291 # <tr>
1292 # @tp <b>MODULE</b>|<b>EXECUTABLE</b>|<b>LIBEXEC</b> @endtp
1293 # <td>Type of script to built, i.e., either arbitrary module script which
1294 # cannot be executed directly, an executable script with proper shebang
1295 # directive and execute permissions on Unix or Windows Command on Windows,
1296 # or an auxiliary executable. The type of the script mainly changes the
1297 # default values of the target properties such as the output and installation
1298 # directories. To add an (auxiliary) executable script, use
1299 # basis_add_executable(), however, instead of this function.
1300 # The @c EXECUTABLE and @c LIBEXEC options are only intended for
1301 # internal use by BASIS. (default: MODULE)</td>
1302 # </tr>
1303 # <tr>
1304 # @tp @b COMPONENT name @endtp
1305 # <td>Name of installation component as part of which this script is being
1306 # installed if the @c INSTALL_DIRECTORY property is not "none".
1307 # (default: @c BASIS_LIBRARY_COMPONENT for arbitrary scripts or
1308 # @c BASIS_RUNTIME_COMPONENT for executable scripts)</td>
1309 # </tr>
1310 # <tr>
1311 # @tp @b DESTINATION dir @endtp
1312 # <td>Installation directory for script file relative to @c CMAKE_INSTALL_PREFIX.
1313 # If an absolute path is given as argument, it is made relative to the
1314 # configured installation prefix.
1315 # (default: @c INSTALL_LIBRARY_DIR for arbitrary scripts,
1316 # @c INSTALL_RUNTIME_DIR for executable scripts, and @c INSTALL_LIBEXEC_DIR
1317 # for auxiliary executable scripts)</td>
1318 # </tr>
1319 # <tr>
1320 # @tp @b LANGUAGE lang @endtp
1321 # <td>Programming language in which script file is written (case-insensitive).
1322 # If not specified, the programming language is derived from the file name
1323 # extension of the source file and the shebang directive on the first line
1324 # of the script if any. If the programming language could not be detected
1325 # automatically, the @c LANGUAGE property is set to @c UNKNOWN. Note that
1326 # for arbitrary script targets, the script file will still be built correctly
1327 # even if the scripting language was not recognized. The automatic detection
1328 # whether the BASIS utilities are used and required will fail, however.
1329 # In this case, specify the programming language using this option.
1330 # (default: auto-detected or @c UNKNOWN)</td>
1331 # </tr>
1332 # <tr>
1333 # @tp @b [NO]EXPORT @endtp
1334 # <td>Whether to export this target. (default: @c TRUE)</td>
1335 # </tr>
1336 # <tr>
1337 # @tp @b NO_BASIS_UTILITIES @endtp
1338 # <td>Specify that the BASIS utilities are not used by this script. If the
1339 # programming language of the script is known and BASIS utilities are
1340 # available for this language, BASIS will in most cases automatically
1341 # detect whether these utilities are used by a script or not. Use this
1342 # option to skip this check because the script does not make use of the
1343 # BASIS utilities.</td>
1344 # </tr>
1345 # <tr>
1346 # @tp @b USE_BASIS_UTILITIES @endtp
1347 # <td>Specify that the BASIS utilities are used and thus required by this script.
1348 # If the programming language of the script is known and BASIS utilities are
1349 # available for this language, BASIS will in most cases automatically
1350 # detect whether these utilities are used by a script or not. Use this option
1351 # to skip this check because it is already known that the script makes use of
1352 # the BASIS utilities. Note that an error is raised if this option is given,
1353 # but no BASIS utilities are available for the programming language of this
1354 # script or if the programming language is unknown, respectively, not detected
1355 # correctly. In this case, consider the use of the @p LANGUAGE argument.</td>
1356 # </tr>
1357 # <tr>
1358 # @tp @b FINAL @endtp
1359 # <td>Finalize custom targets immediately. Any following target property changes
1360 # will have no effect. When this option is used, the custom target which
1361 # executes the custom build command is added in the current working directory.
1362 # Otherwise it will be added in the top-level source directory of the project.
1363 # Which with the Visual Studio generators adds the corresponding Visual Studio
1364 # Project files directly to the top-level build directory. This can be avoided
1365 # using this option or calling basis_finalize_targets() at the end of each
1366 # CMakeLists.txt file.</td>
1367 # </tr>
1368 # </table>
1369 #
1370 # @returns Adds a custom CMake target with the documented properties. The actual custom
1371 # command to build the script is added by basis_build_script().
1372 #
1373 # @ingroup CMakeAPI
1374 function (basis_add_script TARGET_NAME)
1375  # parse arguments
1376  CMAKE_PARSE_ARGUMENTS (
1377  ARGN
1378  "MODULE;EXECUTABLE;LIBEXEC;NO_BASIS_UTILITIES;USE_BASIS_UTILITIES;EXPORT;NOEXPORT;FINAL"
1379  "COMPONENT;DESTINATION;LANGUAGE"
1380  ""
1381  ${ARGN}
1382  )
1383  if (NOT ARGN_MODULE AND NOT ARGN_EXECUTABLE AND NOT ARGN_LIBEXEC)
1384  set (ARGN_MODULE TRUE)
1385  endif ()
1386  if (ARGN_MODULE)
1387  set (TYPE MODULE)
1388  else ()
1389  set (TYPE EXECUTABLE)
1390  endif ()
1391  string (TOLOWER "${TYPE}" type)
1392  # derive target name from file name if existing source file given as first argument
1393  get_filename_component (S "${TARGET_NAME}" ABSOLUTE)
1394  if (EXISTS "${S}" AND NOT IS_DIRECTORY "${S}" OR (NOT S MATCHES "\\.in$" AND EXISTS "${S}.in" AND NOT IS_DIRECTORY "${S}.in"))
1395  set (SOURCES "${S}")
1396  if (ARGN_MODULE)
1397  basis_get_source_target_name (TARGET_NAME "${TARGET_NAME}" NAME)
1398  else ()
1399  basis_get_source_target_name (TARGET_NAME "${TARGET_NAME}" NAME_WE)
1400  endif ()
1401  set (SET_OUTPUT_NAME_TO_TARGET_NAMEE FALSE)
1402  else ()
1403  set (SOURCES)
1404  set (SET_OUTPUT_NAME_TO_TARGET_NAME TRUE)
1405  endif ()
1406  # check target name
1407  basis_check_target_name ("${TARGET_NAME}")
1408  basis_make_target_uid (TARGET_UID "${TARGET_NAME}")
1409  message (STATUS "Adding ${type} script ${TARGET_UID}...")
1410  if (ARGN_MODULE AND TYPE MATCHES "EXECUTABLE")
1411  message (FATAL_ERROR "Target ${TARGET_UID}: MODULE and EXECUTABLE or LIBEXEC options are mutually exclusive!")
1412  endif ()
1413  # check/set parsed arguments
1414  basis_set_flag (ARGN EXPORT ${BASIS_EXPORT_DEFAULT})
1415  if (ARGN_USE_BASIS_UTILITIES AND ARGN_NO_BASIS_UTILITIES)
1416  message (FATAL_ERROR "Options USE_BASIS_UTILITIES and NO_BASIS_UTILITIES are mutually exclusive!")
1417  endif ()
1418  list (LENGTH ARGN_UNPARSED_ARGUMENTS N)
1419  if (SOURCES)
1420  math (EXPR N "${N} + 1")
1421  endif ()
1422  if (N GREATER 1)
1423  if (NOT SOURCES)
1424  list (REMOVE_AT ARGN_UNPARSED_ARGUMENTS 0)
1425  endif ()
1426  message (FATAL_ERROR "Target ${TARGET_UID}: Too many or unrecognized arguments: ${ARGN_UNPARSED_ARGUMENTS}!\n"
1427  " Only one script can be built by each script target.")
1428  elseif (NOT SOURCES)
1429  set (SOURCES "${ARGN_UNPARSED_ARGUMENTS}")
1430  get_filename_component (SOURCES "${SOURCES}" ABSOLUTE)
1431  endif ()
1432  if (NOT EXISTS "${SOURCES}" AND NOT SOURCES MATCHES "\\.in$" AND EXISTS "${SOURCES}.in")
1433  set (SOURCES "${SOURCES}.in")
1434  endif ()
1435  if (NOT EXISTS "${SOURCES}")
1436  string (REGEX REPLACE "\\.in$" "" SOURCES "${SOURCES}")
1437  message (FATAL_ERROR "Target ${TARGET_UID}: Source file ${SOURCES}[.in] does not exist!")
1438  endif ()
1439  # add custom target
1440  add_custom_target (${TARGET_UID} ALL SOURCES ${SOURCES})
1441  # dump CMake variables for configuration of script
1442  set (BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TARGET_UID}")
1443  basis_dump_variables ("${BUILD_DIR}.dir/cache.cmake.tmp")
1444  # auto-detect programming language (may be as well UNKNOWN)
1445  if (ARGN_LANGUAGE)
1446  string (TOUPPER "${ARGN_LANGUAGE}" ARGN_LANGUAGE)
1447  else ()
1448  basis_get_source_language (ARGN_LANGUAGE ${SOURCES})
1449  endif ()
1450  # IS_TEST flag
1451  basis_sanitize_for_regex (RE "${PROJECT_TESTING_DIR}")
1452  if (CMAKE_CURRENT_SOURCE_DIR MATCHES "^${RE}")
1453  set (IS_TEST TRUE)
1454  else ()
1455  set (IS_TEST FALSE)
1456  endif ()
1457  # default directory infix used below
1458  if (ARGN_MODULE)
1459  set (TYPE_INFIX "LIBRARY")
1460  elseif (ARGN_LIBEXEC)
1461  set (TYPE_INFIX "LIBEXEC")
1462  else ()
1463  set (TYPE_INFIX "RUNTIME")
1464  endif ()
1465  # output name
1466  string (REGEX REPLACE "\\.in$" "" SOURCE_NAME "${SOURCES}")
1467  if (SET_OUTPUT_NAME_TO_TARGET_NAME)
1468  basis_get_target_name (OUTPUT_NAME ${TARGET_UID})
1469  else ()
1470  get_filename_component (OUTPUT_NAME "${SOURCE_NAME}" NAME_WE)
1471  endif ()
1472  if (ARGN_MODULE)
1473  get_filename_component (SUFFIX "${SOURCE_NAME}" EXT)
1474  else ()
1475  if (WIN32)
1476  if (ARGN_LANGUAGE MATCHES "[JP]YTHON|PERL")
1477  set (SUFFIX ".cmd")
1478  else ()
1479  get_filename_component (SUFFIX "${SOURCE_NAME}" EXT)
1480  endif ()
1481  else ()
1482  set (SUFFIX)
1483  endif ()
1484  endif ()
1485  # output directory
1486  if (IS_TEST)
1487  set (OUTPUT_DIRECTORY "${TESTING_${TYPE_INFIX}_DIR}")
1488  else ()
1489  set (OUTPUT_DIRECTORY "${BINARY_${TYPE_INFIX}_DIR}")
1490  endif ()
1491  # installation component
1492  if (NOT ARGN_COMPONENT)
1493  if (ARGN_MODULE)
1494  set (ARGN_COMPONENT "${BASIS_LIBRARY_COMPONENT}")
1495  else ()
1496  set (ARGN_COMPONENT "${BASIS_RUNTIME_COMPONENT}")
1497  endif ()
1498  endif ()
1499  if (NOT ARGN_COMPONENT)
1500  set (ARGN_COMPONENT "Unspecified")
1501  endif ()
1502  # installation directory
1503  if (ARGN_DESTINATION)
1504  if (ARGN_DESTINATION MATCHES "^[nN][oO][nN][eE]$")
1505  set (ARGN_DESTINATION)
1506  elseif (IS_ABSOLUTE "${ARGN_DESTINATION}")
1507  file (RELATIVE_PATH ARGN_DESTINATION "${CMAKE_INSTALL_PREFIX}" "${ARGN_DESTINATION}")
1508  endif ()
1509  elseif (IS_TEST)
1510  set (ARGN_DESTINATION) # do not install
1511  else ()
1512  set (ARGN_DESTINATION "${INSTALL_${TYPE_INFIX}_DIR}")
1513  endif ()
1514  # script configuration ("compile definitions")
1515  if (EXISTS "${BINARY_CONFIG_DIR}/ScriptConfig.cmake")
1516  set (CONFIG_FILE "${BINARY_CONFIG_DIR}/ScriptConfig.cmake")
1517  else ()
1518  set (CONFIG_FILE)
1519  endif ()
1520  # auto-detect use of BASIS utilities
1521  set (LINK_DEPENDS)
1522  if (ARGN_LANGUAGE MATCHES "[JP]YTHON")
1523  set (UTILITIES_LANGUAGE "PYTHON")
1524  else ()
1525  set (UTILITIES_LANGUAGE "${ARGN_LANGUAGE}")
1526  endif ()
1527  if (ARGN_USE_BASIS_UTILITIES)
1528  if (NOT BASIS_UTILITIES_ENABLED MATCHES "${UTILITIES_LANGUAGE}")
1529  message (FATAL_ERROR "Target ${TARGET_UID} requires the BASIS utilities for ${UTILITIES_LANGUAGE}"
1530  " but BASIS was either build without the build of these utilities enabled"
1531  " or no utilities for this programming language are implemented. Remove the"
1532  " USE_BASIS_UTILITIES option if no BASIS utilities are used by the script"
1533  " ${SOURCES} or specify the correct programming language if it was not"
1534  " detected correctly.")
1535  endif ()
1536  set (USES_BASIS_UTILITIES TRUE)
1537  elseif (NOT ARGN_NO_BASIS_UTILITIES AND NOT UTILITIES_LANGUAGE MATCHES "UNKNOWN")
1538  basis_utilities_check (USES_BASIS_UTILITIES ${SOURCES} ${UTILITIES_LANGUAGE})
1539  else ()
1540  set (USES_BASIS_UTILITIES FALSE)
1541  endif ()
1542  if (USES_BASIS_UTILITIES)
1543  basis_set_project_property (PROPERTY PROJECT_USES_${UTILITIES_LANGUAGE}_UTILITIES TRUE)
1544  if (BASIS_DEBUG)
1545  message ("** Target ${TARGET_UID} uses the BASIS utilities for ${UTILITIES_LANGUAGE}.")
1546  endif ()
1547  endif ()
1548  # set properties of custom build target
1550  ${TARGET_UID}
1551  PROPERTIES
1552  LANGUAGE ${ARGN_LANGUAGE}
1553  BASIS_TYPE SCRIPT_${TYPE}
1554  BASIS_UTILITIES ${USES_BASIS_UTILITIES}
1555  BUILD_DIRECTORY "${BUILD_DIR}"
1556  SOURCE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
1557  BINARY_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
1558  OUTPUT_DIRECTORY "${OUTPUT_DIRECTORY}"
1559  INSTALL_DIRECTORY "${ARGN_DESTINATION}"
1560  COMPONENT "${ARGN_COMPONENT}"
1561  OUTPUT_NAME "${OUTPUT_NAME}"
1562  PREFIX ""
1563  SUFFIX "${SUFFIX}"
1564  SCRIPT_DEFINITIONS ""
1565  SCRIPT_DEFINITIONS_FILE "${CONFIG_FILE}"
1566  LINK_DEPENDS "${LINK_DEPENDS}"
1567  EXPORT ${EXPORT}
1568  COMPILE ${BASIS_COMPILE_SCRIPTS}
1569  TEST ${IS_TEST}
1570  LIBEXEC ${ARGN_LIBEXEC}
1571  )
1572  # finalize target
1573  if (ARGN_FINAL)
1574  basis_finalize_targets (${TARGET_UID})
1575  endif ()
1576  # add target to list of targets
1577  basis_set_project_property (APPEND PROPERTY TARGETS "${TARGET_UID}")
1578  message (STATUS "Adding ${type} script ${TARGET_UID}... - done")
1579 endfunction ()
1580 
1581 # ----------------------------------------------------------------------------
1582 ## @brief Finalize custom targets by adding the missing build commands.
1583 #
1584 # This function is called by basis_project_end() in order to finalize the
1585 # addition of the custom build targets such as, for example, build targets
1586 # for the build of executable scripts, Python packages, MATLAB Compiler
1587 # executables and shared libraries, and MEX-files. It can, however, also
1588 # be called explicitly either at the end of each CMakeLists.txt file that
1589 # adds new build targets or with the name of the target(s) to finalize in
1590 # some of the CMakeLists.txt files. This is to ensure that the custom target
1591 # which executes the actual build command is added in the same directory as
1592 # the original custom target with the respective target properties.
1593 #
1594 # @param[in] ARGN List of targets to finalize. If none specified, all custom
1595 # targets that were added before and are not finalized already
1596 # will be finalized using the current binary directory.
1597 #
1598 # @returns Generates the CMake build scripts and adds custom build commands
1599 # and corresponding targets for the execution of these scripts.
1600 #
1601 # @sa basis_build_script()
1602 # @sa basis_build_script_library()
1603 # @sa basis_build_mcc_target()
1604 # @sa basis_build_mex_file()
1605 function (basis_finalize_targets)
1606  if (ARGN)
1607  set (TARGETS)
1608  foreach (TARGET_NAME ${ARGN})
1609  basis_get_target_uid (TARGET_UID ${TARGET_NAME})
1610  list (APPEND TARGETS ${TARGET_UID})
1611  endforeach ()
1612  else ()
1613  basis_get_project_property (TARGETS PROPERTY TARGETS)
1614  if (NOT TARGETS)
1615  return()
1616  endif ()
1617  # targets of BASIS utilities are finalized separately
1618  # because some properties still have to be set by
1619  # basis_configure_utilities, see UtilitiesTools module
1620  basis_make_target_uid (TARGET_UID_basis_sh basis_sh)
1621  basis_make_target_uid (TARGET_UID_basis_py basis_py)
1622  basis_make_target_uid (TARGET_UID_Basis_pm Basis_pm)
1623  list (REMOVE_ITEM TARGETS
1624  ${TARGET_UID_basis_sh}
1625  ${TARGET_UID_basis_py}
1626  ${TARGET_UID_Basis_pm}
1627  )
1628  endif ()
1629  basis_get_project_property (FINALIZED_TARGETS PROPERTY FINALIZED_TARGETS)
1630  if (FINALIZED_TARGETS)
1631  list (REMOVE_ITEM TARGETS ${FINALIZED_TARGETS})
1632  endif ()
1633  if (BASIS_DEBUG)
1634  message (
1635  "** basis_finalize_targets:"
1636  "\n TARGETS: [${TARGETS}]"
1637  "\n FINALIZED: [${FINALIZED_TARGETS}]"
1638  )
1639  endif ()
1640  foreach (TARGET_UID ${TARGETS})
1641  get_target_property (BASIS_TYPE ${TARGET_UID} BASIS_TYPE)
1642  if (BASIS_TYPE MATCHES "^EXECUTABLE$|^(SHARED|MODULE)_LIBRARY$")
1643  if (BASIS_INSTALL_RPATH AND NOT CMAKE_SKIP_RPATH)
1644  # Only if BASIS is allowed to take care of the INSTALL_RPATH property
1645  # and the use of this property was not disabled by the project
1646  basis_set_target_install_rpath (${TARGET_UID})
1647  endif ()
1648  elseif (BASIS_TYPE MATCHES "SCRIPT_LIBRARY")
1649  basis_build_script_library (${TARGET_UID})
1650  elseif (BASIS_TYPE MATCHES "SCRIPT")
1651  basis_build_script (${TARGET_UID})
1652  elseif (BASIS_TYPE MATCHES "MEX")
1653  basis_build_mex_file (${TARGET_UID})
1654  elseif (BASIS_TYPE MATCHES "MCC")
1655  basis_build_mcc_target (${TARGET_UID})
1656  endif ()
1657  list (APPEND FINALIZED_TARGETS ${TARGET_UID})
1658  endforeach ()
1659  basis_set_project_property (PROPERTY FINALIZED_TARGETS ${FINALIZED_TARGETS})
1660 endfunction ()
1661 
1662 # ============================================================================
1663 # internal helpers
1664 # ============================================================================
1665 
1666 # ----------------------------------------------------------------------------
1667 ## @brief Add executable target.
1668 #
1669 # This BASIS function overwrites CMake's
1670 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_executable">
1671 # add_executable()</a> command in order to store information of imported targets
1672 # which is in particular used to generate the source code of the ExecutableTargetInfo
1673 # modules which are part of the BASIS utilities.
1674 #
1675 # @note Use basis_add_executable() instead where possible!
1676 #
1677 # @param [in] TARGET_UID Name of the target.
1678 # @param [in] ARGN Further arguments of CMake's add_executable().
1679 #
1680 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_executable
1681 function (add_executable TARGET_UID)
1682  _add_executable (${TARGET_UID} ${ARGN})
1683  list (FIND ARGN IMPORTED IDX)
1684  if (IDX EQUAL 0)
1686  basis_add_imported_target ("${TARGET_UID}" EXECUTABLE)
1687  endif ()
1688  else ()
1689  basis_set_project_property (APPEND PROPERTY TARGETS "${TARGET_UID}")
1690  endif ()
1691 endfunction ()
1692 
1693 # ----------------------------------------------------------------------------
1694 ## @brief Add library target.
1695 #
1696 # This BASIS function overwrites CMake's
1697 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_library">
1698 # add_library()</a> command in order to store information of imported targets.
1699 #
1700 # @note Use basis_add_library() instead where possible!
1701 #
1702 # @param [in] TARGET_UID Name of the target.
1703 # @param [in] ARGN Further arguments of CMake's add_library().
1704 #
1705 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_library
1706 function (add_library TARGET_UID)
1707  _add_library (${TARGET_UID} ${ARGN})
1708  list (FIND ARGN IMPORTED IDX)
1709  if (IDX EQUAL 1)
1710  if (COMMAND basis_add_imported_target)
1711  basis_add_imported_target ("${TARGET_UID}" "${ARGV1}")
1712  endif ()
1713  else ()
1714  basis_set_project_property (APPEND PROPERTY TARGETS "${TARGET_UID}")
1715  endif ()
1716 endfunction ()
1717 
1718 # ----------------------------------------------------------------------------
1719 ## @brief Add executable built from C++ source code.
1720 #
1721 # @note This function should not be used directly. Instead, it is called
1722 # by basis_add_executable() if the (detected) programming language
1723 # of the given source code files is @c CXX (i.e., C/C++).
1724 #
1725 # This function adds an executable target for the build of an executable from
1726 # C++ source code files. Refer to the documentation of basis_add_executable()
1727 # for a description of general options for adding an executable target.
1728 #
1729 # By default, the BASIS C++ utilities library is added as link dependency.
1730 # If none of the BASIS C++ utilities are used by this target, the option
1731 # NO_BASIS_UTILITIES can be given. To enable this option by default, set the
1732 # variable @c BASIS_UTILITIES to @c FALSE, best in the <tt>Settings.cmake</tt>
1733 # file located in the @c PROJECT_CONFIG_DIR (add such file if missing).
1734 # If the use of the BASIS C++ utilities is disabled by default, the
1735 # @c USE_BASIS_UTILITIES option can be used to enable them for this target
1736 # only. Note that the utilities library is a static library and thus the linker
1737 # would simply not include any of the BASIS utility functions in the final
1738 # binary file if not used. The only advantage of setting @c BASIS_UTILITIES to
1739 # @c FALSE or to always specify @c NO_BASIS_UTILITIES if no target uses the
1740 # utilities is that the BASIS utilities library will not be build in this case.
1741 #
1742 # @param [in] TARGET_NAME Name of build target.
1743 # @param [in] ARGN This argument list is parsed and the following
1744 # arguments are extracted, all other arguments are
1745 # considered to be source code files and simply passed
1746 # on to CMake's add_executable() command.
1747 # @par
1748 # <table border=0>
1749 # <tr>
1750 # @tp @b COMPONENT name @endtp
1751 # <td>Name of component as part of which this executable will be installed
1752 # if the specified @c DESTINATION is not "none".
1753 # (default: @c BASIS_RUNTIME_COMPONENT)</td>
1754 # </tr>
1755 # <tr>
1756 # @tp @b DESTINATION dir @endtp
1757 # <td>Installation directory relative to @c CMAKE_INSTALL_PREFIX.
1758 # If "none" (case-insensitive) is given as argument, no default
1759 # installation rules are added for this executable target.
1760 # (default: @c INSTALL_RUNTIME_DIR or @c INSTALL_LIBEXEC_DIR
1761 # if @p LIBEXEC is given)</td>
1762 # </tr>
1763 # <tr>
1764 # @tp @b LIBEXEC @endtp
1765 # <td>Specifies that the built executable is an auxiliary executable which
1766 # is only called by other executables. (default: @c FALSE)</td>
1767 # </tr>
1768 # <tr>
1769 # @tp @b [NO]EXPORT @endtp
1770 # <td>Whether to export this target. (default: @c TRUE)</td>
1771 # </tr>
1772 # <tr>
1773 # @tp @b NO_BASIS_UTILITIES @endtp
1774 # <td>Specify that the BASIS utilities are not used by this executable and hence
1775 # no link dependency on the BASIS utilities library shall be added.
1776 # (default: @c NOT @c BASIS_UTILITIES)</td>
1777 # </tr>
1778 # <tr>
1779 # @tp @b USE_BASIS_UTILITIES @endtp
1780 # <td>Specify that the BASIS utilities are used and required by this executable
1781 # and hence a link dependency on the BASIS utilities library has to be added.
1782 # (default: @c BASIS_UTILITIES)</td>
1783 # </tr>
1784 # </table>
1785 #
1786 # @returns Adds executable target using CMake's add_executable() command.
1787 #
1788 # @sa basis_add_executable()
1789 function (basis_add_executable_target TARGET_NAME)
1790  # check target name
1791  basis_check_target_name (${TARGET_NAME})
1792  basis_make_target_uid (TARGET_UID "${TARGET_NAME}")
1793  message (STATUS "Adding executable ${TARGET_UID}...")
1794  # parse arguments
1795  CMAKE_PARSE_ARGUMENTS (
1796  ARGN
1797  "USE_BASIS_UTILITIES;NO_BASIS_UTILITIES;EXPORT;NOEXPORT;LIBEXEC"
1798  "COMPONENT;DESTINATION"
1799  ""
1800  ${ARGN}
1801  )
1802  set (SOURCES ${ARGN_UNPARSED_ARGUMENTS})
1803  basis_set_flag (ARGN EXPORT ${BASIS_EXPORT_DEFAULT})
1804  if (ARGN_USE_BASIS_UTILITIES AND ARGN_NO_BASIS_UTILITIES)
1805  message (FATAL_ERROR "Target ${TARGET_UID}: Options USE_BASIS_UTILITIES and NO_BASIS_UTILITIES are mutually exclusive!")
1806  endif ()
1807  if (ARGN_USE_BASIS_UTILITIES)
1808  set (USES_BASIS_UTILITIES TRUE)
1809  elseif (ARGN_NO_BASIS_UTILITIES)
1810  set (USES_BASIS_UTILITIES FALSE)
1811  else ()
1812  set (USES_BASIS_UTILITIES ${BASIS_UTILITIES})
1813  endif ()
1814  # IS_TEST flag
1815  basis_sanitize_for_regex (RE "${PROJECT_TESTING_DIR}")
1816  if (CMAKE_CURRENT_SOURCE_DIR MATCHES "^${RE}")
1817  set (IS_TEST TRUE)
1818  else ()
1819  set (IS_TEST FALSE)
1820  endif ()
1821  # installation component
1822  if (NOT ARGN_COMPONENT)
1823  set (ARGN_COMPONENT "${BASIS_RUNTIME_COMPONENT}")
1824  endif ()
1825  if (NOT ARGN_COMPONENT)
1826  set (ARGN_COMPONENT "Unspecified")
1827  endif ()
1828  # installation directory
1829  if (ARGN_DESTINATION)
1830  if (ARGN_DESTINATION MATCHES "^[nN][oO][nN][eE]$")
1831  set (ARGN_DESTINATION)
1832  elseif (IS_ABSOLUTE "${ARGN_DESTINATION}")
1833  file (RELATIVE_PATH ARGN_DESTINATION "${CMAKE_INSTALL_PREFIX}" "${ARGN_DESTINATION}")
1834  endif ()
1835  elseif (ARGN_LIBEXEC)
1836  set (ARGN_DESTINATION "${INSTALL_LIBEXEC_DIR}")
1837  else ()
1838  set (ARGN_DESTINATION "${INSTALL_RUNTIME_DIR}")
1839  endif ()
1840  # configure (.in) source files
1841  basis_configure_sources (SOURCES ${SOURCES})
1842  # add executable target
1843  add_executable (${TARGET_UID} ${SOURCES})
1844  basis_make_target_uid (HEADERS_TARGET headers)
1845  if (TARGET "${HEADERS_TARGET}")
1846  add_dependencies (${TARGET_UID} ${HEADERS_TARGET})
1847  endif ()
1848  basis_get_target_name (OUTPUT_NAME ${TARGET_UID})
1849  set_target_properties (${TARGET_UID} PROPERTIES BASIS_TYPE "EXECUTABLE" LANGUAGE "CXX" OUTPUT_NAME "${OUTPUT_NAME}")
1850  if (ARGN_LIBEXEC)
1851  set_target_properties (${TARGET_UID} PROPERTIES LIBEXEC 1 COMPILE_DEFINITIONS LIBEXEC SCRIPT_DEFINITIONS LIBEXEC)
1852  else ()
1853  set_target_properties (${TARGET_UID} PROPERTIES LIBEXEC 0)
1854  endif ()
1855  set_target_properties (${TARGET_UID} PROPERTIES TEST ${IS_TEST})
1856  # output directory
1857  if (IS_TEST)
1858  if (ARGN_LIBEXEC)
1859  set_target_properties (${TARGET_UID} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_LIBEXEC_DIR}")
1860  else ()
1861  set_target_properties (${TARGET_UID} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_RUNTIME_DIR}")
1862  endif ()
1863  elseif (ARGN_LIBEXEC)
1864  set_target_properties (${TARGET_UID} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${BINARY_LIBEXEC_DIR}")
1865  else ()
1866  set_target_properties (${TARGET_UID} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${BINARY_RUNTIME_DIR}")
1867  endif ()
1868  # installation directory
1869  set_target_properties (${TARGET_UID} PROPERTIES RUNTIME_INSTALL_DIRECTORY "${ARGN_DESTINATION}")
1870  # link to BASIS utilities
1871  if (USES_BASIS_UTILITIES)
1872  basis_target_link_libraries (.${TARGET_UID} basis)
1873  else ()
1874  set_target_properties (${TARGET_UID} PROPERTIES BASIS_UTILITIES FALSE)
1875  endif ()
1876  # export
1877  set (EXPORT_OPT)
1878  if (EXPORT)
1879  basis_add_export_target (EXPORT_OPT ${TARGET_UID} "${IS_TEST}" ${ARGN_DESTINATION})
1880  endif ()
1881  # installation
1882  if (ARGN_DESTINATION)
1883  if (IS_TEST)
1884  # TODO install (selected?) tests
1885  else ()
1886  install (
1887  TARGETS ${TARGET_UID} ${EXPORT_OPT}
1888  DESTINATION "${ARGN_DESTINATION}"
1889  COMPONENT "${ARGN_COMPONENT}"
1890  )
1891  endif ()
1892  endif ()
1893  # done
1894  message (STATUS "Adding executable ${TARGET_UID}... - done")
1895 endfunction ()
1896 
1897 # ----------------------------------------------------------------------------
1898 ## @brief Add library built from C++ source code.
1899 #
1900 # @note This function should not be used directly. Instead, it is called
1901 # by basis_add_library() if the (detected) programming language
1902 # of the given source code files is @c CXX (i.e., C/C++) and the
1903 # option @c MEX is not given.
1904 #
1905 # This function adds a library target which builds a library from C++ source
1906 # code files. Refer to the documentation of basis_add_library() for a
1907 # description of the general options for adding a library target.
1908 #
1909 # By default, the BASIS C++ utilities library is added as link dependency.
1910 # If none of the BASIS C++ utilities are used by this target, the option
1911 # NO_BASIS_UTILITIES can be given. To enable this option by default, set the
1912 # variable @c BASIS_UTILITIES to @c FALSE, best in the <tt>Settings.cmake</tt>
1913 # file located in the @c PROJECT_CONFIG_DIR (add such file if missing).
1914 # If the use of the BASIS C++ utilities is disabled by default, the
1915 # @c USE_BASIS_UTILITIES option can be used to enable them for this target
1916 # only. Note that the utilities library is a static library and thus the linker
1917 # would simply not include any of the BASIS utility functions in the final
1918 # binary file if not used. The only advantage of setting @c BASIS_UTILITIES to
1919 # @c FALSE or to always specify @c NO_BASIS_UTILITIES if no target uses the
1920 # utilities is that the BASIS utilities library will not be build in this case.
1921 #
1922 # @param [in] TARGET_NAME Name of build target.
1923 # @param [in] ARGN This argument list is parsed and the following
1924 # arguments are extracted. All other arguments are
1925 # considered to be source code files and simply
1926 # passed on to CMake's add_library() command.
1927 # @par
1928 # <table border=0>
1929 # <tr>
1930 # @tp <b>STATIC</b>|<b>SHARED</b>|<b>MODULE</b> @endtp
1931 # <td>Type of the library. (default: @c SHARED if @c BUILD_SHARED_LIBS
1932 # evaluates to true or @c STATIC otherwise)</td>
1933 # </tr>
1934 # <tr>
1935 # @tp @b COMPONENT name @endtp
1936 # <td>Name of component as part of which this library will be installed
1937 # if either the @c RUNTIME_INSTALL_DIRECTORY or
1938 # @c LIBRARY_INSTALL_DIRECTORY property is not "none". Used only if
1939 # either @p RUNTIME_COMPONENT or @p LIBRARY_COMPONENT not specified.
1940 # (default: see @p RUNTIME_COMPONENT and @p LIBRARY_COMPONENT)</td>
1941 # </tr>
1942 # <tr>
1943 # @tp @b DESTINATION dir @endtp
1944 # <td>Installation directory for runtime and library component relative
1945 # to @c CMAKE_INSTALL_PREFIX. Used only if either @p RUNTIME_DESTINATION
1946 # or @p LIBRARY_DESTINATION not specified. If "none" (case-insensitive)
1947 # is given as argument, no default installation rules are added.
1948 # (default: see @p RUNTIME_DESTINATION and @p LIBRARY_DESTINATION)</td>
1949 # </tr>
1950 # <tr>
1951 # @tp @b LIBRARY_COMPONENT name @endtp
1952 # <td>Name of component as part of which import/static library will be intalled
1953 # if @c LIBRARY_INSTALL_DIRECTORY property is not "none".
1954 # (default: @c COMPONENT if specified or @c BASIS_LIBRARY_COMPONENT otherwise)</td>
1955 # </tr>
1956 # <tr>
1957 # @tp @b LIBRARY_DESTINATION dir @endtp
1958 # <td>Installation directory of the library component relative to
1959 # @c CMAKE_INSTALL_PREFIX. If "none" (case-insensitive) is given as argument,
1960 # no installation rule for the library component is added.
1961 # (default: @c INSTALL_ARCHIVE_DIR)</td>
1962 # </tr>
1963 # <tr>
1964 # @tp @b RUNTIME_COMPONENT name @endtp
1965 # <td>Name of component as part of which runtime library will be installed
1966 # if @c RUNTIME_INSTALL_DIRECTORY property is not "none".
1967 # (default: @c COMPONENT if specified or @c BASIS_RUNTIME_COMPONENT otherwise)</td>
1968 # </tr>
1969 # <tr>
1970 # @tp @b RUNTIME_DESTINATION dir @endtp
1971 # <td>Installation directory of the runtime component relative to
1972 # @c CMAKE_INSTALL_PREFIX. If "none" (case-insensitive) is given as argument,
1973 # no installation rule for the runtime library is added.
1974 # (default: @c INSTALL_LIBRARY_DIR on Unix or @c INSTALL_RUNTIME_DIR Windows)</td>
1975 # </tr>
1976 # <tr>
1977 # @tp @b [NO]EXPORT @endtp
1978 # <td>Whether to export this target. (default: @c TRUE)</td>
1979 # </tr>
1980 # <tr>
1981 # @tp @b NO_BASIS_UTILITIES @endtp
1982 # <td>Specify that the BASIS utilities are not used by this executable and hence
1983 # no link dependency on the BASIS utilities library shall be added.
1984 # (default: @c NOT BASIS_UTILITIES)</td>
1985 # </tr>
1986 # <tr>
1987 # @tp @b USE_BASIS_UTILITIES @endtp
1988 # <td>Specify that the BASIS utilities are used and required by this executable
1989 # and hence a link dependency on the BASIS utilities library shall be added.
1990 # (default: @c BASIS_UTILITIES)</td>
1991 # </tr>
1992 # </table>
1993 #
1994 # @returns Adds library target using CMake's add_library() command.
1995 #
1996 # @sa basis_add_library()
1997 function (basis_add_library_target TARGET_NAME)
1998  # On UNIX-based systems setting the VERSION property only creates
1999  # annoying files with the version string as suffix.
2000  # Moreover, MEX-files may NEVER have a suffix after the MEX extension!
2001  # Otherwise, the MATLAB Compiler when using the symbolic link
2002  # without this suffix will create code that fails on runtime
2003  # with an .auth file missing error.
2004  #
2005  # Thus, do NOT set VERSION and SOVERSION properties on library targets!
2006 
2007  # check target name
2008  basis_check_target_name (${TARGET_NAME})
2009  basis_make_target_uid (TARGET_UID "${TARGET_NAME}")
2010  # parse arguments
2011  CMAKE_PARSE_ARGUMENTS (
2012  ARGN
2013  "STATIC;SHARED;MODULE;USE_BASIS_UTILITIES;NO_BASIS_UTILITIES;EXPORT;NOEXPORT"
2014  "COMPONENT;RUNTIME_COMPONENT;LIBRARY_COMPONENT;DESTINATION;RUNTIME_DESTINATION;LIBRARY_DESTINATION"
2015  ""
2016  ${ARGN}
2017  )
2018  set (SOURCES ${ARGN_UNPARSED_ARGUMENTS})
2019  basis_set_flag (ARGN EXPORT ${BASIS_EXPORT_DEFAULT})
2020  if (ARGN_USE_BASIS_UTILITIES AND ARGN_NO_BASIS_UTILITIES)
2021  message (FATAL_ERROR "Target ${TARGET_UID}: Options USE_BASIS_UTILITIES and NO_BASIS_UTILITIES are mutually exclusive!")
2022  endif ()
2023  if (ARGN_USE_BASIS_UTILITIES)
2024  set (USES_BASIS_UTILITIES TRUE)
2025  elseif (ARGN_NO_BASIS_UTILITIES)
2026  set (USES_BASIS_UTILITIES FALSE)
2027  else ()
2028  set (USES_BASIS_UTILITIES ${BASIS_UTILITIES})
2029  endif ()
2030  # IS_TEST flag
2031  basis_sanitize_for_regex (RE "${PROJECT_TESTING_DIR}")
2032  if (CMAKE_CURRENT_SOURCE_DIR MATCHES "^${RE}")
2033  set (IS_TEST TRUE)
2034  else ()
2035  set (IS_TEST FALSE)
2036  endif ()
2037  # library type
2038  if (NOT ARGN_SHARED AND NOT ARGN_STATIC AND NOT ARGN_MODULE)
2039  if (BUILD_SHARED_LIBS)
2040  set (ARGN_SHARED TRUE)
2041  else ()
2042  set (ARGN_STATIC TRUE)
2043  endif ()
2044  endif ()
2045  set (TYPE)
2046  if (ARGN_STATIC)
2047  if (TYPE)
2048  message (FATAL_ERROR "More than one library type specified for target ${TARGET_UID}!")
2049  endif ()
2050  set (TYPE "STATIC")
2051  endif ()
2052  if (ARGN_SHARED)
2053  if (TYPE)
2054  message (FATAL_ERROR "More than one library type specified for target ${TARGET_UID}!")
2055  endif ()
2056  set (TYPE "SHARED")
2057  endif ()
2058  if (ARGN_MODULE)
2059  if (TYPE)
2060  message (FATAL_ERROR "More than one library type specified for target ${TARGET_UID}!")
2061  endif ()
2062  set (TYPE "MODULE")
2063  endif ()
2064  string (TOLOWER "${TYPE}" type)
2065  # status message
2066  message (STATUS "Adding ${type} library ${TARGET_UID}...")
2067  # installation component
2068  if (ARGN_COMPONENT)
2069  if (NOT ARGN_RUNTIME_COMPONENT)
2070  set (ARGN_RUNTIME_COMPONENT "${ARGN_COMPONENT}")
2071  endif ()
2072  if (NOT ARGN_LIBRARY_COMPONENT)
2073  set (ARGN_LIBRARY_COMPONENT "${ARGN_COMPONENT}")
2074  endif ()
2075  endif ()
2076  if (NOT ARGN_RUNTIME_COMPONENT)
2077  set (ARGN_RUNTIME_COMPONENT "${BASIS_RUNTIME_COMPONENT}")
2078  endif ()
2079  if (NOT ARGN_RUNTIME_COMPONENT)
2080  set (ARGN_RUNTIME_COMPONENT "Unspecified")
2081  endif ()
2082  if (NOT ARGN_LIBRARY_COMPONENT)
2083  set (ARGN_LIBRARY_COMPONENT "${BASIS_LIBRARY_COMPONENT}")
2084  endif ()
2085  if (NOT ARGN_LIBRARY_COMPONENT)
2086  set (ARGN_LIBRARY_COMPONENT "Unspecified")
2087  endif ()
2088  # installation directories
2089  if (ARGN_DESTINATION)
2090  if (NOT ARGN_STATIC AND NOT ARGN_RUNTIME_DESTINATION)
2091  set (ARGN_RUNTIME_DESTINATION "${ARGN_DESTINATION}")
2092  endif ()
2093  if (NOT ARGN_LIBRARY_DESTINATION)
2094  set (ARGN_LIBRARY_DESTINATION "${ARGN_DESTINATION}")
2095  endif ()
2096  endif ()
2097  if (NOT ARGN_RUNTIME_DESTINATION)
2098  set (ARGN_RUNTIME_DESTINATION "${INSTALL_RUNTIME_DIR}")
2099  endif ()
2100  if (NOT ARGN_LIBRARY_DESTINATION)
2101  set (ARGN_LIBRARY_DESTINATION "${INSTALL_LIBRARY_DIR}")
2102  endif ()
2103  if (ARGN_STATIC OR ARGN_RUNTIME_DESTINATION MATCHES "^[nN][oO][nN][eE]$")
2104  set (ARGN_RUNTIME_DESTINATION)
2105  endif ()
2106  if (ARGN_LIBRARY_DESTINATION MATCHES "^[nN][oO][nN][eE]$")
2107  set (ARGN_LIBRARY_DESTINATION)
2108  endif ()
2109  # configure (.in) source files
2110  basis_configure_sources (SOURCES ${SOURCES})
2111  # add library target
2112  add_library (${TARGET_UID} ${TYPE} ${SOURCES})
2113  basis_make_target_uid (HEADERS_TARGET headers)
2114  if (TARGET ${HEADERS_TARGET})
2115  add_dependencies (${TARGET_UID} ${HEADERS_TARGET})
2116  endif ()
2117  basis_get_target_name (OUTPUT_NAME ${TARGET_UID})
2118  set_target_properties (${TARGET_UID} PROPERTIES BASIS_TYPE "${TYPE}_LIBRARY" LANGUAGE "CXX" OUTPUT_NAME "${OUTPUT_NAME}")
2119  # output directory
2120  if (IS_TEST)
2122  ${TARGET_UID}
2123  PROPERTIES
2124  RUNTIME_OUTPUT_DIRECTORY "${TESTING_RUNTIME_DIR}"
2125  LIBRARY_OUTPUT_DIRECTORY "${TESTING_LIBRARY_DIR}"
2126  ARCHIVE_OUTPUT_DIRECTORY "${TESTING_ARCHIVE_DIR}"
2127  )
2128  else ()
2130  ${TARGET_UID}
2131  PROPERTIES
2132  RUNTIME_OUTPUT_DIRECTORY "${BINARY_RUNTIME_DIR}"
2133  LIBRARY_OUTPUT_DIRECTORY "${BINARY_LIBRARY_DIR}"
2134  ARCHIVE_OUTPUT_DIRECTORY "${BINARY_ARCHIVE_DIR}"
2135  )
2136  endif ()
2137  # installation directory
2138  # these properties are used by basis_get_target_location() in particular
2140  ${TARGET_UID}
2141  PROPERTIES
2142  RUNTIME_INSTALL_DIRECTORY "${ARGN_RUNTIME_DESTINATION}"
2143  LIBRARY_INSTALL_DIRECTORY "${ARGN_LIBRARY_DESTINATION}"
2144  ARCHIVE_INSTALL_DIRECTORY "${ARGN_LIBRARY_DESTINATION}"
2145  )
2146  # link to BASIS utilities
2147  if (USES_BASIS_UTILITIES)
2148  basis_target_link_libraries (.${TARGET_UID} basis)
2149  else ()
2150  set_target_properties (${TARGET_UID} PROPERTIES BASIS_UTILITIES FALSE)
2151  endif ()
2152  # export
2153  set (EXPORT_OPT)
2154  if (EXPORT)
2155  basis_add_export_target (EXPORT_OPT ${TARGET_UID} "${IS_TEST}" ${ARGN_RUNTIME_DESTINATION} ${ARGN_LIBRARY_DESTINATION})
2156  endif ()
2157  # installation
2158  set (DESTINATION_OPTS)
2159  if (IS_TEST)
2160  # TODO At the moment, no tests are installed. Once there is a way to
2161  # install selected tests, the shared libraries they depend on
2162  # need to be installed as well.
2163  else ()
2164  if (ARGN_RUNTIME_DESTINATION)
2165  list (APPEND DESTINATION_OPTS
2166  RUNTIME
2167  DESTINATION "${ARGN_RUNTIME_DESTINATION}"
2168  COMPONENT "${ARGN_RUNTIME_COMPONENT}"
2169  )
2170  endif ()
2171  if (ARGN_LIBRARY_DESTINATION)
2172  list (APPEND DESTINATION_OPTS
2173  LIBRARY
2174  DESTINATION "${ARGN_LIBRARY_DESTINATION}"
2175  COMPONENT "${ARGN_LIBRARY_COMPONENT}"
2176  ARCHIVE
2177  DESTINATION "${ARGN_LIBRARY_DESTINATION}"
2178  COMPONENT "${ARGN_LIBRARY_COMPONENT}"
2179  )
2180  endif ()
2181  endif ()
2182  if (DESTINATION_OPTS)
2183  install (TARGETS ${TARGET_UID} ${EXPORT_OPT} ${DESTINATION_OPTS})
2184  endif ()
2185  # done
2186  message (STATUS "Adding ${type} library ${TARGET_UID}... - done")
2187 endfunction ()
2188 
2189 # ----------------------------------------------------------------------------
2190 ## @brief Add script library target.
2191 #
2192 # @note This function should not be used directly. Instead, it is called
2193 # by basis_add_library() if the (detected) programming language
2194 # of the given source code files is neither @c CXX (i.e., C/C++) nor
2195 # @c MATLAB.
2196 #
2197 # This function adds a build target for libraries which are a collection of
2198 # one or more modules written in a scripting language. The relative paths
2199 # of the modules relative to the library's @p SOURCE_DIRECTORY property are
2200 # preserved. This is important for the most widely used scripting languages
2201 # such as Python, Perl, or MATLAB, where the file path relative to the
2202 # package root directory defines the package namespace.
2203 #
2204 # A custom CMake build target with the following properties is added by this
2205 # function to the build system. These properties are used by
2206 # basis_build_script_library() to generate a build script written in CMake
2207 # code which is executed by a custom CMake command. Before the invokation of
2208 # basis_build_script_library(), the target properties can be modified using
2209 # basis_set_target_properties().
2210 #
2211 # @note Custom BASIS build targets are finalized by BASIS using basis_project_end(),
2212 # i.e., the end of the root CMake configuration file of the (sub-)project.
2213 #
2214 # @par Properties on script library targets
2215 # <table border=0>
2216 # <tr>
2217 # @tp @b BASIS_TYPE @endtp
2218 # <td>Read-only property with value "SCRIPT_LIBRARY" for script library targets.</td>
2219 # </tr>
2220 # <tr>
2221 # @tp @b BASIS_UTILITIES @endtp
2222 # <td>Whether the BASIS utilities are used by any module of this library.
2223 # For the supported scripting languages for which BASIS utilities are
2224 # implemented, BASIS will in most cases automatically detect whether
2225 # these utilities are used by a module or not. Otherwise, set this
2226 # property manually or use either the @p USE_BASIS_UTILITIES or the
2227 # @p NO_BASIS_UTILITIES option when adding the library target.
2228 # (default: auto-detected or @c UNKNOWN)</td>
2229 # </tr>
2230 # <tr>
2231 # @tp @b BINARY_DIRECTORY @endtp
2232 # <td>Build tree directory of this target. (default: @c CMAKE_CURRENT_BINARY_DIR)</td>
2233 # </tr>
2234 # <tr>
2235 # @tp @b COMPILE @endtp
2236 # <td>Whether to compile the library, respectively, it's modules if the
2237 # programming language allows such pre-compilation as in case of Python,
2238 # for example. If @c TRUE, only the compiled files are installed.
2239 # (default: @c BASIS_COMPILE_SCRIPTS)</td>
2240 # </tr>
2241 # <tr>
2242 # @tp @b SCRIPT_DEFINITIONS @endtp
2243 # <td>CMake code which is evaluated after the inclusion of the default script
2244 # configuration files. This code can be used to set the replacement text of the
2245 # CMake variables ("@VAR@" patterns) used in the source files.
2246 # See <a href="https://cmake-basis.github.io/standard/scripttargets.html#script-configuration">
2247 # Build System Standard</a> for details. (default: "")</td>
2248 # </tr>
2249 # <tr>
2250 # @tp @b SCRIPT_DEFINITIONS_FILE @endtp
2251 # <td>CMake script file with compile definitions, also referred to as script
2252 # configuration file. The named files are included after the default BASIS
2253 # script configuration and before the @c SCRIPT_DEFINITIONS code is being
2254 # evaluated. (default: @c BINARY_CONFIG_DIR/ScriptConfig.cmake)</td>
2255 # </tr>
2256 # <tr>
2257 # @tp @b EXPORT @endtp
2258 # <td>Whether to export this build target in which case an import library
2259 # target is added to the custom exports file with the path to the
2260 # built/installed modules set as @c IMPORT_LOCATION. (default: @c TRUE)</td>
2261 # </tr>
2262 # <tr>
2263 # @tp @b LANGUAGE @endtp
2264 # <td>Read-only property of programming language of modules in uppercase letters.
2265 # (default: see @p LANGUAGE argument)</td>
2266 # </tr>
2267 # <tr>
2268 # @tp @b LIBRARY_COMPONENT @endtp
2269 # <td>Name of component as part of which this library is installed if
2270 # @c LIBRARY_INSTALL_DIRECTORY is not set to "none".
2271 # (default: see @p COMPONENT argument)</td>
2272 # </tr>
2273 # <tr>
2274 # @tp @b LIBRARY_INSTALL_DIRECTORY @endtp
2275 # <td>Installation directory of library configured for use in installation tree
2276 # relative to @c CMAKE_INSTALL_PREFIX. Set to "none" (case-insensitive) to skip the
2277 # addition of an installation rule.
2278 # (default: <tt>INSTALL_&lt;LANGUAGE&gt;_LIBRARY_DIR</tt> if defined or
2279 # @c INSTALL_LIBRARY_DIR otherwise)</td>
2280 # </tr>
2281 # <tr>
2282 # @tp @b LIBRARY_OUTPUT_DIRECTORY @endtp
2283 # <td>Output directory of library configured for use within the build tree.
2284 # (default: <tt>BINARY_&lt;LANGUAGE&gt;_LIBRARY_DIR</tt> if defined or
2285 # @c BINARY_LIBRARY_DIR otherwise)</td>
2286 # </tr>
2287 # <tr>
2288 # @tp @b LINK_DEPENDS @endtp
2289 # <td>Paths or target names of script modules and libraries used by this script.
2290 # For each listed build target, a dependency is added between this
2291 # library target and the named build targets. Use basis_target_link_libraries()
2292 # to add additional link dependencies. Further note that if this library is
2293 # a link dependency of an executable script added by basis_add_executable()
2294 # (i.e., basis_add_script() actually), the link dependencies of this library
2295 # are inherited by the executable script.
2296 # (default: BASIS utilities module if used or empty list otherwise)</td>
2297 # </tr>
2298 # <tr>
2299 # @tp @b PREFIX @endtp
2300 # <td>Common module prefix. The given directory path is appended to both
2301 # @c LIBRAR_OUTPUT_DIRECTORY and @c LIBRARY_INSTALL_DIRECTORY and can,
2302 # for example, be used to install modules of a Python package as part of
2303 # another Python package, where @c LIBRARY_OUTPUT_DIRECTORY or
2304 # @c LIBRARY_INSTALL_DIRECTORY, respectively, is the directory of the
2305 # main package which is added to the @c PYTHONPATH. Possibly missing
2306 # __init__.py files in case of Python are generated by the _initpy target
2307 # which is automatically added by BASIS in that case and further added to
2308 # the dependencies of this library target.
2309 # (default: @c PROJECT_NAMESPACE_PYTHON if @c LANGUAGE is @c PYTHON with
2310 # periods (.) replaced by slashes (/), @c PROJECT_NAMESPACE_PERL if
2311 # @c LANGUAGE is @c PERL with <tt>::</tt> replaced by slashes (/),
2312 # and "" otherwise)</td>
2313 # </tr>
2314 # <tr>
2315 # @tp @b SOURCE_DIRECTORY @endtp
2316 # <td>Source directory of this target. This directory is in particular
2317 # used to convert the paths of the given source files to relative paths.
2318 # The built modules within the build and installation tree will have the
2319 # same relative path (relative to the @c LIBRARY_OUTPUT_DIRECTORY or
2320 # @c LIBRARY_INSTALL_DIRECTORY, respectively).
2321 # (default: @c CMAKE_CURRENT_SOURCE_DIR)</td>
2322 # </tr>
2323 # <tr>
2324 # @tp @b SOURCES @endtp
2325 # <td>Read-only property which lists the source files of this library.
2326 # Note that the first element in this list actually names a directory
2327 # in the build, the one where the build script for this target is located
2328 # instead of a source file and thus should be ignored.</td>
2329 # </tr>
2330 # </table>
2331 #
2332 # @attention Properties documented as read-only must not be modified.
2333 #
2334 # @param [in] TARGET_NAME Name of build target.
2335 # @param [in] ARGN The remaining arguments are parsed and the following
2336 # arguments extracted. All unparsed arguments are treated
2337 # as the module files of the script library.
2338 # @par
2339 # <table border=0>
2340 # <tr>
2341 # @tp @b COMPONENT name @endtp
2342 # <td>Name of installation component as part of which this library is being
2343 # installed if the @c LIBRARY_INSTALL_DIRECTORY property is not "none".
2344 # (default: @c BASIS_LIBRARY_COMPONENT)</td>
2345 # </tr>
2346 # <tr>
2347 # @tp @b DESTINATION dir @endtp
2348 # <td>Installation directory for library relative to @c CMAKE_INSTALL_PREFIX.
2349 # If an absolute path is given as argument, it is made relative to the
2350 # configured installation prefix. (default: @c INSTALL_LIBRARY_DIR)</td>
2351 # </tr>
2352 # <tr>
2353 # @tp @b LANGUAGE lang @endtp
2354 # <td>Programming language in which modules are written (case-insensitive).
2355 # If not specified, the programming language is derived from the file name
2356 # extensions of the source files and the shebang directive on the first line
2357 # of each module if any. If the programming language could not be detected
2358 # automatically, the @c LANGUAGE property is set to @c UNKNOWN. Note that
2359 # for script library targets, the library may still be built correctly
2360 # even if the scripting language was not recognized. The automatic detection
2361 # whether the BASIS utilities are used and required will fail, however.
2362 # In this case, specify the programming language using this option.
2363 # (default: auto-detected or @c UNKNOWN)</td>
2364 # </tr>
2365 # <tr>
2366 # @tp @b [NO]EXPORT @endtp
2367 # <td>Whether to export this target. (default: @c TRUE)</td>
2368 # </tr>
2369 # <tr>
2370 # @tp @b NO_BASIS_UTILITIES @endtp
2371 # <td>Specify that the BASIS utilities are not used by this library. If the
2372 # programming language of the modules is known and BASIS utilities are
2373 # available for this language, BASIS will in most cases automatically
2374 # detect whether these utilities are used by any module of this library.
2375 # Use this option to skip this check in the case that no module makes
2376 # use of the BASIS utilities.</td>
2377 # </tr>
2378 # <tr>
2379 # @tp @b USE_BASIS_UTILITIES @endtp
2380 # <td>Specify that the BASIS utilities are used and thus required by this library.
2381 # If the programming language of the modules is known and BASIS utilities are
2382 # available for this language, BASIS will in most cases automatically
2383 # detect whether these utilities are used by any module of this library.
2384 # Use this option to skip this check when it is already known that no module
2385 # makes use of the BASIS utilities. Note that an error is raised if this option
2386 # is given, but no BASIS utilities are available for the programming language
2387 # of this script or if the programming language is unknown, respectively, not
2388 # detected correctly. In this case, consider the use of the @p LANGUAGE argument.</td>
2389 # </tr>
2390 # <tr>
2391 # @tp @b FINAL @endtp
2392 # <td>Finalize custom targets immediately. Any following target property changes
2393 # will have no effect. When this option is used, the custom target which
2394 # executes the custom build command is added in the current working directory.
2395 # Otherwise it will be added in the top-level source directory of the project.
2396 # Which with the Visual Studio generators adds the corresponding Visual Studio
2397 # Project files directly to the top-level build directory. This can be avoided
2398 # using this option or calling basis_finalize_targets() at the end of each
2399 # CMakeLists.txt file.</td>
2400 # </tr>
2401 # </table>
2402 #
2403 # @returns Adds a custom CMake target with the documented properties. The actual custom
2404 # command to build the library is added by basis_build_script_library().
2405 #
2406 # @sa basis_add_library()
2407 function (basis_add_script_library TARGET_NAME)
2408  # check target name
2409  basis_check_target_name ("${TARGET_NAME}")
2410  basis_make_target_uid (TARGET_UID "${TARGET_NAME}")
2411  message (STATUS "Adding script library ${TARGET_UID}...")
2412  # dump CMake variables for configuration of script
2413  set (BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TARGET_UID}")
2414  basis_dump_variables ("${BUILD_DIR}.dir/cache.cmake.tmp")
2415  # parse arguments
2416  CMAKE_PARSE_ARGUMENTS (
2417  ARGN
2418  "NO_BASIS_UTILITIES;USE_BASIS_UTILITIES;EXPORT;NOEXPORT;FINAL"
2419  "COMPONENT;DESTINATION;LANGUAGE"
2420  ""
2421  ${ARGN}
2422  )
2423  basis_set_flag (ARGN EXPORT ${BASIS_EXPORT_DEFAULT})
2424  set (SOURCES "${ARGN_UNPARSED_ARGUMENTS}")
2425  # IS_TEST flag
2426  basis_sanitize_for_regex (RE "${PROJECT_TESTING_DIR}")
2427  if (CMAKE_CURRENT_SOURCE_DIR MATCHES "^${RE}")
2428  set (IS_TEST TRUE)
2429  else ()
2430  set (IS_TEST FALSE)
2431  endif ()
2432  # check source files
2433  set (_SOURCES)
2434  foreach (S IN LISTS SOURCES)
2435  get_filename_component (S "${S}" ABSOLUTE)
2436  if (NOT EXISTS "${S}" AND NOT S MATCHES "\\.in$" AND EXISTS "${S}.in" AND NOT IS_DIRECTORY "${S}.in")
2437  set (S "${S}.in")
2438  elseif (IS_DIRECTORY "${S}")
2439  message (FATAL_ERROR "Target ${TARGET_UID}: Directory ${S} given where file name expected!")
2440  endif ()
2441  if (NOT EXISTS "${S}")
2442  string (REGEX REPLACE "\\.in$" "" S "${S}")
2443  message (FATAL_ERROR "Target ${TARGET_UID}: Source file ${S}[.in] does not exist!")
2444  endif ()
2445  list (APPEND _SOURCES "${S}")
2446  endforeach ()
2447  if (NOT _SOURCES)
2448  message (FATAL_ERROR "Target ${TARGET_UID}: No source files specified!")
2449  endif ()
2450  set (SOURCES "${_SOURCES}")
2451  unset (_SOURCES)
2452  # auto-detect programming language (may be as well UNKNOWN)
2453  string (TOUPPER "${ARGN_LANGUAGE}" ARGN_LANGUAGE)
2454  if (NOT ARGN_LANGUAGE)
2455  basis_get_source_language (ARGN_LANGUAGE ${SOURCES})
2456  if (ARGN_LANGUAGE MATCHES "AMBIGUOUS|UNKNOWN")
2457  message (FATAL_ERROR "Target ${TARGET_UID}: Failed to determine programming"
2458  " language of modules! Make sure that all modules are"
2459  " written in the same language and that the used programming"
2460  " language is supported by BASIS, i.e., either Python (Jython),"
2461  " Perl, Bash, or MATLAB. Otherwise, try to specify the language"
2462  " explicitly using the LANGUAGE option.")
2463  endif ()
2464  endif ()
2465  # output directory
2466  if (IS_TEST)
2467  if (DEFINED TESTING_${ARGN_LANGUAGE}_LIBRARY_DIR)
2468  set (OUTPUT_DIRECTORY "${TESTING_${ARGN_LANGUAGE}_LIBRARY_DIR}")
2469  else ()
2470  set (OUTPUT_DIRECTORY "${TESTING_LIBRARY_DIR}")
2471  endif ()
2472  else ()
2473  if (DEFINED BINARY_${ARGN_LANGUAGE}_LIBRARY_DIR)
2474  set (OUTPUT_DIRECTORY "${BINARY_${ARGN_LANGUAGE}_LIBRARY_DIR}")
2475  else ()
2476  set (OUTPUT_DIRECTORY "${BINARY_LIBRARY_DIR}")
2477  endif ()
2478  endif ()
2479  # installation component
2480  if (NOT ARGN_COMPONENT)
2481  set (ARGN_COMPONENT "${BASIS_LIBRARY_COMPONENT}")
2482  endif ()
2483  if (NOT ARGN_COMPONENT)
2484  set (ARGN_COMPONENT "Unspecified")
2485  endif ()
2486  # installation directory
2487  if (IS_TEST)
2488  if (ARGN_DESTINATION)
2489  message (WARNING "Target ${TARGET_UID} is a library used for testing only."
2490  " Installation to the specified directory will be skipped.")
2491  set (ARGN_DESTINATION)
2492  endif ()
2493  else ()
2494  if (ARGN_DESTINATION)
2495  if (IS_ABSOLUTE "${ARGN_DESTINATION}")
2496  file (RELATIVE_PATH ARGN_DESTINATION "${CMAKE_INSTALL_PREFIX}" "${ARGN_DESTINATION}")
2497  endif ()
2498  else ()
2499  if (DEFINED INSTALL_${ARGN_LANGUAGE}_LIBRARY_DIR)
2500  set (ARGN_DESTINATION "${INSTALL_${ARGN_LANGUAGE}_LIBRARY_DIR}")
2501  else ()
2502  set (ARGN_DESTINATION "${INSTALL_LIBRARY_DIR}")
2503  endif ()
2504  endif ()
2505  endif ()
2506  # common module prefix
2507  if (ARGN_LANGUAGE MATCHES "^([JP]YTHON|PERL|MATLAB|BASH)$")
2508  basis_library_prefix (PREFIX ${ARGN_LANGUAGE})
2509  else ()
2510  set (PREFIX)
2511  endif ()
2512  # script configuration ("compile definitions")
2513  if (EXISTS "${BINARY_CONFIG_DIR}/ScriptConfig.cmake")
2514  set (CONFIG_FILE "${BINARY_CONFIG_DIR}/ScriptConfig.cmake")
2515  else ()
2516  set (CONFIG_FILE)
2517  endif ()
2518  # auto-detect use of BASIS utilities
2519  if (ARGN_LANGUAGE MATCHES "[JP]YTHON")
2520  set (UTILITIES_LANGUAGE "PYTHON")
2521  else ()
2522  set (UTILITIES_LANGUAGE "${ARGN_LANGUAGE}")
2523  endif ()
2524  if (ARGN_USE_BASIS_UTILITIES)
2525  if (NOT BASIS_UTILITIES_ENABLED MATCHES "${UTILITIES_LANGUAGE}")
2526  message (FATAL_ERROR "Target ${TARGET_UID} requires the BASIS utilities for ${UTILITIES_LANGUAGE}"
2527  " but BASIS was either build without the build of these utilities enabled"
2528  " or no utilities for this programming language are implemented. Remove the"
2529  " USE_BASIS_UTILITIES option if no BASIS utilities are used by the modules"
2530  " of the library or specify the correct programming language if it was not"
2531  " detected correctly.")
2532  endif ()
2533  set (USES_BASIS_UTILITIES TRUE)
2534  elseif (BASIS_UTILITIES AND NOT ARGN_NO_BASIS_UTILITIES AND NOT UTILITIES_LANGUAGE MATCHES "UNKNOWN")
2535  set (USES_BASIS_UTILITIES FALSE)
2536  foreach (M IN LISTS SOURCES)
2537  basis_utilities_check (USES_BASIS_UTILITIES "${M}" ${UTILITIES_LANGUAGE})
2538  if (USES_BASIS_UTILITIES)
2539  break ()
2540  endif ()
2541  endforeach ()
2542  else ()
2543  set (USES_BASIS_UTILITIES FALSE)
2544  endif ()
2545  # add custom target
2546  add_custom_target (${TARGET_UID} ALL SOURCES ${SOURCES})
2548  ${TARGET_UID}
2549  PROPERTIES
2550  LANGUAGE "${ARGN_LANGUAGE}"
2551  BASIS_TYPE "SCRIPT_LIBRARY"
2552  BASIS_UTILITIES "${USES_BASIS_UTILITIES}"
2553  BUILD_DIRECTORY "${BUILD_DIR}"
2554  SOURCE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
2555  BINARY_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
2556  LIBRARY_OUTPUT_DIRECTORY "${OUTPUT_DIRECTORY}"
2557  LIBRARY_INSTALL_DIRECTORY "${ARGN_DESTINATION}"
2558  LIBRARY_COMPONENT "${BASIS_LIBRARY_COMPONENT}"
2559  PREFIX "${PREFIX}"
2560  SCRIPT_DEFINITIONS ""
2561  SCRIPT_DEFINITIONS_FILE "${CONFIG_FILE}"
2562  LINK_DEPENDS ""
2563  EXPORT "${EXPORT}"
2564  COMPILE "${BASIS_COMPILE_SCRIPTS}"
2565  TEST "${IS_TEST}"
2566  )
2567  # link to BASIS utilities
2568  if (USES_BASIS_UTILITIES)
2569  basis_target_link_libraries (.${TARGET_UID} basis)
2570  if (BASIS_DEBUG)
2571  message ("** Target ${TARGET_UID} uses the BASIS utilities for ${UTILITIES_LANGUAGE}.")
2572  endif ()
2573  endif ()
2574  # finalize target
2575  if (ARGN_FINAL)
2576  basis_finalize_targets (${TARGET_UID})
2577  endif ()
2578  # add target to list of targets
2579  basis_set_project_property (APPEND PROPERTY TARGETS "${TARGET_UID}")
2580  message (STATUS "Adding script library ${TARGET_UID}... - done")
2581 endfunction ()
2582 
2583 # ============================================================================
2584 # custom build commands
2585 # ============================================================================
2586 
2587 # ----------------------------------------------------------------------------
2588 ## @brief Set INSTALL_RPATH property of executable or shared library target.
2589 #
2590 # This function sets the @c INSTALL_RPATH property of a specified executable or
2591 # shared library target using the @c LINK_DEPENDS obtained using the
2592 # basis_get_target_link_libraries() function. It determines the installation
2593 # location of each dependency using the basis_get_target_location() function.
2594 #
2595 # @returns Sets the @c INSTALL_RPATH property of the specified target.
2596 #
2597 # @sa basis_get_target_link_libraries()
2598 function (basis_set_target_install_rpath TARGET_NAME)
2599  basis_get_target_uid (TARGET_UID "${TARGET_NAME}")
2600  if (BASIS_VERBOSE)
2601  message (STATUS "Setting INSTALL_RPATH property of ${TARGET_UID}...")
2602  endif ()
2603  if (NOT TARGET "${TARGET_UID}")
2604  message (FATAL_ERROR "Unknown target: ${TARGET_UID}")
2605  endif ()
2606  if (BASIS_DEBUG)
2607  message ("** basis_set_target_install_rpath():")
2608  message ("** TARGET_NAME: ${TARGET_UID}")
2609  endif ()
2610  if (CMAKE_HOST_APPLE)
2611  set (ORIGIN "@loader_path")
2612  else ()
2613  set (ORIGIN "\$ORIGIN")
2614  endif ()
2615  # always prefer libraries located within the same directory
2616  set (INSTALL_RPATH "${ORIGIN}/.")
2617  # common default RPATH (rarely used)
2618  if (CMAKE_INSTALL_RPATH)
2619  set (INSTALL_RPATH "${INSTALL_RPATH};${CMAKE_INSTALL_RPATH}")
2620  endif ()
2621  # get location of target used to make paths relative to this $ORIGIN
2622  basis_get_target_location (TARGET_LOCATION ${TARGET_UID} POST_INSTALL_PATH)
2623  # directories of external projects belonging to same bundle which
2624  # were added using [basis_]link_directories() command
2625  basis_get_project_property (BUNDLE_LINK_DIRS PROPERTY BUNDLE_LINK_DIRS)
2626  foreach (LINK_DIR ${BUNDLE_LINK_DIRS})
2627  list (FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${LINK_DIR}" IDX)
2628  if (IDX EQUAL -1)
2629  if (BASIS_DEBUG AND BASIS_VERBOSE)
2630  message ("** BUNDLE_LINK_DIR: ${LINK_DIR}")
2631  endif ()
2632  basis_get_relative_path (RPATH "${TARGET_LOCATION}" "${LINK_DIR}")
2633  list (APPEND INSTALL_RPATH "${ORIGIN}/${RPATH}")
2634  endif ()
2635  endforeach ()
2636  # directories of link libraries
2637  #
2638  # only the libraries of this project and targets imported
2639  # from other projects which are part of the same bundle
2640  basis_get_target_link_libraries (LINK_DEPENDS ${TARGET_UID})
2641  if (BASIS_DEBUG AND BASIS_VERBOSE)
2642  message ("** LINK_DEPENDS: [${LINK_DEPENDS}]")
2643  endif ()
2644  foreach (LINK_DEPEND ${LINK_DEPENDS})
2645  set (DEPEND_LOCATION)
2646  if (TARGET "${LINK_DEPEND}")
2647  basis_get_target_type (LINK_TYPE ${LINK_DEPEND})
2648  if ("^${LINK_TYPE}$" STREQUAL "^SHARED_LIBRARY$")
2649  basis_get_target_property (BUNDLED ${LINK_DEPEND} BUNDLED)
2650  basis_get_target_property (IMPORTED ${LINK_DEPEND} IMPORTED)
2651  if (NOT IMPORTED OR BUNDLED)
2652  basis_get_target_location (DEPEND_LOCATION ${LINK_DEPEND} POST_INSTALL_PATH)
2653  if (BASIS_DEBUG AND BASIS_VERBOSE)
2654  message ("** LOCATION(${LINK_DEPEND}): ${DEPEND_LOCATION}")
2655  endif ()
2656  endif ()
2657  endif ()
2658  elseif (IS_ABSOLUTE "${LINK_DEPEND}")
2659  if (IS_DIRECTORY "${LINK_DEPEND}")
2660  set (DEPEND_LOCATION "${LINK_DEPEND}")
2661  else ()
2662  get_filename_component (DEPEND_LOCATION "${LINK_DEPEND}" PATH)
2663  endif ()
2664  list (FIND BUNDLE_LINK_DIRS "${DEPEND_LOCATION}" IDX)
2665  if (IDX EQUAL -1)
2666  set (DEPEND_LOCATION)
2667  endif ()
2668  endif ()
2669  if (DEPEND_LOCATION)
2670  list (FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${DEPEND_LOCATION}" IDX)
2671  if (IDX EQUAL -1)
2672  basis_get_relative_path (RPATH "${TARGET_LOCATION}" "${DEPEND_LOCATION}")
2673  list (APPEND INSTALL_RPATH "${ORIGIN}/${RPATH}")
2674  endif ()
2675  endif ()
2676  endforeach ()
2677  # remove duplicates
2678  if (INSTALL_RPATH)
2679  list (REMOVE_DUPLICATES INSTALL_RPATH)
2680  endif ()
2681  # set INSTALL_RPATH property
2682  set_target_properties (${TARGET_UID} PROPERTIES INSTALL_RPATH "${INSTALL_RPATH}")
2683  if (BASIS_DEBUG)
2684  message ("** INSTALL_RPATH: [${INSTALL_RPATH}]")
2685  endif ()
2686  if (BASIS_VERBOSE)
2687  message (STATUS "Setting INSTALL_RPATH property of ${TARGET_UID}... - done")
2688  endif ()
2689 endfunction ()
2690 
2691 # ----------------------------------------------------------------------------
2692 ## @brief Add custom command for build of single script.
2693 #
2694 # This function is called by basis_finalize_targets() which in turn is called
2695 # by basis_project_end(), i.e., the end of the root CMake configuration file
2696 # of the (sub-)project.
2697 #
2698 # @param [in] TARGET_UID Name/UID of custom target added by basis_add_script().
2699 #
2700 # @sa basis_add_script()
2701 function (basis_build_script TARGET_UID)
2702  # does this target exist ?
2703  basis_get_target_uid (TARGET_UID "${TARGET_UID}")
2704  if (NOT TARGET "${TARGET_UID}")
2705  message (FATAL_ERROR "Unknown build target: ${TARGET_UID}")
2706  endif ()
2707  if (BASIS_VERBOSE)
2708  message (STATUS "Adding build command for target ${TARGET_UID}...")
2709  endif ()
2710  # get target properties
2711  basis_get_target_link_libraries (LINK_DEPENDS ${TARGET_UID}) # paths of script modules/packages
2712  # including BASIS utilities if used
2713  set (
2714  PROPERTIES
2715  LANGUAGE # programming language of script
2716  BASIS_TYPE # must match "^SCRIPT_(EXECUTABLE|LIBEXEC|MODULE)$"
2717  BUILD_DIRECTORY # CMakeFiles build directory
2718  SOURCE_DIRECTORY # CMake source directory
2719  BINARY_DIRECTORY # CMake binary directory
2720  OUTPUT_DIRECTORY # output directory for built script
2721  INSTALL_DIRECTORY # installation directory for built script
2722  COMPONENT # installation component
2723  OUTPUT_NAME # name of built script including extension (if any)
2724  PREFIX # name prefix
2725  SUFFIX # name suffix (e.g., extension for executable script)
2726  SCRIPT_DEFINITIONS # CMake code to set variables used to configure script
2727  SCRIPT_DEFINITIONS_FILE # script configuration file
2728  EXPORT # whether this target shall be exported
2729  COMPILE # whether to compile script if applicable
2730  SOURCES # path of script source file
2731  )
2732  get_target_property (IS_TEST ${TARGET_UID} TEST) # whether this script is used for testing only
2733  foreach (PROPERTY ${PROPERTIES})
2734  get_target_property (${PROPERTY} ${TARGET_UID} ${PROPERTY})
2735  endforeach ()
2736  set (EXECUTABLE FALSE)
2737  set (LIBEXEC FALSE)
2738  set (MODULE FALSE)
2739  if (BASIS_TYPE MATCHES "^SCRIPT_(EXECUTABLE|LIBEXEC|MODULE)$")
2740  set (${CMAKE_MATCH_1} TRUE)
2741  if (LIBEXEC)
2742  set (EXECUTABLE TRUE)
2743  endif ()
2744  else ()
2745  message (FATAL_ERROR "Target ${TARGET_UID}: Unexpected BASIS_TYPE: ${BASIS_TYPE}")
2746  endif ()
2747  if (NOT BINARY_DIRECTORY)
2748  message (FATAL_ERROR "Target ${TARGET_UID}: Missing BINARY_DIRECTORY property!")
2749  endif ()
2750  file (RELATIVE_PATH _relpath "${CMAKE_BINARY_DIR}" "${BINARY_DIRECTORY}")
2751  if (_relpath MATCHES "^\\.\\./")
2752  message (FATAL_ERROR "Target ${TARGET_UID}: BINARY_DIRECTORY must be inside of build tree!")
2753  endif ()
2754  unset (_relpath)
2755  if (INSTALL_DIRECTORY AND NOT COMPONENT)
2756  set (COMPONENT "Unspecified")
2757  endif ()
2758  list (GET SOURCES 0 BUILD_DIR) # CMake <3.1 stores path to internal build directory here
2759  if (BUILD_DIR MATCHES "CMakeFiles")
2760  list (REMOVE_AT SOURCES 0)
2761  endif ()
2762  list (LENGTH SOURCES L)
2763  if (NOT L EQUAL 1)
2764  message (FATAL_ERROR "Target ${TARGET_UID}: Expected one element in SOURCES list!"
2765  " Have you modified this (read-only) property or is your"
2766  " (newer) CMake version not compatible with BASIS?")
2767  endif ()
2768  set (SOURCE_FILE "${SOURCES}")
2769  set (BUILD_DIR "${BUILD_DIRECTORY}.dir")
2770  # output directory and name
2771  if (NOT OUTPUT_NAME)
2772  basis_get_target_name (OUTPUT_NAME ${TARGET_UID})
2773  endif ()
2774  if (PREFIX)
2775  set (OUTPUT_NAME "${PREFIX}${OUTPUT_NAME}")
2776  endif ()
2777  if (SUFFIX)
2778  set (OUTPUT_NAME "${OUTPUT_NAME}${SUFFIX}")
2779  endif ()
2780  if (CMAKE_GENERATOR MATCHES "Visual Studio|Xcode")
2781  set (OUTPUT_FILE "${BUILD_DIR}/build/${OUTPUT_NAME}")
2782  set (OUTPUT_DIR "${OUTPUT_DIRECTORY}/$<${BASIS_GE_CONFIG}>")
2783  elseif (MODULE AND COMPILE)
2784  set (OUTPUT_FILE "${BUILD_DIR}/build/${OUTPUT_NAME}")
2785  set (OUTPUT_DIR "${OUTPUT_DIRECTORY}")
2786  else ()
2787  set (OUTPUT_FILE "${OUTPUT_DIRECTORY}/${OUTPUT_NAME}")
2788  unset (OUTPUT_DIR)
2789  endif ()
2790  # arguments of build script
2791  if (INSTALL_DIRECTORY)
2792  if (MODULE)
2793  get_filename_component (SOURCE_NAME "${SOURCE_FILE}" NAME)
2794  set (INSTALL_FILE "${BUILD_DIR}/install/${SOURCE_NAME}")
2795  string (REGEX REPLACE "\\.in$" "" INSTALL_FILE "${INSTALL_FILE}")
2796  else ()
2797  set (INSTALL_FILE "${BUILD_DIR}/install/${OUTPUT_NAME}")
2798  endif ()
2799  set (DESTINATION "${INSTALL_DIRECTORY}")
2800  if (NOT IS_ABSOLUTE "${DESTINATION}")
2801  set (DESTINATION "${CMAKE_INSTALL_PREFIX}/${DESTINATION}")
2802  endif ()
2803  else ()
2804  set (INSTALL_FILE)
2805  set (DESTINATION)
2806  endif ()
2807  set (CONFIG_FILES)
2808  if (EXISTS "${BASIS_SCRIPT_CONFIG_FILE}")
2809  list (APPEND CONFIG_FILES "${BASIS_SCRIPT_CONFIG_FILE}")
2810  endif ()
2811  if (SCRIPT_DEFINITIONS_FILE)
2812  list (APPEND CONFIG_FILES "${SCRIPT_DEFINITIONS_FILE}")
2813  endif ()
2814  if (SCRIPT_DEFINITIONS)
2815  set (SCRIPT_CONFIG_FILE "${BUILD_DIR}/ScriptConfig.cmake")
2816  file (WRITE "${SCRIPT_CONFIG_FILE}.tmp" "# DO NOT edit. Automatically generated by BASIS.\n${SCRIPT_DEFINITIONS}\n")
2817  execute_process (COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${SCRIPT_CONFIG_FILE}.tmp" "${SCRIPT_CONFIG_FILE}")
2818  file (REMOVE "${SCRIPT_CONFIG_FILE}.tmp")
2819  list (APPEND CONFIG_FILES "${SCRIPT_CONFIG_FILE}")
2820  endif ()
2821  set (CACHE_FILE "${BUILD_DIR}/cache.cmake")
2822  execute_process (COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CACHE_FILE}.tmp" "${CACHE_FILE}")
2823  file (REMOVE "${CACHE_FILE}.tmp")
2824  set (OPTIONS)
2825  foreach (FLAG IN ITEMS COMPILE EXECUTABLE)
2826  if (${FLAG})
2827  list (APPEND OPTIONS ${FLAG})
2828  endif ()
2829  endforeach ()
2830  # link dependencies - module search paths
2831  set (BUILD_LINK_DEPENDS)
2832  set (INSTALL_LINK_DEPENDS)
2833  foreach (LINK_DEPEND IN LISTS LINK_DEPENDS)
2834  basis_get_target_uid (UID "${LINK_DEPEND}")
2835  if (TARGET "${UID}")
2836  get_target_property (IMPORTED ${UID} IMPORTED)
2837  get_target_property (BUNDLED ${UID} BUNDLED)
2838  if (IMPORTED AND NOT BUNDLED)
2839  basis_get_target_location (LOCATION "${UID}" ABSOLUTE)
2840  if (LOCATION)
2841  list (APPEND BUILD_LINK_DEPENDS "${LOCATION}")
2842  list (APPEND INSTALL_LINK_DEPENDS "${LOCATION}")
2843  else ()
2844  message (WARNING "Could not determine build tree location of file corresponding to target ${UID}")
2845  endif ()
2846  else ()
2847  basis_get_target_location (LOCATION "${UID}" ABSOLUTE)
2848  if (LOCATION)
2849  list (APPEND BUILD_LINK_DEPENDS "${LOCATION}")
2850  else ()
2851  message (WARNING "Could not determine build tree location of file corresponding to target ${UID}")
2852  endif ()
2853  basis_get_target_property (LINK_DEPEND_IS_TEST "${UID}" TEST)
2854  if (NOT LINK_DEPEND_IS_TEST)
2855  basis_get_target_location (LOCATION "${UID}" POST_INSTALL)
2856  if (LOCATION)
2857  list (APPEND INSTALL_LINK_DEPENDS "relative ${LOCATION}")
2858  else ()
2859  message (WARNING "Could not determine installation location of file corresponding to target ${UID}")
2860  endif ()
2861  endif ()
2862  endif ()
2863  else ()
2864  list (APPEND BUILD_LINK_DEPENDS "${LINK_DEPEND}")
2865  list (APPEND INSTALL_LINK_DEPENDS "${LINK_DEPEND}")
2866  endif ()
2867  endforeach ()
2868  # prepend own module search paths - if dependencies among own modules
2869  # not specified or to ensure that
2870  # these are preferred
2871  if (LANGUAGE MATCHES "JYTHON")
2873  list (INSERT BUILD_LINK_DEPENDS 0 "${BINARY_PYTHON_LIBRARY_DIR}")
2874  endif ()
2876  list (INSERT INSTALL_LINK_DEPENDS 0 "relative ${CMAKE_INSTALL_PREFIX}/${INSTALL_PYTHON_LIBRARY_DIR}")
2877  endif ()
2878  endif ()
2879  if (BINARY_${LANGUAGE}_LIBRARY_DIR)
2880  list (INSERT BUILD_LINK_DEPENDS 0 "${BINARY_${LANGUAGE}_LIBRARY_DIR}")
2881  endif ()
2882  if (INSTALL_${LANGUAGE}_LIBRARY_DIR)
2883  list (INSERT INSTALL_LINK_DEPENDS 0 "relative ${CMAKE_INSTALL_PREFIX}/${INSTALL_${LANGUAGE}_LIBRARY_DIR}")
2884  endif ()
2885  list (INSERT BUILD_LINK_DEPENDS 0 "${BINARY_LIBRARY_DIR}")
2886  list (INSERT INSTALL_LINK_DEPENDS 0 "relative ${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBRARY_DIR}")
2887  if (IS_TEST)
2888  list (INSERT BUILD_LINK_DEPENDS 0 "${TESTING_LIBRARY_DIR}")
2889  endif ()
2890  if (BUILD_LINK_DEPENDS)
2891  list (REMOVE_DUPLICATES BUILD_LINK_DEPENDS)
2892  endif ()
2893  if (INSTALL_LINK_DEPENDS)
2894  list (REMOVE_DUPLICATES INSTALL_LINK_DEPENDS)
2895  endif ()
2896  # remove default site-packages directories
2897  if (LANGUAGE MATCHES "[JP]YTHON|PERL")
2898  list (REMOVE_ITEM BUILD_LINK_DEPENDS "${${LANGUAGE}_SITELIB}")
2899  list (REMOVE_ITEM INSTALL_LINK_DEPENDS "${${LANGUAGE}_SITELIB}")
2900  endif ()
2901  # configure build script
2902  set (BUILD_SCRIPT "${BUILD_DIR}/build.cmake")
2903  configure_file ("${BASIS_MODULE_PATH}/configure_script.cmake.in" "${BUILD_SCRIPT}" @ONLY)
2904  # list of all output files
2905  set (OUTPUT_FILES "${OUTPUT_FILE}")
2906  if (INSTALL_FILE)
2907  list (APPEND OUTPUT_FILES "${INSTALL_FILE}")
2908  endif ()
2909  if (MODULE AND COMPILE)
2910  basis_get_compiled_file (OUTPUT_CFILE "${OUTPUT_FILE}" ${LANGUAGE})
2911  basis_get_compiled_file (INSTALL_CFILE "${INSTALL_FILE}" ${LANGUAGE})
2912  if (OUTPUT_CFILE)
2913  list (APPEND OUTPUT_FILES "${OUTPUT_CFILE}")
2914  endif ()
2915  if (INSTALL_CFILE)
2916  list (APPEND OUTPUT_FILES "${INSTALL_CFILE}")
2917  endif ()
2918  if (LANGUAGE MATCHES "PYTHON")
2920  if (RV)
2921  basis_get_compiled_jython_file_of_python_module (JYTHON_OUTPUT_CFILE "${OUTPUT_FILE}")
2922  basis_get_compiled_file (JYTHON_INSTALL_CFILE "${INSTALL_FILE}" JYTHON)
2923  if (JYTHON_OUTPUT_CFILE)
2924  list (APPEND OUTPUT_FILES "${JYTHON_OUTPUT_CFILE}")
2925  endif ()
2926  if (JYTHON_INSTALL_CFILE)
2927  list (APPEND OUTPUT_FILES "${JYTHON_INSTALL_CFILE}")
2928  endif ()
2929  endif ()
2930  endif ()
2931  endif ()
2932  # add build command for script
2933  if (OUTPUT_CFILE)
2934  file (RELATIVE_PATH REL "${CMAKE_BINARY_DIR}" "${OUTPUT_CFILE}")
2935  else ()
2936  file (RELATIVE_PATH REL "${CMAKE_BINARY_DIR}" "${OUTPUT_FILE}")
2937  endif ()
2938  if (LANGUAGE MATCHES "UNKNOWN")
2939  set (COMMENT "Building script ${REL}...")
2940  elseif (MODULE)
2941  set (COMMENT "Building ${LANGUAGE} module ${REL}...")
2942  else ()
2943  set (COMMENT "Building ${LANGUAGE} executable ${REL}...")
2944  endif ()
2945  add_custom_command (
2946  OUTPUT ${OUTPUT_FILES}
2947  COMMAND "${CMAKE_COMMAND}" -D "CONFIGURATION:STRING=$<${BASIS_GE_CONFIG}>" -P "${BUILD_SCRIPT}"
2948  MAIN_DEPENDENCY "${SOURCE_FILE}"
2949  DEPENDS "${BUILD_SCRIPT}" "${BASIS_MODULE_PATH}/CommonTools.cmake" # basis_configure_script() definition
2950  COMMENT "${COMMENT}"
2951  VERBATIM
2952  )
2953  # add custom target
2954  add_custom_target (_${TARGET_UID} DEPENDS ${OUTPUT_FILES})
2955  foreach (T IN LISTS LINK_DEPENDS)
2956  if (TARGET ${T})
2957  add_dependencies (_${TARGET_UID} ${T})
2958  endif ()
2959  endforeach ()
2960  add_dependencies (${TARGET_UID} _${TARGET_UID})
2961  # cleanup on "make clean" - including compiled files regardless of COMPILE flag
2962  set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${OUTPUT_FILES})
2963  foreach (OUTPUT_FILE IN LISTS OUTPUT_FILES)
2964  basis_get_compiled_file (CFILE "${OUTPUT_FILE}" ${LANGUAGE})
2965  if (CFILE)
2966  list (FIND OUTPUT_FILES "${CFILE}" IDX)
2967  if (IDX EQUAL -1)
2968  set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${CFILE}")
2969  endif ()
2970  endif ()
2971  endforeach ()
2972  # copy configured (and compiled) script to (configuration specific) output directory
2973  if (OUTPUT_DIR)
2974  if (OUTPUT_CFILE)
2975  get_filename_component (OUTPUT_CNAME "${OUTPUT_CFILE}" NAME)
2976  add_custom_command (
2977  TARGET _${TARGET_UID} POST_BUILD
2978  COMMAND "${CMAKE_COMMAND}" -E copy "${OUTPUT_CFILE}" "${OUTPUT_DIR}/${OUTPUT_CNAME}"
2979  )
2980  set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${OUTPUT_DIR}/${OUTPUT_CNAME}")
2981  if (JYTHON_OUTPUT_CFILE)
2982  get_filename_component (OUTPUT_CNAME "${JYTHON_OUTPUT_CFILE}" NAME)
2983  add_custom_command (
2984  TARGET _${TARGET_UID} POST_BUILD
2985  COMMAND "${CMAKE_COMMAND}" -E copy "${JYTHON_OUTPUT_CFILE}" "${OUTPUT_DIR}/${OUTPUT_CNAME}"
2986  )
2987  set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${OUTPUT_DIR}/${OUTPUT_CNAME}")
2988  endif ()
2989  else ()
2990  add_custom_command (
2991  TARGET _${TARGET_UID} POST_BUILD
2992  COMMAND "${CMAKE_COMMAND}" -E copy "${OUTPUT_FILE}" "${OUTPUT_DIR}/${OUTPUT_NAME}"
2993  )
2994  set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${OUTPUT_DIR}/${OUTPUT_NAME}")
2995  endif ()
2996  endif ()
2997  # export target
2998  if (EXPORT)
2999  basis_add_custom_export_target (${TARGET_UID} "${IS_TEST}")
3000  endif ()
3001  # install script
3002  if (INSTALL_DIRECTORY)
3003  if (INSTALL_CFILE)
3004  if (MODULE AND LANGUAGE MATCHES "PYTHON")
3006  if (RV)
3007  basis_get_compiled_script (INSTALL_JYTHON_CFILE "${INSTALL_FILE}" JYTHON)
3008  basis_sanitize_for_regex (LIBRE "${INSTALL_PYTHON_LIBRARY_DIR}")
3009  basis_sanitize_for_regex (SITERE "${INSTALL_PYTHON_SITE_DIR}")
3010  if (INSTALL_CFILE MATCHES "^${LIBRE}/" AND INSTALL_JYTHON_LIBRARY_DIR)
3011  string (REGEX REPLACE "^${LIBRE}/" "${INSTALL_JYTHON_LIBRARY_DIR}/" INSTALL_DIRECTORY_JYTHON "${INSTALL_DIRECTORY}")
3012  elseif (INSTALL_CFILE MATCHES "^${SITERE}/" AND INSTALL_JYTHON_SITE_DIR)
3013  string (REGEX REPLACE "^${SITERE}/" "${INSTALL_JYTHON_SITE_DIR}/" INSTALL_DIRECTORY_JYTHON "${INSTALL_DIRECTORY}")
3014  else ()
3015  set (INSTALL_DIRECTORY_JYTHON "${INSTALL_DIRECTORY}")
3016  endif ()
3017  install (
3018  FILES "${INSTALL_JYTHON_CFILE}"
3019  DESTINATION "${INSTALL_DIRECTORY_JYTHON}"
3020  COMPONENT "${COMPONENT}"
3021  )
3022  endif ()
3023  endif ()
3024  set (INSTALL_FILE "${INSTALL_CFILE}")
3025  elseif (NOT INSTALL_FILE)
3026  set (INSTALL_FILE "${OUTPUT_FILE}")
3027  endif ()
3028  if (MODULE)
3029  set (INSTALLTYPE FILES)
3030  else ()
3031  set (INSTALLTYPE PROGRAMS)
3032  endif ()
3033  install (
3034  ${INSTALLTYPE} "${INSTALL_FILE}"
3035  DESTINATION "${INSTALL_DIRECTORY}"
3036  COMPONENT "${COMPONENT}"
3037  RENAME "${OUTPUT_NAME}"
3038  )
3039  endif ()
3040  # done
3041  if (BASIS_VERBOSE)
3042  message (STATUS "Adding build command for target ${TARGET_UID}... - done")
3043  endif ()
3044 endfunction ()
3045 
3046 # ----------------------------------------------------------------------------
3047 ## @brief Add custom command for build of script library.
3048 #
3049 # This function is called by basis_finalize_targets() which in turn is called
3050 # by basis_project_end(), i.e., the end of the root CMake configuration file
3051 # of the (sub-)project.
3052 #
3053 # @param [in] TARGET_UID Name/UID of custom target added by basis_add_script_library().
3054 #
3055 # @sa basis_add_script_library()
3056 function (basis_build_script_library TARGET_UID)
3057  # does this target exist ?
3058  basis_get_target_uid (TARGET_UID "${TARGET_UID}")
3059  if (NOT TARGET "${TARGET_UID}")
3060  message (FATAL_ERROR "Unknown target: ${TARGET_UID}")
3061  endif ()
3062  if (BASIS_VERBOSE)
3063  message (STATUS "Adding build command for target ${TARGET_UID}...")
3064  endif ()
3065  # get target properties
3066  basis_get_target_link_libraries (LINK_DEPENDS ${TARGET_UID}) # paths of script modules/packages
3067  # including BASIS utilities if used
3068  set (
3069  PROPERTIES
3070  LANGUAGE # programming language of modules
3071  BASIS_TYPE # must be "SCRIPT_LIBRARY"
3072  BASIS_UTILITIES # whether this target requires the BASIS utilities
3073  BUILD_DIRECTORY # CMakeFiles build directory
3074  SOURCE_DIRECTORY # CMake source directory
3075  BINARY_DIRECTORY # CMake binary directory
3076  LIBRARY_OUTPUT_DIRECTORY # output directory for built modules
3077  LIBRARY_INSTALL_DIRECTORY # installation directory for built modules
3078  LIBRARY_COMPONENT # installation component
3079  PREFIX # common prefix for modules
3080  SCRIPT_DEFINITIONS # CMake code to set variables used to configure modules
3081  SCRIPT_DEFINITIONS_FILE # script configuration file
3082  LINK_DEPENDS # paths of script modules/packages used by the modules of this library
3083  EXPORT # whether to export this target
3084  COMPILE # whether to compile the modules/library if applicable
3085  SOURCES # source files of module scripts
3086  )
3087  get_target_property (IS_TEST ${TARGET_UID} TEST) # whether this script is used for testing only
3088  foreach (PROPERTY ${PROPERTIES})
3089  get_target_property (${PROPERTY} ${TARGET_UID} ${PROPERTY})
3090  endforeach ()
3091  if (NOT BASIS_TYPE MATCHES "^SCRIPT_LIBRARY$")
3092  message (FATAL_ERROR "Target ${TARGET_UID}: Unexpected BASIS_TYPE: ${BASIS_TYPE}")
3093  endif ()
3094  if (NOT SOURCE_DIRECTORY)
3095  message (FATAL_ERROR "Missing SOURCE_DIRECTORY property!")
3096  endif ()
3097  if (NOT LIBRARY_OUTPUT_DIRECTORY)
3098  message (FATAL_ERROR "Missing LIBRARY_OUTPUT_DIRECTORY property!")
3099  endif ()
3100  if (NOT IS_ABSOLUTE "${LIBRARY_OUTPUT_DIRECTORY}")
3101  set (LIBRARY_OUTPUT_DIRECTORY "${TOPLEVEL_PROJECT_BINARY_DIR}/${LIBRARY_OUTPUT_DIRECTORY}")
3102  endif ()
3103  file (RELATIVE_PATH _relpath "${CMAKE_BINARY_DIR}" "${LIBRARY_OUTPUT_DIRECTORY}")
3104  if (_relpath MATCHES "^\\.\\./")
3105  message (FATAL_ERROR "Output directory LIBRARY_OUTPUT_DIRECTORY is outside the build tree!")
3106  endif ()
3107  unset(_relpath)
3108  if (NOT LIBRARY_COMPONENT)
3109  set (LIBRARY_COMPONENT "Unspecified")
3110  endif ()
3111  list (GET SOURCES 0 BUILD_DIR) # CMake <3.1 stores path to internal build directory here
3112  if (BUILD_DIR MATCHES "CMakeFiles")
3113  list (REMOVE_AT SOURCES 0)
3114  endif ()
3115  if (NOT SOURCES)
3116  message (FATAL_ERROR "Target ${TARGET_UID}: Expected at least one element in SOURCES list!"
3117  " Have you incorrectly modified this (read-only) property or"
3118  " is your (newer) CMake version not compatible with BASIS?")
3119  endif ()
3120  set (BUILD_DIR "${BUILD_DIRECTORY}.dir")
3121  # common arguments of build script
3122  set (CONFIG_FILES)
3123  if (EXISTS "${BASIS_SCRIPT_CONFIG_FILE}")
3124  list (APPEND CONFIG_FILES "${BASIS_SCRIPT_CONFIG_FILE}")
3125  endif ()
3126  if (SCRIPT_DEFINITIONS_FILE)
3127  list (APPEND CONFIG_FILES ${SCRIPT_DEFINITIONS_FILE})
3128  endif ()
3129  if (SCRIPT_DEFINITIONS)
3130  set (SCRIPT_CONFIG_FILE "${BUILD_DIR}/ScriptConfig.cmake")
3131  file (WRITE "${SCRIPT_CONFIG_FILE}.tmp" "# DO NOT edit. Automatically generated by BASIS.\n${SCRIPT_DEFINITIONS}\n")
3132  execute_process (COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${SCRIPT_CONFIG_FILE}.tmp" "${SCRIPT_CONFIG_FILE}")
3133  file (REMOVE "${SCRIPT_CONFIG_FILE}.tmp")
3134  list (APPEND CONFIG_FILES "${SCRIPT_CONFIG_FILE}")
3135  endif ()
3136  set (CACHE_FILE "${BUILD_DIR}/cache.cmake")
3137  execute_process (COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CACHE_FILE}.tmp" "${CACHE_FILE}")
3138  file (REMOVE "${CACHE_FILE}.tmp")
3139  set (OPTIONS) # no additional options
3140  if (COMPILE)
3141  list (APPEND OPTIONS COMPILE)
3142  endif ()
3143  # add build command for each module
3144  set (OUTPUT_FILES) # list of all output files
3145  set (FILES_TO_COPY) # relative paths of build tree modules
3146  set (FILES_TO_INSTALL) # list of output files for installation
3147  set (BINARY_INSTALL_DIRECTORY "${BUILD_DIR}/install") # common base directory for files to install
3148  if (COMPILE OR CMAKE_GENERATOR MATCHES "Visual Studio|Xcode") # post-build copy to <libdir>/<config>/
3149  set (BINARY_OUTPUT_DIRECTORY "${BUILD_DIR}/build") # common base directory for build tree files
3150  set (POST_BUILD_COPY TRUE)
3151  else ()
3152  set (BINARY_OUTPUT_DIRECTORY "${LIBRARY_OUTPUT_DIRECTORY}")
3153  set (POST_BUILD_COPY FALSE)
3154  endif ()
3155  foreach (SOURCE_FILE IN LISTS SOURCES)
3156  file (RELATIVE_PATH S "${SOURCE_DIRECTORY}" "${SOURCE_FILE}")
3157  string (REGEX REPLACE "\\.in$" "" S "${S}")
3158  basis_get_source_target_name (BUILD_SCRIPT_NAME "build_${S}")
3159  # arguments of build script
3160  if (PREFIX)
3161  set (S "${PREFIX}${S}")
3162  endif ()
3163  set (OUTPUT_FILE "${BINARY_OUTPUT_DIRECTORY}/${S}")
3164  get_filename_component (OUTPUT_DIR "${LIBRARY_OUTPUT_DIRECTORY}/${S}" PATH)
3165  if (LIBRARY_INSTALL_DIRECTORY)
3166  set (INSTALL_FILE "${BINARY_INSTALL_DIRECTORY}/${S}")
3167  set (DESTINATION "${LIBRARY_INSTALL_DIRECTORY}/${S}")
3168  if (NOT IS_ABSOLUTE "${DESTINATION}")
3169  set (DESTINATION "${CMAKE_INSTALL_PREFIX}/${DESTINATION}")
3170  endif ()
3171  get_filename_component (DESTINATION "${DESTINATION}" PATH)
3172  else ()
3173  set (INSTALL_FILE)
3174  set (DESTINATION)
3175  endif ()
3176  # configure build script
3177  set (BUILD_SCRIPT "${BUILD_DIR}/${BUILD_SCRIPT_NAME}.cmake")
3178  configure_file ("${BASIS_MODULE_PATH}/configure_script.cmake.in" "${BUILD_SCRIPT}" @ONLY)
3179  # output files of this command
3180  set (_OUTPUT_FILES "${OUTPUT_FILE}")
3181  if (INSTALL_FILE)
3182  list (APPEND _OUTPUT_FILES "${INSTALL_FILE}")
3183  endif ()
3184  if (COMPILE)
3185  basis_get_compiled_file (OUTPUT_CFILE "${OUTPUT_FILE}" ${LANGUAGE})
3186  basis_get_compiled_file (INSTALL_CFILE "${INSTALL_FILE}" ${LANGUAGE})
3187  if (OUTPUT_CFILE)
3188  list (APPEND _OUTPUT_FILES "${OUTPUT_CFILE}")
3189  endif ()
3190  if (INSTALL_CFILE)
3191  list (APPEND _OUTPUT_FILES "${INSTALL_CFILE}")
3192  endif ()
3193  if (LANGUAGE MATCHES "PYTHON")
3195  if (RV)
3196  basis_get_compiled_jython_file_of_python_module (JYTHON_OUTPUT_CFILE "${OUTPUT_FILE}")
3197  basis_get_compiled_file (JYTHON_INSTALL_CFILE "${INSTALL_FILE}" JYTHON)
3198  if (JYTHON_OUTPUT_CFILE)
3199  list (APPEND _OUTPUT_FILES "${JYTHON_OUTPUT_CFILE}")
3200  endif ()
3201  if (JYTHON_INSTALL_CFILE)
3202  list (APPEND _OUTPUT_FILES "${JYTHON_INSTALL_CFILE}")
3203  endif ()
3204  endif ()
3205  endif ()
3206  endif ()
3207  if (POST_BUILD_COPY)
3208  if (OUTPUT_CFILE)
3209  file (RELATIVE_PATH _file "${BINARY_OUTPUT_DIRECTORY}" "${OUTPUT_CFILE}")
3210  list (APPEND FILES_TO_COPY "${_file}")
3211  if (JYTHON_OUTPUT_CFILE)
3212  file (RELATIVE_PATH _file "${BINARY_OUTPUT_DIRECTORY}" "${JYTHON_OUTPUT_CFILE}")
3213  list (APPEND FILES_TO_COPY "${_file}")
3214  endif ()
3215  else ()
3216  list (APPEND FILES_TO_COPY "${S}")
3217  endif ()
3218  endif ()
3219  if (INSTALL_CFILE)
3220  list (APPEND FILES_TO_INSTALL "${INSTALL_CFILE}")
3221  elseif (INSTALL_FILE)
3222  list (APPEND FILES_TO_INSTALL "${INSTALL_FILE}")
3223  endif ()
3224  # add build command
3225  if (OUTPUT_CFILE)
3226  file (RELATIVE_PATH REL "${CMAKE_BINARY_DIR}" "${OUTPUT_CFILE}")
3227  else ()
3228  file (RELATIVE_PATH REL "${CMAKE_BINARY_DIR}" "${OUTPUT_FILE}")
3229  endif ()
3230  set (COMMENT "Building ${LANGUAGE} module ${REL}...")
3231  add_custom_command (
3232  OUTPUT ${_OUTPUT_FILES}
3233  COMMAND "${CMAKE_COMMAND}" -D "CONFIGURATION=$<${BASIS_GE_CONFIG}>" -P "${BUILD_SCRIPT}"
3234  MAIN_DEPENDENCY "${SOURCE_FILE}"
3235  DEPENDS "${BUILD_SCRIPT}" "${BASIS_MODULE_PATH}/CommonTools.cmake" # basis_configure_script() definition
3236  COMMENT "${COMMENT}"
3237  VERBATIM
3238  )
3239  # add output files of command to list of all output files
3240  list (APPEND OUTPUT_FILES ${_OUTPUT_FILES})
3241  endforeach ()
3242  # add custom target to build modules
3243  add_custom_target (_${TARGET_UID} DEPENDS ${OUTPUT_FILES})
3244  foreach (T IN LISTS LINK_DEPENDS)
3245  if (TARGET ${T})
3246  add_dependencies (_${TARGET_UID} ${T})
3247  endif ()
3248  endforeach ()
3249  add_dependencies (${TARGET_UID} _${TARGET_UID})
3250  # copy configured modules to output directory
3251  foreach (OUTPUT_FILE IN LISTS FILES_TO_COPY)
3252  add_custom_command (
3253  TARGET _${TARGET_UID} POST_BUILD
3254  COMMAND "${CMAKE_COMMAND}" -E copy "${BINARY_OUTPUT_DIRECTORY}/${OUTPUT_FILE}" "${LIBRARY_OUTPUT_DIRECTORY}/${OUTPUT_FILE}"
3255  )
3256  endforeach ()
3257  # cleanup on "make clean" - including compiled files regardless of COMPILE flag
3258  set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${OUTPUT_FILES})
3259  foreach (OUTPUT_FILE IN LISTS OUTPUT_FILES)
3260  basis_get_compiled_file (CFILE "${OUTPUT_FILE}" ${LANGUAGE})
3261  if (CFILE)
3262  list (FIND OUTPUT_FILES "${CFILE}" IDX)
3263  if (IDX EQUAL -1)
3264  set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${CFILE}")
3265  endif ()
3266  endif ()
3267  endforeach ()
3268  # export target
3269  if (EXPORT)
3270  basis_add_custom_export_target (${TARGET_UID} "${IS_TEST}")
3271  endif ()
3272  # add installation rule
3273  foreach (INSTALL_FILE IN LISTS FILES_TO_INSTALL)
3274  get_filename_component (D "${INSTALL_FILE}" PATH)
3275  file (RELATIVE_PATH D "${BINARY_INSTALL_DIRECTORY}" "${D}")
3276  install (
3277  FILES "${INSTALL_FILE}"
3278  DESTINATION "${LIBRARY_INSTALL_DIRECTORY}/${D}"
3279  COMPONENT "${LIBRARY_COMPONENT}"
3280  )
3281  if (LANGUAGE MATCHES "PYTHON" AND INSTALL_FILE MATCHES "\\.pyc$")
3283  if (RV)
3284  basis_sanitize_for_regex (LIBRE "${INSTALL_PYTHON_LIBRARY_DIR}")
3285  basis_sanitize_for_regex (SITERE "${INSTALL_PYTHON_SITE_DIR}")
3286  if (LIBRARY_INSTALL_DIRECTORY MATCHES "^${LIBRE}/*$")
3287  set (JYTHON_INSTALL_DIRECTORY "${INSTALL_JYTHON_LIBRARY_DIR}")
3288  elseif (LIBRARY_INSTALL_DIRECTORY MATCHES "^${SITERE}/*$")
3289  set (JYTHON_INSTALL_DIRECTORY "${INSTALL_JYTHON_SITE_DIR}")
3290  else ()
3291  set (JYTHON_INSTALL_DIRECTORY "${LIBRARY_INSTALL_DIRECTORY}")
3292  endif ()
3293  string (REGEX REPLACE "c$" "" SOURCE_FILE "${INSTALL_FILE}")
3294  basis_get_compiled_file (INSTALL_JYTHON_CFILE "${SOURCE_FILE}" JYTHON)
3295  install (
3296  FILES "${INSTALL_JYTHON_CFILE}"
3297  DESTINATION "${JYTHON_INSTALL_DIRECTORY}/${D}"
3298  COMPONENT "${LIBRARY_COMPONENT}"
3299  )
3300  endif ()
3301  endif ()
3302  endforeach ()
3303  # done
3304  if (BASIS_VERBOSE)
3305  message (STATUS "Adding build command for target ${TARGET_UID}... - done")
3306  endif ()
3307 endfunction ()
3308 
3309 # ----------------------------------------------------------------------------
3310 # @brief Add target to build/install __init__.py files.
3311 function (basis_add_init_py_target)
3312  if (NOT BASIS_PYTHON_TEMPLATES_DIR)
3313  message (WARNING "BASIS_PYTHON_TEMPLATES_DIR not set, skipping basis_add_init_py_target")
3314  return ()
3315  endif ()
3316  # constants
3317  set (BUILD_DIR "${PROJECT_BINARY_DIR}/CMakeFiles/_initpy.dir")
3318  basis_sanitize_for_regex (BINARY_PYTHON_LIBRARY_DIR_RE "${BINARY_PYTHON_LIBRARY_DIR}")
3319  basis_sanitize_for_regex (TESTING_PYTHON_LIBRARY_DIR_RE "${TESTING_PYTHON_LIBRARY_DIR}")
3320  basis_sanitize_for_regex (INSTALL_PYTHON_LIBRARY_DIR_RE "${INSTALL_PYTHON_LIBRARY_DIR}")
3321  basis_sanitize_for_regex (BINARY_JYTHON_LIBRARY_DIR_RE "${BINARY_JYTHON_LIBRARY_DIR}")
3322  basis_sanitize_for_regex (TESTING_JYTHON_LIBRARY_DIR_RE "${TESTING_JYTHON_LIBRARY_DIR}")
3323  basis_sanitize_for_regex (INSTALL_JYTHON_LIBRARY_DIR_RE "${INSTALL_JYTHON_LIBRARY_DIR}")
3324  # collect directories requiring a __init__.py file
3325  set (DEPENDENTS) # targets which generate Python/Jython modules and depend on _initpy
3326  set (PYTHON_DIRS) # Python library directories requiring a __init__.py file
3327  set (JYTHON_DIRS) # Jython library directories requiring a __init__.py file
3328  set (EXCLUDE) # exclude these directories
3329  set (INSTALL_EXCLUDE) # exclude these directories upon installation
3330  set (COMPONENTS) # installation components
3331  basis_get_project_property (TARGETS PROPERTY TARGETS)
3332  foreach (TARGET_UID IN LISTS TARGETS)
3333  get_target_property (BASIS_TYPE ${TARGET_UID} BASIS_TYPE)
3334  get_target_property (LANGUAGE ${TARGET_UID} LANGUAGE)
3335  if (BASIS_TYPE MATCHES "MODULE|LIBRARY" AND LANGUAGE MATCHES "^[JP]YTHON$")
3336  # get path of built Python modules
3337  basis_get_target_location (LOCATION ${TARGET_UID} ABSOLUTE)
3338  basis_get_target_location (INSTALL_LOCATION ${TARGET_UID} POST_INSTALL_RELATIVE)
3339  if (BASIS_TYPE MATCHES "^SCRIPT_LIBRARY$")
3340  get_target_property (PREFIX ${TARGET_UID} PREFIX)
3341  get_target_property (SOURCES ${TARGET_UID} SOURCES)
3342  get_target_property (SOURCE_DIRECTORY ${TARGET_UID} SOURCE_DIRECTORY)
3343  string (REGEX REPLACE "/+$" "" PREFIX "${PREFIX}")
3344  if (PREFIX)
3345  set (LOCATION "${LOCATION}/${PREFIX}")
3346  set (INSTALL_LOCATION "${INSTALL_LOCATION}/${PREFIX}")
3347  endif ()
3348  list (GET SOURCES 0 BINARY_DIR) # CMake <3.1 stores path to internal build directory here
3349  if (BINARY_DIR MATCHES "CMakeFiles")
3350  list (REMOVE_AT SOURCES 0)
3351  endif ()
3352  foreach (SOURCE IN LISTS SOURCES)
3353  file (RELATIVE_PATH SOURCE "${SOURCE_DIRECTORY}" "${SOURCE}")
3354  list (APPEND _LOCATION "${LOCATION}/${SOURCE}")
3355  list (APPEND _INSTALL_LOCATION "${INSTALL_LOCATION}/${SOURCE}")
3356  endforeach ()
3357  set (LOCATION "${_LOCATION}")
3358  set (INSTALL_LOCATION "${_INSTALL_LOCATION}")
3359  endif ()
3360  # get component (used by installation rule)
3361  get_target_property (COMPONENT ${TARGET_UID} "LIBRARY_COMPONENT")
3362  list (FIND COMPONENTS "${COMPONENT}" IDX)
3363  if (IDX EQUAL -1)
3364  list (APPEND COMPONENTS "${COMPONENT}")
3365  set (INSTALL_${LANGUAGE}_DIRS_${COMPONENT}) # list of directories for which to install
3366  # __init__.py for this component
3367  endif ()
3368  # directories for which to build a __init__.py file
3369  foreach (L IN LISTS LOCATION)
3370  basis_get_filename_component (DIR "${L}" PATH)
3371  if (L MATCHES "/__init__\\.py$")
3372  list (APPEND EXCLUDE "${DIR}")
3373  else ()
3374  list (APPEND DEPENDENTS ${TARGET_UID}) # depends on _initpy
3375  if (BINARY_${LANGUAGE}_LIBRARY_DIR_RE AND DIR MATCHES "^${BINARY_${LANGUAGE}_LIBRARY_DIR_RE}/.+")
3376  while (NOT "${DIR}" MATCHES "^${BINARY_${LANGUAGE}_LIBRARY_DIR_RE}$")
3377  list (APPEND ${LANGUAGE}_DIRS "${DIR}")
3378  get_filename_component (DIR "${DIR}" PATH)
3379  endwhile ()
3380  elseif (TESTING_${LANGUAGE}_LIBRARY_DIR_RE AND DIR MATCHES "^${TESTING_${LANGUAGE}_LIBRARY_DIR_RE}/.+")
3381  while (NOT "${DIR}" MATCHES "^${TESTING_${LANGUAGE}_LIBRARY_DIR_RE}$")
3382  list (APPEND ${LANGUAGE}_DIRS "${DIR}")
3383  get_filename_component (DIR "${DIR}" PATH)
3384  endwhile ()
3385  endif ()
3386  endif ()
3387  endforeach ()
3388  # directories for which to install a __init__.py file
3389  foreach (L IN LISTS INSTALL_LOCATION)
3390  basis_get_filename_component (DIR "${L}" PATH)
3391  if (L MATCHES "/__init__\\.py$")
3392  list (APPEND INSTALL_EXCLUDE "${DIR}")
3393  else ()
3394  list (APPEND DEPENDENTS ${TARGET_UID}) # depends on _initpy
3395  if (INSTALL_${LANGUAGE}_LIBRARY_DIR_RE AND DIR MATCHES "^${INSTALL_${LANGUAGE}_LIBRARY_DIR_RE}/.+")
3396  while (NOT "${DIR}" MATCHES "^${INSTALL_${LANGUAGE}_LIBRARY_DIR_RE}$")
3397  list (APPEND INSTALL_${LANGUAGE}_DIRS_${COMPONENT} "${DIR}")
3398  if (BASIS_COMPILE_SCRIPTS AND LANGUAGE MATCHES "PYTHON")
3400  if (RV)
3401  if (INSTALL_JYTHON_LIBRARY_DIR)
3402  file (RELATIVE_PATH REL "${CMAKE_INSTALL_PREFIX}/${INSTALL_PYTHON_LIBRARY_DIR}" "${CMAKE_INSTALL_PREFIX}/${DIR}")
3403  else ()
3404  set (REL)
3405  endif ()
3406  if (NOT REL MATCHES "^$|^\\.\\./")
3407  list (APPEND INSTALL_JYTHON_DIRS_${COMPONENT} "${INSTALL_JYTHON_LIBRARY_DIR}/${REL}")
3408  endif ()
3409  endif ()
3410  endif ()
3411  get_filename_component (DIR "${DIR}" PATH)
3412  endwhile ()
3413  endif ()
3414  endif ()
3415  endforeach ()
3416  endif ()
3417  endforeach ()
3418  if (DEPENDENTS)
3419  list (REMOVE_DUPLICATES DEPENDENTS)
3420  endif ()
3421  # return if nothing to do
3422  if (NOT PYTHON_DIRS AND NOT JYTHON_DIRS)
3423  return ()
3424  endif ()
3425  if (PYTHON_DIRS)
3426  list (REMOVE_DUPLICATES PYTHON_DIRS)
3427  endif ()
3428  if (JYTHON_DIRS)
3429  list (REMOVE_DUPLICATES JYTHON_DIRS)
3430  endif ()
3431  if (EXCLUDE)
3432  list (REMOVE_DUPLICATES EXCLUDE)
3433  endif ()
3434  if (INSTALL_EXCLUDE)
3435  list (REMOVE_DUPLICATES INSTALL_EXCLUDE)
3436  endif ()
3437  # generate build script
3438  set (PYTHON_COMPILED_FILES "${CFILE}")
3439  set (JYTHON_COMPILED_FILES "${CFILE}")
3440  set (C "configure_file (\"${BASIS_PYTHON_TEMPLATES_DIR}/__init__.py.in\" \"${BUILD_DIR}/__init__.py\" @ONLY)\n")
3441  foreach (LANGUAGE IN ITEMS PYTHON JYTHON) # Python *must* come first. See JYTHON_COMPILED_FILES list.
3442  set (${LANGUAGE}_OUTPUT_FILES)
3443  set (${LANGUAGE}_INSTALL_FILE "${BUILD_DIR}/__init__.py")
3444  set (C "${C}\nset (${LANGUAGE}_EXECUTABLE \"${${LANGUAGE}_EXECUTABLE}\")\n\n")
3445  foreach (DIR IN LISTS ${LANGUAGE}_DIRS)
3446  list (FIND EXCLUDE "${DIR}" IDX)
3447  if (IDX EQUAL -1)
3448  set (C "${C}configure_file (\"${BASIS_PYTHON_TEMPLATES_DIR}/__init__.py.in\" \"${DIR}/__init__.py\" @ONLY)\n")
3449  list (APPEND ${LANGUAGE}_OUTPUT_FILES "${DIR}/__init__.py")
3450  endif ()
3451  endforeach ()
3452  if (BASIS_COMPILE_SCRIPTS AND ${LANGUAGE}_EXECUTABLE)
3453  set (C "${C}\n")
3454  string (TOLOWER "${LANGUAGE}" language)
3455  basis_get_compiled_file (CFILE "${BUILD_DIR}/${language}/__init__.py" ${LANGUAGE})
3456  set (C "${C}file (MAKE_DIRECTORY \"${BUILD_DIR}/${language}\")\n")
3457  set (C "${C}execute_process (COMMAND \"${${LANGUAGE}_EXECUTABLE}\" -c \"import py_compile; py_compile.compile('${BUILD_DIR}/__init__.py', '${CFILE}')\")\n")
3458  set (${LANGUAGE}_INSTALL_FILE "${CFILE}")
3459  set (C "${C}\n")
3460  foreach (SFILE IN LISTS ${LANGUAGE}_OUTPUT_FILES)
3461  basis_get_compiled_file (CFILE "${SFILE}" ${LANGUAGE})
3462  set (C "${C}execute_process (COMMAND \"${${LANGUAGE}_EXECUTABLE}\" -c \"import py_compile; py_compile.compile('${SFILE}', '${CFILE}')\")\n")
3463  list (APPEND ${LANGUAGE}_COMPILED_FILES "${CFILE}")
3464  if (LANGUAGE MATCHES "PYTHON")
3466  if (RV)
3468  file (RELATIVE_PATH REL "${BINARY_PYTHON_LIBRARY_DIR}" "${SFILE}")
3469  else ()
3470  set (REL)
3471  endif ()
3472  if (NOT REL MATCHES "^$|^\\.\\./")
3473  basis_get_compiled_file (CFILE "${BINARY_JYTHON_LIBRARY_DIR}/${REL}" JYTHON)
3474  else ()
3475  basis_get_compiled_file (CFILE "${SFILE}" JYTHON)
3476  endif ()
3477  get_filename_component (CDIR "${CFILE}" PATH)
3478  set (C "${C}file (MAKE_DIRECTORY \"${CDIR}\")\n")
3479  set (C "${C}execute_process (COMMAND \"${JYTHON_EXECUTABLE}\" -c \"import py_compile; py_compile.compile('${SFILE}', '${CFILE}')\")\n")
3480  list (APPEND JYTHON_COMPILED_FILES "${CFILE}")
3481  endif ()
3482  endif ()
3483  endforeach ()
3484  list (APPEND ${LANGUAGE}_OUTPUT_FILES ${${LANGUAGE}_COMPILED_FILES})
3485  endif ()
3486  endforeach ()
3487  # write/update build script
3488  set (BUILD_SCRIPT "${BUILD_DIR}/build.cmake")
3489  if (EXISTS "${BUILD_SCRIPT}")
3490  file (WRITE "${BUILD_SCRIPT}.tmp" "${C}")
3491  execute_process (COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${BUILD_SCRIPT}.tmp" "${BUILD_SCRIPT}")
3492  file (REMOVE "${BUILD_SCRIPT}.tmp")
3493  else ()
3494  file (WRITE "${BUILD_SCRIPT}" "${C}")
3495  endif ()
3496  # add custom build command
3497  add_custom_command (
3498  OUTPUT "${BUILD_DIR}/__init__.py" ${PYTHON_OUTPUT_FILES} ${JYTHON_OUTPUT_FILES}
3499  COMMAND "${CMAKE_COMMAND}" -P "${BUILD_SCRIPT}"
3500  MAIN_DEPENDENCY "${BASIS_PYTHON_TEMPLATES_DIR}/__init__.py.in"
3501  COMMENT "Building PYTHON modules */__init__.py..."
3502  )
3503  # add custom target which triggers execution of build script
3504  add_custom_target (_initpy ALL DEPENDS "${BUILD_DIR}/__init__.py" ${PYTHON_OUTPUT_FILES} ${JYTHON_OUTPUT_FILES})
3505  if (BASIS_DEBUG)
3506  message ("** basis_add_init_py_target():")
3507  endif ()
3508  foreach (DEPENDENT IN LISTS DEPENDENTS)
3509  if (BASIS_DEBUG)
3510  message ("** Adding dependency on _initpy target to ${DEPENDENT}")
3511  endif ()
3512  add_dependencies (${DEPENDENT} _initpy)
3513  endforeach ()
3514  # cleanup on "make clean" - including compiled modules regardless of COMPILE flag
3515  set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${BUILD_DIR}/__init__.py" ${PYTHON_OUTPUT_FILES} ${JYTHON_OUTPUT_FILES})
3516  # add install rules
3517  foreach (LANGUAGE IN ITEMS PYTHON JYTHON)
3518  foreach (COMPONENT IN LISTS COMPONENTS)
3519  if (INSTALL_${LANGUAGE}_DIRS_${COMPONENT})
3520  list (REMOVE_DUPLICATES INSTALL_${LANGUAGE}_DIRS_${COMPONENT})
3521  endif ()
3522  foreach (DIR IN LISTS INSTALL_${LANGUAGE}_DIRS_${COMPONENT})
3523  list (FIND INSTALL_EXCLUDE "${DIR}" IDX)
3524  if (IDX EQUAL -1)
3525  if (BASIS_DEBUG AND BASIS_VERBOSE)
3526  message("** Copy ${${LANGUAGE}_INSTALL_FILE} to ${DIR} upon installation of ${COMPONENT} component")
3527  endif ()
3528  install (
3529  FILES "${${LANGUAGE}_INSTALL_FILE}"
3530  DESTINATION "${DIR}"
3531  COMPONENT "${COMPONENT}"
3532  )
3533  endif ()
3534  endforeach ()
3535  endforeach ()
3536  endforeach ()
3537 endfunction ()
3538 
3539 
3540 ## @}
3541 # end of Doxygen group
function basis_build_mex_file(in TARGET_UID)
Add custom command for build of MEX-file.
function basis_get_source_target_name(out TARGET_NAME, in SOURCE_FILE, in ARGN)
Derive target name from source file name.
function basis_get_target_uid(out TARGET_UID, in TARGET_NAME)
Get "global" target name, i.e., actual CMake target name.
function basis_build_script_library(in TARGET_UID)
Add custom command for build of script library.
cmake BASIS_UTILITIES
Enable the automatic detection of the use of the BASIS utilities.
function set_target_properties(in ARGN)
Set target property.
cmake INSTALL_JYTHON_LIBRARY_DIR
Path of installation directory of private Jython modules relative to CMAKE_INSTALL_PREFIX.
cmake __BASIS_TARGETTOOLS_INCLUDED
function basis_get_relative_path(out REL, in BASE, in PATH)
Get path relative to a given base directory.
function basis_target_link_libraries(in TARGET_NAME, in ARGN)
Add link dependencies to build target.
macro basis_get_compiled_jython_file_of_python_module(out CFILE, in MODULE)
Get file path of Jython file compiled from the given Python module.
function is(in result, in expected, in name)
Test whether a given result is equal to the expected result.
macro basis_add_custom_target(in TARGET_NAME)
Add custom target.
def which(command, path=None, verbose=0, exts=None)
Definition: which.py:257
function basis_get_project_property(out VARIABLE, in ARGN)
Get project-global property value.
function basis_build_script(in TARGET_UID)
Add custom command for build of single script.
function basis_finalize_targets(in ARGN)
Finalize custom targets by adding the missing build commands.
cmake SOURCES
Definition: glob.cmake:52
macro basis_compile_python_modules_for_jython(out FLAG)
Whether to compile Python modules for Jython interpreter.
function basis_check_target_name(in TARGET_NAME)
Checks whether a given name is a valid target name.
cmake INSTALL_JYTHON_SITE_DIR
Path of installation directory of public Jython modules relative to CMAKE_INSTALL_PREFIX.
function basis_add_glob_target(in TARGET_UID, out SOURCES, in ARGN)
Glob source files.
cmake BINARY_JYTHON_LIBRARY_DIR
Absolute path to output directory for Jython modules.
function basis_add_export_target(out EXPORT_OPTION, in TARGET_UID, in IS_TEST, in ARGN)
Add target to export set.
function add_library(in TARGET_UID, in ARGN)
Add library target.
macro basis_sanitize_for_regex(out OUT, in STR)
Sanitize string variable for use in regular expression.
option BASIS_COMPILE_SCRIPTS
Enable compilation of scripts if supported by the language.
function basis_get_source_language(out LANGUAGE, in ARGN)
Detect programming language of given source code files.
function basis_remove_definitions(in ARGN)
Remove previously added compile definitions.
function basis_add_mcc_target(in TARGET_NAME, in ARGN)
Add MATLAB Compiler target.
Definition: basis.h:34
function basis_set_project_property()
Set project-global property.
function basis_add_init_py_target()
function basis_add_library_target(in TARGET_NAME, in ARGN)
Add library built from C++ source code.
cmake NAME
macro include_directories(in ARGN)
Add directories to search path for include files.
function basis_get_target_link_libraries(out LINK_DEPENDS, in TARGET_NAME)
Get link libraries/dependencies of (imported) target.
cmake BASIS_EXPORT_DEFAULT
Whether to export targets by default.
macro basis_add_utilities_library(out UID, in LANGUAGE)
Add build target for BASIS utilities library.
macro basis_get_filename_component()
Alias for the overwritten get_filename_component() function.
cmake BUILD_SCRIPT
string VERSION
Project version.
Definition: utilities.sh:81
macro basis_set_flag(in PREFIX, out FLAG, in DEFAULT)
Set flag given mutually exclusive ARGN_<FLAG> and ARGN_NO<FLAG> function arguments.
cmake LINK_DIR
function basis_add_script(in TARGET_NAME, in ARGN)
Add single arbitrary or executable script.
function basis_utilities_check(out VAR, in SOURCE_FILE, in ARGN)
Check whether the BASIS utilities are used within a given source file.
function basis_add_executable_target(in TARGET_NAME, in ARGN)
Add executable built from C++ source code.
macro link_directories(in ARGN)
Add directories to search path for libraries.
function basis_get_target_type(out TYPE, in TARGET_NAME)
Get type name of target.
function basis_add_mex_file(in TARGET_NAME, in ARGN)
Add MEX-file target.
cmake BINARY_PYTHON_LIBRARY_DIR
Absolute path to output directory for Python modules.
function basis_link_directories(in ARGN)
Add directories to search path for libraries.
function basis_get_compiled_file(out CFILE, in SOURCE, in ARGV2)
Get file name of compiled script.
function add_executable(in TARGET_UID, in ARGN)
Add executable target.
function basis_add_definitions(in ARGN)
Add compile definitions.
function basis_make_target_uid(out TARGET_UID, in TARGET_NAME)
Make target UID from given target name.
cmake CONFIG_FILE
Name of the CMake package configuration file.
function basis_configure_sources(out LIST_NAME, in ARGN)
Configure .in source files.
macro basis_use_package(in PACKAGE)
Use found package.
function match(in value, in pattern)
This function implements a more portable way to do pattern matching.
#define UNIX
Whether the sources are compiled on a Unix-based system.
Definition: config.h:60
cmake COMMAND
function basis_add_custom_export_target(in TARGET_UID, in IS_TEST)
Add target to custom export set.
cmake DIR
function basis_add_script_library(in TARGET_NAME, in ARGN)
Add script library target.
function basis_get_target_property(out VAR, in TARGET_NAME, in ARGN)
Get value of property set on target.
function basis_dump_variables(in RESULT_FILE)
Output current CMake variables to file.
option BASIS_DEBUG
Request debugging messages from BASIS functions.
function basis_configure_script(in INPUT, in OUTPUT, in ARGN)
Configure and optionally compile script file.
cmake INSTALL_PYTHON_LIBRARY_DIR
Path of installation directory of private Python modules relative to CMAKE_INSTALL_PREFIX.
cmake VALUE
function basis_build_mcc_target(in TARGET_UID)
Add custom command for build of MATLAB Compiler target.
function basis_set_target_install_rpath(in TARGET_NAME)
Set INSTALL_RPATH property of executable or shared library target.
macro basis_library_prefix(out PREFIX, in LANGUAGE)
Get default subdirectory prefix of scripted library modules.
cmake CMAKE_SKIP_RPATH
option BASIS_VERBOSE
Default Sphinx theme options.
cmake LANGUAGE
Detected scripting language or UNKNOWN.
function basis_set_target_properties(in ARGN)
Set properties on a target.
function basis_add_imported_target(in TARGET, in TYPE)
Add imported target.
function basis_get_target_name(out TARGET_NAME, in TARGET_UID)
Get "local" target name, i.e., BASIS target name without check of UID.
function basis_add_executable(in TARGET_NAME, in ARGN)
Add executable target.
function basis_add_library(in TARGET_NAME, in ARGN)
Add library target.
cmake cmake ARGS
function basis_include_directories(in ARGN)
Add directories to search path for include files.
function get_filename_component(inout ARGN)
Fixes CMake&#39;s get_filename_component() command.
function basis_add_dependencies(in ARGN)
Add dependencies to build target.
cmake BASIS_UTILITIES_ENABLED
Definition: Settings.cmake:109
function basis_get_target_location(out VAR, in TARGET_NAME, in PART)
Get location of build target output file(s).