Skip to content

Commit

Permalink
Merge branch 'rust/bindgen' into 'master'
Browse files Browse the repository at this point in the history
Support for code auto generation from header files

Closes RIOT-OS#26 and RIOT-OS#34

See merge request !8
  • Loading branch information
Tristan Bruns committed Feb 13, 2017
2 parents 23fd471 + e235595 commit 9fd65eb
Show file tree
Hide file tree
Showing 17 changed files with 126 additions and 121 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ tags
# GDB initialization scripts
.gdbinit

# Symlink to /dev/stdin for rust bindgen hack
ffi.rs

# Eclipse symbol file (output from make eclipsesym)
eclipsesym.xml
/toolchain
Expand Down
21 changes: 19 additions & 2 deletions Makefile.base
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ ifeq ($(strip $(RUSTSRC)),)
CRATE_TYPE = lib
endif

RUSTSRC = $(wildcard *.rs)
# ffi.rs is a symlink to /dev/stdin. Don't track it.
RUSTSRC = $(filter-out ffi.rs,$(wildcard *.rs))
endif
ifeq ($(strip $(ASMSRC)),)
ASMSRC := $(wildcard *.s)
Expand Down Expand Up @@ -84,6 +85,16 @@ $(OBJCXX): $(BINDIR)/$(MODULE)/%.o: %.cpp $(RIOTBUILD_CONFIG_HEADER_C)
ifdef CRATE_TYPE
include $(RIOTBASE)/Makefile.rust

ifneq (,$(RUST_FFI_HEADER))
BINDGEN_CFLAGS = -include $(RIOTBUILD_CONFIG_HEADER_C) \
$(INCLUDES)

ifneq ($(TOOLCHAIN),llvm)
include $(RIOTCPU)/Makefile.include.llvm_common
BINDGEN_CFLAGS += $(GCC_C_INCLUDES)
endif
endif

ifeq (1,$(RUST_FFI))
RUST_FFI_LIB = $(BINDIR)/$(MODULE)/libffi.a
$(RUST_FFI_LIB): $(OBJ)
Expand All @@ -98,8 +109,14 @@ $(BINDIR)/$(MODULE).a: $(RUSTOBJ)
$(AD)$(AR) $(ARFLAGS) $@ $<
else ifeq ($(CRATE_TYPE),lib)
LIBNAME = $(MODULE:rust/%=rust/lib%)
$(BINDIR)/$(LIBNAME).rlib: $(RUSTSRC) | $(BINDIR)/$(MODULE)/ $(RUST_FFI_LIB) ${DIRS:%=ALL--%}
$(BINDIR)/$(LIBNAME).rlib: $(RUSTSRC) $(RUST_FFI_HEADER) | $(BINDIR)/$(MODULE)/ $(RUST_FFI_LIB) ${DIRS:%=ALL--%}
ifneq (,$(RUST_FFI_HEADER))
$(AD)ln -fs /dev/stdin ffi.rs
$(AD)bindgen $(BINDGEN_FLAGS) $(RUST_FFI_HEADER) -- $(BINDGEN_CFLAGS) | \
rustc $(RUSTC_FLAGS) --emit link,dep-info --out-dir $(shell dirname $@) lib.rs
else
$(AD)rustc $(RUSTC_FLAGS) --emit link,dep-info --out-dir $(shell dirname $@) lib.rs
endif
$(BINDIR)/$(MODULE).a: $(BINDIR)/$(LIBNAME).rlib
$(AD)ln -fs $< $@
else
Expand Down
6 changes: 6 additions & 0 deletions Makefile.rust
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ else
RUST_TARGET=$(CPU_ARCH)
endif

# Flags to pass to bindgen
BINDGEN_FLAGS := --use-core --generate types \
--ctypes-prefix ::cpu::libc \
--no-doc-comments \
$(RUST_FFI_TYPES:%=--whitelist-type %)

# Enable some compiler optimizations
RUSTC_FLAGS += -C opt-level=s
ifeq (bin,$(CRATE_TYPE))
Expand Down
58 changes: 1 addition & 57 deletions cpu/Makefile.include.llvm
Original file line number Diff line number Diff line change
Expand Up @@ -24,66 +24,10 @@ export DBG = $(GDBPREFIX)gdb
# LLVM lacks a binutils strip tool as well...
#export STRIP = $(LLVMPREFIX)strip

