Skip to content

Commit f892923

Browse files
authored
Merge pull request #7516 from NlightNFotis/rust_api_crate_preparation
Rust API crate preparation
2 parents 19471f8 + 82db78c commit f892923

File tree

7 files changed

+104
-110
lines changed

7 files changed

+104
-110
lines changed

.github/workflows/pull-request-check-rust-api.yaml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ jobs:
5252
# local experiments on the same platform, but it seems to be doing no harm to the build overall
5353
# and allows us to test the Rust API on Linux without issues.
5454
- name: Configure using CMake
55-
run: cmake -S. -B${{env.default_build_dir}} -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_C_COMPILER=/usr/bin/clang-13 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-13 -DWITH_RUST_API=ON
55+
run: cmake -S. -B${{env.default_build_dir}} -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_C_COMPILER=/usr/bin/clang-13 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-13
5656
- name: Build with CMake
5757
run: cmake --build ${{env.default_build_dir}} -j2
5858
- name: Print ccache stats
@@ -61,9 +61,10 @@ jobs:
6161
# by the other jobs already present in `pull-request-checks.yaml`.
6262
- name: Run Rust API tests
6363
run: |
64+
VERSION=$(cat src/config.inc | python3 -c "import sys,re;line = [line for line in sys.stdin if re.search('CBMC_VERSION = (\d+\.\d+\.\d+)', line)];sys.stdout.write(re.search('CBMC_VERSION = (\d+\.\d+\.\d+)', line[0]).group(1))")
6465
cd src/libcprover-rust;\
6566
cargo clean;\
66-
CBMC_BUILD_DIR=../../${{env.default_build_dir}} SAT_IMPL=${{env.default_solver}} cargo test -- --test-threads=1
67+
CBMC_LIB_DIR=../../${{env.default_build_dir}}/lib CBMC_VERSION=$VERSION cargo test -- --test-threads=1
6768
6869
6970
check-macos-12-cmake-clang-rust:
@@ -91,7 +92,7 @@ jobs:
9192
- name: Zero ccache stats and limit in size
9293
run: ccache -z --max-size=500M
9394
- name: Configure using CMake
94-
run: cmake -S. -B${{env.default_build_dir}} -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -DWITH_RUST_API=ON
95+
run: cmake -S. -B${{env.default_build_dir}} -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++
9596
- name: Build with Ninja
9697
run: cd ${{env.default_build_dir}}; ninja -j3
9798
- name: Print ccache stats
@@ -100,6 +101,7 @@ jobs:
100101
# by the other jobs already present in `pull-request-checks.yaml`.
101102
- name: Run Rust API tests
102103
run: |
104+
VERSION=$(cat src/config.inc | python3 -c "import sys,re;line = [line for line in sys.stdin if re.search('CBMC_VERSION = (\d+\.\d+\.\d+)', line)];sys.stdout.write(re.search('CBMC_VERSION = (\d+\.\d+\.\d+)', line[0]).group(1))")
103105
cd src/libcprover-rust;\
104106
cargo clean;\
105-
CBMC_BUILD_DIR=../../${{env.default_build_dir}} SAT_IMPL=${{env.default_solver}} cargo test -- --test-threads=1
107+
CBMC_LIB_DIR=../../${{env.default_build_dir}}/lib CBMC_VERSION=$VERSION cargo test -- --test-threads=1

CMakeLists.txt

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ file(
4242
STRINGS src/config.inc CBMC_VERSION
4343
REGEX "CBMC_VERSION = (.*)")
4444
string(REGEX REPLACE "CBMC_VERSION = (.*)" "\\1" CBMC_VERSION ${CBMC_VERSION})
45+
message(STATUS "Building CBMC version ${CBMC_VERSION}")
4546

4647
project(CBMC VERSION ${CBMC_VERSION})
4748

@@ -256,33 +257,4 @@ if(WITH_JBMC)
256257
add_subdirectory(jbmc)
257258
endif()
258259

