Replaces processmanager with a one-app CAmkES assembly for the entire Kata OS

This also adds a skeleton for the DebugConsole CLI taking IO from a UART
via some Rust wrapper functions, also defined in this change
(kata-uart-client).

Change-Id: I56856c14992010483da58c45f6550c0a4c9987b0
GitOrigin-RevId: e1b2d65ed3a7f627a9f7377caa407151fc943864
This commit is contained in:
Matt Harvey 2021-02-02 14:12:08 -08:00 committed by Sam Leffler
parent 5007f2c48c
commit fd2bebb81f
25 changed files with 785 additions and 26 deletions

View File

@ -1,26 +0,0 @@
cmake_minimum_required(VERSION 3.7.2)
project(ProcessManager C ASM)
set(project_dir "${CMAKE_CURRENT_LIST_DIR}/../../")
file(GLOB project_modules ${project_dir}/projects/*)
list(
APPEND
CMAKE_MODULE_PATH
${project_dir}/kernel
${project_dir}/tools/seL4/cmake-tool/helpers/
${project_dir}/tools/seL4/elfloader-tool/
${project_modules}
)
set(POLLY_DIR ${project_dir}/tools/polly CACHE INTERNAL "")
add_executable(ProcessManager src/main.c)
target_link_libraries(ProcessManager
sel4runtime sel4
muslc utils sel4muslcsys sel4platsupport sel4utils sel4debug)
include(rootserver)
DeclareRootserver(ProcessManager)
include(simulation)
GenerateSimulateScript()

1
CMakeLists.txt Symbolic link
View File

@ -0,0 +1 @@
../camkes/CMakeLists.txt

11
README.md Normal file
View File

@ -0,0 +1,11 @@
# Kata OS
This is a CAmkES project that assembles the entire Kata OS. It exists outside
the seL4 source trees, since it contains code not intended to go to upstream
seL4.
This uses the [standard CAmkES build system](https://docs.sel4.systems/projects/camkes/manual.html#running-a-simple-example)
by symlinking CMakeLists.txt. It also symlinks settings.cmake, and so retains
the notion of "apps," which enables the build system to switch which assembly
it builds using the CAMKES\_APP CMake cache value. Kata OS just has one app,
*system*.

View File

@ -0,0 +1,37 @@
#
# Copyright 2018, Data61
# Commonwealth Scientific and Industrial Research Organisation (CSIRO)
# ABN 41 687 119 230.
#
# This software may be distributed and modified according to the terms of
# the BSD 2-Clause license. Note that NO WARRANTY is provided.
# See "LICENSE_BSD2.txt" for details.
#
# @TAG(DATA61_BSD)
#
cmake_minimum_required(VERSION 3.7.2)
project(system)
include(${CMAKE_CURRENT_LIST_DIR}/rust.cmake)
RustAddLibrary(
kata_debug_console
SOURCE_DIR
${CMAKE_CURRENT_LIST_DIR}/components/DebugConsole
TARGET
"riscv32imc-unknown-none-elf"
LIB_FILENAME
libkata_debug_console.a
)
DeclareCAmkESComponent(DebugConsole
LIBS kata_debug_console
)
DeclareCAmkESComponent(UartDriver
SOURCES components/UartDriver/src/driver.c
)
DeclareCAmkESRootserver(system.camkes)

17
apps/system/README Normal file
View File

@ -0,0 +1,17 @@
<!--
Copyright 2017, Data61
Commonwealth Scientific and Industrial Research Organisation (CSIRO)
ABN 41 687 119 230.
This software may be distributed and modified according to the terms of
the BSD 2-Clause license. Note that NO WARRANTY is provided.
See "LICENSE_BSD2.txt" for details.
@TAG(DATA61_BSD)
-->
#
UART driver for KZM.
This is an example of accessing hardware device memory. The device memory
address may vary.

View File

@ -0,0 +1,49 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "cty"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7313c0d620d0cb4dbd9d019e461a4beb501071ff46ec0ab933efb4daa76d73e3"
[[package]]
name = "kata-debug-console"
version = "0.1.0"
dependencies = [
"kata-shell",
"kata-uart-client",
"panic-halt",
]
[[package]]
name = "kata-io"
version = "0.1.0"
[[package]]
name = "kata-line-reader"
version = "0.1.0"
dependencies = [
"kata-io",
]
[[package]]
name = "kata-shell"
version = "0.1.0"
dependencies = [
"kata-io",
"kata-line-reader",
]
[[package]]
name = "kata-uart-client"
version = "0.1.0"
dependencies = [
"cty",
"kata-io",
]
[[package]]
name = "panic-halt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812"

View File

@ -0,0 +1,9 @@
[workspace]
members = [
"kata-debug-console",
"kata-io",
"kata-line-reader",
"kata-shell",
"kata-uart-client",
]

View File

@ -0,0 +1,6 @@
component DebugConsole {
control;
uses uart_inf uart;
dataport Buf tx_dataport;
dataport Buf rx_dataport;
}

View File

@ -0,0 +1,16 @@
[package]
name = "kata-debug-console"
version = "0.1.0"
authors = ["Matt Harvey <mattharvey@google.com>"]
edition = "2018"
description = "Kata OS DebugConsole"
[dependencies]
panic-halt = "0.2.0"
kata-shell = { path = "../kata-shell" }
kata-uart-client = { path = "../kata-uart-client" }
[lib]
name = "kata_debug_console"
path = "src/run.rs"
crate-type = ["staticlib"]

View File

@ -0,0 +1,27 @@
//! Kata OS command line interface
// This brief bootstrap of Rust-in-Kata prototypes a minimal modular design
// for the DebugConsole CLI use case.
//
// * kata_io Read/Write interface (or move to std::, but that requires alloc)
// * kata_uart_client implementation of the kata_io interface
// * kata_line_reader
// * kata_shell
// * kata_debug_console main entry point fn run()
// std:: requires at least an allocator, which Kata does not have yet. For now
// the CLI will be implemented with only core::.
#![no_std]
extern crate panic_halt;
use kata_shell;
use kata_uart_client;
/// Entry point for DebugConsole. Runs the shell with UART IO.
#[no_mangle]
pub extern "C" fn run() -> ! {
let mut tx = kata_uart_client::Tx {};
let mut rx = kata_uart_client::Rx {};
kata_shell::repl(&mut tx, &mut rx);
}

View File

@ -0,0 +1,5 @@
[package]
name = "kata-io"
version = "0.1.0"
authors = ["Matt Harvey <mattharvey@google.com>"]
edition = "2018"

View File

@ -0,0 +1,35 @@
#![no_std]
pub struct Error;
/// Interface for the CLI to consume bytes.
pub trait Read {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error>;
}
/// Interface for the CLI to emit bytes.
pub trait Write {
fn write(&mut self, buf: &[u8]) -> Result<usize, Error>;
}
/// Adapter for writing core::fmt formatted strings.
impl core::fmt::Write for dyn Write + '_ {
/// Writes the bytes of a &str to the underlying writer.
fn write_str(&mut self, s: &str) -> core::fmt::Result {
match self.write(s.as_bytes()) {
Ok(_) => Ok(()),
Err(_) => Err(core::fmt::Error),
}
}
}
impl dyn Read + '_ {
pub fn get_u8(&mut self) -> Result<u8, Error> {
let mut buf: [u8; 1] = [0u8];
let n_read = self.read(&mut buf)?;
match n_read {
1usize => Ok(buf[0]),
_ => Err(Error),
}
}
}

View File

@ -0,0 +1,8 @@
[package]
name = "kata-line-reader"
version = "0.1.0"
authors = ["Matt Harvey <mattharvey@google.com>"]
edition = "2018"
[dependencies]
kata-io = { path = "../kata-io" }

View File

@ -0,0 +1,78 @@
#![no_std]
use core::fmt;
use kata_io as io;
const LINE_MAX: usize = 128;
pub enum LineReadError {
IO(io::Error),
Overflow,
Encoding(core::str::Utf8Error),
}
impl From<io::Error> for LineReadError {
fn from(err: io::Error) -> LineReadError {
LineReadError::IO(err)
}
}
impl From<core::str::Utf8Error> for LineReadError {
fn from(err: core::str::Utf8Error) -> LineReadError {
LineReadError::Encoding(err)
}
}
impl fmt::Display for LineReadError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
LineReadError::IO(_) => write!(f, "IO error"),
LineReadError::Overflow => write!(f, "line too long"),
LineReadError::Encoding(_) => write!(f, "bad character encoding"),
}
}
}
pub struct LineReader {
// Owned by LineReader to facilitate static allocation.
buf: [u8; LINE_MAX],
}
impl LineReader {
pub fn new() -> LineReader {
LineReader {
buf: [0u8; LINE_MAX],
}
}
pub fn read_line(
&mut self,
output: &mut dyn io::Write,
input: &mut dyn io::Read,
) -> Result<&str, LineReadError> {
const DEL: u8 = 127u8;
const BACKSPACE: u8 = 8u8;
let mut len = 0;
while len < self.buf.len() {
let mut c = input.get_u8()?;
while c == DEL || c == BACKSPACE {
if len > 0 {
output.write(&[BACKSPACE, b' ', BACKSPACE])?;
len -= 1;
}
c = input.get_u8()?;
}
if c == b'\r' || c == b'\n' {
if len > 0 {
output.write(&[b'\n'])?;
}
return Ok(core::str::from_utf8(&self.buf[0..len])?);
}
self.buf[len] = c;
len += 1;
output.write(&[c])?;
}
Err(LineReadError::Overflow)
}
}

View File

@ -0,0 +1,9 @@
[package]
name = "kata-shell"
version = "0.1.0"
authors = ["Matt Harvey <mattharvey@google.com>"]
edition = "2018"
[dependencies]
kata-io = { path = "../kata-io" }
kata-line-reader = { path = "../kata-line-reader" }

View File

@ -0,0 +1,127 @@
#![no_std]
use core::fmt;
use core::fmt::Write;
use kata_io as io;
use kata_line_reader::LineReader;
/// Error type indicating why a command line is not runnable.
enum CommandError {
UnknownCommand,
BadArgs,
Formatter(fmt::Error),
}
impl fmt::Display for CommandError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
CommandError::UnknownCommand => write!(f, "unknown command"),
CommandError::BadArgs => write!(f, "invalid arguments"),
CommandError::Formatter(e) => write!(f, "{}", e),
}
}
}
impl From<core::num::ParseIntError> for CommandError {
fn from(_err: core::num::ParseIntError) -> CommandError {
CommandError::BadArgs
}
}
impl From<core::num::ParseFloatError> for CommandError {
fn from(_err: core::num::ParseFloatError) -> CommandError {
CommandError::BadArgs
}
}
impl From<fmt::Error> for CommandError {
fn from(err: fmt::Error) -> CommandError {
CommandError::Formatter(err)
}
}
/// Read-eval-print loop for the DebugConsole command line interface.
pub fn repl(output: &mut dyn io::Write, input: &mut dyn io::Read) -> ! {
let mut line_reader = LineReader::new();
loop {
// The PROMPT is the Hiragana representation of the word "kata."
const PROMPT: &str = "かた ";
let _ = output.write_str(PROMPT);
match line_reader.read_line(output, input) {
Ok(cmdline) => dispatch_command(cmdline, output),
Err(e) => {
let _ = write!(output, "\n{}\n", e);
}
}
}
}
/// Runs a command line.
///
/// The line is split on whitespace. The first token is the command; the
/// remaining tokens are the arguments.
fn dispatch_command(cmdline: &str, output: &mut dyn io::Write) {
let mut args = cmdline.split_ascii_whitespace();
match args.nth(0) {
Some(command) => {
// Statically binds command names to implementations fns, which are
// defined below.
//
// Since even the binding is static, it is fine for each command
// implementation to use its own preferred signature.
let result = match command {
"echo" => echo_command(cmdline, output),
"add" => add_command(&mut args, output),
"clear" => clear_command(output),
_ => Err(CommandError::UnknownCommand),
};
if let Err(e) = result {
let _ = write!(output, "{}\n", e);
};
}
None => {
let _ = output.write_str("\n");
}
};
}
/// Implements an "echo" command which writes its arguments to output.
fn echo_command(cmdline: &str, output: &mut dyn io::Write) -> Result<(), CommandError> {
const COMMAND_LENGTH: usize = 5; // "echo "
if cmdline.len() < COMMAND_LENGTH {
Ok(())
} else {
Ok(write!(
output,
"{}\n",
&cmdline[COMMAND_LENGTH..cmdline.len()]
)?)
}
}
/// Implements a binary float addition command.
///
/// This is a toy to demonstrate that the CLI can operate on some very basic
/// dynamic input and that the Rust runtime provides floating point arithmetic
/// on integer-only hardware. It is also a prototype example of "command taking
/// arguments." It should be removed once actually useful system control
/// commands are implemented and done cribbing from it.
fn add_command(
args: &mut dyn Iterator<Item = &str>,
output: &mut dyn io::Write,
) -> Result<(), CommandError> {
if let Some(x_str) = args.nth(0) {
if let Some(y_str) = args.nth(0) {
let x = x_str.parse::<f32>()?;
let y = y_str.parse::<f32>()?;
return Ok(write!(output, "{}\n", x + y)?);
}
}
Err(CommandError::BadArgs)
}
/// Implements a command that outputs the ANSI "clear console" sequence.
fn clear_command(output: &mut dyn io::Write) -> Result<(), CommandError> {
Ok(output.write_str("\x1b\x63")?)
}

View File

@ -0,0 +1,9 @@
[package]
name = "kata-uart-client"
version = "0.1.0"
authors = ["Matt Harvey <mattharvey@google.com>"]
edition = "2018"
[dependencies]
cty = "0.2.1"
kata-io = { path = "../kata-io" }

View File

@ -0,0 +1,37 @@
#![no_std]
use kata_io as io;
// C interface to external UART driver.
extern "C" {
static rx_dataport: *mut cty::c_char;
static tx_dataport: *mut cty::c_char;
fn uart_rx(n: cty::size_t);
fn uart_tx(n: cty::size_t);
}
pub struct Rx {}
impl io::Read for Rx {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
unsafe {
uart_rx(buf.len());
let port = core::slice::from_raw_parts(rx_dataport, buf.len());
buf.copy_from_slice(&port);
}
Ok(buf.len())
}
}
pub struct Tx {}
impl io::Write for Tx {
fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
unsafe {
let port = core::slice::from_raw_parts_mut(tx_dataport, buf.len());
port.copy_from_slice(buf);
uart_tx(buf.len());
}
Ok(buf.len())
}
}

View File

@ -0,0 +1,21 @@
/*
* Copyright 2017, Data61
* Commonwealth Scientific and Industrial Research Organisation (CSIRO)
* ABN 41 687 119 230.
*
* This software may be distributed and modified according to the terms of
* the BSD 2-Clause license. Note that NO WARRANTY is provided.
* See "LICENSE_BSD2.txt" for details.
*
* @TAG(DATA61_BSD)
*/
component UartDriver {
dataport Buf mem;
dataport Buf tx_dataport;
dataport Buf rx_dataport;
// consumes Interrupt interrupt;
provides uart_inf uart;
}

View File

@ -0,0 +1,94 @@
// 16550a UART driver
//
// Pared down from the xv6 RISC-V source (MIT license).
// https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/uart.c
#include <camkes.h>
#define UART0 (unsigned int)mem
// the UART control registers are memory-mapped
// at address UART0. this macro returns the
// address of one of the registers.
#define Reg(reg) ((volatile unsigned char *)(UART0 + reg))
// the UART control registers.
// some have different meanings for
// read vs write.
// see http://byterunner.com/16550.html
#define RHR 0 // receive holding register (for input bytes)
#define THR 0 // transmit holding register (for output bytes)
#define IER 1 // interrupt enable register
#define IER_RX_ENABLE (1<<0)
#define IER_TX_ENABLE (1<<1)
#define FCR 2 // FIFO control register
#define FCR_FIFO_ENABLE (1<<0)
#define FCR_FIFO_CLEAR (3<<1) // clear the content of the two FIFOs
#define ISR 2 // interrupt status register
#define LCR 3 // line control register
#define LCR_EIGHT_BITS (3<<0)
#define LCR_BAUD_LATCH (1<<7) // special mode to set baud rate
#define LSR 5 // line status register
#define LSR_RX_READY (1<<0) // input is waiting to be read from RHR
#define LSR_TX_IDLE (1<<5) // THR can accept another character to send
#define ReadReg(reg) (*(Reg(reg)))
#define WriteReg(reg, v) (*(Reg(reg)) = (v))
void uart__init()
{
// disable interrupts (UART from generating, not hart from dispatching)
WriteReg(IER, 0x00);
// special mode to set baud rate.
WriteReg(LCR, LCR_BAUD_LATCH);
// LSB for baud rate of 38.4K.
WriteReg(0, 0x03);
// MSB for baud rate of 38.4K.
WriteReg(1, 0x00);
// leave set-baud mode,
// and set word length to 8 bits, no parity.
WriteReg(LCR, LCR_EIGHT_BITS);
// reset and enable FIFOs.
WriteReg(FCR, FCR_FIFO_ENABLE | FCR_FIFO_CLEAR);
// TODO (mattharvey): seL4 is not configured to dispatch UART interrupts to
// this driver yet. Until that time, this driver spins to wait. The proper
// thing will be to make a Rust embedded_hal implementation for Sparrow.
//
// enable transmit and receive interrupts.
// WriteReg(IER, IER_TX_ENABLE | IER_RX_ENABLE);
}
static int uart_received()
{
return ReadReg(LSR) & LSR_RX_READY;
}
static int is_transmit_empty() {
return ReadReg(LSR) & LSR_TX_IDLE;
}
void uart_rx(size_t n) {
char *c = (char*)rx_dataport;
// TODO(mattharvey): Error return value for n > PAGE_SIZE
for (size_t i = 0; i < n && i < PAGE_SIZE; ++i) {
while (!uart_received());
*c = ReadReg(RHR);
++c;
}
}
void uart_tx(size_t n) {
char *c = (char*)tx_dataport;
// TODO(mattharvey): Error return value for n > PAGE_SIZE
for (size_t i = 0; i < n && i < PAGE_SIZE; ++i) {
while(!is_transmit_empty());
WriteReg(THR, *c);
++c;
}
}

View File

@ -0,0 +1,16 @@
/*
* Copyright 2017, Data61
* Commonwealth Scientific and Industrial Research Organisation (CSIRO)
* ABN 41 687 119 230.
*
* This software may be distributed and modified according to the terms of
* the BSD 2-Clause license. Note that NO WARRANTY is provided.
* See "LICENSE_BSD2.txt" for details.
*
* @TAG(DATA61_BSD)
*/
procedure uart_inf {
void rx(in size_t n);
void tx(in size_t n);
};

53
apps/system/rust.cmake Normal file
View File

@ -0,0 +1,53 @@
#
# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
#
# SPDX-License-Identifier: BSD-2-Clause
#
cmake_minimum_required(VERSION 3.8.2)
include_guard(GLOBAL)
# add_library but for rust libraries. Invokes cargo in the SOURCE_DIR that is provided,
# all build output is placed in BUILD_DIR or CMAKE_CURRENT_BINARY_DIR if BUILD_DIR isn't provided.
# lib_name: Name of library that is created
# SOURCE_DIR: source directory of cargo project
# BUILD_DIR: directory for cargo build output
# TARGET: custom target to use. See in ../rust_targets/ for list of available targets.
# LIB_FILENAME: filename of library created by cargo
# DEPENDS: And target or file dependencies that need to be run before cargo
function(RustAddLibrary lib_name)
cmake_parse_arguments(PARSE_ARGV 1 RUST "" "SOURCE_DIR;BUILD_DIR;TARGET;LIB_FILENAME" "DEPENDS")
if(NOT "${RUST_UNPARSED_ARGUMENTS}" STREQUAL "")
message(FATAL_ERROR "Unknown arguments to RustAddLibrary ${RUST_UNPARSED_ARGUMENTS}")
endif()
if("${RUST_SOURCE_DIR}" STREQUAL "")
message(FATAL_ERROR "SOURCE_DIR must be set for RustAddLibrary")
endif()
if("${RUST_LIB_FILENAME}" STREQUAL "")
message(FATAL_ERROR "LIB_FILENAME must be set for RustAddLibrary")
endif()
if("${RUST_BUILD_DIR}" STREQUAL "")
set(RUST_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR})
endif()
add_custom_target(
${libmain}_custom
BYPRODUCTS
${RUST_BUILD_DIR}/${RUST_LIB_FILENAME}
${USES_TERMINAL_DEBUG}
DEPENDS ${RUST_DEPENDS}
WORKING_DIRECTORY ${RUST_SOURCE_DIR}
COMMAND
${CMAKE_COMMAND} -E env cargo +nightly build
--target riscv32imc-unknown-none-elf
--target-dir ${RUST_BUILD_DIR} -Z unstable-options
--out-dir ${RUST_BUILD_DIR}
)
add_library(${lib_name} STATIC IMPORTED GLOBAL)
set_property(
TARGET ${lib_name}
PROPERTY IMPORTED_LOCATION "${RUST_BUILD_DIR}/${RUST_LIB_FILENAME}"
)
add_dependencies(${lib_name} ${libmain}_custom)
endfunction()

