sandimschuh
sandimschuh

Reputation: 55

How to implement a solution-wide build configuration in a central location with Visual Studio 2015 (MSBuild 14.0)

With Visual Studio 2017 and MSBuild 15.0 a new feature was introduced to extend the build process for all projects in a solution at a central place by placing a Directory.Build.props and/or Directory.Build.targets file in the root folder of the solution (the folder in which the *sln file resides).

Unfortunately, this great feature does not work with older VS and MSBuild versions. Is there a way to make global build configurations work in VS 2015 and MSBuild 14.0 in a similar way like with VS 2017 and MSBuild 15.0?

Upvotes: 0

Views: 700

Answers (1)

sandimschuh
sandimschuh

Reputation: 55

After studying how MSBuild works I figured out that there is the Microsoft.Common.targets file located in the MSBuildToolsPath directory (e.g. C:\Program Files (x86)\MSBuild\14.0\Bin) which is used by MSBuild during each build.

When I compared the Microsoft.Common.targets files of MSBuild 14.0 and MSBuild 15.0, it turned out that they are almost identical. The main difference was, that the 15.0 file contains some logic to discover the path of the Directory.Build.targets file and if such a file exists the build targets in this file are also included in the build.

Differences of MSBuild 14.0 and 15.0 Microsoft.Common.targets files

* Important Note *
The following solution changes parts of the MS Visual Studio installation and can lead to unforseen and serious effects. In general, it is dangerous, completely unsupported, and could break all sorts of things. Please only proceed if you are absolutely sure what you're doing.

The solution for me was simply to paste the part that includes the Directory.Build.targets file from the MSBuild 15.0 Microsoft.Common.targets file into the MSBuild 14.0 Microsoft.Common.targets file. But it should also be safe to just replace the 14.0 file by the 15.0 file. The current version of the Microsoft.Common.targets file can be found here

To automate this process and to repeat it on other development machines I made this Windows batch file which discovers the MSBuildTools path and replaces the Microsoft.Common.targets file with the updated one. The updated file I use in this batch script is named MSBuil15.Microsoft.Common.targets and has to be located in the same folder like the batch file. This batch file is based on MSBuildPath.bat and GotAdmin.bat where I added two lines of code to replace the file.

@echo off

reg.exe query "HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0" /v MSBuildToolsPath > nul 2>&1
if ERRORLEVEL 1 goto MissingMSBuildRegistry

for /f "skip=2 tokens=2,*" %%A in ('reg.exe query "HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0" /v MSBuildToolsPath') do SET "MSBUILDDIR=%%B"

echo.
echo MSBuildToolsPath: %MSBUILDDIR%
echo.

IF NOT EXIST "%MSBUILDDIR%" goto MissingMSBuildToolsPath
IF NOT EXIST "%MSBUILDDIR%msbuild.exe" goto MissingMSBuildExe
IF EXIST "%MSBUILDDIR%Microsoft.Common.targets.bak" goto AlreadyPatched


::-------------------------------------
REM  --> Check for permissions
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"

REM --> If error flag set, we do not have admin.
if '%errorlevel%' NEQ '0' (
    echo Requesting administrative privileges...
    goto UACPrompt
) else ( goto gotAdmin )

:UACPrompt
    echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
    echo UAC.ShellExecute "%~s0", "", "", "runas", 1 >> "%temp%\getadmin.vbs"

    "%temp%\getadmin.vbs"
    exit /B

:gotAdmin
    if exist "%temp%\getadmin.vbs" ( del "%temp%\getadmin.vbs" )
    pushd "%CD%"
    CD /D "%~dp0"
::-------------------------------------- 


:: Replace MSBuild 14.0 Microsoft.Common.targets file with MSBuild 15.0 file.
rename "%MSBUILDDIR%Microsoft.Common.targets" "Microsoft.Common.targets.bak"
copy "MSBuil15.Microsoft.Common.targets" "%MSBUILDDIR%Microsoft.Common.targets"


exit /b 0

goto:eof
::ERRORS
::---------------------
:MissingMSBuildRegistry
echo Cannot obtain path to MSBuild tools from registry
goto:eof
:MissingMSBuildToolsPath
echo The MSBuild tools path from the registry '%MSBUILDDIR%' does not exist
goto:eof
:MissingMSBuildExe
echo The MSBuild executable could not be found at '%MSBUILDDIR%'
goto:eof
:AlreadyPatched
echo The Microsoft.Common.targets file is already patched
goto:eof

Upvotes: 1

Related Questions