Можно ли использовать препроцессор C, чтобы определить, существует ли файл?
У меня очень большая база кода (читайте: тысячи модhive), которая имеет общий код для множества проектов, которые все работают в разных операционных системах с разными компиляторами на C ++. Разумеется, сохранение процесса сборки может быть довольно сложной задачей.
В кодовой базе есть несколько мест, где она могла бы существенно очистить код, если бы существовал способ заставить препроцессор игнорировать некоторые #includes
если файл не существовал в текущей папке. Кто-нибудь знает, как это достичь?
В настоящее время мы используем #ifdef
вокруг #include
в общем файле со вторым файлом, специфичным для проекта, который #defines определяет, существует или нет #include
в проекте. Это работает, но это уродливо. Люди часто забывают правильно обновлять определения при добавлении или удалении файлов из проекта. Я рассматривал возможность написания инструмента предварительной сборки, чтобы обновлять этот файл, но если это будет независимый от платформы способ сделать это с помощью препроцессора, я бы скорее сделал это именно так. Есть идеи?
- Должен ли я использовать #include рядом с ?
- Является ли хорошей идеей обернуть #include в блоке пространства имен?
- Как включить другой XHTML в XHTML с помощью JSF 2.0 Facelets?
- Как установить include path в проект xcode
- Как включить функции из другого файла в свой Perl-скрипт?
- Должен ли я включать или в программы на C ++?
- Когда вы можете опустить расширение файла в директиве #include?
- В чем разница между #include и #include "filename"?
- Как определить, откуда включен заголовочный файл?
- Включить файлы заголовков с помощью командной строки?
- EF Core Второй уровень ThenInclude missworks
- Построить путь для директивы #include с макросом
Как правило, это делается с помощью скрипта, который пытается запустить препроцессор при попытке включить файл. В зависимости от того, препроцессор возвращает ошибку, скрипт обновляет сгенерированный файл .h с соответствующим #define (или #undef). В bash сценарий может выглядеть смутно следующим образом:
cat > .test.h <<'EOM' #include EOM if gcc -E .test.h then echo '#define HAVE_ASDF_H 1' >> config.h else echo '#ifdef HAVE_ASDF_H' >> config.h echo '# undef HAVE_ASDF_H' >> config.h echo '#endif' >> config.h fi
Достаточно тщательная основа для портативной работы с такими проверками переносимости, как это (а также тысячи других), является autoconf .
Маленькое обновление
Некоторые компиляторы могут поддерживать __has_include ( header-name )
.
Расширение было добавлено к стандарту C ++ 17 ( P0061R1 ).
Поддержка компилятора
- лязг
- GCC от 5.X
- Visual Studio от VS2015 Update 2 (?)
Пример (с сайта clang):
// Note the two possible file name string formats. #if __has_include("myinclude.h") && __has_include() # include "myinclude.h" #endif
источники
- SD-6: рекомендации по функциональным испытаниям SG10
- Расширения языка Clang
Создайте специальную папку для отсутствующих заголовков и сделайте поиск этой папки последней
(то есть специфичный для компилятора – последний элемент в переменной среды «INCLUDES», что-то вроде этого)
Тогда, если некоторые header1.h могут отсутствовать, создайте в этой папке заглушку
header1.h:
#define header1_is_missing
Теперь вы всегда можете написать
#include #ifdef header1_is_missing // there is no header1.h #endif
Препроцессор сам по себе не может идентифицировать существование файлов, но вы, конечно, можете использовать среду сборки для этого. Я в основном знаком с make, который позволит вам сделать что-то подобное в вашем make-файле:
ifdef $(test -f filename && echo "present") DEFINE=-DFILENAME_PRESENT endif
Конечно, вам придется найти аналог в других средах сборки, таких как VisualStudio, но я уверен, что они существуют.
У вас может быть шаг заготовки, который создает файл include, содержащий список #defines, который представляет имена файлов, существующих в текущем каталоге:
#define EXISTS_FILE1_C #define EXISTS_FILE1_H #define EXISTS_FILE2_C
Затем EXISTS_*
этот файл из исходного кода, а затем ваш источник может протестировать EXISTS_*
чтобы определить, существует ли файл или нет.
Насколько я знаю, cpp не имеет директивы относительно существования файла.
Возможно, вы сможете выполнить это с небольшой помощью из Makefile, если вы используете один и тот же make на разных платформах. Вы можете обнаружить наличие файла в файле Makefile:
foo.o: foo.c if [ -f header1.h ]; then CFLAGS+=-DHEADER1_INC
Как упоминает @Greg Hewgill, вы можете сделать свой #includes условным:
#ifdef HEADER1_INC #include #endif
Другая возможность: заполнить каталог где-нибудь нулевыми версиями всех заголовков, которые вы хотите включить. Передайте аргумент -I этому каталогу в качестве последнего такого параметра.
GCP cpp ищет свои включенные каталоги в порядке, если он найдет заголовочный файл в более раннем каталоге, который он будет использовать. В противном случае он в конечном итоге найдет файл с нулевой длиной и будет счастлив.
Я предполагаю, что другие реализации cpp также ищут свои каталоги include в указанном порядке.
Я должен был сделать что-то подобное для ОС Symbian. Вот как я это сделал: скажем, вы хотите проверить, существует ли файл «file_strange.h», и вы хотите включить некоторые заголовки или ссылку на некоторые библиотеки в зависимости от существования этого файла.
сначала создайте небольшой пакетный файл для проверки существования этого файла.
autoconf является хорошим, но более убитым для многих небольших проектов.
———- check.bat
@echo off IF EXIST [\epoc32\include\domain\middleware\file_strange] GOTO NEW_API GOTO OLD_API GOTO :EOF :NEW_API echo.#define NEW_API_SUPPORTED>../inc/file_strange_supported.h GOTO :EOF :OLD_API echo.#define OLD_API_SUPPORTED>../inc/file_strange_supported.h GOTO :EOF
———- check.bat заканчивается
то я создал файл gnumake
———-checkmedialist.mk
do_nothing : @rem do_nothing MAKMAKE : check.bat BLD : do_nothing CLEAN : do_nothing LIB : do_nothing CLEANLIB : do_nothing RESOURCE : do_nothing FREEZE : do_nothing SAVESPACE : do_nothing RELEASABLES : do_nothing FINAL : do_nothing
———-check.mk заканчивается
включить файл check.mk в ваш файл bld.inf, он ДОЛЖЕН быть перед вашими файлами MMP
PRJ_MMPFILES gnumakefile checkmedialist.mk
теперь во время компиляции файл file_strange_supported.h
будет иметь соответствующий флаг. вы можете использовать этот флаг в своих файлах cpp или даже в файле mmp, например, в mmp
#include "../inc/file_strange_supported.h" #ifdef NEW_API_SUPPORTED LIBRARY newapi.lib #else LIBRARY oldapi.lib #endif
и в .cpp
#include "../inc/file_strange_supported.h" #ifdef NEW_API_SUPPORTED CStrangeApi* api = Api::NewLC(); #else // .. #endif