54
apps/system/system.camkes Normal file
View File

@ -0,0 +1,54 @@
/*
* Copyright 2017, Data61
* Commonwealth Scientific and Industrial Research Organisation (CSIRO)
* ABN 41 687 119 230.
*
* This software may be distributed and modified according to the terms of
* the BSD 2-Clause license. Note that NO WARRANTY is provided.
* See "LICENSE_BSD2.txt" for details.
*
* @TAG(DATA61_BSD)
*/
import <std_connector.camkes>;
import "interfaces/uart.idl4";
import "components/UartDriver/UartDriver.camkes";
import "components/DebugConsole/DebugConsole.camkes";
component UART {
hardware;
dataport Buf mem;
// TODO(mattharvey): Make receives wait on interrupt.
// emits Interrupt interrupt;
}
assembly {
composition {
component UART uart;
component UartDriver drv;
component DebugConsole debug_console;
connection seL4HardwareMMIO uart_mem(from drv.mem, to uart.mem);
// TODO(mattharvey): Make receives wait on interrupt.
// connection seL4HardwareInterrupt uart_interrupt(
// from uart.interrupt, to drv.interrupt);
connection seL4RPCCall uart_inf(from debug_console.uart, to drv.uart);
connection seL4SharedData tx_channel(
from debug_console.tx_dataport, to drv.tx_dataport);
connection seL4SharedData rx_channel(
from debug_console.rx_dataport, to drv.rx_dataport);
}
configuration {
uart.mem_paddr = 0x10000000;
uart.mem_size = 0x1000;
// seL4 claims 10 is bigger than irqMax if this is uncommented.
// uart.interrupt_irq_number = 10;
random.ID = 1;
uart.integrity_label = "drv";
}
}

