Skip to content

Commit 2a0f03b

Browse files
committed
Add a Rust project that exposes the C++ CProver API in Rust.
At the moment this supports the capacity for * loading a goto_model from files * verifying the goto_model * performing a sample instrumentation pass
1 parent ff03dd5 commit 2a0f03b

File tree

12 files changed

+506
-9
lines changed

12 files changed

+506
-9
lines changed

CMakeLists.txt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,4 +256,32 @@ if(WITH_JBMC)
256256
add_subdirectory(jbmc)
257257
endif()
258258

259+
option(WITH_RUST_API "Build with the CPROVER Rust API" ON)
260+
if(${CMAKE_VERSION} VERSION_LESS "3.19.0")
261+
message("Unable to build the Rust API without version CMake 3.19.0")
262+
message("(The Rust build depends on CMake plugins with dependencies on CMake 3.19.0 and above)")
263+
else()
264+
if(WITH_RUST_API)
265+
include(FetchContent)
266+
267+
FetchContent_Declare(
268+
Corrosion
269+
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
270+
GIT_TAG v0.3.1
271+
)
272+
273+
FetchContent_MakeAvailable(Corrosion)
274+
275+
corrosion_import_crate(MANIFEST_PATH src/libcprover-rust/Cargo.toml)
276+
corrosion_set_env_vars(cprover-api-rust CBMC_LIB_DIR=${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
277+
corrosion_link_libraries(cprover-api-rust cprover-api-cpp)
278+
install(TARGETS cprover-api-rust RUNTIME DESTINATION lib)
279+
# NOTE: We want to rename to a name consistent with the name of the
280+
# rest of the static libraries built as a result of a build. The reason
281+
# we cannot set the target name directly is that Cargo doesn't support
282+
# hyphens in names of packages, so it builds the name by default with
283+
# an underscore.
284+
endif()
285+
endif()
286+
259287
include(cmake/packaging.cmake)

src/libcprover-cpp/CMakeLists.txt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,21 @@ file(GLOB_RECURSE sources "*.cpp" "*.h")
33
# This step builds the API in the form of a statically linked library (libcprover-api-cpp.a)
44
add_library(cprover-api-cpp ${sources})
55
generic_includes(cprover-api-cpp)
6-
target_link_libraries(cprover-api-cpp goto-checker goto-programs util langapi ansi-c)
6+
target_link_libraries(cprover-api-cpp
7+
goto-checker
8+
goto-programs
9+
util
10+
langapi
11+
ansi-c
12+
json-symtab-language
13+
solvers
14+
xml
15+
cpp
16+
cbmc-lib
17+
analyses
18+
statement-list
19+
linking
20+
pointer-analysis
21+
goto-instrument-lib
22+
goto-analyzer-lib
23+
goto-cc-lib)

src/libcprover-cpp/api.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131

3232
extern configt config;
3333

34+
std::unique_ptr<std::string> api_sessiont::get_api_version() const {
35+
return util_make_unique<std::string>(std::string{"0.1"});
36+
}
37+
3438
struct api_session_implementationt
3539
{
3640
std::unique_ptr<goto_modelt> model;
@@ -112,13 +116,13 @@ void api_sessiont::set_message_callback(
112116
util_make_unique<api_message_handlert>(callback, context);
113117
}
114118

115-
void api_sessiont::load_model_from_files(const std::vector<std::string> &files)
119+
void api_sessiont::load_model_from_files(const std::vector<std::string> &files) const
116120
{
117121
implementation->model = util_make_unique<goto_modelt>(initialize_goto_model(
118122
files, *implementation->message_handler, *implementation->options));
119123
}
120124

121-
void api_sessiont::verify_model()
125+
void api_sessiont::verify_model() const
122126
{
123127
PRECONDITION(implementation->model);
124128

@@ -162,7 +166,7 @@ void api_sessiont::verify_model()
162166
verifier.report();
163167
}
164168

165-
void api_sessiont::drop_unused_functions()
169+
void api_sessiont::drop_unused_functions() const
166170
{
167171
INVARIANT(
168172
implementation->model != nullptr,
@@ -177,7 +181,7 @@ void api_sessiont::drop_unused_functions()
177181
*implementation->model, *implementation->message_handler);
178182
}
179183

180-
void api_sessiont::validate_goto_model()
184+
void api_sessiont::validate_goto_model() const
181185
{
182186
INVARIANT(
183187
implementation->model != nullptr,

src/libcprover-cpp/api.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,19 @@ struct api_sessiont
6666

6767
/// Load a goto_model from a given vector of filenames.
6868
/// \param files: A vector<string> containing the filenames to be loaded
69-
void load_model_from_files(const std::vector<std::string> &files);
69+
void load_model_from_files(const std::vector<std::string> &files) const;
7070

7171
/// Verify previously loaded model.
72-
void verify_model();
72+
void verify_model() const;
7373

7474
/// Drop unused functions from the loaded goto_model simplifying it
75-
void drop_unused_functions();
75+
void drop_unused_functions() const;
7676

7777
/// Validate the loaded goto model
78-
void validate_goto_model();
78+
void validate_goto_model() const;
79+
80+
// A simple API version information function.
81+
std::unique_ptr<std::string> get_api_version() const;
7982

8083
private:
8184
std::unique_ptr<api_session_implementationt> implementation;

src/libcprover-rust/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Ignore build artefacts folder
2+
target/

src/libcprover-rust/Cargo.lock

Lines changed: 173 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/libcprover-rust/Cargo.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "cprover-api-rust"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
cxx = "1.0"
10+
11+
[build-dependencies]
12+
cxx-build = "1.0"
13+
14+
[lib]
15+
crate-type = ["staticlib"]

src/libcprover-rust/build.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use std::env;
2+
use std::io::{Error, ErrorKind};
3+
use std::path::Path;
4+
use std::path::PathBuf;
5+
6+
fn get_current_working_dir() -> std::io::Result<PathBuf> {
7+
env::current_dir()
8+
}
9+
10+
fn get_library_build_dir() -> std::io::Result<PathBuf> {
11+
let env_var_name = "CBMC_LIB_DIR";
12+
let env_var_fetch_result = env::var(env_var_name);
13+
if let Ok(lib_dir) = env_var_fetch_result {
14+
let mut path = PathBuf::new();
15+
path.push(lib_dir);
16+
return Ok(path);
17+
}
18+
Err(Error::new(ErrorKind::Other, "failed to get library output directory"))
19+
}
20+
21+
fn main() {
22+
let cbmc_source_path = Path::new("..");
23+
let cpp_api_path = Path::new("../libcprover-cpp/");
24+
let _build = cxx_build::bridge("src/lib.rs")
25+
.include(cbmc_source_path)
26+
.include(cpp_api_path)
27+
.include(get_current_working_dir().unwrap())
28+
.file("src/c_api.cc")
29+
.flag_if_supported("-std=c++11")
30+
.compile("cprover-rust-api");
31+
32+
println!("cargo:rerun-if-changed=src/c_api.cc");
33+
println!("cargo:rerun-if-changed=include/c_api.h");
34+
35+
let libraries_path = match get_library_build_dir() {
36+
Ok(path) => path,
37+
Err(err) => panic!("{}", err)
38+
};
39+
40+
println!("cargo:rustc-link-search=native={}", libraries_path.display());
41+
println!("cargo:rustc-link-lib=static=goto-programs");
42+
println!("cargo:rustc-link-lib=static=util");
43+
println!("cargo:rustc-link-lib=static=langapi");
44+
println!("cargo:rustc-link-lib=static=ansi-c");
45+
println!("cargo:rustc-link-lib=static=analyses");
46+
println!("cargo:rustc-link-lib=static=goto-instrument-lib");
47+
println!("cargo:rustc-link-lib=static=big-int");
48+
println!("cargo:rustc-link-lib=static=linking");
49+
println!("cargo:rustc-link-lib=static=goto-checker");
50+
println!("cargo:rustc-link-lib=static=solvers");
51+
println!("cargo:rustc-link-lib=static=assembler");
52+
println!("cargo:rustc-link-lib=static=xml");
53+
println!("cargo:rustc-link-lib=static=json");
54+
println!("cargo:rustc-link-lib=static=json-symtab-language");
55+
println!("cargo:rustc-link-lib=static=cpp");
56+
println!("cargo:rustc-link-lib=static=jsil");
57+
println!("cargo:rustc-link-lib=static=statement-list");
58+
println!("cargo:rustc-link-lib=static=goto-symex");
59+
println!("cargo:rustc-link-lib=static=pointer-analysis");
60+
println!("cargo:rustc-link-lib=static=minisat2-condensed");
61+
println!("cargo:rustc-link-lib=static=cbmc-lib");
62+
println!("cargo:rustc-link-lib=static=cprover-api-cpp");
63+
}

src/libcprover-rust/include/c_api.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#pragma once
2+
3+
#include "rust/cxx.h"
4+
#include <memory>
5+
6+
struct api_sessiont;
7+
8+
// Helper function
9+
std::vector<std::string> const &translate_vector_of_string(rust::Vec<rust::String> elements);
10+
11+
// Exposure of the C++ object oriented API through free-standing functions.
12+
std::unique_ptr<api_sessiont> new_api_session();
13+
std::vector<std::string> const &get_messages();

0 commit comments

Comments
 (0)