Build support in SharedProject

Jan 8, 2015 at 10:08 PM
I understand that Python projects do not actually build - no MSBuild tasks are invoked. I noticed that adding a "CoreCompile" target in my project file (I use .pcaproj extension) makes the project buildable, but the build just succeeds as there are no actual tasks in the CoreCompile target. My projects are built by running a BAT file generated for every build by the other code in my build system, so I override the StartBuild method to programmatically add the "Exec" task for my BAT file to the CoreCompile target, and it basically works.

My problem, however, is that the Exec task I added is saved in the project file, which I do not want. I need these MSBuild tasks created on the fly and not affecting the project file, but the only way I found so far is by using the MSBuild.Construction API, which updates my project file. The MSBuild documentation is good for users dealing with project files/scripts, but the MSBuild API reference is very limited. Is there any way of injecting build tasks without affecting the project file? I would really like to use the existing SharedProject framework, rather than adding my own method of running build tasks.
Coordinator
Jan 8, 2015 at 10:38 PM
Just put them in the corresponding .targets file (Microsoft.PythonTools.targets for PTVS, probably something else for your own project templates).
Jan 8, 2015 at 11:18 PM
Thanks, let me see if I understand correctly. My project file will always have a reference to a temporary .targets file, which will be always created at a known location on each build. Then when I use the MSBuild API, the AddTask method will add my virtual tasks in the temporary .targets file, not affecting my project file, correct? Will the projects load properly if the .targets file is not there?
Coordinator
Jan 8, 2015 at 11:42 PM
I'm not sure I follow. If your batch file is always generated in a known place (relative to the project file), then you can just have a single fixed Exec task invoking it - why do you need to add the task dynamically when project is loaded in VS?

The latter is not a good approach in general, anyway, because it will break building from command line.
Marked as answer by sun2sirius on 1/8/2015 at 7:48 PM
Jan 8, 2015 at 11:51 PM
Edited Jan 9, 2015 at 12:05 AM
These BAT files are the temporary files with random names - the way it currently works with the old CPP project framework. I can change it to a fixed name, located in the build output path, but it becomes harder to do since the output path or other temp location depends on project configuration. I suppose, I can try to use a variable like $(OutputPath) - will try...

OK, so I have this in my project file:
  <Target Name="CoreCompile">
    <Exec Command="$(TempBatFilePath)" />
  </Target>
Then I set $(TempBatFilePath) with the SetProjectProperty method in StartBuild. The build works, but now the "TempBatFilePath" property is saved in the project file. Is there a way to set a variable evaluated by MSBuild, but not write it to the project file?
Coordinator
Jan 9, 2015 at 12:08 AM
Yes, if it's an artifact of the build, you definitely want to be using the intermediate build output directory. This is $(IntermediateOutputPath) - it will automatically include the configuration name, so it's something like obj\Debug.

Don't set your variable using MSBuild APIs, but instead compute its value inside MSBuild itself. It should really be something straightforward, like "$(OutputPath)\build.cmd". Then you can put both the property element and the target element inside your shared .targets file, and all your projects will just reference that file.
Jan 9, 2015 at 2:48 AM
I figured, I have to call SetGlobalProperty, not SetProjectProperty, to create a property that MSBuild evaluates without saving it in the project file. Now I can either use a standard one like IntermediateOutputPath or create a completely new one like my TempBatFilePath. The key was to use a fixed Exec task with a variable Command value - thanks for the help!