Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Including files as raw string literals [duplicate]

I have a C++ source file and a Python source file. I'd like the C++ source file to be able to use the contents of the Python source file as a big string literal. I could do something like this:

char* python_code = "
#include "script.py"
"

But that won't work because there need to be \'s at the end of each line. I could manually copy and paste in the contents of the Python code and surround each line with quotes and a terminating \n, but that's ugly. Even though the python source is going to effectively be compiled into my C++ app, I'd like to keep it in a separate file because it's more organized and works better with editors (emacs isn't smart enough to recognize that a C string literal is python code and switch to python mode while you're inside it).

Please don't suggest I use PyRun_File, that's what I'm trying to avoid in the first place ;)

like image 710
Joseph Garvin Avatar asked Aug 07 '09 18:08

Joseph Garvin


People also ask

Why string literals should not be duplicated?

Duplicated string literals are error-prone to refactor, as one must pay attention to update all occurrences. Constants can be referenced from many places, but there value is updated in a single place.

What is a raw string literal?

Raw String Literal in C++ A Literal is a constant variable whose value does not change during the lifetime of the program. Whereas, a raw string literal is a string in which the escape characters like ' \n, \t, or \” ' of C++ are not processed. Hence, a raw string literal that starts with R”( and ends in )”.

What does \r do in Python string?

In Python strings, the backslash "\" is a special character, also called the "escape" character. It is used in representing certain whitespace characters: "\t" is a tab, "\n" is a newline, and "\r" is a carriage return.


5 Answers

The C/C++ preprocessor acts in units of tokens, and a string literal is a single token. As such, you can't intervene in the middle of a string literal like that.

You could preprocess script.py into something like:

"some code\n"
"some more code that will be appended\n"

and #include that, however. Or you can use xxd​ -i to generate a C static array ready for inclusion.

like image 96
bdonlan Avatar answered Sep 26 '22 02:09

bdonlan


This won't get you all the way there, but it will get you pretty damn close.

Assuming script.py contains this:

print "The current CPU time in seconds is: ", time.clock()

First, wrap it up like this:

STRINGIFY(print "The current CPU time in seconds is: ", time.clock())

Then, just before you include it, do this:

#define STRINGIFY(x) #x

const char * script_py =
#include "script.py"
;

There's probably an even tighter answer than that, but I'm still searching.

like image 39
Michael Bishop Avatar answered Sep 25 '22 02:09

Michael Bishop


The best way to do something like this is to include the file as a resource if your environment/toolset has that capability.

If not (like embedded systems, etc.), you can use a bin2c utility (something like http://stud3.tuwien.ac.at/~e0025274/bin2c/bin2c.c). It'll take a file's binary representation and spit out a C source file that includes an array of bytes initialized to that data. You might need to do some tweaking of the tool or the output file if you want the array to be '\0' terminated.

Incorporate running the bin2c utility into your makefile (or as a pre-build step of whatever you're using to drive your builds). Then just have the file compiled and linked with your application and you have your string (or whatever other image of the file) sitting in a chunk of memory represented by the array.

If you're including a text file as string, one thing you should be aware of is that the line endings might not match what functions expect - this might be another thing you'd want to add to the bin2c utility or you'll want to make sure your code handles whatever line endings are in the file properly. Maybe modify the bin2c utility to have a '-s' switch that indicates you want a text file incorportated as a string so line endings will be normalized and a zero byte will be at the end of the array.

like image 22
Michael Burr Avatar answered Sep 26 '22 02:09

Michael Burr


You're going to have to do some of your own processing on the Python code, to deal with any double-quotes, backslashes, trigraphs, and possibly other things, that appear in it. You can at the same time turn newlines into \n (or backslash-escape them) and add the double-quotes on either end. The result will be a header file generated from the Python source file, which you can then #include. Use your build process to automate this, so that you can still edit the Python source as Python.

like image 44
Steve Jessop Avatar answered Sep 23 '22 02:09

Steve Jessop


You could use Cog as part of your build process (to do the preprocessing and to embed the code). I admit that the result of this is probably not ideal, since then you end up seeing the code in both places. But any time I see the "Python," "C++", and "Preprocessor" in closs proximity, I feel it deserves a mention.

like image 23
Brian Avatar answered Sep 26 '22 02:09

Brian