-
Notifications
You must be signed in to change notification settings - Fork 1
/
rocbuild.cmake
310 lines (258 loc) · 11.3 KB
/
rocbuild.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
# Author: Zhuo Zhang <[email protected]>
# Homepage: https://github.com/zchrissirhcz/rocbuild
cmake_minimum_required(VERSION 3.13)
# CMake 3.10: include_guard()
# CMake 3.21: $<TARGET_RUNTIME_DLLS:tgt>
# CMake 3.13: target_link_options() use "LINKER:" as a portable way for different compiler + linker combo
include_guard()
macro(rocbuild_set_artifacts_path)
if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
# Where add_executable() generates executable file
# Where add_library(SHARED) generates .dll file on Windowos
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" CACHE INTERNAL "")
endif()
if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
# Where add_library(MODULE) generates loadable module file (.dll or .so)
# Where add_library(SHARED) generates shared library (.so, .dylib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" CACHE INTERNAL "")
endif()
if(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
# Where add_library(STATIC) generates static library file
# Where add_library(SHARED) generates the import library file (.lib) of the shared library (.dll) if exports at least one symbol
# Where add_executable() generates the import library file (.lib) of the executable target if ENABLE_EXPORTS target property is set
# Where add_executable() generates the linker import file (.imp on AIX) of the executable target if ENABLE_EXPORTS target property is set
# Where add_library(SHARED) generates the linker import file (.tbd) of the shared library target if ENABLE_EXPORTS target property is set
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" CACHE INTERNAL "")
endif()
endmacro()
macro(rocbuild_enable_ninja_colorful_output)
# When building a CMake-based project, Ninja may speedup the building speed, comparing to Make.
# However, with `-GNinja` specified, compile errors are with no obvious colors.
# This cmake plugin just solve this mentioned problem, giving colorful output for Ninja.
## References: https://medium.com/@alasher/colored-c-compiler-output-with-ninja-clang-gcc-10bfe7f2b949
add_compile_options(
"$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-fdiagnostics-color=always>"
"$<$<COMPILE_LANG_AND_ID:CXX,Clang,AppleClang>:-fcolor-diagnostics>"
"$<$<COMPILE_LANG_AND_ID:C,GNU>:-fdiagnostics-color=always>"
"$<$<COMPILE_LANG_AND_ID:C,Clang,AppleClang>:-fcolor-diagnostics>"
)
endmacro()
# Transitively list all link libraries of a target (recursive call)
# Modified from https://github.com/libigl/libigl/blob/main/cmake/igl/igl_copy_dll.cmake, GPL-3.0 / MPL-2.0
function(rocbuild_get_dependencies_recursive OUTPUT_VARIABLE TARGET)
get_target_property(_aliased ${TARGET} ALIASED_TARGET)
if(_aliased)
set(TARGET ${_aliased})
endif()
get_target_property(_IMPORTED ${TARGET} IMPORTED)
get_target_property(_TYPE ${TARGET} TYPE)
if(_IMPORTED OR (${_TYPE} STREQUAL "INTERFACE_LIBRARY"))
get_target_property(TARGET_DEPENDENCIES ${TARGET} INTERFACE_LINK_LIBRARIES)
else()
get_target_property(TARGET_DEPENDENCIES ${TARGET} LINK_LIBRARIES)
endif()
set(VISITED_TARGETS ${${OUTPUT_VARIABLE}})
foreach(DEPENDENCY IN ITEMS ${TARGET_DEPENDENCIES})
if(TARGET ${DEPENDENCY})
get_target_property(_aliased ${DEPENDENCY} ALIASED_TARGET)
if(_aliased)
set(DEPENDENCY ${_aliased})
endif()
if(NOT (DEPENDENCY IN_LIST VISITED_TARGETS))
list(APPEND VISITED_TARGETS ${DEPENDENCY})
rocbuild_get_dependencies_recursive(VISITED_TARGETS ${DEPENDENCY})
endif()
endif()
endforeach()
set(${OUTPUT_VARIABLE} ${VISITED_TARGETS} PARENT_SCOPE)
endfunction()
# Transitively list all link libraries of a target
function(rocbuild_get_dependencies OUTPUT_VARIABLE TARGET)
set(DISCOVERED_TARGETS "")
rocbuild_get_dependencies_recursive(DISCOVERED_TARGETS ${TARGET})
set(${OUTPUT_VARIABLE} ${DISCOVERED_TARGETS} PARENT_SCOPE)
endfunction()
# Copy .dll dependencies to a target executable's folder. This function must be called *after* all the CMake
# dependencies of the executable target have been defined, otherwise some .dlls might not be copied to the target
# folder.
function(rocbuild_copy_dlls target)
# Sanity checks
if(CMAKE_CROSSCOMPILING OR (NOT WIN32))
return()
endif()
if(NOT TARGET ${target})
message(STATUS "rocbuild_copy_dlls() was called with a non-target: ${target}")
return()
endif()
# Sanity checks
get_target_property(TYPE ${target} TYPE)
if(NOT ${TYPE} STREQUAL "EXECUTABLE")
message(FATAL_ERROR "rocbuild_copy_dlls() was called on a non-executable target: ${target}")
endif()
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.21")
add_custom_command(TARGET ${target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_RUNTIME_DLLS:${target}> $<TARGET_FILE_DIR:${target}>
COMMAND_EXPAND_LISTS
)
return()
endif()
# set the name of file to be written
if(DEFINED CMAKE_CONFIGURATION_TYPES)
set(COPY_SCRIPT "${CMAKE_BINARY_DIR}/rocbuild_copy_dlls_${target}_$<CONFIG>.cmake")
else()
set(COPY_SCRIPT "${CMAKE_BINARY_DIR}/rocbuild_copy_dlls_${target}.cmake")
endif()
add_custom_command(
TARGET ${target}
PRE_LINK
COMMAND ${CMAKE_COMMAND} -E touch "${COPY_SCRIPT}"
COMMAND ${CMAKE_COMMAND} -P "${COPY_SCRIPT}"
COMMENT "Copying dlls for target ${target}"
)
# Retrieve all target dependencies
rocbuild_get_dependencies(TARGET_DEPENDENCIES ${target})
set(DEPENDENCY_FILES "")
foreach(DEPENDENCY IN LISTS TARGET_DEPENDENCIES)
get_target_property(TYPE ${DEPENDENCY} TYPE)
if(NOT (${TYPE} STREQUAL "SHARED_LIBRARY" OR ${TYPE} STREQUAL "MODULE_LIBRARY"))
continue()
endif()
string(APPEND DEPENDENCY_FILES " $<TARGET_FILE:${DEPENDENCY}> # ${DEPENDENCY}\n")
endforeach()
set(COPY_SCRIPT_CONTENT "")
string(APPEND COPY_SCRIPT_CONTENT
"set(dependency_files \n${DEPENDENCY_FILES})\n\n"
"list(REMOVE_DUPLICATES dependency_files)\n\n"
"foreach(file IN ITEMS \${dependency_files})\n"
" if(EXISTS \"\${file}\")\n "
"execute_process(COMMAND \${CMAKE_COMMAND} -E copy_if_different "
"\"\${file}\" \"$<TARGET_FILE_DIR:${target}>/\")\n"
" endif()\n"
)
string(APPEND COPY_SCRIPT_CONTENT "endforeach()\n")
# Finally generate one script for each configuration supported by this generator
message(STATUS "Populating copy rules for target: ${target}")
file(GENERATE
OUTPUT "${COPY_SCRIPT}"
CONTENT "${COPY_SCRIPT_CONTENT}"
)
endfunction()
# Scan opencv_videoio dlls and copy them to the target executable's folder
function(rocbuild_copy_opencv_videoio_plugin_dlls target)
# Sanity checks
if(CMAKE_CROSSCOMPILING OR (NOT WIN32))
return()
endif()
if(NOT TARGET ${target})
message(WARNING "rocbuild_copy_opencv_videoio_plugin_dlls() was called with a non-target: ${target}")
return()
endif()
get_target_property(TYPE ${target} TYPE)
if(NOT ${TYPE} STREQUAL "EXECUTABLE")
message(WARNING "rocbuild_copy_opencv_videoio_plugin_dlls() was called on a non-executable target: ${target}")
return()
endif()
# If OpenCV_DIR is not set, we can't copy the opencv_videoio dlls
if(NOT DEFINED OpenCV_DIR)
message(WARNING "OpenCV_DIR is not defined, can't copy opencv_videoio dlls")
return()
endif()
if(DEFINED CMAKE_CONFIGURATION_TYPES)
set(COPY_SCRIPT "${CMAKE_BINARY_DIR}/rocbuild_copy_opencv_videoio_plugin_dlls_${target}_$<CONFIG>.cmake")
else()
set(COPY_SCRIPT "${CMAKE_BINARY_DIR}/rocbuild_copy_opencv_videoio_plugin_dlls_${target}.cmake")
endif()
set(COPY_SCRIPT_CONTENT "")
if(EXISTS "${OpenCV_DIR}/bin")
set(opencv_videoio_plugin_dll_dir "${OpenCV_DIR}/bin")
elseif(EXISTS "${OpenCV_DIR}/../bin")
set(opencv_videoio_plugin_dll_dir "${OpenCV_DIR}/../bin")
else()
message(WARNING "Could not find opencv videoio plugin dlls in ${OpenCV_DIR}/bin or ${OpenCV_DIR}/../bin")
return()
endif()
file(REAL_PATH "${opencv_videoio_plugin_dll_dir}" opencv_videoio_plugin_dll_dir)
file(GLOB opencv_videoio_plugin_dlls "${opencv_videoio_plugin_dll_dir}/opencv_videoio_*.dll")
# convert opencv_videoio_dlls to a string
string(REPLACE ";" "\n" opencv_videoio_plugin_dlls "${opencv_videoio_plugin_dlls}")
string(APPEND COPY_SCRIPT_CONTENT
"set(opencv_videoio_plugin_dlls\n${opencv_videoio_plugin_dlls}\n)\n"
"foreach(file IN ITEMS \${opencv_videoio_plugin_dlls})\n"
" if(EXISTS \"\${file}\")\n"
" execute_process(COMMAND \${CMAKE_COMMAND} -E copy_if_different \"\${file}\" \"$<TARGET_FILE_DIR:${target}>\")\n"
" endif()\n"
"endforeach()\n"
)
file(GENERATE
OUTPUT "${COPY_SCRIPT}"
CONTENT "${COPY_SCRIPT_CONTENT}"
)
add_custom_command(
TARGET ${target}
PRE_LINK
COMMAND ${CMAKE_COMMAND} -E touch "${COPY_SCRIPT}"
COMMAND ${CMAKE_COMMAND} -P "${COPY_SCRIPT}"
COMMENT "Copying opencv_videoio plugin dlls for target ${target}"
)
endfunction()
function(rocbuild_set_debug_postfix TARGET)
# determine TARGET type
get_target_property(TYPE ${TARGET} TYPE)
if(NOT TYPE)
message(FATAL_ERROR "rocbuild_define_package() called with non-existent target: ${TARGET}")
endif()
# determine if TARGET is imported
get_target_property(IMPORTED ${TARGET} IMPORTED)
if(IMPORTED)
return()
endif()
# Don't treat for single config generators
if(NOT CMAKE_CONFIGURATION_TYPES)
return()
endif()
if(TYPE MATCHES "^(STATIC_LIBRARY|SHARED_LIBRARY|EXECUTABLE)$")
set_target_properties(${TARGET} PROPERTIES DEBUG_POSTFIX "_d")
endif()
endfunction()
function(rocbuild_hide_symbols TARGET)
get_target_property(TARGET_TYPE ${TARGET} TYPE)
if(TARGET_TYPE STREQUAL "SHARED_LIBRARY")
if((CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") OR
(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang"))
target_compile_options(${TARGET} PRIVATE "-fvisibility=hidden")
endif()
endif()
endfunction()
function(rocbuild_link_as_needed TARGET)
get_target_property(TARGET_TYPE ${TARGET} TYPE)
if(TARGET_TYPE STREQUAL "SHARED_LIBRARY")
if((CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang)$") OR
(CMAKE_CXX_COMPILER_ID MATCHES "^(GNU|Clang)$"))
target_link_options(${TARGET} PRIVATE "LINKER:-as-needed")
elseif((CMAKE_C_COMPILER_ID STREQUAL "AppleClang") OR
(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"))
target_link_options(${TARGET} PRIVATE "LINKER:-dead_strip_dylibs")
endif()
endif()
endfunction()
function(rocbuild_remove_unused_data_and_function TARGET)
if(CMAKE_BUILD_TYPE STREQUAL "Release" OR "$<CONFIG:Release>")
if((CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang)$") OR
(CMAKE_CXX_COMPILER_ID MATCHES "^(GNU|Clang)$"))
target_compile_options(${TARGET} PRIVATE "-fdata-sections" "-ffunction-sections")
target_link_options(${TARGET} PRIVATE "LINKER:--gc-sections")
elseif((CMAKE_C_COMPILER_ID STREQUAL "AppleClang") OR
(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"))
target_compile_options(${TARGET} PRIVATE "-fdata-sections" "-ffunction-sections")
target_link_options(${TARGET} PRIVATE "LINKER:-dead_strip")
endif()
endif()
endfunction()
function(rocbuild_print_args)
message(STATUS "ROCBUILD/I: CMake version: ${CMAKE_VERSION}")
message(STATUS "ROCBUILD/I: ROCBUILD_PLATFORM: ${ROCBUILD_PLATFORM}")
message(STATUS "ROCBUILD/I: ROCBUILD_ARCH: ${ROCBUILD_ARCH}")
endfunction()
rocbuild_print_args()
rocbuild_set_artifacts_path()
rocbuild_enable_ninja_colorful_output()