Packaging fonts and shaders with cmake - c++

I am writing an OpenGL app which runs on windows, OSX and linux.
I have some free-for-commercial-use truetype fonts that I'm packaging with the app, so the user can choose their preferred font for the text part of my renders.
I have some glsl shaders of my own making, so that my rendering does just the right thing. I need to package these with the app, too
I build with cmake and build an installer with cpack. I use the install command to control where the fonts and shaders go, on the target machine.
I have C++ code which, given a path to a font file, will give me just the right font in the rendered image. Similarly, I have OpenGL code which needs to know where the shaders are, at runtime.
On the build machine I've used configure_file to handle OS/user variations. The fonts and shaders are relative to a directory where the code resides, so I can put their location into a header file as a namespace variable, and the shading and font code can always find them.
Now I'm trying to get the installed app to work I've hit a problem: I can put my fonts and shaders anywhere I like on the target machine, at install time, but am struggling to see how the runtime (installed) executable, on the target machine, can be made to understand where that location is.
Compiler flag? Environment variable? Target property? None of them seems to quite fit the bill. Or is that wrong? Any thoughts would be very much appreciated.

You have two possibilities here:
The application is installed to a directory chosen by the user, but you control everything within that directory (what CMake calls the install tree). Because of this, you know where all of the external files are located relatively to the executable, so you can use relative paths for addressing them (as was also suggested in the comments). This approach is very common for OS X and Windows, where each application is typically installed to its own distinct directory. It's a bit less common for Unix-y systems, where stuff is typically just dumped to /usr/bin.
If you are not comfortable with relative paths, you can always package all resources into the executable itself. This is typically done using a resource compiler, but CMake has built-in support for those. This approach is particularly popular with GUI applications that package their fonts and icons into the executable itself. Qt offers a cross-platform resource compiler for this purpose, that is also supported by CMake.

Linux has a really different installation philosophy. Resources are installed in standard locations, which are not at a fixed relative location from the binary itself (windows in somewhat moving in this direction with ProgramData and .AppData)
The Linux approach would be to use fontconfig to locate fonts, and then install your fonts system-wide in /usr/share/fonts/myapp or in the user directory (~/.fonts/myapp or even better the new XDG location)
For shaders it would be similar with /usr/share/myapp system-wide and XDG locations user-side (https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html)
Of course you can force whatever you want in your code, and install in /opt, it will never feel like an integrated linux app from the user POW though

Related

How to ANGLE in Qt 6 OpenGL

Qt 6 has removed the support for ANGLE for their OpenGL backend. Now I would still like to use ANGLE with Qt because I would like to run custom OpenGL code that is translated by ANGLE to Vulkan Linux and Direct3D on Windows. I've tried to use ANGLE in my Qt 6 application, but without success. What I have tried is:
Build ANGLE from source files (on Linux) as per instructions (ANGLE build instructions).
Copied the generated libGLESv2.so and libEGL.so files into application directory. Then in my CMakeFiles.txt I have added:
find_library(libGLESv2 GLESv2)
find_library(libEGL EGL)
target_link_libraries(MyApp PRIVATE ${libGLESv2} ${libEGL})
Then in my main file I have added
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL);
My project links and builds fine, but the ANGLE backend seems to have no effect. It appears that Qt is still using the standard OpenGL implementation rather than the one provided by ANGLE (running QOpenGLContext::currentContext()->hasExtension("EGL_ANGLE_platform_angle") returns false when I set up my context).
Using QT_LOGGING_RULES=qt.qpa.gl=true,the logs show:
qt.qpa.gl: Choosing xcb gl-integration based on following priority
("xcb_glx", "xcb_egl") qt.qpa.gl: Xcb GLX gl-integration created
qt.qpa.gl: Xcb GLX gl-integration successfully initialized qt.qpa.gl:
Requested format before FBConfig/Visual selection:
QSurfaceFormat(version 3.0, options
QFlagsQSurfaceFormat::FormatOption(), depthBufferSize 24,
redBufferSize 8, greenBufferSize 8, blueBufferSize 8, alphaBufferSize
-1, stencilBufferSize 8, samples -1, swapBehavior QSurfaceFormat::DoubleBuffer, swapInterval 1, colorSpace
QSurfaceFormat::DefaultColorSpace, profile QSurfaceFormat::NoProfile)
How can I correctly setup Qt to rely on ANGLE?
Okay,
When I asked for a buildable project that reproduces the problem I didn't mean a snippet of source without the CMakeLists.txt that is causing the problem. I spent a good 4 hours trying to duplicate your environment blind. Nobody uses Qt 6 because it is horrible.
The first problem is you can't "just copy" libs.
GLES libs
EGL libs
After copy
the build and runtime system wants its series of links. When you copy you loose that because you get multiple copies of the same file rather than one copy with a bunch of links. If you are going to use these libraries you need to use them from an installed location or the original build location.
I wanted to prove this solution to you rather than just tell you, but I ran into the same problem 98.5% of all developers run into when anything Android is installed near Qt.
I wanted you to look at the CMakeLists.txt file for WaylandGUI not because it is some shining example of wonderful, rather so you see how to use message() to dump your cmake variables. This is the "default debugger" when troubleshooting cmake issues.
You aren't properly using find_library()
https://cmake.org/cmake/help/latest/command/find_library.html
Had you installed the ANGLE library you built there is a 50/50 chance find_library would have found it. One would need to dump the cmake variables to see where it looked and what it found and to do that you need message().
In particular read up on CMAKE_PREFIX_PATH and the PATHS option for find_library(). If the documentation seems clear as mud you can view this SO discussion on CMAKE_PREFIX_PATH.
cmake - find_library - custom library location
The other command you need to know is ldd. It's really shocking how many people developing on Linux that don't know this command.
What ldd does, from a high conceptual level, is tell you every library the loader is going to use when running your executable, at least from an initial load standpoint. The executable itself may be able to force load other libraries at run time. When an executable dies before it starts you can use ldd to track down what library (or library used by a library) cannot be found.
In your particular case, ldd will tell you what GLES and EGL libraries were used during link. By default find_library() looks in "the usual places" first which isn't your local build directory. The problem you are running into is you are trying to replace an existing system library in your link. Here's a very detailed write-up on how to use HINTS and such with find_library().
Without being able to replicate your build environment and without a complete buildable example replicating the problem I cannot be of further help.

