File: MwrapAddMex.cmake

package info (click to toggle)
mwrap 1.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,548 kB
  • sloc: cpp: 3,315; python: 1,850; ansic: 856; makefile: 258; lex: 233; sh: 145
file content (314 lines) | stat: -rw-r--r-- 10,868 bytes parent folder | download | duplicates (2)
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
# mwrap_add_mex.cmake - helper to generate MATLAB/Octave wrapper sources with mwrap
#
# Usage:
#   mwrap_add_mex(<target>
#     MW_FILES <file> [...]
#     [MEX_NAME <name>]
#     [CC_FILENAME <filename>]
#     [M_FILENAME <filename>]
#     [CLASSDEF_NAME <name>]
#     [MWRAP_FLAGS <flag> [...]]
#     [WORK_DIR <directory>]
#     [EXTRA_DEPENDS <dep> [...]]
#     [COMPILE_DEFINITIONS <definition> [...]]
#     [OUTPUT_VAR <variable>]
#   )
#
# The function wraps the mwrap executable produced by the current build to
# generate a C/C++ source file (and optional MATLAB scaffolding).  It creates a
# custom target named after <target> that depends on the generated source file.
# Downstream projects can request the absolute path to the generated source via
# OUTPUT_VAR and add it to their own targets.

set(_MWRAP_ADD_MEX_MODULE_DIR ${CMAKE_CURRENT_LIST_DIR})

