Devolutions / conan-rs

A Rust wrapper of the conan C/C++ package manager (conan.io) to simplify usage in build scripts
Apache License 2.0
37 stars 10 forks source link

Having trouble grasping once the conan package is added.. how best to call the code.. CXX + ConanRS example? #11

Closed EMCP closed 2 years ago

EMCP commented 2 years ago

I have two successful separate projects which I am now trying to sort of combine.

Project #1

a basic conanrs setup which pulls in the C++ recipe I wrote .. but I am unsure how to proceed to use it in rust

Project #2

instantiate this project https://github.com/dtolnay/cxx/tree/master/demo

The challenge

How can I start to call my Conan package code.. like the CXX demo example ? are there tutorials out there showing the way to include C++ code via conan.. and start integrating it properly in a rust program.. in my case it will be a GRPC server wrapping my custom conan packages C++

Progress So Far

I've so far just combined the build.rs of the two

use std::path::Path;
use std::env;

use conan::*;

fn main() {

    let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
    let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
    let default_conan_profile = "default";
    let _conan_profile = format!("{}-{}", target_os, target_arch);

    let command = InstallCommandBuilder::new()
        .with_profile(&default_conan_profile)
        .build_policy(BuildPolicy::Missing)
        .recipe_path(Path::new("conanfile.txt"))
        .build();

    if let Some(build_info) = command.generate() {
        println!("using conan build info");
        build_info.cargo_emit();
    }

    cxx_build::bridge("src/main.rs")
        .file("src/blobstore.cc")
        .flag_if_supported("-std=c++17")
        .compile("cxxbridge-demo");

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

Everything builds fine.. but next I need to learn how to start calling the Conan provided code..

awakecoding commented 2 years ago

@EMCP conan is really there to handle the C/C++ dependency management, where you can write recipes to build and import C/C++ dependencies. The way we are using it at Devolutions is that we always prebuild dependencies in our CI environment, after which we always import prebuilt dependencies on the consumer projects. Developers never rebuild the C/C++ dependencies locally when importing them since they are prebuilt.

Wrapping C/C++ through Rust FFI is outside the scope of conan-rs: the goal is to facilitate importing conan packages into Rust, such that all the build information from the conan package (what to link to, library directories, include directories, system link libraries, etc) is automatically exported for cargo to understand. This is similar to cmake-rs which tries to some the same, except you need to call and build the CMake project every time as part of the build.rs script. In the past, I have often modified Rust crates doing cmake-rs or even cc-rs to import our corresponding conan packages instead, avoid the costly rebuilding, but also ensuring easier control over what got built.

The crucial part of conan-rs is what gets "emitted" to cargo during build_info.cargo_emit() - these are lines output by the build.rs script to stdout that begin with "cargo:" and contain the information for library directories, include directories, link libraries, etc. All this gets picked up by cargo and will be used to link your native library into your Rust project. From there, you can try calling your native C/C++ functions, but you need to write the FFI yourself: https://doc.rust-lang.org/nomicon/ffi.html

EMCP commented 2 years ago

Developers never rebuild the C/C++ dependencies locally when importing them since they are prebuilt.

Correct, I have a prebuilt C++ library in conan.. and now wondering how to leverage that via Rust

Wrapping C/C++ through Rust FFI is outside the scope of conan-rs: the goal is to facilitate importing conan packages into Rust, > such that all the build information from the conan package (what to link to, library directories, include directories, system link libraries, etc) is automatically exported for cargo to understand.

So perhaps all I need to worry about with conan-rs is... does it bring in everything into a place I can find... from there I need to do the rest (ie write or refactor my C++ code to interface with the library that conan brought in)

From there, you can try calling your native C/C++ functions, but you need to write the FFI yourself: https://doc.rust-lang.org/nomicon/ffi.html

Excellent.. I will first try that link.. and see if i even need CXX after that (still grasping the difference between the various ways to call C++ code from Rust).

Reference : https://github.com/dtolnay/cxx Forum post : https://users.rust-lang.org/t/of-the-following-languages-which-is-easiest-for-rust-to-interoperate-with-c-c-java/83123 Big thanks for the link. Closing.

EMCP commented 2 years ago

one last question if I may..

I can see my code is installed under the usual .conan area.. how am I to properly reference it? bar.h is not found so I am guessing it's needing a certain path?

image

I do not see the files within my rust projects target subdir.. I am assuming that's expected?

I tried include/bar.h as well

  cargo:warning=src/blobstore.cc:9:10: fatal error: bar.h: No such file or directory
  cargo:warning=    9 | #include "bar.h"
  cargo:warning=      |          ^~~~~~~
  cargo:warning=compilation terminated.
  exit status: 1

  --- stderr

The relevant output from cargo build

  twsapi/10.17.01@stonks/prod: Already installed!
  conanfile.txt: Generator txt created conanbuildinfo.txt
  conanfile.txt: Generator json created conanbuildinfo.json
  conanfile.txt: Aggregating env generators
  conanfile.txt: Generated conaninfo.txt
  conanfile.txt: Generated graphinfo
  using conan build info
  cargo:rustc-link-search=native=/home/emcp/.conan/data/twsapi/10.17.01/stonks/prod/package/062863c92a5a0a247840166e9f84ebe8d10786b9/lib
  cargo:rustc-link-lib=twsapi
  cargo:include=/home/emcp/.conan/data/twsapi/10.17.01/stonks/prod/package/062863c92a5a0a247840166e9f84ebe8d10786b9/include
  cargo:rerun-if-env-changed=CONAN
  cargo:CXXBRIDGE_PREFIX=rust_twsapi_demo
  cargo:CXXBRIDGE_DIR0=/home/emcp/Dev/git/JRGEMCP_Bootstrapping/bootstrap-rust-cpp-conan/demo_conan/target/debug/build/rust_twsapi_demo-44270ce78e9ae991/out/cxxbridge/include
  cargo:CXXBRIDGE_DIR1=/home/emcp/Dev/git/JRGEMCP_Bootstrapping/bootstrap-rust-cpp-conan/demo_conan/target/debug/build/rust_twsapi_demo-44270ce78e9ae991/out/cxxbridge/crate
  TARGET = Some("x86_64-unknown-linux-gnu")
awakecoding commented 2 years ago

conan emits build information for cargo to consume, and here you're using a crate to build C++ code which needs to be manually passed the same information (link libraries, include directories, etc). I suggest you take a look at how cargo_emit transforms the conan build information for cargo, and you can probably write your own function to pass the same information to cxx_build: https://github.com/Devolutions/conan-rs/blob/master/src/build_info/mod.rs#L59

EMCP commented 2 years ago

as a reference I successfully got the includes of my conan based code to work in a CXX based project via this https://github.com/dtolnay/cxx/issues/1129

at least it works so far as I have kicked the CXX tires.. my final (I hope) question.. is do I need to do anything to add the conan lib/ directory ? or is ConanRS handling that already? My guess is I need to look into how to add this the CXX way