none
Problem with Conditional Import inside VS RRS feed

  • Question

  • Hello

    I have a .targets file that supports multiple platforms, and has 3 elements like this:
    <Import Condition=" '$(Platform)' == '...' " Project="...">

    When I build using msbuild.exe and specify /p:Platform=... it works ok for all platforms. When inside VS, it always imports the first one, regardless what Platform I choose. I also have a dummy Platform called "BuildAllPlatforms" that invokes the msbuild task for all platforms, and that works ok in VS. If instead of the import, I literally replace the import, and add the condition to every target, propertygroup and itemgroup, it all works ok.
    Is this a bug in VS? I'm using RC1.

    Regards,
    Gustavo Guerra
    Sunday, October 16, 2005 10:12 PM

Answers

  • This is a known limitation.  VS will only ever process the <Import> tags once, when the project is loaded.  So whatever <Import> tag is active at the time the project is first loaded (based on whatever values your properties have at that time)... that's the <Import> tag that you will get for the lifetime of that project in the IDE.  We do not have the ability to reprocess <Import> after the project has been loaded.  Changing the <Import>'s after project load has the potential to completely change the entire structure of the project file, and the IDE is not equipped to handle that kind of a drastic change to your project mid-stream.

    The trick you discovered (your "BuildAll" target) is one way to go.  Another way is to have a separate project entirely (a "master" project) that drives the build for this one project.  Another way is to take advantage of VS's "Batch Build" feature.

    Hope this helps.

    --Rajeev


    Monday, October 17, 2005 7:03 PM

All replies

  • The target file is here:
    https://ovatsus.ath.cx/Ovatsus.CSharp.targets

    The problematic lines are these:

    <Import Condition=" !$(All_NET_CF_Test) " 
    Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />

    <Import Condition=" $(All_NET_CF_1_0_Test) " 
    Project="$(MSBuildBinPath\Microsoft.CompactFramework.CSharp.v1.targets" />

    <Import Condition=" $(All_NET_CF_2_0_Test) " 
    Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.targets" />

    Inside VS, the first is always included. Using msbuild.exe it works ok, the conditions are respected.
    Also, inside VS, if I use the BuildAllPlatforms Platform, which rewires the Build to the BuildAll target it works ok.

      <Target Name="BuildAll">
        <MSBuild Projects="$(MSBuildProjectFile)"
                 Properties="Configuration=$(Configuration);Platform=%(AllPlatforms.Identity)"
                 Targets="Build"
                 ContinueOnError="true"/>
      </Target>

    Can anyone help. please?

    Best regards,
    Gustavo Guerra
    Monday, October 17, 2005 8:52 AM
  • This is a known limitation.  VS will only ever process the <Import> tags once, when the project is loaded.  So whatever <Import> tag is active at the time the project is first loaded (based on whatever values your properties have at that time)... that's the <Import> tag that you will get for the lifetime of that project in the IDE.  We do not have the ability to reprocess <Import> after the project has been loaded.  Changing the <Import>'s after project load has the potential to completely change the entire structure of the project file, and the IDE is not equipped to handle that kind of a drastic change to your project mid-stream.

    The trick you discovered (your "BuildAll" target) is one way to go.  Another way is to have a separate project entirely (a "master" project) that drives the build for this one project.  Another way is to take advantage of VS's "Batch Build" feature.

    Hope this helps.

    --Rajeev


    Monday, October 17, 2005 7:03 PM
  • Too bad :(

    I do change a lot of targets with conditions and VS seems to work ok. Well, I gess I'll have to just copy paste the whole file.

    Thanks

    PS: What's VS's "Batch Build" feature?
    Monday, October 17, 2005 9:09 PM
  • And what about conditional UsingTask elements? Will they work ok inside VS.
    I was conditionally importing Microsoft.CSharp.targets, Microsoft.CompactFramework.CSharp.targets and Microsoft.CompactFramework.CSharp.v1.targets, and the last one redefines the csc task. The problem is that both Microsoft.Build.Tasks.dll and Microsoft.Compactframework.Build.Tasks.dll have the csc under the exact same namespace: Microsoft.Build.Tasks.Csc. So, how can I conditionally select one of them?

    Best regards,
    Gustavo Guerra
    Monday, October 17, 2005 11:44 PM
  • Are you saying that all three files (MS.C#.targets, MS.CF.C#.targets, and MS.CF.C#.v1.targets) are getting imported simultaneously into the same project?  I thought earlier you were saying that only one of the Imports would be active based on the Condition.  Having all three files imported simultaneously might cause problems, because as you said, many of them register the same tasks and have targets with the same name, so you might not get the behavior you want.

    But in any case, to answer your question, yes, a Condition on the <UsingTask> tag will work correctly, and the Condition will get reevaluated as appropriate even while the project is loaded in the IDE.

    Tuesday, October 18, 2005 5:40 PM
  •  Rajeev Goel msft wrote:

    Are you saying that all three files (MS.C#.targets, MS.CF.C#.targets, and MS.CF.C#.v1.targets) are getting imported simultaneously into the same project?



    No no, I imported one of them, based on a condition. What I was trying to say was that if I replace the condition on the import to a condition on a UsingTask would VS work ok. You already answered (Altought I don't have a way to see if the CSC task is being used from Microsoft.Build.Tasks.dll or Microsoft.CompactFramework.Build.Tasks.dll. BTW, what's the difference between them? It seems to work either way)

     Thanks

    Tuesday, October 18, 2005 5:55 PM
  • The only real difference between the Csc task in Microsoft.Build.Tasks.dll versus the one in Microsoft.CompactFramework.Build.Tasks.dll is simply the version of CSC.EXE that those tasks attempt to invoke.  The one in MS.Build.Tasks will try and locate v2.0 of CSC.EXE and execute that.  The one in MS.CF.Build.Tasks tries to locate v1.1 of CSC.EXE.
    Tuesday, October 18, 2005 6:42 PM
  • That then only changes the default csc it tries to locate, right? If I set CscToolPath, I can use either Csc task, right?

    Regards,
    Gustavo Guerra
    Tuesday, October 18, 2005 7:04 PM
  • Well, almost.  You're right that setting CscToolPath will completely override everything else ... if you set this property, then you have complete control over which CSC.EXE gets invoked, regardless of which version of the task you're using.  However, understand that CSC.EXE v2.0 supported more switches and options than CSC.EXE v1.1.  If you just do "csc.exe /?" on the two versions, you can see all the differences.  So, as a result, since the Csc task in MS.CF.Build.Tasks is designed to work against the v1.1 of CSC.EXE, it will refuse to pass in certain command-line switches into CSC.EXE.  For example, it will refuse to pass in the /langversion, /moduleassemblyname, /pdb, and /platform switches, since those switches didn't exist in v1.1.  If you don't need those switches, then it pretty much shouldn't matter which Csc task you use.
    Wednesday, October 19, 2005 5:57 PM