As soon as a project gets to a certain size developers want to break it up to decrease their turnaround time for changes. The common solution is to have a set of headers in a 'common' include directory that is separated from the source, the idea being that as long as you're not touching those headers you can build the subdirectories of source independently of each other without worrying about dependency issues.
Common Header Includes
On a smaller scale this works great, the developers are all enlisted in all the source and maybe only do a world build every now and then (when they sync everything), otherwise they're able to just build the portion of the source they're actively working in. The only way this is broken is if people break the model and do a direct dependency between one of the subdirectories of source to another without using the common directory (that's bad).
Note that, given this model, you must rebuild the world if you sync anything in that depends on common header changes. You also have to be careful about implied dependencies between different libraries or DLLs, such as a resource change in a localizable resource-only DLL that is required by code in a different file (maybe an EXE). The correct way to declare this dependency is through header files (such as a resource.h equivalent in the common directory). This can easily fall apart if there's an implied structure to the resource that changes in a way that doesn't impact the common files, however.
The larger the project gets, the more likely these subtle side effects will happen. The more people working on the code, the more likely it will happen on any given day. Since the time for a full build is usually large by this time, developers demand support for independently buildable portions of the source tree. The common include directory solution doesn't hack it, anymore.
Pre-Built Binaries
The next step is to solve the binary file problem. To be able to compile a portion of the tree independently of the rest, you must have what would be the results of the rest of the compilation available to you in some form or another. Commonly this is done by having the group's build lab publish the results of their official builds. The developer's build process then picks up the portions the developer is not enlisted in from this official build and compiles from source the portions they are enlisted in.
The usual model in this case is to have the common include files checked in to a central repository everyone is enlisted in, and they separately enlist in the portion of the overall tree that they're working in. You now need to either be very careful about syncing to well known good build points or work to protect those common headers. I'll go through both models.
Well Defined Sync Points
In this model the build supports a set of well defined timestamps or labels that mark points where the source was known to produce a good build (for many different values of 'good'). When you want to make changes, you sync everything to one of those labels and make your changes based on that build.
Problems start when you want to make changes that rely on changes made by someone else since that label. Depending on the scope and dependencies of those changes, you may only need to sync the files they made the changes to and build. At worst, however, you may need to enlist in everything and build the entire project.
Furthermore, any time you change one of the headers in the common includes you must enlist in and build the whole project to make sure you don't break anything that depends on it. Same issue with the more subtle binary dependencies I talked about above.
Protected Common Directory
This is the 'publics' philosophy of the Windows build system. There is a central location for the shared headers (and binaries), but only the build labs can check in changes to them. This means that they will by definition always be at the sync point good state, since the build labs only check in their changes after a successful build (for many different values of 'successful').
What happens if you need to make a change to one of those files? The copy that gets changed is in the normal sources, when you make changes to them they get 'published' to the central place during the build. For things you're not building you get the known good copy, for things you are building you override with the copy you're building. This applies for headers, libraries, and binary files.
The advantage is that you don't have to worry so much about what you sync to except for the state of the portions of the source you're enlisted in. However, if someone (or you) makes a change that spans across multiple areas, changes common headers, etc. you're still in the same boat.
Future
The general form of this problem is: I'm only making changes to this, that, and the other thing. I want to only build what I have to and take advantage of official build lab work that has already been done as much as possible. I only want to incrementally build what I have to, but get a stable, predictable, and usable result.