2

I'm aware of many similar questions on this site. I really like the solution mention in the following link:

https://stackoverflow.com/a/25021520/884553

with some modification, you can include text file at compile time, for example:

constexpr const char* s = 
#include "file.txt"

BUT to make this work you have to add string literal prefix and suffix to your original file, for example

R"(
This is the original content,
and I don't want this file to be modified. but i
 don't know how to do it.
)";

My question is: is there a way to make this work but not modifying file.txt?

(I know I can use command line tools to make a copy, prepend and append to the copy, remove the copy after compile. I'm looking for a more elegant solution than this. hopefully no need of other tools)

Here's what I've tried (but not working):

#include <iostream>

int main() {
  constexpr const char* s =
#include "bra.txt"  // R"(
#include "file.txt" //original file without R"( and )";
#include "ket.txt"  // )";
  std::cout << s << "\n";
  return 0;
}

/opt/gcc8/bin/g++ -std=c++1z a.cpp
In file included from a.cpp:5:
bra.txt:1:1: error: unterminated raw string
 R"(
 ^
a.cpp: In function ‘int main()’:
a.cpp:4:27: error: expected primary-expression at end of input
   constexpr const char* s =
                           ^
a.cpp:4:27: error: expected ‘}’ at end of input
a.cpp:3:12: note: to match this ‘{’
 int main() {
            ^
TMS
  • 363
  • 5
  • 17

1 Answers1

7

No, this cannot be done.

There is a proposal to allow inclusion of such resources at compile time called std::embed.

The motivation part of ths p1040r1 proposal:

Motivation

Every C and C++ programmer -- at some point -- attempts to #include large chunks of non-C++ data into their code. Of course, #include expects the format of the data to be source code, and thusly the program fails with spectacular lexer errors. Thusly, many different tools and practices were adapted to handle this, as far back as 1995 with the xxd tool. Many industries need such functionality, including (but hardly limited to):

  • Financial Development

    • representing coefficients and numeric constants for performance-critical algorithms;
  • Game Development

    • assets that do not change at runtime, such as icons, fixed textures and other data

    • Shader and scripting code;

  • Embedded Development

    • storing large chunks of binary, such as firmware, in a well-compressed format

    • placing data in memory on chips and systems that do not have an operating system or file system;

  • Application Development

    • compressed binary blobs representing data

    • non-C++ script code that is not changed at runtime; and

  • Server Development

    • configuration parameters which are known at build-time and are baked in to set limits and give compile-time information to tweak performance under certain loads

SSL/TLS Certificates hard-coded into your executable (requiring a rebuild and potential authorization before deploying new certificates).

In the pursuit of this goal, these tools have proven to have inadequacies and contribute poorly to the C++ development cycle as it continues to scale up for larger and better low-end devices and high-performance machines, bogging developers down with menial build tasks and trying to cover-up disappointing differences between platforms.

MongoDB has been kind enough to share some of their code below. Other companies have had their example code anonymized or simply not included directly out of shame for the things they need to do to support their workflows. The author thanks MongoDB for their courage and their support for std::embed.

The request for some form of #include_string or similar dates back quite a long time, with one of the oldest stack overflow questions asked-and-answered about it dating back nearly 10 years. Predating even that is a plethora of mailing list posts and forum posts asking how to get script code and other things that are not likely to change into the binary.

This paper proposes <embed> to make this process much more efficient, portable, and streamlined. Here’s an example of the ideal:

#include <embed>

int main (int, char*[]) {
  constexpr std::span<const std::byte> fxaa_binary = std::embed( "fxaa.spirv" );
  
  // assert this is a SPIRV file, compile-time  
  static_assert( fxaa_binary[0] == 0x03 && fxaa_binary[1] == 0x02
    && fxaa_binary[2] == 0x23 && fxaa_binary[3] == 0x07
    , "given wrong SPIRV data, check rebuild or check the binaries!" )

  auto context = make_vulkan_context();

  // data kept around and made available for binary
  // to use at runtime
  auto fxaa_shader = make_shader( context, fxaa_binary );

  for (;;) {
    // ...
    // and we’re off!
    // ...
  }

  return 0;
}
Community
  • 1
  • 1
Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524