5
votes

I have a solution file (MySolution.sln) with a single project in it (MyProject.vcxproj). I would like to execute a custom target (MyCustomTarget) on my project through the solution. It would look something like this:

msbuild MySolution.sln /t:MyCustomTarget

When I execute the command, I'll get an error message:

MySolution.sln.metaproj : error MSB4057: The target "MyCustomTarget" does not exist in the project. [MySolution.sln]

You can replace MyCustomTarget with any standard targets from Microsoft.Cpp.Win32.targets (e.g.: ClCompile, Link) or any other target of your choice you include from .targets files in MyProject.vcxproj. None of them would work.

When the environment variable msbuildemitsolution is set to 1, I can inspect the generated MySolution.sln.metaproj file. At the bottom 4 targets are specified: Build, Rebuild, Clean, and Publish. Using these targets instead of MyCustomTarget, the project builds ok. Also, if I specify the project file instead of the solution file, it builds too:

msbuild MyProject.vcxproj /t:MyCustomTarget

But using this format, I will lose the OutDir property, manually have to set the Configuration and Platform, so I just lose the benefits of having a solution file.

Is there any way I can use my custom target with the solution file I originally intended?

As far as I understand the problem is that msbuild generates this intermediate project file (mysolution.sln.metproj) but that will won have the imports from MyProject.vcxproj, including the .targets files. No wonder MyCustomTarget is not recognized.

My current workaround is using the project file with msbuild and trying not to miss anything from the solution file:

msbuild MyProject.vcxproj /t:MyCustomTarget /p:Configuration=MyConfig;Platform=MyPlatform;OutDir=MySolution\Platform_MyConfig\

But this is not a proper solution, inflexible, prone to error and does not automatically adapt changes in the solution file.

3
Have you tried a before.{solutionname}.sln.targets? to import your targets file as part of the solution? stackoverflow.com/a/17712386/736079jessehouwing

3 Answers

2
votes

I think you already answered your question. The answer is NO. There is no target called "MyCustomTarget" inside the .sln.metaproj file, so MSBuild gives you that error message.

Now, to resolve your problem with passing extra parameters on command line. Passing platform and configuration won't be required, if you set defaults in your .vcxproj file. Add this somewhere in your project file, before any of the standard target files are imported:

<Platform Condition="'$(Platform)'==''">MyPlatform</Platform>
<Configuration Condition="'$(Configuration)'==''">MyConfiguration</Configuration>

Configuring OutDir, which is shared across all projects in solution can be done like this. I will assume your solution is structured so that .sln file is in root folder, and all projects are in sub-folders (arbitrarily deep) under the root, or in the same folder as the solution. If this is not the case, you will have to tweak the code a little to adjust to your situation.

Right after you defined Platform and Configuration in your project, add this property group:

<PropertyGroup>
    <RootFolder>$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory),MySolutionName.sln))</RootFolder>
    <OutDir Condition="'$(OutDir)'==''">$(RootFolder)\$(Platform)_$(Configuration)</OutDir>
</PropertyGroup>

The code above follows your convention of setting OutDir to MySolution\MyPlatform_MyConfiguration.

The downside of all this approach is that you have to manually modify all projects in your solution. However it will give you lots of flexibility in the future. For example, any common settings shared across all projects, could be extracted into single .props file that you can <Import> into every project, so changes to configuration could be done in one place.

2
votes

In order to use the custom target that exists in your project file while building using the solution file, use the following format:

msbuild MySolution.sln /t:MyProject:MyCustomTarget

Note that if the project is in a sub folder (solution folder) you need to add the folder name:

msbuild MySolution.sln /t:src\MyProject:MyCustomTarget

and if the project name contains spaces or dots they are replaced with underscores.

2
votes

MSBuild 15 now raises custom targets automatically into the solution metaproj so your initial approach of running the target directly on the solution is now supposed to work.