Skip to content

Commit d52f8b8

Browse files
authored
Merge pull request #27 from hashmismatch/tests_staticlib_examples
Ported tests to compile into static libraries using examples
2 parents 6f7cf41 + d9085d2 commit d52f8b8

31 files changed

+1024
-893
lines changed

.travis.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ dist: trusty
33

44
language: rust
55
rust:
6-
- beta
6+
- nightly
77

88
cache:
99
directories:
@@ -21,8 +21,8 @@ install:
2121
- curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $TRAVIS_RUST_VERSION
2222
- source ~/.cargo/env
2323
- export QEMU_ARCHIVE=$HOME/qemueclipse.tgz
24-
- export QEMU_URL=https://github.com/gnu-mcu-eclipse/qemu/releases/download/v2.8.0-6-20190517/gnu-mcu-eclipse-qemu-2.8.0-6-20190517-1329-centos64.tgz
25-
- export QEMU_DIR=$HOME/gnu-mcu-eclipse/qemu/2.8.0-6-20190517-1329
24+
- export QEMU_URL=https://github.com/gnu-mcu-eclipse/qemu/releases/download/gae-2.7.0-20161128/gnuarmeclipse-qemu-debian64-2.7.0-201611282115-dev.tgz
25+
- export QEMU_DIR=$HOME/qemu/2.7.0-201611282115-dev
2626
- if [ ! -e $QEMU_DIR/bin/qemu-system-gnuarmeclipse ]; then wget $QEMU_URL -O $QEMU_ARCHIVE && tar xzf $QEMU_ARCHIVE -C $HOME ; fi
2727
- export PATH=$PATH:$QEMU_DIR/bin:$HOME/.cargo/bin
2828
- rustup target add thumbv7m-none-eabi

qemu_runner/src/builder.rs

+84-77
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,32 @@ use std::path::Path;
66
use std::process::{Command, Stdio};
77
use std::ffi::OsString;
88

9+
fn is_cargo(path: &str) -> bool {
10+
let output = Command::new(path).arg("-V").output();
11+
if let Ok(output) = Command::new(path).arg("-V").output() {
12+
let s = String::from_utf8_lossy(&output.stdout);
13+
if s.contains("cargo") {
14+
return true;
15+
}
16+
}
17+
18+
false
19+
}
20+
21+
fn find_cargo_path() -> Option<String> {
22+
let mut p: Vec<String> = vec!["cargo".to_string()];
23+
if let Some(home) = env::home_dir() {
24+
p.push(format!("{}/.cargo/bin/cargo", home.display()));
25+
}
26+
27+
for path in p {
28+
if is_cargo(&path) {
29+
return Some(path.into());
30+
}
31+
}
32+
33+
None
34+
}
935