5
easy-settings.cmake Normal file
View File

@ -0,0 +1,5 @@
set(CAMKES_APP "system" CACHE STRING "The one and only CAmkES application in this project")
set(SIMULATION ON CACHE BOOL "Whether to build simulate script")
set(RELEASE OFF CACHE BOOL "Performance optimized build")
set(PLATFORM "spike" CACHE STRING "The one and only seL4 platform for Sparrow")
set(KernelSel4Arch "riscv32" CACHE STRING "Specifies 32-bit branch of the seL4 spike platform")

60
rust.cmake Normal file
View File

@ -0,0 +1,60 @@
# Fork of tools/seL4/cmake-tool/helpers/rust.cmake.
#
# The differences are that a) xargo has been replaced with cargo +nightly, since
# xargo was upstreamed into Rust proper after seL4 created rust.cmake, and b)
# the Rust target is hard-coded to riscv32imc-unknown-none-elf to make this
# file easier to read.
#
# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
#
# SPDX-License-Identifier: BSD-2-Clause
#
cmake_minimum_required(VERSION 3.8.2)
include_guard(GLOBAL)
# add_library but for rust libraries. Invokes cargo in the SOURCE_DIR that is provided,
# all build output is placed in BUILD_DIR or CMAKE_CURRENT_BINARY_DIR if BUILD_DIR isn't provided.
# lib_name: Name of library that is created
# SOURCE_DIR: source directory of cargo project
# BUILD_DIR: directory for cargo build output
# TARGET: custom target to use. See in ../rust_targets/ for list of available targets.
# LIB_FILENAME: filename of library created by cargo
# DEPENDS: And target or file dependencies that need to be run before cargo
function(RustAddLibrary lib_name)
cmake_parse_arguments(PARSE_ARGV 1 RUST "" "SOURCE_DIR;BUILD_DIR;TARGET;LIB_FILENAME" "DEPENDS")
if(NOT "${RUST_UNPARSED_ARGUMENTS}" STREQUAL "")
message(FATAL_ERROR "Unknown arguments to RustAddLibrary ${RUST_UNPARSED_ARGUMENTS}")
endif()
if("${RUST_SOURCE_DIR}" STREQUAL "")
message(FATAL_ERROR "SOURCE_DIR must be set for RustAddLibrary")
endif()
if("${RUST_LIB_FILENAME}" STREQUAL "")
message(FATAL_ERROR "LIB_FILENAME must be set for RustAddLibrary")
endif()
if("${RUST_BUILD_DIR}" STREQUAL "")
set(RUST_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR})
endif()
add_custom_target(
${libmain}_custom
BYPRODUCTS
${RUST_BUILD_DIR}/${RUST_LIB_FILENAME}
${USES_TERMINAL_DEBUG}
DEPENDS ${RUST_DEPENDS}
WORKING_DIRECTORY ${RUST_SOURCE_DIR}
COMMAND
${CMAKE_COMMAND} -E env cargo +nightly build
--target riscv32imc-unknown-none-elf
--target-dir ${RUST_BUILD_DIR} -Z unstable-options
--out-dir ${RUST_BUILD_DIR}
)
add_library(${lib_name} STATIC IMPORTED GLOBAL)
set_property(
TARGET ${lib_name}
PROPERTY IMPORTED_LOCATION "${RUST_BUILD_DIR}/${RUST_LIB_FILENAME}"
)
add_dependencies(${lib_name} ${libmain}_custom)
endfunction()

1
settings.cmake Symbolic link
View File

@ -0,0 +1 @@
../camkes/settings.cmake