Argument must be a string literal... What, why?

String literal, What is this error all about:

use std::process::Command;

fn main() {

    let output = Command::new("pwd")
                     .expect("failed to execute process");
    let out = std::string::String::from_utf8(output.stdout)
                      .expect("Failed to read");
    let a = "/my.payload".to_string();
    let st = format!("{}{}", out.trim(), a);

    let my_str = include_str!(st);
    println!("{}", my_str);

And the error:

error: argument must be a string literal
  --> src/
18 |     let my_str = include_str!(st);
   |                               ^^

I do not understand what is wrong here

include_str! works at compile time, statically inserting the file contents as a string literal in your code, so it can't use a runtime variable. Use a File and read_to_string() to do it at runtime.

Also, starting a process for pwd is rather heavy -- try env::current_dir() instead.


ok, that makes a lot of sense :slight_smile: thnx... But what if i wanna have my file read at compile time ... consider the following situation: I have one app that is generating a simple txt file and then once generated i need to issue a command to compile another tool with the content of that file inside so when executed it prints out the content... any hints on how to do that ?

Sounds like you might be interested in cargo build scripts.


ok ... did not know about that thnx (learning by examples -> this never came up :slight_smile: ) but still it looks like i need to do some sort of regex as pre-processin step to modify and then call to compile is there a simpler way ?

Update: I might be wrong.. and i probably am but i don't see it :slight_smile:

I don't think you should need to modify Most of the time it suffices to have the build script create a .rs file inside env!("OUT_DIR") containing the stuff that can change, and read it using e.g.


include!(concat!(env!("OUT_DIR"), "/"));
1 Like

I sincerely do not wanna waste your time, so if you find the post annoying just ignore it. Thank you anyways.
But i still think i need to pre-modify / given that in that app i need to have my txt file loaded into at compile time ... or am I wrong...

Your should create that, with whatever modifications you want. The build script can read your text file and generate anything from it. The actual compilation of that file will happen via when you include it.

1 Like

would you say this is a correct formulation :slight_smile:


use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::env::current_dir;

fn main() {
    let mut out_dir = current_dir().unwrap();

    let dest_path = out_dir.into_os_string().into_string().unwrap();
    let mut f = File::create(&dest_path).unwrap();

fn main() {

	let my_str = include_str!(\"../my.payload\");
	println!(\"{}\", my_str);  

I mean it does what I want but how badly is it written / done ?

I would formulate it slightly differently. Your build script generates a file inside the $OUT_DIR directory (e.g. $OUT_DIR/my.payload), then your would include that as a string constant with include_str!(concat!(env!("OUT_DIR"), "/my.payload")).

You don't want to edit your itself. For one, it means the generated data will end up in git and add loads of unnecessary changes to the history, but more importantly it means whenever you want to make changes to you'll need to open up and edit a string constant. That could be a pain to maintain.

For example:


use std::path::Path;
use std::fs::File;
use std::io::Result;

fn main() {
  // the compiler tells us which directory to write generated code to
  let out_dir = std::env::var("OUT_DIR").unwrap();
  let payload_file = Path::from(out_dir).join("my.payload");

  // open the file for writing
  let mut f = File::create(&payload_file).unwrap();

  // then write the generated information to it
  writeln!(f, "This is some content").unwrap();
  writeln!(f, "Answer to the Ultimate Question of Life, the Universe, and Everything = {}", 42).unwrap();

And then you can use the generated artefact from your


const MY_PAYLOAD: &'static str = include_str!(concat!(env!("OUT_DIR"), "/my.payload"));

fn main() {
  println!("Payload: {}", MY_PAYLOAD);

Note that the write!() and writeln!() macros are like println!() in that they let you do string formatting, except it'll write to some "writer" (e.g. a file) instead of your console.file).