@@ -5,6 +5,8 @@ use bindgen::builder;
5
5
use std:: env;
6
6
use std:: path:: PathBuf ;
7
7
8
+ use serde_json:: json;
9
+
8
10
fn main ( ) {
9
11
let cflags = env:: var ( "RIOT_CFLAGS" )
10
12
. expect ( "Please pass in RIOT_CFLAGS; see README.md for details." ) ;
@@ -14,7 +16,7 @@ fn main() {
14
16
println ! ( "cargo:rerun-if-env-changed=RIOT_CFLAGS" ) ;
15
17
println ! ( "cargo:rerun-if-changed=riot-all.h" ) ;
16
18
17
- let cflags = cflags. iter ( ) . filter ( |x| {
19
+ let cflags: Vec < String > = cflags. into_iter ( ) . filter ( |x| {
18
20
match x. as_ref ( ) {
19
21
// non-clang flags showing up with arm cortex m3 (eg. stk3700 board)
20
22
"-Werror" => false ,
@@ -30,12 +32,12 @@ fn main() {
30
32
// accept all others
31
33
_ => true ,
32
34
}
33
- } ) ;
35
+ } ) . collect ( ) ;
34
36
35
37
let bindings = builder ( )
36
38
. header ( "riot-all.h" )
37
39
. size_t_is_usize ( true )
38
- . clang_args ( cflags)
40
+ . clang_args ( & cflags)
39
41
. use_core ( )
40
42
. ctypes_prefix ( "libc" )
41
43
. impl_debug ( true )
@@ -48,4 +50,73 @@ fn main() {
48
50
bindings
49
51
. write_to_file ( out_path. join ( "bindings.rs" ) )
50
52
. expect ( "Couldn't write bindings!" ) ;
53
+
54
+ // Build a compile_commands.json, and run C2Rust
55
+ //
56
+ // The output is cleared beforehand (for c2rust no-ops when an output file is present), and the
57
+ // input is copied to OUT_DIR as that's the easiest way to get c2rust to put the output file in
58
+ // a different place.
59
+
60
+ let headercopy = out_path. join ( "riot-c2rust.h" ) ;
61
+ let output = out_path. join ( "riot_c2rust.rs" ) ;
62
+ println ! ( "cargo:rerun-if-changed=riot-c2rust.h" ) ;
63
+ std:: fs:: copy ( "riot-c2rust.h" , headercopy)
64
+ . expect ( "Failed to copy over header file" ) ;
65
+ match std:: fs:: remove_file ( & output) {
66
+ Ok ( _) => ( ) ,
67
+ Err ( e) if e. kind ( ) == std:: io:: ErrorKind :: NotFound => ( ) ,
68
+ Err ( e) => panic ! ( "Failed to remove output file: {}" , e) ,
69
+ }
70
+
71
+ let arguments: Vec < _ > = core:: iter:: once ( "any-cc" . to_string ( ) )
72
+ . chain ( cflags. into_iter ( ) )
73
+ . chain ( core:: iter:: once ( "riot-c2rust.h" . to_string ( ) ) )
74
+ . collect ( ) ;
75
+ let compile_commands = json ! ( [ {
76
+ "arguments" : arguments,
77
+ "directory" : out_path,
78
+ "file" : "riot-c2rust.h" ,
79
+ } ] ) ;
80
+ let compile_commands_name = out_path. join ( "compile_commands.json" ) ;
81
+
82
+ let mut compile_commands_file = std:: fs:: File :: create ( compile_commands_name. clone ( ) )
83
+ . expect ( "Failed to create compile_commands.json" ) ;
84
+ serde_json:: to_writer_pretty ( & mut compile_commands_file, & compile_commands)
85
+ . expect ( "Failed to write to compile_commands.json" ) ;
86
+ compile_commands_file. sync_all ( )
87
+ . expect ( "Failed to write to compile_commands.json" ) ;
88
+
89
+ let compile_commands_name = compile_commands_name. to_str ( ) . expect ( "Inexpressible path name" ) ;
90
+ // FIXME: This does not rat on the used files. Most are probably included from riot-all.h
91
+ // anyway, tough.
92
+ println ! ( "Running C2Rust on {}" , compile_commands_name) ;
93
+ let status = std:: process:: Command :: new ( "c2rust" )
94
+ . args ( & [ "transpile" , compile_commands_name, "--preserve-unused-functions" , "--emit-modules" , "--emit-no-std" ] )
95
+ . status ( )
96
+ . expect ( "C2Rust failed" ) ;
97
+ if !status. success ( ) {
98
+ println ! ( "cargo:warning=C2Rust failed with error code {}, exiting" , status) ;
99
+ std:: process:: exit ( status. code ( ) . unwrap_or ( 1 ) ) ;
100
+ }
101
+
102
+ // Some fix-ups to the C2Rust output
103
+ // (could just as well call sed...)
104
+
105
+ use std:: io:: { Read , Write } ;
106
+
107
+ let mut rustcode = String :: new ( ) ;
108
+ std:: fs:: File :: open ( output)
109
+ . expect ( "Failed to open riot_c2rust.rs" )
110
+ . read_to_string ( & mut rustcode)
111
+ . expect ( "Failed to read from riot_c2rust.rs" ) ;
112
+
113
+ rustcode = rustcode. replace ( "use ::libc;\n " , "" ) ;
114
+ rustcode = rustcode. replace ( r#"unsafe extern "C" fn "# , r#"pub unsafe extern "C" fn "# ) ;
115
+
116
+ let output_replaced = out_path. join ( "riot_c2rust_replaced.rs" ) ;
117
+ std:: fs:: File :: create ( output_replaced)
118
+ . expect ( "Failed to create riot_c2rust_replaced.rs" )
119
+ . write ( rustcode. as_bytes ( ) )
120
+ . expect ( "Failed to write to riot_c2rust_replaced.rs" ) ;
121
+
51
122
}
0 commit comments