Dynamically use QGLWidget or QOpenGLWidget depending on Qt version - c++

My code is supposed to compile and run on platforms before and after Qt 5.4 where QOpenGLWidget was introduced, superseding QGLWidget. I thought I could write code like this to support both:
#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:
[...]
But that will not fly because moc does not seem to understand the preprocessor directives and will generate code for the wrong class.
I tried to work around the problem by adding a add_custom_command directive to my CMakeLists.txt which would run ${CMAKE_CXX_COMPILER}" -E -P -x c++-header ... on the file before passing it to moc. But that doesn't seem to work either as the preprocessor will remove the magic Q_OBJECT line, indicating that indeed moc must be run before the C preprocessor is run.
What other options do I have?
Must I resort to having two nearly identical header files (except for two lines) and then choose the right one at build time in cmake?
EDIT
To test this problem, try out the following:
on a Ubuntu trusty system which comes with qt 5.2.1 (you can create a chroot using sudo debootstrap trusty ubuntu-trusty) do:
apt-get install libqt5opengl5-dev build-essential qttools5-dev qt5-default
then create glwidget.h containing:
#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
then run:
$ 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!
so you see that even though qt 5.2.1 does not have QOpenGL, moc interpretes the preprocessor directive that way
we can change the version check to the much simpler
#if QT_VERSION >= 0x050400
if we try again with that check, then moc in qt 5.2.1 in Ubuntu trusty generates the right results
so we think that we found the solution and try running moc from a more recent qt distribution on the same code. This time I'm using moc from qt 5.5.1 in Debian unstable and I get:
$ 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
most funnily, if under qt 5.5.1 I turn the version check macro mack to using
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
then it does work!
So in summary, moc does understand some preprocessor directives but the ones it does understand are different between versions before and after qt 5.4. There does not seem to exist a common preprocessor directive that is understood by both. Thus I do not see a way to solve this problem using preprocessor directives.

You can use CMake to generate this header. Put this code into it:
#include <#GL_CLASS#>
class GLWidget : #GL_CLASS#
{
Q_OBJECT
public:
[...]
And then do this in 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)
Finally, use #include "output.h" in your code.

Related

QtCore/QTextCodec not found in Qt 6

After upgrading to Qt 6.0, the compiler told me
qzxing/src/QZXing.cpp:16: error: 'QtCore/QTextCodec' file not found
qzxing/src/QZXing.cpp:16:10: fatal error: 'QtCore/QTextCodec' file not found
#include <QtCore/QTextCodec>
^~~~~~~~~~~~~~~~~~~
qzxing/src/QZXing.cpp:16:10: note: did not find header 'QTextCodec' in framework 'QtCore' (loaded from '/Applications/Qt/6.0.0/clang_64/lib')
According to Qt's documentation, it can be imported by adding QT += core5compat.
However, the compiler told me that "Unknown module(s) in QT: core5compat".
How to solve this problem?
Make sure that you have installed "Qt 5 Compatibility Module".
Add QT += core5compat in .pro file.
Replace #include <QtCore/QTextCodec> to #include <QTextCodec>
The QTextCodec class was moved to the core5compat submodule so it is not enough to add that in the .pro, but you must correct the import to:
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
#include <QtCore/QTextCodec>
#else
#include <QtCore5Compat/QTextCodec>
#endif
Or simply
#include <QTextCodec>
On the other hand, you must install this module since it does not come by default and for this you must use Maintenance Tool.
add greaterThan(QT_MAJOR_VERSION,5): QT += core5compat in .pro file

Failed to compile Boilerplate Generated Based on GstPlugin

