C Macro - Динамический #include - PullRequest
9 голосов
/ 03 мая 2011

Я пытаюсь выяснить, как создать переменную строку для оператора #include с помощью GCC.

Идея состоит в том, что для каждого написанного исходного модуля я хочу включить в качестве заголовкадинамически сгенерированный C источник, созданный ранее в процессе сборки.

Создание этого файла не является проблемой.Включая его, к сожалению, это.

То, что у меня пока есть, (identity.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

В идеале это можно использовать так (main.c):

//main.c

# include "identities.h"

int main() {return 0;}

Который будет обработан препроцессором за один проход до компиляции, чтобы получить:

//main.c (preprocessed)

# include "main.c.iden"

int main() {return 0;}

Два уровня косвенности, которые я использую (PASTER и EVALUATOR), являются результатом это сообщение.

К сожалению, это не работает, и я остаюсь с ошибкой:

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

Я думаю, что проблема в том, что в операторе включения отсутствуют кавычки.. Есть идеи?

Ответы [ 5 ]

7 голосов
/ 12 декабря 2013

На самом деле это делается в дереве исходников Linux; См. строка 100 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__)

Я пытаюсь выяснить, как создать переменную строку для оператора #include с помощью GCC.

Этот токен вставляет значение __GNUC__ в строку; "linux / compiler-gcc" __GNUC__ ".h" и затем приводит к строковому результату. Это может быть gcc расширение препроцессора.

Вот пример,

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

Вот два компилятора,

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

Результат любой компиляции дает ожидаемый результат.

Как и в случае с исходным кодом Linux, вы можете отключить предопределенные значения gcc. echo | g++ -dM -E - выдаст список.

В вашем случае вы можете использовать makefile , чтобы передать определение для компиляции, чтобы разрешить динамическое включение сгенерированного заголовка без изменения источника. Но тогда простой альтернативой является просто запустить sed и т. Д. В исходном файле шаблона и заменить его известным именем include.

Любой метод хорош для генерации тестовых приборов и т. Д. Однако для обнаружения функций компилятора это лучший метод. Для программистов, которые используют IDE, это может быть их единственным выбором.

3 голосов
/ 03 мая 2011

Я вполне уверен, что вы не можете делать то, что хотите, __FILE__ возвращает строку, а ## работает с токенами, и отсутствует макрос препроцессора concat для строки CPP.Обычно это достигается благодаря тому факту, что две строки подряд, например

"Hello" " World"

, будут обрабатываться синтаксическим анализатором C ++ как одна строка, однако #include является частью препроцессора и поэтому не может использовать преимуществаэтого факта.

Старый ответ:

Почему вы делаете это

{ #str, str ## .iden }

Я уверен, что это не синтаксис препроцессора, чего вы надеетесь достичь с помощью этого?Вы пытались просто:

str ## .iden

A '{' может объяснить ошибку, которую вы получаете.

1 голос
/ 03 мая 2011

А как насчет BOOST_PP_STRINGIZE из библиотеки Boost Preprocessor . Это сделано специально для добавления кавычек вокруг имени.

0 голосов
/ 03 мая 2011

Пропустив некоторое время весь синтаксис включения, я не понимаю, что пытается сделать ваш код.Вы говорите:

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

Вы даете это main.c и ожидаете "main.c.iden", но это возвращает {"main.c", main.c.iden }.

Вместо этого вы ищете это?

#define PASTER2(str) #str
#define PASTER(str) PASTER2(str ## .iden)
0 голосов
/ 03 мая 2011

Вы не можете использовать препроцессор, как это.Вы должны указать имя файла для директивы #include, это не может быть какой-то другой макрос.

...