2014-10-02 19 views
21

Ich frage mich, ob es in C++ 11/14 möglich ist, Dateien tatsächlich zur Kompilierzeit zu lesen. Der folgende Code wird beispielsweise nur dann kompiliert, wenn er die Datei erfolgreich lesen kann.Kann eine Datei zur Kompilierzeit gelesen werden?

constexpr std::string shader_source = load("~/foo.glsl"); 

Glauben Sie, dass dies möglich ist?

Ich weiß, dass ich dies mit einem benutzerdefinierten Tool beim Erstellen meiner Anwendung tun konnte.

+6

Es hängt davon ab, was Sie durch * load * entwöhnen. Die einzige Lösung, die ich kenne, ist '# include', und es bedeutet, dass der Inhalt der Datei vom Compiler verstanden werden muss. –

+6

Was Sie wahrscheinlich wollen, ist eine externe Variablendeklaration, die vom Linker an die tatsächlichen Daten angepasst wird. Kombinieren Sie das mit einem Werkzeug, das eine beliebige binäre Ressource in eine Objektdatei mit einem exportierten Symbol Ihrer Wahl einbettet, und Sie sind golden. (Ich könnte ein solches Tool vorschlagen, aber Sie haben nicht erwähnt, welche Toolchain Sie verwenden, und die Tools sind unterschiedlich für ELF vs CV vs PE vs a.out Objektdateiformate) Beachten Sie, dass die Ressource in C/C++ - Code konvertieren Ein mit hexadezimalen Literalen initialisiertes Konstantenarray ist wahrscheinlich sehr sehr langsam. Gehen Sie also direkt zur Objektdatei. –

+0

Ich kann nicht glauben, dass deine 'load' Funktion ein' constexpr' ist. Daher kann der vollständige Ausdruck nicht konsexpr sein. Ich habe keine Ahnung, wie ein externer Dateiinhalt ein conexpr-String sein kann.Die einzige Möglichkeit besteht darin, ein Werkzeug zu verwenden, das die Datei einfach lädt und c/C++ - Code erzeugt. – Klaus

Antwort

16

Aufbauend auf teivaz Idee, frage ich mich, wenn die üblichen "stringize nach der Expansion" Trick funktioniert:

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

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


Aber ich würde für eine herkömmliche extern const char[] Deklaration gehen, die vom Linker zum Inhalt aufgelöst wird. Der Artikel "Embedding a File in an Executable, aka Hello World, Version 5967" hat ein Beispiel:

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

Natürlich sollten Sie die --output und --binary-architecture Befehle ändern Ihre Plattform anzupassen. Der Dateiname aus der Objektdatei endet im Namen des Symbols, so dass Sie ihn wie folgt verwenden können:

#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++); 
} 
+0

Aber wie Interjay darauf hinweist, könnte dies aufgrund von Kommas in der GLSL unterbrochen werden .. –

+0

Ich habe es überprüft .. shader_sourc e enthält '#include" ~/.foo.glsl "' – teivaz

+0

@teivaz: Sogar mit dem zweischichtigen Makroaufruf? –

-1
#define STR(x) #x 

const char* a = 
{ 
#include "foo.glsl" 
}; 

und foo.glsl sollte sein Gehalt in STR ( ... )

upd umschließen. Das wird richtig Komma Griff

#define STRINGIFY(...) #__VA_ARGS__ 
#define STR(...) STRINGIFY(__VA_ARGS__) 
+4

Preprocessor-Deklarationen wie '# include' müssen die ersten nicht-Leerzeichen in der Zeile sein :( –

+0

Aber siehe http://StackOverflow.com/a/5566624/103167. Es ist in Ordnung, eine neue Zeile zwischen den Klammern und dem '# include' zu ​​setzen, solange das Datenformat tolerant gegenüber den zusätzlichen Zeilenumbrüchen in der Zeichenfolge ist (GLSL ist tolerant) –

+0

Hmm, Ihre Bearbeitung hat den Preprozessor-Aufruf repariert, aber abgebrochen stringizing –

0

Ich habe so etwas getan. Sehen Sie, ob dies Ihnen geben wird, was Sie wollen.

Fügen Sie dem Programm eine Befehlszeilenoption hinzu, die das Vorhandensein und die Gültigkeit der Eingabedatei überprüft.
Diese Option sollte das Programm mit einem Fehlercode beenden, wenn die Datei nicht existiert oder nicht gültig ist.

Fügen Sie in Ihrer Make-Datei einen Aufruf an das Programm (mit dieser Befehlszeilenoption) als letzten Build-Schritt hinzu.

Jetzt, wenn Sie das Programm erstellen, erhalten Sie einen Fehler, wenn die richtigen Dateien nicht verfügbar oder nicht gültig sind.

+0

Er möchte externe Programme vermeiden. – Deduplicator

Verwandte Themen