Is it possible to read a file at compile time? - c++

I am wondering if it is possible in C++11/14 to actually read files at compile time. For example the following code will only compile if it can successfully read the file.
constexpr std::string shader_source = load("~/foo.glsl");
Do you think this could be possible?
I know that I could do this with some custom tool when building my application.

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

#define STR(x) #x
const char* a =
{
#include "foo.glsl"
};
and foo.glsl should enclose its content in
STR(
...
)
upd. This will properly handle commas
#define STRINGIFY(...) #__VA_ARGS__
#define STR(...) STRINGIFY(__VA_ARGS__)

I have done something like this. See if this will give you what you want.
Add a command line option to the program that checks for the existence and validity of the input file.
That option should exit the program with an error code if the file does not exist, or is not valid.
In your make file, add a call to the program (using that command line option), as the final build step.
Now when you build the program, you will get an error if the proper files are not available or not valid.

This is my C solution, but for C++ is the same. Stringify #define does not work with #include in my case with modern compilers, so you can use raw string literals inside your file to embed the content inside a string at compile time.
test.c:
#include <stdio.h>
const char *text = {
#include "test.dat"
};
int main() {
printf("%s\n", text);
}
test.dat:
R"(This is a line.
This is another line...)"

Related

How to convert value #define'd in a macro to a char* (c++)

In a .cpp, I want to output a file to a directory created at compile time (determined by the time of compilation). I have passed this value via -DCOMPILETIME=$(stuff about time) in my makefile. I would like to pass the value stored in COMPILETIME to sprintf so I can create a filepath string to eventually use to place my output file.
I have tried:
#define str(x) #x
sprintf(filepath,"\"%s\file\"",str(COMPILETIME));
as well as
#define str(x) #x
#define strname(name) str(name)
sprintf(filepath,"\"%s\file\"",strname(COMPILETIME));
but I only ever get
"COMPILETIME/file"
as output.
Your macros are fine. Here's a test program:
#include <stdio.h>
#define str(x) #x
#define strname(name) str(name)
int main()
{
printf("\"%s/file\"\n",strname(COMPILETIME));
return 0;
}
Build command:
cc -Wall -o soc soc.c
Output:
"COMPILETIME/file"
Build command:
cc -Wall -o soc soc.c -DCOMPILETIME=abcd
Output:
"abcd/file"
Tested under gcc 4.9.2.
The problem you are facing with fopen could be related to:
sprintf(filepath,"\"%s\file\"",strname(COMPILETIME));
^^^^
Make that
sprintf(filepath,"\"%s\\file\"",strname(COMPILETIME));
^^^^
Otherwise, you are escaping the character f, which does nothing. You should also be able to use a forward slash instead of a backward slash.
sprintf(filepath,"\"%s/file\"",strname(COMPILETIME));
^^^^

what is the result about the recursive Macro spread?

#include <iostream>
#define help(a) #a
#define xhelp(a) help(a)
#define glue(a,b) a##b
#define xglue(a,b) glue(a,b)
#define HIGHLOW "hello"
#define LOWLOW ",world"
int main()
{
std::cout<<xhelp(xglue(HIGH,LOW))<<std::endl;
return 0;
}
here is my test code. I want to know the spread of the MACOR xglue(HIGH,LOW).
For me, i think the result is "hello"
but i learn from one website, the result is "hello, world".
I am really confused with it.
the result of my code is aslo "hello".
Is there anyone could help me with it?
I think the xgule(HIGH,LOW)=glue(HIGH,LOW)=HIGHLOW="hello"
THe website show that xglue(HIGH,LOW)=glue(HIGH,LOW",world")="hello, world"
First of all, there is no recursive macro.
Most work in the example is performed by the two preprocessor operators # and ##.
# is a unary operator that turns its argument into a string literal.
## is a binary operator that pastes two tokens together to form one single token.
The easiest way to check what a given preprocessor code expands to is actually to run the preprocessor. The g++ compiler has a -E option to do exactly that.
# Assuming your file is saved as code.cpp
$ g++ -E code.cpp
... lots of output ...
int main()
{
std::cout<<"\"hello\""<<std::endl;
return 0;
}

Bison and doesn't name a type error

