1

So I would like to have a file that I can conditionally include as either code or a string. Like this:

#define something
#include "myfile.inc" 

#undef something
const char myfileasastring = 
#include "myfile.inc" 

myfile.inc would be simple code like this:

something // anything extra here is fine as long as it goes away in the code include case
int myfunc() { return 23; } 

Is this possible? I tried having #define something R("mystring and start myfile with it but that does not seem to work.

My specific use case for this is a GLSL shader that, when running under GL I need as a string to pass to the GL driver but when running it in software emulation I want to compile it as CPP code.

I would love to have the same file for both cases. I know many workarounds on the project/make/build level, and even just cut and paste is not terrible, but it would be neat to have a portable compiler level way of doing this.

Not a dupe as detected. I know how to include as one xor the other, but not as either or with the same file. Also I know how to do it using external tools, I am really just wondering if is wondering in just plain, portable c++11. It might not be possible. (try to remove dupe tag again.. please comment if you still think it is a dupe)

10
  • sorry, the dupe is not asking the same question. just including as text works fine with R( as a first line for me. But then I can no longer include it as code! Commented Jan 23, 2015 at 4:34
  • I don't think it can be done because the pre-processor tokenizes the input before processing #include or any other pre-processor directives. There are programs to convert a text file into an appropriate string declaration. Commented Jan 23, 2015 at 4:42
  • Assuming you do get it to work, you're shader code happens to be compatible for both GLSL and C++? Commented Jan 23, 2015 at 4:43
  • Jonathan: Yes, I fear that. I am using outside tools now. But asking in case I missed something. Commented Jan 23, 2015 at 4:45
  • BWG: yes, just needs some structs, #defines, functions, a base class with virtual main. The only thing so far that does not work is non-regular swizzle like .yx. But i just fix the GLSL for that with vec2(a.y,a.x) instead of a.yx.Stuff like .xy works ok through anonymous unions. I also have to manually export names and pointers. For example: RegisterVar ("name", varying, 3, &name). Commented Jan 23, 2015 at 4:51

4 Answers 4

1

Make a file called include.cpp containing this:

int f()
{
  return 42;
}

Then, main.cpp (with inspiration from https://stackoverflow.com/a/25021520/4323):

#include <iostream>
#include "include.cpp"

int main()
{
  const char* const str =
    R"(include(include.cpp))"
  ;
  std::cout << str << '\n';
  return f();
}

What's that include() syntax?? That's m4! So you compile like this:

m4 main.cpp | g++ -x c++ -std=c++11 -

Or if you can't use a pipeline in your compilation command:

g++ -x c++ -std=c++11 <(m4 main.cpp)

If you use the second option, you'll need a -I rule to tell the compiler where to #include "include.cpp" because the source file "exists" in /dev (it's a Bash-ism). You could instead say include(include.cpp) instead of using #include at the top, either way works.

The program prints the code from include.cpp then invokes the function in it.

I do apologize for using m4, but it is available on lots of systems (and you can write your own trivial implementation for others).

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for the answer and it does exactly what I want the result to be but I am really looking for a way to do it without external tools. I am using a project level solution like yours right now! This question was not meant as "how can I achieve this goal?" but "is this possible using only portable cpp?".
@starmole: I'm pretty sure it's not possible using portable C++.
1

I've worked on a project where we did something like this. We wrote a script to compile the code as C++, then linked our main target (our application) against the result. We then also include the code as a resource in the application or library we're building and read it from disk when we want to pass it to OpenGL as glsl. We did this in Xcode by having a target that first compiles the code as C++ into a shared library, and a second target for our application that links against the resulting shared library, and also copies the code into our app bundle as a text file. You can probably do the same with make files or Visual Studio, or whatever tool you're using.

1 Comment

Thanks for the answer! That's quite like what I am doing now. But I was looking for a way to do it in cpp only, without involving extra tools/projects/build steps. Might not be possible after all though.
1

Ah sorry for wasting everybody's time. I figured it out and it is quite easy:

test.inc:

#ifdef ASSTRING
R"foo(
#else
int do () { return 23; }
// )foo";
#endif

main.cpp

#define ASSTRING
const char s[] =
#include "test.inc";

#undef ASSTRING
#include "test.inc"

printf ( "hello\n%s\n%i\n", s+6, me() );

Will both print the code and run it.

2 Comments

On what compiler you've managed to run this code? It looks like a neat solution, but it does not work with g++ 5.3.0. The compiler always parses the code as #ifdef ASSTRING \n R"(something)"; \n #endif.
@HolyBlackCat It only works in VC++, unfortunatelly. See my related question here stackoverflow.com/questions/30997129/…
1

As commented and explained (by the two other answers by John Zwinck and by user1118321), it is impossible without an external tool. It looks you are dreaming of some (yet inexistent) preprocessor directive #include_verbatim such that #include_verbatim "myfile.inc" expands to a long literal string constant containing the contents of myfile.inc.

This does not exist yet. You might perhaps customize a compiler (e.g. using MELT if compiling with a recent GCC...) which for example would process #pragma MAKE_VERBATIM_LITERAL_FROM_FILE_CONTENT(MYCONTENT,myfile.inc) to define the preprocessor symbol MYCONTENT be the literal content of myfile.inc ; but this would need a significant effort and would be compiler specific.

The most pragmatic solution is to accept using some external tool (e.g. a simple make rule to transform myfile.inc into myfile.inc.data such that you could #include "myfile.inc.data" appropriately). This would take a few minutes of your development time (e.g. with m4, awk, hexdump, reswrap from FOX toolkit ...)

If you don't want to depend from some external tool, make it internal to your project by coding an autonomous transform_to_hex_string.cpp program compiled to transform_to_hex_string.bin inside your project and add make rules handling it - i.e. building transform_to_hex_string.bin from transform_to_hex_string.cpp on one side, and running transform_to_hex_string.bin < myfile.inc > myfile.inc.data in another make rule; but it is still external to the compiler!

Customizing a compiler (be it GCC or LLVM) is compiler specific (and probably version-specific) and would take much more efforts (perhaps a week).

You might try to lobby some C++ standardization committee member to have such a language feature included in some future (post C++17) standard.

Remember however that the C++ standard could be read even on hypothetical implementations not even having files or directories (the C++11 compiler is required to process "translation units", not "source files" in the operating system sense, in the standard wording; a compiler handling source code from some database filled by some IDE would be standard compliant - and there have existed such compilers in the previous century, perhaps VisualAge from IBM)

From the latest C++11 draft specification (n3337 §2.1 Separate translation)

The text of the program is kept in units called source files in this International Standard. A source file together with all the headers (17.6.1.2) and source files included (16.2) via the preprocessing directive #include, less any source lines skipped by any of the conditional inclusion (16.1) preprocessing directives, is called a translation unit. [ Note: A C ++ program need not all be translated at the same time. — end note ] [ Note: Previously translated translation units and instantiation units can be preserved individually or in libraries. The separate translation units of a program communicate (3.5) by (for example) calls to functions whose identifiers have external linkage, manipulation of objects whose identifiers have external linkage, or manipulation of data files. Translation units can be separately translated and then later linked to produce an executable program (3.5). — end note ]

Read also the §2.2 Phases of translation of the C++11 standard, notably:

The precedence among the syntax rules of translation is specified by the following phases.

  1. Physical source file characters are mapped, in an implementation-defined manner, to the basic source character set [....]

  2. Each instance of a backslash character () immediately followed by a new-line character is deleted, splicing physical source lines to form logical source lines. [....]

  3. The source file is decomposed into preprocessing tokens (2.5) and sequences of white-space characters (including comments). A source file shall not end in a partial preprocessing token or in a partial com- ment. 12 Each comment is replaced by one space character. New-line characters are retained. Whether each nonempty sequence of white-space characters other than new-line is retained or replaced by one space character is unspecified. The process of dividing a source file’s characters into preprocessing to- kens is context-dependent. [ Example: see the handling of < within a #include preprocessing directive. — end example ]

  4. Preprocessing directives are executed, macro invocations are expanded, and _Pragma unary operator expressions are executed. If a character sequence that matches the syntax of a universal-character-name is produced by token concatenation (16.3.3), the behavior is undefined. A #include preprocessing directive causes the named header or source file to be processed from phase 1 through phase 4, recursively. All preprocessing directives are then deleted.

See also wikipage on Quine (computing)

BTW, generating C++ code from external sources with external tools is very common practice: Yacc (or GNU bison) & Lex (or Flex) & ANTLR & MOC from Qt are very well known examples (and MELT is translated to C++).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.