1# ==============================================================================
2# Medical Image Registration ToolKit (MIRTK)
3#
4# Copyright 2013-2015 Imperial College London
5# Copyright 2013-2015 Andreas Schuh
6#
7# Licensed under the Apache License, Version 2.0 (the "License");
8# you may not use this file except in compliance with the License.
9# You may obtain a copy of the License at
10#
11#     http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS,
15# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16# See the License for the specific language governing permissions and
17# limitations under the License.
18# ==============================================================================
19
20if (COMMAND mirtk_add_executable)
21  return()
22endif ()
23
24# Name of subdirectory of MIRTK command executables.
25# This variable is also used by the Applications module and therefore global.
26if (WIN32)
27  set(MIRTK_TOOLS_SUBDIR "Tools")
28else ()
29  set(MIRTK_TOOLS_SUBDIR "tools")
30endif ()
31
32# ------------------------------------------------------------------------------
33## Add build target for executable MIRTK command
34function(mirtk_add_executable target_name)
35  # Parse arguments
36  if (NOT PROJECT_NAME)
37    message(FATAL_ERROR "mirtk_add_executable called outside project scope!")
38  endif ()
39  if (NOT COMMAND cmake_parse_arguments)
40    include("${CMAKE_ROOT}/Modules/CMakeParseArguments.cmake")
41  endif ()
42  cmake_parse_arguments(TARGET "" "" "SOURCES;DEPENDS;OPTIONAL" ${ARGN})
43  if (TARGET_UNPARSED_ARGUMENTS)
44    message(FATAL_ERROR "mirtk_add_executable called with unrecognized arguments: ${TARGET_UNPARSED_ARGUMENTS}!")
45  endif ()
46  if (target_name MATCHES "^(commands|commands-help)$")
47    message(FATAL_ERROR "Internally used target name cannot be used for command: ${target_name}")
48  endif ()
49  # Add executable target
50  set(LANGUAGE CXX)
51  set(BINARY_LIBEXEC_DIR  "${BINARY_LIBEXEC_DIR}/${MIRTK_TOOLS_SUBDIR}")
52  if (MIRTK_TOOLS_DIR)
53    set(INSTALL_LIBEXEC_DIR "${MIRTK_TOOLS_DIR}")
54  else ()
55    set(INSTALL_LIBEXEC_DIR "${INSTALL_LIBEXEC_DIR}/${MIRTK_TOOLS_SUBDIR}")
56  endif ()
57  if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${target_name}.cc")
58    basis_add_executable(${target_name}.cc ${TARGET_SOURCES} LIBEXEC)
59  elseif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${target_name}.cxx")
60    basis_add_executable(${target_name}.cxx ${TARGET_SOURCES} LIBEXEC)
61  elseif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${target_name}.cpp")
62    basis_add_executable(${target_name}.cpp ${TARGET_SOURCES} LIBEXEC)
63  elseif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${target_name}.py" OR
64          EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${target_name}.py.in")
65    basis_add_executable(${target_name}.py ${TARGET_SOURCES} LIBEXEC FINAL)
66    set(LANGUAGE PYTHON)
67  elseif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${target_name}.sh" OR
68          EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${target_name}.sh.in")
69    basis_add_executable(${target_name}.sh ${TARGET_SOURCES} LIBEXEC FINAL)
70    set(LANGUAGE BASH)
71  else ()
72    message(FATAL_ERROR "Source file for MIRTK command ${target_name} not found!"
73                        " Must have extension '.cc', '.cxx', '.cpp', '.sh', or '.py'."
74                        " Exclude extension from mirtk_add_executable argument.")
75  endif ()
76  set_property(GLOBAL APPEND PROPERTY MIRTK_COMMANDS ${target_name})
77  if (LANGUAGE STREQUAL CXX)
78    basis_get_target_uid(target_uid "${target_name}")
79    # Add target dependencies
80    if (TARGET_DEPENDS OR TARGET_OPTIONAL)
81      if (NOT COMMAND mirtk_target_dependencies)
82        include("${MIRTK_MODULE_PATH}/mirtkTargetDependencies.cmake")
83      endif ()
84      mirtk_target_dependencies(${target_name} ${TARGET_DEPENDS})
85      mirtk_target_dependencies(${target_name} ${TARGET_OPTIONAL} OPTIONAL)
86    endif ()
87    # Set RPATH of installed binary
88    #
89    # Would be set automatically by basis_project_end/mirtk_project_end when
90    # BASIS_INSTALL_RPATH is set to TRUE/ON in mirtk_project_begin instead.
91    # This requires, however, the use of basis_target_link_libraries instead of
92    # the CMake target_link_libraries command for basis_get_target_link_libraries
93    # used by basis_set_target_install_rpath to work. This function is very
94    # costly. Hence, as we know what RPATH we want without inspecting the list
95    # of all link dependencies, we rather set the INSTALL_RPATH ourselves.
96    if (CMAKE_HOST_APPLE)
97      set(ORIGIN "@loader_path")
98    else ()
99      set(ORIGIN "\$ORIGIN")
100    endif ()
101    basis_get_relative_path(rpath
102      "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBEXEC_DIR}"
103      "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBRARY_DIR}"
104    )
105    string(REGEX REPLACE "/+$" "" rpath "${rpath}")
106    set_target_properties(${target_uid} PROPERTIES INSTALL_RPATH "${ORIGIN}/${rpath}")
107  endif ()
108endfunction()
109