Visual Studio ProTip: Copying Binaries on Pre and Post-Build Macros

Last year I had to spend a fair amount of time working on C and C++ projects in Visual Studio 2013, and one of the tasks that I had to learn how to do was use Visual Studio’s pre-build and post-build events to copy all of my dependent DLLs into the final output folder for my applications.

In C# we take the ability to do this for granted - if we need to add a reference to another project in our Visual Studio solution we just Add Reference –> Projects –> [Project Name] and boom, we’re all set. Visual Studio will automatically copy our dependent binaries into our final /bin/[Release|Debug] folder automatically.

In C/C++ - hell no. You have to do this all yourself!

And as it turns out, there’s lots of cases where you might need to do this yourself inside C# projects too. If your application uses run-time loading (Assembly.Load) or if you need to be able to call Process.Start to launch a custom application that you’ve written, then you might want to be able to easily debug your application by copying the dependent, non-reference binaries you need into your application’s bin folder.

I’m going to show you how to do that!

Using Pre-Build and Post-Build Visual Studio Macros

During the course of some routine work on Akka.NET today, I needed a way to test our MultiNodeTestRunner.exe - a custom unit test runner we developed to help test Akka.NET’s highly availability modules and user-defined, distributed applications built on top of Akka.NET.

This test runner needs to be able to do both assembly run-time loading AND launch third-party processes, so it’s a perfect example of a real-world application that can utilize pre and post-build macros for easy debugging.

So in Visual Studio, I have the following two projects inside the Akka.NET solution:

We’re going to copy the output binaries from Akka.Cluster.Tests.MultiNode INTO the bin folder for Akka.MultiNodeTestRunner, so we can run all of the tests using the same working directory as the MultiNodeTestRunner.exe itself.

Adding a Pre-Build Macro

To add a pre-build macro for a Visual Studio project, right click on the project (in this case,the Akka.MultiNodeTestRunner project) and view Properties, then click on Build Events.

Blank pre-build event in project view in Visual Studio

Next, we’re going to use some good-ole MS-DOS commands to XCOPY all of the binaries from Akka.Cluster.Tests.MultiNode into the bin directory of Akka.MultiNodeTestRunner. And we’re using MS-DOS commands because PowerShell is for script kiddies, right! Actually… I have no idea if Visual Studio supports PowerShell :p

echo PREBUILDSTEP for $(ProjectName)

echo Copying files from $(SolutionDir)core\Akka.Cluster.Tests.MultiNode\$(OutDir) to $(ProjectDir)bin\$(Configuration)\Akka.Cluster

if not exist "$(ProjectDir)bin\$(Configuration)\Akka.Cluster" mkdir "$(ProjectDir)bin\$(Configuration)\Akka.Cluster"
 
xcopy "$(SolutionDir)core\Akka.Cluster.Tests.MultiNode\$(OutDir)*.dll" "$(ProjectDir)bin\$(Configuration)\Akka.Cluster" /i /d /y
if errorlevel 1 goto BuildEventFailed

if errorlevel 1 goto BuildEventFailed 

REM Exit properly because the build will not fail 
REM unless the final step exits with an error code

goto BuildEventOK
:BuildEventFailed
echo PREBUILDSTEP for $(ProjectName) FAILED
exit 1
:BuildEventOK
echo PREBUILDSTEP for $(ProjectName) COMPLETED OK

This batch file uses XCOPY with wild-card matching to copy all binaries from Akka.Cluster.Tests.MultiNode\bin[Build Configuration] to Akka.MultiNodeTestRunner\bin[Build Configuration]\Akka.Cluster, and we need to paste this into the pre-build event under Debug configuration to make sure that this runs.

Populated pre-build event in project view in Visual Studio

Now we just need to kick off a build, and we should see all of these echo statements log their output into the Output window in Visual Studio.

Visual Studio pre-build macro logs in Output view

All of our output was successfully copied, and we can verify that be looking for the Akka.Cluster folder inside Akka.MultiNodeTestRunner\bin[Build Configuration].

Copied build output

So with all of the binaries in their proper place, we’re almost ready to debug! Last thing we need to do is pass some command-line arguments to the MultiNodeTestRunner.exe via the Debug view in the Project Properties dialog.

Debug settings

And if we run the Akka.MultiNodeTestRunner project, viola! We can observe it successfully loading the Akka.Cluster.Tests.MultiNode.dll and executing the tests!

Application output

You can use this technique in a lot of different cases. Macros are eternal!

Discussion, links, and tweets

I'm the CTO and founder of Petabridge, where I'm making distributed programming for .NET developers easy by working on Akka.NET, Phobos, and more..