How to Read a File at Compile Time

Is it possible to read a file at compile time?

Building on teivaz's idea, I wonder if the usual "stringize after expansion" trick will work:

#define STRINGIZE(...) #__VA_ARGS__
#define EXPAND_AND_STRINGIZE(...) STRINGIZE(__VA_ARGS__)

constexpr std::string shader_source = EXPAND_AND_STRINGIZE(
#include "~/.foo.glsl"
);


Still, I would go for a conventional extern const char[] declaration resolved to the content by the linker. The article "Embedding a File in an Executable, aka Hello World, Version 5967" has an example:

# objcopy --input binary \
--output elf32-i386 \
--binary-architecture i386 data.txt data.o

Naturally you should change the --output and --binary-architecture commands to match your platform. The filename from the object file ends up in the symbol name, so you can use it like so:

#include <stdio.h>

/* here "data" comes from the filename data.o */
extern "C" char _binary_data_txt_start;
extern "C" char _binary_data_txt_end;

main()
{
char* p = &_binary_data_txt_start;

while ( p != &_binary_data_txt_end ) putchar(*p++);
}

How to read a file at compile time in C++?

the classic way to do this is to write an awk or perl script that reads the data file and generates a .H file

Read File At Compile Time (constexpr or other)

C++20 might ship with std::embed. Have a look at P1040. If this lands, you can

constexpr std::span<const std::byte> someBytes = std::embed("pathToFile");

Import a text file to std::string at complie time

Google is full of C-ish answers.

Those answers will work in C++ as well. C++ doesn't have features that would make this easier... yet 1.

An overview of options that are available:

  • Copy the content into a compiled object file. This is not portable across language implementations. May be achieved with a tool such as objcopy.
  • Include the file with a linker script. This is not portable across language implementations.
  • Generate a source file (based on the input file) which initialises an array of bytes that have the content. xxd tool (from the vim editor) can be used to do this. This is portable, although there may be implementation specific limits to how large files can be included like this.

It is also worth it to re-consider whether importing text file at compile time is even a good idea for your use case. Often, it is more useful to read the file at runtime because it allows the file to easily be changed without requiring re-compilation.

1 There is a proposal to add such feature to a future standard.

How to read in files with a specific file ending at compile time in nim?

Thanks to enthus1ast from nim's discord server I arrived at an answer: using the collect macro with the walkDir iterator.

The walkDir iterator does not make use of things that are only available at runtime and thus can be safely used at compiletime. With the collect macro you can iterate over all your files in a specific directory and collect their paths into a compile-time seq!

Basically you start writing collect-block, which is a simple for-loop that at its end evaluates to some form of value. The collect macro will put them all into a seq at the end.

The end result looks pretty much like this:

import std/[sequtils, sugar, strutils, strformat, os]
import webgui

const resourceFolder = "/home/philipp/dev/imagestable/html"

proc getFilesWithEnding(folder: string, fileEnding: string): seq[string] {.compileTime.} =
result = collect:
for path in walkDir(folder):
if path.path.endswith(fmt".{fileEnding}"): path.path

proc readFilesWithEnding(folder: string, fileEnding: string): seq[string] {.compileTime.} =
result = getFilesWithEnding(folder, fileEnding).mapIt(staticRead(it))


Related Topics



Leave a reply



Submit