diff options
10 files changed, 220 insertions, 5 deletions
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/RemoteBuildEngineManager.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/RemoteBuildEngineManager.cs index b024f9b48e..2c28218fa8 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/RemoteBuildEngineManager.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/RemoteBuildEngineManager.cs @@ -172,21 +172,21 @@ namespace MonoDevelop.Projects.MSBuild // Find builders which are not being shut down - var candiateBuilders = builders.GetBuilders (builderKey).Where (b => !b.IsShuttingDown); + var candiateBuilders = builders.GetBuilders (builderKey).Where (b => !b.IsShuttingDown && (!b.IsBusy || allowBusy)); if (buildSessionId != null) { - // Look for a builder that already started the session, no matter if the builder is busy or not. + // Look for a builder that already started the session. // If there isn't one, pick builders which don't have any session assigned, so a new one // can be started. var sessionBuilders = candiateBuilders.Where (b => b.BuildSessionId == buildSessionId); if (!sessionBuilders.Any ()) - sessionBuilders = candiateBuilders.Where (b => b.BuildSessionId == null && (!b.IsBusy || allowBusy)); + sessionBuilders = candiateBuilders.Where (b => b.BuildSessionId == null); candiateBuilders = sessionBuilders; } else // Pick builders which are not bound to any session - candiateBuilders = candiateBuilders.Where (b => b.BuildSessionId == null && (!b.IsBusy || allowBusy)); + candiateBuilders = candiateBuilders.Where (b => b.BuildSessionId == null); // Prefer non-busy builders diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs index 0e8297e46f..f9ac9372f0 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs @@ -1228,7 +1228,7 @@ namespace MonoDevelop.Projects foreach (var err in result.Errors) { FilePath file = null; if (err.File != null) - file = Path.Combine (Path.GetDirectoryName (err.ProjectFile), err.File); + file = Path.Combine (Path.GetDirectoryName (err.ProjectFile ?? ItemDirectory.ToString ()), err.File); br.Append (new BuildError (file, err.LineNumber, err.ColumnNumber, err.Code, err.Message) { Subcategory = err.Subcategory, diff --git a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/BuilderManagerTests.cs b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/BuilderManagerTests.cs index f946e326a0..fdfdd35b2b 100644 --- a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/BuilderManagerTests.cs +++ b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/BuilderManagerTests.cs @@ -556,6 +556,53 @@ namespace MonoDevelop.Projects } } + [Test] + public async Task ParallelBuilds () + { + // Check that the project system can start two builds in parallel. + + await RemoteBuildEngineManager.RecycleAllBuilders (); + Assert.AreEqual (0, RemoteBuildEngineManager.ActiveEnginesCount); + + var currentSetting = Runtime.Preferences.ParallelBuild.Value; + try { + Runtime.Preferences.ParallelBuild.Set (true); + + FilePath solFile = Util.GetSampleProject ("builder-manager-tests", "builder-manager-tests.sln"); + using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem (Util.GetMonitor (), solFile)) { + + // DepMain depends on both Dep1 and Dep2. + + var demMain = sol.Items.FirstOrDefault (p => p.Name == "DepMain"); + var dep1 = sol.Items.FirstOrDefault (p => p.Name == "Dep1"); + var dep2 = sol.Items.FirstOrDefault (p => p.Name == "Dep2"); + + InitBuildSyncEvent (dep1); + InitBuildSyncEvent (dep2); + + // Start the build + var build1 = demMain.Build (Util.GetMonitor (), sol.Configurations [0].Selector, true); + + // Wait for sync signal from projects Dep1 and Dep2, which will mean that + // both projects started building in parallel + + var syncAll = Task.WhenAll (WaitForBuildSyncEvent (dep1), WaitForBuildSyncEvent (dep2)); + if (await Task.WhenAny (syncAll, Task.Delay (5000)) != syncAll) + Assert.Fail ("Not all builds were started"); + + // Finish the build + SignalBuildToContinue (dep1); + SignalBuildToContinue (dep2); + + if (await Task.WhenAny (build1, Task.Delay (5000)) != build1) + Assert.Fail ("Build did not end in time"); + + Assert.AreEqual (0, build1.Result.ErrorCount); + } + } finally { + Runtime.Preferences.ParallelBuild.Set (currentSetting); + } + } void InitBuildSyncEvent (SolutionItem p) { var file = p.FileName.ParentDirectory.Combine ("sync-event"); diff --git a/main/tests/test-projects/builder-manager-tests/Dep1/Dep1.csproj b/main/tests/test-projects/builder-manager-tests/Dep1/Dep1.csproj new file mode 100644 index 0000000000..eeeeac2bfc --- /dev/null +++ b/main/tests/test-projects/builder-manager-tests/Dep1/Dep1.csproj @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="..\SyncTask.targets" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{B515C1C3-9897-45FE-B350-037EECD0BDC7}</ProjectGuid> + <OutputType>Library</OutputType> + <RootNamespace>Dep1</RootNamespace> + <AssemblyName>Dep1</AssemblyName> + <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug</OutputPath> + <DefineConstants>DEBUG;</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <ConsolePause>false</ConsolePause> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <Optimize>true</Optimize> + <OutputPath>bin\Release</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <ConsolePause>false</ConsolePause> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + </ItemGroup> + <ItemGroup> + <Compile Include="MyClass.cs" /> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> +</Project>
\ No newline at end of file diff --git a/main/tests/test-projects/builder-manager-tests/Dep1/MyClass.cs b/main/tests/test-projects/builder-manager-tests/Dep1/MyClass.cs new file mode 100644 index 0000000000..7513c54b2a --- /dev/null +++ b/main/tests/test-projects/builder-manager-tests/Dep1/MyClass.cs @@ -0,0 +1,10 @@ +using System; +namespace Dep1 +{ + public class MyClass + { + public MyClass() + { + } + } +} diff --git a/main/tests/test-projects/builder-manager-tests/Dep2/Dep2.csproj b/main/tests/test-projects/builder-manager-tests/Dep2/Dep2.csproj new file mode 100644 index 0000000000..3307066845 --- /dev/null +++ b/main/tests/test-projects/builder-manager-tests/Dep2/Dep2.csproj @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="..\SyncTask.targets" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{99329AC5-674A-4475-9431-43CAC8ED1CBF}</ProjectGuid> + <OutputType>Library</OutputType> + <RootNamespace>Dep2</RootNamespace> + <AssemblyName>Dep2</AssemblyName> + <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug</OutputPath> + <DefineConstants>DEBUG;</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <ConsolePause>false</ConsolePause> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <Optimize>true</Optimize> + <OutputPath>bin\Release</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <ConsolePause>false</ConsolePause> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + </ItemGroup> + <ItemGroup> + <Compile Include="MyClass.cs" /> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> +</Project>
\ No newline at end of file diff --git a/main/tests/test-projects/builder-manager-tests/Dep2/MyClass.cs b/main/tests/test-projects/builder-manager-tests/Dep2/MyClass.cs new file mode 100644 index 0000000000..b93930601e --- /dev/null +++ b/main/tests/test-projects/builder-manager-tests/Dep2/MyClass.cs @@ -0,0 +1,10 @@ +using System; +namespace Dep2 +{ + public class MyClass + { + public MyClass() + { + } + } +} diff --git a/main/tests/test-projects/builder-manager-tests/DepMain/DepMain.csproj b/main/tests/test-projects/builder-manager-tests/DepMain/DepMain.csproj new file mode 100644 index 0000000000..318f73a010 --- /dev/null +++ b/main/tests/test-projects/builder-manager-tests/DepMain/DepMain.csproj @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{12D301E7-3AAC-4375-A6DB-E3755E9892E4}</ProjectGuid> + <OutputType>Library</OutputType> + <RootNamespace>DepMain</RootNamespace> + <AssemblyName>DepMain</AssemblyName> + <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug</OutputPath> + <DefineConstants>DEBUG;</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <ConsolePause>false</ConsolePause> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <Optimize>true</Optimize> + <OutputPath>bin\Release</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <ConsolePause>false</ConsolePause> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + </ItemGroup> + <ItemGroup> + <Compile Include="MyClass.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\Dep1\Dep1.csproj"> + <Project>{B515C1C3-9897-45FE-B350-037EECD0BDC7}</Project> + <Name>Dep1</Name> + </ProjectReference> + <ProjectReference Include="..\Dep2\Dep2.csproj"> + <Project>{99329AC5-674A-4475-9431-43CAC8ED1CBF}</Project> + <Name>Dep2</Name> + </ProjectReference> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> +</Project>
\ No newline at end of file diff --git a/main/tests/test-projects/builder-manager-tests/DepMain/MyClass.cs b/main/tests/test-projects/builder-manager-tests/DepMain/MyClass.cs new file mode 100644 index 0000000000..f6cf0a7afd --- /dev/null +++ b/main/tests/test-projects/builder-manager-tests/DepMain/MyClass.cs @@ -0,0 +1,10 @@ +using System; +namespace DepMain +{ + public class MyClass + { + public MyClass() + { + } + } +} diff --git a/main/tests/test-projects/builder-manager-tests/builder-manager-tests.sln b/main/tests/test-projects/builder-manager-tests/builder-manager-tests.sln index 5f576d53ea..c160279f4a 100644 --- a/main/tests/test-projects/builder-manager-tests/builder-manager-tests.sln +++ b/main/tests/test-projects/builder-manager-tests/builder-manager-tests.sln @@ -7,6 +7,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SyncTask", "SyncTask\SyncTa EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SyncBuildProject", "TaskTest\SyncBuildProject.csproj", "{441F02A0-E0AC-4E7E-99D9-E6E516D0B35F}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dep1", "Dep1\Dep1.csproj", "{B515C1C3-9897-45FE-B350-037EECD0BDC7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dep2", "Dep2\Dep2.csproj", "{99329AC5-674A-4475-9431-43CAC8ED1CBF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DepMain", "DepMain\DepMain.csproj", "{12D301E7-3AAC-4375-A6DB-E3755E9892E4}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
@@ -25,5 +31,17 @@ Global {441F02A0-E0AC-4E7E-99D9-E6E516D0B35F}.Debug|x86.Build.0 = Debug|Any CPU
{441F02A0-E0AC-4E7E-99D9-E6E516D0B35F}.Release|x86.ActiveCfg = Release|Any CPU
{441F02A0-E0AC-4E7E-99D9-E6E516D0B35F}.Release|x86.Build.0 = Release|Any CPU
+ {B515C1C3-9897-45FE-B350-037EECD0BDC7}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B515C1C3-9897-45FE-B350-037EECD0BDC7}.Debug|x86.Build.0 = Debug|Any CPU
+ {B515C1C3-9897-45FE-B350-037EECD0BDC7}.Release|x86.ActiveCfg = Release|Any CPU
+ {B515C1C3-9897-45FE-B350-037EECD0BDC7}.Release|x86.Build.0 = Release|Any CPU
+ {99329AC5-674A-4475-9431-43CAC8ED1CBF}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {99329AC5-674A-4475-9431-43CAC8ED1CBF}.Debug|x86.Build.0 = Debug|Any CPU
+ {99329AC5-674A-4475-9431-43CAC8ED1CBF}.Release|x86.ActiveCfg = Release|Any CPU
+ {99329AC5-674A-4475-9431-43CAC8ED1CBF}.Release|x86.Build.0 = Release|Any CPU
+ {12D301E7-3AAC-4375-A6DB-E3755E9892E4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {12D301E7-3AAC-4375-A6DB-E3755E9892E4}.Debug|x86.Build.0 = Debug|Any CPU
+ {12D301E7-3AAC-4375-A6DB-E3755E9892E4}.Release|x86.ActiveCfg = Release|Any CPU
+ {12D301E7-3AAC-4375-A6DB-E3755E9892E4}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
|