Do not unnecessarily constrain values in verifyPropType()
[hiphop-php.git] / third-party / watchman / src / build / fbcode_builder / CMake / RustStaticLibrary.cmake
blobd35f208cf8dcf2e68cdb5b7f11c641132db2ad93
1 # Copyright (c) Facebook, Inc. and its affiliates.
3 include(FBCMakeParseArgs)
5 set(
6   USE_CARGO_VENDOR AUTO CACHE STRING
7   "Download Rust Crates from an internally vendored location"
9 set_property(CACHE USE_CARGO_VENDOR PROPERTY STRINGS AUTO ON OFF)
11 set(
12   GENERATE_CARGO_VENDOR_CONFIG AUTO CACHE STRING
13   "Whether to generate Rust cargo vendor config or use existing"
15 set_property(CACHE GENERATE_CARGO_VENDOR_CONFIG PROPERTY STRINGS AUTO ON OFF)
17 set(RUST_VENDORED_CRATES_DIR "$ENV{RUST_VENDORED_CRATES_DIR}")
19 if("${USE_CARGO_VENDOR}" STREQUAL "AUTO")
20   if(EXISTS "${RUST_VENDORED_CRATES_DIR}")
21     set(USE_CARGO_VENDOR ON)
22   else()
23     set(USE_CARGO_VENDOR OFF)
24   endif()
25 endif()
27 if("${GENERATE_CARGO_VENDOR_CONFIG}" STREQUAL "AUTO")
28   set(GENERATE_CARGO_VENDOR_CONFIG "${USE_CARGO_VENDOR}")
29 endif() 
31 if(GENERATE_CARGO_VENDOR_CONFIG)
32   if(NOT EXISTS "${RUST_VENDORED_CRATES_DIR}")
33     message(
34       FATAL "vendored rust crates not present: "
35       "${RUST_VENDORED_CRATES_DIR}"
36     )
37   endif()
39   set(RUST_CARGO_HOME "${CMAKE_BINARY_DIR}/_cargo_home")
40   file(MAKE_DIRECTORY "${RUST_CARGO_HOME}")
42   file(
43     TO_NATIVE_PATH "${RUST_VENDORED_CRATES_DIR}"
44     ESCAPED_RUST_VENDORED_CRATES_DIR
45   )
46   string(
47     REPLACE "\\" "\\\\"
48     ESCAPED_RUST_VENDORED_CRATES_DIR
49     "${ESCAPED_RUST_VENDORED_CRATES_DIR}"
50   )
51   file(
52     WRITE "${RUST_CARGO_HOME}/config"
53     "[source.crates-io]\n"
54     "replace-with = \"vendored-sources\"\n"
55     "\n"
56     "[source.vendored-sources]\n"
57     "directory = \"${ESCAPED_RUST_VENDORED_CRATES_DIR}\"\n"
58   )
59 endif()
61 # Cargo is a build system in itself, and thus will try to take advantage of all
62 # the cores on the system. Unfortunately, this conflicts with Ninja, since it
63 # also tries to utilize all the cores. This can lead to a system that is
64 # completely overloaded with compile jobs to the point where nothing else can
65 # be achieved on the system.
67 # Let's inform Ninja of this fact so it won't try to spawn other jobs while
68 # Rust being compiled.
69 set_property(GLOBAL APPEND PROPERTY JOB_POOLS rust_job_pool=1)
71 # This function creates an interface library target based on the static library
72 # built by Cargo. It will call Cargo to build a staticlib and generate a CMake
73 # interface library with it.
75 # This function requires `find_package(Python COMPONENTS Interpreter)`.
77 # You need to set `lib:crate-type = ["staticlib"]` in your Cargo.toml to make
78 # Cargo build static library.
80 # ```cmake
81 # rust_static_library(<TARGET> [CRATE <CRATE_NAME>])
82 # ```
84 # Parameters:
85 # - TARGET:
86 #   Name of the target name. This function will create an interface library
87 #   target with this name.
88 # - CRATE_NAME:
89 #   Name of the crate. This parameter is optional. If unspecified, it will
90 #   fallback to `${TARGET}`.
92 # This function creates two targets:
93 # - "${TARGET}": an interface library target contains the static library built
94 #   from Cargo.
95 # - "${TARGET}.cargo": an internal custom target that invokes Cargo.
97 # If you are going to use this static library from C/C++, you will need to
98 # write header files for the library (or generate with cbindgen) and bind these
99 # headers with the interface library.
101 function(rust_static_library TARGET)
102   fb_cmake_parse_args(ARG "" "CRATE" "" "${ARGN}")
104   if(DEFINED ARG_CRATE)
105     set(crate_name "${ARG_CRATE}")
106   else()
107     set(crate_name "${TARGET}")
108   endif()
110   set(cargo_target "${TARGET}.cargo")
111   set(target_dir $<IF:$<CONFIG:Debug>,debug,release>)
112   set(staticlib_name "${CMAKE_STATIC_LIBRARY_PREFIX}${crate_name}${CMAKE_STATIC_LIBRARY_SUFFIX}")
113   set(rust_staticlib "${CMAKE_CURRENT_BINARY_DIR}/${target_dir}/${staticlib_name}")
115   set(cargo_cmd cargo)
116   if(WIN32)
117     set(cargo_cmd cargo.exe)
118   endif()
120   set(cargo_flags build $<IF:$<CONFIG:Debug>,,--release> -p ${crate_name})
121   if(USE_CARGO_VENDOR)
122     set(extra_cargo_env "CARGO_HOME=${RUST_CARGO_HOME}")
123     set(cargo_flags ${cargo_flags})
124   endif()
126   add_custom_target(
127     ${cargo_target}
128     COMMAND
129       "${CMAKE_COMMAND}" -E remove -f "${CMAKE_CURRENT_SOURCE_DIR}/Cargo.lock"
130     COMMAND
131       "${CMAKE_COMMAND}" -E env
132       "CARGO_TARGET_DIR=${CMAKE_CURRENT_BINARY_DIR}"
133       ${extra_cargo_env}
134       ${cargo_cmd}
135       ${cargo_flags}
136     COMMENT "Building Rust crate '${crate_name}'..."
137     JOB_POOL rust_job_pool
138     WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
139     BYPRODUCTS
140       "${CMAKE_CURRENT_BINARY_DIR}/debug/${staticlib_name}"
141       "${CMAKE_CURRENT_BINARY_DIR}/release/${staticlib_name}"
142   )
144   add_library(${TARGET} INTERFACE)
145   add_dependencies(${TARGET} ${cargo_target})
146   set_target_properties(
147     ${TARGET}
148     PROPERTIES
149       INTERFACE_STATICLIB_OUTPUT_PATH "${rust_staticlib}"
150       INTERFACE_INSTALL_LIBNAME
151         "${CMAKE_STATIC_LIBRARY_PREFIX}${crate_name}_rs${CMAKE_STATIC_LIBRARY_SUFFIX}"
152   )
153   target_link_libraries(
154     ${TARGET}
155     INTERFACE "$<BUILD_INTERFACE:${rust_staticlib}>"
156   )
157 endfunction()
159 # This function instructs cmake to define a target that will use `cargo build`
160 # to build a bin crate referenced by the Cargo.toml file in the current source
161 # directory.
162 # It accepts a single `TARGET` parameter which will be passed as the package
163 # name to `cargo build -p TARGET`. If binary has different name as package,
164 # use optional flag BINARY_NAME to override it.
165 # The cmake target will be registered to build by default as part of the
166 # ALL target.
167 function(rust_executable TARGET)
168   fb_cmake_parse_args(ARG "" "BINARY_NAME" "" "${ARGN}")
170   set(crate_name "${TARGET}")
171   set(cargo_target "${TARGET}.cargo")
172   set(target_dir $<IF:$<CONFIG:Debug>,debug,release>)
174   if(DEFINED ARG_BINARY_NAME)
175     set(executable_name "${ARG_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX}")
176   else()
177       set(executable_name "${crate_name}${CMAKE_EXECUTABLE_SUFFIX}")
178   endif()
180   set(cargo_cmd cargo)
181   if(WIN32)
182     set(cargo_cmd cargo.exe)
183   endif()
185   set(cargo_flags build $<IF:$<CONFIG:Debug>,,--release> -p ${crate_name})
186   if(USE_CARGO_VENDOR)
187     set(extra_cargo_env "CARGO_HOME=${RUST_CARGO_HOME}")
188     set(cargo_flags ${cargo_flags})
189   endif()
191   add_custom_target(
192     ${cargo_target}
193     ALL
194     COMMAND
195       "${CMAKE_COMMAND}" -E remove -f "${CMAKE_CURRENT_SOURCE_DIR}/Cargo.lock"
196     COMMAND
197       "${CMAKE_COMMAND}" -E env
198       "CARGO_TARGET_DIR=${CMAKE_CURRENT_BINARY_DIR}"
199       ${extra_cargo_env}
200       ${cargo_cmd}
201       ${cargo_flags}
202     COMMENT "Building Rust executable '${crate_name}'..."
203     JOB_POOL rust_job_pool
204     WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
205     BYPRODUCTS
206       "${CMAKE_CURRENT_BINARY_DIR}/debug/${executable_name}"
207       "${CMAKE_CURRENT_BINARY_DIR}/release/${executable_name}"
208   )
210   set_property(TARGET "${cargo_target}"
211       PROPERTY EXECUTABLE "${CMAKE_CURRENT_BINARY_DIR}/${target_dir}/${executable_name}")
212 endfunction()
214 # This function can be used to install the executable generated by a prior
215 # call to the `rust_executable` function.
216 # It requires a `TARGET` parameter to identify the target to be installed,
217 # and an optional `DESTINATION` parameter to specify the installation
218 # directory.  If DESTINATION is not specified then the `bin` directory
219 # will be assumed.
220 function(install_rust_executable TARGET)
221   # Parse the arguments
222   set(one_value_args DESTINATION)
223   set(multi_value_args)
224   fb_cmake_parse_args(
225     ARG "" "${one_value_args}" "${multi_value_args}" "${ARGN}"
226   )
228   if(NOT DEFINED ARG_DESTINATION)
229     set(ARG_DESTINATION bin)
230   endif()
232   get_target_property(foo "${TARGET}.cargo" EXECUTABLE)
234   install(
235     PROGRAMS "${foo}"
236     DESTINATION "${ARG_DESTINATION}"
237   )
238 endfunction()
240 # This function installs the interface target generated from the function
241 # `rust_static_library`. Use this function if you want to export your Rust
242 # target to external CMake targets.
244 # ```cmake
245 # install_rust_static_library(
246 #   <TARGET>
247 #   INSTALL_DIR <INSTALL_DIR>
248 #   [EXPORT <EXPORT_NAME>]
249 # )
250 # ```
252 # Parameters:
253 # - TARGET: Name of the Rust static library target.
254 # - EXPORT_NAME: Name of the exported target.
255 # - INSTALL_DIR: Path to the directory where this library will be installed.
257 function(install_rust_static_library TARGET)
258   fb_cmake_parse_args(ARG "" "EXPORT;INSTALL_DIR" "" "${ARGN}")
260   get_property(
261     staticlib_output_path
262     TARGET "${TARGET}"
263     PROPERTY INTERFACE_STATICLIB_OUTPUT_PATH
264   )
265   get_property(
266     staticlib_output_name
267     TARGET "${TARGET}"
268     PROPERTY INTERFACE_INSTALL_LIBNAME
269   )
271   if(NOT DEFINED staticlib_output_path)
272     message(FATAL_ERROR "Not a rust_static_library target.")
273   endif()
275   if(NOT DEFINED ARG_INSTALL_DIR)
276     message(FATAL_ERROR "Missing required argument.")
277   endif()
279   if(DEFINED ARG_EXPORT)
280     set(install_export_args EXPORT "${ARG_EXPORT}")
281   endif()
283   set(install_interface_dir "${ARG_INSTALL_DIR}")
284   if(NOT IS_ABSOLUTE "${install_interface_dir}")
285     set(install_interface_dir "\${_IMPORT_PREFIX}/${install_interface_dir}")
286   endif()
288   target_link_libraries(
289     ${TARGET} INTERFACE
290     "$<INSTALL_INTERFACE:${install_interface_dir}/${staticlib_output_name}>"
291   )
292   install(
293     TARGETS ${TARGET}
294     ${install_export_args}
295     LIBRARY DESTINATION ${ARG_INSTALL_DIR}
296   )
297   install(
298     FILES ${staticlib_output_path}
299     RENAME ${staticlib_output_name}
300     DESTINATION ${ARG_INSTALL_DIR}
301   )
302 endfunction()