как запретить другим разработчикам #включать сторонний заголовок в C++

Таким образом, есть сторонняя библиотека с заголовочным файлом, который необходимо включить, чтобы использовать ее. Поскольку реализация библиотеки не является объектно-ориентированной, я написал класс, чтобы инкапсулировать все использование библиотеки, поэтому, если ее нужно заменить, я могу просто изменить реализацию этого класса.

Поскольку другие разработчики будут работать с той же кодовой базой, мне нужен способ выдать им ошибку, если они включат библиотеку. Это делается для того, чтобы избежать ссылок на библиотеку повсюду.

Например, если они делают что-то вроде этого:

#include "cool_library.h"

они получают сообщение об ошибке:

do not include directly cool_library.h, instead use the cool_library_wrapper class

Это возможно? Я использую GNU GCC


person Makako    schedule 12.10.2011    source источник
comment
Я думаю, что более чистым решением было бы добавить проверку в ваш процесс сборки (makefile или что-то еще, что вы используете). Вы можете добавить cppcheck или другие средства проверки работоспособности кода, пока вы это делаете. C-препроцессор не совсем подходит для этой работы.   -  person Patrick    schedule 13.10.2011
comment
grep 'some_header.h' include/ src/ -R должен это сделать. И не забывайте увольнять рецидивистов. Это не проблема, которую нужно решить на уровне исходного кода.   -  person R. Martinho Fernandes    schedule 13.10.2011


Ответы (5)


Вы можете использовать директиву препроцессора #error в блоке #ifndef.

Например, в исходном файле .h есть это:

#ifndef COOL_LIBRARY_WRAPPER_CLASS_INCLUDED
#error "do not include this file directly
#endif

И в заголовочном файле класса-оболочки сделайте следующее:

#define COOL_LIBRARY_WRAPPER_CLASS_INCLUDED
person sashang    schedule 12.10.2011
comment
Я забыл упомянуть, что я не могу модифицировать сторонний код, это бы сработало, если бы я мог, но я не могу. Спасибо - person Makako; 13.10.2011
comment
@Makako: Кажется, тебе нужна магия. Вы хотите, чтобы заголовок вел себя по-другому, не изменяя его. - person MSalters; 13.10.2011

Поскольку вы используете gcc, вы можете использовать функцию #include_next препроцессора: создать заголовок с тем же именем, что и у третьей стороны, в каталоге, который будет иметь более высокий приоритет при поиске файлов заголовков. В вашей версии заголовка используйте что-то вроде

#if WRAPPER_HEADER_HAS_BEEN_INCLUDED
#  include_next <cool_library.h>
#else
#  error ...
#endif
person Idelic    schedule 13.10.2011

Это возможно только в том случае, если вы согласны с изменением файла cool_library.h. Вы можете сделать что-то вроде:

cool_library.h

#ifndef INCLUDED_FROM_COOL_LIBRARY_WRAPPER
#error do not include directly cool_library.h, instead use the cool_library_wrapper class
#endif

.. remainder of original cool_library.h

cool_library_wrapper.h

#define INCLUDED_FROM_COOL_LIBRARY_WRAPPER
#include "cool_library.h"

... your wrapper

#undef INCLUDED_FROM_COOL_LIBRARY_WRAPPER

Конечно, вы по-прежнему не можете запретить своим коллегам определять INCLUDED_FROM_COOL_LIBRARY_WRAPPER самостоятельно и включать исходный заголовочный файл. Это социальная проблема, не имеющая технического решения.

person Greg Hewgill    schedule 12.10.2011
comment
Я не могу изменить cool_library.h, иначе это было бы отлично - person Makako; 13.10.2011

Если вы обычно включаете некоторые заголовки для всего проекта, вы можете проверить наличие защиты включения из стороннего заголовка, например.

// third_party.h
#ifndef THIRD_PARTY_H
#define THIRD_PARTY_H
...

и

// your_project_wide.h
...
#ifdef THIRD_PARTY_H
#warning "Please include "cool_library.h"
#endif
...

Предостережения здесь: #warning - это расширение gcc, и все это зависит от внешних зависимостей, включенных перед заголовками вашего проекта (, которые вы может не захотеть делать).

person Benjamin Bannier    schedule 12.10.2011
comment
поскольку я не могу изменить сторонний заголовок, но он обернут соответствующим #ifndef _X_ #define _X_ #endif, я мог бы сделать что-то подобное, чтобы предупредить других. Однако им необходимо включить файл *.h для всего проекта. Спасибо - person Makako; 13.10.2011

Не помещайте <cool_library.h> в стандартный путь включения сборки. Вы можете либо использовать специальный CFLAGS для своей оболочки, чтобы предоставить ей доступ, либо получить к ней доступ с помощью более явного пути, такого как <vendor/xyz/cool_library.h>, из некоторого пути включения более высокого уровня.

Другой подход, основанный на пути, заключается в том, чтобы поместить локальный <cool_library.h> раньше в путь включения и использовать подход #ifdef/#error, описанный выше. Если присутствует магическое определение, то заголовок-заглушка может использовать более явный путь для получения реального заголовка. (У некоторых компиляторов есть хак для продолжения пути поиска, если вы включаете что-то с точно таким же именем, что и читаемый заголовок)

person Ben Jackson    schedule 12.10.2011