From 9c9f95c2d9d224c9c5978ae5b1e65f92a969413e Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Wed, 11 Nov 2015 17:29:22 -0500 Subject: [PATCH 1/4] trpl: get all examples in ffi.md compiling --- src/doc/trpl/ffi.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/doc/trpl/ffi.md b/src/doc/trpl/ffi.md index 7a58a327b9f95..d0d2215ba8236 100644 --- a/src/doc/trpl/ffi.md +++ b/src/doc/trpl/ffi.md @@ -16,11 +16,14 @@ compile if snappy is installed: extern crate libc; use libc::size_t; +#[cfg(nope)] #[link(name = "snappy")] extern { fn snappy_max_compressed_length(source_length: size_t) -> size_t; } +# #[cfg(not(nope))] unsafe fn snappy_max_compressed_length(_: size_t) -> size_t { 0 } + fn main() { let x = unsafe { snappy_max_compressed_length(100) }; println!("max compressed length of a 100 byte buffer: {}", x); @@ -50,6 +53,7 @@ The `extern` block can be extended to cover the entire snappy API: extern crate libc; use libc::{c_int, size_t}; +# #[cfg(nope)] #[link(name = "snappy")] extern { fn snappy_compress(input: *const u8, @@ -67,6 +71,7 @@ extern { fn snappy_validate_compressed_buffer(compressed: *const u8, compressed_length: size_t) -> c_int; } + # fn main() {} ``` @@ -85,8 +90,11 @@ the allocated memory. The length is less than or equal to the capacity. # #![feature(libc)] # extern crate libc; # use libc::{c_int, size_t}; +# # unsafe fn snappy_validate_compressed_buffer(_: *const u8, _: size_t) -> c_int { 0 } +# # fn main() {} +# pub fn validate_compressed_buffer(src: &[u8]) -> bool { unsafe { snappy_validate_compressed_buffer(src.as_ptr(), src.len() as size_t) == 0 @@ -110,10 +118,13 @@ the true length after compression for setting the length. # #![feature(libc)] # extern crate libc; # use libc::{size_t, c_int}; +# # unsafe fn snappy_compress(a: *const u8, b: size_t, c: *mut u8, # d: *mut size_t) -> c_int { 0 } # unsafe fn snappy_max_compressed_length(a: size_t) -> size_t { a } +# # fn main() {} +# pub fn compress(src: &[u8]) -> Vec { unsafe { let srclen = src.len() as size_t; @@ -137,6 +148,7 @@ format and `snappy_uncompressed_length` will retrieve the exact buffer size requ # #![feature(libc)] # extern crate libc; # use libc::{size_t, c_int}; +# # unsafe fn snappy_uncompress(compressed: *const u8, # compressed_length: size_t, # uncompressed: *mut u8, @@ -145,6 +157,7 @@ format and `snappy_uncompressed_length` will retrieve the exact buffer size requ # compressed_length: size_t, # result: *mut size_t) -> c_int { 0 } # fn main() {} +# pub fn uncompress(src: &[u8]) -> Option> { unsafe { let srclen = src.len() as size_t; @@ -197,11 +210,16 @@ extern fn callback(a: i32) { println!("I'm called from C with value {0}", a); } +# #[cfg(nope)] #[link(name = "extlib")] extern { fn register_callback(cb: extern fn(i32)) -> i32; fn trigger_callback(); } +# +# #[cfg(not(nope))] static mut CALLBACK: Option = None; +# #[cfg(not(nope))] unsafe fn register_callback(cb: extern fn(i32)) -> i32 { CALLBACK = Some(cb); 1 } +# #[cfg(not(nope))] unsafe fn trigger_callback() { CALLBACK.unwrap()(7); } fn main() { unsafe { @@ -260,12 +278,17 @@ extern "C" fn callback(target: *mut RustObject, a: i32) { } } +# #[cfg(nope)] #[link(name = "extlib")] extern { fn register_callback(target: *mut RustObject, cb: extern fn(*mut RustObject, i32)) -> i32; fn trigger_callback(); } +# +# #[cfg(not(nope))] static mut CALLBACK: Option<(*mut RustObject, extern fn(*mut RustObject, i32))> = None; +# #[cfg(not(nope))] unsafe fn register_callback(target: *mut RustObject, cb: extern fn(*mut RustObject, i32)) -> i32 { CALLBACK = Some((target, cb)); 1 } +# #[cfg(not(nope))] unsafe fn trigger_callback() { let (target, cb) = CALLBACK.unwrap(); cb(target, 7); } fn main() { // Create the object that will be referenced in the callback @@ -379,6 +402,8 @@ this: ```rust unsafe fn kaboom(ptr: *const i32) -> i32 { *ptr } + +# fn main() {} ``` This function can only be called from an `unsafe` block or another `unsafe` function. @@ -451,6 +476,7 @@ extern crate libc; extern "stdcall" { fn SetEnvironmentVariableA(n: *const u8, v: *const u8) -> libc::c_int; } + # fn main() { } ``` @@ -525,6 +551,7 @@ fairly easy, but requires a few things: pub extern fn hello_rust() -> *const u8 { "Hello, world!\0".as_ptr() } + # fn main() {} ``` @@ -554,6 +581,7 @@ pub extern fn oh_no() -> i32 { Err(_) => 0, } } + # fn main() {} ``` @@ -578,6 +606,7 @@ extern "C" { pub fn foo(arg: *mut libc::c_void); pub fn bar(arg: *mut libc::c_void); } + # fn main() {} ``` @@ -603,6 +632,7 @@ extern "C" { pub fn foo(arg: *mut Foo); pub fn bar(arg: *mut Bar); } + # fn main() {} ``` From 566330bc2b0059f196a657f4dac310c66f959a7d Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Wed, 11 Nov 2015 18:26:16 -0500 Subject: [PATCH 2/4] trpl: push cargo in FFI chapter --- src/doc/trpl/ffi.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/doc/trpl/ffi.md b/src/doc/trpl/ffi.md index d0d2215ba8236..81a09d7164316 100644 --- a/src/doc/trpl/ffi.md +++ b/src/doc/trpl/ffi.md @@ -5,8 +5,19 @@ This guide will use the [snappy](https://github.com/google/snappy) compression/decompression library as an introduction to writing bindings for foreign code. Rust is currently unable to call directly into a C++ library, but -snappy includes a C interface (documented in -[`snappy-c.h`](https://github.com/google/snappy/blob/master/snappy-c.h)). +snappy includes a C interface (documented in [`snappy-c.h`][snappy-header]). + +[snappy-header]: https://github.com/google/snappy/blob/master/snappy-c.h + +Often when writing these bindings, types and functions from the C standard +library will be necessary. These can be found in the +[libc crate on crates.io][libc], which can be accessed in a Cargo project +by [adding it as a dependency][cargo-add]. (Note that if you click the examples +here to load them in the [playground](https://play.rust-lang.org), which doesn't +support Cargo, you'll see extra lines of code to keep them compiling while +remaining self-contained... but in your own projects you should use Cargo.) + +[cargo-add]: http://doc.crates.io/guide.html#adding-a-dependency The following is a minimal example of calling a foreign function which will compile if snappy is installed: @@ -23,7 +34,7 @@ extern { } # #[cfg(not(nope))] unsafe fn snappy_max_compressed_length(_: size_t) -> size_t { 0 } - +# fn main() { let x = unsafe { snappy_max_compressed_length(100) }; println!("max compressed length of a 100 byte buffer: {}", x); From 371567294e05be31490e677bc83056282bba3cce Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Thu, 12 Nov 2015 10:56:31 -0500 Subject: [PATCH 3/4] Revert "trpl: get all examples in ffi.md compiling" This reverts commit 9c9f95c2d9d224c9c5978ae5b1e65f92a969413e. --- src/doc/trpl/ffi.md | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/src/doc/trpl/ffi.md b/src/doc/trpl/ffi.md index 81a09d7164316..625c72f928da1 100644 --- a/src/doc/trpl/ffi.md +++ b/src/doc/trpl/ffi.md @@ -27,14 +27,11 @@ compile if snappy is installed: extern crate libc; use libc::size_t; -#[cfg(nope)] #[link(name = "snappy")] extern { fn snappy_max_compressed_length(source_length: size_t) -> size_t; } -# #[cfg(not(nope))] unsafe fn snappy_max_compressed_length(_: size_t) -> size_t { 0 } -# fn main() { let x = unsafe { snappy_max_compressed_length(100) }; println!("max compressed length of a 100 byte buffer: {}", x); @@ -64,7 +61,6 @@ The `extern` block can be extended to cover the entire snappy API: extern crate libc; use libc::{c_int, size_t}; -# #[cfg(nope)] #[link(name = "snappy")] extern { fn snappy_compress(input: *const u8, @@ -82,7 +78,6 @@ extern { fn snappy_validate_compressed_buffer(compressed: *const u8, compressed_length: size_t) -> c_int; } - # fn main() {} ``` @@ -101,11 +96,8 @@ the allocated memory. The length is less than or equal to the capacity. # #![feature(libc)] # extern crate libc; # use libc::{c_int, size_t}; -# # unsafe fn snappy_validate_compressed_buffer(_: *const u8, _: size_t) -> c_int { 0 } -# # fn main() {} -# pub fn validate_compressed_buffer(src: &[u8]) -> bool { unsafe { snappy_validate_compressed_buffer(src.as_ptr(), src.len() as size_t) == 0 @@ -129,13 +121,10 @@ the true length after compression for setting the length. # #![feature(libc)] # extern crate libc; # use libc::{size_t, c_int}; -# # unsafe fn snappy_compress(a: *const u8, b: size_t, c: *mut u8, # d: *mut size_t) -> c_int { 0 } # unsafe fn snappy_max_compressed_length(a: size_t) -> size_t { a } -# # fn main() {} -# pub fn compress(src: &[u8]) -> Vec { unsafe { let srclen = src.len() as size_t; @@ -159,7 +148,6 @@ format and `snappy_uncompressed_length` will retrieve the exact buffer size requ # #![feature(libc)] # extern crate libc; # use libc::{size_t, c_int}; -# # unsafe fn snappy_uncompress(compressed: *const u8, # compressed_length: size_t, # uncompressed: *mut u8, @@ -168,7 +156,6 @@ format and `snappy_uncompressed_length` will retrieve the exact buffer size requ # compressed_length: size_t, # result: *mut size_t) -> c_int { 0 } # fn main() {} -# pub fn uncompress(src: &[u8]) -> Option> { unsafe { let srclen = src.len() as size_t; @@ -221,16 +208,11 @@ extern fn callback(a: i32) { println!("I'm called from C with value {0}", a); } -# #[cfg(nope)] #[link(name = "extlib")] extern { fn register_callback(cb: extern fn(i32)) -> i32; fn trigger_callback(); } -# -# #[cfg(not(nope))] static mut CALLBACK: Option = None; -# #[cfg(not(nope))] unsafe fn register_callback(cb: extern fn(i32)) -> i32 { CALLBACK = Some(cb); 1 } -# #[cfg(not(nope))] unsafe fn trigger_callback() { CALLBACK.unwrap()(7); } fn main() { unsafe { @@ -289,17 +271,12 @@ extern "C" fn callback(target: *mut RustObject, a: i32) { } } -# #[cfg(nope)] #[link(name = "extlib")] extern { fn register_callback(target: *mut RustObject, cb: extern fn(*mut RustObject, i32)) -> i32; fn trigger_callback(); } -# -# #[cfg(not(nope))] static mut CALLBACK: Option<(*mut RustObject, extern fn(*mut RustObject, i32))> = None; -# #[cfg(not(nope))] unsafe fn register_callback(target: *mut RustObject, cb: extern fn(*mut RustObject, i32)) -> i32 { CALLBACK = Some((target, cb)); 1 } -# #[cfg(not(nope))] unsafe fn trigger_callback() { let (target, cb) = CALLBACK.unwrap(); cb(target, 7); } fn main() { // Create the object that will be referenced in the callback @@ -413,8 +390,6 @@ this: ```rust unsafe fn kaboom(ptr: *const i32) -> i32 { *ptr } - -# fn main() {} ``` This function can only be called from an `unsafe` block or another `unsafe` function. @@ -487,7 +462,6 @@ extern crate libc; extern "stdcall" { fn SetEnvironmentVariableA(n: *const u8, v: *const u8) -> libc::c_int; } - # fn main() { } ``` @@ -562,7 +536,6 @@ fairly easy, but requires a few things: pub extern fn hello_rust() -> *const u8 { "Hello, world!\0".as_ptr() } - # fn main() {} ``` @@ -592,7 +565,6 @@ pub extern fn oh_no() -> i32 { Err(_) => 0, } } - # fn main() {} ``` @@ -617,7 +589,6 @@ extern "C" { pub fn foo(arg: *mut libc::c_void); pub fn bar(arg: *mut libc::c_void); } - # fn main() {} ``` @@ -643,7 +614,6 @@ extern "C" { pub fn foo(arg: *mut Foo); pub fn bar(arg: *mut Bar); } - # fn main() {} ``` From 9454fd45dec402c5b93863693c42bd2b60b73a73 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Thu, 12 Nov 2015 11:03:46 -0500 Subject: [PATCH 4/4] trpl: make FFI examples compile using comments and shims --- src/doc/trpl/ffi.md | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/doc/trpl/ffi.md b/src/doc/trpl/ffi.md index 625c72f928da1..0122ad056c641 100644 --- a/src/doc/trpl/ffi.md +++ b/src/doc/trpl/ffi.md @@ -22,15 +22,18 @@ remaining self-contained... but in your own projects you should use Cargo.) The following is a minimal example of calling a foreign function which will compile if snappy is installed: -```no_run +```rust # #![feature(libc)] extern crate libc; use libc::size_t; +# /* #[link(name = "snappy")] extern { fn snappy_max_compressed_length(source_length: size_t) -> size_t; } +# */ +# unsafe fn snappy_max_compressed_length(_: size_t) -> size_t { 0 } fn main() { let x = unsafe { snappy_max_compressed_length(100) }; @@ -56,12 +59,14 @@ keeping the binding correct at runtime. The `extern` block can be extended to cover the entire snappy API: -```no_run +```rust # #![feature(libc)] extern crate libc; use libc::{c_int, size_t}; +# /* #[link(name = "snappy")] +# */ extern { fn snappy_compress(input: *const u8, input_length: size_t, @@ -203,16 +208,21 @@ A basic example is: Rust code: -```no_run +```rust extern fn callback(a: i32) { println!("I'm called from C with value {0}", a); } +# /* #[link(name = "extlib")] extern { fn register_callback(cb: extern fn(i32)) -> i32; fn trigger_callback(); } +# */ +# static mut CALLBACK: Option = None; +# unsafe fn register_callback(cb: extern fn(i32)) -> i32 { CALLBACK = Some(cb); 0 } +# unsafe fn trigger_callback() { CALLBACK.unwrap()(7); } fn main() { unsafe { @@ -256,7 +266,7 @@ referenced Rust object. Rust code: -```no_run +```rust #[repr(C)] struct RustObject { a: i32, @@ -271,12 +281,17 @@ extern "C" fn callback(target: *mut RustObject, a: i32) { } } +# /* #[link(name = "extlib")] extern { fn register_callback(target: *mut RustObject, cb: extern fn(*mut RustObject, i32)) -> i32; fn trigger_callback(); } +# */ +# static mut CALLBACK: Option<(*mut RustObject, extern fn(*mut RustObject, i32))> = None; +# unsafe fn register_callback(target: *mut RustObject, cb: extern fn(*mut RustObject, i32)) -> i32 { CALLBACK = Some((target, cb)); 0 } +# unsafe fn trigger_callback() { let (target, cb) = CALLBACK.unwrap(); cb(target, 7); } fn main() { // Create the object that will be referenced in the callback @@ -390,6 +405,7 @@ this: ```rust unsafe fn kaboom(ptr: *const i32) -> i32 { *ptr } +# fn main() {} ``` This function can only be called from an `unsafe` block or another `unsafe` function. @@ -400,7 +416,7 @@ Foreign APIs often export a global variable which could do something like track global state. In order to access these variables, you declare them in `extern` blocks with the `static` keyword: -```no_run +```rust # #![feature(libc)] extern crate libc; @@ -419,7 +435,7 @@ Alternatively, you may need to alter global state provided by a foreign interface. To do this, statics can be declared with `mut` so we can mutate them. -```no_run +```rust # #![feature(libc)] extern crate libc;