1 | initial version |
By debugging a DLL (also called debgging into a DLL) we can inspect the inner workings of a DLL. As with any other code, debugging a DLL is only possible if we are in possession of the DLL's source code. Debugging a DLL however differs from debugging an executable. Since DLLs (like any libraries) do not have an entry point (the main
function in C++ executables), they can not be executed on their own. Rather a calling application is specified, which calls the DLL's functionality we want to debug. For debugging the DLL, the calling application is executed, which calls the DLL and the debugger stops at requested break points. From here on, debugging a DLL is the same as debugging any other code.
We document debugging DLLs written in C++ and called by applications naively written in C++. For debugging, we use Visual Studio 2013 and show the process at the hand of OpenCV.
For debugging the DLL, first we need to create debug symbols. OpenCV comes with a complete debug configuration. This means, by simply changing the configuration tab to Debug, the build process will produce debug symbols and add a suffix (d) to the debug DLLs. If your DLL project has no propper debug configuration yet, follow this guide to set the needed properties.
Next, we need to add the debug DLL path to the system environment variable PATH. Otherwise, the calling application will crash as it can not find the required DLL. The DLL's path is the DLL's project output directory (right click the DLL project -> Properties -> Configuration Properties/General -> Output Directory). After changing PATH, do not forget to reopen any application which needs the new set of environment variables!
Furthermore, we need to remember the output folder and name for the created .lib file. (Note, not all DLLs produce a .lib file in the build process, but OpenCV does. We will mention this case later.) For example, our Visual Studio OpenCV project outputs a .lib file, with the same name as the DLL but different file extension, into the folder C:\Users\local_user\Documents\OpenCV\opencv-3.4.1/build/lib/debug/
. This .lib will be important when configuring the calling application.
As mentioned, a DLL can not be executed on its own but needs to be called by an application. To specify the calling application, follow this guide.
Finally, we need to configure the calling application, such that on execution the debug versions of the called DLL are used. For this reason we already added the DLL's path to PATH earlier. However, most likely not in keep with your first intuition, when building an executable which makes use of a DLL, we also need to specify the corresponding .lib file as additional dependencies. This brings us to the topic of implicit linking of DLLs.
There exists two ways of linking to DLLs, implicit and explicit linking. Since OpenCV, as most other open source libraries, employs implicit linking we will only discuss this topic. For employing implicit linking, an additional .lib file is provided to the .dll. This .lib file is called an import library and unfortunately shares the same file extension as a static library but is actually something different. The code in an import library is basically a wrapper, which calls the functionality in the DLL. For the user, writing the executable, this is more convenient, as she does not need to keep track of the correct ordering and naming in the DLL.
To conclude, when implicitly linking to a DLL (.dll file extension), we need to provide the import library (.lib file extension) during the linker phase in the build process for the executable.
As discusses above, we need to provide the .lib files generated during the DLL's build process to the calling application. To not confuse the debug and release builds of the calling application, only change the additional dependencies for the calling application's debug configuration (right click the calling application project -> Properties -> Configuration Properties/Linker/General -> Additional Library Directories; right click the calling application project -> Properties -> Configuration Properties/Linker/Input -> Additional Dependencies).
For the case of OpenCV, where release and debug configurations initially both use the same (release) DLLs, we need to jump to the additional dependencies and replace all of OpenCV's .lib files with their respective debug version, e.g. changing C:\Users\local_user\Documents\OpenCV\opencv-3.4.1\build\lib\Release\opencv_ccalib341.lib
to C:\Users\mfischer-g\Documents\OpenCV\opencv-3.4.1\build\lib\Debug\opencv_ccalib341d.lib
(see the Debug in the path and d suffix in .lib file).
Now, rebuild the calling application and start with the fun part of debugging the DLL.