After having regained an interest in C++ recently, I've been fiddling around a bit with it and as I thought I might need to use a DLL some day, I wanted to know how to build and use one by myself in the first place.
As I'm using Visual Studio Code, I can't (and actually don't want to) use the wizardry of the proprietary Visual Studio versions that are doing a lot of magic in the background. My goal in this was to specifically be able to do it manually using MSVC so as to better understand the processes and commands behind it.
So as a first step, I followed the offical MSDN tutorial on creating and using own DLLs, translating the steps on there into MSVC tool commands and to my own surprise, it all went well and now I'm having my DLL lying around and getting used by my sample application.
The next step for me was then to be able to debug that DLL with the debugger jumping right into the source file, but that's where I'm struggling a bit. I am linking the DLL with /DEBUG to create a PDB and also am compiling the consumer application with /Zi to have debugging symbols enabled in there, too.
Debugging the consumer source works as expected, but when trying to jump into a function exported by the DLL, the debugger simply steps over.
These are the commands I am running / steps I am taking (full path up to the workspace replaced with ${ws} to have the lines shorter here):
Compile the library:
cl.exe /EHsc /c /DMATHLIBRARY_EXPORTS /Fo: ${ws}\obj\ ${ws}\src\MathLibrary.cpp
Link it as DLL with debug symbols:
link.exe /DLL /DEBUG /OUT:${ws}\out\MathLibrary.dll ${ws}\obj\MathLibrary.obj
Compile the DLL consumer with debugging symbols
cl.exe /EHsc /Zi /Fo: ${ws}\obj\ /Fe: ${ws}\bin\math_d.exe ${ws}\src\MathClient.cpp ${ws}\out\MathLibrary.lib
Then I copy the MathLibrary.dll and the MathLibrary.pdb from out\ to bin\ (for the executable to be able to load it) and then run it with the results described above. The debug console in VSCode reads
Loaded '${ws}\bin\MathLibrary.dll'. Symbols loaded.
so part of it seems to work, but I'm not sure on what to try next.
I assume I am either missing something in the linking of the DLL or the compilation of the consumer, but I don't know what exactly it is. I have read that the linker requires both, the DLL and its PDB to be available when linking the executable consuming the DLL, but I'm not quite sure what exactly this means.
Do I need to compile and link the executable in separate steps, passing the DDL's PDB to the linker command for it to "incorporate" it into the executable's PDB?
Or am I making false assumptions here and "jumping into the source of a DLL" is simply not possible? If so, how exactly would I debug a DLL's code, especially if it's my own?
Related
I have a debug .dll build that uses libcurl to send HTTP requests, all working fine.
With the release, the program that uses my .dll doesn't like it, the program maker recommended
make the libcurl.dll as delay-loaded, and calling LoadLibrary
so I did this
LoadLibrary(TEXT("C:\\Users\\user\\Documents\\VirtualDJ\\Plugins64\\SoundEffect\\libcurl.dll"));
and pointed Linker>input>delay loaded dlls to libcurl.dll [literally that]
It makes the plugin compatible again but I'm no longer getting communication.
I'm not sure how to proceed.
Is my LoadLibrary syntax correct?
I've been told debug the release, and I followed all these properties changes
https://learn.microsoft.com/en-us/cpp/build/how-to-debug-a-release-build?view=msvc-160
but I don't understand how you would run the release.
I'm pretty new at this so the simpler it is explained the better.
C++ Visual Studio 19
According to https://learn.microsoft.com/en-us/cpp/build/reference/linker-support-for-delay-loaded-dlls?view=msvc-160 the delay loaded dlls has nuances which you should consider. I didn't use this, but I use LoadLibrary/GetProcAdress/FreeLibrary always without any problems so I suggest you to try this way.
You can try to debug a release in the WinDbg. Just need to set paths to source code and PDB files. Sometimes WinDbg can be more useful than Visual Studio. More details about WinDbg https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-download-tools
What's the correct configuration to make a privately symbolicatable release build in Visual Studio? I want to generate and store a PDB file which would allow me to symbolicate crash dumps of the built executable, but to avoid embedding debug information in the executable itself which would allow an external user to observe symbols, e.g., function and variable names, without the PDB.
I'm used to the DWARF debugging format, which can either be embedded in an executable or be exported to a separate dSYM file, which seems to be the rough equivalent of a PDB; I'm not sure whether or not Visual Studio has the similar option of ever/sometimes embedding the debug information similarly or not in the executable, and if it does, what configuration options I need to turn on to make sure a release build doesn't embed this information.
The /Z7, /Zi, /ZI (Debug Information Format) compiler options allow you to
select the type of debugging information created for your program and whether this information is kept in object (.obj) files or in a program database (PDB).
Both /Zi as well as /ZI store debugging information in a program database. None of the information will be compiled into the final executable image.
Since you plan to use the debugging information for analyzing crash dumps of (presumably) release builds, make sure the /Zo (Enhance Optimized Debugging) compiler option is also enabled.
I have built a particular dll with debug information (compiler option /Zi and linker option /DEBUG). Through an interrupt statement in the main program, I launched the Visual Studio for debugging. In the list of modules shown as seen from Debug->Windows menu, I could see that the symbols have been loaded for the dll interested in. However when I open a C++ file from that dll and try to set a breakpoint, it says debug symbols are not available for the document. There is no question that this C++ file was compiled into that dll, and that it is the same source used to build the dll (I only did it). Why does this happen? Please help, before I shoot myself.
I don't have a definitive answer, only a few suggestions.
Sometimes mdm.exe (Machine Debug Manager) stops to work properly. Terminating the process and re-starting Visual Studio helps. If the problem persists between reboots however that probably isn't the cause.
Source-file-times (last modified) that are in the future can cause all kind of weird problems. To check file times, you can do a search for nothing (Windows XP) or "*" (Windows 7). That will list all files in the selected folder. Then sort the result by date to see the max/min file time. I have no idea where the incorrect file-times come from - I just know that it happens from time to time. Might be Visual Studio itself, might be some other tool I'm using.
You could try to start the application that uses your DLL from Visual Studio, with your DLL project already open. To do that, open the "Configuration Properties", select the "Debugging" page, and enter the .exe that should be started (+ arguments if you need any). Then start the debug session as you would for a .exe project.
A cure for many problems with Visual Studio is to "clean" the project manually, and do a full re-compile. Delete all files that are generated during a build process or that store solution or project "options". i.e. all .suo .ncb .user files plus everything in the "intermediate" and "output" folders. If you're using source control, just retrieve the whole project from your source control system into a clean directory, and re-build from scratch. (Getting everything "fresh" from source control also takes care of any potential file-time problems - at least with source control systems that don't preserve file-times)
Another possible reason would be, that VS loads the wrong .pdb file. A .pdb file with a matching name could be found in a symbol server/symbol directory configured for VS (or system wide through the _NT_SYMBOL_PATH variable), or in the VS symbol cache directory. How a .pdb file with a matching name came to be in such a place is a different story, but one can easily check if the wrong .pdb file is loaded: delete the .pdb file generated by the build, and start a debug session. If VS traces "symbols loaded" for the .exe/.dll in question, it must have found a .pdb file in some other location.
Sometimes VS seems to mess up breakpoint locations in some way. I don't exactly know when or how this happens, but one of the symptoms is, that if one deletes some breakpoints, they magically reappear when starting the next debug-session. I found that setting a new breakpoint, then deleting all break points by Debug/Delete All Breakpoints, and the re-setting the required ones helps.
1) Are you not able to hit the breakpoint at all ? Generally, it gets resolved once the code in the module or stack frame needs to be hit.
2) Check if your pdb is not source information stripped
Do a Build->Clean Solution, close visual studio and then restart it and do a fresh build. This happened to me once before, and that seemed to fix it, just some outdated pdb information, I suppose.
In my case, I had renamed the C++ project. The compiler was outputting newName.lib while my other projects were still referencing oldName.lib which of course would not be removed by a Build->Clean.
I found this out by following the advice to manually clean the build directory. The subsequent linker unresolved external reference gave away the situation.
I'm testing swig, and I found that SWIG's vcxproj file runs the mt.exe to generate the manifest file.
swig -c++ -csharp example.i
CL.exe ... -> compile the c++ source
link.exe ... -> generate dll
mt.exe ...
Csc.exe ...
What is this for? I skipped the mt.exe, but it seems to work fine.
It was a Very Big Deal in versions of VS prior to 2010. mt.exe embeds the auto-generated manifest in the executable image, important to get the DLL dependencies that are stored in the Windows side-by-side cache listed. Not much of a big deal anymore, it only embeds an "I'm compatible with Vista" manifest now. The side-by-side cache was rather a big headache and abandoned for VS2010.
You ought to check the .manifest file in the build directory and make sure nothing important is in it. Like the common dialogs version 6 entry that enables visual styles.
This has nothing to do with SWIG, but with how Visual C++ generates it's binary output.
The mt.exe tool does not generate a manifest file, it embeds the info from the manifest file that is already there (I think the linker would have created it) into the output DLL. Without this, the output DLL may only work while the manifest file resides along the DLL in the same directory.
(Note: I never really bothered to dig deeper regarding manifests, what info is exactly in there and if all the info in there is needed all the time, but since it's just all done automatically when you create an exe or dll in VC++ one shouldn't immediately need to bother unless something's not working :-)
Update: I posted a comment on John Robbins blog about the. He wrote a response here:
http://www.wintellect.com/CS/blogs/jrobbins/archive/2009/06/19/do-pdb-files-affect-performance.aspx
The project I am working on does not build symbols for its release binaries, and I would like to change this.
Some info:
Mostly C++ code base, some C#.
Compiled under VS2k5, will be moving to VS2k8 Team System.
Time critical software.
Must have optimizations enabled.
Source code is provided to customer so full symbols are fine.
What are the best command line switches to generate what I need, and what, if any, performance hits am I going to take?
Also, are there any "Gotchas" to be aware of?
Generating debug symbols (ie PDB files) is just creating an external file that a debugger can reference when looking at your code in memory. It doesn't affect the code that the compiler or linker generate (sort of like generating a .MAP file).
Now if you're talking about defining _DEBUG in a release build, that's a whole different question.
Update: I posted a comment on John Robbins blog about the. He wrote a response here:
http://www.wintellect.com/CS/blogs/jrobbins/archive/2009/06/19/do-pdb-files-affect-performance.aspx
I found the following link on microsofts website:
Generating and Deploying Debug Symbols with Microsoft Visual C++ 6.0
This link pertains to Visual C++ 6, but I am assuming these instructions are the same for Visual C++ 8(2005) and 9(2008).
The information it gives is very similar to the link provided by TheBlack but more in-depth.
The /Zi switch in Visual C++ will create a PDB, but this setting also implies additional settings that will make the DLL or EXE larger. Specifically, /Zi implies /DEBUG, which implies /INCREMENTAL, /OPT:NOREF and /OPT:NOICF. The last three make the compiled DLL or EXE bigger, but they can be overridden by specifying /OPT:REF and /OPT:ICF in addition to /Zi. There is no need to override /INCREMENTAL, as /OPT:REF and/or /OPT:ICF will ensure a full, non-incremental link.
Source: Correctly Creating Native C++ Release Build PDBs
I don't know the command line, but you need to set debug symbols both in c++ compiler config (program database) and the linker (generate debug info) in the IDE.
If you find the settings in the project, you can use help to see which command-lines they refer to.