I have followed the instruction available in Gst Plugin Development Basics in constructing the boilerplate for my sample plugin which is HelloWorld in this case.
I have created the sample plugin by calling the make_element tool in the cloned repo
../tools/make_element HelloWorld
After that, I have modified the meson.build in gst-plugin directory to include the generated source files namely gsthelloworld.h and gsthelloworld.c
helloworld_sources = [
'src/gsthelloworld.c'
]
gsthelloworld = library('gsthelloworld',
helloworld_sources,
c_args: plugin_c_args,
dependencies : [gst_dep],
install : true,
install_dir : plugins_install_dir,
)
I encountered errors after doing meson build && ninja -C build:
gst-template/build/../gst-plugin/src/gsthelloworld.c:184: undefined reference to `GST_HELLOWORLD'
**there are multiple lines of the same errors happen at different part of the source file.
I cant seem to find the declaration of GST_HELLOWORLD in either generated source files.
Looking at the tutorial in Gst Plugin Development Basics, I see there was a declaration of macro that follows the similar naming convention with mine being HelloWorld while the provided sample being MyFilter.
#define GST_MY_FILTER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MY_FILTER,GstMyFilter))
However, I see none of the macro in the generated source files. So, I guess it might have been written somewhere else as the template provided in form of gstplugin.c and gstplugin.h looks very similar to the generated source files and can be compiled successfully if I remove my sample plugin from the build file.
Thus, is there any step I miss that is relevant for the compilation?
Thanks.
EDITED:
I was doing this on a PC with Ubuntu 18.04(gstreamer 1.14.5)
In
#define GST_TYPE_HELLOWORLD (gst_my_filter_get_type())
G_DECLARE_FINAL_TYPE (GstHelloWorld, gst_hello_world,
GST, PLUGIN_TEMPLATE, GstElement)
replace PLUGIN_TEMPLATE with HELLOWORLD
I compared with a working plugin and this modification to gsthelloworld.h worked for me :
#define GST_TYPE_HELLOWORLD (gst_my_filter_get_type())
G_DECLARE_FINAL_TYPE (GstHelloWorld, gst_hello_world,
GST, PLUGIN_TEMPLATE, GstElement)
// You need to add this one below in your gsthelloworld.h
#define GST_HELLOWORLD(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_HELLOWORLD,GstHelloWorld))
The gstmyfilter.h which worked for me is:
#ifndef __GST_MYFILTER_H__
#define __GST_MYFILTER_H__
#include <gst/gst.h>
G_BEGIN_DECLS
/* #defines don't like whitespacey bits */
#define GST_TYPE_MYFILTER \
(gst_my_filter_get_type())
#define GST_MYFILTER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MYFILTER,GstMyFilter))
#define GST_MYFILTER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MYFILTER,GstMyFilterClass))
#define GST_IS_MYFILTER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MYFILTER))
#define GST_IS_MYFILTER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MYFILTER))
typedef struct _GstMyFilter GstMyFilter;
typedef struct _GstMyFilterClass GstMyFilterClass;
struct _GstMyFilter
{
GstElement element;
GstPad *sinkpad, *srcpad;
gboolean silent;
};
struct _GstMyFilterClass
{
GstElementClass parent_class;
};
GType gst_my_filter_get_type (void);
G_END_DECLS
#endif /* __GST_MYFILTER_H__ */
Also these are build commands:
meson --reconfigure build
ninja -C build

Qt vulkan classes not defined during make on windows

I have been trying to compile a Qt/Vulkan project that works fine on Linux, on Windows. I am using QtCreator, Qt (5.11.0), and MingW.
I can qmake without problems, but make crashes with errors for each reference to a QVulkan* class, such as "not defined in this scope", but seems to have found and included the headers for that class.
I have tried compiling the qt vulkan examples, and got the same problem.
I ran configure -v, and found :
Qt Gui:
Vulkan ................................. yes
Here is an example of a header that crashes :
#ifndef WINDU_H
#define WINDU_H
#include <QWindow>
#include <QVulkanInstance>
#include <QVulkanFunctions>
#include <QVulkanDeviceFunctions>
class Windu : public QWindow {
public :
Windu();
~Windu();
void render();
void start();
void reset();
QVulkanInstance inst;
QVulkanFunctions* vki;
QVulkanDeviceFunctions* vkd;
};
#endif
I have stripped it down to the important : this gives not defined errors for QWindow, QVulkanInstance, QVulkanFunctions, QVulkanDeviceFunctions.
I have tried building qtgui separately, but it also crashes because it can't find Qt OpenGLES sources files.
I don't know much about C++ on windows.
This is my .pro file :
SHADERS = $$files(*.comp, true)
SHADERS += $$files(*.frag, true)
SHADERS += $$files(*.vert, true)
spirv.output = ${QMAKE_FILE_NAME}.spv
spirv.commands = glslangValidator -V ${QMAKE_FILE_NAME} -o ${QMAKE_FILE_OUT}
spirv.depends = $$SHADERS
spirv.input = SHADERS
spirv.variable_out = COMPILED_SHADERS
spirv.CONFIG = target_predeps
SOURCES = $$files(*.cpp, true)
HEADERS = $$files(*.h, true)
# install
target.path = build
target.depends = spirv
DESTDIR=bin #Target file directory
OBJECTS_DIR=build #Intermediate object files directory
MOC_DIR=build #Intermediate moc files directory
CONFIG+=debug
QMAKE_EXTRA_COMPILERS += spirv
and here is the repo if needed :
https://github.com/Paul-Hubert/fantastic-octree/blob/master/fantastic-octree.pro
So I found out that on Windows, the only way to get the Vulkan classes is to build Qt yourself. I had done this, but something i had done wrong made the build unuseable. You have to build the sources as described here : http://doc.qt.io/qt-5/build-sources.html, and use that to build the project. I added a kit in QtCreator to do this.

pass variable value to make using cmake

I'm trying to do something like
cmake -DUSE_FILES_FOR_INPUT=ON ..
and then get make to compile my files with -DUSE_FILES_FOR_INPUT=ON. But I don't get the =ON value. It seems that it should be written to a flags.make file, but it isn't:
$ grep USE_FILES_FOR_INPUT source/CMakeFiles/myprogram.dir/flags.make
CXX_DEFINES = -DUSE_FILES_FOR_INPUT
If I manually change that file with -DUSE_FILES_FOR_INPUT=ON then everything works fine.
How can I get cmake to add the value in flags.make?
A different approach to what I need to do: the variable I am using has type BOOL, so it would be good enough to get
CXX_DEFINES = -DUSE_FILES_FOR_INPUT when I do cmake -DUSE_FILES_FOR_INPUT=ON ..
and
CXX_DEFINES = when I do cmake -DUSE_FILES_FOR_INPUT=OFF ..
Is this possible?
Here is a small demonstration,
// demo.cpp
#include <iostream>
using namespace std;
int main()
{
#ifdef USE_FILES_FOR_INPUT
cout << "Using files.." << endl;
#else
cout << "Not using files.." << endl;
#endif
return 0;
}
The CMakeLists.txt,
cmake_minimum_required(VERSION 3.0)
add_executable(demo demo.cpp)
if (USE_FILES_FOR_INPUT)
add_definitions(-DUSE_FILES_FOR_INPUT)
endif()
And a sample output,
baris$ cmake . && make && ./demo
<...>
Not using files..
baris$ cmake -DUSE_FILES_FOR_INPUT=ON . && make && ./demo
<...>
Using files..
You should look at the configure_file documentation. They show an example using the special cmake construct #cmakedefine. This may be a little more work than Baris describes, but I prefer using configure_file and #cmakedefine to get cmake settings into C++ code.
Here is the complete example:
Consider a source tree containing a foo.h.in file:
#cmakedefine FOO_ENABLE
#cmakedefine FOO_STRING "#FOO_STRING#"
An adjacent CMakeLists.txt may use configure_file to configure the header:
option(FOO_ENABLE "Enable Foo" ON)
if(FOO_ENABLE)
set(FOO_STRING "foo")
endif()
configure_file(foo.h.in foo.h #ONLY)
This creates a foo.h in the build directory corresponding to this source directory. If the FOO_ENABLE option is on, the configured file will contain:
#define FOO_ENABLE
#define FOO_STRING "foo"
Otherwise it will contain:
/* #undef FOO_ENABLE */
/* #undef FOO_STRING */
One may then use the include_directories() command to specify the output directory as an include directory:
include_directories(${CMAKE_CURRENT_BINARY_DIR})
so that sources may include the header as #include <foo.h>.

Statically linked, correctly working readline library under Windows?

We're developing a C++ software package which depends on the GNU readline library and we usually build using gcc (requiring at least version 4). Now we would like to port this to Windows, obtaining a statically linked version which we can redistribute without requiring compilation by users.
I've tried several approaches:
Building using Cygwin (no go with the provided readline combined with -mno-cygwin or a MinGW compiler),
Building using MinGW and readline from GnuWin32 (unresolved dependencies to stat64, which I could not resolve),
Building using MinGW and building readline and required pdcurses from source (most promising approach, got to a static binary! But the obtained interactive shell behaved incorrectly, e.g. backspace was not visualized).
Any ideas how we might get one of the approaches to work?
After similar frustrations, I have just now compiled both a 32bit and 64bit version of libreadline 6.2 using MinGW-w64. Here's my how I did it:
Layout of my dev directory:
c:\dev\msys
c:\dev\mingw32
c:\dev\local32
c:\dev\mingw64
c:\dev\local64
Set some environment variables for the 32 bit build:
export CPPFLAGS=-I/c/dev/local32/include
export LDFLAGS=-L/c/dev/local32/lib
termcap 1.3.1.
Run the configure script:
./configure --host=i686-w64_mingw32 --prefix=/c/dev/local32
Edit termcap.c and fix up a few lines at the top. Mine looks like this:
/* Emacs config.h may rename various library functions such as malloc. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef emacs
#include <lisp.h> /* xmalloc is here */
/* Get the O_* definitions for open et al. */
#include <sys/file.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
//#ifdef HAVE_UNISTD_H
#include <unistd.h>
//#endif
#else /* not emacs */
//#ifdef STDC_HEADERS
#include <stdlib.h>
#include <string.h>
#define bcopy(b1,b2,len) (memmove((b2), (b1), (len)), (void) 0)
//#else
//char *getenv ();
//char *malloc ();
//char *realloc ();
//#endif
and tparam.c
/* Emacs config.h may rename various library functions such as malloc. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef emacs
#include "lisp.h" /* for xmalloc */
#else
//#ifdef STDC_HEADERS
#include <stdlib.h>
#include <string.h>
//#else
//char *malloc ();
//char *realloc ();
//#endif
/* Do this after the include, in case string.h prototypes bcopy. */
//#if (defined(HAVE_STRING_H) || defined(STDC_HEADERS)) && !defined(bcopy)
#define bcopy(s, d, n) memcpy ((d), (s), (n))
//#endif
#endif /* not emacs */
Modify the Makefile:
Line 23: CC = i686-w64-mingw32-gcc
Line 24: AR = i686-w64-mingw32-ar
Line 36: prefix = /c/dev/local32
Line 49: #oldincludedir = /usr/local
After that call make install and it should compile without warnings or errors.
readline 6.2
Set the same CPPFLAGS and LDFLAGS variables as with termcap before calling:
./configure --prefix=/c/dev/local32 --host=i686-w64-mingw32 --enable-static --enable-shared
Edit the Makefile:
Line 40: AR = i686-w64-mingw32-ar
make install should now compile and install readline!
If you want a 64bit library, replace i686-w64-mingw32 with x86_64-w64-mingw32 and local32 with local64.
Check out MinGWEditLine library
An EditLine API implementation for the native Windows Console. This BSD-licensed library provides command line editing and history functions similar to those found in GNU Readline.
Main readline functions are implemented for the native Windows console. BSD license.
gnuwin32 has a port of readline: http://gnuwin32.sourceforge.net/packages/readline.htm
for non-GPL projects, libedit has a more acceptable licensing [uses BSD licensing]
There is now a cygwin distribution of readline, which worked for me. The package name is libreadline-devel