1036
#[derive(Clone, Debug)]
1137
pub struct FoundFile {
@@ -47,104 +73,76 @@ pub struct CrossbuildOptions {
4773
#[derive(Debug)]
4874
pub struct CrossbuiltTests {
4975
pub object_paths: Vec<String>,
50-
pub tests: Vec<String>
76+
pub tests: Vec<String>,
77+
pub library_path: String
5178
}
5279

5380
pub fn crossbuild_rust_tests(options: &CrossbuildOptions) -> CrossbuiltTests {
5481

82+
// check if we can find cargo for cross building
83+
let cargo_path = find_cargo_path();
84+
let cargo_path = cargo_path.expect("Cargo not found! Install Rust's package manager.");
85+
5586
let build_proj_root = {
5687
let p = Path::new(&options.tests_project_path);
5788
let mut absolute_path = ::std::env::current_dir().expect("Can't find current dir?");
5889
absolute_path.push(p);
5990
p.canonicalize().expect("Error canonicalizing")
6091
};
6192

62-
// cross-build the tests library
63-
let cargo_build = Command::new("cargo")
64-
.current_dir(&options.tests_project_path)
65-
.arg("build")
66-
.arg("--verbose")
67-
.arg("--target")
68-
.arg(&options.target_arch)
69-
.env("CARGO_INCREMENTAL", "")
70-
.env("RUSTFLAGS", "--emit=obj")
71-
.env("RUST_TARGET_PATH", &build_proj_root.to_str().expect("Missing path to proj root for target path?"))
72-
.stdout(Stdio::inherit())
73-
.stderr(Stdio::inherit())
74-
.output();
75-
76-
let output = cargo_build.expect("Cargo build of the tests projects failed");
77-
if !output.status.success() {
78-
panic!("cargo build failed");
79-
}
80-
8193
// grab the list of tests to compile binaries for
82-
let tests = {
83-
// slightly hackish way that requires each test entrypoint to be in its
84-
// own source file with a matching name
85-
86-
let dir = format!("{}/src/", &options.tests_project_path);
94+
let tests: Vec<_> = {
95+
let dir = format!("{}/examples/", &options.tests_project_path);
8796
let tests = find_files(&dir, |n| {
8897
n.starts_with("test_") && n.ends_with(".rs")
8998
}).iter().cloned().map(|f| f.name).map(|n| { n.replace(".rs", "") }).collect();
9099

91100
tests
92101
};
93-
94-
let object_paths = {
95-
let active_toolchain: String = {
96-
let output = Command::new("rustup")
97-
.arg("show")
98-
.arg("active-toolchain")
99-
.stderr(Stdio::inherit())
100-
.output()
101-
.expect("Can't get a current toolchain");
102-
103-
let active_toolchain = String::from_utf8_lossy(&output.stdout);
104-
let mut split = active_toolchain.split_whitespace();
105-
split.next().expect("active toolchain missing").trim().to_owned()
106-
};
107-
108-
let rustup_sysroot = {
109-
let home = env::home_dir().expect("missing profile home dir");
110-
format!("{}/.rustup/toolchains/{}/lib/rustlib/{}/lib/",
111-
home.to_str().unwrap(), active_toolchain, &options.target_arch)
112-
};
113-
114-
let mut sysroot_rlibs: Vec<FoundFile> = find_files(&rustup_sysroot, |n| {
115-
n.ends_with(".rlib")
116-
}).iter().cloned().collect();
117-
118-
let tests_deps_dir = format!("{}/target/{}/debug/deps/", &options.tests_project_path, &options.target_arch);
119-
120-
for sysroot_rlib in sysroot_rlibs {
121-
copy(sysroot_rlib.absolute_path, format!("{}/{}.o", tests_deps_dir, sysroot_rlib.name.trim_right_matches(".rlib")));
102+
let mut built_tests = vec![];
103+
104+
for test in &tests {
105+
// cross-build the tests library
106+
let cargo_build = Command::new(&cargo_path)
107+
.current_dir(&options.tests_project_path)
108+
.arg("build")
109+
110+
.arg("--example")
111+
.arg(test)
112+
113+
.arg("--verbose")
114+
115+
.arg("--target")
116+
.arg(&options.target_arch)
117+
118+
//.env("RUSTFLAGS", "-C linker=arm-none-eabi-gcc -Z linker-flavor=gcc")
119+
120+
.env("CARGO_INCREMENTAL", "0")
121+
//.env("RUSTFLAGS", "--emit=obj")
122+
//.env("RUST_TARGET_PATH", &build_proj_root.to_str().expect("Missing path to proj root for target path?"))
123+
124+
.stdout(Stdio::inherit())
125+
.stderr(Stdio::inherit())
126+
.output();
127+
128+
let output = cargo_build.expect("Cargo build of the tests projects failed");
129+
if !output.status.success() {
130+
panic!("Cargo build failed");
122131
}
123132

124-
let mut test_objects: Vec<_> = find_files(&tests_deps_dir, |n| {
125-
n.ends_with(".o")
126-
}).iter().cloned().collect();
127-
128-
test_objects.sort_by_key(|f| {
129-
if f.name.contains("freertos_rs") { 0 }
130-
else if f.name.contains("lazy_static") { 1 }
131-
else if f.name.contains("liballoc") { 2 }
132-
else if f.name.contains("libcompiler_builtins") { 3 }
133-
else if f.name.contains("libcore") { 4 }
134-
else if f.name.contains("librustc_std_workspace_core") { 5 }
135-
else { 6 }
136-
});
137-
138-
let mut test_objects: Vec<_> = test_objects.into_iter().map(|f| f.absolute_path).collect();
133+
built_tests.push(test.clone());
134+
}
139135

140-
let mut objects = vec![];
141-
objects.append(&mut test_objects);
142-
objects
136+
let library_path = {
137+
let p = format!("{}/target/{}/debug/examples/", &options.tests_project_path, &options.target_arch);
138+
let p = Path::new(&p);
139+
p.canonicalize().unwrap().to_str().unwrap().into()
143140
};
144-
141+
145142
CrossbuiltTests {
146-
object_paths: object_paths,
147-
tests: tests
143+
object_paths: vec![],
144+
tests: built_tests,
145+
library_path: library_path
148146
}
149147
}
150148

@@ -168,19 +166,28 @@ pub fn build_test_binaries(options: &CrossbuildOptions, tests: &CrossbuiltTests)
168166
for test in &tests.tests {
169167
let mut test_renames = "".to_string();
170168

169+
/*
171170
if test.contains("isr_timer4") {
172171
test_renames.push_str(&format!("testbed_timer4_isr = {}_timer4_isr;", test));
173172
}
173+
*/
174+
175+
176+
let mut test_deps = vec![
177+
format!("{}/lib{}.a", &tests.library_path, &test)
178+
];
174179

175180
let test_binary_build = Command::new("make")
176181
.current_dir(&gcc_proj_dir)
177-
.env("TEST_ENTRY", test.clone())
182+
.env("TEST_NAME", test.clone())
183+
.env("TEST_LIBRARY_PATH", format!("-L {}", &tests.library_path))
184+
.env("TEST_LIBRARY_PRE", format!("-l:lib{}.a", &test))
178185
.env("TEST_OBJECTS", &test_objects)
186+
.env("TEST_DEPS", test_deps.join(" "))
179187
.env("TEST_RENAMES", test_renames)
180188
.stdout(Stdio::inherit())
181189
.stderr(Stdio::inherit())
182190
.output();
183-
184191
let output = test_binary_build.unwrap();
185192
if !output.status.success() {
186193
panic!(format!("GCC ARM build for '{}' failed", test));

qemu_stm32_tests/Cargo.toml

+41-2
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,50 @@ authors = ["Rudi Benkovic <[email protected]>"]
55

66
[lib]
77
name = "qemu_stm32_tests"
8-
crate-type = ["lib"]
98

109
[dependencies]
1110
freertos_rs = { path = "../" }
1211

1312
[dependencies.lazy_static]
1413
version = "1.3.0"
15-
features = ["spin_no_std"]
14+
features = ["spin_no_std"]
15+
16+
[[example]]
17+
name = "test_basics"
18+
crate-type = ["staticlib"]
19+
20+
[[example]]
21+
name = "test_delay"
22+
crate-type = ["staticlib"]
23+
24+
[[example]]
25+
name = "test_mutex"
26+
crate-type = ["staticlib"]
27+
28+
[[example]]
29+
name = "test_mem_leaks1"
30+
crate-type = ["staticlib"]
31+
32+
[[example]]
33+
name = "test_timers"
34+
crate-type = ["staticlib"]
35+
36+
[[example]]
37+
name = "test_stats"
38+
crate-type = ["staticlib"]
39+
40+
[[example]]
41+
name = "test_processor"
42+
crate-type = ["staticlib"]
43+
44+
[[example]]
45+
name = "test_sample1"
46+
crate-type = ["staticlib"]
47+
48+
[[example]]
49+
name = "test_isr_timer4_notify"
50+
crate-type = ["staticlib"]
51+
52+
[[example]]
53+
name = "test_isr_timer4_queue"
54+
crate-type = ["staticlib"]
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
#[macro_use]
5+
extern crate qemu_stm32_tests;
6+
7+
use qemu_stm32_tests::prelude::v1::*;
8+
9+
freertos_rs_test!(TestBasics);
10+
11+
pub struct TestBasics;
12+
impl Test for TestBasics {
13+
fn run<T: Testbed>(tb: &T) {
14+
let check = shim_sanity_check();
15+
if check.is_err() {
16+
T::debug_print(&format!("Shim sanity check failed: {:?}", check));
17+
T::exit_test(1);
18+
}
19+
20+
T::debug_print("Type sizes are OK!");
21+
22+
T::exit_test(0);
23+
}
24+
}
+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
#[macro_use]
5+
extern crate qemu_stm32_tests;
6+
7+
use qemu_stm32_tests::prelude::v1::*;
8+
9+
freertos_rs_test!(TestDelay);
10+
11+
pub struct TestDelay;
12+
impl Test for TestDelay {
13+
fn run<T: Testbed>(tb: &T) {
14+
let main_task = Task::new().name("main").start(|| {
15+
let start = FreeRtosUtils::get_tick_count();
16+
17+
let counter = Arc::new(Mutex::new(0).unwrap());
18+
19+
{
20+
let counter = counter.clone();
21+
let delay_task = Task::new().name("delay").start(move || {
22+
for _ in 0..10 {
23+
CurrentTask::delay(Duration::ms(100));
24+
25+
// increase the counter and immediately release it
26+
{
27+
let mut counter = counter.lock(Duration::infinite()).unwrap();
28+
*counter += 1;
29+
}
30+
}
31+
}).unwrap();
32+
}
33+
34+
CurrentTask::delay(Duration::ms(550));
35+
36+
{
37+
let counter = counter.lock(Duration::infinite()).unwrap();
38+
assert_eq!(*counter, 5);
39+
}
40+
41+
CurrentTask::delay(Duration::ms(500));
42+
43+
{
44+
let counter = counter.lock(Duration::infinite()).unwrap();
45+
assert_eq!(*counter, 10);
46+
}
47+
48+
// negative test: the counter should never increment
49+
{
50+
let counter = Arc::new(Mutex::new(0).unwrap());
51+
{
52+
let counter = counter.clone();
53+
let task = Task::new().name("delay_long").start(move || {
54+
for _ in 0..10 {
55+
CurrentTask::delay(Duration::ms(1000));
56+
57+
// increase the counter and immediately release it
58+
{
59+
let mut counter = counter.lock(Duration::infinite()).unwrap();
60+
*counter += 1;
61+
}
62+
}
63+
});
64+
}
65+
66+
CurrentTask::delay(Duration::ms(500));
67+
let counter = counter.lock(Duration::infinite()).unwrap();
68+
assert_eq!(*counter, 0);
69+
}
70+
71+
T::exit_test(0);
72+
});
73+
74+
let main_task = main_task.unwrap();
75+
T::start_kernel();
76+
}
77+
}

0 commit comments

Comments
 (0)