4
4
use crate :: args:: KaniArgs ;
5
5
use crate :: session:: KaniSession ;
6
6
use anyhow:: { Context , Result } ;
7
- use cargo_metadata:: { Metadata , MetadataCommand } ;
7
+ use cargo_metadata:: { Metadata , MetadataCommand , Package } ;
8
8
use std:: ffi:: OsString ;
9
9
use std:: path:: { Path , PathBuf } ;
10
10
use std:: process:: Command ;
@@ -26,7 +26,7 @@ impl KaniSession {
26
26
/// Calls `cargo_build` to generate `*.symtab.json` files in `target_dir`
27
27
pub fn cargo_build ( & self ) -> Result < CargoOutputs > {
28
28
let build_target = env ! ( "TARGET" ) ; // see build.rs
29
- let metadata = MetadataCommand :: new ( ) . exec ( ) . expect ( "Failed to get cargo metadata." ) ;
29
+ let metadata = MetadataCommand :: new ( ) . exec ( ) . context ( "Failed to get cargo metadata." ) ? ;
30
30
let target_dir = self
31
31
. args
32
32
. target_dir
@@ -39,10 +39,6 @@ impl KaniSession {
39
39
let rustc_args = self . kani_rustc_flags ( ) ;
40
40
41
41
let mut cargo_args: Vec < OsString > = vec ! [ "rustc" . into( ) ] ;
42
- if self . args . tests {
43
- cargo_args. push ( "--tests" . into ( ) ) ;
44
- }
45
-
46
42
if self . args . all_features {
47
43
cargo_args. push ( "--all-features" . into ( ) ) ;
48
44
}
@@ -53,6 +49,13 @@ impl KaniSession {
53
49
cargo_args. push ( "--target-dir" . into ( ) ) ;
54
50
cargo_args. push ( target_dir. into ( ) ) ;
55
51
52
+ if self . args . tests {
53
+ // Use test profile in order to pull dev-dependencies and compile using `--test`.
54
+ // Initially the plan was to use `--tests` but that brings in multiple targets.
55
+ cargo_args. push ( "--profile" . into ( ) ) ;
56
+ cargo_args. push ( "test" . into ( ) ) ;
57
+ }
58
+
56
59
if self . args . verbose {
57
60
cargo_args. push ( "-v" . into ( ) ) ;
58
61
}
@@ -75,17 +78,20 @@ impl KaniSession {
75
78
// Only joing them at the end. All kani flags must come first.
76
79
kani_args. extend_from_slice ( & rustc_args) ;
77
80
78
- let members = project_members ( & self . args , & metadata) ;
79
- for member in members {
80
- let mut cmd = Command :: new ( "cargo" ) ;
81
- cmd. args ( & cargo_args)
82
- . args ( vec ! [ "-p" , & member] )
83
- . args ( & pkg_args)
84
- . env ( "RUSTC" , & self . kani_compiler )
85
- . env ( "RUSTFLAGS" , "--kani-flags" )
86
- . env ( "KANIFLAGS" , & crate :: util:: join_osstring ( & kani_args, " " ) ) ;
87
-
88
- self . run_terminal ( cmd) ?;
81
+ let packages = packages_to_verify ( & self . args , & metadata) ;
82
+ for package in packages {
83
+ for target in package_targets ( & self . args , package) {
84
+ let mut cmd = Command :: new ( "cargo" ) ;
85
+ cmd. args ( & cargo_args)
86
+ . args ( vec ! [ "-p" , & package. name] )
87
+ . args ( & target. to_args ( ) )
88
+ . args ( & pkg_args)
89
+ . env ( "RUSTC" , & self . kani_compiler )
90
+ . env ( "RUSTFLAGS" , "--kani-flags" )
91
+ . env ( "KANIFLAGS" , & crate :: util:: join_osstring ( & kani_args, " " ) ) ;
92
+
93
+ self . run_terminal ( cmd) ?;
94
+ }
89
95
}
90
96
91
97
if self . args . dry_run {
@@ -123,15 +129,60 @@ fn glob(path: &Path) -> Result<Vec<PathBuf>> {
123
129
/// - I.e.: Do whatever cargo does when there's no default_members.
124
130
/// - This is because `default_members` is not available in cargo metadata.
125
131
/// See <https://github.com/rust-lang/cargo/issues/8033>.
126
- fn project_members ( args : & KaniArgs , metadata : & Metadata ) -> Vec < String > {
132
+ fn packages_to_verify < ' a , ' b > ( args : & ' a KaniArgs , metadata : & ' b Metadata ) -> Vec < & ' b Package > {
127
133
if !args. package . is_empty ( ) {
128
- args. package . clone ( )
134
+ args. package
135
+ . iter ( )
136
+ . map ( |pkg_name| {
137
+ metadata
138
+ . packages
139
+ . iter ( )
140
+ . find ( |pkg| pkg. name == * pkg_name)
141
+ . expect ( & format ! ( "Cannot find package '{}'" , pkg_name) )
142
+ } )
143
+ . collect ( )
129
144
} else {
130
145
match ( args. workspace , metadata. root_package ( ) ) {
131
- ( true , _) | ( _, None ) => {
132
- metadata. workspace_members . iter ( ) . map ( |id| metadata[ id] . name . clone ( ) ) . collect ( )
133
- }
134
- ( _, Some ( root_pkg) ) => vec ! [ root_pkg. name. clone( ) ] ,
146
+ ( true , _) | ( _, None ) => metadata. workspace_packages ( ) ,
147
+ ( _, Some ( root_pkg) ) => vec ! [ root_pkg] ,
135
148
}
136
149
}
137
150
}
151
+
152
+ /// Possible verification targets.
153
+ enum VerificationTarget {
154
+ Bin ( String ) ,
155
+ Lib ,
156
+ Test ( String ) ,
157
+ }
158
+
159
+ impl VerificationTarget {
160
+ /// Convert to cargo argument that select the specific target.
161
+ fn to_args ( & self ) -> Vec < String > {
162
+ match self {
163
+ VerificationTarget :: Test ( name) => vec ! [ String :: from( "--test" ) , name. clone( ) ] ,
164
+ VerificationTarget :: Bin ( name) => vec ! [ String :: from( "--bin" ) , name. clone( ) ] ,
165
+ VerificationTarget :: Lib => vec ! [ String :: from( "--lib" ) ] ,
166
+ }
167
+ }
168
+ }
169
+
170
+ /// Extract the targets inside a package.
171
+ /// If `--tests` is given, the list of targets will include any integration tests.
172
+ fn package_targets ( args : & KaniArgs , package : & Package ) -> Vec < VerificationTarget > {
173
+ package
174
+ . targets
175
+ . iter ( )
176
+ . filter_map ( |target| {
177
+ if target. kind . contains ( & String :: from ( "bin" ) ) {
178
+ Some ( VerificationTarget :: Bin ( target. name . clone ( ) ) )
179
+ } else if target. kind . contains ( & String :: from ( "lib" ) ) {
180
+ Some ( VerificationTarget :: Lib )
181
+ } else if target. kind . contains ( & String :: from ( "test" ) ) && args. tests {
182
+ Some ( VerificationTarget :: Test ( target. name . clone ( ) ) )
183
+ } else {
184
+ None
185
+ }
186
+ } )
187
+ . collect ( )
188
+ }
0 commit comments