File: Rust.cmake

package info (click to toggle)
cryptominisat 5.11.21%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 4,488 kB
  • sloc: cpp: 55,562; ansic: 7,786; python: 7,485; sh: 813; sql: 403; xml: 34; makefile: 22; javascript: 17
file content (354 lines) | stat: -rw-r--r-- 14,672 bytes parent folder | download | duplicates (3)
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
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
# Copyright (c) 2014 SiegeLord -- Pavel Sountsov
#
# This software is provided 'as-is', without any express or implied
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
#
# Permission is granted to anyone to use this software for any purpose,
# including commercial applications, and to alter it and redistribute it
# freely, subject to the following restrictions:
#
#    1. The origin of this software must not be misrepresented; you must not
#    claim that you wrote the original software. If you use this software
#    in a product, an acknowledgment in the product documentation would be
#    appreciated but is not required.
#
#    2. Altered source versions must be plainly marked as such, and must not be
#    misrepresented as being the original software.
#
#    3. This notice may not be removed or altered from any source
#    distribution.

# Defines a few macros, variables and a function to help with compiling Rust
# programs/libraries and documentation with CMake.
#
# This file utilizes several global variables:
#
# RUSTC_EXECUTABLE - Filename of the rustc executable. You can fill it in using the Findrustc package.
# RUSTDOC_EXECUTABLE - Filename of the rustc executable. You can fill it in using the Findrustdoc package.
# RUSTC_FLAGS - These get passed to rustc.
# RUSTDOC_FLAGS - These flags get passed to rustdoc.

include(CMakeParseArguments)

if(NOT RUSTC_FLAGS)
	set(RUSTC_FLAGS "" CACHE STRING "Flags to pass to the Rust compiler.")
endif()
mark_as_advanced(RUSTC_FLAGS)

if(NOT RUSTDOC_FLAGS)
	set(RUSTDOC_FLAGS "" CACHE STRING "Flags to pass to Rustdoc.")
endif()
mark_as_advanced(RUSTDOC_FLAGS)

# Fetches the dependencies of a Rust crate with local crate root located at
# local_root_file and places them into out_var. Optionally also builds the crate.
#
# Optional arguments:
# OTHER_RUSTC_FLAGS flags - Other flags to pass to rustc.
# DESTINATION destination - If compiling, where to place the compilation artifacts.
# COMPILE - Whether or not to produce artifacts (it won't by default).
#           NOTE! This will force the compillation of this crate every time the
#           project is reconfigured, so use with care!
#
# NOTE: Only the first target's dependencies are fetched!
function(get_rust_deps local_root_file out_var)
	cmake_parse_arguments("OPT" "COMPILE" "DESTINATION" "OTHER_RUSTC_FLAGS" ${ARGN})

	set(root_file "${CMAKE_CURRENT_SOURCE_DIR}/${local_root_file}")

	set(dep_dir "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/.cmake_rust_dependencies")
	file(MAKE_DIRECTORY "${dep_dir}")

	if(OPT_COMPILE)
		file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}")
		set(flags --out-dir "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}")
		message(STATUS "Compiling Rust dependency info for crate root ${local_root_file}")
		# XXX: It'd be nice if this wasn't a separate operation (need to handle the dep file location being different, or rewrite this macro thing)
		execute_process(COMMAND ${RUSTC_EXECUTABLE} ${RUSTC_FLAGS} ${OPT_OTHER_RUSTC_FLAGS} ${flags} "${root_file}")
	endif()

	set(flags "-Zno-analysis")
	message(STATUS "Getting Rust dependency info for crate root ${local_root_file}")

	execute_process(COMMAND ${RUSTC_EXECUTABLE} ${RUSTC_FLAGS} ${OPT_OTHER_RUSTC_FLAGS} ${flags} --emit dep-info -o "${dep_dir}/deps.d" "${root_file}")

	# Read and parse the dependency information
	file(STRINGS "${dep_dir}/deps.d" crate_deps LIMIT_COUNT 1)
	file(REMOVE "${dep_dir}/deps.d")
	string(REGEX REPLACE ".*: (.*)" "\\1" crate_deps "${crate_deps}")
	string(STRIP "${crate_deps}" crate_deps)
	string(REPLACE " " ";" crate_deps "${crate_deps}")

	# Make the dependencies be relative to the source directory
	set(crate_deps_relative "")
	foreach(var IN ITEMS ${crate_deps})
		file(TO_CMAKE_PATH "${var}" var)
		file(RELATIVE_PATH var "${CMAKE_CURRENT_SOURCE_DIR}" "${var}")
		list(APPEND crate_deps_relative "${var}")
		# Hack to re-run CMake if the file changes
		configure_file("${var}" "${dep_dir}/${var}" COPYONLY)
	endforeach()

	set(${out_var} "${crate_deps_relative}" PARENT_SCOPE)
