I have a custom build.rs file, which is supposed to download a c++ libary from github and build it. My build.rs file is seperated into three parts:
cloning the github repository
compiling all the files using the crate cc
linking the required libaries
a) If i comment out the second part, the cloning part works just fine and the linking part fails. (just like expected)
b) If i only comment out the cloning part, while already having cloned the repository from "a)" everything works just fine and the application runs.
c) If i delete the ./target directory and use the whole ./build.rs file without commenting anything out, the build fails while trying to clone the repository, with the following error: fatal: destination path '<path to my directory>\target\debug\build\rust_imgui-9999b756f624420c\out/imgui' already exists and is not an empty directory. Looking at the directory it is complaining about, i can see, that it contains a sub directory "backends". Uncommenting line 8 in ./build.rs doesn't change anything.
So the problem is the following:
Somehow the compiling part of the build script is causing the creation of of the directory .\target\debug\build\rust_imgui-9999b756f624420c\out/imgui/backends prior to its execution.
Edit: The creation of the unwanted directory is caused by the lines '''.file()'''.
If you now any way tho disable this behavior or maby a small workaround please leave a comment :)
./build.rs
use std::{process::Command, fs};
use cc;
fn main() {
let imgui_str = format!("{}{}", std::env::var("OUT_DIR").unwrap(), "/imgui/");
let imgui_path = imgui_str.as_str();
// fs::remove_dir_all("target/debug/build/rust_imgui-9999b756f624420c/out/imgui/backends").expect("deleting error");
//clone Dear ImGui
Command::new("git").args(["clone", "https://github.com/ocornut/imgui.git", "--branch", "docking", imgui_path]).spawn().expect("cloning failed");
Command::new("git").args(["-C", imgui_path, "pull",]).spawn().expect("pulling failed");
//compile Dear ImGui
cc::Build::new()
.cpp(true)
.include(format!("{}{}", imgui_path, ""))
.include(format!("{}{}", imgui_path, "backends"))
.include(format!("{}{}", imgui_path, "examples/libs/glfw/include"))
.file("src/gui/gui_lib.cpp")
.file(format!("{}{}", imgui_path, "imgui.cpp"))
.file(format!("{}{}", imgui_path, "imgui_draw.cpp"))
.file(format!("{}{}", imgui_path, "imgui_tables.cpp"))
.file(format!("{}{}", imgui_path, "imgui_widgets.cpp"))
.file(format!("{}{}", imgui_path, "backends/imgui_impl_opengl3.cpp"))
.file(format!("{}{}", imgui_path, "backends/imgui_impl_glfw.cpp"))
.file(format!("{}{}", imgui_path, "imgui_demo.cpp"))
.compile("gui_lib_cc");
//link everything
println!("cargo:rustc-link-lib=glfw3");
println!("{}", format!("cargo:rustc-link-search={}examples/libs/glfw/lib-vc2010-64", imgui_path));
println!("cargo:rustc-link-lib=gdi32");
println!("cargo:rustc-link-lib=opengl32");
println!("cargo:rustc-link-lib=shell32");
}
rust version: 1.59.0
os: Windows 10
The problem is, that the commands to clone the repository are started but not waited for to finish. Changing the .spawn() to .status() changes that.
Applying that change gets rid of the whole issue.
Related
I am new to rust and cargo, and I am trying to do something very simple!
I have something like this (in build.rs):
use std::process::Command;
fn main() {
Command::new("echo 123");
}
And I want to see the output of the command echo 123. I want 123 to get printed to the build output (this is mostly to debug what I am doing) and wont be part of the final project.
I have tried cargo build --verbose - this does not work.
I can't extrapolate an answer from there posts (and some others like it):
https://github.com/rust-lang/cargo/issues/985
https://github.com/rust-lang/cargo/issues/1106
I feel this must be simple to do - but I have been stuck for hours looking on the web and not finding the answer.
Just building a Command with Command::new does not execute it yet. It just starts a builder pattern. To actually execute it, you have to use the methods spawn, output or status. Example:
Command::new("echo")
.arg("123")
.spawn()
.expect("failed to spawn process");
It's very unfortunate that this doesn't produce a warning. Someone recently tried to add the #[must_use] attribute to Command, which would make your code procude a warning. The PR closed for now but it seems like it will be added eventually.
We can use a macro and it worked form me, but there is a warning, since it uses cargo to display. but that is fine for me.
I found below code from git hub discussion:
Cargo doesn’t display output from a command in build.rs #985
macro_rules! p {
($($tokens: tt)*) => {
println!("cargo:warning={}", format!($($tokens)*))
}
}
fn main() {
p!("BUILD.rs -> Starting ...");
}
When I was reading through the tutorial for Rust here (https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html). I found this block of code:
use std::fs::File;
fn main() {
let f = File::open("hello.txt");
let f = match f {
Ok(file) => file,
Err(error) => panic!("Problem opening the file: {:?}", error),
};
}
It always displays an error: { code: 2, kind: NotFound, message: "The system cannot find the file specified." } even when I make a hello.txt at the root folder of the src, it fails to read it.
In another example here, I use cargo run to no success. The program still fails to read hello.txt file. I'm aware that the example uses rustc open.rs && ./open. Since I don't understand why is it suddenly use different compile method and what's it even mean... I just kinda skip it and try to use cargo run instead
Where do I need to put my file here so cargo run can read it ?
Also if I run the production code and need the program to read an external file, where do I need to put it ?
Here's my folder structure. Pretty simple since I just start to learn RUST.
Thank you in advance.
A file without a directory component in the name needs to be in the current working directory, i.e. the directory from which you start your executable or cargo run.
If you start cargo from an IDE, it might not be immediately apparent what directory it will use as the current directory. In that case, you can always find the current working directory by printing it explicitly:
fn main() {
println!("{}", std::env::current_dir().unwrap().display())
}
I'm having a hard time figuring out where do I need to write something to enable this feature.
I tried adding #![feature(str_split_once)] to the file where I'm using it but nothing happens. By Googling I found How do you enable a Rust "crate feature"? but after adding
[features]
default = ["str_split_once"]
to Cargo it doesn't build with
Caused by: feature default includes str_split_once which is
neither a dependency nor another feature
I tried adding #![feature(str_split_once)] to the file where I'm using it but nothing happens.
I guess there's not really "nothing happens", but there was a warning similar to this one:
warning: crate-level attribute should be in the root module
--> src/lib.rs:2:5
|
2 | #![feature(str_split_once)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
Playground
Just add this line at the beginning of lib.rs and/or main.rs, build with nightly, and it should work:
#![feature(str_split_once)]
fn main() {
// prints Some(("test1", "test2 test3"))
println!("{:?}", "test1 test2 test3".split_once(" "));
}
Playground
use std::{
env, io,
path::PathBuf,
process::{self, Command},
};
fn inner_main() -> io::Result<PathBuf> {
let exe = env::current_exe()?;
let dir = exe.parent().expect("Executable must be in some directory");
let dir = dir.join("nvs");
Ok(dir)
}
fn main() {
let path = inner_main().expect("Couldn't get path.");
let path = path.into_os_string().into_string().unwrap();
Command::new("cd")
.arg(&path)
.status()
.expect("Something went wrong.");
process::exit(0);
}
I grab the path that the binary is in, go into the parent directory so the binaries name is no longer in the path and then append "nvs" at the end of the path and then in main() I put the inner_main() function in a let and then redeclare the let as a string so I can cd into the directory.
Whenever it tries CDing into the nvs directory nothing happens and I know that the command runs because if I move the binary somewhere with no nvs file in it's same directory it runs saying it can't find that directory so my question is when it's in a directory with nvs why doesn't it actually cd into the said directory like it should?
You're attempting to run an external command called cd. Depending on your operating system, this either fails because there is no command called cd, or this does nothing other than test whether the directory exists and you have permission to access it. If a cd command exists, it runs in a subprocess of your program, and its change of directory does not affect your process.
To change to a different directory, you need to change the working directory of your own process. Call std::env::set_current_dir.
std::env::set_current_dir(&path).expect("Unable to change into [path to executable]/nvs");
// do stuff in …/nvs
I'm trying to run go build command for my project but it exits with below error.
alpha#GHOST-RIDER:~/GoWorkspace/src/github.com/hyperledger/firstproject$ go build
# github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/core/operations
../fabric-sdk-go/internal/github.com/hyperledger/fabric/core/operations/system.go:227:23: not enough arguments in call to s.statsd.SendLoop
have (<-chan time.Time, string, string)
want (context.Context, <-chan time.Time, string, string)
Any help would be appreciated.
As per code fabric is using the different version of this library: github.com/go-kit/kit/metrics/statsd. If you follow the System struct's statsd attribute, you can reach the reference on imports.
In master branch of this lib, SendLoop function requires 4 attributes, so that's the root cause. So this causes error when you compile on your local environment.
I had the same issue and worked around it by checking out a tag of library as below:
cd $GOPATH/src/github.com/go-kit/kit
git fetch --tags
git checkout v0.8.0
found a solution on the hyperledger-fabric-go-sdk group chat.
Add context.Background() in s.statsd.SendLoop like below
s.statsd.SendLoop(context.Background(), s.sendTicker.C, network, address)
in fabric-sdk-go/internal/github.com/hyperledger/fabric/core/operations/system.go file at line 227.
I had a same issue, my solution worked and don't need edit fabric source code.
specify github.com/go-kit/kit to v0.8.0, modify go.mod:
replace github.com/go-kit/kit => github.com/go-kit/kit v0.8.0 // you specific version
require (
... ...
// Maybe other version, go mod tidy update automatically, don't care it.
github.com/go-kit/kit v0.9.0 // indirect
... ...
)
then it worked.