53

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 ;)

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Joseph Garvin
  • 20,727
  • 18
  • 94
  • 165
  • 4
    If it's a duplicate can you provide a link? I looked around and didn't see anything with my search terms. – Joseph Garvin Aug 07 '09 at 19:19
  • Also, was the previous version python specific? Because it is a more general question. – Joseph Garvin Aug 07 '09 at 19:20
  • 1
    By the way, embedding a python script is bad form unless it is extremely trivial. People at work do this, and it causes all sorts of problems when we change things in the python environment, but miss updating their code because it's in .cpp file! – Christopher Aug 08 '09 at 00:51
  • It's semi-trivial, they're part of unit tests. – Joseph Garvin Aug 08 '09 at 07:59
  • Funny how the linked-to duplicate question is for C, yet the best answer there is specific to C++11. :-/ – Emile Cormier May 29 '16 at 16:23

7 Answers7

43

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.

bdonlan
  • 224,562
  • 31
  • 268
  • 324
  • 20
    +1 for xxd. The script probably does not really need to be a string literal. – Steve Jessop Aug 07 '09 at 18:41
  • How do you preprocess script.py that way though? I don't see a way to do it with the CPP. Unless you mean with an external tool like sed in that instance too. – Joseph Garvin Aug 07 '09 at 19:24
  • An external tool, yes. You can't do what you want with just CPP. – bdonlan Aug 07 '09 at 19:44
  • 1
    For those with `-Wall -Wextra` turned on using this trick to generate files and assigning the values to a `const char[]`, run the output of `xxd` through `xargs`: `xxd -i some-file.txt | xargs printf "(char)%s"`. It's not pretty but it works. – Qix - MONICA WAS MISTREATED Feb 11 '16 at 19:25
16

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.

Michael Bishop
  • 4,240
  • 3
  • 37
  • 41
  • 1
    you Sir, have a cookie! 2 years of dancing around the issue – Bebe Carabina Jul 22 '16 at 23:53
  • 1
    I had a (surely rare) case where I sometimes needed to include the same file as code, and sometimes as a string (don't ask ;)). So I added in the included file `#ifndef STRINGIFY \n #define STRINGIFY(x) x \n #endif` and when I want to include it as code, I make sure STRINGIFY is not defined. Miraculously it also works for multii-line files! – Marcin Zukowski May 12 '17 at 02:26
  • I think this answer is more helpful that the accepted answer, but it's not quite there yet. It still requires some modification to the file being included. I wonder if someone has found any workarounds? – Shabgard Dec 30 '19 at 08:46
4

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.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
1

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.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
1

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.

Brian
  • 25,523
  • 18
  • 82
  • 173
-1

Here is how automate the conversion with cmd.exe

------ html2h.bat ------

@echo off
echo const char * html_page = "\
sed "/.*/ s/$/ \\n\\/" ../src/page.html | sed s/\"/\\\x22/g 
echo.
echo ";

It was called like

cmd /c "..\Debug\html2h.bat" > "..\debug\src\html.h"

and attached to the code by

#include "../Debug/src/html.h"
printf("%s\n", html_page);

This is quite system-dependent approach but, as most of the people, I disliked the hex dump.

Val
  • 1
  • 8
  • 40
  • 64
-10

Use fopen, getline, and fclose.

Linuxios
  • 34,849
  • 13
  • 91
  • 116
AareP
  • 2,355
  • 3
  • 21
  • 28
  • 3
    That's equivalent to PyRun_File. The idea is to bundle it in to the executable at compile time so I don't have to do that sort of thing. – Joseph Garvin Aug 07 '09 at 20:50
  • 1
    This will get you the run-time content of the file that is on the executing machine, not the compile-time content of the file on the build machine. – not-a-user Apr 15 '14 at 13:38