forked from halide/Halide
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHalideGenerator.cmake
172 lines (147 loc) · 7.93 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
include(CMakeParseArguments)
# This function returns the intermediate output directory where the Halide
# generator output will be placed. This path is automatically added to the
# library path and include path of the specified target. This function can be
# used to determine the location of the other output files like the bit code and
# html.
function(halide_generator_output_path args_GENERATOR_NAME result_var)
# Convert the binary dir to a native path
file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/" NATIVE_INT_DIR)
# Create a directory to contain generator specific intermediate files
set(scratch_dir "${NATIVE_INT_DIR}scratch_${args_GENERATOR_NAME}")
file(MAKE_DIRECTORY "${scratch_dir}")
# Set the output variable
set(${result_var} "${scratch_dir}" PARENT_SCOPE)
endfunction(halide_generator_output_path)
# This function adds custom build steps to invoke a Halide generator exectuable,
# produce a static library containing the generated code, and then link that
# static library to the specified target.
# The generator executable must be produced separately, e.g. using a call to the
# function halide_project(...) or add_executable(...) and passed to this
# function in the GENERATOR_TARGET parameter.
#
# Usage:
# halide_add_generator_dependency(TARGET <app name>
# GENERATOR_TARGET <new target>
# GENERATOR_NAME <string>
# GENERATED_FUNCTION <string>
# GENERATOR_ARGS <arg> <arg> ...
# [OUTPUT_LIB_VAR <var>]
# [OUTPUT_TARGET_VAR <var>])
#
# TARGET is the name of the app or test target that the generator
# invocation target should be added to. Can either be a ordinary or Utility
# cmake target created by halide_project(), add_executable(), etc.
# GENERATOR_TARGET is the name of the generator executable target.
# GENERATOR_NAME is the C++ class name of the Halide::Generator derived object
# GENERATED_FUNCTION is the name of the C function to be generated by Halide
# GENERATOR_ARGS are extra arguments passed to the generator executable during
# build for example, "-e html target=host-opengl"
# OUTPUT_LIB_VAR is the output variable that will be set to the path of the
# halide generated library. Use this to add the output to Utility targets.
# OUTPUT_TARGET_VAR is the output variable that will be set to the name of the
# target created by this function to invoke the generator. It is
# automatically added as a dependency to ordinary non-Utility cmake targets.
function(halide_add_generator_dependency)
# Parse arguments
set(options )
set(oneValueArgs TARGET GENERATOR_TARGET GENERATOR_NAME GENERATED_FUNCTION OUTPUT_LIB_VAR OUTPUT_TARGET_VAR)
set(multiValueArgs GENERATOR_ARGS)
cmake_parse_arguments(args "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
# Determine a scratch directory to build and execute the generator. ${args_TARGET}
# will include the generated header from this directory.
halide_generator_output_path(${args_GENERATOR_NAME} SCRATCH_DIR)
# Determine the name of the output files
# CMake 2.8 doesn't have string(CONCAT), so fake it like so:
string(REPLACE ".lib" "${CMAKE_STATIC_LIBRARY_SUFFIX}" FILTER_LIB "${args_GENERATED_FUNCTION}.lib" )
string(REPLACE ".h" ".h" FILTER_HDR "${args_GENERATED_FUNCTION}.h" )
# Check to see if the target includes pnacl
if ("${args_GENERATOR_ARGS}" MATCHES ".*pnacl.*")
set(FILTER_LIB "${args_GENERATED_FUNCTION}.bc")
set(target_is_pnacl TRUE)
endif()
set(invoke_args "-g" "${args_GENERATOR_NAME}" "-f" "${args_GENERATED_FUNCTION}" "-o" "${SCRATCH_DIR}" ${args_GENERATOR_ARGS})
set(generator_exec ${args_GENERATOR_TARGET}${CMAKE_EXECUTABLE_SUFFIX})
# Add a custom target to invoke the GENERATOR_TARGET and output the Halide
# generated library
if (WIN32)
add_custom_command(OUTPUT "${SCRATCH_DIR}/${FILTER_LIB}" "${SCRATCH_DIR}/${FILTER_HDR}"
"${SCRATCH_DIR}/${args_GENERATED_FUNCTION}.obj"
DEPENDS "${args_GENERATOR_TARGET}"
COMMAND "${CMAKE_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/${generator_exec}" ${invoke_args}
COMMAND "lib.exe" "/OUT:${FILTER_LIB}" "${SCRATCH_DIR}\\${args_GENERATED_FUNCTION}.obj"
WORKING_DIRECTORY "${SCRATCH_DIR}"
)
elseif(XCODE)
if (NOT target_is_pnacl)
add_custom_command(OUTPUT "${SCRATCH_DIR}/${FILTER_LIB}" "${SCRATCH_DIR}/${FILTER_HDR}"
"${SCRATCH_DIR}/${args_GENERATED_FUNCTION}.o"
DEPENDS "${args_GENERATOR_TARGET}"
# The generator executable will be placed in a configuration specific
# directory, so the Xcode variable $(CONFIGURATION) is passed in the custom
# build script.
COMMAND "${CMAKE_BINARY_DIR}/bin/$(CONFIGURATION)/${generator_exec}" ${invoke_args}
# If we are building an ordinary executable, use libtool to create the
# static library.
COMMAND libtool -static -o "${FILTER_LIB}" "${SCRATCH_DIR}/${args_GENERATED_FUNCTION}.o"
WORKING_DIRECTORY "${SCRATCH_DIR}"
)
else()
# For pnacl targets, there is no libtool step
add_custom_command(OUTPUT "${SCRATCH_DIR}/${FILTER_LIB}" "${SCRATCH_DIR}/${FILTER_HDR}"
DEPENDS "${args_GENERATOR_TARGET}"
COMMAND "${CMAKE_BINARY_DIR}/bin/$(CONFIGURATION)/${generator_exec}" ${invoke_args}
WORKING_DIRECTORY "${SCRATCH_DIR}"
)
endif()
else()
if (NOT target_is_pnacl)
add_custom_command(OUTPUT "${SCRATCH_DIR}/${FILTER_LIB}" "${SCRATCH_DIR}/${FILTER_HDR}"
"${SCRATCH_DIR}/${args_GENERATED_FUNCTION}.o"
DEPENDS "${args_GENERATOR_TARGET}"
COMMAND "${CMAKE_BINARY_DIR}/bin/${generator_exec}" ${invoke_args}
# Create an archive using ar (or similar)
COMMAND "${CMAKE_AR}" r "${FILTER_LIB}" "${SCRATCH_DIR}/${args_GENERATED_FUNCTION}.o"
WORKING_DIRECTORY "${SCRATCH_DIR}"
)
else()
# No archive step for pnacl targets
add_custom_command(OUTPUT "${SCRATCH_DIR}/${FILTER_LIB}" "${SCRATCH_DIR}/${FILTER_HDR}"
DEPENDS "${args_GENERATOR_TARGET}"
COMMAND "${CMAKE_BINARY_DIR}/bin/${generator_exec}" ${invoke_args}
WORKING_DIRECTORY "${SCRATCH_DIR}"
)
endif()
endif()
# Use a custom target to force it to run the generator before the
# object file for the runner. The target name will start with the prefix
# "exec_generator_"
set(exec_generator_target "exec_generator_${args_GENERATOR_NAME}_${args_GENERATED_FUNCTION}")
add_custom_target(${exec_generator_target}
DEPENDS "${SCRATCH_DIR}/${FILTER_LIB}" "${SCRATCH_DIR}/${FILTER_HDR}"
)
# Place the target in a special folder in IDEs
set_target_properties(${exec_generator_target} PROPERTIES
FOLDER "generator"
)
# Associate the generator invocation target with the main app target
if (TARGET "${args_TARGET}")
# Make the generator invocation target run before the app target is built
add_dependencies("${args_TARGET}" ${exec_generator_target})
# Check if it is safe to call target_link_libraries on the target
get_target_property(target_type "${args_TARGET}" TYPE)
if (NOT (${target_type} MATCHES "UTILITY"))
target_link_libraries("${args_TARGET}" "${SCRATCH_DIR}/${FILTER_LIB}")
# Add the scratch directory to the include path for ${args_TARGET}. The generated
# header may be included via #include "${args_GENERATOR_NAME}.h"
target_include_directories("${args_TARGET}" PRIVATE "${SCRATCH_DIR}")
endif()
endif()
# Set the output vars
if (NOT ${args_OUTPUT_LIB_VAR} STREQUAL "")
set(${args_OUTPUT_LIB_VAR} "${SCRATCH_DIR}/${FILTER_LIB}" PARENT_SCOPE)
endif()
if (NOT ${args_OUTPUT_TARGET_VAR} STREQUAL "")
set(${args_OUTPUT_TARGET_VAR} ${exec_generator_target} PARENT_SCOPE)
endif()
endfunction(halide_add_generator_dependency)