Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make PreBuildEvents\PostBuildEvents work using targets #1569

Closed
dsplaisted opened this issue Feb 15, 2017 · 31 comments
Closed

Make PreBuildEvents\PostBuildEvents work using targets #1569

dsplaisted opened this issue Feb 15, 2017 · 31 comments
Labels
Bug
Milestone

Comments

@dsplaisted
Copy link
Member

@dsplaisted dsplaisted commented Feb 15, 2017

As referenced in dotnet/sdk#677, PreBuildEvent and PostBuildEvent don't get correctly evaluated property values for .NET SDK projects. In non-SDK projects, VS inserts those after the default .targets import, so they get the final evaluated versions of the properties. In SDK projects, the final targets import is implicit, so the event properties get added to the body of the project, and end up with empty values if they try to reference most of the standard build properties.

Since these don't work, we should just disable the property page for .NET SDK projects.

@davkean
Copy link
Member

@davkean davkean commented Feb 15, 2017

Or rather we should just make this work with targets instead of properties.

@davkean davkean added the Bug label Mar 20, 2017
@davkean davkean added this to the 16.0 milestone Mar 20, 2017
@davkean
Copy link
Member

@davkean davkean commented Mar 22, 2017

We've got lots of bugs around this internally, devs use these tabs - removing them doesn't solve the problem. Convinced that we should replace these with targets.

@srivatsn srivatsn modified the milestones: 15.3, 16.0 Mar 23, 2017
@srivatsn
Copy link
Contributor

@srivatsn srivatsn commented Mar 23, 2017

Agreed. Pulling this back into 15.3

@davkean
Copy link
Member

@davkean davkean commented Mar 28, 2017

We're also not roundtripping the value that the user enters: #1569.

@davkean
Copy link
Member

@davkean davkean commented Mar 28, 2017

Here's a workaround for those running into this issue:

Edit your project file, and change the following format:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp1.1</TargetFramework>
    <PreBuildEvent>echo $(ProjectDir)</PreBuildEvent>
    <PostBuildEvent>echo $(ProjectDir)</PostBuildEvent>
  </PropertyGroup>
  
</Project>

Into this style, where the PreBuildEvent and PostBuildEvent properties are moved below the Sdk.targets import.

<Project>

  <Import Sdk="Microsoft.NET.Sdk" Project="Sdk.props" />
  
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp1.1</TargetFramework>
  </PropertyGroup>

  <Import Sdk="Microsoft.NET.Sdk" Project="Sdk.targets" />

  <PropertyGroup>
    <PreBuildEvent>echo $(ProjectDir)</PreBuildEvent>
    <PostBuildEvent>echo $(ProjectDir)</PostBuildEvent>
  </PropertyGroup>
  
</Project>
@gulbanana
Copy link

@gulbanana gulbanana commented Apr 6, 2017

one issue i've encountered when working around this problem by using targets instead is that the Exec task has more limitations than whatever runs the PostBuildEvent. for example, there's an obfuscation tool which runs fine via event but throws OutOfMemory when run via target.

@davkean
Copy link
Member

@davkean davkean commented Apr 6, 2017

@gulbanana That smells like a different problem - the PostBuildEvent itself is run in a target. Are you sure this isn't related to you running over a different kind of binary (.NET Core) that the obfuscation tool doesn't recognize?

@gulbanana
Copy link

@gulbanana gulbanana commented Apr 6, 2017

yeah, it's net461. could it be that i was just on the edge of memory usage before and slightly more is consumed while building sdk projects? or, do the existing targets use some task other than Exec?

@gulbanana
Copy link

@gulbanana gulbanana commented Apr 6, 2017

you're right, and sorry for the waste of time - turns out that the command transliteration wasn't perfect, causing it to run in a different working directory, meaning it picked up a new-style pdb, which is what crashed the obfuscator.. anyway, Exec is fine after all.

(for anyone coming from google and following a breadcrumb trail: you want <DebugType>Full</DebugType>)

@davkean
Copy link
Member

@davkean davkean commented Apr 6, 2017

Great, glad you figured it out, and followed up. Thanks,

@srivatsn srivatsn changed the title Disable Build Events tab for .NET SDK projects Make PreBuildEvents\PostBuildEvents work using targets May 6, 2017
@ppumkin
Copy link

@ppumkin ppumkin commented May 11, 2017

Using NET CORE and have this problem. Tried the suggested workaround and did not work.

-EDIT-
Actually now when I close and reopen the build events, the macros get removed!

