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 –>
[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++ - hellllllllll 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
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:
- Akka.MultiNodeTestRunner - a project that defines the
MultiNodeTestRunner.exe, used to run all
- Akka.Cluster.Tests.MultiNode - a .DLL that contains a bunch of
MultiNodeSpectests that will be run by the
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
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.
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.
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.
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].
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.
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!
You can use this technique in a lot of different cases. Macros are eternal!