Skip to content

Commit ff60f5a

Browse files
authored
wrap the C++ library in a -sys crate to ensure compatibility (#24)
This PR transforms the repo into a two crate workspace, one crate being a -sys wrapper crate around the c++ library, and the other being the higher level rust API you use.
1 parent 0c3875d commit ff60f5a

32 files changed

+1203
-349
lines changed

.github/workflows/rust.yml

+5-5
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ jobs:
1616
steps:
1717
- uses: actions/checkout@v2
1818
- name: Build - All Features
19-
run: cargo build --verbose --all-features
19+
run: RUSTFLAGS="-D warnings" cargo build --verbose --all-features
2020
- name: Build - Default
21-
run: cargo build --verbose
21+
run: RUSTFLAGS="-D warnings" cargo build --verbose --features="c-stubs"
2222
- name: Build - No Default Features
23-
run: cargo build --verbose --no-default-features
23+
run: RUSTFLAGS="-D warnings" cargo build --verbose --no-default-features --features="c-stubs"
2424
- name: Build - Check Examples & Tests
25-
run: cargo check --verbose --all-features --tests --examples
25+
run: RUSTFLAGS="-D warnings" cargo check --verbose --all-features --tests --examples
2626

2727
clippy:
2828
runs-on: ubuntu-latest
@@ -48,4 +48,4 @@ jobs:
4848
toolchain: nightly
4949
components: rustfmt
5050
override: true
51-
- run: rustfmt --check --edition 2018 ./src/* ./examples/*
51+
- run: rustfmt --check --edition 2018 ./*/src/* ./*/examples/* ./*/build.rs

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,6 @@ Cargo.lock
99

1010
# These are backup files generated by rustfmt
1111
**/*.rs.bk
12+
13+
# mac stuff
14+
*.DS_Store

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "rpi-led-matrix-sys/cpp-library"]
2+
path = rpi-led-matrix-sys/cpp-library
3+
url = [email protected]:hzeller/rpi-rgb-led-matrix.git

.vscode/settings.json

-6
This file was deleted.

Cargo.toml

+5-43
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,9 @@
1-
[package]
2-
name = "rpi-led-matrix"
3-
description = "Bindings for Hzeller's RPi-RGB-Led-Matrix"
4-
version = "0.2.2"
5-
authors = [
6-
"Vincent Pasquier <[email protected]>",
7-
"Tyler Holmes <[email protected]>",
8-
"Broderick Carlin <[email protected]>",
9-
]
10-
repository = "https://github.com/rust-rpi-led-matrix/rust-rpi-rgb-led-matrix"
11-
homepage = "https://docs.rs/rpi-led-matrix/"
12-
build = "build.rs"
13-
license = "GPL-3.0"
14-
readme = "README.md"
15-
edition = "2018"
16-
17-
[features]
18-
default = ["embeddedgraphics"]
19-
20-
embeddedgraphics = ["embedded-graphics"]
21-
args = ["clap"]
22-
23-
[build-dependencies]
24-
gcc = "0.3"
25-
26-
[dependencies]
27-
libc = "0.2"
28-
embedded-graphics = { version = "0.6.2", optional = true }
29-
clap = { version = "2.33", optional = true }
1+
[workspace]
302

31-
[[example]]
32-
name = "arguments"
33-
required-features = ["args"]
34-
35-
[[example]]
36-
name = "c-api-basic"
37-
required-features = ["args"]
38-
39-
[[example]]
40-
name = "embedded-graphics-basic"
41-
required-features = ["args", "embeddedgraphics"]
42-
43-
[package.metadata.docs.rs]
44-
all-features = true
3+
members = [
4+
"rpi-led-matrix",
5+
"rpi-led-matrix-sys",
6+
]
457

468
[profile.release]
479
codegen-units = 1

README.md

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Control RGB LED displays from Rust
22

3-
This repository contains rust bindings for the C++ library [rpi-rgb-led-matrix](https://github.com/hzeller/rpi-rgb-led-matrix),
4-
which enables controlling Hub75 based displays.
5-
In order to take advantage of the newer APIs, the minimum supported commit of the library is
6-
[55fa32f](https://github.com/hzeller/rpi-rgb-led-matrix/commit/55fa32fc2e02afb254ac834aea93589d5b891a11)
7-
(Sept. 7th, 2020), which exposes all parameters that affect how the matrix runs.
3+
This repository contains rust bindings for the C++ library
4+
[rpi-rgb-led-matrix](https://github.com/hzeller/rpi-rgb-led-matrix),
5+
which enables controlling Hub75 based displays. It includes both raw bindings
6+
to the library in [`rpi-led-matrix-sys`] as well as higher level, safe rust
7+
bindings in [`rpi-led-matrix`].
88

99
# Usage
1010

@@ -24,3 +24,6 @@ for red in 0..255 {
2424
}
2525
```
2626
Note that if you have wirings other than the libraries "default", you will need to construct arguments to the library to specify the layout. See `LedMatrixOptions` for more information.
27+
28+
[`rpi-led-matrix-sys`]: docs.rs/crate/rpi-led-matrix-sys
29+
[`rpi-led-matrix`]: docs.rs/crate/rpi-led-matrix

build.rs

-5
This file was deleted.
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"rust-analyzer.cargo.allFeatures": true
3+
}

rpi-led-matrix-sys/CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [0.1.0] - ???
9+
10+
- Initial release

rpi-led-matrix-sys/Cargo.toml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[package]
2+
name = "rpi-led-matrix-sys"
3+
version = "0.1.0"
4+
edition = "2018"
5+
description = "system library for the rpi-rgb-led-matrix C++ library"
6+
links = "rgbmatrixsys"
7+
build = "build.rs"
8+
license = "GPL-3.0"
9+
10+
[dependencies]
11+
libc = "0.2"
12+
13+
[build-dependencies]
14+
copy_dir = "0.1"
15+
16+
[features]
17+
default = []
18+
c-stubs = []
19+
20+
[package.metadata.docs.rs]
21+
all-features = true
File renamed without changes.

rpi-led-matrix-sys/README.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# rpi-led-matrix-sys
2+
3+
This crate provides direct, low-level bindings to the C++ library
4+
[`rpi-rgb-led-matrix`].
5+
6+
## [Documentation](docs.rs/crate/rpi-led-matrix-sys)
7+
8+
## Safe Rust Bindings
9+
10+
The [rpi-led-matrix](https://docs.rs/crate/rpi-led-matrix/) crate builds
11+
safe rust bindings on top of this crate and is the recommended way to
12+
interact with [`rpi-rgb-led-matrix`]
13+
14+
[`rpi-rgb-led-matrix`]: https://github.com/hzeller/rpi-rgb-led-matrix

rpi-led-matrix-sys/build.rs

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//! Build script for `rpi-led-matrix-sys`
2+
//!
3+
//! This build script:
4+
//! 0. checks if we're on a raspberry pi to make sure compilation has a chance of success
5+
//! 1. copies our git submodule checkout of the C++ library to build artifacts
6+
//! 2. builds the C++ library from there
7+
//! 3. statically links against it
8+
9+
fn main() {
10+
// Early out if we're stubbing the C api ourselves
11+
if std::env::var("CARGO_FEATURE_C_STUBS").is_ok() {
12+
std::process::exit(0);
13+
}
14+
15+
// 0. To guess at if we're on the right platform, look for linux as the system & arm as the architecture
16+
// Note I'm checking HOST instead of TARGET since the C++ library depends on natively linking to some libraries
17+
// that are only on rpis
18+
let host = std::env::var("HOST").unwrap();
19+
if !(host.contains("arm") || host.contains("aarch")) || !host.contains("linux") {
20+
eprintln!("rpi-led-matrix-sys detected you're likely not compiling on a raspberry pi");
21+
std::process::exit(-1);
22+
}
23+
24+
// 1. copy our git submodule over to build artifacts so things like `cargo clean` work properly
25+
let target_dir = std::env::var("OUT_DIR").unwrap();
26+
let repo_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
27+
let cpp_lib_dir: std::path::PathBuf = [&repo_dir, "cpp-library"].iter().collect();
28+
let cpp_lib_out_dir: std::path::PathBuf = [&target_dir, "cpp-library"].iter().collect();
29+
// Make sure our git submodule is checked out and up to date
30+
let status = std::process::Command::new("git")
31+
.arg("submodule")
32+
.arg("init")
33+
.status()
34+
.expect("process failed to execute");
35+
if !status.success() {
36+
panic!("failed to checkout the C++ library git submodule");
37+
}
38+
let status = std::process::Command::new("git")
39+
.arg("submodule")
40+
.arg("update")
41+
.status()
42+
.expect("process failed to execute");
43+
if !status.success() {
44+
panic!("failed to checkout the C++ library git submodule");
45+
}
46+
// delete our output git directory, if it exists, then copy the git repo over
47+
std::fs::remove_dir_all(&cpp_lib_out_dir).ok();
48+
copy_dir::copy_dir(&cpp_lib_dir, &cpp_lib_out_dir).unwrap();
49+
println!("cargo:rerun-if-changed={}", cpp_lib_dir.display());
50+
51+
// 2. build the library. We assume you have the tools necessary to build the library,
52+
// which I think are available by default on all pis
53+
let cpp_lib_lib_out_dir: std::path::PathBuf =
54+
[cpp_lib_out_dir.to_str().unwrap(), "lib"].iter().collect();
55+
std::env::set_current_dir(&cpp_lib_lib_out_dir).unwrap();
56+
println!("building from {}", cpp_lib_out_dir.display());
57+
let status = std::process::Command::new("make")
58+
.status()
59+
.expect("process failed to execute");
60+
if !status.success() {
61+
panic!("failed to compile the C++ library");
62+
}
63+
64+
// 2.1 rename the library produced to avoid ambiguity with global variants.
65+
let cpp_lib_lib_out_file: std::path::PathBuf =
66+
[cpp_lib_out_dir.to_str().unwrap(), "lib", "librgbmatrix.a"]
67+
.iter()
68+
.collect();
69+
let cpp_lib_lib_out_file_rename: std::path::PathBuf = [
70+
cpp_lib_out_dir.to_str().unwrap(),
71+
"lib",
72+
"librgbmatrixsys.a",
73+
]
74+
.iter()
75+
.collect();
76+
println!(
77+
"renaming library from {:?} to {:?}",
78+
&cpp_lib_lib_out_file, &cpp_lib_lib_out_file_rename
79+
);
80+
std::fs::rename(&cpp_lib_lib_out_file, &cpp_lib_lib_out_file_rename).unwrap();
81+
82+
// 3. link!
83+
println!(
84+
"cargo:rustc-link-search=native={}",
85+
cpp_lib_lib_out_dir.display()
86+
);
87+
println!("cargo:rustc-link-lib=static=rgbmatrixsys");
88+
}

rpi-led-matrix-sys/cpp-library

Submodule cpp-library added at 153e2ee

rpi-led-matrix-sys/src/c_stubs.rs

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//! rust implemented stubs of the C++ library for testing on non rpi hosts
2+
use crate::*;
3+
use libc::{c_char, c_int};
4+
5+
#[no_mangle]
6+
extern "C" fn led_matrix_create_from_options_and_rt_options(
7+
_opts: *mut CLedMatrixOptions,
8+
_rt_opts: *mut CLedRuntimeOptions,
9+
) -> *mut CLedMatrix {
10+
std::ptr::null_mut()
11+
}
12+
13+
#[no_mangle]
14+
extern "C" fn led_matrix_delete(_matrix: *mut CLedMatrix) {}
15+
16+
#[no_mangle]
17+
extern "C" fn led_matrix_get_canvas(_matrix: *mut CLedMatrix) -> *mut CLedCanvas {
18+
std::ptr::null_mut()
19+
}
20+
21+
#[no_mangle]
22+
extern "C" fn led_canvas_get_size(
23+
_canvas: *const CLedCanvas,
24+
_width: *mut c_int,
25+
_height: *mut c_int,
26+
) {
27+
}
28+
29+
#[no_mangle]
30+
extern "C" fn led_canvas_set_pixel(
31+
_canvas: *mut CLedCanvas,
32+
_x: c_int,
33+
_y: c_int,
34+
_r: u8,
35+
_g: u8,
36+
_b: u8,
37+
) {
38+
}
39+
40+
#[no_mangle]
41+
extern "C" fn led_canvas_clear(_canvas: *mut CLedCanvas) {}
42+
43+
#[no_mangle]
44+
extern "C" fn led_canvas_fill(_canvas: *mut CLedCanvas, _r: u8, _g: u8, _b: u8) {}
45+
46+
#[no_mangle]
47+
extern "C" fn led_matrix_create_offscreen_canvas(_matrix: *mut CLedMatrix) -> *mut CLedCanvas {
48+
std::ptr::null_mut()
49+
}
50+
51+
#[no_mangle]
52+
extern "C" fn led_matrix_swap_on_vsync(
53+
_matrix: *mut CLedMatrix,
54+
_canvas: *mut CLedCanvas,
55+
) -> *mut CLedCanvas {
56+
std::ptr::null_mut()
57+
}
58+
59+
#[no_mangle]
60+
extern "C" fn load_font(_bdf_font_file: *const c_char) -> *mut CLedFont {
61+
std::ptr::null_mut()
62+
}
63+
64+
#[no_mangle]
65+
extern "C" fn delete_font(_font: *mut CLedFont) {}
66+
67+
#[no_mangle]
68+
extern "C" fn draw_text(
69+
_canvas: *mut CLedCanvas,
70+
_font: *const CLedFont,
71+
_x: c_int,
72+
_y: c_int,
73+
_r: u8,
74+
_g: u8,
75+
_b: u8,
76+
_utf8_text: *const c_char,
77+
_kerning_offset: c_int,
78+
) -> c_int {
79+
0
80+
}
81+
82+
#[no_mangle]
83+
extern "C" fn vertical_draw_text(
84+
_canvas: *mut CLedCanvas,
85+
_font: *const CLedFont,
86+
_x: c_int,
87+
_y: c_int,
88+
_r: u8,
89+
_g: u8,
90+
_b: u8,
91+
_utf8_text: *const c_char,
92+
_kerning_offset: c_int,
93+
) -> c_int {
94+
0
95+
}
96+
97+
#[no_mangle]
98+
extern "C" fn draw_circle(
99+
_canvas: *mut CLedCanvas,
100+
_x: c_int,
101+
_y: c_int,
102+
_radius: c_int,
103+
_r: u8,
104+
_g: u8,
105+
_b: u8,
106+
) {
107+
}
108+
109+
#[no_mangle]
110+
extern "C" fn draw_line(
111+
_canvas: *mut CLedCanvas,
112+
_x0: c_int,
113+
_y0: c_int,
114+
_x1: c_int,
115+
_y1: c_int,
116+
_r: u8,
117+
_g: u8,
118+
_b: u8,
119+
) {
120+
}

0 commit comments

Comments
 (0)