{"id":15017910,"url":"https://github.com/devolutions/conan-rs","last_synced_at":"2025-05-07T07:21:01.091Z","repository":{"id":57609892,"uuid":"185264900","full_name":"Devolutions/conan-rs","owner":"Devolutions","description":"A Rust wrapper of the conan C/C++ package manager (conan.io) to simplify usage in build scripts","archived":false,"fork":false,"pushed_at":"2024-01-29T12:23:19.000Z","size":60,"stargazers_count":39,"open_issues_count":4,"forks_count":13,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-03-31T07:34:22.896Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Devolutions.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-05-06T20:13:23.000Z","updated_at":"2025-03-11T09:54:56.000Z","dependencies_parsed_at":"2022-08-27T21:50:34.787Z","dependency_job_id":"c1db0ee8-f996-4427-96a2-f818d780981e","html_url":"https://github.com/Devolutions/conan-rs","commit_stats":{"total_commits":28,"total_committers":9,"mean_commits":3.111111111111111,"dds":0.4642857142857143,"last_synced_commit":"32165b1c3f10a595a9a11d3067fb36b69b6310ca"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Devolutions%2Fconan-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Devolutions%2Fconan-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Devolutions%2Fconan-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Devolutions%2Fconan-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Devolutions","download_url":"https://codeload.github.com/Devolutions/conan-rs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252831441,"owners_count":21810806,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["architecture"],"created_at":"2024-09-24T19:51:09.978Z","updated_at":"2025-05-07T07:21:01.068Z","avatar_url":"https://github.com/Devolutions.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003cimg src=https://blog.conan.io/assets/conan_cargo.png width=138/\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003econan-rs\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\u003cstrong\u003eA Rust wrapper of the conan C/C++ package manager (conan.io) to simplify usage in build scripts\u003c/strong\u003e\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e\n    \u003ca href=\"https://crates.io/crates/conan\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://img.shields.io/crates/v/conan\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://docs.rs/conan\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://img.shields.io/docsrs/conan\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/Devolutions/conan-rs\" target=\"_blank\"\u003e\n    \u003cimg alt=\"GitHub Repo stars\" src=\"https://img.shields.io/github/stars/Devolutions/conan-rs?style=social\"\u003e\n\u003c/div\u003e\n\n## TLDR\n\nAdd conan to the build-dependencies section:\n\n```bash\ncargo add conan --build\n```\n\nModify the project `build.rs` script to invoke cargo and emit the conan build\ninformation automatically. Using conan profiles with names derived from the\ncargo target information is recommended:\n\nNOTE: The conan executable is assumed to be `conan` unless the `CONAN`\nenvironment variable is set.\n\n```rust\nuse std::path::Path;\nuse std::env;\n\nuse conan::*;\n\nfn main() {\n    let target_os = env::var(\"CARGO_CFG_TARGET_OS\").unwrap();\n    let target_arch = env::var(\"CARGO_CFG_TARGET_ARCH\").unwrap();\n    let conan_profile = format!(\"{}-{}\", target_os, target_arch);\n\n    let command = InstallCommandBuilder::new()\n        .with_profile(\u0026conan_profile)\n        .build_policy(BuildPolicy::Missing)\n        .with_option(\"sign\", \"True\")\n        .recipe_path(Path::new(\"conanfile.txt\"))\n        .build();\n\n    if let Some(build_info) = command.generate() {\n        println!(\"using conan build info\");\n        build_info.cargo_emit();\n    }\n\n    let build_command = BuildCommandBuilder::new()\n        .with_recipe_path(PathBuf::from(\"../../../conanfile.py\"))\n        .with_build_path(PathBuf::from(\"../../../build/\"))\n        .build();\n\n    if let Some(exit_status) = build_command.run() {\n        println!(\"conan build exited with {}\", exit_status);\n    }\n}\n```\n\nThe simplest approach is to add a conanfile.txt file alongside build.rs:\n\n```\n[requires]\nopenssl/1.1.1l@devolutions/stable\n```\n\nTo test if the conan packages are properly imported, run `cargo -vv build`, and\nlook for output similar to this:\n\n```bash\n[conan-test 0.1.0] using conan build info\n[conan-test 0.1.0] cargo:rustc-link-search=native=/Users/mamoreau/.conan/data/openssl/1.1.1l/devolutions/stable/package/ce597277d61571523403b5b500bda70acd77cd8a/lib\n[conan-test 0.1.0] cargo:rustc-link-lib=crypto\n[conan-test 0.1.0] cargo:rustc-link-lib=ssl\n[conan-test 0.1.0] cargo:include=/Users/mamoreau/.conan/data/openssl/1.1.1l/devolutions/stable/package/ce597277d61571523403b5b500bda70acd77cd8a/include\n[conan-test 0.1.0] cargo:rerun-if-env-changed=CONAN\n```\n\nThis sample conan recipe is available\n[here](https://github.com/Devolutions/conan-public), even if it is not available\nin a public conan repository.\n\n## Documentation\n\n### Conan Install\n\nThe `InstallCommand` struct represents the \"conan install\" command, facilitating\npackage installation and dependency management in Rust projects.\n`InstallCommandBuilder` provides a fluent API for constructing an\n`InstallCommand`.\n\n### Example\n\n```rust\nuse conan::{InstallCommandBuilder, BuildPolicy};\nuse std::path::Path;\n\nfn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    let install_command = InstallCommandBuilder::new()\n        .with_profile(\"default\")\n        .build_policy(BuildPolicy::Missing)\n        .recipe_path(Path::new(\"conanfile.txt\"))\n        .output_dir(Path::new(\"output_directory\"))\n        .build();\n\n    if install_command.generate().is_some() {\n        println!(\"Packages installed successfully!\");\n    } else {\n        println!(\"Failed to install packages.\");\n    }\n\n    Ok(())\n}\n```\n\nIn this example, `InstallCommandBuilder` configures the Conan install command\nwith a profile, build policy, recipe file path, and output directory.\n`generate()` executes the command, returning `Some(BuildInfo)` on success or\n`None` on failure.\n\n### Conan Build\n\nThe `BuildCommand` struct represents the \"conan build\" command, facilitating the\nbuild process of Conan packages in Rust projects. `BuildCommandBuilder` provides\na fluent API to construct a `BuildCommand`.\n\n### Example\n\n```rust\nuse conan::BuildCommandBuilder;\nuse std::path::PathBuf;\n\nfn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    let build_command = BuildCommandBuilder::new()\n        .with_recipe_path(PathBuf::from(\"conanfile.py\"))\n        .with_build_path(PathBuf::from(\"build\"))\n        .should_configure(true)\n        .should_build(true)\n        .should_install(true)\n        .build();\n\n    match build_command.run() {\n        Some(status) if status.success() =\u003e println!(\"Build succeeded!\"),\n        _ =\u003e println!(\"Build failed.\"),\n    }\n\n    Ok(())\n}\n```\n\nIn this example, _BuildCommandBuilder_ is used to configure the Conan build\ncommand with paths and options. _run()_ executes the command, returning\n_Some(ExitStatus)_ on success or _None_ on failure.\n\n### Conan Package\n\nThe `PackageCommand` struct represents the \"conan package\" command and is used\nfor creating packages. The `PackageCommandBuilder` provides a fluent API for\nconstructing a `PackageCommand`.\n\nThe `ConanPackage` struct provides functionality for managing Conan packages\nthat generate C++ libraries, and it aids in linking these libraries with Rust.\n\n#### Example Usage:\n\n```rust\nuse conan::{PackageCommandBuilder, PackageComman, ConanPackage};\nuse std::path::PathBuf;\n\nfn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    let package_command = PackageCommandBuilder::new()\n        .with_recipe_path(PathBuf::from(\"conanfile.py\"))\n        .build();\n\n    if let Some(status) = package_command.run() {\n        if !status.success() {\n            println!(\"Package command failed.\");\n            return Ok(());\n        }\n    }\n\n    let conan_package = ConanPackage::new(PathBuf::from(\"./package/\"));\n    conan_package.emit_cargo_libs_linkage(PathBuf::from(\"lib\"))?;\n\n    Ok(())\n}\n```\n\n## Use Case: Integrating Rust into a legacy c++/conan1 codebase\n\nIntegrating Rust into a legacy C++ codebase can be a strategic move to leverage\nRust's memory safety features while maintaining existing C++ functionality. In\nthis guide, we will explore how to integrate Rust into a legacy C++/Conan\ncodebase using `conan-rs` and `autocxx`.\n\n### Existing C++ Conan Codebase Structure\n\nYour existing C++ codebase with Conan and CMake might look like this:\n\n```\n.\n├── build\n│   ├── bin\n│   │   └── target_bin\n│   ├── lib\n│   │   ├── lib1.a\n│   │   ├── lib2.a\n│   │   ├── lib3.so\n│   │   ├── lib4.so\n│   │   ├── ...\n│   │   └── libn.a\n├── CMakeLists.txt\n├── conanfile.py\n├── include\n│   └── ...\n├── profiles\n│   ├── ...\n├── src\n│   ├── target_bin\n│   │   ├── ...\n│   ├── lib1\n│   │   ├── CMakeLists.txt\n│   │   ├── include\n│   │   │   └── ...\n│   │   ├── src\n│   │   │   └── ...\n│   ├── ...\n│   ├── libn\n│   │   ├── CMakeLists.txt\n│   │   ├── include\n│   │   │   └── ...\n│   │   ├── src\n│   │   │   └── ...\n```\n\nMake sure that after a build the build dir look like this(Your configuration may\nvary):\n\n```\n├── build\n│   ├── bin\n│   │   └── target_bin\n│   ├── lib\n│   │   ├── lib1.a\n│   │   ├── lib2.a\n│   │   ├── lib3.so\n│   │   ├── lib4.so\n│   │   ├── ...\n│   │   └── libn.a\n```\n\nAlso, the `package()` method in your conanfile should organize your libs and\nassociated includes in a config akin to:\n\n```\npackage\n├── conaninfo.txt\n├── conanmanifest.txt\n├── include\n└── lib\n├── lib1.a\n├── ...\n└── libn.so\n```\n\n### Creating the Rust \"Bridge\" Crate\n\nCreate a Rust library crate within the codebase to act as the \"bridge\" between\nthe C++ and Rust code:\n\n```\n.\n├── build.rs\n├── Cargo.lock\n├── Cargo.toml\n└── src\n├── lib.rs\n└── main.rs\n```\n\n### Setting Up Dependencies\n\nInstall `conan-rs` and `autocxx`:\n\n```bash\ncargo add conan-rs autocxx --build\ncargo add autocxx\n```\n\n### Setting the build script:\n\nIn your crate's build script (`build.rs`), configure the integration:\n\n```rust\nuse conan::{\n    BuildCommandBuilder, BuildPolicy, ConanPackage, InstallCommandBuilder, PackageCommandBuilder,\n};\nuse std::env;\nuse std::path::{Path, PathBuf};\nuse std::process;\n\nfn main() {\n    println!(\"cargo:rerun-if-changed=build.rs\");\n    println!(\"cargo:rerun-if-changed=../../path/to/your/conanfile.py\");\n    println!(\"cargo:rerun-if-changed=../../path/to/your/build/directory\");\n\n    let out_dir = env::var(\"OUT_DIR\").map(PathBuf::from).unwrap_or_else(|_| {\n        eprintln!(\"Error: OUT_DIR environment variable is not set\");\n        process::exit(1);\n    });\n\n    println!(\"OUT_DIR: {:?}\", out_dir);\n\n    let conan_profile = env::var(\"CONAN_PROFILE\").unwrap_or_else(|_| \"default\".to_string());\n    let install_command = InstallCommandBuilder::new()\n        .with_profile(\u0026conan_profile)\n        .with_remote(\"your_remote\")\n        .build_policy(BuildPolicy::Missing)\n        .with_profile(\"../../path/to/your/conan/profile\")\n        .recipe_path(Path::new(\"../../path/to/your/conanfile.py\"))\n        .output_dir(Path::new(\"../../path/to/your/build/directory\"))\n        .with_options(\u0026[\"option1=True\", \"option2=True\"])\n        .update_check()\n        .build();\n\n    if let Some(build_info) = install_command.generate() {\n        println!(\"using conan build info\");\n        build_info.cargo_emit();\n    } else {\n        eprintln!(\"Error: failed to run conan install\");\n        process::exit(1);\n    }\n\n    BuildCommandBuilder::new()\n        .with_recipe_path(PathBuf::from(\"../../path/to/your/conanfile.py\"))\n        .with_build_path(PathBuf::from(\"../../path/to/your/build/directory\"))\n        .build()\n        .run()\n        .unwrap_or_else(|| {\n            eprintln!(\"Error: Unable to run conan build\");\n            process::exit(1);\n        });\n\n    let package_command = PackageCommandBuilder::new()\n        .with_recipe_path(PathBuf::from(\"../../path/to/your/conanfile.py\"))\n        .with_build_path(PathBuf::from(\"../../path/to/your/build/directory\"))\n        .with_package_path(out_dir.clone())\n        .build();\n\n    if let Some(exit_status) = package_command.run() {\n        println!(\"conan package exited with {}\", exit_status);\n    }\n\n    let conan_package = ConanPackage::new(out_dir.clone());\n    if let Err(err) = conan_package.emit_cargo_libs_linkage(\"lib\".into()) {\n        eprintln!(\"Error: Unable to emit cargo linkage: {:?}\", err);\n        process::exit(1);\n    }\n\n    let include_path = out_dir.join(\"include\");\n    let mut builder = autocxx_build::Builder::new(\"src/lib.rs\", \u0026[include_path])\n        .build()\n        .unwrap_or_else(|err| {\n            eprintln!(\"Error: Unable to generate bindings: {:?}\", err);\n            process::exit(1);\n        });\n\n    builder.flag_if_supported(\"-std=c++14\").compile(\"foo_bar\");\n    println!(\"cargo:rerun-if-changed=src/main.rs\");\n}\n```\n\n### Using C++ Libraries in Rust\n\nFinally, use the C++ libraries in `lib.rs`:\n\n```rust\nuse autocxx::prelude::*;\n\ninclude_cpp! {\n    #include \"path/to/header.h\"\n    safety!(unsafe_ffi)\n    generate!(\"FunctionFromCpp\")\n}\n\npub fn use_cpp_function() {\n    let result = ffi::FunctionFromCpp();\n    // Use result as needed\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevolutions%2Fconan-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevolutions%2Fconan-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevolutions%2Fconan-rs/lists"}