Browse Source

Create C++ node API library

tags/v0.0.0-test-pr-120
Philipp Oppermann 3 years ago
parent
commit
c56e9ea57e
Failed to extract signature
10 changed files with 105 additions and 65 deletions
  1. +10
    -11
      Cargo.lock
  2. +2
    -1
      Cargo.toml
  3. +7
    -3
      apis/c++/node/Cargo.toml
  4. +4
    -0
      apis/c++/node/build.rs
  5. +32
    -21
      apis/c++/node/src/lib.rs
  6. +1
    -1
      examples/c++-dataflow/dataflow.yml
  7. +0
    -10
      examples/c++-dataflow/node-rust-api/build.rs
  8. +10
    -6
      examples/c++-dataflow/node-rust-api/main.cc
  9. +0
    -4
      examples/c++-dataflow/node-rust-api/src/main.h
  10. +39
    -8
      examples/c++-dataflow/run.rs

+ 10
- 11
Cargo.lock View File

@@ -746,17 +746,6 @@ dependencies = [
"syn",
]

[[package]]
name = "cxx-dataflow-example-node-rust-api"
version = "0.1.0"
dependencies = [
"cxx",
"cxx-build",
"dora-node-api",
"eyre",
"rand",
]

[[package]]
name = "cxx-dataflow-example-operator-rust-api"
version = "0.1.0"
@@ -1007,6 +996,16 @@ dependencies = [
"tracing",
]

[[package]]
name = "dora-node-api-cxx"
version = "0.1.0"
dependencies = [
"cxx",
"cxx-build",
"dora-node-api",
"eyre",
]

[[package]]
name = "dora-node-api-python"
version = "0.1.0"


+ 2
- 1
Cargo.toml View File