function(mwrap_add_mex target_name)
  if(NOT target_name)
    message(FATAL_ERROR "mwrap_add_mex requires a target name")
  endif()

  set(options)
  set(oneValueArgs MEX_NAME CC_FILENAME M_FILENAME CLASSDEF_NAME WORK_DIR OUTPUT_VAR)
  set(multiValueArgs MW_FILES MWRAP_FLAGS EXTRA_DEPENDS EXTRA_SOURCES INCLUDE_DIRECTORIES COMPILE_DEFINITIONS)
  cmake_parse_arguments(MAM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

  if(MWRAP_ENABLE_MATLAB_CLASSDEF)
    list(APPEND MAM_COMPILE_DEFINITIONS R2008OO)
    list(REMOVE_DUPLICATES MAM_COMPILE_DEFINITIONS)
  endif()

  if(NOT MAM_MW_FILES)
    message(FATAL_ERROR "mwrap_add_mex(${target_name}) requires MW_FILES to be specified")
  endif()

  if(NOT TARGET mwrap)
    message(FATAL_ERROR "mwrap_add_mex requires the mwrap executable target to exist")
  endif()

  if(NOT MAM_MEX_NAME)
    set(MAM_MEX_NAME "${target_name}")
  endif()

  if(NOT MAM_CC_FILENAME)
    if(MAM_MEX_NAME MATCHES "\\.(c|cc|cpp)$")
      set(MAM_CC_FILENAME "${MAM_MEX_NAME}")
    else()
      set(MAM_CC_FILENAME "${MAM_MEX_NAME}.cc")
    endif()
  endif()

  if(MAM_WORK_DIR)
    set(mwrap_binary_dir "${MAM_WORK_DIR}")
  else()
    set(mwrap_binary_dir "${CMAKE_CURRENT_BINARY_DIR}/${target_name}")
  endif()

  file(MAKE_DIRECTORY "${mwrap_binary_dir}")

  set(cc_output "${mwrap_binary_dir}/${MAM_CC_FILENAME}")
  get_filename_component(cc_basename "${cc_output}" NAME)

  set(mwrap_command $<TARGET_FILE:mwrap> -mex ${MAM_MEX_NAME} -c "${cc_output}")

  set(mwrap_depends ${MAM_EXTRA_DEPENDS})

  set(mwrap_working_dir "${mwrap_binary_dir}")
  set(mwrap_inputs)
  set(mw_absolute_inputs)
  set(mw_parent_dirs)
  set(mwrap_stage_commands)
  foreach(mw IN LISTS MAM_MW_FILES)
    if(IS_ABSOLUTE "${mw}")
      set(mw_abs "${mw}")
    else()
      set(mw_abs "${CMAKE_CURRENT_SOURCE_DIR}/${mw}")
    endif()
    list(APPEND mw_absolute_inputs "${mw_abs}")
    get_filename_component(mw_parent "${mw_abs}" DIRECTORY)
    list(APPEND mw_parent_dirs "${mw_parent}")
  endforeach()

  list(REMOVE_DUPLICATES mw_parent_dirs)
  if(mw_parent_dirs)
    list(LENGTH mw_parent_dirs mw_parent_dir_count)
    if(mw_parent_dir_count EQUAL 1)
      foreach(mw_abs IN LISTS mw_absolute_inputs)
        get_filename_component(mw_basename "${mw_abs}" NAME)
        list(APPEND mwrap_inputs "${mw_basename}")
        list(APPEND mwrap_stage_commands
          COMMAND ${CMAKE_COMMAND} -E copy_if_different "${mw_abs}" "${mwrap_binary_dir}/${mw_basename}")
      endforeach()
    else()
      foreach(mw_abs IN LISTS mw_absolute_inputs)
        file(RELATIVE_PATH mw_rel "${mwrap_binary_dir}" "${mw_abs}")
        list(APPEND mwrap_inputs "${mw_rel}")
      endforeach()
    endif()
  endif()

  if(MAM_CLASSDEF_NAME)
    set(classdef_dir "${mwrap_binary_dir}/@${MAM_CLASSDEF_NAME}")
  endif()

  if(NOT mwrap_inputs)
    set(mwrap_inputs ${MAM_MW_FILES})
  endif()

  if(MAM_M_FILENAME)
    list(APPEND mwrap_command -m "${mwrap_binary_dir}/${MAM_M_FILENAME}")
  endif()
  if(MAM_MWRAP_FLAGS)
    list(APPEND mwrap_command ${MAM_MWRAP_FLAGS})
  endif()
  foreach(mw IN LISTS mwrap_inputs)
    list(APPEND mwrap_command "${mw}")
  endforeach()

  list(APPEND mwrap_depends ${mw_absolute_inputs})
  list(APPEND mwrap_depends mwrap)

  set(pre_commands COMMAND ${CMAKE_COMMAND} -E make_directory "${mwrap_binary_dir}")
  if(classdef_dir)
    list(APPEND pre_commands COMMAND ${CMAKE_COMMAND} -E make_directory "${classdef_dir}")
  endif()
  list(APPEND pre_commands ${mwrap_stage_commands})

  add_custom_command(
    OUTPUT "${cc_output}"
    ${pre_commands}
    COMMAND ${mwrap_command}
    WORKING_DIRECTORY "${mwrap_working_dir}"
    DEPENDS ${mwrap_depends}
    COMMENT "Generating ${cc_basename} with mwrap"
    VERBATIM COMMAND_EXPAND_LISTS
  )

  set_source_files_properties("${cc_output}" PROPERTIES GENERATED TRUE)

  add_custom_target(${target_name} DEPENDS "${cc_output}")
  add_dependencies(${target_name} mwrap)

  if(MAM_OUTPUT_VAR)
    set(${MAM_OUTPUT_VAR} "${cc_output}" PARENT_SCOPE)
  endif()

  set_property(TARGET ${target_name} PROPERTY MWRAP_OUTPUT_SOURCE "${cc_output}")
  set_property(TARGET ${target_name} PROPERTY MWRAP_OUTPUT_DIRECTORY "${mwrap_binary_dir}")
  set_property(TARGET ${target_name} PROPERTY MWRAP_MEX_NAME "${MAM_MEX_NAME}")
  if(MAM_EXTRA_SOURCES)
    set_property(TARGET ${target_name} PROPERTY MWRAP_EXTRA_SOURCES "${MAM_EXTRA_SOURCES}")
  endif()
  if(MAM_INCLUDE_DIRECTORIES)
    set_property(TARGET ${target_name} PROPERTY MWRAP_INCLUDE_DIRECTORIES "${MAM_INCLUDE_DIRECTORIES}")
  endif()
  if(MAM_COMPILE_DEFINITIONS)
    set_property(TARGET ${target_name} PROPERTY MWRAP_COMPILE_DEFINITIONS "${MAM_COMPILE_DEFINITIONS}")
  endif()
  if(MAM_M_FILENAME)
    set_property(TARGET ${target_name} PROPERTY MWRAP_OUTPUT_M_FILE "${mwrap_binary_dir}/${MAM_M_FILENAME}")
  endif()
  if(classdef_dir)
    set_property(TARGET ${target_name} PROPERTY MWRAP_OUTPUT_CLASSDEF_DIR "${classdef_dir}")
  endif()
endfunction()

function(_mwrap_compile_mex target_name)
  set(options)
  set(oneValueArgs OUTPUT_VAR)
  set(multiValueArgs)
  cmake_parse_arguments(MCC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

  if(NOT TARGET ${target_name})
    message(FATAL_ERROR "_mwrap_compile_mex was asked to process unknown target '${target_name}'")
  endif()

  if(NOT MWRAP_MEX_BACKENDS)
    message(FATAL_ERROR "_mwrap_compile_mex requires at least one configured backend")
  endif()

  get_target_property(cc_output ${target_name} MWRAP_OUTPUT_SOURCE)
  if(NOT cc_output)
    message(FATAL_ERROR "Target '${target_name}' does not have generated source metadata")
  endif()

  get_target_property(mwrap_binary_dir ${target_name} MWRAP_OUTPUT_DIRECTORY)
  if(NOT mwrap_binary_dir OR mwrap_binary_dir STREQUAL "NOTFOUND")
    message(FATAL_ERROR "Target '${target_name}' is missing its output directory metadata")
  endif()

  get_target_property(mex_name ${target_name} MWRAP_MEX_NAME)
  if(NOT mex_name)
    set(mex_name ${target_name})
  endif()

  get_target_property(extra_sources ${target_name} MWRAP_EXTRA_SOURCES)
  if(NOT extra_sources OR extra_sources STREQUAL "NOTFOUND")
    unset(extra_sources)
  endif()

  set(mex_sources "${cc_output}")
  if(extra_sources)
    list(APPEND mex_sources ${extra_sources})
  endif()

  get_target_property(include_dirs ${target_name} MWRAP_INCLUDE_DIRECTORIES)
  if(include_dirs STREQUAL "NOTFOUND")
    unset(include_dirs)
  endif()

  get_target_property(compile_defs ${target_name} MWRAP_COMPILE_DEFINITIONS)
  if(compile_defs STREQUAL "NOTFOUND")
    unset(compile_defs)
  endif()

  set(_mwrap_mex_targets)
  set(_mwrap_mex_paths)

  foreach(_mwrap_backend IN LISTS MWRAP_MEX_BACKENDS)
    if(_mwrap_backend STREQUAL "MATLAB")
      if(NOT COMMAND matlab_add_mex)
        message(FATAL_ERROR "MATLAB backend requested, but matlab_add_mex() is unavailable")
      endif()

      set(mex_target "${target_name}_mex")
      matlab_add_mex(NAME ${mex_target} SRC ${mex_sources} OUTPUT_NAME "${mex_name}")
      add_dependencies(${mex_target} ${target_name})

      if(include_dirs)
        target_include_directories(${mex_target} PRIVATE ${include_dirs})
      endif()

      if(compile_defs)
        target_compile_definitions(${mex_target} PRIVATE ${compile_defs})
      endif()

      list(APPEND _mwrap_mex_targets "${mex_target}")
      list(APPEND _mwrap_mex_paths "$<TARGET_FILE:${mex_target}>")
    elseif(_mwrap_backend STREQUAL "OCTAVE")
      if(NOT MWRAP_OCTAVE_MKOCTFILE_EXECUTABLE)
        message(FATAL_ERROR "Octave backend requested, but no mkoctfile executable was configured")
      endif()

      set(mex_target "${target_name}_mex_octave")
      set(octave_output "${mwrap_binary_dir}/${mex_name}.mex")

      set(octave_sources)
      foreach(oct_src IN LISTS mex_sources)
        if(IS_ABSOLUTE "${oct_src}")
          set(oct_src_abs "${oct_src}")
        else()
          get_filename_component(oct_src_abs "${oct_src}" ABSOLUTE)
        endif()
        list(APPEND octave_sources "${oct_src_abs}")
      endforeach()

      set(octave_include_args)
      if(include_dirs)
        foreach(inc_dir IN LISTS include_dirs)
          if(NOT IS_ABSOLUTE "${inc_dir}")
            get_filename_component(inc_dir "${inc_dir}" ABSOLUTE)
          endif()
          list(APPEND octave_include_args "-I${inc_dir}")
        endforeach()
      endif()

      set(octave_define_args)
      if(compile_defs)
        foreach(definition IN LISTS compile_defs)
          list(APPEND octave_define_args "-D${definition}")
        endforeach()
      endif()

      add_custom_command(
        OUTPUT "${octave_output}"
        COMMAND ${CMAKE_COMMAND} -E make_directory "${mwrap_binary_dir}"
        COMMAND ${MWRAP_OCTAVE_MKOCTFILE_EXECUTABLE} --mex -o "${octave_output}"
                ${octave_include_args} ${octave_define_args} ${octave_sources}
        DEPENDS ${octave_sources} ${target_name}
        COMMENT "Building Octave MEX ${mex_name}"
        VERBATIM COMMAND_EXPAND_LISTS
      )

      add_custom_target(${mex_target} DEPENDS "${octave_output}")
      add_dependencies(${mex_target} ${target_name})

      list(APPEND _mwrap_mex_targets "${mex_target}")
      list(APPEND _mwrap_mex_paths "${octave_output}")
    else()
      message(FATAL_ERROR "Unknown MEX backend '${_mwrap_backend}' requested")
    endif()
  endforeach()

  if(_mwrap_mex_targets)
    list(GET _mwrap_mex_targets 0 _mwrap_primary_target)
    list(GET _mwrap_mex_paths 0 _mwrap_primary_path)
    set_property(TARGET ${target_name} PROPERTY MWRAP_OUTPUT_MEX_TARGET "${_mwrap_primary_target}")
    set_property(TARGET ${target_name} PROPERTY MWRAP_OUTPUT_MEX_PATH "${_mwrap_primary_path}")
    set_property(TARGET ${target_name} PROPERTY MWRAP_OUTPUT_MEX_TARGETS "${_mwrap_mex_targets}")
    set_property(TARGET ${target_name} PROPERTY MWRAP_OUTPUT_MEX_PATHS "${_mwrap_mex_paths}")
  endif()

  if(MCC_OUTPUT_VAR)
    set(${MCC_OUTPUT_VAR} "${_mwrap_mex_targets}" PARENT_SCOPE)
  endif()
endfunction()