2021-03-04 21:14:08 -08:00
# Find the Rust toolchain and add the `add_rust_library()` API to build Rust
# libraries.
#
# Copyright (C) 2021 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
#
# Author: Micah Snyder
# To see this in a sample project, visit: https://github.com/micahsnyder/cmake-rust-demo
#
# Code to set the Cargo arguments was lifted from:
# https://github.com/Devolutions/CMakeRust
#
# This Module defines the following variables:
# - <program>_FOUND - True if the program was found
# - <program>_EXECUTABLE - path of the program
# - <program>_VERSION - version number of the program
#
# ... for the following Rust toolchain programs:
# - cargo
# - rustc
# - rustup
# - rust-gdb
# - rust-lldb
# - rustdoc
# - rustfmt
# - bindgen
# - cbindgen
#
# Note that `cbindgen` is presently 3rd-party, and is not included with the
# standard Rust installation. `bindgen` is a part of the rust toolchain, but
# might need to be installed separately.
#
# Callers can make any program mandatory by setting `<program>_REQUIRED` before
# the call to `find_package(Rust)`
#
# Eg:
#
# if(MAINTAINER_MODE)
# set(cbindgen_REQUIRED 1)
# set(bindgen_REQUIRED 1)
# endif()
# find_package(Rust REQUIRED)
#
# This module also provides an `add_rust_library()` function which allows a
# caller to create a Rust static library target which you can link to with
# `target_link_libraries()`.
#
# Your Rust static library target will itself depend on the native static libs
# you get from `rustc --crate-type staticlib --print=native-static-libs /dev/null`
#
# Example `add_rust_library()` usage:
#
# add_rust_library(TARGET yourlib WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
# add_library(YourProject::yourlib ALIAS yourlib)
#
# add_executable(yourexe)
# target_link_libraries(yourexe YourProject::yourlib)
#
if ( NOT DEFINED CARGO_HOME )
if ( WIN32 )
set ( CARGO_HOME "$ENV{USERPROFILE}/.cargo" )
else ( )
set ( CARGO_HOME "$ENV{HOME}/.cargo" )
endif ( )
endif ( )
include ( FindPackageHandleStandardArgs )
function ( find_rust_program RUST_PROGRAM )
find_program ( ${ RUST_PROGRAM } _EXECUTABLE ${ RUST_PROGRAM }
H I N T S " $ { C A R G O _ H O M E } "
P A T H _ S U F F I X E S " b i n "
)
if ( ${ RUST_PROGRAM } _EXECUTABLE )
execute_process ( COMMAND "${${RUST_PROGRAM}_EXECUTABLE}" --version
O U T P U T _ V A R I A B L E $ { R U S T _ P R O G R A M } _ V E R S I O N _ O U T P U T
E R R O R _ V A R I A B L E $ { R U S T _ P R O G R A M } _ V E R S I O N _ E R R O R
R E S U L T _ V A R I A B L E $ { R U S T _ P R O G R A M } _ V E R S I O N _ R E S U L T
)
if ( NOT ${ ${RUST_PROGRAM } _VERSION_RESULT} EQUAL 0 )
message ( STATUS "Rust tool `${RUST_PROGRAM}` not found: Failed to determine version." )
unset ( ${ RUST_PROGRAM } _EXECUTABLE )
else ( )
string ( REGEX
M A T C H " [ 0 - 9 ] + \ \ . [ 0 - 9 ] + ( \ \ . [ 0 - 9 ] + ) ? ( - n i g h t l y ) ? "
$ { R U S T _ P R O G R A M } _ V E R S I O N " $ { $ { R U S T _ P R O G R A M } _ V E R S I O N _ O U T P U T } "
)
set ( ${ RUST_PROGRAM } _VERSION "${${RUST_PROGRAM}_VERSION}" PARENT_SCOPE )
message ( STATUS "Rust tool `${RUST_PROGRAM}` found: ${${RUST_PROGRAM}_EXECUTABLE}, ${${RUST_PROGRAM}_VERSION}" )
endif ( )
mark_as_advanced ( ${ RUST_PROGRAM } _EXECUTABLE ${ RUST_PROGRAM } _VERSION )
else ( )
if ( ${ ${RUST_PROGRAM } _REQUIRED} )
message ( FATAL_ERROR "Rust tool `${RUST_PROGRAM}` not found." )
else ( )
message ( STATUS "Rust tool `${RUST_PROGRAM}` not found." )
endif ( )
endif ( )
endfunction ( )
2021-04-22 17:35:15 -07:00
function ( cargo_vendor )
set ( options )
set ( oneValueArgs TARGET WORKING_DIRECTORY )
cmake_parse_arguments ( ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ ARGN } )
if ( NOT EXISTS ${ ARGS_WORKING_DIRECTORY } }/.cargo/config.toml )
# Vendor the dependencies and create .cargo/config.toml
# Vendored dependencies will be used during the build.
# This will allow us to package vendored dependencies in source tarballs
# for online builds when we run `cpack --config CPackSourceConfig.cmake`
message ( STATUS "Running `cargo vendor` to collect dependencies for ${ARGS_TARGET}. This may take a while if the local crates.io index needs to be updated ..." )
make_directory ( ${ ARGS_WORKING_DIRECTORY } /.cargo )
execute_process (
C O M M A N D $ { C M A K E _ C O M M A N D } - E e n v " C A R G O _ T A R G E T _ D I R = $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } " $ { c a r g o _ E X E C U T A B L E } v e n d o r " . c a r g o / v e n d o r "
W O R K I N G _ D I R E C T O R Y " $ { A R G S _ W O R K I N G _ D I R E C T O R Y } "
O U T P U T _ V A R I A B L E C A R G O _ V E N D O R _ O U T P U T
E R R O R _ V A R I A B L E C A R G O _ V E N D O R _ E R R O R
R E S U L T _ V A R I A B L E C A R G O _ V E N D O R _ R E S U L T
)
if ( NOT ${ CARGO_VENDOR_RESULT } EQUAL 0 )
message ( FATAL_ERROR "Failed!\n${CARGO_VENDOR_ERROR}" )
else ( )
message ( "Success!" )
endif ( )
write_file ( ${ ARGS_WORKING_DIRECTORY } /.cargo/config.toml "
[ s o u r c e . c r a t e s - i o ]
r e p l a c e - w i t h = \ " v e n d o r e d - s o u r c e s \ "
[ s o u r c e . v e n d o r e d - s o u r c e s ]
d i r e c t o r y = \ " . c a r g o / v e n d o r \ "
"
)
endif ( )
endfunction ( )
2021-03-04 21:14:08 -08:00
function ( add_rust_library )
set ( options )
set ( oneValueArgs TARGET WORKING_DIRECTORY )
cmake_parse_arguments ( ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ ARGN } )
if ( WIN32 )
set ( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${LIB_TARGET}/${LIB_BUILD_TYPE}/${ARGS_TARGET}.lib" )
else ( )
set ( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${LIB_TARGET}/${LIB_BUILD_TYPE}/lib${ARGS_TARGET}.a" )
endif ( )
file ( GLOB_RECURSE LIB_SOURCES "${ARGS_WORKING_DIRECTORY}/*.rs" )
set ( MY_CARGO_ARGS ${ CARGO_ARGS } )
list ( APPEND MY_CARGO_ARGS "--target-dir" ${ CMAKE_CURRENT_BINARY_DIR } )
list ( JOIN MY_CARGO_ARGS " " MY_CARGO_ARGS_STRING )
# Build the library and generate the c-binding, if `cbindgen` is required.
if ( ${ cbindgen_REQUIRED } )
2021-10-26 19:35:37 -07:00
if ( "${CMAKE_OSX_ARCHITECTURES}" MATCHES "^arm64;x86_64$" )
add_custom_command (
O U T P U T " $ { O U T P U T } "
C O M M A N D $ { C M A K E _ C O M M A N D } - E e n v " C A R G O _ T A R G E T _ D I R = $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } " $ { c a r g o _ E X E C U T A B L E } A R G S $ { M Y _ C A R G O _ A R G S } - - t a r g e t = x 8 6 _ 6 4 - a p p l e - d a r w i n
C O M M A N D $ { C M A K E _ C O M M A N D } - E e n v " C A R G O _ T A R G E T _ D I R = $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } " $ { c a r g o _ E X E C U T A B L E } A R G S $ { M Y _ C A R G O _ A R G S } - - t a r g e t = a a r c h 6 4 - a p p l e - d a r w i n
C O M M A N D $ { C M A K E _ C O M M A N D } - E m a k e _ d i r e c t o r y " $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } / $ { L I B _ T A R G E T } / $ { L I B _ B U I L D _ T Y P E } "
C O M M A N D l i p o A R G S - c r e a t e $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } / x 8 6 _ 6 4 - a p p l e - d a r w i n / $ { L I B _ B U I L D _ T Y P E } / l i b $ { A R G S _ T A R G E T } . a $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } / a a r c h 6 4 - a p p l e - d a r w i n / $ { L I B _ B U I L D _ T Y P E } / l i b $ { A R G S _ T A R G E T } . a - o u t p u t " $ { O U T P U T } "
C O M M A N D $ { c b i n d g e n _ E X E C U T A B L E } - - l a n g c - o $ { A R G S _ W O R K I N G _ D I R E C T O R Y } / $ { A R G S _ T A R G E T } . h $ { A R G S _ W O R K I N G _ D I R E C T O R Y }
W O R K I N G _ D I R E C T O R Y " $ { A R G S _ W O R K I N G _ D I R E C T O R Y } "
D E P E N D S $ { L I B _ S O U R C E S }
C O M M E N T " B u i l d i n g $ { A R G S _ T A R G E T } i n $ { A R G S _ W O R K I N G _ D I R E C T O R Y } w i t h : $ { c a r g o _ E X E C U T A B L E } $ { M Y _ C A R G O _ A R G S _ S T R I N G } " )
else ( )
add_custom_command (
O U T P U T " $ { O U T P U T } "
C O M M A N D $ { C M A K E _ C O M M A N D } - E e n v " C A R G O _ T A R G E T _ D I R = $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } " $ { c a r g o _ E X E C U T A B L E } A R G S $ { M Y _ C A R G O _ A R G S }
C O M M A N D $ { c b i n d g e n _ E X E C U T A B L E } - - l a n g c - o $ { A R G S _ W O R K I N G _ D I R E C T O R Y } / $ { A R G S _ T A R G E T } . h $ { A R G S _ W O R K I N G _ D I R E C T O R Y }
W O R K I N G _ D I R E C T O R Y " $ { A R G S _ W O R K I N G _ D I R E C T O R Y } "
D E P E N D S $ { L I B _ S O U R C E S }
C O M M E N T " B u i l d i n g $ { A R G S _ T A R G E T } i n $ { A R G S _ W O R K I N G _ D I R E C T O R Y } w i t h : $ { c a r g o _ E X E C U T A B L E } $ { M Y _ C A R G O _ A R G S _ S T R I N G } " )
endif ( )
2021-03-04 21:14:08 -08:00
else ( )
2021-10-26 19:35:37 -07:00
if ( "${CMAKE_OSX_ARCHITECTURES}" MATCHES "^arm64;x86_64$" )
add_custom_command (
O U T P U T " $ { O U T P U T } "
C O M M A N D $ { C M A K E _ C O M M A N D } - E e n v " C A R G O _ T A R G E T _ D I R = $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } " $ { c a r g o _ E X E C U T A B L E } A R G S $ { M Y _ C A R G O _ A R G S } - - t a r g e t = x 8 6 _ 6 4 - a p p l e - d a r w i n
C O M M A N D $ { C M A K E _ C O M M A N D } - E e n v " C A R G O _ T A R G E T _ D I R = $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } " $ { c a r g o _ E X E C U T A B L E } A R G S $ { M Y _ C A R G O _ A R G S } - - t a r g e t = a a r c h 6 4 - a p p l e - d a r w i n
C O M M A N D $ { C M A K E _ C O M M A N D } - E m a k e _ d i r e c t o r y " $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } / $ { L I B _ T A R G E T } / $ { L I B _ B U I L D _ T Y P E } "
C O M M A N D l i p o A R G S - c r e a t e $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } / x 8 6 _ 6 4 - a p p l e - d a r w i n / $ { L I B _ B U I L D _ T Y P E } / l i b $ { A R G S _ T A R G E T } . a $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } / a a r c h 6 4 - a p p l e - d a r w i n / $ { L I B _ B U I L D _ T Y P E } / l i b $ { A R G S _ T A R G E T } . a - o u t p u t " $ { O U T P U T } "
W O R K I N G _ D I R E C T O R Y " $ { A R G S _ W O R K I N G _ D I R E C T O R Y } "
D E P E N D S $ { L I B _ S O U R C E S }
C O M M E N T " B u i l d i n g $ { A R G S _ T A R G E T } i n $ { A R G S _ W O R K I N G _ D I R E C T O R Y } w i t h : $ { c a r g o _ E X E C U T A B L E } $ { M Y _ C A R G O _ A R G S _ S T R I N G } " )
else ( )
add_custom_command (
O U T P U T " $ { O U T P U T } "
C O M M A N D $ { C M A K E _ C O M M A N D } - E e n v " C A R G O _ T A R G E T _ D I R = $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } " $ { c a r g o _ E X E C U T A B L E } A R G S $ { M Y _ C A R G O _ A R G S }
W O R K I N G _ D I R E C T O R Y " $ { A R G S _ W O R K I N G _ D I R E C T O R Y } "
D E P E N D S $ { L I B _ S O U R C E S }
C O M M E N T " B u i l d i n g $ { A R G S _ T A R G E T } i n $ { A R G S _ W O R K I N G _ D I R E C T O R Y } w i t h : $ { c a r g o _ E X E C U T A B L E } $ { M Y _ C A R G O _ A R G S _ S T R I N G } " )
endif ( )
2021-03-04 21:14:08 -08:00
endif ( )
# Create a target from the build output
add_custom_target ( ${ ARGS_TARGET } _target
D E P E N D S $ { O U T P U T } )
# Create a static imported library target from library target
add_library ( ${ ARGS_TARGET } STATIC IMPORTED GLOBAL )
add_dependencies ( ${ ARGS_TARGET } ${ ARGS_TARGET } _target )
target_link_libraries ( ${ ARGS_TARGET } INTERFACE ${ RUST_NATIVE_STATIC_LIBS } )
# Specify where the library is and where to find the headers
set_target_properties ( ${ ARGS_TARGET }
P R O P E R T I E S
I M P O R T E D _ L O C A T I O N " $ { O U T P U T } "
I N T E R F A C E _ I N C L U D E _ D I R E C T O R I E S " $ { A R G S _ W O R K I N G _ D I R E C T O R Y } "
)
2021-04-22 17:35:15 -07:00
# Vendor the dependencies, if desired
if ( VENDOR_DEPENDENCIES )
cargo_vendor ( TARGET "${ARGS_TARGET}" WORKING_DIRECTORY "${ARGS_WORKING_DIRECTORY}" )
endif ( )
2021-03-04 21:14:08 -08:00
endfunction ( )
function ( add_rust_test )
set ( options )
set ( oneValueArgs NAME WORKING_DIRECTORY )
cmake_parse_arguments ( ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ ARGN } )
add_test (
N A M E t e s t - $ { A R G S _ N A M E }
C O M M A N D $ { C M A K E _ C O M M A N D } - E e n v " C A R G O _ T A R G E T _ D I R = $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } " $ { c a r g o _ E X E C U T A B L E } t e s t - v v - - c o l o r a l w a y s
W O R K I N G _ D I R E C T O R Y $ { A R G S _ W O R K I N G _ D I R E C T O R Y }
)
endfunction ( )
#
# Cargo is the primary tool for using the Rust Toolchain to to build static
# libs that can include other crate dependencies.
#
find_rust_program ( cargo )
# These other programs may also be useful...
find_rust_program ( rustc )
find_rust_program ( rustup )
find_rust_program ( rust-gdb )
find_rust_program ( rust-lldb )
find_rust_program ( rustdoc )
find_rust_program ( rustfmt )
find_rust_program ( bindgen )
find_rust_program ( cbindgen )
# Determine the native libs required to link w/ rust static libs
# message(STATUS "Detecting native static libs for rust: ${rustc_EXECUTABLE} --crate-type staticlib --print=native-static-libs /dev/null")
execute_process (
C O M M A N D $ { C M A K E _ C O M M A N D } - E e n v " C A R G O _ T A R G E T _ D I R = $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } " $ { r u s t c _ E X E C U T A B L E } - - c r a t e - t y p e s t a t i c l i b - - p r i n t = n a t i v e - s t a t i c - l i b s / d e v / n u l l
O U T P U T _ V A R I A B L E R U S T _ N A T I V E _ S T A T I C _ L I B S _ O U T P U T
E R R O R _ V A R I A B L E R U S T _ N A T I V E _ S T A T I C _ L I B S _ E R R O R
R E S U L T _ V A R I A B L E R U S T _ N A T I V E _ S T A T I C _ L I B S _ R E S U L T
)
string ( REGEX REPLACE "\r?\n" ";" LINE_LIST "${RUST_NATIVE_STATIC_LIBS_ERROR}" )
foreach ( LINE ${ LINE_LIST } )
# do the match on each line
string ( REGEX MATCH "native-static-libs: .*" LINE "${LINE}" )
if ( NOT LINE )
continue ( )
endif ( )
string ( REPLACE "native-static-libs: " "" LINE "${LINE}" )
string ( REGEX REPLACE " " "" LINE "${LINE}" )
string ( REGEX REPLACE " " ";" LINE "${LINE}" )
if ( LINE )
message ( STATUS "Rust's native static libs: ${LINE}" )
set ( RUST_NATIVE_STATIC_LIBS "${LINE}" )
break ( )
endif ( )
endforeach ( )
if ( WIN32 )
if ( CMAKE_SIZEOF_VOID_P EQUAL 8 )
set ( LIB_TARGET "x86_64-pc-windows-msvc" )
else ( )
set ( LIB_TARGET "i686-pc-windows-msvc" )
endif ( )
elseif ( ANDROID )
if ( ANDROID_SYSROOT_ABI STREQUAL "x86" )
set ( LIB_TARGET "i686-linux-android" )
elseif ( ANDROID_SYSROOT_ABI STREQUAL "x86_64" )
set ( LIB_TARGET "x86_64-linux-android" )
elseif ( ANDROID_SYSROOT_ABI STREQUAL "arm" )
set ( LIB_TARGET "arm-linux-androideabi" )
elseif ( ANDROID_SYSROOT_ABI STREQUAL "arm64" )
set ( LIB_TARGET "aarch64-linux-android" )
endif ( )
elseif ( IOS )
set ( LIB_TARGET "universal" )
elseif ( CMAKE_SYSTEM_NAME STREQUAL Darwin )
2021-10-26 19:35:37 -07:00
if ( "${CMAKE_OSX_ARCHITECTURES}" MATCHES "^arm64;x86_64$" )
set ( LIB_TARGET "universal-apple-darwin" )
else ( )
set ( LIB_TARGET "x86_64-apple-darwin" )
endif ( )
2021-03-04 21:14:08 -08:00
else ( )
if ( CMAKE_SIZEOF_VOID_P EQUAL 8 )
set ( LIB_TARGET "x86_64-unknown-linux-gnu" )
else ( )
set ( LIB_TARGET "i686-unknown-linux-gnu" )
endif ( )
endif ( )
if ( IOS )
set ( CARGO_ARGS "lipo" )
else ( )
set ( CARGO_ARGS "build" )
2021-10-26 19:35:37 -07:00
if ( NOT "${CMAKE_OSX_ARCHITECTURES}" MATCHES "^arm64;x86_64$" ) # Don't specify the target for universal, we'll do that manually for each build.
list ( APPEND CARGO_ARGS "--target" ${ LIB_TARGET } )
endif ( )
2021-03-04 21:14:08 -08:00
endif ( )
if ( NOT CMAKE_BUILD_TYPE )
set ( LIB_BUILD_TYPE "debug" )
elseif ( ${ CMAKE_BUILD_TYPE } STREQUAL "Release" )
set ( LIB_BUILD_TYPE "release" )
list ( APPEND CARGO_ARGS "--release" )
else ( )
set ( LIB_BUILD_TYPE "debug" )
endif ( )
find_package_handle_standard_args ( Rust
R E Q U I R E D _ V A R S c a r g o _ E X E C U T A B L E
V E R S I O N _ V A R c a r g o _ V E R S I O N
)