Manifold Geometry // Многообразная Геометрия

Debugging journey on Linux / CLion

/ Просмотров: 403

While working on Analysis Situs and derived products, I came across some nuances that are not obvious for Windows-oriented developers (like myself). First off, I really recommend installing and using CLion as an IDE, mainly because of its following advantages:

  • CMake is natively supported by CLion.
  • CLion is merely adequate compared to Visual Studio, which has remained my sole professional IDE over decades.

Now to the point. Here are some notes, mainly related to runtime issues that I'd like to keep documented, even though they are probably too specialized for anybody else to find interesting.

Watch your LD_LIBRARY_PATH while in IDE

CMake projects are usually configured for both debug and release modes, and this is generally what you want to have. While the debug build is necessary for development, the release build is utilized in actual production. One issue I frequently run into is the fact that the global environment variables are set only once for both configurations, leading to the assumption that you would use the same LD_LIBRARY_PATH for both build types.

"Edit Configurations..." menu in CLion.

One practice our team inherited from OPEN CASCADE is the distribution of release and debug libraries separately in lib (release) and libd (debug) directories located in the INSTALL_DIR. As a result, the dependent projects that must link against and use these libraries at runtime must ensure that the correct destinations are configured. On Windows, mixing up release and debug libraries is such a bad idea that you often come across spontaneous crashes, especially, if you're extremely fond of STL (Standard Template Library). On Linux, the effect is not as vital, and the indirect consequence of debug-release mix would rather be the absence of debugging symbols (so that the breakpoints you put in the code are never triggered).

So here is my banality golden rule: every time you switch configuration in CLion, make sure that release/debug libs are set consistently for the linker (in CMake) and runtime (in the IDE settings). For now, I always have to change the environment manually in CLion settings and that is pretty annoying.

Build and install

That's a little one. But one thing I found pretty useful is just to bind the "build plus install" action to the familiar <Ctrl>+<Shift>+<B> key combination, so that you never forget to install the thing (which is often the cause of confusion).

Preferences in CLion.

Runtime for FreeCAD as a subprocess

One idea that looked appealing to me was running a piece of FreeCAD-based Python code right from Analysis Situs. Since you can just start a separate process directly from your app and leave Python to handle the rest, this problem appears to be easily manageable. It could be anything like that (with Qt):

// instantiate dynamically to avoid stack unwinding before the process terminates
QProcess* process = new QProcess();
// start the process after making signal/slots connections (skipped in this listing)

The issue was that it did not work. The worst part was that, despite connecting all signals to listen for process outcome messages, I could only receive the exit code 1 ("error") from the executed process. One clever trick here is to launch a terminal window rather than the derived process itself to observe what happens there:


As this terminal inherits the runtime of your app, you will be able to hear what the child process was desperate to say by running it manually from this terminal.

Runtime error, welcome back to dependency hell.

The issue here was the mix of OpenCascade libraries: the ones installed by FreeCAD are different from the ones used in Analysis Situs (ver. 7.3.0 versus ver. 7.6.0). The problem is nothing new for anyone who has ever heard about such things as LD_LIBRARY_PATH on Linux and PATH on Windows.

Unexpected version of OpenCascade libraries.

Then I executed the following bash commands in the same terminal to check and fix the issue:

export LD_LIBRARY_PATH=/usr/lib/freecad-python3/lib/

The idea here was to override the runtime directories and this way prevent FreeCAD from loading your native app's dependencies and bring it to its own warm waters. The same trick programmatically looks like this (should be done before the subprocess is launched):

qputenv("LD_LIBRARY_PATH", "/usr/lib/freecad-python3/lib");

So another rule goes here: make sure that your dependent processes do not mess up with the runtime of the caller process. If that happens though, run a terminal window as a subprocess and test it from there (I don't know why, but I'm kinda proud of this sorry little trick).

Want to discuss this? Jump in to our forum.