259-
option(WITH_RUST_API "Build with the CPROVER Rust API" OFF)
260-
if(${CMAKE_VERSION} VERSION_LESS "3.19.0" AND WITH_RUST_API)
261-
message("Unable to build the Rust API without version CMake 3.19.0")
262-
message(FATAL_ERROR "(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-
list(JOIN sat_impl " " sat_impl_str)
277-
corrosion_set_env_vars(cprover-api-rust CBMC_BUILD_DIR=${CMAKE_BINARY_DIR} "SAT_IMPL=${sat_impl_str}")
278-
corrosion_link_libraries(cprover-api-rust cprover-api-cpp)
279-
install(TARGETS cprover-api-rust RUNTIME DESTINATION lib)
280-
# NOTE: We want to rename to a name consistent with the name of the
281-
# rest of the static libraries built as a result of a build. The reason
282-
# we cannot set the target name directly is that Cargo doesn't support
283-
# hyphens in names of packages, so it builds the name by default with
284-
# an underscore.
285-
endif()
286-
endif()
287-
288260
include(cmake/packaging.cmake)

src/libcprover-rust/Cargo.lock

Lines changed: 8 additions & 8 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: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
[package]
2-
name = "cprover-api-rust"
2+
name = "libcprover_rust"
33
version = "0.1.0"
44
edition = "2021"
5+
description = "Rust API for CBMC and assorted CProver tools"
6+
repository = "https://github.com/diffblue/cbmc"
7+
documentation = "https://diffblue.github.io/cbmc/"
8+
license = "BSD-4-Clause"
9+
exclude = ["other/", "module_dependencies.txt"]
510

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

@@ -12,4 +17,4 @@ cxx = "1.0"
1217
cxx-build = "1.0"
1318

1419
[lib]
15-
crate-type = ["staticlib"]
20+
crate-type = ["rlib"]

src/libcprover-rust/build.rs

Lines changed: 33 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -8,62 +8,30 @@ fn get_current_working_dir() -> std::io::Result<PathBuf> {
88
env::current_dir()
99
}
1010

11-
fn get_build_directory() -> Result<String, VarError> {
12-
env::var("CBMC_BUILD_DIR")
11+
// Passed by the top-level CMakeLists.txt to control which version of the
12+
// static library of CBMC we're linking against. A user can also change the
13+
// environment variable to link against different versions of CBMC.
14+
fn get_cbmc_version() -> Result<String, VarError> {
15+
env::var("CBMC_VERSION")
1316
}
1417

15-
fn get_library_build_dir() -> std::io::Result<PathBuf> {
16-
let env_var_fetch_result = get_build_directory();
17-
if let Ok(build_dir) = env_var_fetch_result {
18-
let mut path = PathBuf::new();
19-
path.push(build_dir);
20-
path.push("lib/");
21-
return Ok(path);
22-
}
23-
Err(Error::new(
24-
ErrorKind::Other,
25-
"failed to get build output directory",
26-
))
18+
// Passed by the top-level CMakeLists.txt to control where the static library we
19+
// link against is located. A user can also change the location of the library
20+
// on their system by supplying the environment variable themselves.
21+
fn get_lib_directory() -> Result<String, VarError> {
22+
env::var("CBMC_LIB_DIR")
2723
}
2824

29-
fn get_cadical_build_dir() -> std::io::Result<PathBuf> {
30-
let env_var_fetch_result = get_build_directory();
25+
fn get_library_build_dir() -> std::io::Result<PathBuf> {
26+
let env_var_fetch_result = get_lib_directory();
3127
if let Ok(build_dir) = env_var_fetch_result {
3228
let mut path = PathBuf::new();
3329
path.push(build_dir);
34-
path.push("cadical-src/build/");
3530
return Ok(path);
3631
}
3732
Err(Error::new(
3833
ErrorKind::Other,
39-
"failed to get build output directory",
40-
))
41-
}
42-
43-
fn get_sat_libraries() -> std::io::Result<Vec<&'static str>> {
44-
let env_var_name = "SAT_IMPL";
45-
let env_var_fetch_result = env::var(env_var_name);
46-
if let Ok(sat_impls) = env_var_fetch_result {
47-
let mut solver_libs = Vec::new();
48-
for sat_impl in sat_impls.split(" ") {
49-
let solver_lib = match sat_impl {
50-
"minisat2" => "minisat2-condensed",
51-
"glucose" => "glucose-condensed",
52-
"cadical" => "cadical",
53-
_ => {
54-
return Err(Error::new(
55-
ErrorKind::Other,
56-
"no identifiable solver detected",
57-
))
58-
}
59-
};
60-
solver_libs.push(solver_lib);
61-
}
62-
return Ok(solver_libs);
63-
}
64-
Err(Error::new(
65-
ErrorKind::Other,
66-
"SAT_IMPL environment variable not set",
34+
"Environment variable `CBMC_LIB_DIR' not set",
6735
))
6836
}
6937

@@ -83,34 +51,32 @@ fn main() {
8351

8452
let libraries_path = match get_library_build_dir() {
8553
Ok(path) => path,
86-
Err(err) => panic!("Error: {}", err),
87-
};
88-
89-
let solver_libs = match get_sat_libraries() {
90-
Ok(solvers) => solvers,
91-
Err(err) => panic!("Error: {}", err),
92-
};
93-
94-
for solver_lib in solver_libs.iter() {
95-
// Cadical is being built in its own directory, with the resultant artefacts being
96-
// present only there. Hence, we need to instruct cargo to look for them in cadical's
97-
// build directory, otherwise we're going to get build errors.
98-
if *solver_lib == "cadical" {
99-
let cadical_build_dir = match get_cadical_build_dir() {
100-
Ok(cadical_directory) => cadical_directory,
101-
Err(err) => panic!("Error: {}", err),
102-
};
103-
println!(
104-
"cargo:rustc-link-search=native={}",
105-
cadical_build_dir.display()
54+
Err(err) => {
55+
let error_message = &format!(
56+
"Error: {}.\n Advice: {}.",
57+
err,
58+
"Please set the environment variable `CBMC_LIB_DIR' with the path that contains libcprover.x.y.z.a on your system"
10659
);
60+
panic!("{}", error_message);
10761
}
108-
}
62+
};
10963

11064
println!(
11165
"cargo:rustc-link-search=native={}",
11266
libraries_path.display()
11367
);
11468

115-
println!("cargo:rustc-link-lib=static=cprover.5.78.0");
69+
let cprover_static_libname = match get_cbmc_version() {
70+
Ok(version) => String::from("cprover.") + &version,
71+
Err(_) => {
72+
let error_message = &format!(
73+
"Error: {}.\n Advice: {}.",
74+
"Environment variable `CBMC_VERSION' not set",
75+
"Please set the environment variable `CBMC_VERSION' with the version of CBMC you want to link against (e.g. 5.78.0)"
76+
);
77+
panic!("{}", error_message);
78+
}
79+
};
80+
81+
println!("cargo:rustc-link-lib=static={}", cprover_static_libname);
11682
}

src/libcprover-rust/readme.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# CProver (CBMC) Rust API
2+
3+
This folder contains the implementation of the Rust API of the CProver (CBMC) project.
4+
5+
## Building instructions
6+
7+
To build the Rust project you need the Rust language toolchain installed
8+
(you can install from [rustup.rs](https://rustup.rs)).
9+
10+
With that instaled, you can execute `cargo build` under this (`src/libcprover-rust`)
11+
directory.
12+
13+
For this to work, you need to supply two environment variables to the
14+
project:
15+
16+
* `CBMC_LIB_DIR`, for selecting where the `libcprover-x.y.z.a` is located
17+
(say, if you have downloaded a pre-packaged release which contains
18+
the static library), and
19+
* `CBMC_VERSION`, for selecting the version of the library to link against
20+
(this is useful if you have multiple versions of the library in the same
21+
location and you want to control which version you compile against).
22+
23+
As an example, a command sequence to build the API through `cargo` would look
24+
like this (assuming you're executing these instructions from the root level
25+
directory of the CBMC project.)
26+
27+
```sh
28+
$ cd src/libcprover-rust
29+
$ cargo clean
30+
$ CBMC_LIB_DIR=../../build/lib CBMC_VERSION=5.78.0 cargo build
31+
```
32+
33+
To build the project and run its associated tests, the command sequence would
34+
look like this:
35+
36+
```sh
37+
$ cd src/libcprover-rust
38+
$ cargo clean
39+
$ CBMC_LIB_DIR=../../build/lib CBMC_VERSION=5.78.0 cargo test -- --test-threads=1 --nocapture
40+
```
41+
42+
## Notes
43+
44+
* The functions supported by the Rust API are catalogued within the `ffi` module within
45+
`lib.rs`.
46+
* The API supports exception handling from inside CBMC by catching the exceptions in
47+
a C++ shim, and then translating the exception into the Rust `Result` type.
48+
* Because of limitations from the C++ side of CBMC, the API is not thread-safe.

src/libcprover-rust/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use cxx::{CxxString, CxxVector};
2+
23
#[cxx::bridge]
34
pub mod ffi {
45

0 commit comments

Comments
 (0)