[
  {
    "path": ".github/workflows/docker-image.yml",
    "content": "name: Docker Image CI\n\non:\n  push:\n    branches: [ \"main\" ]\n  pull_request:\n    branches: [ \"main\" ]\n\njobs:\n\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v3\n    - name: Build the Docker image on examples\n      working-directory: .\n      run: docker build . --tag my-image-name:$(date +%s) -f examples/Dockerfile\n"
  },
  {
    "path": ".gitignore",
    "content": "# Calling Rust from C++\nexamples/rust-from-cpp/src/cxxbridge_code/target\nexamples/rust-from-cpp/build\n\n# Calling C++ from Rust\n"
  },
  {
    "path": "LICENSE",
    "content": "This is free and unencumbered software released into the public domain.\n\nAnyone is free to copy, modify, publish, use, compile, sell, or\ndistribute this software, either in source code form or as a compiled\nbinary, for any purpose, commercial or non-commercial, and by any\nmeans.\n\nIn jurisdictions that recognize copyright laws, the author or authors\nof this software dedicate any and all copyright interest in the\nsoftware to the public domain. We make this dedication for the benefit\nof the public at large and to the detriment of our heirs and\nsuccessors. We intend this dedication to be an overt act of\nrelinquishment in perpetuity of all present and future rights to this\nsoftware under copyright law.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\nOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n\nFor more information, please refer to <https://unlicense.org>\n"
  },
  {
    "path": "README.MD",
    "content": "# CMake file for using [CXX](https://cxx.rs/) and [Corrosion](https://github.com/corrosion-rs/corrosion) in CMake project to call Rust functions from C++ and C++ from Rust\n\nThis is a fork of the [rusty_cmake](https://github.com/trondhe/rusty_cmake) repository to use CXX and Corrosion in a CMake project with the following modifications:\n\n### `cxx_corrosion.cmake` file:\n - Function to get STEM is removed in a favor of one-line solution;\n - Simplify by using a simple one CMakeLists file for the project;\n - Windows-related code is removed (Linux and MacOS are supported);\n - Minor code changes to simplify and use a modern C++.\n\n# Why?\n\nThis `cmake/corrosion_cxx.cmake` can be imported in any CMake project to simplify Rust code usage in C++.\n\nCurrent solution is a battle-tested and `cmake/corrosion_cxx.cmake` file is used in a [Comm](https://comm.app) application development.\n\n# Current examples\n\nExamples are located in `examples` folder.\n\nThis repo examples can be used as a sandbox playground for testing simple ideas of the Rust library integration in the current C++ CMake project (`examples/rust-from-cpp`) and as examples of the usage and calling C++ code from Rust (`examples/cpp-from-rust`).\n\n# Calling Rust code from C++\n## Code examples to call Rust functions from C++:\n- [Example of using a different primitive types](https://github.com/geekbrother/cxx-corrosion-cmake/blob/fe14ac52173737163e3ba427557187b9e4ba5d33/examples/src/main.cpp#L8) for arguments and returns;\n- [Example](https://github.com/geekbrother/cxx-corrosion-cmake/blob/fe14ac52173737163e3ba427557187b9e4ba5d33/examples/src/main.cpp#L21) of using [Rust Result type](https://cxx.rs/binding/result.html#returning-result-from-rust-to-c) and [Anyhow](https://docs.rs/anyhow/latest/anyhow/) in return to C++;\n- [Example of using panics](https://github.com/geekbrother/cxx-corrosion-cmake/blob/fe14ac52173737163e3ba427557187b9e4ba5d33/examples/src/main.cpp#L33) in Rust when calling from C++.\n\n## Dependencies\n  - Linux or MacOS\n  - CMake\n  - Clang\n  - [Corrosion](https://github.com/corrosion-rs/corrosion#installation)\n  - Rustup\n  - Nix (optional) or Docker (optional)\n\n## Build\n\n### Using CMake\n\nRun CMake and build commands in the `examples/rust-from-cpp` folder: \n\n`cmake -B build . && make -C build -j4`.\n\nThen you can run the example app by calling:\n\n`build/cxx_cmake`.\n\n### In Nix\n\nIf you are using [Nix](https://nixos.org/download.html) as a development environment you can use a nix shell with all dependencies:\n\n```\nnix-shell -p cmake -p clang -p rustup -p corrosion -p libiconv -p git --pure\n```\n\nAnd then run build commands from the CMake section above.\n\n### In Docker\n\nThere is a Docker file to build and run the example app in Docker container.\nTo build it run the build command from the project root directory:\n\n```\ndocker build . -t cxx-corrosion-cmake -f examples/Dockerfile\n```\n\nThen you can run the example app by calling:\n\n```\ndocker run cxx-corrosion-cmake\n```\n\n# Todo\n\nCreate a packages in package managers to help tracking updates in the project instead of manually track the changes.\n\n - Make it nix package\n - Make it vcpkg package\n\n# Sponsors ❤️\n\n[**Comm.app**](https://comm.app) is a crypto-native chat (think \"Web3 Discord\").\n"
  },
  {
    "path": "cmake/corrosion_cxx.cmake",
    "content": "# Creates a target including rust lib and cxxbridge which is\n# named as ${NAMESPACE}::${_LIB_PATH_STEM}\n# <_LIB_PATH_STEM> must match the crate name:\n# \"path/to/myrustcrate\" -> \"libmyrustcrate.a\"\nfunction(add_library_rust)\n    set(value_keywords PATH NAMESPACE CXX_BRIDGE_SOURCE_FILE)\n    cmake_parse_arguments(\n        rust_lib\n        \"${OPTIONS}\"\n        \"${value_keywords}\"\n        \"${MULTI_value_KEYWORDS}\"\n        ${ARGN}\n    )\n\n    if(\"${Rust_CARGO_TARGET}\" STREQUAL \"\")\n        message(\n            FATAL_ERROR\n            \"Rust_CARGO_TARGET is not detected and empty\")\n    endif()\n\n    if(\"${rust_lib_PATH}\" STREQUAL \"\")\n        message(\n            FATAL_ERROR\n            \"add_library_rust called without a given path to root of a rust crate\")\n    endif()\n\n    if(\"${rust_lib_NAMESPACE}\" STREQUAL \"\")\n        message(\n            FATAL_ERROR\n            \"Must supply a namespace given by keyvalue NAMESPACE <value>\")\n    endif()\n\n    if(\"${rust_lib_CXX_BRIDGE_SOURCE_FILE}\" STREQUAL \"\")\n        set(rust_lib_CXX_BRIDGE_SOURCE_FILE \"src/lib.rs\")\n    endif()\n\n    if(NOT EXISTS \"${CMAKE_CURRENT_LIST_DIR}/${rust_lib_PATH}/Cargo.toml\")\n        message(\n            FATAL_ERROR\n            \"${CMAKE_CURRENT_LIST_DIR}/${rust_lib_PATH} doesn't contain a Cargo.toml\")\n    endif()\n\n    set(lib_path ${rust_lib_PATH})\n    set(namespace ${rust_lib_NAMESPACE})\n    set(cxx_bridge_source_file ${rust_lib_CXX_BRIDGE_SOURCE_FILE})\n\n    corrosion_import_crate(MANIFEST_PATH \"${lib_path}/Cargo.toml\")\n\n    # Set cxxbridge values\n    get_filename_component(_LIB_PATH_STEM ${lib_path} NAME)\n    message(STATUS \"Library stem path: ${_LIB_PATH_STEM}\")\n    set(\n        cxx_bridge_binary_folder\n        ${CMAKE_BINARY_DIR}/cargo/build/${Rust_CARGO_TARGET}/cxxbridge)\n    set(\n        common_header\n        ${cxx_bridge_binary_folder}/rust/cxx.h)\n    set(\n        binding_header\n        ${cxx_bridge_binary_folder}/${_LIB_PATH_STEM}/${cxx_bridge_source_file}.h)\n    set(\n        binding_source\n        ${cxx_bridge_binary_folder}/${_LIB_PATH_STEM}/${cxx_bridge_source_file}.cc)\n    set(\n        cxx_binding_include_dir\n        ${cxx_bridge_binary_folder})\n\n    # Create cxxbridge target\n    add_custom_command(\n        OUTPUT\n        ${common_header}\n        ${binding_header}\n        ${binding_source}\n        COMMAND\n        DEPENDS ${_LIB_PATH_STEM}-static\n        COMMENT \"Fixing cmake to find source files\"\n    )\n    add_library(${_LIB_PATH_STEM}_cxxbridge\n        ${common_header}\n        ${binding_header}\n        ${binding_source}\n    )\n    target_include_directories(${_LIB_PATH_STEM}_cxxbridge\n        PUBLIC ${cxx_binding_include_dir}\n    )\n\n    # Create total target with alias with given namespace\n    add_library(${_LIB_PATH_STEM}-total INTERFACE)\n    target_link_libraries(${_LIB_PATH_STEM}-total\n        INTERFACE\n        ${_LIB_PATH_STEM}_cxxbridge\n        ${_LIB_PATH_STEM}\n    )\n\n    # for end-user to link into project\n    add_library(${namespace}::${_LIB_PATH_STEM} ALIAS ${_LIB_PATH_STEM}-total)\nendfunction(add_library_rust)\n"
  },
  {
    "path": "examples/Dockerfile",
    "content": "FROM ubuntu:23.04\n\nENV DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC\nARG LOCAL_DIRECTORY=/var/cxx_corrosion_cmake\nARG RUST_VERSION=1.69.0\n\n# Install essential packages for building the c++\nRUN apt update \\\n\t&& apt install -y \\\n  build-essential curl cmake git \\\n  lsb-release software-properties-common\n\n# Install Rust\nRUN curl https://sh.rustup.rs -sSf | bash -s -- --default-toolchain ${RUST_VERSION} -y\n\n# Install Corrosion\nWORKDIR /var\nRUN git clone https://github.com/corrosion-rs/corrosion.git\nRUN cmake -Scorrosion -Bbuild -DCMAKE_BUILD_TYPE=Release\nRUN cmake --build build --config Release && cmake --install build --config Release\n\n# Copy files\nCOPY examples ${LOCAL_DIRECTORY}/examples\nCOPY cmake ${LOCAL_DIRECTORY}/cmake\n\n# Compile example app\nWORKDIR ${LOCAL_DIRECTORY}/examples/rust-from-cpp\nRUN rm -dfr build && cmake -B build . && make -C build -j4\n\n# Run the example app\nCMD [\"${LOCAL_DIRECTORY}/examples/rust-from-cpp/build/cxx_cmake\"]\n"
  },
  {
    "path": "examples/rust-from-cpp/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\nset(CMAKE_EXPORT_COMPILE_COMMANDS true)\n\nproject(cxx_cmake CXX)\n\nset(CMAKE_CXX_STANDARD 17)\n\nfind_package(Corrosion REQUIRED)\ninclude(../../cmake/corrosion_cxx.cmake)\n\nadd_executable(${PROJECT_NAME})\n\ntarget_sources(${PROJECT_NAME}\n  PRIVATE\n  src/main.cpp\n)\n\nadd_library_rust(PATH src/cxxbridge_code NAMESPACE my)\n\ntarget_link_libraries(${PROJECT_NAME}\n  PUBLIC\n  my::cxxbridge_code\n)\n"
  },
  {
    "path": "examples/rust-from-cpp/src/cxxbridge_code/Cargo.toml",
    "content": "[package]\nname = \"cxxbridge_code\"\nversion = \"0.1.0\"\nauthors = [\"Trond H Emaus <trondhe@gmail.com>\", \"Max Kalashnikoff <geekmaks@gmail.com>\"]\nedition = \"2021\"\n\n[dependencies]\ncxx = \"1.0\"\nanyhow = \"1.0\"\n\n[build-dependencies]\ncxx-build = \"1.0\"\n\n[lib]\ncrate-type = [\"staticlib\"]\n\n[profile.release]\ndebug = true\npanic = \"abort\"\n\n[profile.dev]\npanic = \"abort\"\n"
  },
  {
    "path": "examples/rust-from-cpp/src/cxxbridge_code/build.rs",
    "content": "fn main() {\n    let _build = cxx_build::bridge(\"src/lib.rs\");\n    println!(\"cargo:rerun-if-changed=src/lib.rs\");\n}\n"
  },
  {
    "path": "examples/rust-from-cpp/src/cxxbridge_code/src/lib.rs",
    "content": "use anyhow::Result;\n\n#[cxx::bridge]\nmod ffi {\n    extern \"Rust\" {\n        // Primitive types:\n        fn lib_cxxbridge_bool(some: bool) -> bool;\n        fn lib_cxxbridge_integer(some: i32) -> i32;\n        fn lib_cxxbridge_string(some: &str) -> String;\n        // Return Result:\n        fn lib_cxxbridge_return_result_ok() -> Result<String>;\n        fn lib_cxxbridge_return_result_error() -> Result<String>;\n        // Panic in a function call:\n        fn lib_cxxbridge_panicked_function() -> String;\n    }\n}\n\npub fn lib_cxxbridge_bool(some: bool) -> bool {\n    if some {\n        return false;\n    }\n    true\n}\n\npub fn lib_cxxbridge_integer(some: i32) -> i32 {\n    some + 10\n}\n\npub fn lib_cxxbridge_string(some: &str) -> String {\n    String::from(\"Say hello to \".to_owned() + &some)\n}\n\npub fn lib_cxxbridge_return_result_ok() -> Result<String> {\n    Ok(String::from(\"This is a string from result\"))\n}\n\npub fn lib_cxxbridge_return_result_error() -> Result<String> {\n    let some_string = std::fs::read_to_string(\"cluster.json\")?;\n    Ok(some_string)\n}\n\npub fn lib_cxxbridge_panicked_function() -> String {\n    panic!(\"Panicked_function in panic\");\n}\n"
  },
  {
    "path": "examples/rust-from-cpp/src/main.cpp",
    "content": "#include \"cxxbridge_code/src/lib.rs.h\"\n#include <iostream>\n#include <string>\n#include \"rust/cxx.h\"\n\nint main()\n{\n\t// Primitive types:\n\tstd::cout << \"[1] A value given via generateb cxxbridge for lib_cxxbridge_bool: \"\n\t\t\t\t\t\t<< lib_cxxbridge_bool(true) << std::endl;\n\tstd::cout << \"[2] A value given via generated cxxbridge for lib_cxxbridge_integer: \"\n\t\t\t\t\t\t<< lib_cxxbridge_integer(86) << std::endl;\n\tconst rust::String testString = \"Max\";\n\tstd::cout << \"[3] A value given via generated cxxbridge for lib_cxxbridge_string: \"\n\t\t\t\t\t\t<< lib_cxxbridge_string(testString) << std::endl;\n\n\t// Return Rust `Result` with  Ok:\n\tstd::cout << \"[4] A Rust `Result Ok` value given via generated cxxbridge for lib_cxxbridge_return_result_ok:\" << std::endl\n\t\t\t\t\t\t<< lib_cxxbridge_return_result_ok() << std::endl;\n\n\t// Return Rust `Result` with Error:\n\ttry\n\t{\n\t\tstd::cout << \"[5] A Rust `Result Error` value given via generated cxxbridge for lib_cxxbridge_return_result_error:\" << std::endl\n\t\t\t\t\t\t\t<< lib_cxxbridge_return_result_error() << std::endl;\n\t}\n\tcatch (rust::Error e)\n\t{\n\t\tstd::cerr << \"Got an error from Rust function `Result`:\" << std::endl;\n\t\tstd::cerr << e.what() << std::endl;\n\t}\n\n\t// Panic in a function call:\n\tstd::cout << \"[6] Testing a case of panic by running lib_cxxbridge_panicked_function:\" << std::endl;\n\tstd::cout << lib_cxxbridge_panicked_function();\n\n\treturn 0;\n}\n"
  }
]