加载MsBuild项目文件时无效的静态方法调用语法异常

时间:2011-11-28 07:25:57

标签: multithreading msbuild msbuild-4.0

我为MsBuild创建了MergeSolution任务。它用于将多个解决方案合并到一个解决方案文件中。我正在使用PLINQ来并行解析和处理所有解决方案。我正在使用 我的DisposableProject类可以访问每个解决方案中的项目文件,以获取一些项目特定的值。创建DisposableProject类是为了修复竞争条件问题,因为一些项目文件包含在多个解决方案中,并且还用于在合并过程中修复大量内存消耗。

/// <summary>
/// Adding disposable functionality to Microsof.Build.BuildEngine.Project class.
/// Every project file is locked during processing to get a rid of huge memory consumption and race condition issues.
/// Project files are unloaded from build engine to save memory.
/// </summary>
public class DisposableProject : Project, IDisposable
{
    // Build engine - is it really needed?
    private static Engine buildEngine = new Engine();
    // Event used for thread safe Mutex creation
    static AutoResetEvent loadingEvent = new AutoResetEvent(true);
    // Project file name
    private string FileName {get;set;}
    // Dictionary with Mutex name -  Mutex
    static ConcurrentDictionary<string, Mutex> mutexLocks = new ConcurrentDictionary<string, Mutex>();

    /// <summary>
    /// DisposableProject constructor. Project file is loaded and named Mutex is created to lock file by its file name.
    /// </summary>
    /// <param name="projectFileName">MsBuild project file name</param>
    public DisposableProject(string projectFileName)
    : base(buildEngine)
    {
        // Use file name as mutex name
        FileName = GetMutexName(projectFileName);
        // Lock file during processing
        // Lock Mutex creation because multiple threads can create duplicate Mutexes causing sync exceptions
        loadingEvent.WaitOne();
        // Check if mutex object already exists
        if(!mutexLocks.ContainsKey(FileName))
            mutexLocks[FileName] = new Mutex(false, FileName);
        // Unlock mutex creation
        loadingEvent.Set();
        // Wait for file 
        mutexLocks[FileName].WaitOne();
        // Load project file
        this.Load(projectFileName, ProjectLoadSettings.IgnoreMissingImports);
    }

    /// <summary>
    /// Unload MsBuild project file from memory and Mutex (file lock) is released.
    /// </summary>
    public void Dispose()
    {
        // Unload from build engine to save memory
        this.ParentEngine.UnloadProject(this);
        // Unlock file
        mutexLocks[FileName].ReleaseMutex();
    }

    /// <summary>
    /// Create mutex name from file name.
    /// </summary>
    /// <param name="pathName">File name</param>
    /// <returns>Mutex name</returns>
    private string GetMutexName(string pathName)
    {
        // Replace directory separator chars with underscore
        return pathName.Replace(Path.DirectorySeparatorChar, '_');
    }
}

有时我的MergeSolutions任务在加载第一个项目文件时失败并出现以下异常:

InvalidProjectFileException: Invalid static method invocation syntax: "$([Microsoft.Build.Utilities.ToolLocationHelper]::GetPathToStandardLibraries($(TargetFrameworkIdentifier), $(TargetFrameworkVersion), $(TargetFrameworkProfile)))". Static method invocation should be of the form: $([FullTypeName]::Method()), e.g. $([System.IO.Path]::Combine(`a`, `b`))\r
 at Microsoft.Build.BuildEngine.Shared.ProjectErrorUtilities.VerifyThrowInvalidProject(Boolean condition, String errorSubCategoryResourceName, XmlNode xmlNode, String resourceName, Object arg0)\r
 at Microsoft.Build.BuildEngine.Expander.Function.ExtractPropertyFunction(String expressionFunction, Object propertyValue)\r
 at Microsoft.Build.BuildEngine.Expander.ExpandPropertyBody(String propertyBody, Object propertyValue, BuildPropertyGroup properties, ExpanderOptions options)\r
 at Microsoft.Build.BuildEngine.Expander.ExpandPropertiesLeaveTypedAndEscaped(String expression, XmlNode expressionNode)\r
 at Microsoft.Build.BuildEngine.Expander.ExpandAllIntoStringLeaveEscaped(String expression, XmlNode expressionNode)\r
 at Microsoft.Build.BuildEngine.BuildPropertyGroup.Evaluate(BuildPropertyGroup evaluatedPropertyBag, Hashtable conditionedPropertiesTable, ProcessingPass pass)\r
 at Microsoft.Build.BuildEngine.Project.ProcessProjectChildren(XmlElement projectElement, String projectDirectoryLocation, Boolean importedProject)\r
 at Microsoft.Build.BuildEngine.Project.ProcessImportElement(XmlElement importElement, String projectDirectoryLocation, Boolean importedProject)\r
 at Microsoft.Build.BuildEngine.Project.ProcessProjectChildren(XmlElement projectElement, String projectDirectoryLocation, Boolean importedProject)\r
 at Microsoft.Build.BuildEngine.Project.ProcessImportElement(XmlElement importElement, String projectDirectoryLocation, Boolean importedProject)\r
 at Microsoft.Build.BuildEngine.Project.ProcessProjectChildren(XmlElement projectElement, String projectDirectoryLocation, Boolean importedProject)\r
 at Microsoft.Build.BuildEngine.Project.ProcessMainProjectElement()\r
 at Microsoft.Build.BuildEngine.Project.InternalLoadFromXmlDocument(XmlDocument projectXml, ProjectLoadSettings projectLoadSettings)\r
 at Microsoft.Build.BuildEngine.Project.Load(String projectFileName, BuildEventContext buildEventContext, ProjectLoadSettings projectLoadSettings)\r
 at XXX.Build.Common.Types.DisposableProject..ctor(String projectFileName) in D:\XXX\DisposableProject.cs:line 35\r

MergeSolution任务总是在合并过程开始时抛出此异常,有时只会发生。是猜测是BuildEngine的初始化问题。 BuildEngine构造函数可能不是线程安全的。我正在使用默认的MSBuild构造函数。 任何想法如何解决?

0 个答案:

没有答案