How to set a Qt application to use the actual environment variables of a unix-like system?

I'm creating a Qt gui application using a library which searches the PATH environment variable for certain executables, namely compilers, make and cmake.
The problem is that std::getenv("PATH") returns something different in the gui and certain executables are missed. I've tried to use the QProcessEnvironment class to the set the PATH, however, the same problem arises. I can set it to specific paths in my machine but it would be great if it could get the PATH of any machine the application is deployed to.
Strangely if I start the gui using the command-line, everything works out fine! Although I find it unreasonable to ask users to open the gui using the command line.
Any help would be greatly appreciated.
This problem has nothing to do with Qt. You've set the PATH using shell initialization scripts and such, in your own user folder. It'd be a terribly bad idea for the graphical shell to use that path, as a mistake in your shell profile would potentially make the entire desktop non-functional. Of course it works from the command line, since your shell profiles take effect then.
You could, as a user configuration option, extract the shell PATH by running the equivalent of user's $SHELL -c 'echo $PATH', and processing the result.
Otherwise, you'll have to defer to what's customary on the platform, and consult package managers if needed. Different package systems tend to install these tools in different directories, but there is just a few common ones. I presume it'd be enough to cover Ubuntu, RedHat, macports and homebrew, and make sure that you check in "pure" FHS (Filesystem Hierarchy Standard) locations as well.

Is it possible to edit the hardcoded path in a Windows (custom built) installation of Qt 5?

We are building Qt 5.10 internally, and installing it to a given prefix on the build environments.
We would like to be able to relocate the installation (notably, but not only for, distribution). We are aware of qt.conf, as pointed out by this answer.
Yet, is there a maintained way to directly edit the values of those hardcoded paths in the installed files?
EDIT:
More rationale behind why we thing qt.conf is inferior to directly patching the binaries.
On development machines, it means that instead of simply patching the installed binaries once, we have to provide a configuration file in each folder containing an application depending on Qt.
Even worse than that, we discovered through failures (and the help of this post) that qtwebengineprocess.exe, in qtprefix/bin, expects its own qt.conf file, otherwise it will use the paths hardcoded in the libraries. This means that we have to touch the the library folder anyway, in otder to edit the configuration file to make it match the folder location on each development machine.

How do I configure QT5 without Xlib

I am trying to configure (and build) QT5 static. I want it to draw to the framebuffer and use webkit. I searched the docs but I didn't find anything on how I can do this without X. Does anyone know a way of doing this ?
Building Qt statically is totally orthogonal to the platform selection. Depending on your target device, you can choose between using Wayland, EGLFS, LinuxFB/DirectFB, etc.
Just be sure when you run configure that the actual plugin you're interested in gets compiled. In other words, check configure's final output (or read the config.summary file generated). If the platform is not there, run configure -v and try to see what's missing (headers, libs, ...).
You can then make any application use a given plugin by simply starting the application and passing the argument -platform eglfs|wayland|... (or by setting the QT_QPA_PLATFORM environment variable; or you can make it the default by mangling with the device mkspecs). More info here.
When it actually comes to static linking: this multi-platform support is implemented via plugins. A statically linked application won't have plugin loading available, so you must actually link the platform plugin into the application itself by adding something like
QTPLUGIN.platforms = eglfs
into your .pro file. More info here.
The best way is to use the "minimal" plugin and blit it into the framebuffer (something similar to the discussion at http://lists.qt-project.org/pipermail/development/2015-April/021160.html). However, ask your Platform vendor - check if "eglfs with fb" is a supported option.
However be aware that things like Cursor, overlays, rotation, vsync handling, GPU acceleration, may not be fully supported in these non-mainstream options on Linux.

Cross-platform fonts in WxWidgets GLCanvas

I'm developing a cross-platform app w/ wxWidgets and opengl...
I'm not sure what the best way is to have fonts work in the glcanvas. I've tried using FTGL but I think the version included in Fedora 11 must be broken or something since I can't get the example code on the web site to compile. I could try using GLUT or SDL but I'm not sure I want to include those as dependencies...
EDIT: Turns out it's just a different version than the one that is documented on the web site and has a completely different API.
Even if I have a font library though, all the ones I've seen require a path to a font file, and I have no idea how to do that in a cross-platform manner.
All platforms deal with fonts differently. There is no cross platform way to find fonts on a system. Alternatives include...
Package your fonts with your app so you know where they are.
Convert the fonts to a binary blob and embed them in your app.
Test for the OS and set the font path accordingly.
Transliterate this tutorial to C++ and array-embed a gzipped copy of the GNU Unifont. QuesoGLC might also be an option, but watch out for performance gotchas.