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)

starmole
  • 4,974
  • 1
  • 28
  • 48
  • 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! – starmole Jan 23 '15 at 04: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. – Jonathan Leffler Jan 23 '15 at 04:42
  • Assuming you do get it to work, you're shader code happens to be compatible for both GLSL and C++? – BWG Jan 23 '15 at 04:43
  • Jonathan: Yes, I fear that. I am using outside tools now. But asking in case I missed something. – starmole Jan 23 '15 at 04: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). – starmole Jan 23 '15 at 04:51
  • @starmole Lol, the hoops you jump through. If you want some more hoops, you could `#define xz xz()`, and then in your vector class implement `xz()` as `vec2 xz() const { return vec2(x, z); }`. So you can have non-regular swizzles – BWG Jan 23 '15 at 04:56
  • BWG: yep, tried that! :) Unfortunatelly just xy is too common, and .xy can not be #defined (no . in macros!). And for hoop jumping, it's a lot less work than parsing GLSL and generating code at runtime! A SW fallback is just a hard requirement in my use case and I hate duplicating code. – starmole Jan 23 '15 at 05:04
  • @starmole: Use "@username" notification syntax to create notifications that actually alert users to your replies. Otherwise they can only run into them by chance. Please spend some time reading Stack Overflow's Help Centre and FAQ to learn how it works. Sadly, despite having been a member for almost five years, it seems you have some things to learn still about our model. – Lightness Races in Orbit Jan 23 '15 at 05:15
  • @LightnessRacesinOrbit thanks for the tip! A bit aggressive (almost like a ship!) but useful. – starmole Jan 23 '15 at 05:29
  • I use this: http://stackoverflow.com/a/19591902/1888983 – jozxyqk Jan 24 '15 at 03:08

4 Answers4

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

Community
  • 1
  • 1
John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • 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 Jan 23 '15 at 05:14
  • 2
    @starmole: I'm pretty sure it's not possible using portable C++. – John Zwinck Jan 23 '15 at 05:32
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.

user1118321
  • 25,567
  • 4
  • 55
  • 86
  • 1
    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. – starmole Jan 24 '15 at 05:37
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++).

rici
  • 234,347
  • 28
  • 237
  • 341
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
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.

starmole
  • 4,974
  • 1
  • 28
  • 48
  • 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 May 01 '16 at 18:16
  • @HolyBlackCat It only works in VC++, unfortunatelly. See my related question here http://stackoverflow.com/questions/30997129/in-c11-what-should-happen-first-raw-string-expansion-or-macros – starmole May 05 '16 at 04:30