Allow compiling with Rust code (#3137)

Co-authored-by: Yuri Astrakhan <YuriAstrakhan@gmail.com>
Co-authored-by: Ian Wagner <ianwagner+github@switzerlandmail.ch>
This commit is contained in:
Bart Louwers
2025-01-16 16:01:11 +01:00
committed by GitHub
parent 79d625b03c
commit 527e70b6fa
23 changed files with 649 additions and 25 deletions

1
rustutils/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target

46
rustutils/BUILD.bazel Normal file
View File

@@ -0,0 +1,46 @@
load("@rules_rust//rust:defs.bzl", "rust_static_library")
genrule(
name = "cpp_bindings",
srcs = [
"src/color.rs",
],
outs = [
"cpp/include/rustutils/color.hpp",
"cpp/src/color.rs.cpp",
],
cmd = "CXXBRIDGE_CMD=$(location @cxx.rs//:codegen) ./$(location :generate.sh) $(@D) $(SRCS)",
# Using the cxxbridge binary built by Bazel
tools = [
":generate.sh",
"@cxx.rs//:codegen",
],
)
rust_static_library(
name = "rustutils",
srcs = [
"src/color.rs",
"src/lib.rs",
],
crate_name = "rustutils",
visibility = ["//visibility:public"],
deps = [
"@crates//:csscolorparser",
"@crates//:cxx",
],
)
cc_library(
name = "rustutilslib",
srcs = [
":cpp_bindings",
],
includes = [
"cpp/include",
],
visibility = ["//visibility:public"],
deps = [
":rustutils",
],
)

162
rustutils/Cargo.lock generated Normal file
View File

@@ -0,0 +1,162 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "cc"
version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f"
[[package]]
name = "csscolorparser"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb2a7d3066da2de787b7f032c736763eb7ae5d355f81a68bab2675a96008b0bf"
dependencies = [
"phf",
]
[[package]]
name = "cxx"
version = "1.0.124"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "273dcfd3acd4e1e276af13ed2a43eea7001318823e7a726a6b3ed39b4acc0b82"
dependencies = [
"cc",
"cxxbridge-flags",
"cxxbridge-macro",
"link-cplusplus",
]
[[package]]
name = "cxxbridge-flags"
version = "1.0.124"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "839fcd5e43464614ffaa989eaf1c139ef1f0c51672a1ed08023307fa1b909ccd"
[[package]]
name = "cxxbridge-macro"
version = "1.0.124"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b2c1c1776b986979be68bb2285da855f8d8a35851a769fca8740df7c3d07877"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "link-cplusplus"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9"
dependencies = [
"cc",
]
[[package]]
name = "phf"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
dependencies = [
"phf_macros",
"phf_shared",
]
[[package]]
name = "phf_generator"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
dependencies = [
"phf_shared",
"rand",
]
[[package]]
name = "phf_macros"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
dependencies = [
"phf_generator",
"phf_shared",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "phf_shared"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
dependencies = [
"siphasher",
]
[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[package]]
name = "rustutils"
version = "0.1.0"
dependencies = [
"csscolorparser",
"cxx",
]
[[package]]
name = "siphasher"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
[[package]]
name = "syn"
version = "2.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"

19
rustutils/Cargo.toml Normal file
View File

@@ -0,0 +1,19 @@
[package]
name = "rustutils"
version = "0.1.0"
authors = ["MapLibre contributors"]
description = "Core Rust utilities for MapLibre Native"
edition = "2021"
license = "BSD-2-Clause"
repository = "https://github.com/maplibre/maplibre-native"
[lib]
crate-type = ["staticlib"]
[dependencies]
csscolorparser = "0.6.2"
cxx = "1"
[profile.release]
lto = true
codegen-units = 1

35
rustutils/generate.sh Executable file
View File

@@ -0,0 +1,35 @@
#!/bin/bash
# Run this script from the repository root
# Install cxxbridge with:
# $ cargo install cxxbridge-cmd
set -e
if [ "$#" -lt 2 ]; then
echo "Error: output_dir and at least one input file are required." >&2
echo "Usage: $0 <output_dir> <input_file1> [input_file2 ...]" >&2
exit 1
fi
# Use CXXBRIDGE_CMD environment variable if set, otherwise fallback to "cxxbridge"
CXXBRIDGE_CMD="${CXXBRIDGE_CMD:-cxxbridge}"
output_dir="$1"
shift
for input_file in "$@"; do
if [[ "$input_file" != *.rs ]]; then
echo "Error: All input files must have a .rs extension. Invalid file: $input_file" >&2
exit 1
fi
done
mkdir -p "$output_dir/cpp/include/rustutils"
mkdir -p "$output_dir/cpp/src"
for input_file in "$@"; do
base_name=$(basename "$input_file" .rs)
"$CXXBRIDGE_CMD" "$input_file" --header > "$output_dir/cpp/include/rustutils/${base_name}.hpp"
"$CXXBRIDGE_CMD" "$input_file" > "$output_dir/cpp/src/${base_name}.rs.cpp"
done

63
rustutils/rustutils.cmake Normal file
View File

@@ -0,0 +1,63 @@
# Include guard
if(TARGET rustutils)
return()
endif()
include(FetchContent)
FetchContent_Declare(
Corrosion
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
GIT_TAG v0.5 # Optionally specify a commit hash, version tag or branch here
)
FetchContent_MakeAvailable(Corrosion)
corrosion_import_crate(MANIFEST_PATH ${CMAKE_CURRENT_LIST_DIR}/Cargo.toml)
# Define output directories for generated bindings
set(RUSTUTILS_OUTPUT_DIR "${CMAKE_BINARY_DIR}/rustutils_bindings")
set(RUSTUTILS_INCLUDE_DIR "${RUSTUTILS_OUTPUT_DIR}/cpp/include")
set(RUSTUTILS_SRC_DIR "${RUSTUTILS_OUTPUT_DIR}/cpp/src")
# Ensure the output directories exist
file(MAKE_DIRECTORY ${RUSTUTILS_INCLUDE_DIR})
file(MAKE_DIRECTORY ${RUSTUTILS_SRC_DIR})
set(RUSTUTILS_RS_FILES
${CMAKE_CURRENT_LIST_DIR}/src/color.rs
)
# Initialize variables for generated files
set(RUSTUTILS_GENERATED_SOURCES)
set(RUSTUTILS_GENERATED_HEADERS)
# Transform .rs to .rs.cpp and .hpp
foreach(rs_file ${RUSTUTILS_RS_FILES})
get_filename_component(base_name ${rs_file} NAME_WE)
list(APPEND RUSTUTILS_GENERATED_SOURCES "${RUSTUTILS_SRC_DIR}/${base_name}.rs.cpp")
list(APPEND RUSTUTILS_GENERATED_HEADERS "${RUSTUTILS_INCLUDE_DIR}/rustutils/${base_name}.hpp")
endforeach()
add_custom_command(
OUTPUT ${RUSTUTILS_GENERATED_SOURCES} ${RUSTUTILS_GENERATED_HEADERS}
COMMAND ${CMAKE_COMMAND} -E env
${CMAKE_CURRENT_LIST_DIR}/generate.sh ${RUSTUTILS_OUTPUT_DIR} ${RUSTUTILS_RS_FILES}
DEPENDS ${CMAKE_CURRENT_LIST_DIR}/generate.sh ${RUSTUTILS_RS_FILES}
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
COMMENT "Generating C++ bindings for Rust sources"
VERBATIM
)
add_custom_target(rustutils_bindings DEPENDS ${RUSTUTILS_GENERATED_SOURCES} ${RUSTUTILS_GENERATED_HEADERS})
add_library(mbgl-rustutils STATIC
${RUSTUTILS_GENERATED_SOURCES}
)
add_dependencies(mbgl-rustutils rustutils_bindings)
target_include_directories(mbgl-rustutils PUBLIC
${RUSTUTILS_INCLUDE_DIR}
)
target_link_libraries(mbgl-rustutils PUBLIC rustutils)

35
rustutils/src/color.rs Normal file
View File

@@ -0,0 +1,35 @@
use csscolorparser::Color;
#[cxx::bridge(namespace = "rustutils")]
mod ffi {
struct ParsedColor {
pub success: bool,
pub r: f32,
pub g: f32,
pub b: f32,
pub a: f32,
}
extern "Rust" {
fn parse_css_color(css_str: &str) -> ParsedColor;
}
}
pub fn parse_css_color(css_str: &str) -> ffi::ParsedColor {
css_str
.parse::<Color>()
.map(|color| ffi::ParsedColor {
success: true,
r: color.r as f32,
g: color.g as f32,
b: color.b as f32,
a: color.a as f32,
})
.unwrap_or_else(|_| ffi::ParsedColor {
success: false,
r: 0.0,
g: 0.0,
b: 0.0,
a: 0.0,
})
}

1
rustutils/src/lib.rs Normal file
View File

@@ -0,0 +1 @@
mod color;