ExportTools.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 ExportTools.cmake
12 # @brief Functions and macros for the export of targets.
13 #
14 # @ingroup CMakeTools
15 ##############################################################################
16 
18  return ()
19 else ()
21 endif ()
22 
23 
24 ## @addtogroup CMakeUtilities
25 # @{
26 
27 
28 # ----------------------------------------------------------------------------
29 ## @brief Add target to export set.
30 #
31 # Targets are added to the export set named after the top-level project.
32 # This is necessary because CMake does not allow us to split the exports
33 # into different sets when there are inter-dependencies between library
34 # targets of the modules.
35 #
36 # @param[out] EXPORT_OPTION Export option for install() command including
37 # the EXPORT option name. Set to an empty string
38 # if target is not installed (see @p ARGN).
39 # @param[in] TARGET_UID UID of target to be exported.
40 # @param[in] IS_TEST Whether given target is a test executable or library.
41 # @param[in] ARGN Optional installation destinations. The actual
42 # values are ignored and argument @c TRUE should
43 # be used if no specific destination paths are given,
44 # but the target is also to be included in the export
45 # set used for installation. If ARGN is empty, the
46 # target is only added to the build tree export set.
47 # When @p ARGN is @c 0, @c FALSE or @c OFF, the target
48 # is not added to list of installation exports.
49 function (basis_add_export_target EXPORT_OPTION TARGET_UID IS_TEST)
50  set (EXPORT_SET "${TOPLEVEL_PROJECT_NAME}")
51  if (IS_TEST)
52  basis_set_project_property (PROJECT "${EXPORT_SET}" APPEND PROPERTY TEST_EXPORT_TARGETS "${TARGET_UID}")
53  set (${EXPORT_OPTION} "" PARENT_SCOPE)
54  else ()
55  basis_set_project_property (PROJECT "${EXPORT_SET}" APPEND PROPERTY EXPORT_TARGETS "${TARGET_UID}")
56  if (ARGN AND NOT "^${ARGN}$" STREQUAL "^(0|false|FALSE|off|OFF)$")
57  basis_set_project_property (PROJECT "${EXPORT_SET}" APPEND PROPERTY INSTALL_EXPORT_TARGETS "${TARGET_UID}")
58  set (${EXPORT_OPTION} "EXPORT;${EXPORT_SET}" PARENT_SCOPE)
59  else ()
60  set (${EXPORT_OPTION} "" PARENT_SCOPE)
61  endif ()
62  endif ()
63 endfunction ()
64 
65 # ----------------------------------------------------------------------------
66 ## @brief Add target to custom export set.
67 #
68 # Targets are added to the export set named after the top-level project.
69 # This is necessary because CMake does not allow us to split the exports
70 # into different sets when there are inter-dependencies between library
71 # targets of the modules.
72 #
73 # @param[in] TARGET_UID UID of target to add to the export set.
74 # @param[in] IS_TEST Whether given target is a test executable or library.
75 function (basis_add_custom_export_target TARGET_UID IS_TEST)
76  set (EXPORT_SET "${TOPLEVEL_PROJECT_NAME}")
77  if (IS_TEST)
78  basis_set_project_property (PROJECT "${EXPORT_SET}" APPEND PROPERTY TEST_EXPORT_TARGETS "${TARGET_UID}")
79  else ()
80  basis_set_project_property (PROJECT "${EXPORT_SET}" APPEND PROPERTY CUSTOM_EXPORT_TARGETS "${TARGET_UID}")
81  endif ()
82 endfunction ()
83 
84 # ----------------------------------------------------------------------------
85 ## @brief Get soname of object file.
86 #
87 # This function extracts the soname from object files in the ELF format on
88 # systems where the objdump command is available. On all other systems,
89 # an empty string is returned.
90 #
91 # @param [out] SONAME The soname of the object file.
92 # @param [in] OBJFILE Object file in ELF format.
93 function (basis_get_soname SONAME OBJFILE)
94  # get absolute path of object file
95  basis_get_target_uid (TARGET_UID ${OBJFILE})
96  if (TARGET TARGET_UID)
97  basis_get_target_location (OBJFILE ${TARGET_UID} ABSOLUTE)
98  string (REPLACE "$<${BASIS_GE_CONFIG}>" "${CMAKE_BUILD_TYPE}" OBJFILE "${OBJFILE}")
99  else ()
100  get_filename_component (OBJFILE "${OBJFILE}" ABSOLUTE)
101  endif ()
102  # usually CMake did this already
103  find_program (CMAKE_OBJDUMP NAMES objdump DOC "The objdump command")
104  # run objdump and extract soname
105  execute_process (
106  COMMAND ${CMAKE_OBJDUMP} -p "${OBJFILE}"
107  COMMAND sed -n "-e's/^[[:space:]]*SONAME[[:space:]]*//p'"
108  RESULT_VARIABLE STATUS
109  OUTPUT_VARIABLE SONAME_OUT
110  ERROR_QUIET
111  )
112  # return
113  if (STATUS EQUAL 0)
114  set (${SONAME} "${SONAME_OUT}" PARENT_SCOPE)
115  else ()
116  set (${SONAME} "" PARENT_SCOPE)
117  endif ()
118 endfunction ()
119 
120 # ----------------------------------------------------------------------------
121 ## @brief Generate header of exports file.
122 function (basis_export_header CODE)
123  set (C "# Generated by BASIS\n\n")
124  set (C "${C}if (\"\${CMAKE_MAJOR_VERSION}.\${CMAKE_MINOR_VERSION}\" LESS 2.8)\n")
125  set (C "${C} message (FATAL_ERROR \"CMake >= 2.8.4 required\")\n")
126  set (C "${C}endif ()\n")
127  set (C "${C}cmake_policy (PUSH)\n")
128  set (C "${C}cmake_policy (VERSION 2.8.4)\n")
129  set (C "${C}#----------------------------------------------------------------\n")
130  set (C "${C}# Generated CMake target import file.\n")
131  set (C "${C}#----------------------------------------------------------------\n")
132  set (C "${C}\n# Commands may need to know the format version.\n")
133  set (C "${C}set (CMAKE_IMPORT_FILE_VERSION 1)\n")
134  set (${CODE} "${C}" PARENT_SCOPE)
135 endfunction ()
136 
137 # ----------------------------------------------------------------------------
138 ## @brief Add code to compute prefix relative to @c INSTALL_CONFIG_DIR.
139 function (basis_export_prefix CODE)
140  set (C "\n# Compute the installation prefix relative to this file.\n")
141  set (C "${C}get_filename_component (_IMPORT_PREFIX \"\${CMAKE_CURRENT_LIST_FILE}\" PATH)\n")
142  string (REGEX REPLACE "[/\\]" ";" DIRS "${INSTALL_CONFIG_DIR}")
143  foreach (D IN LISTS DIRS)
144  set (C "${C}get_filename_component (_IMPORT_PREFIX \"\${_IMPORT_PREFIX}\" PATH)\n")
145  endforeach ()
146  set (${CODE} "${${CODE}}${C}" PARENT_SCOPE)
147 endfunction ()
148 
149 # ----------------------------------------------------------------------------
150 ## @brief Add code to add import targets.
151 function (basis_export_import_targets CODE)
152  set (C)
153  foreach (T IN LISTS ARGN)
155  set (C "${C}\n# Create import target \"${UID}\"\n")
156  get_target_property (BASIS_TYPE ${T} "BASIS_TYPE")
157  if (BASIS_TYPE MATCHES "EXECUTABLE")
158  set (C "${C}add_executable (${UID} IMPORTED)\n")
159  elseif (BASIS_TYPE MATCHES "LIBRARY|MODULE|MEX")
160  if (BASIS_TYPE MATCHES "MEX|MCC")
161  set (TYPE SHARED)
162  elseif (BASIS_TYPE MATCHES "SCRIPT")
163  set (TYPE UNKNOWN)
164  else ()
165  string (REGEX REPLACE "_LIBRARY" "" TYPE "${BASIS_TYPE}")
166  endif ()
167  set (C "${C}add_library (${UID} ${TYPE} IMPORTED)\n")
168  else ()
169  message (FATAL_ERROR "Cannot export target ${T} of type ${BASIS_TYPE}! Use NOEXPORT option.")
170  endif ()
171  set (C "${C}set_target_properties (${UID} PROPERTIES BASIS_TYPE \"${BASIS_TYPE}\")\n")
172  endforeach ()
173  set (${CODE} "${${CODE}}${C}" PARENT_SCOPE)
174 endfunction ()
175 
176 # ----------------------------------------------------------------------------
177 ## @brief Add code to set properties of imported targets for build tree.
178 function (basis_export_build_properties CODE)
179  set (C)
180  if (CMAKE_BUILD_TYPE)
181  set (CONFIG "${CMAKE_BUILD_TYPE}")
182  else ()
183  set (CONFIG "noconfig")
184  endif ()
185  string (TOUPPER "${CONFIG}" CONFIG_U)
186  foreach (T IN LISTS ARGN)
188  get_target_property (BASIS_TYPE ${T} BASIS_TYPE)
189  set (C "${C}\n# Import target \"${UID}\" for configuration \"${CONFIG}\"\n")
190  set (C "${C}set_property (TARGET ${UID} APPEND PROPERTY IMPORTED_CONFIGURATIONS ${CONFIG_U})\n")
191  set (C "${C}set_target_properties (${UID} PROPERTIES\n")
192  if (BASIS_TYPE MATCHES "SCRIPT|LIBRARY|MEX")
193  get_target_property (LANGUAGE ${T} LANGUAGE)
194  if (LANGUAGE)
195  set (C "${C} IMPORTED_LINK_INTERFACE_LANGUAGES_${CONFIG_U} \"${LANGUAGE}\"\n")
196  endif ()
197  get_target_property (LINK_DEPENDS ${T} LINK_DEPENDS)
198  set (LINK_UIDS)
199  foreach (LINK_DEPEND IN LISTS LINK_DEPENDS)
200  basis_get_fully_qualified_target_uid (LINK_UID ${LINK_DEPEND})
201  list (APPEND LINK_UIDS "${LINK_UID}")
202  endforeach ()
203  set (C "${C} IMPORTED_LINK_INTERFACE_LIBRARIES_${CONFIG_U} \"${LINK_UIDS}\"\n")
204  endif ()
205  basis_get_target_location (LOCATION ${T} ABSOLUTE)
206  string (REPLACE "$<${BASIS_GE_CONFIG}>" "${CONFIG}" LOCATION "${LOCATION}")
207  set (C "${C} IMPORTED_LOCATION_${CONFIG_U} \"${LOCATION}\"\n")
208  set (C "${C} )\n")
209  endforeach ()
210  set (${CODE} "${${CODE}}${C}" PARENT_SCOPE)
211 endfunction ()
212 
213 # ----------------------------------------------------------------------------
214 ## @brief Add code to set properties of imported targets for installation.
215 function (basis_export_install_properties CODE)
216  set (C)
217  if (CMAKE_BUILD_TYPE)
218  set (CONFIG "${CMAKE_BUILD_TYPE}")
219  else ()
220  set (CONFIG "noconfig")
221  endif ()
222  string (TOUPPER "${CONFIG}" CONFIG_U)
223  foreach (T IN LISTS ARGN)
225  get_target_property (BASIS_TYPE ${T} BASIS_TYPE)
226  set (C "${C}\n# Import target \"${UID}\" for configuration \"${CONFIG}\"\n")
227  set (C "${C}set_property (TARGET ${UID} APPEND PROPERTY IMPORTED_CONFIGURATIONS ${CONFIG_U})\n")
228  set (C "${C}set_target_properties (${UID} PROPERTIES\n")
229  basis_get_target_location (LOCATION ${T} POST_INSTALL_RELATIVE)
230  set (C "${C} IMPORTED_LOCATION_${CONFIG_U} \"\${_IMPORT_PREFIX}/${LOCATION}\"\n")
231  if (BASIS_TYPE MATCHES "SCRIPT|LIBRARY|MEX")
232  get_target_property (LANGUAGE ${T} LANGUAGE)
233  if (LANGUAGE)
234  set (C "${C} IMPORTED_LINK_INTERFACE_LANGUAGES_${CONFIG_U} \"${LANGUAGE}\"\n")
235  endif ()
236  get_target_property (LINK_DEPENDS ${T} LINK_DEPENDS)
237  set (LINK_UIDS)
238  foreach (LINK_DEPEND IN LISTS LINK_DEPENDS)
239  basis_get_fully_qualified_target_uid (LINK_UID ${LINK_DEPEND})
240  list (APPEND LINK_UIDS "${LINK_UID}")
241  endforeach ()
242  set (C "${C} IMPORTED_LINK_INTERFACE_LIBRARIES_${CONFIG_U} \"${LINK_UIDS}\"\n")
243  endif ()
244  set (C "${C} )\n")
245  endforeach ()
246  set (${CODE} "${${CODE}}${C}" PARENT_SCOPE)
247 endfunction ()
248 
249 # ----------------------------------------------------------------------------
250 ## @brief Add footer of exports file.
251 function (basis_export_footer CODE)
252  set (C "\n# Cleanup temporary variables.\n")
253  set (C "${C}set (_IMPORT_PREFIX)\n")
254  set (C "${C}\n# Commands beyond this point should not need to know the version.\n")
255  set (C "${C}set (CMAKE_IMPORT_FILE_VERSION)\n")
256  set (C "${C}cmake_policy (POP)\n")
257  set (${CODE} "${${CODE}}${C}" PARENT_SCOPE)
258 endfunction ()
259 
260 # ----------------------------------------------------------------------------
261 ## @brief Export all targets added by basis_add_* commands.
262 function (basis_export_targets)
263  # parse arguments
264  CMAKE_PARSE_ARGUMENTS (ARGN "" "FILE;CUSTOM_FILE" "" ${ARGN})
265 
266  if (NOT ARGN_FILE)
267  message (FATAL_ERROR "basis_export_targets(): FILE option is required!")
268  endif ()
269  if (NOT ARGN_CUSTOM_FILE)
270  message (FATAL_ERROR "basis_export_targets(): CUSTOM_FILE option is required!")
271  endif ()
272 
273  if (IS_ABSOLUTE ${ARGN_FILE})
274  message (FATAL_ERROR "basis_export_targets(): FILE option argument must be a relative path!")
275  endif ()
276  if (IS_ABSOLUTE ${ARGN_CUSTOM_FILE})
277  message (FATAL_ERROR "basis_export_targets(): CUSTOM_FILE option argument must be a relative path!")
278  endif ()
279 
280  # --------------------------------------------------------------------------
281  # export non-custom targets
282  basis_get_project_property (EXPORT_TARGETS)
283  if (EXPORT_TARGETS)
284  # add link dependencies to build tree export set
285  foreach (EXPORT_TARGET IN LISTS EXPORT_TARGETS)
286  get_target_property (LINK_DEPENDS ${EXPORT_TARGET} BASIS_LINK_DEPENDS)
287  foreach (LINK_DEPEND IN LISTS LINK_DEPENDS)
288  if (TARGET ${LINK_DEPEND})
289  list (FIND EXPORT_TARGETS ${LINK_DEPEND} IDX)
290  if (IDX EQUAL -1)
291  get_target_property (IMPORTED ${LINK_DEPEND} IMPORTED)
292  if (NOT IMPORTED)
293  message (AUTHOR_WARNING
294  "Adding missing link dependency ${LINK_DEPEND} of ${EXPORT_TARGET} to list of export() targets."
295  " Add the target ${LINK_DEPEND} to the export set using basis_add_export_target() after the"
296  " add_library(${LINK_DEPEND}) command and before basis_project_end(). If the target is added"
297  " using basis_add_library(${LINK_DEPEND}), remove the NOEXPORT option or add EXPORT instead when"
298  " the global variable BASIS_EXPORT_DEFAULT is set to FALSE (actual value is ${BASIS_EXPORT_DEFAULT})."
299  )
300  list (APPEND EXPORT_TARGETS ${LINK_DEPEND})
301  endif ()
302  endif ()
303  endif ()
304  endforeach ()
305  endforeach ()
306  list (REMOVE_DUPLICATES EXPORT_TARGETS)
307  # set namespace of exported import targets
308  if (BASIS_USE_TARGET_UIDS AND BASIS_USE_FULLY_QUALIFIED_UIDS)
309  set (NAMESPACE_OPT)
311  set (NAMESPACE_OPT NAMESPACE "${TOPLEVEL_PROJECT_NAMESPACE_CMAKE}${BASIS_NAMESPACE_DELIMITER_CMAKE}")
312  endif ()
313  # export build tree targets
314  export (
315  TARGETS ${EXPORT_TARGETS}
316  FILE "${BINARY_LIBCONF_DIR}/${ARGN_FILE}"
317  ${NAMESPACE_OPT}
318  )
319  # install export set
320  basis_get_project_property (INSTALL_EXPORT_TARGETS)
321  if (INSTALL_EXPORT_TARGETS AND NOT BASIS_BUILD_ONLY)
322  foreach (COMPONENT "${BASIS_RUNTIME_COMPONENT}" "${BASIS_LIBRARY_COMPONENT}")
323  install (
324  EXPORT "${PROJECT_NAME}"
325  DESTINATION "${INSTALL_CONFIG_DIR}"
326  FILE "${ARGN_FILE}"
327  COMPONENT "${COMPONENT}"
328  ${NAMESPACE_OPT}
329  )
330  endforeach ()
331  endif ()
332  endif ()
333 
334  # --------------------------------------------------------------------------
335  # export custom targets and/or test targets
336  basis_get_project_property (CUSTOM_EXPORT_TARGETS)
337  basis_get_project_property (TEST_EXPORT_TARGETS)
338 
339  if (CUSTOM_EXPORT_TARGETS OR TEST_EXPORT_TARGETS)
340 
341  # write exports for build tree
342  basis_export_header (CONTENT)
343  basis_export_import_targets (CONTENT ${CUSTOM_EXPORT_TARGETS} ${TEST_EXPORT_TARGETS})
344  basis_export_build_properties (CONTENT ${CUSTOM_EXPORT_TARGETS} ${TEST_EXPORT_TARGETS})
345  basis_export_footer (CONTENT)
346 
347  file (WRITE "${BINARY_LIBCONF_DIR}/${ARGN_CUSTOM_FILE}" "${CONTENT}")
348  unset (CONTENT)
349 
350  # write exports for installation - excluding test targets
351  if (CUSTOM_EXPORT_TARGETS AND NOT BASIS_BUILD_ONLY)
352  set (INSTALL_EXPORT_FILE "${PROJECT_BINARY_DIR}/CMakeFiles/Export/${INSTALL_CONFIG_DIR}/${ARGN_CUSTOM_FILE}")
353 
354  basis_export_header (CONTENT)
355  basis_export_prefix (CONTENT)
356  basis_export_import_targets (CONTENT ${CUSTOM_EXPORT_TARGETS})
357  basis_export_install_properties (CONTENT ${CUSTOM_EXPORT_TARGETS})
358  basis_export_footer (CONTENT)
359 
360  file (WRITE "${INSTALL_EXPORT_FILE}" "${CONTENT}")
361  unset (CONTENT)
362 
363  install (
364  FILES "${INSTALL_EXPORT_FILE}"
365  DESTINATION "${INSTALL_CONFIG_DIR}"
366  )
367  endif ()
368 
369  endif ()
370 endfunction ()
371 
372 
373 ## @}
374 # end of Doxygen group
string PROJECT
Project name.
Definition: utilities.sh:79
function basis_get_target_uid(out TARGET_UID, in TARGET_NAME)
Get "global" target name, i.e., actual CMake target name.
function basis_get_project_property(out VARIABLE, in ARGN)
Get project-global property value.
function basis_add_export_target(out EXPORT_OPTION, in TARGET_UID, in IS_TEST, in ARGN)
Add target to export set.
function basis_export_header(in CODE)
Generate header of exports file.
function basis_export_targets()
Export all targets added by basis_add_* commands.
function basis_export_import_targets(in CODE)
Add code to add import targets.
function basis_set_project_property()
Set project-global property.
cmake BASIS_USE_FULLY_QUALIFIED_UIDS
Whether BASIS shall use fully-qualified target UIDs.
function basis_export_footer(in CODE)
Add footer of exports file.
function basis_get_soname(out SONAME, in OBJFILE)
Get soname of object file.
function basis_export_install_properties(in CODE)
Add code to set properties of imported targets for installation.
string CMAKE_BUILD_TYPE
cmake TOPLEVEL_PROJECT_NAMESPACE_CMAKE
CMake namespace of top-level project.
function basis_get_fully_qualified_target_uid(out TARGET_UID, in TARGET_NAME)
Get fully-qualified target name.
cmake __BASIS_EXPORTIMPORTTOOLS_INCLUDED
cmake COMMAND
cmake FILE
function basis_add_custom_export_target(in TARGET_UID, in IS_TEST)
Add target to custom export set.
cmake LANGUAGE
Detected scripting language or UNKNOWN.
option BASIS_BUILD_ONLY
Request configuration of software build only, skipping steps related to packaging and installation...
function basis_export_build_properties(in CODE)
Add code to set properties of imported targets for build tree.
function basis_export_prefix(in CODE)
Add code to compute prefix relative to INSTALL_CONFIG_DIR.
function get_filename_component(inout ARGN)
Fixes CMake&#39;s get_filename_component() command.
function basis_get_target_location(out VAR, in TARGET_NAME, in PART)
Get location of build target output file(s).