endfunction()

# Adds a target to build a rust crate with the crate root located at local_root_file.
# The compilation output is placed inside DESTINATION within the build directory.
#
# Please pass the crate dependencies obtained through get_rust_deps to the dependencies argument in
# addition to other targets/files you want this target to depend on.
#
# Optional arguments:
#
# ALL - Pass this to make this crate be built by default.
# DESTINATION dest - Where to place the compilation artifacts.
# TARGET_NAME target - Target name for the command to build this crate.
# DEPENDS depends - List of dependencies of this crate.
# OTHER_RUSTC_FLAGS flags - Other flags to pass to rustc.
#
# This function sets two variables:
#
# ${target_name}_FULL_TARGET - This is what you would use as a set of dependencies
#                              for other targets when you want them to depend on the
#                              output of this target.
#
# ${target_name}_ARTIFACTS -   The actual files generated by this command.
#                              You'd use this as a set of files to install/copy elsewhere.
function(rust_crate local_root_file)
	cmake_parse_arguments("OPT" "ALL" "DESTINATION;TARGET_NAME" "DEPENDS;OTHER_RUSTC_FLAGS" ${ARGN})

	if(NOT OPT_TARGET_NAME)
		set(OPT_TARGET_NAME CRATE)
	endif()

	if(OPT_ALL)
		set(ALL_ARG "ALL")
	else()
		set(ALL_ARG "")
	endif()

	set(root_file "${CMAKE_CURRENT_SOURCE_DIR}/${local_root_file}")

	execute_process(COMMAND ${RUSTC_EXECUTABLE} ${RUSTC_FLAGS} ${OPT_OTHER_RUSTC_FLAGS} --print file-names "${root_file}"
	                OUTPUT_VARIABLE rel_crate_filenames
	                OUTPUT_STRIP_TRAILING_WHITESPACE)

	# Split up the names into a list
	string(REGEX MATCHALL "[^\n\r]+" rel_crate_filenames "${rel_crate_filenames}")

	set(comment "Building ")
	set(crate_filenames "")
	set(first TRUE)
	foreach(name IN ITEMS ${rel_crate_filenames})
		if(${first})
			set(first FALSE)
		else()
			set(comment "${comment}, ")
		endif()
		set(comment "${comment}${OPT_DESTINATION}/${name}")
		list(APPEND crate_filenames "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}/${name}")
	endforeach()
	file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}")

	add_custom_command(OUTPUT ${crate_filenames}
	                   COMMAND ${RUSTC_EXECUTABLE} ${RUSTC_FLAGS} ${OPT_OTHER_RUSTC_FLAGS} --out-dir "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}" "${root_file}"
	                   DEPENDS ${crate_deps_list}
	                   DEPENDS ${OPT_DEPENDS}
	                   COMMENT "${comment}")

	add_custom_target("${OPT_TARGET_NAME}"
	                  ${ALL_ARG}
	                  DEPENDS ${crate_filenames})

	set("${OPT_TARGET_NAME}_ARTIFACTS" "${crate_filenames}" PARENT_SCOPE)
	# CMake Bug #10082
	set("${OPT_TARGET_NAME}_FULL_TARGET" "${OPT_TARGET_NAME};${crate_filenames}" PARENT_SCOPE)
endfunction()