# Clang on Linux uses GCC's C++ headers and libstdc++ (installed with GCC)
# Ubuntu and Debian use /etc/alternatives/gcc-$(TARGET_ARCH)-include/c++/$(GCC_VERSION)
# Arch uses /usr/$(TARGET_ARCH)/include/c++/$(GCC_VERSION)
# Gentoo uses /usr/lib/gcc/$(TARGET_ARCH)/$(GCC_VERSION)/include/g++-v5
GCC_CXX_INCLUDE_PATTERNS ?= \
/etc/alternatives/gcc-$(TARGET_ARCH)-include/c++/*/ \
/usr/$(TARGET_ARCH)/include/c++/*/ \
/usr/lib/gcc/$(TARGET_ARCH)/*/include/g++-v5 \
#

# Try to find the proper multilib directory using GCC, this may fail if a cross-
# GCC is not installed.
ifeq ($(GCC_MULTI_DIR),)
GCC_MULTI_DIR := $(shell $(PREFIX)gcc -print-multi-directory $(CFLAGS) 2>/dev/null)
endif

# Tell clang to cross compile
export CFLAGS += -target $(TARGET_ARCH)
export CXXFLAGS += -target $(TARGET_ARCH)
export LINKFLAGS += -target $(TARGET_ARCH)

# Use the wildcard Makefile function to search for existing directories matching
# the patterns above. We use the -isystem gcc/clang argument to add the include
# directories as system include directories, which means they will not be
# searched until after all the project specific include directories (-I/path)
# We sort the list of found directories and take the last one, it will likely be
# the most recent GCC version. This avoids using old headers left over from
# previous tool chain installations.
GCC_CXX_INCLUDES ?= \
$(addprefix \
-isystem $(lastword $(sort \
$(foreach pat, $(GCC_CXX_INCLUDE_PATTERNS), $(wildcard $(pat))))), \
/. /$(TARGET_ARCH)/$(GCC_MULTI_DIR) /backward \
)

# If nothing was found we will try to fall back to searching for a cross-gcc in
# the current PATH and use a relative path for the includes
ifeq (,$(GCC_CXX_INCLUDES))
GCC_CXX_INCLUDES := $(addprefix -isystem ,$(wildcard $(dir $(shell which $(PREFIX)gcc))../$(TARGET_TRIPLE)/include))
endif

# Pass the includes to the C++ compilation rule in Makefile.base
export CXXINCLUDES += $(GCC_CXX_INCLUDES)

# Some C headers (e.g. limits.h) are located with the GCC libraries
GCC_C_INCLUDE_PATTERNS ?= \
/usr/lib/gcc/$(TARGET_TRIPLE)/*/ \
#

GCC_C_INCLUDES ?= \
$(addprefix -isystem ,$(wildcard $(addprefix \
$(lastword $(sort \
$(foreach pat, $(GCC_C_INCLUDE_PATTERNS), $(wildcard $(pat))))), \
include include-fixed) \
))

# If nothing was found we will try to fall back to searching for the libgcc used
# by an installed cross-GCC and use its headers.
ifeq (,$(GCC_C_INCLUDES))
GCC_C_INCLUDES := $(addprefix -isystem ,$(wildcard $(addprefix $(dir $(shell $(PREFIX)gcc -print-libgcc-file-name)), include include-fixed)))
endif

include $(RIOTCPU)/Makefile.include.llvm_common
export INCLUDES += $(GCC_C_INCLUDES)
56 changes: 56 additions & 0 deletions cpu/Makefile.include.llvm_common
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Clang on Linux uses GCC's C++ headers and libstdc++ (installed with GCC)
# Ubuntu and Debian use /etc/alternatives/gcc-$(TARGET_ARCH)-include/c++/$(GCC_VERSION)
# Arch uses /usr/$(TARGET_ARCH)/include/c++/$(GCC_VERSION)
# Gentoo uses /usr/lib/gcc/$(TARGET_ARCH)/$(GCC_VERSION)/include/g++-v5
GCC_CXX_INCLUDE_PATTERNS ?= \
/etc/alternatives/gcc-$(TARGET_ARCH)-include/c++/*/ \
/usr/$(TARGET_ARCH)/include/c++/*/ \
/usr/lib/gcc/$(TARGET_ARCH)/*/include/g++-v5 \
#

# Try to find the proper multilib directory using GCC, this may fail if a cross-
# GCC is not installed.
ifeq ($(GCC_MULTI_DIR),)
GCC_MULTI_DIR := $(shell $(PREFIX)gcc -print-multi-directory $(CFLAGS) 2>/dev/null)
endif

# Use the wildcard Makefile function to search for existing directories matching
# the patterns above. We use the -isystem gcc/clang argument to add the include
# directories as system include directories, which means they will not be
# searched until after all the project specific include directories (-I/path)
# We sort the list of found directories and take the last one, it will likely be
# the most recent GCC version. This avoids using old headers left over from
# previous tool chain installations.
GCC_CXX_INCLUDES ?= \
$(addprefix \
-isystem $(lastword $(sort \
$(foreach pat, $(GCC_CXX_INCLUDE_PATTERNS), $(wildcard $(pat))))), \
/. /$(TARGET_ARCH)/$(GCC_MULTI_DIR) /backward \
)

# If nothing was found we will try to fall back to searching for a cross-gcc in
# the current PATH and use a relative path for the includes
ifeq (,$(GCC_CXX_INCLUDES))
GCC_CXX_INCLUDES := $(addprefix -isystem ,$(wildcard $(dir $(shell which $(PREFIX)gcc))../$(TARGET_TRIPLE)/include))
endif

# Pass the includes to the C++ compilation rule in Makefile.base
export CXXINCLUDES += $(GCC_CXX_INCLUDES)

# Some C headers (e.g. limits.h) are located with the GCC libraries
GCC_C_INCLUDE_PATTERNS ?= \
/usr/lib/gcc/$(TARGET_TRIPLE)/*/ \
#

