-
Notifications
You must be signed in to change notification settings - Fork 0
/
TargetTools.cmake
3548 lines (3505 loc) · 153 KB
/
TargetTools.cmake
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# ============================================================================
# Copyright (c) 2011-2012 University of Pennsylvania
# Copyright (c) 2013-2016 Andreas Schuh
# All rights reserved.
#
# See COPYING file for license information or visit
# https://cmake-basis.github.io/download.html#license
# ============================================================================
##############################################################################
# @file TargetTools.cmake
# @brief Functions and macros to add executable and library targets.
#
# @ingroup CMakeTools
##############################################################################
if (__BASIS_TARGETTOOLS_INCLUDED)
return ()
else ()
set (__BASIS_TARGETTOOLS_INCLUDED TRUE)
endif ()
## @addtogroup CMakeUtilities
# @{
# ============================================================================
# properties
# ============================================================================
# ----------------------------------------------------------------------------
## @brief Set properties on a target.
#
# This function replaces CMake's
# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_target_properties">
# set_target_properties()</a> command and extends its functionality.
# In particular, it maps the given target names to the corresponding target UIDs.
#
# @note If @c BASIS_USE_TARGET_UIDS is @c OFF and is not required by a project,
# it is recommended to use set_target_properties() instead (note that
# set_target_properties is overriden by the ImportTools.cmake module of BASIS).
# This will break the build configuration scripts when @c BASIS_USE_TARGET_UIDS
# is set to @c ON later. It should thus only be used if the project will
# never use the target UID feature of BASIS. A project can possibly define
# a global macro which either calls set_target_properties or
# basis_set_target_properties. But be aware of the related CMake bugs
# which prevent basis_set_target_properties to do the same already.
# ARGV/ARGN do not preserve empty arguments nor list arguments!
#
# @note Due to a bug in CMake (http://www.cmake.org/Bug/view.php?id=12303),
# except of the first property given directly after the @c PROPERTIES keyword,
# only properties listed in @c BASIS_PROPERTIES_ON_TARGETS can be set.
#
# @param [in] ARGN List of arguments. See
# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_target_properties">
# set_target_properties()</a>.
#
# @returns Sets the specified properties on the given target.
#
# @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_target_properties
#
# @ingroup CMakeAPI
function (basis_set_target_properties)
# convert target names to UIDs
set (TARGET_UIDS)
list (LENGTH ARGN N)
if (N EQUAL 0)
message (FATAL_ERROR "basis_set_target_properties(): Missing arguments!")
endif ()
list (GET ARGN 0 ARG)
while (NOT ARG MATCHES "^PROPERTIES$")
basis_get_target_uid (TARGET_UID "${ARG}")
list (APPEND TARGET_UIDS "${TARGET_UID}")
list (REMOVE_AT ARGN 0)
list (LENGTH ARGN N)
if (N EQUAL 0)
break ()
else ()
list (GET ARGN 0 ARG)
endif ()
endwhile ()
if (NOT ARG MATCHES "^PROPERTIES$")
message (FATAL_ERROR "Missing PROPERTIES argument!")
elseif (NOT TARGET_UIDS)
message (FATAL_ERROR "No target specified!")
endif ()
# remove PROPERTIES keyword
list (REMOVE_AT ARGN 0)
math (EXPR N "${N} - 1")
# set targets properties
#
# Note: By iterating over the properties, the empty property values
# are correctly passed on to CMake's set_target_properties()
# command, while
# _set_target_properties(${TARGET_UIDS} PROPERTIES ${ARGN})
# (erroneously) discards the empty elements in ARGN.
if (BASIS_DEBUG)
message ("** basis_set_target_properties:")
message ("** Target(s): ${TARGET_UIDS}")
message ("** Properties: [${ARGN}]")
endif ()
while (N GREATER 1)
list (GET ARGN 0 PROPERTY)
list (GET ARGN 1 VALUE)
list (REMOVE_AT ARGN 0 1)
list (LENGTH ARGN N)
# The following loop is only required b/c CMake's ARGV and ARGN
# lists do not support arguments which are themselves lists.
# Therefore, we need a way to decide when the list of values for a
# property is terminated. Hence, we only allow known properties
# to be set, except for the first property where the name follows
# directly after the PROPERTIES keyword.
while (N GREATER 0)
list (GET ARGN 0 ARG)
if (ARG MATCHES "${BASIS_PROPERTIES_ON_TARGETS_RE}")
break ()
endif ()
list (APPEND VALUE "${ARG}")
list (REMOVE_AT ARGN 0)
list (LENGTH ARGN N)
endwhile ()
if (BASIS_DEBUG)
message ("** -> ${PROPERTY} = [${VALUE}]")
endif ()
# check property name
if (PROPERTY MATCHES "^$") # remember: STREQUAL is buggy and evil!
message (FATAL_ERROR "Empty property name given!")
endif ()
# set target property
if (COMMAND _set_target_properties) # i.e. ImportTools.cmake included
_set_target_properties (${TARGET_UIDS} PROPERTIES ${PROPERTY} "${VALUE}")
else ()
set_target_properties (${TARGET_UIDS} PROPERTIES ${PROPERTY} "${VALUE}")
endif ()
endwhile ()
# make sure that every property had a corresponding value
if (NOT N EQUAL 0)
message (FATAL_ERROR "No value given for target property ${ARGN}")
endif ()
endfunction ()
# ----------------------------------------------------------------------------
## @brief Get value of property set on target.
#
# This function replaces CMake's
# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_target_properties">
# get_target_properties()</a> command and extends its functionality.
# In particular, it maps the given @p TARGET_NAME to the corresponding target UID.
#
# @param [out] VAR Name of output variable.
# @param [in] TARGET_NAME Name of build target.
# @param [in] ARGN Remaining arguments for
# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_target_properties">
# get_target_properties()</a>.
#
# @returns Sets @p VAR to the value of the requested property.
#
# @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_target_property
#
# @ingroup CMakeAPI
function (basis_get_target_property VAR TARGET_NAME)
basis_get_target_uid (TARGET_UID "${TARGET_NAME}")
get_target_property (VALUE "${TARGET_UID}" ${ARGN})
set (${VAR} "${VALUE}" PARENT_SCOPE)
endfunction ()
# ============================================================================
# definitions
# ============================================================================
# ----------------------------------------------------------------------------
## @brief Add compile definitions.
#
# This function replaces CMake's
# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_definitions">
# add_definitions()</a> command.
#
# @param [in] ARGN List of arguments for
# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_definitions">
# add_definitions()</a>.
#
# @returns Adds the given definitions.
#
# @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_definitions
#
# @ingroup CMakeAPI
function (basis_add_definitions)
add_definitions (${ARGN})
endfunction ()
# ----------------------------------------------------------------------------
## @brief Remove previously added compile definitions.
#
# This function replaces CMake's
# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:remove_definitions">
# remove_definitions()</a> command.
#
# @param [in] ARGN List of arguments for
# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:remove_definitions">
# remove_definitions()</a>.
#
# @returns Removes the specified definitions.
#
# @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:remove_definition
#
# @ingroup CMakeAPI
function (basis_remove_definitions)
remove_definitions (${ARGN})
endfunction ()
# ============================================================================
# directories
# ============================================================================
# ----------------------------------------------------------------------------
## @brief Add directories to search path for include files.
#
# Overwrites CMake's
# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories">
# include_directories()</a> command. This is required because the
# basis_include_directories() function is not used by other projects in their
# package use files. Therefore, this macro is an alias for
# basis_include_directories().
#
# @param [in] ARGN List of arguments for basis_include_directories().
#
# @returns Adds the given paths to the search path for include files.
#
# @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories
macro (include_directories)
basis_include_directories (${ARGN})
endmacro ()
# ----------------------------------------------------------------------------
## @brief Add directories to search path for include files.
#
# This function replaces CMake's
# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories">
# include_directories()</a> command. Besides invoking CMake's internal command
# with the given arguments, it updates the @c PROJECT_INCLUDE_DIRECTORIES
# property on the current project (see basis_set_project_property()). This list
# contains a list of all include directories used by a project, regardless of
# the directory in which the basis_include_directories() function was used.
#
# @param ARGN List of arguments for
# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories">
# include_directories()</a> command.
#
# @returns Nothing.
#
# @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories
#
# @ingroup CMakeAPI
function (basis_include_directories)
# CMake's include_directories ()
_include_directories (${ARGN})
# parse arguments
CMAKE_PARSE_ARGUMENTS (ARGN "AFTER;BEFORE;SYSTEM" "" "" ${ARGN})
# make relative paths absolute
set (DIRS)
foreach (P IN LISTS ARGN_UNPARSED_ARGUMENTS)
if (NOT P MATCHES "^\\$<") # preserve generator expressions
get_filename_component (P "${P}" ABSOLUTE)
endif ()
list (APPEND DIRS "${P}")
endforeach ()
if (DIRS)
# append directories to "global" list of include directories
basis_get_project_property (INCLUDE_DIRS PROPERTY PROJECT_INCLUDE_DIRS)
if (BEFORE)
list (INSERT INCLUDE_DIRS 0 ${DIRS})
else ()
list (APPEND INCLUDE_DIRS ${DIRS})
endif ()
if (INCLUDE_DIRS)
list (REMOVE_DUPLICATES INCLUDE_DIRS)
endif ()
if (BASIS_DEBUG)
message ("** basis_include_directories():")
if (BEFORE)
message ("** Add before: ${DIRS}")
else ()
message ("** Add after: ${DIRS}")
endif ()
if (BASIS_VERBOSE)
message ("** Directories: ${INCLUDE_DIRS}")
endif ()
endif ()
basis_set_project_property (PROPERTY PROJECT_INCLUDE_DIRS ${INCLUDE_DIRS})
endif ()
endfunction ()
# ----------------------------------------------------------------------------
## @brief Add directories to search path for libraries.
#
# Overwrites CMake's
# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:link_directories">
# link_directories()</a> command. This is required because the
# basis_link_directories() function is not used by other projects in their
# package use files. Therefore, this macro is an alias for
# basis_link_directories().
#
# @param [in] ARGN List of arguments for basis_link_directories().
#
# @returns Adds the given paths to the search path for libraries.
#
# @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:link_directories
macro (link_directories)
basis_link_directories (${ARGN})
endmacro ()
# ----------------------------------------------------------------------------
## @brief Add directories to search path for libraries.
#
# This function replaces CMake's
# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:link_directories">
# link_directories()</a> command. Even though this function yet only invokes
# CMake's internal command, it should be used in BASIS projects to enable the
# extension of this command's functionality as part of BASIS if required.
#
# @param [in] ARGN List of arguments for
# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:link_directories">
# link_directories()</a>.
#
# @returns Adds the given paths to the search path for libraries.
#
# @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:link_directories
#
# @ingroup CMakeAPI
function (basis_link_directories)
# CMake's link_directories() command
_link_directories (${ARGN})
# make relative paths absolute
set (DIRS)
foreach (P IN LISTS ARGN)
if (NOT P MATCHES "^\\$<") # preserve generator expressions
get_filename_component (P "${P}" ABSOLUTE)
endif ()
list (APPEND DIRS "${P}")
endforeach ()
if (DIRS)
# append directories to "global" list of link directories
basis_get_project_property (LINK_DIRS PROPERTY PROJECT_LINK_DIRS)
list (APPEND LINK_DIRS ${DIRS})
if (LINK_DIRS)
list (REMOVE_DUPLICATES LINK_DIRS)
endif ()
if (BASIS_DEBUG)
message ("** basis_link_directories():")
message ("** Add: [${DIRS}]")
if (BASIS_VERBOSE)
message ("** Directories: [${LINK_DIRS}]")
endif ()
endif ()
basis_set_project_property (PROPERTY PROJECT_LINK_DIRS "${LINK_DIRS}")
# if the directories are added by an external project's <Pkg>Use.cmake
# file which is part of the same superbuild as this project, add the
# directories further to the list of directories that may be added to
# the RPATH. see basis_set_target_install_rpath().
if (BUNDLE_PROJECT) # set in basis_use_package()
basis_get_project_property (LINK_DIRS PROPERTY BUNDLE_LINK_DIRS)
list (APPEND LINK_DIRS ${DIRS})
if (LINK_DIRS)
list (REMOVE_DUPLICATES LINK_DIRS)
endif ()
basis_set_project_property (PROPERTY BUNDLE_LINK_DIRS "${LINK_DIRS}")
endif ()
endif ()
endfunction ()
# ============================================================================
# dependencies
# ============================================================================
# ----------------------------------------------------------------------------
## @brief Add dependencies to build target.
#
# This function replaces CMake's
# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_dependencies">
# add_dependencies()</a> command and extends its functionality.
# In particular, it maps the given target names to the corresponding target UIDs.
#
# @param [in] ARGN Arguments for
# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_dependencies">
# add_dependencies()</a>.
#
# @returns Adds the given dependencies of the specified build target.
#
# @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_dependencies
#
# @ingroup CMakeAPI
if (BASIS_USE_TARGET_UIDS)
function (basis_add_dependencies)
set (ARGS)
foreach (ARG ${ARGN})
basis_get_target_uid (UID "${ARG}")
if (TARGET "${UID}")
list (APPEND ARGS "${UID}")
else ()
list (APPEND ARGS "${ARG}")
endif ()
endforeach ()
add_dependencies (${ARGS})
endfunction ()
else ()
macro (basis_add_dependencies)
add_dependencies (${ARGV})
endmacro ()
endif ()
# ----------------------------------------------------------------------------
## @brief Add link dependencies to build target.
#
# This function replaces CMake's
# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:target_link_libraries">
# target_link_libraries()</a> command.
#
# The main reason for replacing this function is to treat libraries such as
# MEX-files which are supposed to be compiled into a MATLAB executable added
# by basis_add_executable() special. In this case, these libraries are added
# to the LINK_DEPENDS property of the given MATLAB Compiler target. Similarly,
# executable scripts and modules written in a scripting language may depend
# on other modules.
#
# Another reason is the mapping of build target names to fully-qualified
# build target names as used by BASIS (see basis_get_target_uid()).
#
# Only link dependencies added with this function are considered for the setting
# of the INSTALL_RPATH of executable targets (see basis_set_target_install_rpath()).
#
# Example:
# @code
# basis_add_library (MyMEXFunc MEX myfunc.c)
# basis_add_executable (MyMATLABApp main.m)
# basis_target_link_libraries (MyMATLABApp MyMEXFunc OtherMEXFunc.mexa64)
# @endcode
#
# @param [in] TARGET_NAME Name of the target.
# @param [in] ARGN Link libraries.
#
# @returns Adds link dependencies to the specified build target.
# For custom targets, the given libraries are added to the
# @c LINK_DEPENDS property of these targets, in particular.
#
# @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:target_link_libraries
#
# @ingroup CMakeAPI
function (basis_target_link_libraries TARGET_NAME)
basis_get_target_uid (TARGET_UID "${TARGET_NAME}")
if (NOT TARGET "${TARGET_UID}")
message (FATAL_ERROR "basis_target_link_libraries(): Unknown target ${TARGET_UID}.")
endif ()
# get type of named target
get_target_property (BASIS_TYPE ${TARGET_UID} BASIS_TYPE)
# substitute non-fully qualified target names
set (ARGS)
foreach (ARG ${ARGN})
if ("^${ARG}$" STREQUAL "^basis$")
get_target_property (LANGUAGE ${TARGET_UID} LANGUAGE)
if (NOT LANGUAGE OR "^${LANGUAGE}$" STREQUAL "^UNKNOWN$")
message (FATAL_ERROR "Target ${TARGET_UID} is of unknown LANGUAGE! Cannot add dependency on \"basis\" utilities.")
endif ()
basis_add_utilities_library (BASIS_UTILITIES_TARGET ${LANGUAGE})
list (APPEND ARGS ${BASIS_UTILITIES_TARGET})
set_target_properties (${TARGET_UID} PROPERTIES BASIS_UTILITIES TRUE)
else ()
basis_get_target_uid (UID "${ARG}")
if (TARGET "${UID}")
if ("^${UID}$" STREQUAL "^${TARGET_UID}$")
message (FATAL_ERROR "Cannot add link library ${UID} as dependency of itself!")
endif ()
list (APPEND ARGS "${UID}")
else ()
list (APPEND ARGS "${ARG}")
endif ()
endif ()
endforeach ()
# get current link libraries
if (BASIS_TYPE MATCHES "^EXECUTABLE$|^(SHARED|STATIC|MODULE)_LIBRARY$")
get_target_property (DEPENDS ${TARGET_UID} BASIS_LINK_DEPENDS)
else ()
get_target_property (DEPENDS ${TARGET_UID} LINK_DEPENDS)
endif ()
if (NOT DEPENDS)
set (DEPENDS)
endif ()
# note that MCC does itself a dependency check and in case of scripts
# the basis_get_target_link_libraries() function is used
if (BASIS_TYPE MATCHES "MCC|SCRIPT")
list (APPEND DEPENDS ${ARGS})
# otherwise
else ()
list (APPEND DEPENDS ${ARGS})
# pull implicit dependencies (e.g., ITK uses this)
set (DEPENDENCY_ADDED 1)
while (DEPENDENCY_ADDED)
set (DEPENDENCY_ADDED 0)
foreach (LIB IN LISTS DEPENDS)
foreach (LIB_DEPEND IN LISTS ${LIB}_LIB_DEPENDS)
if (NOT LIB_DEPEND MATCHES "^$|^general$")
string (REGEX REPLACE "^-l" "" LIB_DEPEND "${LIB_DEPEND}")
list (FIND DEPENDS ${LIB_DEPEND} IDX)
if (IDX EQUAL -1)
list (APPEND DEPENDS ${LIB_DEPEND})
set (DEPENDENCY_ADDED 1)
endif ()
endif ()
endforeach ()
endforeach ()
endwhile ()
endif ()
# update LINK_DEPENDS
if (BASIS_TYPE MATCHES "^EXECUTABLE$|^(SHARED|STATIC|MODULE)_LIBRARY$")
set_target_properties (${TARGET_UID} PROPERTIES BASIS_LINK_DEPENDS "${DEPENDS}")
target_link_libraries (${TARGET_UID} ${ARGS})
else ()
# FIXME cannot use LINK_DEPENDS for CMake targets as these depends are
# otherwise added as is to the Makefile. therefore, consider renaming
# LINK_DEPENDS in general to BASIS_LINK_DEPENDS.
set_target_properties (${TARGET_UID} PROPERTIES LINK_DEPENDS "${DEPENDS}")
endif ()
endfunction ()
# ============================================================================
# add targets
# ============================================================================
# ----------------------------------------------------------------------------
## @brief Add custom target.
macro (basis_add_custom_target TARGET_NAME)
basis_check_target_name ("${TARGET_NAME}")
basis_make_target_uid (_UID "${TARGET_NAME}")
add_custom_target (${_UID} ${ARGN})
unset (_UID)
endmacro ()
# ----------------------------------------------------------------------------
## @brief Determine language of source files.
# @sa basis_add_executable(), basis_add_library()
macro (_basis_target_source_language)
if (NOT ARGN_LANGUAGE)
basis_get_source_language (ARGN_LANGUAGE ${SOURCES})
if (ARGN_LANGUAGE MATCHES "AMBIGUOUS|UNKNOWN")
set (_FILES)
foreach (SOURCE IN LISTS SOURCES)
set (_FILES "${_FILES}\n ${SOURCE}")
endforeach ()
if (ARGN_LANGUAGE MATCHES "AMBIGUOUS")
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}")
elseif (ARGN_LANGUAGE MATCHES "UNKNOWN")
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}")
endif ()
endif ()
else ()
string (TOUPPER "${ARGN_LANGUAGE}" ARGN_LANGUAGE)
endif ()
endmacro ()
# ----------------------------------------------------------------------------
## @brief Add executable target.
#
# This is the main function to add an executable target to the build system,
# where an executable can be a binary file or a script written in a scripting
# language. In general we refer to any output file which is part of the software
# (i.e., excluding configuration files) and which can be executed
# (e.g., a binary file in the ELF format) or interpreted (e.g., a Python script)
# directly, as executable file. Natively, CMake supports only executables built
# from C/C++ source code files. This function extends CMake's capabilities
# by adding custom build commands for non-natively supported programming
# languages and further standardizes the build of executable targets.
# For example, by default, it is not necessary to specify installation rules
# separately as these are added by this function already (see below).
#
# @par Programming languages
# Besides adding usual executable targets build by the set <tt>C/CXX</tt>
# language compiler, this function inspects the list of source files given and
# detects whether this list contains sources which need to be build using a
# different compiler. In particular, it supports the following languages:
# @n
# <table border="0">
# <tr>
# @tp @b CXX @endtp
# <td>The default behavior, adding an executable target build from C/C++
# source code. The target is added via CMake's add_executable() command.</td>
# </tr>
# <tr>
# @tp <b>PYTHON</b>|<b>JYTHON</b>|<b>PERL</b>|<b>BASH</b> @endtp
# <td>Executables written in one of the named scripting languages are built by
# configuring and/or copying the script files to the build tree and
# installation tree, respectively. During the build step, certain strings
# of the form \@VARIABLE\@ are substituted by the values set during the
# configure step. How these CMake variables are set is specified by a
# so-called script configuration, which itself is either a CMake script
# file or a string of CMake code set as value of the @c SCRIPT_DEFINITIONS
# property of the executable target.</td>
# </tr>
# <tr>
# @tp @b MATLAB @endtp
# <td>Standalone application built from MATLAB sources using the
# MATLAB Compiler (mcc). This language option is used when the list
# of source files contains one or more *.m files. A custom target is
# added which depends on custom command(s) that build the executable.</td>
# @n@n
# Attention: The *.m file with the entry point/main function of the
# executable has to be given before any other *.m file.
# </tr>
# </table>
#
# @par Helper functions
# If the programming language of the input source files is not specified
# explicitly by providing the @p LANGUAGE argument, the extensions of the
# source files and if necessary the first line of script files are inspected
# by the basis_get_source_language() function. Once the programming language is
# known, this function invokes the proper subcommand which adds the respective
# build target. In particular, it calls basis_add_executable_target() for C++
# sources (.cxx), basis_add_mcc_target() for MATLAB scripts (.m), and
# basis_add_script() for all other source files.
#
# @note DO NOT use the mentioned subcommands directly. Always use
# basis_add_executable() to add an executable target to your project.
# Only refer to the documentation of the subcommands to learn about the
# available options of the particular subcommand and considered target
# properties.
#
# @par Output directories
# The built executable file is output to the @c BINARY_RUNTIME_DIR or
# @c BINARY_LIBEXEC_DIR if the @p LIBEXEC option is given.
# If this function is used within the @c PROJECT_TESTING_DIR, however,
# the built executable is output to the @c TESTING_RUNTIME_DIR or
# @c TESTING_LIBEXEC_DIR instead.
#
# @par Installation
# An install command for the added executable target is added by this function
# as well. The executable will be installed as part of the specified @p COMPONENT
# in the directory @c INSTALL_RUNTIME_DIR or @c INSTALL_LIBEXEC_DIR if the option
# @p LIBEXEC is given. Executable targets are exported by default such that they
# can be imported by other CMake-aware projects by including the CMake
# configuration file of this package (<Package>Config.cmake file).
# No installation rules are added, however, if this function is used within the
# @c PROJECT_TESTING_DIR or if "none" (case-insensitive) is given as
# @p DESTINATION. Test executables are further only exported as part of the
# build tree, but not the installation as they are by default not installed.
#
# @param [in] TARGET_NAME Name of the target. If an existing source file is given
# as first argument, it is added to the list of source files
# and the build target name is derived from the name of this file.
# @param [in] ARGN This argument list is parsed and the following
# arguments are extracted, all other arguments are passed
# on to add_executable() or the respective custom
# commands used to add an executable build target.
# @par
# <table border="0">
# <tr>
# @tp @b COMPONENT name @endtp
# <td>Name of component as part of which this executable will be installed
# if the specified @c DESTINATION is not "none".
# (default: @c BASIS_RUNTIME_COMPONENT)</td>
# </tr>
# <tr>
# @tp @b DESTINATION dir @endtp
# <td>Installation directory relative to @c CMAKE_INSTALL_PREFIX.
# If "none" (case-insensitive) is given as argument, no default
# installation rules are added for this executable target.
# (default: @c INSTALL_RUNTIME_DIR or @c INSTALL_LIBEXEC_DIR
# if the @p LIBEXEC option is given)</td>
# </tr>
# <tr>
# @tp @b LANGUAGE lang @endtp
# <td>Programming language in which source files are written (case-insensitive).
# If not specified, the programming language is derived from the file name
# extensions of the source files and, if applicable, the shebang directive
# on the first line of the script file. If the programming language could
# not be detected automatically, check the file name extensions of the
# source files and whether no unrecognized additional arguments were given
# or specify the programming language using this option.
# (default: auto-detected)</td>
# </tr>
# <tr>
# @tp @b LIBEXEC @endtp
# <td>Specifies that the built executable is an auxiliary executable which
# is only called by other executables. (default: @c FALSE)</td>
# </tr>
# <tr>
# @tp @b [NO]EXPORT @endtp
# <td>Whether to export this target. (default: @c TRUE)</td>
# </tr>
# <tr>
# @tp @b NO_BASIS_UTILITIES @endtp
# <td>Specify that the BASIS utilities are not used by this executable and hence
# no link dependency on the BASIS utilities shall be added.
# (default: @c NOT @c BASIS_UTILITIES)</td>
# </tr>
# <tr>
# @tp @b USE_BASIS_UTILITIES @endtp
# <td>Specify that the BASIS utilities are used and required by this executable
# and hence a link dependency on the BASIS utilities has to be added.
# (default: @c BASIS_UTILITIES)</td>
# </tr>
# <tr>
# @tp @b FINAL @endtp
# <td>Finalize custom targets immediately. Any following target property changes
# will have no effect. When this option is used, the custom target which
# executes the custom build command is added in the current working directory.
# Otherwise it will be added in the top-level source directory of the project.
# Which with the Visual Studio generators adds the corresponding Visual Studio
# Project files directly to the top-level build directory. This can be avoided
# using this option or calling basis_finalize_targets() at the end of each
# CMakeLists.txt file.</td>
# </tr>
# </table>
#
# @returns Adds an executable build target. In case of an executable which is
# not build from C++ source files, the function basis_finalize_targets()
# has to be invoked to finalize the addition of the custom build target.
# This is done by the basis_project_end() macro.
#
# @sa basis_add_executable_target()
# @sa basis_add_script()
# @sa basis_add_mcc_target()
#
# @ingroup CMakeAPI
function (basis_add_executable TARGET_NAME)
# --------------------------------------------------------------------------
# parse arguments
CMAKE_PARSE_ARGUMENTS (
ARGN
"EXECUTABLE;LIBEXEC;NO_BASIS_UTILITIES;USE_BASIS_UTILITIES;EXPORT;NOEXPORT;FINAL"
"COMPONENT;DESTINATION;LANGUAGE"
""
${ARGN}
)
# derive target name from path if existing source path is given as first argument instead
# and get list of library source files
get_filename_component (S "${TARGET_NAME}" ABSOLUTE)
if (IS_DIRECTORY "${S}" AND NOT ARGN_UNPARSED_ARGUMENTS)
set (SOURCES "${S}")
basis_get_source_target_name (TARGET_NAME "${TARGET_NAME}" NAME_WE)
elseif (EXISTS "${S}" AND NOT IS_DIRECTORY "${S}" OR (NOT S MATCHES "\\.in$" AND EXISTS "${S}.in" AND NOT IS_DIRECTORY "${S}.in"))
set (SOURCES "${S}")
basis_get_source_target_name (TARGET_NAME "${TARGET_NAME}" NAME_WE)
else ()
set (SOURCES)
endif ()
if (ARGN_UNPARSED_ARGUMENTS)
list (APPEND SOURCES ${ARGN_UNPARSED_ARGUMENTS})
endif ()
if (NOT SOURCES)
message (FATAL_ERROR "basis_add_executable called with only one argument which does however not"
" appear to be a file name. Note that the filename extension must be"
" included if the target name should be derived from the base filename"
" of the source file.")
endif ()
# --------------------------------------------------------------------------
# make target UID
basis_check_target_name ("${TARGET_NAME}")
basis_make_target_uid (TARGET_UID "${TARGET_NAME}")
# --------------------------------------------------------------------------
# process globbing expressions to get complete list of source files
basis_add_glob_target (${TARGET_UID} SOURCES ${SOURCES})
# --------------------------------------------------------------------------
# determine programming language
_basis_target_source_language ()
# --------------------------------------------------------------------------
# prepare arguments for subcommand
foreach (ARG IN LISTS ARGN_UNPARSED_ARGUMENTS)
list (REMOVE_ITEM ARGN "${ARG}")
endforeach ()
list (APPEND ARGN ${SOURCES})
# --------------------------------------------------------------------------
# C++
if (ARGN_LANGUAGE MATCHES "CXX")
basis_add_executable_target (.${TARGET_UID} ${ARGN})
# --------------------------------------------------------------------------
# MATLAB
elseif (ARGN_LANGUAGE MATCHES "MATLAB")
if (ARGN_LIBEXEC)
list (REMOVE_ITEM ARGN LIBEXEC)
basis_add_mcc_target (.${TARGET_UID} LIBEXEC ${ARGN})
else ()
list (REMOVE_ITEM ARGN EXECUTABLE)
basis_add_mcc_target (.${TARGET_UID} EXECUTABLE ${ARGN})
endif ()
# --------------------------------------------------------------------------
# others
else ()
if (ARGN_LIBEXEC)
list (REMOVE_ITEM ARGN LIBEXEC)
basis_add_script (.${TARGET_UID} LIBEXEC ${ARGN})
else ()
list (REMOVE_ITEM ARGN EXECUTABLE)
basis_add_script (.${TARGET_UID} EXECUTABLE ${ARGN})
endif ()
endif ()
# --------------------------------------------------------------------------
# re-glob source files before each build (if necessary)
if (TARGET __${TARGET_UID})
if (TARGET _${TARGET_UID})
add_dependencies (_${TARGET_UID} __${TARGET_UID})
endif ()
add_dependencies (${TARGET_UID} __${TARGET_UID})
endif ()
endfunction ()
# ----------------------------------------------------------------------------
## @brief Add library target.
#
# This is the main function to add a library target to the build system, where
# a library can be a binary archive, shared library, a MEX-file or module(s)
# written in a scripting language. In general we refer to any output file which
# is part of the software (i.e., excluding configuration files), but cannot be
# executed (e.g., a binary file in the ELF format) or interpreted
# (e.g., a Python module) directly, as library file. Natively, CMake supports only
# libraries built from C/C++ source code files. This function extends CMake's
# capabilities by adding custom build commands for non-natively supported
# programming languages and further standardizes the build of library targets.
# For example, by default, it is not necessary to specify installation rules
# separately as these are added by this function already (see below).
#
# @par Programming languages
# Besides adding usual library targets built from C/C++ source code files,
# this function can also add custom build targets for libraries implemented
# in other programming languages. It therefore tries to detect the programming
# language of the given source code files and delegates the addition of the
# build target to the proper helper functions. It in particular supports the
# following languages:
# @n
# <table border="0">
# <tr>
# @tp @b CXX @endtp
# <td>Source files written in C/C++ are by default built into either
# @p STATIC, @p SHARED, or @p MODULE libraries. If the @p MEX option
# is given, however, a MEX-file (a shared library) is build using
# the MEX script instead of using the default C++ compiler directly.</td>
# </tr>
# <tr>
# @tp <b>PYTHON</b>|<b>JYTHON</b>|<b>PERL</b>|<b>BASH</b> @endtp
# <td>Modules written in one of the named scripting languages are built similar
# to executable scripts except that the file name extension is preserved
# and no executable file permission is set on Unix. These modules are
# intended for import/inclusion in other modules or executables written
# in the particular scripting language only.</td>
# </tr>
# <tr>
# @tp @b MATLAB @endtp
# <td>Libraries of M-files or shared libraries built using the MATLAB Compiler (mcc).
# This language option is used when the list of source files contains one or
# more *.m files. A custom target is added which depends on custom command(s)
# that build the library. If the type of the library is @c SHARED, a shared
# library is build using the MATLAB Compiler. Otherwise, the M-files are
# configured and installed such that they can be used in MATLAB.</td>
# </tr>
# </table>
#
# @par Helper functions
# If the programming language of the input source files is not specified
# explicitly by providing the @p LANGUAGE argument, the extensions of the
# source files are inspected using basis_get_source_language(). Once the
# programming language is known, this function invokes the proper subcommand.
# In particular, it calls basis_add_library_target() for C++ sources (.cxx)
# if the target is not a MEX-file target, basis_add_mex_file() for C++ sources
# if the @p MEX option is given, basis_add_mcc_target() for MATLAB scripts (.m),
# and basis_add_script_library() for all other source files.
#
# @note DO NOT use the mentioned subcommands directly. Always use
# basis_add_library() to add a library target to your project. Only refer
# to the documentation of the subcommands to learn about the available
# options of the particular subcommand and the considered target properties.
#
# @par Output directories
# In case of modules written in a scripting language, the libraries are output to
# the <tt>BINARY_<LANGUAGE>_LIBRARY_DIR</tt> if defined. Otherwise,
# the built libraries are output to the @c BINARY_RUNTIME_DIR, @c BINARY_LIBRARY_DIR,
# and/or @c BINARY_ARCHIVE_DIR. If this command is used within the @c PROJECT_TESTING_DIR,
# however, the files are output to the corresponding directories in the testing tree,
# instead.
#
# @par Installation
# An installation rule for the added library target is added by this function
# if the destination is not "none" (case-insensitive). Runtime libraries are
# installed as part of the @p RUNTIME_COMPONENT to the @p RUNTIME_DESTINATION.
# Library components are installed as part of the @p LIBRARY_COMPONENT to the
# @p LIBRARY_DESTINATION. Library targets are further exported such that they
# can be imported by other CMake-aware projects by including the CMake
# configuration file of this package (<Package>Config.cmake file).
# If this function is used within the @c PROJECT_TESTING_DIR, however, no
# installation rules are added. Test library targets are further only exported
# as part of the build tree.
#
# @par Example
# @code
# basis_add_library (MyLib1 STATIC mylib.cxx)
# basis_add_library (MyLib2 STATIC mylib.cxx COMPONENT dev)
#
# basis_add_library (
# MyLib3 SHARED mylib.cxx
# RUNTIME_COMPONENT bin
# LIBRARY_COMPONENT dev
# )
#
# basis_add_library (MyMex MEX mymex.cxx)
# basis_add_library (PythonModule MyModule.py.in)
# basis_add_library (ShellModule MODULE MyModule.sh.in)
# @endcode
#
# @param [in] TARGET_NAME Name of build target. If an existing file is given as
# argument, it is added to the list of source files and
# the target name is derived from the name of this file.
# @param [in] ARGN This argument list is parsed and the following
# arguments are extracted. All unparsed arguments are
# treated as source files.
# @par
# <table border="0">
# <tr>
# @tp <b>STATIC</b>|<b>SHARED</b>|<b>MODULE</b>|<b>MEX</b> @endtp
# <td>Type of the library. (default: @c SHARED for C++ libraries if
# @c BUILD_SHARED_LIBS evaluates to true or @c STATIC otherwise,
# and @c MODULE in all other cases)</td>
# </tr>
# <tr>
# @tp @b COMPONENT name @endtp
# <td>Name of component as part of which this library will be installed
# if the @c RUNTIME_DESTINATION or @c LIBRARY_DESTINATION is not "none".
# Used only if @p RUNTIME_COMPONENT or @p LIBRARY_COMPONENT not specified.
# (default: see @p RUNTIME_COMPONENT and @p LIBRARY_COMPONENT)</td>
# </tr>
# <tr>
# @tp @b DESTINATION dir @endtp
# <td>Installation directory for runtime and library component relative
# to @c CMAKE_INSTALL_PREFIX. Used only if @p RUNTIME_DESTINATION or
# @p LIBRARY_DESTINATION not specified. If "none" (case-insensitive)
# is given as argument, no default installation rules are added.
# (default: see @p RUNTIME_DESTINATION and @p LIBRARY_DESTINATION)</td>
# </tr>
# <tr>
# @tp @b LANGUAGE lang @endtp
# <td>Programming language in which source files are written (case-insensitive).
# If not specified, the programming language is derived from the file name
# extensions of the source files and, if applicable, the shebang directive
# on the first line of the script file. If the programming language could
# not be detected automatically, check the file name extensions of the
# source files and whether no unrecognized additional arguments were given
# or specify the programming language using this option.
# (default: auto-detected)</td>
# </tr>
# <tr>
# @tp @b LIBRARY_COMPONENT name @endtp
# <td>Name of component as part of which import/static library will be intalled
# if @c LIBRARY_DESTINATION is not "none".
# (default: @c COMPONENT if specified or @c BASIS_LIBRARY_COMPONENT otherwise)</td>
# </tr>
# <tr>
# @tp @b LIBRARY_DESTINATION dir @endtp
# <td>Installation directory of the library component relative to
# @c CMAKE_INSTALL_PREFIX. If "none" (case-insensitive) is given as argument,
# no installation rule for the library component is added.
# (default: @c INSTALL_ARCHIVE_DIR)</td>
# </tr>
# <tr>
# @tp @b RUNTIME_COMPONENT name @endtp
# <td>Name of component as part of which runtime library will be installed
# if @c RUNTIME_DESTINATION is not "none".
# (default: @c COMPONENT if specified or @c BASIS_RUNTIME_COMPONENT otherwise)</td>
# </tr>
# <tr>
# @tp @b RUNTIME_DESTINATION dir @endtp
# <td>Installation directory of the runtime component relative to
# @c CMAKE_INSTALL_PREFIX. If "none" (case-insensitive) is given as argument,
# no installation rule for the runtime library is added.
# (default: @c INSTALL_LIBRARY_DIR on Unix or @c INSTALL_RUNTIME_DIR Windows)</td>
# </tr>
# <tr>
# @tp @b [NO]EXPORT @endtp
# <td>Whether to export this target. (default: @c TRUE)</td>
# </tr>
# <tr>
# @tp @b NO_BASIS_UTILITIES @endtp
# <td>Specify that the BASIS utilities are not used by this executable and hence
# no link dependency on the BASIS utilities shall be added.
# (default: @c NOT @c BASIS_UTILITIES)</td>
# </tr>
# <tr>
# @tp @b USE_BASIS_UTILITIES @endtp
# <td>Specify that the BASIS utilities are used and required by this executable
# and hence a link dependency on the BASIS utilities has to be added.
# (default: @c BASIS_UTILITIES)</td>
# </tr>
# <tr>
# @tp @b FINAL @endtp
# <td>Finalize custom targets immediately. Any following target property changes
# will have no effect. When this option is used, the custom target which
# executes the custom build command is added in the current working directory.
# Otherwise it will be added in the top-level source directory of the project.
# Which with the Visual Studio generators adds the corresponding Visual Studio
# Project files directly to the top-level build directory. This can be avoided
# using this option or calling basis_finalize_targets() at the end of each
# CMakeLists.txt file.</td>