# Like rust_crate, but fetches the crate dependencies for you. This is convenient
# but inefficient if you want to compile the crate several times with different
# configurations (e.g. with --test and without) or if you want to build documentation.
#
# Optional arguments:
#
# ALL - Pass this to make this crate be built by default.
# DESTINATION dest - Where to place the compilation artifacts.
# TARGET_NAME target - Target name for the command to build this crate.
# DEPENDS depends - List of dependencies of this crate.
# OTHER_RUSTC_FLAGS flags - Other flags to pass to rustc.
#
# This function sets two variables:
#
# ${target_name}_FULL_TARGET - This is what you would use as a set of dependencies
#                              for other targets when you want them to depend on the
#                              output of this target.
#
# ${target_name}_ARTIFACTS - The actual files generated by this command.
#                            You'd use this as a set of files to install/copy elsewhere.
function(rust_crate_auto local_root_file)
	cmake_parse_arguments("OPT" "ALL" "DESTINATION;TARGET_NAME" "DEPENDS;OTHER_RUSTC_FLAGS" ${ARGN})

	if(NOT OPT_TARGET_NAME)
		set(OPT_TARGET_NAME CRATE)
	endif()

	if(OPT_ALL)
		set(ALL_ARG "ALL")
	else()
		set(ALL_ARG "")
	endif()

	get_rust_deps(${local_root_file} crate_deps_list
	              OTHER_RUSTC_FLAGS ${OPT_OTHER_RUSTC_FLAGS})

	rust_crate("${local_root_file}"
	           ${ALL_ARG}
	           TARGET_NAME "${OPT_TARGET_NAME}"
	           DESTINATION "${OPT_DESTINATION}"
	           DEPENDS "${crate_deps_list};${OPT_DEPENDS}"
	           OTHER_RUSTC_FLAGS ${OPT_OTHER_RUSTC_FLAGS})
	set("${OPT_TARGET_NAME}_ARTIFACTS" "${${OPT_TARGET_NAME}_ARTIFACTS}" PARENT_SCOPE)
	set("${OPT_TARGET_NAME}_FULL_TARGET" "${${OPT_TARGET_NAME}_FULL_TARGET}" PARENT_SCOPE)
endfunction(rust_crate_auto)

# Like rust_crate, but this time it generates documentation using rust_doc.
#
# Optional arguments:
#
# ALL - Pass this to make this crate be built by default.
# DESTINATION dest - Where to place the compilation artifacts.
# TARGET_NAME target - Target name for the command to build this crate.
# DEPENDS depends - List of dependencies of this crate.
# OTHER_RUSTC_FLAGS flags - Other flags to pass to rustc.
# OTHER_RUSTDOC_FLAGS flags - Other flags to pass to rustdoc.
#
# This function sets two variables:
#
# ${target_name}_FULL_TARGET - This is what you would use as a set of dependencies
#                              for other targets when you want them to depend on the
#                              output of this target.
#
# ${target_name}_ARTIFACTS - The actual files generated by this command.
#                            You'd use this as a set of files to install/copy elsewhere.
function(rust_doc local_root_file)
	cmake_parse_arguments("OPT" "ALL" "DESTINATION;TARGET_NAME" "DEPENDS;OTHER_RUSTDOC_FLAGS;OTHER_RUSTC_FLAGS" ${ARGN})

	if(NOT OPT_TARGET_NAME)
		set(OPT_TARGET_NAME DOC)
	endif()

	if(OPT_ALL)
		set(ALL_ARG "ALL")
	else()
		set(ALL_ARG "")
	endif()

	set(root_file "${CMAKE_CURRENT_SOURCE_DIR}/${local_root_file}")

	execute_process(COMMAND ${RUSTC_EXECUTABLE} ${RUSTC_FLAGS} ${OPT_OTHER_RUSTC_FLAGS} --print crate-name "${root_file}"
	                OUTPUT_VARIABLE crate_name
	                OUTPUT_STRIP_TRAILING_WHITESPACE)

	set(doc_dir "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}/${crate_name}")
	set(src_dir "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}/src/${crate_name}")
	file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}")

	add_custom_command(OUTPUT "${doc_dir}/index.html" "${doc_dir}" "${src_dir}"
	                   COMMAND ${RUSTDOC_EXECUTABLE} ${RUSTDOC_FLAGS} ${OPT_OTHER_RUSTDOC_FLAGS} -o "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}" "${root_file}"
	                   DEPENDS ${crate_deps_list}
	                   DEPENDS ${OPT_DEPENDS})

	add_custom_target("${OPT_TARGET_NAME}"
	                  ${ALL_ARG}
	                  DEPENDS "${doc_dir}/index.html")

	set("${OPT_TARGET_NAME}_ARTIFACTS" "${doc_dir};${src_dir}" PARENT_SCOPE)
	# CMake Bug #10082
	set("${OPT_TARGET_NAME}_FULL_TARGET" "${OPT_TARGET_NAME};${doc_dir}/index.html" PARENT_SCOPE)
endfunction()