@@ -1,6 +1,7 @@
[workspace]
members = [
"apis/c/*",
"apis/c++/*",
"apis/python/node",
"apis/python/operator",
"apis/rust/*",
@@ -8,7 +9,7 @@ members = [
"apis/rust/operator/types",
"binaries/*",
"examples/rust-dataflow/*",
"examples/c++-dataflow/*-rust-*",
"examples/c++-dataflow/operator-rust-api",
"examples/iceoryx/*",
"libraries/communication-layer",
"libraries/core",


examples/c++-dataflow/node-rust-api/Cargo.toml → apis/c++/node/Cargo.toml View File

@@ -1,15 +1,19 @@
[package]
name = "cxx-dataflow-example-node-rust-api"
name = "dora-node-api-cxx"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

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

[dependencies]
cxx = "1.0.73"
dora-node-api = { version = "0.1.0", path = "../../../apis/rust/node" }
dora-node-api = { version = "0.1.0", path = "../../../apis/rust/node", default-features = false, features = [
"zenoh",
] }
eyre = "0.6.8"
rand = "0.8.5"

[build-dependencies]
cxx-build = "1.0.73"

+ 4
- 0
apis/c++/node/build.rs View File

@@ -0,0 +1,4 @@
fn main() {
let _build = cxx_build::bridge("src/lib.rs");
println!("cargo:rerun-if-changed=src/lib.rs");
}

examples/c++-dataflow/node-rust-api/src/main.rs → apis/c++/node/src/lib.rs View File

@@ -1,7 +1,12 @@
use dora_node_api::{self, DoraNode, Input, Receiver};
use dora_node_api::{self, Input, Receiver};

#[cxx::bridge]
mod ffi {
struct DoraNode {
inputs: Box<Inputs>,
send_output: Box<OutputSender>,
}

struct DoraInput {
end_of_input: bool,
id: String,
@@ -14,22 +19,38 @@ mod ffi {

extern "Rust" {
type Inputs;
type OutputSender<'a>;
type OutputSender;

fn next_input(inputs: &mut Inputs) -> DoraInput;
fn send_output(output_sender: &mut OutputSender, id: String, data: &[u8]) -> DoraResult;
fn init_dora_node() -> Result<DoraNode>;
fn free_dora_node(node: DoraNode);
fn next_input(inputs: &mut Box<Inputs>) -> DoraInput;
fn send_output(
output_sender: &mut Box<OutputSender>,
id: String,
data: &[u8],
) -> DoraResult;
}
}

unsafe extern "C++" {
include!("cxx-dataflow-example-node-rust-api/src/main.h");
fn init_dora_node() -> eyre::Result<ffi::DoraNode> {
let mut node = dora_node_api::DoraNode::init_from_env()?;
let input_stream = node.inputs()?;
let inputs = Inputs(input_stream);
let send_output = OutputSender(node);

fn cxx_main(inputs: &mut Inputs, output_sender: &mut OutputSender);
}
Ok(ffi::DoraNode {
inputs: Box::new(inputs),
send_output: Box::new(send_output),
})
}

fn free_dora_node(node: ffi::DoraNode) {
let _ = node;
}

pub struct Inputs(Receiver<Input>);

fn next_input(inputs: &mut Inputs) -> ffi::DoraInput {
fn next_input(inputs: &mut Box<Inputs>) -> ffi::DoraInput {
match inputs.0.recv() {
Ok(input) => {
let id = input.id.clone().into();
@@ -48,9 +69,9 @@ fn next_input(inputs: &mut Inputs) -> ffi::DoraInput {
}
}

pub struct OutputSender<'a>(&'a mut DoraNode);
pub struct OutputSender(dora_node_api::DoraNode);

fn send_output(sender: &mut OutputSender, id: String, data: &[u8]) -> ffi::DoraResult {
fn send_output(sender: &mut Box<OutputSender>, id: String, data: &[u8]) -> ffi::DoraResult {
let result = sender
.0
.send_output(&id.into(), Default::default(), data.len(), |out| {
@@ -62,13 +83,3 @@ fn send_output(sender: &mut OutputSender, id: String, data: &[u8]) -> ffi::DoraR
};
ffi::DoraResult { error }
}

fn main() -> eyre::Result<()> {
let mut node = DoraNode::init_from_env()?;
let input_stream = node.inputs()?;
let mut inputs = Inputs(input_stream);
let mut outputs = OutputSender(&mut node);
ffi::cxx_main(&mut inputs, &mut outputs);

Ok(())
}

+ 1
- 1
examples/c++-dataflow/dataflow.yml View File

@@ -5,7 +5,7 @@ communication:
nodes:
- id: cxx-node-rust-api
custom:
source: ../../target/debug/cxx-dataflow-example-node-rust-api
source: build/node_rust_api
inputs:
tick: dora/timer/millis/300
outputs:


+ 0
- 10
examples/c++-dataflow/node-rust-api/build.rs View File

@@ -1,10 +0,0 @@
fn main() {
cxx_build::bridge("src/main.rs") // returns a cc::Build
.file("src/main.cc")
.flag_if_supported("-std=c++14")
.compile("cxx-example-dataflow-node");

println!("cargo:rerun-if-changed=src/main.rs");
println!("cargo:rerun-if-changed=src/main.cc");
println!("cargo:rerun-if-changed=src/main.h");
}

examples/c++-dataflow/node-rust-api/src/main.cc → examples/c++-dataflow/node-rust-api/main.cc View File

@@ -1,20 +1,22 @@
#include "cxx-dataflow-example-node-rust-api/src/main.h"
#include "../build/dora-node-api.h"

#include <iostream>
#include <vector>

void cxx_main(Inputs &inputs, OutputSender &output_sender)
int main()
{
std::cout << "HELLO FROM C++" << std::endl;
unsigned char counter = 0;

auto dora_node = init_dora_node();

for (int i = 0; i < 20; i++)
{

auto input = next_input(inputs);
auto input = next_input(dora_node.inputs);
if (input.end_of_input)
{
return;
break;
}
counter += 1;

@@ -22,12 +24,14 @@ void cxx_main(Inputs &inputs, OutputSender &output_sender)

std::vector<unsigned char> out_vec{counter};
rust::Slice<const uint8_t> out_slice{out_vec.data(), out_vec.size()};
auto result = send_output(output_sender, "counter", out_slice);
auto result = send_output(dora_node.send_output, "counter", out_slice);
auto error = std::string(result.error);
if (!error.empty())
{
std::cerr << "Error: " << error << std::endl;
return;
return -1;
}
}

return 0;
}

+ 0
- 4
examples/c++-dataflow/node-rust-api/src/main.h View File

@@ -1,4 +0,0 @@
#pragma once
#include "cxx-dataflow-example-node-rust-api/src/main.rs.h"

void cxx_main(Inputs &inputs, OutputSender &output_sender);

+ 39
- 8
examples/c++-dataflow/run.rs View File

@@ -8,20 +8,46 @@ use std::{
#[tokio::main]
async fn main() -> eyre::Result<()> {
let root = Path::new(env!("CARGO_MANIFEST_DIR"));
let target = root.join("target");
std::env::set_current_dir(root.join(file!()).parent().unwrap())
.wrap_err("failed to set working dir")?;

tokio::fs::create_dir_all("build").await?;
let build_dir = Path::new("build");

build_package("cxx-dataflow-example-node-rust-api").await?;
build_package("cxx-dataflow-example-operator-rust-api").await?;

build_package("dora-node-api-cxx").await?;
let cxxbridge = target
.join("cxxbridge")
.join("dora-node-api-cxx")
.join("src");
tokio::fs::copy(cxxbridge.join("lib.rs.cc"), build_dir.join("bridge.cc")).await?;
tokio::fs::copy(
cxxbridge.join("lib.rs.h"),
build_dir.join("dora-node-api.h"),
)
.await?;

build_package("dora-node-api-c").await?;
build_package("dora-operator-api-c").await?;
build_cxx_node(
root,
&dunce::canonicalize(Path::new("node-c-api").join("main.cc"))?,
&[
&dunce::canonicalize(Path::new("node-rust-api").join("main.cc"))?,
&dunce::canonicalize(build_dir.join("bridge.cc"))?,
],
"node_rust_api",
&["-l", "dora_node_api_cxx"],
)
.await?;
build_cxx_node(
root,
&[&dunce::canonicalize(
Path::new("node-c-api").join("main.cc"),
)?],
"node_c_api",
&["-l", "dora_node_api_c"],
)
.await?;
build_cxx_operator(
@@ -52,11 +78,16 @@ async fn build_package(package: &str) -> eyre::Result<()> {
Ok(())
}

async fn build_cxx_node(root: &Path, path: &Path, out_name: &str) -> eyre::Result<()> {
async fn build_cxx_node(
root: &Path,
paths: &[&Path],
out_name: &str,
args: &[&str],
) -> eyre::Result<()> {
let mut clang = tokio::process::Command::new("clang++");
clang.arg(path);
clang.arg("-std=c++14");
clang.arg("-l").arg("dora_node_api_c");
clang.args(paths);
clang.arg("-std=c++17");
clang.args(args);
#[cfg(target_os = "linux")]
{
clang.arg("-l").arg("m");
@@ -110,7 +141,7 @@ async fn build_cxx_node(root: &Path, path: &Path, out_name: &str) -> eyre::Resul
clang
.arg("--output")
.arg(Path::new("../build").join(format!("{out_name}{EXE_SUFFIX}")));
if let Some(parent) = path.parent() {
if let Some(parent) = paths[0].parent() {
clang.current_dir(parent);
}

@@ -125,7 +156,7 @@ async fn build_cxx_operator(path: &Path, out_name: &str) -> eyre::Result<()> {

let mut compile = tokio::process::Command::new("clang++");
compile.arg("-c").arg(path);
compile.arg("-std=c++14");
compile.arg("-std=c++17");
compile.arg("-o").arg(&object_file_path);
#[cfg(unix)]
compile.arg("-fPIC");


Loading…
Cancel
Save