根据 Qt 版本动态使用 QGLWidget 或 QOpenGLWidget
Dynamically use QGLWidget or QOpenGLWidget depending on Qt version
我的代码应该在 Qt 5.4 之前和之后的平台上编译和 运行,Qt 5.4 引入了 QOpenGLWidget,取代了 QGLWidget。我以为我可以编写这样的代码来支持两者:
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
# define USE_Q_OPEN_GL_WIDGET
#endif
#ifdef USE_Q_OPEN_GL_WIDGET
# include <QOpenGLWidget>
#else
# include <QGLWidget>
#endif
class GLWidget :
#ifdef USE_Q_OPEN_GL_WIDGET
public QOpenGLWidget
#else
public QGLWidget
#endif
{
Q_OBJECT
public:
[...]
但这不会成功,因为 moc
似乎不理解预处理器指令,并且会为错误的 class.
生成代码
我试图通过向我的 CMakeLists.txt
添加一个 add_custom_command
指令来解决这个问题,这将在将文件传递给 moc 之前对文件进行 运行 ${CMAKE_CXX_COMPILER}" -E -P -x c++-header ...
。但这似乎也不起作用,因为预处理器将删除神奇的 Q_OBJECT
行,表明确实 moc
必须是 运行 before C 预处理器是 运行.
我还有哪些其他选择?
我必须求助于两个几乎相同的头文件(两行除外),然后在构建时在 cmake 中选择正确的头文件吗?
编辑
要测试此问题,请尝试以下操作:
- 在带有 qt 5.2.1 的 Ubuntu 可信系统上(您可以使用
sudo debootstrap trusty ubuntu-trusty
创建一个 chroot)做:
- apt-get install libqt5opengl5-dev build-essential qttools5-dev qt5-default
然后创建 glwidget.h
包含:
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <QtGlobal>
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
# define USE_Q_OPEN_GL_WIDGET
#endif
#ifdef USE_Q_OPEN_GL_WIDGET
# include <QOpenGLWidget>
#else
# include <QGLWidget>
#endif
class GLWidget :
#ifdef USE_Q_OPEN_GL_WIDGET
public QOpenGLWidget
#else
public QGLWidget
#endif
{
Q_OBJECT
};
#endif
然后 运行:
$ moc -v
moc 5.2.1
$ moc glwidget.h | grep QGL || echo "not found"
not found
$ moc glwidget.h | grep QOpenGL >/dev/null && echo "found!"
found!
所以你看到即使 qt 5.2.1 没有 QOpenGL,moc 也是这样解释预处理器指令的
我们可以把版本检查改得更简单
#if QT_VERSION >= 0x050400
如果我们再次尝试进行该检查,那么 Ubuntu trusty 中的 qt 5.2.1 中的 moc 会生成正确的结果
所以我们认为我们找到了解决方案并尝试 运行ning moc 从更新的 qt 发行版中使用相同的代码。这次我在 Debian unstable 中使用来自 qt 5.5.1 的 moc,我得到:
$ moc -v
moc 5.5.1
$ moc glwidget.h | grep QOpen || echo "not found"
not found
$ moc foo.h | grep QGL > /dev/null && echo "found"
found
最有趣的是,如果在 qt 5.5.1 下,我将版本检查宏 mack 转为 using
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
那就有用了!
所以总而言之,moc 确实理解一些预处理器指令,但它理解的指令在 qt 5.4 之前和之后的版本之间是不同的。似乎不存在两者都能理解的通用预处理器指令。因此,我看不到使用预处理器指令解决此问题的方法。
您可以使用 CMake 生成这个 header。将此代码放入其中:
#include <@GL_CLASS@>
class GLWidget : @GL_CLASS@
{
Q_OBJECT
public:
[...]
然后在 CMakeLists.txt 中执行此操作:
set(GL_CLASS <depending on Qt version>)
include_directories(${CMAKE_CURRENT_BINARY_DIR}) #this is because configure_file produces its output in the build dir
configure_file(yourheader.h output.h @ONLY)
最后,在您的代码中使用 #include "output.h"
。
我的代码应该在 Qt 5.4 之前和之后的平台上编译和 运行,Qt 5.4 引入了 QOpenGLWidget,取代了 QGLWidget。我以为我可以编写这样的代码来支持两者:
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
# define USE_Q_OPEN_GL_WIDGET
#endif
#ifdef USE_Q_OPEN_GL_WIDGET
# include <QOpenGLWidget>
#else
# include <QGLWidget>
#endif
class GLWidget :
#ifdef USE_Q_OPEN_GL_WIDGET
public QOpenGLWidget
#else
public QGLWidget
#endif
{
Q_OBJECT
public:
[...]
但这不会成功,因为 moc
似乎不理解预处理器指令,并且会为错误的 class.
我试图通过向我的 CMakeLists.txt
添加一个 add_custom_command
指令来解决这个问题,这将在将文件传递给 moc 之前对文件进行 运行 ${CMAKE_CXX_COMPILER}" -E -P -x c++-header ...
。但这似乎也不起作用,因为预处理器将删除神奇的 Q_OBJECT
行,表明确实 moc
必须是 运行 before C 预处理器是 运行.
我还有哪些其他选择?
我必须求助于两个几乎相同的头文件(两行除外),然后在构建时在 cmake 中选择正确的头文件吗?
编辑
要测试此问题,请尝试以下操作:
- 在带有 qt 5.2.1 的 Ubuntu 可信系统上(您可以使用
sudo debootstrap trusty ubuntu-trusty
创建一个 chroot)做: - apt-get install libqt5opengl5-dev build-essential qttools5-dev qt5-default
然后创建
glwidget.h
包含:#ifndef GLWIDGET_H #define GLWIDGET_H #include <QtGlobal> #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) # define USE_Q_OPEN_GL_WIDGET #endif #ifdef USE_Q_OPEN_GL_WIDGET # include <QOpenGLWidget> #else # include <QGLWidget> #endif class GLWidget : #ifdef USE_Q_OPEN_GL_WIDGET public QOpenGLWidget #else public QGLWidget #endif { Q_OBJECT }; #endif
然后 运行:
$ moc -v moc 5.2.1 $ moc glwidget.h | grep QGL || echo "not found" not found $ moc glwidget.h | grep QOpenGL >/dev/null && echo "found!" found!
所以你看到即使 qt 5.2.1 没有 QOpenGL,moc 也是这样解释预处理器指令的
我们可以把版本检查改得更简单
#if QT_VERSION >= 0x050400
如果我们再次尝试进行该检查,那么 Ubuntu trusty 中的 qt 5.2.1 中的 moc 会生成正确的结果
所以我们认为我们找到了解决方案并尝试 运行ning moc 从更新的 qt 发行版中使用相同的代码。这次我在 Debian unstable 中使用来自 qt 5.5.1 的 moc,我得到:
$ moc -v moc 5.5.1 $ moc glwidget.h | grep QOpen || echo "not found" not found $ moc foo.h | grep QGL > /dev/null && echo "found" found
最有趣的是,如果在 qt 5.5.1 下,我将版本检查宏 mack 转为 using
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
那就有用了!
所以总而言之,moc 确实理解一些预处理器指令,但它理解的指令在 qt 5.4 之前和之后的版本之间是不同的。似乎不存在两者都能理解的通用预处理器指令。因此,我看不到使用预处理器指令解决此问题的方法。
您可以使用 CMake 生成这个 header。将此代码放入其中:
#include <@GL_CLASS@>
class GLWidget : @GL_CLASS@
{
Q_OBJECT
public:
[...]
然后在 CMakeLists.txt 中执行此操作:
set(GL_CLASS <depending on Qt version>)
include_directories(${CMAKE_CURRENT_BINARY_DIR}) #this is because configure_file produces its output in the build dir
configure_file(yourheader.h output.h @ONLY)
最后,在您的代码中使用 #include "output.h"
。