Source lookup path mappings is a CDT debug feature that you would never notice if it always just worked. And it mostly does. But when it doesn’t you get an error while debugging that looks like this:
And things can get worse for the user: even if they go on to locate the file, they can then suffer problems when trying to set breakpoints. In the example below, the breakpoint is not installed (no blue tick on the breakpoint icon) and an error message from gdb shows up in the console. As far as the user is concerned that file does exists and is just there sitting in their workspace. But there is no help or indication of how to solve the problem.
Source Lookup Path Mappings
Source lookup path mappings is the feature responsible for translating compilation paths into local paths, for example, if a binary is built on a build machine it will have paths like /build/machine. To debug it on a user’s machine and locate the corresponding source files this path must be mapped to the local paths, say /user/project. There are two parts to it:
- Compilation paths to map to local paths: CDT is able to find and open a file reported by GDB. Used for instance to resolve a stack frame to a file in an editor.
- Local paths to map to compilation paths: CDT is able take a user action on a local file and translate that back to GDB. For instance inserting a breakpoint or run to line on a local file
So often, even if you told CDT where to find your source file reported by GDB in case 1, it could then go on to fail to set a breakpoint as in certain cases (detailed below), GDB would not know what the local path was supposed to map to. Hence the unfriendly error message and a user left to deal with it.
The Problem
The Path Mapping pre-9.0 were implemented in CDT and worked very well for the majority of cases. However, there were a few cases which had shortcomings in handling the mappings correctly, namely:
- Cross Platform Work (e.g. build on Windows, run/debug on Linux)
- Relocated files where the compilation path was relative
- Non-canonical paths i.e. paths containing ‘..’ e.g. /path/to/../file
In fact, managed make projects by default get compiled with relative and non-canonical paths. So these bugs would effectively render these projects unrelocatable without recompiling (which is not always possible). Sharing pre-built projects could end up being very difficult to debug.
In addition, the codebase for source lookup is quite involved, with many classes affecting different elements of debug. Making any changes would require a very good understanding of all the various cases. Plus without a comprehensive test-suite, any major changes would be considerably high risk.
The Solution
As it turns out, GDB (as far back as 6.6) has a feature known as “set substitute-path” which it uses to internally handle the mappings between compilation and local paths. So the plan was to modify CDT so by default, defer source mappings to the GDB backend. Another part of the work involved refactoring to avoid the use of IPath. IPath is a normalized and platform-specific representation of a path. As a result IPath is not suitable for saving values which represent paths from different platforms. This work was implemented by Jonah Graham of Kichwa Coders with generous sponsorship from Renesas. This feature was completed through Bug 472765.
Source Lookup On Every Platform
The improved version worked effectively. As part of the work a new, extensive test suite was written which meant the behaviour could be verified on various platforms.
Linux, MinGW & Cygwin:
The table below shows the supported cases for when the compile and target platform match. ‘×’ means source lookup will fail, for example, when performing a run-to-line on the file in question.’√’ means source lookup will be successful.
Use Case When Compilation path is: | CDT 8.8 (Mars) |
CDT 9.0 (Neon) |
Absolute & Canonical, e.g gcc -o elf /path/to/file.c |
√ | √ |
Absolute and Non-canonical, e.g gcc -o elf /path/other/../to/file.c |
× | √ |
Relative and Canonical, e.g. gcc -o elf to/file.c |
√ | √ |
Relative and Non-canonical, e.g. gcc -o elf ../to/file.c |
× | √ |
MinGW Compile & Linux Debug:
The table below shows the supported cases for a MinGW compile with debugging on Linux. ‘×’ means source lookup will fail, for example, when performing a run-to-line on the file in question.’√’ means source lookup will be successful.
Use Case When Compilation path is: | CDT 8.8 (Mars) |
CDT 9.0 (Neon) |
Absolute & Canonical, e.g gcc -o elf /path/to/file.c |
√ | √ |
Absolute and Non-canonical, e.g gcc -o elf /path/other/../to/file.c |
× | √ |
Relative and Canonical, e.g. gcc -o elf to/file.c |
× | √ |
Relative and Non-canonical, e.g. gcc -o elf ../to/file.c |
× | √ |
UNC and Canonical, e.g. gcc -o elf \\machine\path\to\file.c |
× | √ |
UNC and Non-canonical, e.g. gcc -o elf \\machine\path\..\to\file.c |
× | √ |
The inverse case of compiling on Linux and running on Windows-based targets also works in all cases listed in the table. A few corner cases are also fixed, one notable one is when the original source files were in multiple different locations but when debugging the local sources are now in one directory. More details can be found in Bug 472765. A full list of bugs (including some 10-year old ones) are resolved by this feature can be found here.
Additional Benefits
In addition to the supported cases above one other nice thing is that it simplifies complexity in CDT. From a user perspective, they are always presented with the local file name, they never have to see a compilation path (as in the case of the error screenshot earlier) during debug. Furthermore this gives consistency when using the GDB console. Previously a user using the console would have to understand GDB’s view on the paths and running ‘info break’ would return breakpoints with compilation paths. Now these will be local paths and inserting breakpoints at the console can be done on local file names as it can in the editor.
A new test-suite was developed to fully test the various conditions, platform combinations and versions of GDB. Many features that previously never had tests are now tested and so more robust. In total 34 new tests have been added to the build.
Using Improved Source Lookup
Now when the user goes to locate their file, the GDB backend implementation is used by default. As before a new Source Path Mapping is created. User’s can also continue to create new Source Path Mappings manually using the dialog box as before (either via the Launch Configuration’s Source Tab or the Preference Pages). The only difference is a check-box which gives the option to revert to the old behaviour as a fallback for (hopefully rare) cases where the backend does not support the ‘set substitute path’ feature.
Future Improvements
With the new backend working well for source lookup one area for future improvements would be the front end user interface. This could be enhanced to make it even smoother. Options for this include:
- When users go to locate the source file, provide a browse in workspace option
- Have a wizard that could walk the user through the creation of the mapping
- Use heuristics to have CDT ‘guess’ the source file and ask the user ‘is this your file?’ or provide a choice of potential options if more than one.
Conclusion
The improved source lookup feature in CDT 9.0 (Neon) will greatly improve the user experience for CDT users doing cross platform debug or debugging relocatable projects, saving valuable developer time. Thanks to Renesas for funding this work for the benefit of the community. Sharing pre-built projects between machines can be easily done without debug concerns. Now, in all these cases, it just works.
I’m completely stuck with Eclipse Neon.3 Release (4.6.3) and GDB 7.12.1 as provided by MSYS2 (64-bit native mingw-w64 version)… User experience: “not so good”.
Compile paths to source files were absolute, output paths relative to a CMake build directory (the Eclipse project was created with cmake 3.7.2’s “Eclipse CDT4 – Ninja” generator), see [1] for an example with defines, includes and compiler flags stripped.
When I start up a simple Windows console (cmd.exe; C:\msys64\mingw64\bin added to PATH) and run “gdb inkscape.exe” it works out of the box, without any changes needed. Eclipse I can not persuade to work. gdb consistently fails to find source files (“No source file named main.cpp.”) and I have set about every combination of source lookup paths I can think of (which is still a lot considering your article mentions simplified complexity in CDT).
Developer time saved? None… cost a lot of time and I should have stuck with a simple text editor and the console rather then trying to “improve” my productivity with Eclipse.
[1] C:\msys64\mingw64\bin\g++.exe […] -MD -MT src/CMakeFiles/inkscape.dir/main.cpp.obj -MF src\CMakeFiles\inkscape.dir\main.cpp.obj.d -o src/CMakeFiles/inkscape.dir/main.cpp.obj -c E:\Temp\Inkscape\inkscape\test\src\main.cpp