Search code examples
c++compilationvisual-studio-2017visual-studio-community

How to override compile command of Visual Studio 2017 Community


I would like to override the default Visual Studio C++ compiler with a simple shell script. What I want is to capture the arguments, such as file name, and create some statistics. However I want to override the compilation process completely - that is, I want to call the original compilation from my shell script.

I googled but all I found was how to have pre-build and post-build scripts that execute within a project. That's not what I want.

I want to change this globally. How can I do it?


Solution

  • For a standard C++ project file compilation is done by invoking the MsBuild Target named ClCompile. Note there's also an MsBuild Item named ClCompile which lists the actual C++ source files used, this can be readily seen by opening your .vcxproj in a text editor. Consequently this ClCompile Item is used in the ClCompile Target, where it gets passed to the CL Task which in turn will invoke cl.exe, the actual compiler executable. This code for this can be found in the Microsoft.CppCommon.targets file for the toolset you use, for a default install of VS2017 community on a 64bit machine that is C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\VC\VCTargets\Microsoft.CppCommon.targets.

    Any of those 3 could be overridden with a custom version however as you figured already just replacing cl.exe on disk isn't the best idea.

    But CL can use any executable simply by overriding the CLToolExe and CLToolPath properties. Practically: open your .vcxproj file and add

    <PropertyGroup>
      <CLToolExe>mycl.exe</CLToolExe>
      <CLToolPath>c:\path\to\mycompilerstub\</CLToolPath>
    </PropertyGroup>
    

    all the way at the end, after the line importing Microsoft.Cpp.targets; mycl.exe will be called instead of cl.exe. If you want the same effect globally on your machine, you'll put that PropertyGroup in a seperate msbuild file and save it in for example C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\VC\VCTargets\Platforms\x64\ImportAfter\MyCustomImport.targets. Any targets file in that directory will be imported automatically.

    As an alternative you could override the ClCompile target or the CL task. That's more involved though, e.g. for ClCompile you'd start by copying the whole implementation found in Microsoft.CppCommon.targets and then add whatever logic you need. Advantage is you have direct access to e.g. source files etc without having to parse a command line. For example this would override ClCompile and print source files and pass them to a custom executable:

    <Target Name="ClCompile"
            Condition="'@(ClCompile)' != ''"
            DependsOnTargets="SelectClCompile">
    
      <Message Text="All the sources = @(ClCompile)"/>
      <Exec Command="mycustom.exe @(ClCompile)" />
    
      ... <!--rest of implementation copied from Microsoft.CppCommon.targets goes here-->
    </Target>
    

    Again, this needs to be put at the end of your project file or in the ImportAfter directory for global overriding.