Build output binary file does not match for same project build configuration
Ninja is under a second. Build systems get slow when they need to make decisions. Ninja contains the barest functionality necessary to describe arbitrary dependency graphs. Its lack of syntax makes it impossible to express complex decisions. Instead, Ninja is intended to be used with a separate program generating its input files. The generator program like the. Going beyond autotools, even build-time decisions like "which compiler flags should I use? To restate, Ninja is faster than other build systems because it is painfully simple.
Ninja is closest in spirit and functionality to Make, relying on simple dependencies between file timestamps. But fundamentally, make has a lot of features: Many projects find make alone adequate for their build problems.
In contrast, Ninja has almost no features; just those necessary to get builds correct while punting most complexity to generation of the ninja input files. Ninja by itself is unlikely to be useful for most projects. Here are some of the features Ninja adds to Make.
These sorts of features can often be implemented using more complicated Makefiles, but they are not part of make itself. Ninja currently works on Unix-like systems and Windows.
There are many other build systems that are more user-friendly or featureful than Ninja itself. By default, it looks for a file named build. You can specify which targets files to build as command line arguments. For example, if you specify target as foo. Ninja supports one environment variable to control its behavior: The current tools are:. Clicking a file focuses the view on that file, showing inputs and outputs. This feature requires a Python installation.
By default port is used and a web browser will be opened. This can be changed as follows:. In the Ninja source tree, ninja graph. If no target is given generate a graph for all root targets. If used like ninja -t targets rule name it prints the list of targets using the given rule to be built. If no rule is given, it prints the source files the leaves of the graph.
If used like ninja -t targets depth digit it prints the list of targets in a depth-first manner starting by the root targets the ones with no outputs. Indentation is used to mark dependencies. If the depth is zero it prints all targets. If no arguments are provided ninja -t targets depth 1 is assumed. In this mode targets may be listed several times. If used like this ninja -t targets all it prints all the targets available without indentation and it is faster than the depth mode. By default it removes all built files except for those created by the generator.
Adding the -g flag also removes built files created by the generator see the rule reference for the generator attribute. Additional arguments are targets, which removes the given targets and recursively all files built for them. If used like ninja -t clean -r rules it removes all files built using the given rules.
Files created but not referenced in the graph are not removed. This tool takes in account the -v and the -n options note that -n implies -v. Available since Ninja 1. The remainder of this manual is only useful if you are constructing Ninja files yourself: Ninja evaluates a graph of dependencies between files, and runs whichever commands are necessary to make your build target up to date as determined by file modification times.
If you are familiar with Make, Ninja is very similar. A build file default name: Conceptually, build statements describe the dependency graph of your project, while rule statements describe how to generate the files along a given edge of the graph.
It will be used as an example for the following sections. Despite the non-goal of being convenient to write by hand, to keep build files readable debuggable , Ninja supports declaring shorter reusable names for strings.
A declaration like the following. Variables might better be called "bindings", in that a given variable cannot be changed, only shadowed. There is more on how shadowing works later in this document.
Rules declare a short name for a command line. They begin with a line consisting of the rule keyword and a name for the rule. The basic example above declares a new rule named cc , along with the command to run.
A full list of special variables is provided in the reference. Build statements declare a relationship between input and output files. They begin with the build keyword, and have the format build outputs: Such a declaration says that all of the output files are derived from the input files.
When the output files are missing or when the inputs change, Ninja will run the rule to regenerate the outputs. The basic example above describes how to build foo.
These variables will shadow any variables when evaluating the variables in the command. For more discussion of how scoping works, consult the reference. If you need more complicated information passed from the build statement to the rule for example, if the rule needs "the file extension of the first input" , pass that through as an extra variable, like how cflags is passed above.
If the top-level Ninja file is specified as an output of any build statement and it is out of date, Ninja will rebuild and reload it before building the targets requested by the user. It allows you to make Python calls like ninja. The special rule name phony can be used to create aliases for other targets. This makes ninja foo build the longer path. If a phony build statement is written without any dependencies, the target will be considered out of date if it does not exist.
Without a phony build statement, Ninja will report an error if the file does not exist and is required by the build. By default, if no targets are specified on the command line, Ninja will build every output that is not named as an input elsewhere. You can override this behavior using a default target statement.
A default target statement causes Ninja to build only a given subset of output files if none are specified on the command line. Default target statements begin with the default keyword, and have the format default targets. A default target statement must appear after the build statement that declares the target as an output file.
They are cumulative, so multiple statements may be used to extend the list of default targets. This causes Ninja to build the foo , bar and baz targets by default. For each built file, Ninja keeps a log of the command used to build it.
Using this log Ninja can know when an existing output was built with a different command line than the build files specify i. The log file is kept in the build root in a file called. If you provide a variable named builddir in the outermost scope,. Ninja version labels follow the standard major. The problem with headers is that the full list of files that a given source file depends on can only be discovered by the compiler: Some compilers can emit this information while building, and Ninja can use that to get its dependencies perfect.
If any file is later modified even in a way that changes which headers it depends on the modification will cause a rebuild as well, keeping the dependencies up to date. When loading these special dependencies, Ninja implicitly adds extra build edges such that it is not an error if the listed dependency is missing.
This allows you to delete a header file and rebuild without the build aborting due to a missing input. Any command that can write dependencies in this form can be used, not just gcc. To bring this information into Ninja requires cooperation. On the Ninja side, the depfile attribute on the build must point to a path where this data is written. Ninja only supports the limited subset of the Makefile syntax emitted by compilers.
Then the command must know to write dependencies into the depfile path. Use it like in the following example:. The -MMD flag to gcc tells it to output header dependencies, and the -MF flag tells it where to write them.
It turns out that for large projects and particularly on Windows, where the file system is slow loading these dependency files on startup is slow. Briefly, this means the tool outputs specially-formatted lines to its stdout. Most of you reading this will also need to do one preparatory step before putting your PDB files in the Symbol Server. That step is to run the Source Server tools across your public PDB files, which is called source indexing.
The indexing embeds the version control commands to pull the exact source file used in that particular public build. Thus, when you are debugging that public build you never have to worry about finding the source file for that build. The rest of this entry will assume you have set up Symbol Server and Source Server indexing. One good piece of news for those of you who will be using TFS , out of the box the Build server will have the build task for Source Indexing and Symbol Server copying as part of your build.
They source index and store every single build of all products they ship into a Symbol Server. That means everything from Windows, to Office, to SQL, to Games and everything in between is stored in one central location.
My guess is that Building 34 in Redmond is nothing but SAN drives to hold all of those files and everyone in that building is there to support those SANs. NET PDB only contains two pieces of information, the source file names and their lines and the local variable names. All the other information is already in the. When you load a module into the process address space, the debugger uses two pieces of information to find the matching PDB file.
The first is obviously the name of the file. If you load ZZZ. The extremely important part is how the debugger knows this is the exact matching PDB file for this binary. Since the act of compiling creates this GUID, stop and think about this for a moment. This is why it is so critical to save your PDB files for every build. However, you can look at the GUID value in your binary. The Pietrek articles will explain the output, but the important piece to us is the Debug Directories output:.
With the knowledge of how the debugger determines the correctly matching PDB file, I want to talk about where the debugger looks for the PDB files.
You can see all of this order loading yourself by looking at the Visual Studio Modules window, Symbol File column when debugging. The first place searched is the directory where the binary was loaded. If the PDB file is not there, the second place the debugger looks is the hard coded build directory embedded in the Debug Directories in the PE file. If you look at the above output, you see the full path C: If the PDB file is not in the first two locations, and a Symbol Server is set up for the on the machine, the debugger looks in the Symbol Server cache directory.
This search order is why your local builds and public build parts never conflict. Where PDB file loading gets a little more interesting are those.
For private builds on your local machine, life is easy because the debugger will find the PDB file in the build directory as I described above. The pain starts when you need to debug or test a private build on another machine. While it is subject to change in the future, an assembly compiled for Any CPU is actually in a directory like the following:.