12

I'm trying to figure out how to build a variable string for the #include statement using GCC.

The idea is that for each source module I have written, I want to include as a header, a dynamically generated C source, that was created earlier in the build process.

Generating this file is not an issue. Including it, unfortunately, is.

What I have so far is (identities.h):

// identities.h

# define PASTER2(str)  #str
# define PASTER(str)   PASTER2(str ## .iden)
# define EVALUATOR(x)  PASTER(x)

# define IDENTITIES_FILE EVALUATOR(__FILE__)
# include IDENTITIES_FILE

Ideally, this would be used like so (main.c):

//main.c

# include "identities.h"

int main() {return 0;}

Which would be expanded in a single pass by the preprocessor before compilation to yield:

//main.c (preprocessed)

# include "main.c.iden"

int main() {return 0;}

The two levels of indirection I'm using (PASTER and EVALUATOR) are a result of this post.

Unfortunately, this is not working and I am left with the error:

obj/win32/dbg/main.o
In file included from main.c:1:0:
identities.h:42:1: error: #include expects "FILENAME" or <FILENAME>

I think the problem is that the include statement is missing quotes.. Any ideas?

Community
  • 1
  • 1
J T
  • 4,946
  • 5
  • 28
  • 38
  • 1
    If you have a, "a dynamically generated C source source," then can you dynamically generate a new header file of all the header files you want to include? Though I'm still curious to see if it's possible to do what you want to do. – leetNightshade May 03 '11 at 18:07
  • 3
    Short answer: you cannot do this, period. – Alexandre C. May 03 '11 at 18:09
  • @leet: No, the problem requires an absolute minimalist approach to modifying the current build system. It has been agreed upon that we will try to do this, by editing each file to include the single generic header "identities.h" - and only that one file. – J T May 03 '11 at 18:09
  • @AlexandreC. Strange, I can do this. I must not exist in your universe ;-). I think you meant you can not do this with **standard** C/C++. – artless noise Dec 12 '13 at 21:29

5 Answers5

9

This was done in the Linux source tree; See line 125 of and older compiler-gcc.h.

#define __gcc_header(x) #x
#define _gcc_header(x) __gcc_header(linux/compiler-gcc##x.h)
#define gcc_header(x) _gcc_header(x)
#include gcc_header(__GNUC__)

I'm trying to figure out how to build a variable string for the #include statement using GCC.

This token pastes the value of __GNUC__ to a string; "linux/compiler-gcc" __GNUC__ ".h" and then stringifies the result. This maybe a gcc pre-processor extension.

Here is an example,

t1.h

#define FOO 10

t2.h

#define FOO 20

a.c

#ifndef VERSION
#define VERSION 1
#endif
#define __gcc_header(x) #x
#define _gcc_header(x) __gcc_header(t ## x.h)
#define gcc_header(x) _gcc_header(x)
#include gcc_header(VERSION)
#include <stdio.h>

int main(void)
{
        printf("FOO is %d\n", FOO);
        return 0;
}

Here are two compiles,

g++ -o a a.cc
g++ -DVERSION=2 -o a a.cc

The output of either compile gives expected result.

As with the Linux source, you can key off of gcc pre-defined values. echo | g++ -dM -E - will give a list.

For your case, you can use the makefile to pass a define to the compile to allow dynamic inclusion of the generated header without altering the source. But then a simple alternative is just to run sed, etc on a template source file and replace it with the known include name.

Either technique is good for generating test fixtures, etc. However, for compiler feature discovery, this is a better method. For programmers who use IDEs, this might be their only choice.

