Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,6 @@ src/rust/fcb_core/tests/data/*.json
flamegraph*
.roo
.serena/
*.so
*.so

build/
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@
],
"cursorpyright.analysis.extraPaths": [
"${workspaceFolder}/src/rust/fcb_py/python"
]
],
"cmake.sourceDirectory": "${workspaceFolder}/src/cpp"
}
83 changes: 83 additions & 0 deletions src/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
cmake_minimum_required(VERSION 3.16)
project(fcb_cpp VERSION 0.1.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Find cxxbridge CLI tool
find_program(CXXBRIDGE cxxbridge)
if(NOT CXXBRIDGE)
message(STATUS "cxxbridge not found, installing via cargo...")
execute_process(
COMMAND cargo install cxxbridge-cmd
RESULT_VARIABLE CXXBRIDGE_INSTALL_RESULT
)
find_program(CXXBRIDGE cxxbridge REQUIRED)
endif()
Comment on lines +7 to +16
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This CMake script automatically installs and executes the cxxbridge-cmd tool via cargo install cxxbridge-cmd without pinning a version or verifying integrity, which introduces a build-time supply-chain risk. An attacker who compromises the crate or crates.io could ship a malicious cxxbridge-cmd that runs in your build and generates backdoored bridge code compiled into production artifacts. To mitigate this, avoid auto-installation in the build, pin cxxbridge-cmd to a specific trusted version or commit, and/or vendor or pre-generate the bridge code so that build steps do not fetch and execute mutable third-party tooling.

Copilot uses AI. Check for mistakes.

# Configuration
set(RUST_LIB_DIR ${CMAKE_SOURCE_DIR}/../rust)
set(GENERATED_DIR ${CMAKE_BINARY_DIR}/generated)
file(MAKE_DIRECTORY ${GENERATED_DIR})

# Build Rust static library
add_custom_command(
OUTPUT ${RUST_LIB_DIR}/target/release/libfcb_cpp.a
COMMAND cargo build --release -p fcb_cpp
WORKING_DIRECTORY ${RUST_LIB_DIR}
DEPENDS ${RUST_LIB_DIR}/fcb_cpp/src/lib.rs
DEPENDS ${RUST_LIB_DIR}/fcb_cpp/src/reader.rs
DEPENDS ${RUST_LIB_DIR}/fcb_cpp/src/writer.rs
COMMENT "Building Rust fcb_cpp library"
)

add_custom_target(rust_library DEPENDS ${RUST_LIB_DIR}/target/release/libfcb_cpp.a)

# Generate C++ bridge code
add_custom_command(
OUTPUT ${GENERATED_DIR}/lib.rs.h
COMMAND ${CXXBRIDGE} ${RUST_LIB_DIR}/fcb_cpp/src/lib.rs --header > ${GENERATED_DIR}/lib.rs.h
DEPENDS ${RUST_LIB_DIR}/fcb_cpp/src/lib.rs
COMMENT "Generating C++ header from CXX bridge"
)

add_custom_command(
OUTPUT ${GENERATED_DIR}/lib.rs.cc
COMMAND ${CXXBRIDGE} ${RUST_LIB_DIR}/fcb_cpp/src/lib.rs > ${GENERATED_DIR}/lib.rs.cc
DEPENDS ${RUST_LIB_DIR}/fcb_cpp/src/lib.rs
COMMENT "Generating C++ source from CXX bridge"
)

# Create fcb library
add_library(fcb STATIC
${GENERATED_DIR}/lib.rs.cc
)
Comment on lines +44 to +54
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CMake generates and compiles lib.rs.cc (the CXX bridge source) and links it with the Rust staticlib, while the Rust crate’s build.rs also compiles the same bridge code via cxx_build::bridge(...).compile(...). This duplication is likely to cause duplicate symbol errors. Adjust either the Rust build or the CMake build so the bridge .cc is compiled exactly once in the final link.

Suggested change
add_custom_command(
OUTPUT ${GENERATED_DIR}/lib.rs.cc
COMMAND ${CXXBRIDGE} ${RUST_LIB_DIR}/fcb_cpp/src/lib.rs > ${GENERATED_DIR}/lib.rs.cc
DEPENDS ${RUST_LIB_DIR}/fcb_cpp/src/lib.rs
COMMENT "Generating C++ source from CXX bridge"
)
# Create fcb library
add_library(fcb STATIC
${GENERATED_DIR}/lib.rs.cc
)
# Note: The CXX bridge C++ source is compiled by the Rust build (build.rs via cxx_build),
# so we only generate the header here to avoid duplicate symbol definitions.
# Create fcb library (acts as a wrapper around the Rust static library)
add_library(fcb STATIC)

Copilot uses AI. Check for mistakes.

add_dependencies(fcb rust_library)

target_include_directories(fcb PUBLIC
${GENERATED_DIR}
${CMAKE_SOURCE_DIR}/include
)

target_link_libraries(fcb
${RUST_LIB_DIR}/target/release/libfcb_cpp.a
)

# Platform-specific linking
if(APPLE)
target_link_libraries(fcb
"-framework Security"
"-framework CoreFoundation"
"-framework SystemConfiguration"
)
endif()

# Example executable
add_executable(fcb_example examples/example.cpp ${GENERATED_DIR}/lib.rs.h)
target_link_libraries(fcb_example fcb)
target_include_directories(fcb_example PRIVATE ${GENERATED_DIR})

# Install targets
install(TARGETS fcb ARCHIVE DESTINATION lib)
install(FILES ${GENERATED_DIR}/lib.rs.h DESTINATION include/fcb)
62 changes: 62 additions & 0 deletions src/cpp/examples/example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include "lib.rs.h"
#include <iostream>
#include <stdexcept>
#include <string>

int main(int argc, char *argv[]) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <fcb_file>" << std::endl;
return 1;
}

std::string path = argv[1];

try {
// Open FCB file
auto reader = fcb::fcb_reader_open(path);

// Get metadata
auto meta = fcb::fcb_reader_metadata(*reader);
std::cout << "=== FCB File Metadata ===" << std::endl;
std::cout << "Version: " << static_cast<int>(meta.version) << std::endl;
std::cout << "Features count: " << meta.features_count << std::endl;
std::cout << "Has spatial index: "
<< (meta.has_spatial_index ? "yes" : "no") << std::endl;
std::cout << "Has attribute index: "
<< (meta.has_attribute_index ? "yes" : "no") << std::endl;
std::cout << std::endl;

// Select all features
auto iter = fcb::fcb_reader_select_all(std::move(reader));

std::cout << "=== Features ===" << std::endl;
size_t count = 0;
while (fcb::fcb_iterator_next(*iter)) {
auto feature = fcb::fcb_iterator_current(*iter);
std::cout << "Feature " << count << ": ID=" << std::string(feature.id)
<< std::endl;

// Print first 200 chars of JSON
std::string json = std::string(feature.json);
if (json.length() > 200) {
json = json.substr(0, 200) + "...";
}
std::cout << " JSON: " << json << std::endl;

count++;
if (count >= 5) {
std::cout << " ... (showing first 5 features)" << std::endl;
break;
}
}

std::cout << std::endl;
std::cout << "Total features iterated: " << count << std::endl;

} catch (const std::exception &e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}

return 0;
}
4 changes: 3 additions & 1 deletion src/rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

[workspace]
members = ["cli", "fcb_core", "wasm", "fcb_api", "fcb_py"]
members = ["cli", "fcb_core", "fcb_cpp", "wasm", "fcb_api", "fcb_py"]
resolver = "2"

[workspace.dependencies]
Expand Down Expand Up @@ -52,6 +52,8 @@ proj4rs = "0.1.9"
crs-definitions = "0.3.1"
indicatif = "0.17"
console = "0.15"
cxx = "1.0"
cxx-build = "1.0"

#---WASM dependencies---
getrandom = { version = "0.3.3" }
Expand Down
19 changes: 19 additions & 0 deletions src/rust/fcb_cpp/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "fcb_cpp"
version = "0.1.0"
edition = "2021"
authors = ["Hidemichi Baba <baba.papa1120.ba@gmail.com>"]
license = "MIT"
description = "C++ bindings for FlatCityBuf core library"

[lib]
crate-type = ["staticlib"]

[dependencies]
fcb_core = { workspace = true }
cxx = { workspace = true }
cjseq = { workspace = true }
serde_json = { workspace = true }

[build-dependencies]
cxx-build = { workspace = true }
Loading