# Like rust_crate_auto, but this time it generates documentation using rust_doc.
#
# Optional arguments:
#
# ALL - Pass this to make this crate be built by default.
# DESTINATION dest - Where to place the compilation artifacts.
# TARGET_NAME target - Target name for the command to build this crate.
# DEPENDS depends - List of dependencies of this crate.
# OTHER_RUSTC_FLAGS flags - Other flags to pass to rustc.
# OTHER_RUSTDOC_FLAGS flags - Other flags to pass to rustdoc.
#
# This function sets two variables:
#
# ${target_name}_FULL_TARGET - This is what you would use as a set of dependencies
#                              for other targets when you want them to depend on the
#                              output of this target.
#
# ${target_name}_ARTIFACTS - The actual files generated by this command.
#                            You'd use this as a set of files to install/copy elsewhere.
function(rust_doc_auto local_root_file)
	cmake_parse_arguments("OPT" "ALL" "DESTINATION;TARGET_NAME" "DEPENDS;OTHER_RUSTC_FLAGS;OTHER_RUSTDOC_FLAGS" ${ARGN})

	if(NOT OPT_TARGET_NAME)
		set(OPT_TARGET_NAME DOC)
	endif()

	if(OPT_ALL)
		set(ALL_ARG "ALL")
	else()
		set(ALL_ARG "")
	endif()

	get_rust_deps(${local_root_file} crate_deps_list
	              OTHER_RUSTC_FLAGS ${OPT_OTHER_RUSTC_FLAGS})

	rust_doc("${local_root_file}"
	         ${ALL_ARG}
	         TARGET_NAME "${OPT_TARGET_NAME}"
	         DESTINATION "${OPT_DESTINATION}"
	         DEPENDS "${crate_deps_list};${OPT_DEPENDS}"
	         OTHER_RUSTC_FLAGS ${OPT_OTHER_RUSTC_FLAGS}
	         OTHER_RUSTDOC_FLAGS ${OPT_OTHER_RUSTDOC_FLAGS})
	set("${OPT_TARGET_NAME}_ARTIFACTS" "${${OPT_TARGET_NAME}_ARTIFACTS}" PARENT_SCOPE)
	set("${OPT_TARGET_NAME}_FULL_TARGET" "${${OPT_TARGET_NAME}_FULL_TARGET}" PARENT_SCOPE)
endfunction()

# Creates a dummy cargo project named ${name} to fetch crates.io dependencies.
# The package will be created in the ${CMAKE_CURRENT_BINARY_DIR}. Typically you
# would then pass "-L ${CMAKE_CURRENT_BINARY_DIR}/target/debug/deps" to rustc so
# it can pick up the dependencies.
#
# Optional arguments:
#
# OTHER_CARGO_FLAGS - Flags to pass to cargo.
# PACKAGE_NAMES - List of package names to fetch.
# PACKAGE_VERSIONS - List of package versions to fetch.
function(cargo_dependency name)
	cmake_parse_arguments("OPT" "" "" "OTHER_CARGO_FLAGS;PACKAGE_NAMES;PACKAGE_VERSIONS" ${ARGN})

	list(LENGTH OPT_PACKAGE_NAMES num_packages)
	list(LENGTH OPT_PACKAGE_VERSIONS num_versions)
	if(NOT ${num_packages} EQUAL ${num_versions})
		message(FATAL_ERROR "Number of cargo packages doesn't match the number of cargo versions.")
	endif()

	set(cargo_dependency_dir "${CMAKE_CURRENT_BINARY_DIR}/${name}")
	file(MAKE_DIRECTORY "${cargo_dependency_dir}")
	file(MAKE_DIRECTORY "${cargo_dependency_dir}/src")

	set(CARGO_TOML [package] \n name = \"cargo_deps_fetcher\" \n version = \"0.0.0\" \n authors = [\"none\"] \n)

	math(EXPR num_packages "${num_packages} - 1")
	foreach(pkg_idx RANGE 0 ${num_packages})
		list(GET OPT_PACKAGE_NAMES ${pkg_idx} pkg_name)
		list(GET OPT_PACKAGE_VERSIONS ${pkg_idx} pkg_version)
		set(CARGO_TOML ${CARGO_TOML} \n [dependencies.${pkg_name}] \n version = \"${pkg_version}\" \n)
	endforeach()

	file(WRITE "${cargo_dependency_dir}/Cargo.toml" ${CARGO_TOML})
	file(WRITE "${cargo_dependency_dir}/src/lib.rs" "")

	execute_process(COMMAND ${CARGO_EXECUTABLE} build ${CARGO_FLAGS} ${OPT_OTHER_CARGO_FLAGS}
	                WORKING_DIRECTORY ${cargo_dependency_dir})
endfunction()