Why do I get a compilation failure in this elementary program?
use std::thread;
fn main() {
for i in 1..10 {
let _ = thread::scoped( move || {
println!("hello from thread {}", i);
});
}
}
I try to build the program and I get:
src/main.rs:5:17: 5:36 error: unresolved name `thread::scoped`
src/main.rs:5 let _ = thread::scoped( move || {
^~~~~~~~~~~~~~~
Why?
The version of Rust I use:
$ rustc --version
rustc 1.0.0-nightly (170c4399e 2015-01-14 00:41:55 +0000)
The problem indeed was with the version of the rustc.
After upgrade the program was successfully compiled:
Compiling examples v0.0.1 (file:///home/igor/rust/projects/examples)
src/main.rs:1:5: 1:16 warning: unused import, #[warn(unused_imports)] on by default
src/main.rs:1 use std::thread;
^~~~~~~~~~~
The warning disappeared after I removed use:
fn main() {
for i in 1..10 {
let _ = thread::scoped( move || {
println!("hello from thread {}", i);
});
}
}
(Thank you, huon-dbaupp and Dogbert, for your help).
Related
I have a single main.rs file. When I compile it by cargo run, I get an error:
error: linking with `cc` failed: exit status: 1
= note: ld: library not found for -lgtk-3
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I wanted to make a new window with titled "hello world". But when I run the program it gives me this error
I've seen some topic related to this one but none of them helped me to solve the problem.
My code:
extern crate gtk;
use gtk::*;
pub struct Application {
pub window: Window,
pub header: Header,
}
pub struct Header {
pub container: HeaderBar,
}
impl Application {
fn new() -> Application {
let window = Window::new(WindowType::Toplevel);
let header = Header::new();
window.set_titlebar(&header.container);
window.set_title("Простая программа");
window.set_wmclass("simple-gtk", "Простая программа");
Window::set_default_icon_name("имя иконки");
window.connect_delete_event(move |_, _| {
main_quit();
Inhibit(false)
});
Application { window, header }
}
}
impl Header {
fn new() -> Header {
let container = HeaderBar::new();
container.set_title("Простая программа");
container.set_show_close_button(true);
Header { container }
}
}
fn main() {
if gtk::init().is_err() {
eprintln!("Не удалось инициализировать GTK приложение.");
return;
}
let app = Application::new();
app.window.show_all();
gtk::main();
}
My cargo.toml
[package]
name = "hello_world"
version = "0.1.0"
authors = ["Yura Martyr"]
[dependencies]
[dependencies.gtk]
version = "0.3.0"
features = ["v3_22"]
Few weeks ago I started to learn Rust Embedded.
Now I'm stuck, and I would like to ask you for help. So..
I wanted to use TIM3 in my code to change variable (in future peripheral state) and clear (unpend?) interrupt via registers inside ISR.
In C I did something like this inside ISR:
void TIM3_IRQHandler(void)
{
if (TIM3->SR & TIM_SR_UIF)
{
TIM3->SR &= ~(TIM_SR_UIF);
}
}
..and now I'm stuck to do this in Rust.
At first I show what I've done so far.
#![no_std]
#![no_main]
use panic_halt as _;
use cortex_m_rt::entry;
use core::{cell::RefCell};
use core::ops::DerefMut;
use cortex_m::interrupt::{self, Mutex};
use stm32g0::stm32g071::{self, Interrupt, NVIC, TIM3};
static G_TIM: Mutex<RefCell<Option<stm32g071::TIM3>>> =
Mutex::new(RefCell::new(None));
#[entry]
fn main() -> ! {
let p = stm32g071::Peripherals::take().unwrap();
let rcc_r = &p.RCC;
let timer_r = &p.TIM3;
let tim3 = p.TIM3;
unsafe {
NVIC::unmask(Interrupt::TIM3);
};
rcc_r.apbenr1.write(|w| w.tim3en().set_bit());
prepare_timer3(timer_r);
interrupt::free(|cs| {
G_TIM.borrow(cs).replace(Some(tim3))
});
loop {
}
}
fn prepare_timer3(tim3_r_handle: &TIM3) {
tim3_r_handle.cr1.write(|w| w.cen().clear_bit());
tim3_r_handle.psc.write(|w| unsafe { w.psc().bits(16000) });
tim3_r_handle.arr.write(|w| unsafe { w.arr_l().bits(100) });
tim3_r_handle.egr.write(|w| w.ug().set_bit());
tim3_r_handle.dier.write(|w| w.uie().set_bit());
tim3_r_handle.cr1.write(|w| w.cen().set_bit());
}
#[interrupt]
fn TIM3() {
interrupt::free(|cs| {
if let Some(ref mut tim3) = G_TIM.borrow(cs).borrow_mut().deref_mut() {
tim3.sr.write(|w| w.uif().clear_bit());
}
})
}
And I get this compilation error:
error: cannot find attribute `interrupt` in this scope
--> src/main.rs:51:3
|
51 | #[interrupt]
| ^^^^^^^^^
|
= note: consider importing one of these items:
cortex_m_rt::interrupt
crate::stm32g071::interrupt
stm32g0::stm32g071::interrupt
note: `interrupt` is imported here, but it is a module, not an attribute
--> src/main.rs:10:27
|
10 | use cortex_m::interrupt::{self, Mutex};
| ^^^^
error: could not compile `blink-nucleo-g0` due to previous error
I have problem how to resolve those dependency problem.
Could you tell me also that what I did with this Mutex G_TIM is fine?
I mean I did this after read this article: https://docs.rust-embedded.org/book/concurrency/#sharing-peripherals
I also read this https://users.rust-lang.org/t/rust-embedded-stm32f303-timer-interrupt-hanging/40323 but I don't want to use hal crates.
I asked at Rust forum too: https://users.rust-lang.org/t/how-to-clear-interrupt-with-perpiheral-handle/67214
EDIT:
I changed to:
use cortex_m::interrupt::free;
use cortex_m::interrupt::Mutex;
use stm32g0::stm32g071::{self, Interrupt, NVIC, TIM3, interrupt};
and usage of interrupt::free to free.
#[interrupt]
fn TIM2() {
free(|cs| {
if let Some(ref mut tim2) = G_TIM.borrow(cs).borrow_mut().deref_mut() {
tim2.sr.write(|w| w.uif().clear_bit());
}
});
}
I think that my ISR is invkoing in loop. How to clear this interrupt properly?
EDIT:
I changed whole to TIM2.
I cannot reach line tim2.sr.write(|w| w.uif().clear_bit()); with debugger. I think above if let returns false, why?
The macro attribute #[interrupt] is exposed in cortex-m-rt not cortex-m as book chapter Interrupts document:
Similarly to exceptions, the cortex-m-rt crate provides an interrupt attribute to declare interrupt handlers.
I followed instructions in GitHub issue and it worked. I wasn't using Mutex and interrupt::free properly. if let.. in ISR was returning false because interrupt was exectued before replace so... it has value of None in interrupt.
This is my code that works, after fix.
#![no_std]
#![no_main]
use panic_halt as _;
use core::cell::RefCell;
use core::ops::DerefMut;
use cortex_m::interrupt::free;
use cortex_m::interrupt::Mutex;
use cortex_m_rt::entry;
use stm32g0::stm32g071::{self, interrupt, Interrupt, NVIC};
static G_TIM: Mutex<RefCell<Option<stm32g071::TIM2>>> = Mutex::new(RefCell::new(None));
static G_GPIOA: Mutex<RefCell<Option<stm32g071::GPIOA>>> = Mutex::new(RefCell::new(None));
#[entry]
fn main() -> ! {
let p = stm32g071::Peripherals::take().unwrap();
let gpioa = &p.GPIOA;
let rcc_r = &p.RCC;
// enable Clock for GPIOA
rcc_r.iopenr.modify(|_, w| w.iopaen().set_bit());
let tim2 = p.TIM2;
// Nucleo G071RB LED so need to set as output
gpioa.moder.modify(|_, w| unsafe { w.moder5().bits(0b01) });
rcc_r.apbenr1.write(|w| w.tim2en().set_bit());
free(|cs| {
tim2.cr1.write(|w| w.cen().clear_bit());
tim2.psc.write(|w| unsafe { w.psc().bits(16000) });
tim2.arr.write(|w| unsafe { w.arr_l().bits(1000) });
tim2.egr.write(|w| w.ug().set_bit());
tim2.dier.write(|w| w.uie().set_bit());
tim2.cr1.write(|w| w.cen().set_bit());
G_TIM.borrow(cs).replace(Some(tim2));
});
// NVIC unmask interrupt
unsafe {
NVIC::unmask(Interrupt::TIM2);
};
let gpioa = p.GPIOA;
free(|cs| {
G_GPIOA.borrow(cs).replace(Some(gpioa));
});
let mut increment = 0;
loop {
increment += 1;
if increment > 1000 {
increment = 0;
}
}
}
#[interrupt]
fn TIM2() {
free(|cs| {
if let Some(ref mut tim2) = G_TIM.borrow(cs).borrow_mut().deref_mut() {
tim2.sr.write(|w| w.uif().clear_bit());
}
});
free(|cs| {
if let Some(ref mut gpioa) = G_GPIOA.borrow(cs).borrow_mut().deref_mut() {
if gpioa.odr.read().odr5().bit_is_set() {
gpioa.odr.modify(|_, w| w.odr5().clear_bit());
} else {
gpioa.odr.modify(|_, w| w.odr5().set_bit());
}
}
});
}
I'm learning Rust by doing small stuffs. I'm currently writing this app so, its first step is to read a config.json file, but I'm having this compilation error that I'm unable to resolve.
Here's my Cargo.toml dependencies
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
regex = "1.4.3"
Here's the code
use std::error::Error;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use regex::Regex;
use serde_json::Value;
fn _get_config() -> Box<dyn FnMut() -> &Value> {
let mut config = Box::new(Value::Null);
let a = || {
if *config == Value::Null {
match File::open("config.json").and_then(|file| -> Result<Value, std::io::Error> {
serde_json::from_reader(BufReader::new(file)).map_err(|e| e.into())
}) {
Ok(v) => *config = v,
Err(_) => {
*config = serde_json::from_str(
r#"
{
"DOMAIN_AS_ROOT_FOLDER": false,
"secret": "abcxyz"
}
"#,
)
.expect("Cannot initialize config, abort !");
}
}
}
config.as_ref()
};
Box::new(a)
}
fn main() {
let get_config = _get_config();
get_config();
}
And here's the compilation error
❯ cargo run
error[E0106]: missing lifetime specifier
--> src/main.rs:9:40
|
9 | fn _get_config() -> Box<dyn FnMut() -> &Value> {
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
help: consider making the bound lifetime-generic with a new `'a` lifetime
|
9 | fn _get_config() -> Box<dyn for<'a> FnMut() -> &'a Value> {
| ^^^^^^^ ^^^
help: consider using the `'static` lifetime
|
9 | fn _get_config() -> Box<dyn FnMut() -> &'static Value> {
| ^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0106`.
error: could not compile `sieve_generator`
To learn more, run the command again with --verbose.
Basically the _get_config() returns a closure that allows me to get the config object everytime I call it. I don't see why there is such error since the variable config is supposed to live as long as my closure, there's nothing else as parameters here, why does it requires a lifetime here ? And how do I fix it ?
Thank you all very much for your time. I appreciate it a lot.
You'll never be able to do what you want as you can't guarantee to the compiler that the closure will NEVER go out of scope for the applications life time (which you'd have to do in this case because the compiler has no idea how long you'll hold on to the &Value reference).
Instead, since it looks like you're reading the configuration from disk only once why not store it in a static variable with the help of the lazy_static crate.
use std::fs::File;
use std::io::BufReader;
use serde_json::Value;
use lazy_static::lazy_static;
use std::sync::{Arc, Mutex};
lazy_static! {
static ref CONFIG: Arc<Mutex<Value>> = {
let file: std::io::Result<Value> = File::open( "config.json" ).and_then( | f | {
serde_json::from_reader( BufReader::new( f ) )
.map_err( | e | e.into( ) )
} );
Arc::new( Mutex::new( match file {
Ok( v ) => v,
_ => {
serde_json::from_str(
r#"
{
"DOMAIN_AS_ROOT_FOLDER": false,
"secret": "abcxyz"
}
"#
)
.expect( "Cannot initialize config, abort !" )
}
} ) )
};
}
fn main( ) {
let config = CONFIG.lock( ).unwrap( );
// Use your config here.
}
EDIT:
The Arc and Mutex are only necessary if you plan on mutating the Value. If you are not going to mutate the configuration at some point then you can ditch the use the of Arc and Mutex.
In both examples I removed the Option type as it wasn't needed.
lazy_static! {
static ref CONFIG: Value = {
let file: std::io::Result<Value> = File::open( "config.json" ).and_then( | f | {
serde_json::from_reader( BufReader::new( f ) )
.map_err( | e | e.into( ) )
} );
match file {
Ok( v ) => v,
_ => {
serde_json::from_str(
r#"
{
"DOMAIN_AS_ROOT_FOLDER": false,
"secret": "abcxyz"
}
"#
)
.expect( "Cannot initialize config, abort !" )
}
}
};
}
So I'm new to Rust and tinkering with some code to read a config file with nested values and while I seem to have the data, I'm just not sure how to get to the inner values. Am I returning it wrong or is there some simple way to access this struct I'm missing?
This compiles and shows the values properly nested, but I don't seem to be able to reach inside the Ok() wrapper. Even just a page number I should be reading in "The Book" would help.
Cargo.toml
[dependencies]
dirs = "2.0"
config = "0.10"
serde = "1.0"
serde_derive = "1.0"
main.rs
extern crate dirs;
extern crate config;
extern crate serde;
#[macro_use]
extern crate serde_derive;
use config::{ConfigError, Config, File};
#[derive(Debug, Deserialize)]
struct N4_env_conf {
debug: bool,
thingy: String,
blue: String,
}
#[derive(Debug, Deserialize)]
struct N4_conf {
local: N4_env_conf,
dev: N4_env_conf,
prod: N4_env_conf,
}
impl N4_conf {
pub fn new() -> Result<Self, ConfigError> {
let mut s = Config::new();
s.merge(File::with_name("Settings"))?;
s.try_into()
}
}
fn main() {
let config_dir = format!("{}/.config/n4_config", dirs::home_dir().unwrap().display().to_string());
let settings = N4_conf::new();
println!("{:?}", config_dir);
println!("{:#?}", settings);
}
Settings.toml
[local]
debug = true
thingy = "somethingy"
blue = "greenish"
[dev]
debug = true
thingy = "something"
blue = "green"
[prod]
debug = false
thingy = "otherthing"
blue = "red"
The variable settings has the type Result<N4_conf, ConfigError>. That variable may contain a value of type N4_conf or an error of type ConfigError, dependent on the outcome of N4_conf::new().
Example:
match settings {
Ok(conf) => {
println!("local = {:#?}", conf.local);
assert_eq!(conf.local.debug, true);
println!("local.debug = {:?}", conf.local.debug);
println!("local.thingy = {:?}", conf.local.thingy);
println!("local.blue = {:?}", conf.local.blue);
println!("dev = {:#?}", conf.dev);
println!("dev.debug = {:?}", conf.dev.debug);
assert_eq!(conf.dev.debug, true);
println!("dev.thingy = {:?}", conf.dev.thingy);
println!("dev.blue = {:?}", conf.dev.blue);
println!("prod = {:#?}", conf.prod);
assert_eq!(conf.prod.debug, false);
println!("prod.debug = {:?}", conf.prod.debug);
println!("prod.thingy = {:?}", conf.prod.thingy);
println!("prod.blue = {:?}", conf.prod.blue);
}
Err(e) => {
panic!(e);
}
}
See:
https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html
What's the benefit of using a Result?
So thank to #0x64 for trying to help you were definitely closer to the solution than I was when I posted this. My issue was mainly just me trying to follow an example in the source repo for "config" too closely. The solution was to handle the Result inside the constructor method and change the return type to Self. My struct method changed to this and it behaves as I expected:
impl N4_conf {
pub fn new() -> Self {
let mut s = Config::new();
s.merge(File::with_name("Settings")).expect("Problem loading config file");
match s.try_into() {
Ok(conf) => {
conf
}
Err(e) => {
println!("{:?}", e);
panic!(e);
}
}
}
}
When it works, this performs perfectly returning a Struct I can access normally like so:
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/config-playground`
"/home/kill-all-humans/.config/n4_config"
N4_conf {
local: N4_env_conf {
debug: true,
thingy: "somethingy",
blue: "greenish",
},
dev: N4_env_conf {
debug: true,
thingy: "something",
blue: "green",
},
prod: N4_env_conf {
debug: false,
thingy: "otherthing",
blue: "red",
},
}
My next problem is this does not work at all consistently. There appears to be an intermitten bug in processing hierarchical config files in the "config" crate. Such that 50% of the time I get this instead, with zero code changes or rebuilds:
Finished dev [unoptimized + debuginfo] target(s) in 0.02s
Running `target/debug/config-playground`
missing field `local`
thread 'main' panicked at 'Box<Any>', src/main.rs:35:17
stack backtrace:
0: backtrace::backtrace::libunwind::trace...
To which the "missing field" is literally whatever the first field in the N4_conf struct is. I haven't dug into it deeply, but I think I'll skip this crate and just go back to dotenv.
I haven't used the Config module as I switched to toml for my main configuration files. It does support all features from ini files and some more. You might want to have a look. Here is how I use it
This code looks like it would work fine to me, but the rust borrow checker doesn't like it:
extern crate rustbox;
use std::error::Error;
use std::default::Default;
use rustbox::{Color, RustBox};
use rustbox::Key;
use std::fs::File;
use std::env;
use std::io::BufReader;
use std::io::BufRead;
fn display_screenful(rb: &RustBox, fr: BufReader<&'static File>, offset: usize) {
for (rline, idx) in fr.lines().zip(0..).skip(offset).take(rb.height()) {
match rline {
Ok(line) => (*rb).print(0, idx, rustbox::RB_NORMAL, Color::White, Color::Black, &line),
Err(_) => (*rb).print(0, idx, rustbox::RB_NORMAL, Color::White, Color::Black, "")
}
}
}
fn main() {
let rustbox = match RustBox::init(Default::default()) {
Ok(v) => v,
Err(e) => panic!(e),
};
let path = env::args().nth(1).unwrap();
let file = match File::open(&path) {
Ok(file) => file,
Err(e) => panic!(e)
};
let file_reader = BufReader::new(&file);
display_screenful(&rustbox, file_reader, 0);
rustbox.present();
loop {
match rustbox.poll_event(false) {
Ok(rustbox::Event::KeyEvent(key)) => {
match key {
Some(Key::Char('q')) => { break; }
Some(Key::Char(' ')) => {
display_screenful(&rustbox, file_reader, rustbox.height());
rustbox.present();
}
_ => { }
}
},
Err(e) => panic!("{}", e.description()),
_ => { }
}
}
}
I guess I could not use a separate function, and use two for loop parts, instead, but that isn't idiomatic Rust, nor is it good coding practice. In fact, I've tried that, but it just tells me that I'm using a moved value. Here are some errors that I'm getting:
Compiling rusted v0.1.0 (file:///Users/christopherdumas/rusted)
src/main.rs:34:39: 34:43 error: `file` does not live long enough
src/main.rs:34 let file_reader = BufReader::new(&file);
^~~~
note: reference must be valid for the static lifetime...
src/main.rs:33:7: 55:2 note: ...but borrowed value is only valid for the block suffix following statement 2 at 33:6
src/main.rs:33 };
src/main.rs:34 let file_reader = BufReader::new(&file);
src/main.rs:35
src/main.rs:36 display_screenful(&rustbox, file_reader, 0);
src/main.rs:37 rustbox.present();
src/main.rs:38
...
src/main.rs:45:53: 45:64 error: use of moved value: `file_reader` [E0382]
src/main.rs:45 display_screenful(&rustbox, file_reader, rustbox.height());
^~~~~~~~~~~
src/main.rs:45:53: 45:64 help: run `rustc --explain E0382` to see a detailed explanation
src/main.rs:36:33: 36:44 note: `file_reader` moved here because it has type `std::io::buffered::BufReader<&'static std::fs::File>`, which is non-copyable
src/main.rs:36 display_screenful(&rustbox, file_reader, 0);
^~~~~~~~~~~
error: aborting due to 2 previous errors
Could not compile `rusted`.
To learn more, run the command again with --verbose.
Firstly, you shouldn't ask for a BufReader<&'static File>. You can't provide one. Ask instead for a BufReader<&'a File> for some lifetime 'a.
fn display_screenful<'a>(rb: &RustBox, fr: BufReader<&'a File>, offset: usize)
or, for short,
fn display_screenful(rb: &RustBox, fr: BufReader<&File>, offset: usize)
That's not enough either - you then end up moving file_reader into the function. You should borrow instead:
fn display_screenful(rb: &RustBox, fr: &mut BufReader<&File>, offset: usize)
and then it compiles.