C++ tip:
Visual C++ is hot garbage. There are a lot of reasons why it's hot garbage, so let me be more specific.
Visual C++ has roughly a billion dials, a trillion knobs, and a googolplex of moving parts. You have the usual pieces - compiler, linker, archiver, build system - but there is just so much more on top of that. So much that just... no other toolchain even tries doing, even comes close to doing.
So for example, by default CL (the compiler) cannot run in parallel with other CL processes. CL shares state with other processes by performing unsynchronized writes to a file on disk (a PDB file). You may optionally use the CL /FS flag to synchronize writes via a different program called MsPdbSrv, but it's buggy as ****. For one thing, MsPdbSrv is undocumented and hangs around however long it wants, so it's roughly the last process you ever want to see pop up from a continuous integration job. On top of that, though, CL sometimes seems to just totally ignore the /FS flag for no reason. Running CL processes in parallel for the same project seems completely untested. I don't think you can even enable it under Visual Studio, but it's out there, documented, ready and waiting to **** up your day.
Okay, so parallel CL processes for the same project are out. Fortunately, project-level parallelism is fine. That's what you're supposed to do. Take all of the source files in your project, build them all at once in a single CL command. Don't overthink things, either: normally the build system is responsible for knowing which objects need to be rebuilt after source code changes, but CL does this too. If any source file in your project has been changed, rebuild the whole thing. Compile 'em all and let CL sort 'em out. This is the default in Visual Studio, so it's ostensibly well tested.
What about if your build has one or two really big projects, though? Well hey, CL's got you covered there, too! You can optionally tell CL to parallelize itself using the CL /MP option. See, normally build systems are responsible for parallel scheduling of compilers, but here CL handles it too. This is actually a great thing because process creation is much slower on Windows than it is on Linux. Assuming it works. Given how hidden the option is in Visual Studio, I'm thinking it probably isn't tested well. You should split up your projects into smaller ones and link them together instead.
Let's keep count. So far I've mentioned three different, optional/secret ways of parallelizing your Visual C++ builds. Object-level parallelism using /FS and MsPdbSrv, manual project-level parallelism, and CL /MP.
If you're familiar with the Visual Studio UI, you've probably noticed the conspicuous "maximum number of parallel project builds" setting. That means Microsoft has apparently blessed project-level parallelism as the true solution, although it doesn't work exactly like you might think. If you're using MsBuild, that option tells MsBuild to create that many child processes. Projects are dispatched across those child processes for building. This is where the project-level parallelism comes from. It's not just that easy, though. MsBuild lets you specify different compiler options per source file, so instead of just saying something like "take all of my source files and build them", it has to snoop around for CL invocations and merge them together if they have the same command line arguments. It's all very complicated, but in case you can't tell that's supposed to be the theme for this post.
Speaking of complicated, do you want to know how MsBuild /t:Clean works? When you run MsBuild it fires up a daemon called Tracker. This nosey little ****er hooks into every program your build runs, even non-Microsoft ones, and writes down the names of every file they ever created. It stores the information in about a billion files, scattered everywhere. When you run MsBuild /t:Clean it loads those files and deletes everything listed. As far as I can tell there's no way to get rid of Tracker once it's poisoned your process tree. There are pros and cons here. The pro is that Tracker keeps idiots from accidentally persisting out of date files across clean rebuilds. The con is that Tracker makes it impossible to do, even if you want to do something as simple as collect data across CI builds.
That's the second daemon, by the way. First was MsPdbSrv, then Tracker. Then there's also vctip, which spies on you for Microsoft. That's a new one I just discovered today. And, of course, if you're using Visual Basic or C# post-Roslyn, you also have vbcscompiler, a long-running compiler server which starts itself when needed and stops itself whenever it feels like. Which is... well, I don't even know. It's necessary, because the C# compiler takes too long to start up now. But it's also horrible that it's necessary. And it means you have four opaque, undocumented, arbitrary-lifespan servers running on your computer - or worse, your build server.
Might be getting petty at this point, but I'll add this. You all know how the Windows shell is bad at Unicode, right? Yet Visual Studio supports Unicode compiler error messages. How does it do this? It doesn't read diagnostics from stdout. The text in the outbox box actually comes from a pipe that Visual Studio passes to its child processes over an environment variable, and that pipe does support Unicode. It's not just text, either. Visual Studio parses the data from that pipe somehow, and uses it to detect whether some descendant process has failed -- and then it terminates the build. So let's say, hypothetically, that your project has a test, and during that test it runs CL against a source file that contains an error. On purpose, because your code runs CL, and you want to test how your code handles CL errors. You'd run your test under Visual Studio and boom, your whole test suite process tree vanishes into an abyss. If you didn't know about this environment variable you would be mystified. Terrified, even. You'd think you had done something horribly wrong, you'd run your test harness under a debugger, you'd log every damn thing your program does, and nothing. It just goes away. The reason I know about this is because I spent days for a former employer specifically reverse-engineering how Visual Studio does this. If you are just some schmuck writing tests, there'd be no hope for you.
And I haven't even gotten into the frontend yet.