mirror of
https://github.com/facebook/sapling.git
synced 2024-10-04 22:07:44 +03:00
Add rust_cxx_bridge CMake function
Summary: X-link: https://github.com/facebookincubator/hsthrift/pull/120 X-link: https://github.com/facebook/folly/pull/2096 X-link: https://github.com/facebookexperimental/edencommon/pull/14 X-link: https://github.com/facebook/mvfst/pull/322 X-link: https://github.com/facebookincubator/delos_core/pull/9 X-link: https://github.com/facebook/fboss/pull/166 X-link: https://github.com/facebookincubator/zstrong/pull/617 X-link: https://github.com/facebookincubator/katran/pull/208 X-link: https://github.com/facebookincubator/fizz/pull/102 X-link: https://github.com/facebookexternal/traffixr/pull/4 X-link: https://github.com/facebook/watchman/pull/1173 X-link: https://github.com/facebook/proxygen/pull/473 X-link: https://github.com/facebook/hhvm/pull/9411 X-link: https://github.com/facebook/fbthrift/pull/587 X-link: https://github.com/facebookincubator/velox/pull/7518 We need a better way to create cxxbridges - something that uses the recommended method of cxxbridge-cmd. This function creates C++ bindings using the [cxx] crate. Original function found here: https://github.com/corrosion-rs/corrosion/blob/master/cmake/Corrosion.cmake#L1390 Reviewed By: xavierd Differential Revision: D51160627 fbshipit-source-id: c293c48ef8fabd043c1746798b6e85212d3d0f76
This commit is contained in:
parent
ab5ab8202d
commit
1264b9881c
@ -324,3 +324,203 @@ function(install_rust_static_library TARGET)
|
||||
DESTINATION ${ARG_INSTALL_DIR}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
# This function creates C++ bindings using the [cxx] crate.
|
||||
#
|
||||
# Original function found here: https://github.com/corrosion-rs/corrosion/blob/master/cmake/Corrosion.cmake#L1390
|
||||
# Simplified for use as part of RustStaticLibrary module. License below.
|
||||
#
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2018 Andrew Gaspar
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
#
|
||||
# The rules approximately do the following:
|
||||
# - Check which version of `cxx` the Rust crate depends on.
|
||||
# - Check if the exact same version of `cxxbridge-cmd` is installed
|
||||
# - If not, create a rule to build the exact same version of `cxxbridge-cmd`.
|
||||
# - Create rules to run `cxxbridge` and generate
|
||||
# - The `rust/cxx.h` header
|
||||
# - A header and source file for the specified CXX_BRIDGE_FILE.
|
||||
# - The generated sources (and header include directories) are added to the
|
||||
# `${TARGET}` CMake library target.
|
||||
#
|
||||
# ```cmake
|
||||
# rust_cxx_bridge(<TARGET> <CXX_BRIDGE_FILE> [CRATE <CRATE_NAME>])
|
||||
# ```
|
||||
#
|
||||
# Parameters:
|
||||
# - TARGET:
|
||||
# Name of the target name. The target that the bridge will be included with.
|
||||
# - CXX_BRIDGE_FILE:
|
||||
# Name of the file that include the cxxbridge (e.g., "src/ffi.rs").
|
||||
# - CRATE_NAME:
|
||||
# Name of the crate. This parameter is optional. If unspecified, it will
|
||||
# fallback to `${TARGET}`.
|
||||
#
|
||||
function(rust_cxx_bridge TARGET CXX_BRIDGE_FILE)
|
||||
fb_cmake_parse_args(ARG "" "CRATE" "" "${ARGN}")
|
||||
|
||||
if(DEFINED ARG_CRATE)
|
||||
set(crate_name "${ARG_CRATE}")
|
||||
else()
|
||||
set(crate_name "${TARGET}")
|
||||
endif()
|
||||
|
||||
if(USE_CARGO_VENDOR)
|
||||
set(extra_cargo_env "CARGO_HOME=${RUST_CARGO_HOME}")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}" -E env
|
||||
${extra_cargo_env}
|
||||
"${CARGO_COMMAND}" tree -i cxx --depth=0
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
RESULT_VARIABLE cxx_version_result
|
||||
OUTPUT_VARIABLE cxx_version_output
|
||||
)
|
||||
|
||||
if(NOT "${cxx_version_result}" EQUAL "0")
|
||||
message(FATAL_ERROR "Crate ${crate_name} does not depend on cxx.")
|
||||
endif()
|
||||
if(cxx_version_output MATCHES "cxx v([0-9]+.[0-9]+.[0-9]+)")
|
||||
set(cxx_required_version "${CMAKE_MATCH_1}")
|
||||
else()
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Failed to parse cxx version from cargo tree output: `cxx_version_output`")
|
||||
endif()
|
||||
|
||||
# First check if a suitable version of cxxbridge is installed
|
||||
find_program(INSTALLED_CXXBRIDGE cxxbridge PATHS "$ENV{HOME}/.cargo/bin/")
|
||||
mark_as_advanced(INSTALLED_CXXBRIDGE)
|
||||
if(INSTALLED_CXXBRIDGE)
|
||||
execute_process(
|
||||
COMMAND "${INSTALLED_CXXBRIDGE}" --version
|
||||
OUTPUT_VARIABLE cxxbridge_version_output
|
||||
)
|
||||
if(cxxbridge_version_output MATCHES "cxxbridge ([0-9]+.[0-9]+.[0-9]+)")
|
||||
set(cxxbridge_version "${CMAKE_MATCH_1}")
|
||||
else()
|
||||
set(cxxbridge_version "")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(cxxbridge "")
|
||||
if(cxxbridge_version)
|
||||
if(cxxbridge_version VERSION_EQUAL cxx_required_version)
|
||||
set(cxxbridge "${INSTALLED_CXXBRIDGE}")
|
||||
if(NOT TARGET "cxxbridge_v${cxx_required_version}")
|
||||
# Add an empty target.
|
||||
add_custom_target("cxxbridge_v${cxx_required_version}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# No suitable version of cxxbridge was installed,
|
||||
# so use custom target to install correct version.
|
||||
if(NOT cxxbridge)
|
||||
if(NOT TARGET "cxxbridge_v${cxx_required_version}")
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
"${CMAKE_BINARY_DIR}/cxxbridge_v${cxx_required_version}/bin/cxxbridge"
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}" -E make_directory
|
||||
"${CMAKE_BINARY_DIR}/cxxbridge_v${cxx_required_version}"
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}" -E remove -f "${CMAKE_CURRENT_SOURCE_DIR}/Cargo.lock"
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}" -E env
|
||||
${extra_cargo_env}
|
||||
"${CARGO_COMMAND}" install cxxbridge-cmd
|
||||
--version "${cxx_required_version}"
|
||||
--root "${CMAKE_BINARY_DIR}/cxxbridge_v${cxx_required_version}"
|
||||
--quiet
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}" -E remove -f "${CMAKE_CURRENT_SOURCE_DIR}/Cargo.lock"
|
||||
COMMENT "Installing cxxbridge (version ${cxx_required_version})"
|
||||
)
|
||||
add_custom_target(
|
||||
"cxxbridge_v${cxx_required_version}"
|
||||
DEPENDS "${CMAKE_BINARY_DIR}/cxxbridge_v${cxx_required_version}/bin/cxxbridge"
|
||||
)
|
||||
endif()
|
||||
set(
|
||||
cxxbridge
|
||||
"${CMAKE_BINARY_DIR}/cxxbridge_v${cxx_required_version}/bin/cxxbridge"
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(${crate_name} STATIC)
|
||||
target_include_directories(
|
||||
${crate_name}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/rust")
|
||||
add_custom_command(
|
||||
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/rust/cxx.h"
|
||||
COMMAND
|
||||
"${cxxbridge}" --header --output "${CMAKE_CURRENT_BINARY_DIR}/rust/cxx.h"
|
||||
DEPENDS "cxxbridge_v${cxx_required_version}"
|
||||
COMMENT "Generating rust/cxx.h header"
|
||||
)
|
||||
|
||||
get_filename_component(filename_component ${CXX_BRIDGE_FILE} NAME)
|
||||
get_filename_component(directory_component ${CXX_BRIDGE_FILE} DIRECTORY)
|
||||
set(directory "")
|
||||
if(directory_component)
|
||||
set(directory "${directory_component}")
|
||||
endif()
|
||||
|
||||
set(cxx_header ${directory}/${filename_component}.h)
|
||||
set(cxx_source ${directory}/${filename_component}.cc)
|
||||
set(rust_source_path "${CMAKE_CURRENT_SOURCE_DIR}/${CXX_BRIDGE_FILE}")
|
||||
|
||||
file(
|
||||
MAKE_DIRECTORY
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${directory_component}"
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${cxx_header}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${cxx_source}"
|
||||
COMMAND
|
||||
${cxxbridge} ${rust_source_path}
|
||||
--header --output "${CMAKE_CURRENT_BINARY_DIR}/${cxx_header}"
|
||||
COMMAND
|
||||
${cxxbridge} ${rust_source_path}
|
||||
--output "${CMAKE_CURRENT_BINARY_DIR}/${cxx_source}"
|
||||
--include "${cxx_header}"
|
||||
DEPENDS "cxxbridge_v${cxx_required_version}" "${rust_source_path}"
|
||||
COMMENT "Generating cxx bindings for crate ${crate_name}"
|
||||
)
|
||||
|
||||
target_sources(${crate_name}
|
||||
PRIVATE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${cxx_header}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/rust/cxx.h"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${cxx_source}"
|
||||
)
|
||||
endfunction()
|
||||
|
Loading…
Reference in New Issue
Block a user