:(

@calvin998
Copy link

@calvin998 calvin998 commented May 18, 2017

even a simple echo %cd% wasn't saved. After I reopen the project property window, it becomes a weird character echo Í%

@AKlaus
Copy link

@AKlaus AKlaus commented Jun 23, 2017

Had a problem that $(ConfigurationName) was always blank in the PostBuildEvent of my .NET Core 1.1 project (.NET SDK v1.0.4).
A workaround of adding <Import Sdk="Microsoft.NET.Sdk" Project="Sdk.targets" /> as @davkean suggested above worked fine. It was no need in adding Sdk.props in my case.
But now I get "warning MSB4011: ".....\Sdk.targets" cannot be imported again. It was already imported at "...\AppServer.csproj (9,3)". This is most likely a build authoring error. This subsequent import will be ignored."

@davkean
Copy link
Member

@davkean davkean commented Jun 23, 2017

Did you remove the SDK attribute? If so, can you run the following and attach the results:

msbuild /pp [project].csproj > proj.pp
@AKlaus
Copy link

@AKlaus AKlaus commented Jun 23, 2017

@davkean, I didn't remove the SDK attribute. The project file was created by VS 2017 as .NET Core Web project and I'm just adding pre- and post- build events. I compile the project with VS 2017, so not sure how it handles msbuild and donet sdk under the hood.

Please find the file attached
proj.pp.zip

@davkean
Copy link
Member

@davkean davkean commented Jun 23, 2017

Log says:

  <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk.Web">
  This import was added implicitly because of the Project element's Sdk attribute specified "Microsoft.NET.Sdk.Web".

Instead of above, you need:

<Project>

  <Import Sdk="Microsoft.NET.Sdk.Web" Project="Sdk.props" />
  
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp1.1</TargetFramework>
  </PropertyGroup>

  <Import Sdk="Microsoft.NET.Sdk.Web" Project="Sdk.targets" />

  <PropertyGroup>
    <PreBuildEvent>echo $(ProjectDir)</PreBuildEvent>
    <PostBuildEvent>echo $(ProjectDir)</PostBuildEvent>
  </PropertyGroup>
  
</Project>
@AKlaus
Copy link

@AKlaus AKlaus commented Jun 23, 2017

Changed it to Microsoft.NET.Sdk.Web, rather than Microsoft.NET.Sdk as it was before. Get a similar message: "warning MSB4011: "...MSBuild\Sdks\Microsoft.NET.Sdk.Web\Sdk\Sdk.targets" cannot be imported again. It was already imported at "...AppServer.csproj (11,3)". This is most likely a build authoring error. This subsequent import will be ignored."
Everything is still working.

@davkean
Copy link
Member

@davkean davkean commented Jun 23, 2017

You need to remove the SDK attribute - the explicit Imports effectively doing the same thing as it.

@AKlaus
Copy link

@AKlaus AKlaus commented Jun 23, 2017

Sorry, I'm really slow on the uptake. You mean to change the root tag from <Project Sdk="Microsoft.NET.Sdk.Web"> to <Project>? Yes, it helps and removes all the warnings.
Thank you very much!

P.S. For future generations, the key points of the solution:

  • Keep the root tag without attributes: <Project>
  • Import Sdk.props at the beginning: <Import Sdk="Microsoft.NET.Sdk.Web" Project="Sdk.props" />
  • Import Sdk.targets before pre-, post- build events: <Import Sdk="Microsoft.NET.Sdk.Web" Project="Sdk.targets" />
@ivanko2000
Copy link

@ivanko2000 ivanko2000 commented Dec 2, 2017

Could you please clarify the status of this issue and the fix? I am using VS2017 15.4.5 (latest release) and in a project utilizing the new project system e.g. $(TargetPath) and $(ProjectDir) resolve as empty in PostBuildEvent...

@blumu
Copy link

@blumu blumu commented Dec 2, 2017

@ivanko2000 Try using the following target syntax instead to specify the post-build command, this fixed the problem for me:

<Target Name="PostBuild" AfterTargets="PostBuildEvent">
    <Exec Command="somecommand.cmd $(ProjectDir) $(TargetDir) $(OutDir)" />
</Target>
@jmarolf
Copy link
Member

@jmarolf jmarolf commented Dec 4, 2017

@AKlaus The fix for this issue does not change your existing property logic so you should move your events into a target as @blumu suggests.

@StingyJack
Copy link

@StingyJack StingyJack commented Dec 19, 2017

This reported issue directs people here.

If I'm reading this correctly, its not yet fixed, and the workaround requires unloading and editing the csproj file instead of using the UI. Is that assessment correct?

@gulbanana
Copy link

@gulbanana gulbanana commented Dec 19, 2017

you don’t need to unload when using sdk projects. right click on the project node and there should be an edit command available.

@jmarolf
Copy link
Member

@jmarolf jmarolf commented Dec 19, 2017

@StingyJack it is fixed if you create a new project that does not have any PreBuildEvents\PostBuildEvents and add them via the UI. If you already have defined PreBuildEvents\PostBuildEvents you will need to move them into a target as has been suggested, but the UI will pick them up.

@Latency
Copy link

@Latency Latency commented Jan 27, 2018

@jmarolf this does actually work and it is because the way the pre/post build events get saved now has changed!

Microsoft just released an update for a new version of the IDE 15.5.5 this week and it is still broken for $(ProjectDir) & $(TargetDir) using old msbuild calling conventions. The UI macros show the correct paths being resolved within the IDEs project settings only.

Building the project still does not properly resolve them for MSBuild configurations < v15 with build configurations targeting v15 & CLP.

<Project Sdk="Microsoft.NET.Sdk">
...
</Project>

My pre-build event line is as follows:
"$(ProjectDir)PreBuildEvent.bat" "$(ProjectDir).." "$(ProjectDir)" "$(TargetDir)" "$(DevEnvDir)" 1 0

Output:
The command ""PreBuildEvent.bat" ".." "" "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE" 1 0" exited with code 9009.


Here are the changes the IDE does now:

Old:

<PropertyGroup>
    <PreBuildEvent>"$(ProjectDir)PreBuildEvent.bat" "$(ProjectDir)..\" "$(ProjectDir)" "$(TargetDir)" 0 />
</PropertyGroup>

New:

<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
    <Exec Command="&quot;$(ProjectDir)PreBuildEvent.bat&quot; &quot;$(ProjectDir)..\&quot; &quot;$(ProjectDir)&quot; &quot;$(TargetDir)&quot; &quot;$(DevEnvDir)&quot; 1 0" />
</Target>
@jmarolf
Copy link
Member

@jmarolf jmarolf commented Jan 27, 2018

@Latency what does your project file look like? This works on Visual Studio 15.5 with this project file:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

  <Target Name="PreBuild" BeforeTargets="PreBuildEvent">
    <Exec Command="&quot;$(ProjectDir)PreBuildEvent.bat&quot; &quot;$(ProjectDir)..&quot; &quot;$(ProjectDir)&quot; &quot;$(TargetDir)&quot; &quot;$(DevEnvDir)&quot; 1 0" />
  </Target>

</Project>

I don't actually have a PreBuildEvent.bat file but all the paths in the output are correct.

1>------ Build started: Project: ClassLibrary1, Configuration: Debug Any CPU ------
1>'"C:\jmarolf\bug_repros\ClassLibrary1\ClassLibrary1\PreBuildEvent.bat"' is not recognized as an internal or external command,
1>operable program or batch file.
1>C:\jmarolf\bug_repros\ClassLibrary1\ClassLibrary1\ClassLibrary1.csproj(8,5): error MSB3073: The command ""C:\jmarolf\bug_repros\ClassLibrary1\ClassLibrary1\PreBuildEvent.bat" "C:\jmarolf\bug_repros\ClassLibrary1\ClassLibrary1\.." "C:\jmarolf\bug_repros\ClassLibrary1\ClassLibrary1\" "C:\jmarolf\bug_repros\ClassLibrary1\ClassLibrary1\bin\Debug\netstandard2.0\" "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\" 1 0" exited with code 9009.
1>Done building project "ClassLibrary1.csproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
@Latency
Copy link

@Latency Latency commented Jan 28, 2018

@jmarolf the 'PreBuildEvent.bat' is specific to my project. Notice, that you ARE correctly using the new convention for your target which will work just fine.

You may replace the contents of the target with whatever your actual event will contain. You can look at how my batch file reads on my repo in the link here, which I updated last night, that uses this.

I managed to finally get the build configurations to work after reading others comments on GitHub (in a different thread here) for globbing/CLP/XAML files.

If you see anything wrong with the 'Generators' meta-tags, let me know! The default templates create a WPF xaml / designer files with XamlIntelliSenseFileGenerator for both and does not generate the .conf file in CLP.

I am wondering if what I have is also a notable difference between the two styles of build configurations?

@DaveInCaz
Copy link

@DaveInCaz DaveInCaz commented Aug 22, 2018

This issue is mentioned on Stack Overflow: https://stackoverflow.com/a/30612179/3195477

@TahirAhmadov
Copy link

@TahirAhmadov TahirAhmadov commented Aug 20, 2020

There is still an issue with pre-build and post-build macros, they all evaluate to empty.

Microsoft Visual Studio Enterprise 2019
Version 16.6.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
You can’t perform that action at this time.