如何解决依赖包含顺序问题?
How to solve dependencies inclusion order issues?
我正在尝试重新编译一个有两个依赖项的项目:Qt 和 X11。
X11 在全局命名空间中定义以下符号:
// Xlib.h
#define Bool int
#define Status int
#define True 1
#define False 0
// X.h
#define None 0L
但是,这些符号(可能更多)也用于 Qt(例如枚举)。正如我们在 qcoreevent.h 中看到的那样:
enum Type {
/*
If you get a strange compiler error on the line with None,
it's probably because you're also including X11 headers,
which #define the symbol None. Put the X11 includes after
the Qt includes to solve this problem.
*/
None = 0,
...
Qt提供的解决方案很简单:最后包含X11。但我遇到以下情况时遇到了麻烦:
File1.hpp
#include <SomeQtHeader.h>
#include <SomeX11Header.h> // Ok, X11 is included after Qt
... some classes ...
File2.hpp
#include <SomeOtherQtHeader.h>
#include <SomeX11Header.h> // Ok, X11 is included after Qt
... some classes ...
但是,有些文件是这样的:
File3.hpp
#include "File1.hpp"
#include "File2.hpp"
所以在预处理过程中的某个时刻,我假设它被转换成
// #include "File1.hpp" ->
#include <SomeQtHeader.h>
#include <SomeX11Header.h> // X11 ends up included before Qt
// #include "File2.hpp" ->
#include <SomeOtherQtHeader.h>
#include <SomeX11Header.h>
我想过使用前向声明,但一些结构和 类 没有用作指针,其中很多甚至是类型定义的,所以我最终前向声明了用户使用的原始内部结构不应该使用,总的来说是一团糟。
我应该如何有效地处理这个问题,而不滥用前向声明和指针的使用?
你必须处理邪恶的宏,你可以将 X11 库包装成类似
的东西
// X11wrapper.h
#ifndef X11Wrapper_H
#define X11Wrapper_H
#include <X11/Xlib.h>
#undef None
constexpr auto None = 0L;
#endif
并使用该包装器 header 而不是官方包装器。
按照@Jarod42 的回答,这是我的完整包装器,其中包含我必须取消定义并正确重新定义的所有定义,按照它们在编译器错误日志中出现的顺序排列:
#ifndef WRAPPER_HPP
#define WRAPPER_HPP
#include <X11/Xlib.h>
#undef None
constexpr auto None = 0L;
#undef KeyPress
constexpr auto KeyPress = 2;
#undef KeyRelease
constexpr auto KeyRelease = 2;
#undef FocusIn
constexpr auto FocusIn = 9;
#undef FocusOut
constexpr auto FocusOut = 10;
#undef FontChange
constexpr auto FontChange = 255;
#undef Expose
constexpr auto Expose = 12;
#undef False
constexpr auto False = 0;
#undef True
constexpr auto True = 1;
#undef Status
typedef int Status;
#undef Unsorted
constexpr auto Unsorted = 0;
#undef Bool
typedef int Bool;
#endif // WRAPPER_HPP
我正在尝试重新编译一个有两个依赖项的项目:Qt 和 X11。
X11 在全局命名空间中定义以下符号:
// Xlib.h
#define Bool int
#define Status int
#define True 1
#define False 0
// X.h
#define None 0L
但是,这些符号(可能更多)也用于 Qt(例如枚举)。正如我们在 qcoreevent.h 中看到的那样:
enum Type {
/*
If you get a strange compiler error on the line with None,
it's probably because you're also including X11 headers,
which #define the symbol None. Put the X11 includes after
the Qt includes to solve this problem.
*/
None = 0,
...
Qt提供的解决方案很简单:最后包含X11。但我遇到以下情况时遇到了麻烦:
File1.hpp
#include <SomeQtHeader.h>
#include <SomeX11Header.h> // Ok, X11 is included after Qt
... some classes ...
File2.hpp
#include <SomeOtherQtHeader.h>
#include <SomeX11Header.h> // Ok, X11 is included after Qt
... some classes ...
但是,有些文件是这样的:
File3.hpp
#include "File1.hpp"
#include "File2.hpp"
所以在预处理过程中的某个时刻,我假设它被转换成
// #include "File1.hpp" ->
#include <SomeQtHeader.h>
#include <SomeX11Header.h> // X11 ends up included before Qt
// #include "File2.hpp" ->
#include <SomeOtherQtHeader.h>
#include <SomeX11Header.h>
我想过使用前向声明,但一些结构和 类 没有用作指针,其中很多甚至是类型定义的,所以我最终前向声明了用户使用的原始内部结构不应该使用,总的来说是一团糟。
我应该如何有效地处理这个问题,而不滥用前向声明和指针的使用?
你必须处理邪恶的宏,你可以将 X11 库包装成类似
的东西// X11wrapper.h
#ifndef X11Wrapper_H
#define X11Wrapper_H
#include <X11/Xlib.h>
#undef None
constexpr auto None = 0L;
#endif
并使用该包装器 header 而不是官方包装器。
按照@Jarod42 的回答,这是我的完整包装器,其中包含我必须取消定义并正确重新定义的所有定义,按照它们在编译器错误日志中出现的顺序排列:
#ifndef WRAPPER_HPP
#define WRAPPER_HPP
#include <X11/Xlib.h>
#undef None
constexpr auto None = 0L;
#undef KeyPress
constexpr auto KeyPress = 2;
#undef KeyRelease
constexpr auto KeyRelease = 2;
#undef FocusIn
constexpr auto FocusIn = 9;
#undef FocusOut
constexpr auto FocusOut = 10;
#undef FontChange
constexpr auto FontChange = 255;
#undef Expose
constexpr auto Expose = 12;
#undef False
constexpr auto False = 0;
#undef True
constexpr auto True = 1;
#undef Status
typedef int Status;
#undef Unsorted
constexpr auto Unsorted = 0;
#undef Bool
typedef int Bool;
#endif // WRAPPER_HPP