Oct 292014
 

What’s Z7 and Zi?

These are compiler switches which tells the compiler where to dump debugging information collected from a C/C++ source file during compilation. Z7 tells the compiler to dump debugging information into a .obj file. Zi tells the compiler to dumps debugging information into an intermediate .pdb file.

What’s the Difference between Z7 and Zi?

Regarding Z7…

This option produces a .obj file containing full symbolic debugging information for every C/C++ source compiled for use with the linker. The symbolic debugging information includes the names and types of variables, as well as functions and line numbers. .Obj files get bigger in size because of the debugging information dumped in by the compiler into this file and then bloats your disk. /Z7 is based on the old code view format. This option introduces additional burden on the linker to parse every .obj file for debugging information. These .obj files will then be collated into a one .pdb file which will normally be named after the executable file name during linking phase.

Advantages of using Z7 switch
  • Good thing here is that there is no contention to write to one file (as you’ll see below).
  • Every .cpp file will have its own debugging information which will eventually be collated by the linker.
Disadvantages of using Z7 switch
  • Downside being the time taken to link, size of files on disk and old format.
  • Minimal rebuild feature (/Gm) will not work if /Z7 is enabled. You’ll get following warning…
    Command line warning D9007: ‘/Gm’ requires ‘/Zi or /ZI’; option ignored
  • The biggest disadvantage of Z7 is that this format doesn’t allow Edit and Continue, well this matters if you use this feature at all?
During Debugging what’s the effect of Z7 switch?

When debugging the debugger will tell us from where it has loaded a pdb file for a binary that its debugging. It loads the pdb file generated by the Linker which is unaffected by either /Zi or /Z7. Please see highlighted path of .pdb file from the debugger. So yes linker generates .pdb file which is the final .pdb file.

ConsoleApplication4.exe .\ConsoleApplication4.exe Symbols loaded. .\ConsoleApplication4.pdb 00E50000-00E70000 [5476] ConsoleApplication4.exe: Native

Demo

With /Z7 enabled you’ll see following list of files in your intermediate folder, note the size of .obj files…

10/23/2014  06:07 PM               136 ConsoleApplication4.res
10/23/2014  06:07 PM               348 ConsoleApplication4.log
10/23/2014  06:07 PM             2,473 ConsoleApplication4.Build.CppClean.log
10/23/2014  06:07 PM           117,615 ConsoleApplication4.obj
10/23/2014  06:07 PM         4,920,987 stdafx.obj
10/23/2014  06:07 PM        36,175,872 ConsoleApplication4.pch

Please compare above size of .obj files with below output files generated when /Zi is enabled.

Regarding Zi…

The compiler writes debugging information to one centralized file. The compiler names the program database named VCx0.pdb (or what you’ve configured it to be named), where x is the major version of Visual C++ in use.

Advantages of using Zi
    • When you use this option, your .obj files will be smaller, because debugging information is stored in the .pdb file rather than in .obj files.
    • Easy on the linker. It just has one file to parse to figure out debugging information for a binary that’s linking up.
    • Duplicate debugging information doesn’t make into the .pdb file generated by the compiler since its now working on one .pdb file instead of multiple .obj files where it doesn’t maintain a list of symbols generated to figure out duplicate ones.
    • Minimal Rebuild (/Gm) will work only work with /Zi or /ZI.
    • Advanced debugging features like Edit and Continue (/ZI) will work (making code changes when debugging, the changes are then built and we continue debugging again without stopping the debugging session). Sample effect on the debugger when a code change is done when debugging with Edit and Continue enabled…

clip_image002

——– Edit and Continue build started ——–

——————— Done ———————-

Disadvantages of using Zi
  • High contention to write to the one .pdb file as we’ve parallel builds running. Some machines will have several parallel builds configured.
Demo

With Zi enabled you’ll see following list of files generated. Take a note of sizes for the .obj files. Note that now we’ve got a