GCC_C_INCLUDES ?= \
$(addprefix -isystem ,$(wildcard $(addprefix \
$(lastword $(sort \
$(foreach pat, $(GCC_C_INCLUDE_PATTERNS), $(wildcard $(pat))))), \
include include-fixed) \
))

# If nothing was found we will try to fall back to searching for the libgcc used
# by an installed cross-GCC and use its headers.
ifeq (,$(GCC_C_INCLUDES))
GCC_C_INCLUDES := $(addprefix -isystem ,$(wildcard $(addprefix $(dir $(shell $(PREFIX)gcc -print-libgcc-file-name)), include include-fixed)))
endif
1 change: 0 additions & 1 deletion cpu/rust/basecpu/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#![no_std]
#![allow(bad_style)]

pub mod periph_cpu;
pub mod libc;
20 changes: 0 additions & 20 deletions cpu/rust/basecpu/periph_cpu.rs

This file was deleted.

3 changes: 0 additions & 3 deletions cpu/rust/native/periph_cpu.rs

This file was deleted.

20 changes: 0 additions & 20 deletions cpu/rust/stm32f1/periph_cpu.rs

This file was deleted.

2 changes: 0 additions & 2 deletions drivers/rust/gpio/Makefile

This file was deleted.

10 changes: 10 additions & 0 deletions drivers/rust/periph/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Auto generate an ffi.rs file from a C header.
RUST_FFI_HEADER = $(RIOTBASE)/drivers/include/periph/gpio.h

# Types from the headers to autogenerate bindings for.
RUST_FFI_TYPES = gpio_t gpio_mode_t gpio_isr_ctx_t

# Build libffi.a to wrap C Macros.
RUST_FFI = 1

include $(RIOTBASE)/drivers/rust/Makefile.crate
File renamed without changes.
15 changes: 5 additions & 10 deletions drivers/rust/gpio/lib.rs → drivers/rust/periph/gpio.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
#![no_std]

extern crate cpu;

use cpu::libc::c_int;
use core::option::Option;

use cpu::periph_cpu::gpio_mode;
use cpu::periph_cpu::gpio_t;

use cpu::libc::c_int;
pub use ::ffi::gpio_t;
pub use ::ffi::gpio_mode_t;

/// Struct representing a GPIO pin.
pub struct Pin {
num: gpio_t,
}

extern {
fn gpio_init(pin: gpio_t, mode: gpio_mode) -> c_int;
fn gpio_init(pin: gpio_t, mode: gpio_mode_t) -> c_int;
fn gpio_read(pin: gpio_t) -> c_int;
fn gpio_write(pin: gpio_t, val: c_int);
fn gpio_pin(x: c_int, y: c_int) -> gpio_t;
Expand All @@ -40,7 +35,7 @@ impl Pin {
}

/// Initialize the pin as a general purpose input or output.
pub fn init(&self, mode: gpio_mode) -> Option<()> {
pub fn init(&self, mode: gpio_mode_t) -> Option<()> {
let r = unsafe {
gpio_init(self.num, mode)
};
Expand Down
9 changes: 9 additions & 0 deletions drivers/rust/periph/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#![no_std]
#![allow(bad_style)]
#![allow(dead_code)]
#![feature(untagged_unions)]

extern crate cpu;

mod ffi;
pub mod gpio;
17 changes: 14 additions & 3 deletions examples/rust/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,22 @@ crates to map RIOTs API to Rust are available.

Since building binary packages with `#![no_std]` is currently not
supported by the rust stable channel you need a nightly rust toolchain.

After installing the nightly rust toolchain you should be good to go.
The nightly version is needed because it is currently the only version
supporting builds without the standard library for bin crates.

Besides you need to install
[bindgen](https://github.com/servo/rust-bindgen). Bindgen is needed to
automatically generated Rust code from C header files. To install
bindgen you can simply use cargo:

$ cargo install bindgen

Afterwards verify that bindgen works as expected by running:

$ bindgen --help

If you don't see any error message you should be good to go.

# Upgrading

As explained above we can't use libstd and instead rely on the smaller
Expand All @@ -31,6 +42,6 @@ afterwards.

As always,

# make BOARD=native all term
$ make BOARD=native all term

is all you need.
2 changes: 1 addition & 1 deletion examples/rust/blinky/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ FEATURES_REQUIRED += rust_support
BOARD ?= native

# Depend on the rust/fmt wrapper for the fmt module.
USEMODULE += rust/gpio rust/xtimer
USEMODULE += rust/xtimer rust/periph

include $(RIOTBASE)/Makefile.include
4 changes: 2 additions & 2 deletions examples/rust/blinky/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ mod lang_items {
fn eh_personality() {}
}

extern crate gpio;
extern crate periph;
extern crate xtimer;

use gpio::Pin;
use periph::gpio::Pin;
use xtimer::Duration::Seconds;

#[no_mangle]
Expand Down

0 comments on commit 9fd65eb

Please sign in to comment.