2016-05-12 106 views
1

我不清楚WriteCodeFragment任務的用途是什麼(https://msdn.microsoft.com/en-us/library/microsoft.build.tasks.writecodefragment.aspx)。谷歌似乎開啓了文檔,我看到的一個例子不是確定性的。MSBuild WriteCodeFragment任務

有人可以澄清嗎?謝謝。

+0

實測這裏參考的https:/ /github.com/Microsoft/msbuild/blob/c1459f5cbd36f2c33eafc8f4ff087f6ee84c3640/src/XMakeTasks/Microsoft.Common.CurrentVersion.targets#L3030,不知道它做了什麼,雖然 – stijn

+1

@stijn在我做了一些更多的調查後看到答案。 –

回答

2

它看起來只適用於使用屬性填充源代碼文件(您選擇的語言)(閱讀:將構建信息嵌入到項目中)。

這是任務的源代碼:()

https://github.com/Microsoft/msbuild/blob/master/src/XMakeTasks/WriteCodeFragment.cs

具體GenerateCode參考方法。 ,它的主要列舉看起來是屬性特定的類型(讀:聲明和非功能性):

/// <summary> 
/// Generates the code into a string. 
/// If it fails, logs an error and returns null. 
/// If no meaningful code is generated, returns empty string. 
/// Returns the default language extension as an out parameter. 
/// </summary> 
[SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.IO.StringWriter.#ctor(System.Text.StringBuilder)", Justification = "Reads fine to me")] 
private string GenerateCode(out string extension) 
{ 
    extension = null; 
    bool haveGeneratedContent = false; 

    CodeDomProvider provider; 

    try 
    { 
     provider = CodeDomProvider.CreateProvider(Language); 
    } 
    catch (ConfigurationException ex) 
    { 
     Log.LogErrorWithCodeFromResources("WriteCodeFragment.CouldNotCreateProvider", Language, ex.Message); 
     return null; 
    } 
    catch (SecurityException ex) 
    { 
     Log.LogErrorWithCodeFromResources("WriteCodeFragment.CouldNotCreateProvider", Language, ex.Message); 
     return null; 
    } 

    extension = provider.FileExtension; 

    CodeCompileUnit unit = new CodeCompileUnit(); 

    CodeNamespace globalNamespace = new CodeNamespace(); 
    unit.Namespaces.Add(globalNamespace); 

    // Declare authorship. Unfortunately CodeDOM puts this comment after the attributes. 
    string comment = ResourceUtilities.FormatResourceString("WriteCodeFragment.Comment"); 
    globalNamespace.Comments.Add(new CodeCommentStatement(comment)); 

    if (AssemblyAttributes == null) 
    { 
     return String.Empty; 
    } 

    // For convenience, bring in the namespaces, where many assembly attributes lie 
    globalNamespace.Imports.Add(new CodeNamespaceImport("System")); 
    globalNamespace.Imports.Add(new CodeNamespaceImport("System.Reflection")); 

    foreach (ITaskItem attributeItem in AssemblyAttributes) 
    { 
     CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(new CodeTypeReference(attributeItem.ItemSpec)); 

     // Some attributes only allow positional constructor arguments, or the user may just prefer them. 
     // To set those, use metadata names like "_Parameter1", "_Parameter2" etc. 
     // If a parameter index is skipped, it's an error. 
     IDictionary customMetadata = attributeItem.CloneCustomMetadata(); 

     List<CodeAttributeArgument> orderedParameters = new List<CodeAttributeArgument>(new CodeAttributeArgument[customMetadata.Count + 1] /* max possible slots needed */); 
     List<CodeAttributeArgument> namedParameters = new List<CodeAttributeArgument>(); 

     foreach (DictionaryEntry entry in customMetadata) 
     { 
      string name = (string)entry.Key; 
      string value = (string)entry.Value; 

      if (name.StartsWith("_Parameter", StringComparison.OrdinalIgnoreCase)) 
      { 
       int index; 

       if (!Int32.TryParse(name.Substring("_Parameter".Length), out index)) 
       { 
        Log.LogErrorWithCodeFromResources("General.InvalidValue", name, "WriteCodeFragment"); 
        return null; 
       } 

       if (index > orderedParameters.Count || index < 1) 
       { 
        Log.LogErrorWithCodeFromResources("WriteCodeFragment.SkippedNumberedParameter", index); 
        return null; 
       } 

       // "_Parameter01" and "_Parameter1" would overwrite each other 
       orderedParameters[index - 1] = new CodeAttributeArgument(String.Empty, new CodePrimitiveExpression(value)); 
      } 
      else 
      { 
       namedParameters.Add(new CodeAttributeArgument(name, new CodePrimitiveExpression(value))); 
      } 
     } 

     bool encounteredNull = false; 
     for (int i = 0; i < orderedParameters.Count; i++) 
     { 
      if (orderedParameters[i] == null) 
      { 
       // All subsequent args should be null, else a slot was missed 
       encounteredNull = true; 
       continue; 
      } 

      if (encounteredNull) 
      { 
       Log.LogErrorWithCodeFromResources("WriteCodeFragment.SkippedNumberedParameter", i + 1 /* back to 1 based */); 
       return null; 
      } 

      attribute.Arguments.Add(orderedParameters[i]); 
     } 

     foreach (CodeAttributeArgument namedParameter in namedParameters) 
     { 
      attribute.Arguments.Add(namedParameter); 
     } 

     unit.AssemblyCustomAttributes.Add(attribute); 
     haveGeneratedContent = true; 
    } 

    StringBuilder generatedCode = new StringBuilder(); 

    using (StringWriter writer = new StringWriter(generatedCode, CultureInfo.CurrentCulture)) 
    { 
     provider.GenerateCodeFromCompileUnit(unit, writer, new CodeGeneratorOptions()); 
    } 

    string code = generatedCode.ToString(); 

    // If we just generated infrastructure, don't bother returning anything 
    // as there's no point writing the file 
    return haveGeneratedContent ? code : String.Empty; 
} 

這只是另一個例子,我發現是這樣的:

Using WriteCodeFragment MSBuild Task

<Target Name="BeforeBuild"> 
    <ItemGroup> 
    <AssemblyAttributes Include="AssemblyVersion"> 
     <_Parameter1>123.132.123.123</_Parameter1> 
    </AssemblyAttributes> 
    </ItemGroup> 
    <WriteCodeFragment Language="C#" OutputFile="BuildVersion.cs" AssemblyAttributes="@(AssemblyAttributes)" /> 
</Target> 

堵此成實際構建呈現:

//------------------------------------------------------------------------------ 
// <auto-generated> 
//  This code was generated by a tool. 
//  Runtime Version:4.0.30319.42000 
// 
//  Changes to this file may cause incorrect behavior and will be lost if 
//  the code is regenerated. 
// </auto-generated> 
//------------------------------------------------------------------------------ 

using System; 
using System.Reflection; 

[assembly: AssemblyVersion("123.132.123.123")] 

// Generated by the MSBuild WriteCodeFragment class. 
+0

我想知道如何防止它做這個任務。 –