I have the following files:
CP.h
#ifndef CP_H_
#define CP_H_
class CP {
public:
enum Cardinalite {VIDE = '\0', PTINT = '?', AST = '*', PLUS = '+'};
CP(Cardinalite myCard);
virtual ~CP();
private:
Cardinalite card;
};
#endif /* CP_H_ */
And dtd.y
%{
using namespace std;
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include "AnalyseurDTD/DtdDocument.h"
#include "AnalyseurDTD/CP.h"
void yyerror(char *msg);
int yywrap(void);
int yylex(void);
DtdDocument * doc = new DtdDocument();
%}
%union {
char *s;
DtdElement * dtdelt;
CP *cpt;
CP::Cardinalite card;
}
And the following strange error:
AnalyseurDTD/dtd.y:20:2: error: ‘CP’ does not name a type
AnalyseurDTD/dtd.y:21:2: error: ‘CP’ does not name a type
The stange thing is that if I put CP *cpt; after DtdDocument * doc = new DtdDocument(); I have no error :/
Include the header in your scanner file before you include *.tab.h
// scanner.l file
%{
#include "myheader.h"
#include "yacc.tab.h"
// other C/C++ code
%}
// helper definitions
%%
// scanner rules
%%
%union is defined in yacc.tab.h so when you compile you need to make sure the compiler sees your new type definitions before it process yacc.tab.h
Recently I am working with flex and bison. There are several advises that may be helpful for you to locate the problem:
Compile the files one by one to make sure there is no obvious compiling error in your code.
Check the header file generated by bison (something like *.tab.h). Find the definition of YYSTYPE. There is a high probability that it doesn't include your header file AnalyseurDTD/CP.h.
If it's just the case, you should always include AnalyseurDTD/CP.h before you include the *.tab.h. Add it wherever needed to make sure the class CP is defined before YYSTYPE.
If you still cannot locate the problem, try use void *cpt; in the union, then add type conversion in the rest of your code.
Are you sure the error is from Bison? I would venture it comes from your compiler. And probably when it was trying to compile the scanner. I would suggest that your YYSTYPE is not properly defined in your generated header. Try
%code requires { #include "AnalyseurDTD/CP.h" }
so that dtd.h is self-contained. See the documentation about %code.
And please, always provide logs that are complete enough so that we can try to understand your problem. Here, you don't even show the tool you ran, and I hardly think it is Bison.

Programmatically determine via ifdef if a label is defined within a Translation Unit

I have the following bit of code, I expect that given cstdio is included that the first line will be printed, however the second line is printed.
What am I doing wrong? is it possible to know if labels such as printf or strncmp or memcpy have been defined in the current translation unit at compile time?
#include <iostream>
#include <cstdio>
int main()
{
#ifdef printf
std::cout << "printf is defined.\n";
#else
std::cout << "printf NOT defined!\n";
#endif
return 0;
}
Is the reason because the preprocessor is run before variables and labels are introduced into the scope/TU?
In short is the following code bogus? :
http://code.google.com/p/cmockery/source/browse/trunk/src/example/calculator.c#35
#ifdef only applies to preprocessor macros, defined with #define, not to symbols like function names and variables. You can imagine the preprocessor as an actual separate preliminary step, like running your code through a perl script, that occurs before the "real" compiler gets a crack at it.
So there is no programmatic way to check whether symbols like printf are defined in the current scope. If you use one and it's not defined, you'll get a compiler error. The normal thing to do is to #include a header file with the required definition in the source file where you reference it, not to write a source file that will adapt itself to different possible sets of headers.
As a hack, and depending on your environment and specific problem, the header file that does define printf (or whatever function you care about) may also contain some preprocessor #defines that you could check for.
You can use the guards from original include files to determine if they were included and, consequently, functions were declared.
For example, <stdio.h> shipped with my MSVS2010 has _INC_STDIO guards. Thus your code should be like:
int main()
{
#ifdef _INC_STDIO
std::cout << "printf is defined.\n";
#else
std::cout << "printf NOT defined!\n";
#endif
return 0;
}
Note that this solution is environment-dependent, so you should create more complicated rules it you are supposed to support more than one build chain.
Their are a large number of symbols in stdio.h which are #defined, and it is imported by cstdio
So you could use
#include <iostream>
#include <cstdio>
int main()
{
#ifdef stdin
std::cout << "printf is defined.\n";
#else
std::cout << "printf NOT defined!\n";
#endif
return 0;
}
WARNING I've looked at the header but not tested.

Use a #define in printf?

I was wanting to use a constant of some kind for the application ID (so I can use it in printf).
I had this:
#define _APPID_ "Hello World!"
And then the simple printf, calling it into %s (string). It put this out:
simple.cpp:32: error: cannot convert ‘_IO_FILE*’ to ‘const char*’ for argument ‘1’ to ‘int printf(const char*, ...)’
What would I use to define the application ID to use in printf? I tried:
static const char _APPID_[] = "Hello World"`
but it didn't work, same error I think.
I'm not sure I understand exactly what you tried... but this works:
#include <stdio.h>
#define _APPID_ "Hello world"
int main()
{
printf("The app id is " _APPID_ "\n");
/* Output: The app id is Hello world */
return 0;
}
When presented with two constant strings back to back (i.e. "hello " "world"), the compiler treats them as a single concatenated constant string ("hello world").
That means that in the case of trying to printf a compile-time constant string, you don't need to use printf("%s", _APPID_) (although that should still work).
According to the error message, the problem is most likely not caused by the string constant, but by incorrect parameters given to printf().
If you want to print to a file, you should use fprintf(), not printf(). If you want to print to the screen, use printf(), but don't give a file handle as its first parameter.
In source.h
#ifndef _SOURCE_H
#define SOURCE_H
#ifdef APP_ID
#define WHOAMI printf("%s\n", APP_ID);
#endif
#endif
In your program:
#define APP_ID __FILE__
#include "source.h"
int main()
{
WHOAMI
return 0;
}
the reason for this is to have a stadnard include file - source.h. __FILE__ inside a header file returns the name of the header file, so the APP_ID definition is constrained to live in the C file.
If you don't define APP_ID the code won't compile.
_APPID_ is a name that's reserved for the implementation. It matches the pattern ^_[A-Z].*
Rename it to e.g. APP_ID.