artless noise
  • 21,212
  • 6
  • 68
  • 105
  • 1
    You can not use `__FILE__` of course as others have pointed out. In C++ and more recent C, it is a pointer and not a string literal (as per [arelius](http://stackoverflow.com/users/118960/arelius)). – artless noise Dec 12 '13 at 18:45
  • 1
    i solved this, on MSVC its required to use ` ## x` instead of `##x` . the spaces get removed . – irvnriir Apr 21 '23 at 14:15
  • Another possibility is the [has_include extentions](http://clang.llvm.org/docs/LanguageExtensions.html#include-file-checking-macros) in both new GCC and clang. – artless noise Apr 28 '23 at 18:54
3

I am fairly certain you can't do what you want, __FILE__ returns a string and ## works on tokens and there is no CPP string concat preprocessor macro. Normally this is gotten around due to the fact that two strings in succession e.g.

"Hello" " World"

will be treated as a single string by the C++ parser. However, #include is part of the preprocessor, and thus cannot take advantage of that fact.

Old answer:

Why are you doing this

{ #str, str ## .iden }

I'm certain that's not preprocessor syntax; what do you hope to achieve via that? Have you tried just:

str ## .iden

A '{' could explain the error you are getting.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Arelius
  • 1,216
  • 8
  • 15
  • Unfortunately, I tried the latter approach earlier and got the same error. The approach I am using comes from GCC documentation: http://tigcc.ticalc.org/doc/cpp.html#SEC18 – J T May 03 '11 at 18:21
1

What about BOOST_PP_STRINGIZE from the Boost Preprocessor library . It is specifically made to add quotes around a name.

Niklas R
  • 16,299
  • 28
  • 108
  • 203
Mikael Persson
  • 18,174
  • 6
  • 36
  • 52
  • Unfortunately, all this does is add a pound before the text: "# define BOOST_PP_STRINGIZE_I(text) #text" – J T May 03 '11 at 18:30
  • 4
    BOOST_PP_STRINGIZE does not just add a pound #. The doc specifically says that as opposed to just using #, this macro actually allows its argument to be expanded (and the # does not). After a few tests, it appears that your main problem is that __FILE__ expands to a filename that is between quotes already, and removing them is impossible (at least, that I know of). – Mikael Persson May 03 '11 at 19:53
  • @Mikael: You are correct, I just came to this conclusion myself. – J T May 03 '11 at 21:07
  • I suggest you solve this kind of problem with a build system instead (like cmake for example) or with home-brewed script. That's how Qt generates headers for the .ui files for example. – Mikael Persson May 03 '11 at 21:11
  • 2
    Yea, I've resorted to using GCC and Make: gcc -c -DEVALUTOR_ARGUMENT=$< $ – J T May 03 '11 at 21:23
  • Wow, that's nice and simple! Very nice. – Mikael Persson May 03 '11 at 21:40
1

Skipping the whole inclusion syntax thing for a while, I don't understand what your code is trying to do. You say:

# define PASTER(str)  { #str, str ## .iden }

You give it main.c and expect "main.c.iden", but that returns {"main.c", main.c.iden }.

Are instead you looking for this?

#define PASTER2(str) #str
#define PASTER(str) PASTER2(str ## .iden)
Blindy
  • 65,249
  • 10
  • 91
  • 131
  • You are correct and I have changed it, though unfortunately it yields the same error.. – J T May 03 '11 at 18:24
-1

You cannot use preprocessor like this. You have to supply a filename to the #include directive, it can't be some other macro.

ognian
  • 11,451
  • 4
  • 35
  • 33
  • 1
    This I know is incorrect (search "Computed Includes"): http://tigcc.ticalc.org/doc/cpp.html – J T May 03 '11 at 18:10
  • 1
    @JT That's a "feature" of the GCC preprocessor - it's not part of the C or C++ standards for preprocessing. –  May 03 '11 at 18:16
  • @JT, Actually he's plenty correct, the computed includes are a GCC extension and you didn't tag your question as GCC-only. – Blindy May 03 '11 at 18:16
  • 2
    Apologies for not tagging, though I did state in the question that I was using GCC. – J T May 03 '11 at 18:19
  • If you want to rely on the GNU extension, you should remove the scope brackets from your macro. However try to stay portable, it pays back – ognian May 03 '11 at 18:22
  • 5
    Actually "Computed Includes" (or some form thereof) are allowed by the C Standard --- the C99 Standard. See 6.10.2/4 ... `"# include pp-tokens newline"` where pp-tokens must expand to one of `
    ` or `"header-file"`
    – pmg May 03 '11 at 19:07