├── c_from_rust ├── lib.c └── main.rs ├── rust_from_c ├── lib.rs └── main.c ├── cargo_rust_from_c ├── cargo.sh ├── lib.rs ├── Cargo.toml ├── grab_objects.sh └── Cargo.lock ├── meson_options.txt ├── README.md ├── test.sh ├── LICENSE └── meson.build /c_from_rust/lib.c: -------------------------------------------------------------------------------- 1 | int cfunction() { 2 | return 50; 3 | } 4 | -------------------------------------------------------------------------------- /rust_from_c/lib.rs: -------------------------------------------------------------------------------- 1 | #[no_mangle] 2 | fn rustfunction() -> i8 { 3 | 50 4 | } -------------------------------------------------------------------------------- /cargo_rust_from_c/cargo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd $(dirname $0) 4 | cargo build $@ 5 | -------------------------------------------------------------------------------- /cargo_rust_from_c/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate libc; 2 | use libc::c_int; 3 | 4 | #[no_mangle] 5 | fn cargofunction() -> c_int { 6 | 100 7 | } -------------------------------------------------------------------------------- /c_from_rust/main.rs: -------------------------------------------------------------------------------- 1 | #[link(name = "clib")] 2 | extern { 3 | fn cfunction() -> i64; 4 | } 5 | 6 | fn main() { 7 | println!("Hello {}", unsafe { cfunction() }); 8 | } -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option( 2 | 'release', 3 | type : 'boolean', 4 | value : false, 5 | description : 'Controls whether cargo is called with the --release flag or not. Defaults to false.' 6 | ) -------------------------------------------------------------------------------- /cargo_rust_from_c/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cargo_rslib" 3 | version = "0.1.0" 4 | 5 | [dependencies] 6 | libc = "0.2" 7 | 8 | [lib] 9 | name = "cargo_rslib" 10 | path = "lib.rs" 11 | crate-type = ["dylib"] 12 | -------------------------------------------------------------------------------- /rust_from_c/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int rustfunction(); 4 | int cargofunction(); 5 | 6 | 7 | int main(void) { 8 | printf("Hello %d\n", rustfunction()); 9 | printf("Hello %d\n", cargofunction()); 10 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Meson-Rust-C-FFI-Example 2 | Example project showing how Meson can be used to build mixed Rust/C projects 3 | 4 | Run test.sh to go through the build/run/teardown process. Only works on Linux, but could be modified to work on other platforms as well. 5 | -------------------------------------------------------------------------------- /cargo_rust_from_c/grab_objects.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Grabs all of the .so files generated by cargo. 4 | # Takes one argument specifying whether or not it should look 5 | # in the "release" or "debug" folder. 6 | 7 | find cargo_rust_from_c/target/$1/*.so 8 | # The file extension could be "so", "dylib", or "dll" depending on the platform. 9 | -------------------------------------------------------------------------------- /cargo_rust_from_c/Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "cargo_rslib" 3 | version = "0.1.0" 4 | dependencies = [ 5 | "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", 6 | ] 7 | 8 | [[package]] 9 | name = "libc" 10 | version = "0.2.46" 11 | source = "registry+https://github.com/rust-lang/crates.io-index" 12 | 13 | [metadata] 14 | "checksum libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)" = "023a4cd09b2ff695f9734c1934145a315594b7986398496841c7031a5a1bbdbd" 15 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "test.sh: Running Meson..." 4 | meson build-debug -D release=false 5 | echo "" 6 | meson build-release -D release=true 7 | # The -D argument is how options are passed to Meson 8 | 9 | 10 | echo "test.sh: Building 'build-debug' with ninja..." 11 | cd build-debug 12 | ninja 13 | echo "test.sh: Running 'build-debug' executables..." 14 | echo "cexe:" 15 | ./cexe 16 | echo "rsexe:" 17 | ./rsexe 18 | 19 | 20 | echo "" 21 | cd .. 22 | 23 | 24 | echo "test.sh: Building 'build-release' with ninja..." 25 | cd build-release 26 | ninja 27 | echo "test.sh: Running 'build-release' executables..." 28 | echo "cexe:" 29 | ./cexe 30 | echo "rsexe:" 31 | ./rsexe 32 | 33 | 34 | echo "" 35 | cd .. 36 | 37 | 38 | echo "test.sh: Tearing down..." 39 | rm -rf build-debug 40 | rm -rf build-release 41 | rm -rf cargo_rust_from_c/target 42 | 43 | echo "test.sh: Done!" 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Ethan R 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('ffi_test', ['c', 'rust']) 2 | 3 | find_program('cargo', required : true) 4 | cargo_build = find_program('cargo_rust_from_c/cargo.sh') 5 | 6 | if get_option('release') 7 | message('Release mode enabled') 8 | cargo_args = ['--release'] 9 | grab_objects_arg = 'release' 10 | else 11 | message('Debug mode enabled') 12 | cargo_args = [] 13 | grab_objects_arg = 'debug' 14 | endif 15 | 16 | message('Running cargo...') 17 | cargo_result = run_command(cargo_build, cargo_args) 18 | cargo_stdout = cargo_result.stdout().strip() 19 | cargo_stderr = cargo_result.stderr().strip() 20 | if cargo_stderr != '' 21 | message(cargo_stderr) 22 | elif cargo_stdout != '' 23 | message(cargo_stdout) 24 | else 25 | message('Cargo is done') 26 | endif 27 | 28 | # Here we grab any shared library objects from Cargo's generated "target" directory 29 | # using a shell script to take advantage of wildcards. 30 | grab_objects = find_program('cargo_rust_from_c/grab_objects.sh') 31 | 32 | # The output is sanitized and made into an array. 33 | cargo_rslib_objects = run_command(grab_objects, grab_objects_arg).stdout().strip().split('\n') 34 | 35 | message('Found objects:') 36 | message(cargo_rslib_objects) 37 | 38 | executable( 39 | 'cexe', 'rust_from_c/main.c', 40 | link_with : library('rslib', 'rust_from_c/lib.rs'), 41 | objects : cargo_rslib_objects 42 | # The objects generated by cargo are put here so they can be 43 | # linked with the C executable. 44 | 45 | # This method seems like it may be a little dirty, but it's the 46 | # only method I could find. 47 | ) 48 | 49 | executable( 50 | 'rsexe', 'c_from_rust/main.rs', 51 | link_with : library('clib', 'c_from_rust/lib.c') 52 | ) 53 | --------------------------------------------------------------------------------