1

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?

Tomáš Zato
  • 50,171
  • 52
  • 268
  • 778
  • 1
    Find the cl.exe file, replace it with your own file, log the arguments. Optional call the original cl.exe with the arguments. – Richard Critten Aug 23 '17 at 09:00
  • Please be specific. You say you want to capture arguments and create statistics. You also say you want to override the compiler with a script. Those two are not mutually exclusive. The latter is not the only solution for the first problem and I suspect you really just want a solution to the first? – stijn Aug 23 '17 at 09:13
  • @stijn I calrified the question. I really want to override the compilation. Capturing arguments is only one of many things I can do then, if I succeed. – Tomáš Zato Aug 23 '17 at 09:46
  • @RichardCritten Well, this has few flaws, although it might be a good start. But a) visual studio might override this back upon updates and b) shell script cannot have `.exe` extension so I would have to make simple C program that runs the actual script. I want to use Node.js in particular. My final target achievement is to compile files on another machine (for fun, not because I really need to). – Tomáš Zato Aug 23 '17 at 09:47
  • Compilation is done by calling the ClCompile target which in turn calls the CL task (a couple of times) which in turn calls cl.exe. Hence if you cannot touch the latter (which you indeed shouldn't for reasons you figured out alread) there aren't many other options than overriding the CL task. Overriding is simple enough, just define your own CL task before importing Microsoft.Cpp.targets, but the actual definition is a bit of work since you need to override each of the 100 arguments seperately (afaik). Overriding ClCompile might be less work since you could just extract the info you need. – stijn Aug 23 '17 at 10:33
  • @stijn Could you please give me list of things to google? I'm still not sure what are you advising me to do. – Tomáš Zato Aug 23 '17 at 10:35
  • 1
    Ah, you don't know MsBuild yet :] That's going to be a rough ride just through googling then, give me some time and I'll prepare an answer to get you started. – stijn Aug 23 '17 at 10:46
  • Wouldn't it be easier to turn on MsBuild logging `/verbosity:normal` and parse the logfile? For statistics, that's sufficient. Ant to re-issue the equivalent build commands on another machine, it might also be enough although slightly wasteful (as you'd first build locally). – MSalters Aug 23 '17 at 13:38
  • @MSalters I wanted to use it, if I manage to finish it, to use other machines to speed up full project rebuilds. Those take up to 30 minutes. I have a spare notebook and other devices could also be used. The time saved would be valuable, not mentioning that developing this would be fun. – Tomáš Zato Aug 23 '17 at 14:03

1 Answers1

5

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.

stijn
  • 34,664
  • 13
  • 111
  • 163
  • Do I understand correctly that if I override `ClCompile target` the way you outlined, I will be able to select that target in visual studio for build? Anyway thanks a lot for the help, this is a very good starting point for more research! – Tomáš Zato Aug 23 '17 at 14:27
  • 1
    If you override ClCompile it will be called automatically instead of the default ClCompile target, e.g. when in VS you hit Build or compile a single file. – stijn Aug 23 '17 at 14:38