10/23/2014  06:00 PM               136 ConsoleApplication4.res
10/23/2014  06:00 PM               192 ConsoleApplication4.log
10/23/2014  06:00 PM             2,473 ConsoleApplication4.Build.CppClean.log
10/23/2014  06:00 PM           103,106 ConsoleApplication4.obj
10/23/2014  06:00 PM           933,490 stdafx.obj
10/23/2014  06:00 PM         1,551,360 vc120.idb
10/23/2014  06:00 PM         4,239,360 vc120.pdb <<<-- This is the pdb that the compiler generates, which contains debugging information from all the cpp files (path is generated using following pattern: $(IntDir)vc$(PlatformToolsetVersion).pdb). Now .obj files will not have debugging information. Compare their sizes with earlier output.
10/23/2014  06:00 PM        36,896,768 ConsoleApplication4.pch

When debugging the debugger tells exactly from where a pdb file is loaded. It loads the pdb file generated by the Linker which is unaffected by either /Zi or /Z7. Please see highlighted path of .pdb file from the debugger. So yes linker generates .pdb file which is the final .pdb file.

ConsoleApplication4.exe .\ConsoleApplication4.exe  Symbols loaded. .\ConsoleApplication4.pdb [4660] ConsoleApplication4.exe: Native

What’s the effect of these options when debugging in Visual Studio or a crash dump?

As far as debugging is concerned there is zero effect as the linker will eventually generate one final pdb file which is controlled by the linker switch: /DEBUG.

clip_image003

The compiler only generates an ‘intermediate’ .pdb file which contains debugging information collected during compilation which the linker will then eventually dump to a ‘final’ .pdb file. So all that you should be worried is the final .pdb file generated by the linker. This .pdb file is placed alongside the executable. This is the .pdb file that will be used when debugging the application or crash dumps.

So you might ask what if we disable .pdb generation in the compiler settings? Well then your code breakpoints will not hit. The breakpoints will be disabled since the linker couldn’t figure symbols for your code as the compiler didn’t generate any!

Please let me know if you have further questions?

Aug 052014
 

The C Runtime is being refactored…

Note CRT is being refactored. The implementation is split into different modules. Read more here: http://blogs.msdn.com/b/vcblog/archive/2014/06/10/the-great-crt-refactoring.aspx

Relevant excerpt from above blog post:

In order to unify these different CRTs, we have split the CRT into three pieces:

  1. VCRuntime (vcruntime140.dll): This DLL contains all of the runtime functionality required for things like process startup and exception handling, and functionality that is coupled to the compiler for one reason or another. We mayneed to make breaking changes to this library in the future.
  2. AppCRT (appcrt140.dll): This DLL contains all of the functionality that is usable on all platforms. This includes the heap, the math library, the stdio and locale libraries, most of the string manipulation functions, the time library, and a handful of other functions. We will maintain backwards compatibility for this part of the CRT.
  3. DesktopCRT (desktopcrt140.dll): This DLL contains all of the functionality that is usable only by desktop apps. Notably, this includes the functions for working with multibyte strings, the exec and spawn process management functions, and the direct-to-console I/O functions. We will maintain backwards compatibility for this part of the CRT.
Jan 062012
 

What do we mean by intrinsic?

Most functions are contained in libraries, but some functions are built in (that is, intrinsic) to the compiler. These are referred to as intrinsic functions or intrinsics.

Taken from MSDN…

The __noop intrinsic specifies that a function should be ignored and the argument list be parsed but no code be generated for the arguments. It is intended for use in global debug functions that take a variable number of arguments.

The compiler converts the __noop intrinsic to 0 at compile time. The following code shows how you could use __noop.
 

// compiler_intrinsics__noop.cpp
// compile with or without /DDEBUG
#include <stdio.h>

#if DEBUG
   #define PRINT   printf_s
#else
   #define PRINT   __noop
#endif

int main()
{
   PRINT("\nhello\n");
}

So if you have custom macros which should expand to nought in release version the proper way to do this would be via __noop. Remember this is Microsoft(R) specific.