forked from halide/Halide
-
Notifications
You must be signed in to change notification settings - Fork 0
/
HalideGenerator.cmake
268 lines (228 loc) · 11.3 KB
/
HalideGenerator.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
include(CMakeParseArguments)
function(halide_generator_genfiles_dir NAME OUTVAR)
set(GENFILES_DIR "${CMAKE_BINARY_DIR}/generator_genfiles/${NAME}")
file(MAKE_DIRECTORY "${GENFILES_DIR}")
set(${OUTVAR} "${GENFILES_DIR}" PARENT_SCOPE)
endfunction()
function(halide_generator_get_exec_path TARGET OUTVAR)
if(MSVC)
# In MSVC, the generator executable will be placed in a configuration specific
# directory specified by ${CMAKE_CFG_INTDIR}.
set(${OUTVAR} "${CMAKE_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/${TARGET}${CMAKE_EXECUTABLE_SUFFIX}" PARENT_SCOPE)
elseif(XCODE)
# In Xcode, the generator executable will be placed in a configuration specific
# directory, so the Xcode variable $(CONFIGURATION) is passed in the custom build script.
set(${OUTVAR} "${CMAKE_BINARY_DIR}/bin/$(CONFIGURATION)/${TARGET}${CMAKE_EXECUTABLE_SUFFIX}" PARENT_SCOPE)
else()
set(${OUTVAR} "${CMAKE_BINARY_DIR}/bin/${TARGET}${CMAKE_EXECUTABLE_SUFFIX}" PARENT_SCOPE)
endif()
endfunction()
function(halide_generator_add_exec_generator_target EXEC_TARGET)
set(options )
set(oneValueArgs GENERATOR_TARGET GENFILES_DIR)
set(multiValueArgs OUTPUTS GENERATOR_ARGS)
cmake_parse_arguments(args "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
halide_generator_get_exec_path(${args_GENERATOR_TARGET} EXEC_PATH)
add_custom_command(
OUTPUT ${args_OUTPUTS}
DEPENDS ${args_GENERATOR_TARGET}
COMMAND ${EXEC_PATH} ${args_GENERATOR_ARGS}
WORKING_DIRECTORY ${args_GENFILES_DIR}
COMMENT "Executing Generator ${args_GENERATOR_TARGET} with args ${args_GENERATOR_ARGS}..."
)
add_custom_target(${EXEC_TARGET} DEPENDS ${args_OUTPUTS})
set_target_properties(${EXEC_TARGET} PROPERTIES FOLDER "generator")
endfunction()
# This function adds custom build steps to invoke a Halide generator executable
# and produce a static library containing the generated code.
#
# The generator executable must be produced separately, e.g. using a call to the
# function halide_add_generator() or halide_project(...) or add_executable(...)
# and passed to this function in the GENERATOR_TARGET parameter.
#
# Usage:
# halide_add_aot_library(<name>
# GENERATOR_TARGET <target>
# GENERATOR_NAME <string>
# GENERATED_FUNCTION <string>
# GENERATOR_OUTPUTS <arg> <arg> ...
# GENERATOR_ARGS <arg> <arg> ...)
#
# <name> is the name of the library being defined.
# GENERATOR_TARGET is the name of the generator executable target, which is assumed to be
# defined elsewhere.
# GENERATOR_TARGET is the name of the generator executable target, which is assumed to be
# defined elsewhere.
# GENERATOR_NAME is the registered name of the Halide::Generator derived object
# GENERATED_FUNCTION is the name of the C function to be generated by Halide, including C++
# namespace (if any); if omitted, default to GENERATOR_NAME
# GENERATOR_OUTPUTS are the values to pass to -e; if omitted, defaults to "h static_library"
# GENERATOR_ARGS are optional extra arguments passed to the generator executable during
# build.
function(halide_add_aot_library AOT_LIBRARY_TARGET)
# Parse arguments
set(options )
set(oneValueArgs GENERATOR_TARGET GENERATOR_NAME GENERATED_FUNCTION)
set(multiValueArgs GENERATOR_ARGS GENERATOR_OUTPUTS FILTER_DEPS)
cmake_parse_arguments(args "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if (args_GENERATED_FUNCTION STREQUAL "")
set(args_GENERATED_FUNCTION ${args_GENERATOR_NAME})
endif()
# Create a directory to contain generator specific intermediate files
halide_generator_genfiles_dir(${AOT_LIBRARY_TARGET} GENFILES_DIR)
# Determine the name of the output files
set(FILTER_LIB "${AOT_LIBRARY_TARGET}${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(FILTER_HDR "${AOT_LIBRARY_TARGET}.h")
set(FILTER_CPP "${AOT_LIBRARY_TARGET}.cpp")
set(GENERATOR_EXEC_ARGS "-o" "${GENFILES_DIR}")
if (NOT ${args_GENERATED_FUNCTION} STREQUAL "")
list(APPEND GENERATOR_EXEC_ARGS "-f" "${args_GENERATED_FUNCTION}" )
endif()
if (NOT ${args_GENERATOR_NAME} STREQUAL "")
list(APPEND GENERATOR_EXEC_ARGS "-g" "${args_GENERATOR_NAME}")
endif()
if (NOT "${args_GENERATOR_OUTPUTS}" STREQUAL "")
string(REPLACE ";" "," _tmp "${args_GENERATOR_OUTPUTS}")
list(APPEND GENERATOR_EXEC_ARGS "-e" ${_tmp})
endif()
# GENERATOR_ARGS always come last
list(APPEND GENERATOR_EXEC_ARGS ${args_GENERATOR_ARGS})
if ("${args_GENERATOR_OUTPUTS}" STREQUAL "")
set(args_GENERATOR_OUTPUTS static_library h)
endif()
set(OUTPUTS )
# This is the CMake idiom for "if foo in list"
list(FIND args_GENERATOR_OUTPUTS "static_library" _lib_index)
list(FIND args_GENERATOR_OUTPUTS "h" _h_index)
list(FIND args_GENERATOR_OUTPUTS "cpp" _cpp_index)
if (${_lib_index} GREATER -1)
list(APPEND OUTPUTS "${GENFILES_DIR}/${FILTER_LIB}")
endif()
if (${_h_index} GREATER -1)
list(APPEND OUTPUTS "${GENFILES_DIR}/${FILTER_HDR}")
set_source_files_properties("${GENFILES_DIR}/${FILTER_HDR}" PROPERTIES GENERATED TRUE)
endif()
if (${_cpp_index} GREATER -1)
list(APPEND OUTPUTS "${GENFILES_DIR}/${FILTER_CPP}")
set_source_files_properties("${GENFILES_DIR}/${FILTER_HDR}" PROPERTIES GENERATED TRUE)
endif()
halide_generator_add_exec_generator_target(
"${AOT_LIBRARY_TARGET}.exec_generator"
GENERATOR_TARGET ${args_GENERATOR_TARGET}
GENERATOR_ARGS "${GENERATOR_EXEC_ARGS}"
GENFILES_DIR ${GENFILES_DIR}
OUTPUTS ${OUTPUTS}
)
# ------ Code to build the RunGen target
set(RUNGEN "${AOT_LIBRARY_TARGET}.rungen")
add_executable("${RUNGEN}" "${CMAKE_SOURCE_DIR}/tools/RunGenStubs.cpp")
target_compile_definitions("${RUNGEN}" PRIVATE "-DHL_RUNGEN_FILTER_HEADER=\"${AOT_LIBRARY_TARGET}.h\"")
target_link_libraries("${RUNGEN}" PRIVATE HalideToolsRunGen)
halide_add_aot_library_dependency("${RUNGEN}" "${AOT_LIBRARY_TARGET}")
target_link_libraries("${RUNGEN}" PRIVATE ${args_FILTER_DEPS})
# Not all Generators will build properly with RunGen (e.g., missing
# external dependencies), so exclude them from the "ALL" targets
set_target_properties("${RUNGEN}" PROPERTIES EXCLUDE_FROM_ALL TRUE)
add_custom_target("${AOT_LIBRARY_TARGET}.run"
COMMAND "${RUNGEN}" "$(RUNARGS)"
DEPENDS "${RUNGEN}")
set_target_properties("${AOT_LIBRARY_TARGET}.run" PROPERTIES EXCLUDE_FROM_ALL TRUE)
# ---------
endfunction(halide_add_aot_library)
# Usage:
# halide_add_aot_library_dependency(TARGET AOT_LIBRARY_TARGET)
function(halide_add_aot_library_dependency TARGET AOT_LIBRARY_TARGET)
halide_generator_genfiles_dir(${AOT_LIBRARY_TARGET} GENFILES_DIR)
add_dependencies("${TARGET}" "${AOT_LIBRARY_TARGET}.exec_generator")
set(FILTER_LIB "${AOT_LIBRARY_TARGET}${CMAKE_STATIC_LIBRARY_SUFFIX}")
target_link_libraries("${TARGET}" PRIVATE "${GENFILES_DIR}/${FILTER_LIB}")
target_include_directories("${TARGET}" PRIVATE "${GENFILES_DIR}")
if (WIN32)
if (MSVC)
# /FORCE:multiple allows clobbering the halide runtime symbols in the lib
# linker warnings disabled:
# 4006: "already defined, second definition ignored"
# 4088: "/FORCE used, image may not work"
# (Note that MSVC apparently considers 4088 too important to allow us to ignore it;
# I'm nevertheless leaving this here to document that we don't care about it.)
set_target_properties("${TARGET}" PROPERTIES LINK_FLAGS "/STACK:8388608,1048576 /FORCE:multiple /ignore:4006 /ignore:4088")
else()
set_target_properties("${TARGET}" PROPERTIES LINK_FLAGS "-Wl,--allow-multiple-definition")
endif()
else()
target_link_libraries("${TARGET}" PRIVATE dl pthread z)
endif()
endfunction(halide_add_aot_library_dependency)
function(halide_add_generator NAME)
set(options WITH_STUB)
set(oneValueArgs STUB_GENERATOR_NAME)
set(multiValueArgs SRCS STUB_DEPS)
cmake_parse_arguments(args "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
# We need to generate an "object" library for every generator, so that any
# generator that depends on our stub can link in our generator as well.
# Unfortunately, an ordinary static library won't do: CMake has no way to
# force "alwayslink=1", and a static library with just a self-registering
# Generator is almost certain to get optimized away at link time. Using
# an "Object Library" lets us dodge this (it basically just groups .o files
# together and presents them at the end), at the cost of some decidedly
# ugly bits right here.
set(OBJLIB "${NAME}.objlib")
add_library("${OBJLIB}" OBJECT ${args_SRCS})
add_dependencies("${OBJLIB}" Halide)
target_include_directories("${OBJLIB}" PRIVATE "${CMAKE_BINARY_DIR}/include")
if (NOT MSVC)
target_compile_options("${OBJLIB}" PRIVATE "-std=c++11") # Halide clients need C++11
target_compile_options("${OBJLIB}" PRIVATE "-fno-rtti")
endif()
foreach(STUB ${args_STUB_DEPS})
halide_add_generator_stub_dependency(TARGET ${OBJLIB} STUB_GENERATOR_TARGET ${STUB})
endforeach()
set(ALLSTUBS $<TARGET_OBJECTS:${OBJLIB}>)
foreach(STUB ${args_STUB_DEPS})
list(APPEND ALLSTUBS $<TARGET_OBJECTS:${STUB}.objlib>)
endforeach()
halide_project("${NAME}"
"generator"
"${CMAKE_SOURCE_DIR}/tools/GenGen.cpp"
${ALLSTUBS})
# Declare a stub library if requested.
if (${args_WITH_STUB})
halide_add_generator_stub_library(STUB_GENERATOR_TARGET "${NAME}"
STUB_GENERATOR_NAME ${args_STUB_GENERATOR_NAME})
endif()
# Add any stub deps passed to us.
endfunction(halide_add_generator)
function(halide_add_generator_stub_library)
set(options )
set(oneValueArgs STUB_GENERATOR_TARGET STUB_GENERATOR_NAME)
set(multiValueArgs )
cmake_parse_arguments(args "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
halide_generator_genfiles_dir(${args_STUB_GENERATOR_TARGET} GENFILES_DIR)
# STUBNAME_BASE = strip_suffix(STUB_GENERATOR_TARGET, ".generator")
string(REGEX REPLACE "\\.generator*$" "" STUBNAME_BASE ${args_STUB_GENERATOR_TARGET})
set(STUB_HDR "${GENFILES_DIR}/${STUBNAME_BASE}.stub.h")
set(GENERATOR_EXEC_ARGS "-o" "${GENFILES_DIR}" "-e" "cpp_stub")
if (NOT ${args_STUB_GENERATOR_NAME} STREQUAL "")
list(APPEND GENERATOR_EXEC_ARGS "-g" "${args_STUB_GENERATOR_NAME}")
list(APPEND GENERATOR_EXEC_ARGS "-n" "${STUBNAME_BASE}")
endif()
set(STUBGEN "${args_STUB_GENERATOR_TARGET}.exec_stub_generator")
halide_generator_add_exec_generator_target(${STUBGEN}
GENERATOR_TARGET ${args_STUB_GENERATOR_TARGET}
GENERATOR_ARGS "${GENERATOR_EXEC_ARGS}"
GENFILES_DIR ${GENFILES_DIR}
OUTPUTS "${STUB_HDR}"
)
set_source_files_properties("${STUB_HDR}" PROPERTIES GENERATED TRUE)
endfunction(halide_add_generator_stub_library)
function(halide_add_generator_stub_dependency)
# Parse arguments
set(options )
set(oneValueArgs TARGET STUB_GENERATOR_TARGET)
set(multiValueArgs )
cmake_parse_arguments(args "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
halide_generator_genfiles_dir(${args_STUB_GENERATOR_TARGET} GENFILES_DIR)
set(STUBGEN "${args_STUB_GENERATOR_TARGET}.exec_stub_generator")
add_dependencies("${args_TARGET}" ${STUBGEN})
target_include_directories("${args_TARGET}" PRIVATE "${GENFILES_DIR}")
endfunction(halide_add_generator_stub_dependency)