roslyn project configuration - c#

I am using Microsoft.CodeAnalysis and .MSBuild to load up solution, it's projects and retrieve project OutputFilePath. Trouble is Debug and Release have different ones and I can't figure out a way to switch between solution configurations. Any idea how to set which configuration will be used?
MSBuildWorkspace workspace = MSBuildWorkspace.Create();
workspace.LoadMetadataForReferencedProjects = true;
Solution solution = workspace.OpenSolutionAsync("someSolution.sln").Result;
foreach (Project project in solution.Projects)
Console.Out.WriteLine(project.OutputFilePath);
workspace.CloseSolution();

Some MSBuild properties, like typically the output path, depend on the configuration that the project is built with. You have to specify that configuration when you create the workspace.
For example:
var properties = new Dictionary<string, string>
{
{ "Configuration", "Debug" } // Or "Release", or whatever is known to your projects.
// ... more properties that could influence your property,
// e.g. "Platform" ("x86", "AnyCPU", etc.)
};
MSBuildWorkspace workspace = MSBuildWorkspace.Create(properties);
workspace.LoadMetadataForReferencedProjects = true;
Solution solution = workspace.OpenSolutionAsync("someSolution.sln").Result;
foreach (Project project in solution.Projects)
Console.Out.WriteLine(project.OutputFilePath);
workspace.CloseSolution();

Related

Cake MSBuild Targets

I am trying to use Cake's built in MSBuild functionality to only build a specific Target (i.e. Compile). Using the example at: https://cakebuild.net/api/Cake.Common.Tools.MSBuild/MSBuildAliases/C240F0FB
var settings = new MSBuildSettings()
{
Verbosity = Verbosity.Diagnostic,
ToolVersion = MSBuildToolVersion.VS2017,
Configuration = "Release",
PlatformTarget = PlatformTarget.MSIL
};
settings.WithTarget("Compile");
MSBuild("./src/Cake.sln", settings);
But it seems to build all targets, where as i would like to only build a specific target, as detailed in: https://msdn.microsoft.com/en-us/library/ms171486.aspx
As per the documentation here:
https://cakebuild.net/api/Cake.Common.Tools.MSBuild/MSBuildSettingsExtensions/01F8DC03
The WithTarget extension method returns the same instance of the MSBuildSettings with the modifications, it doesn't interact with the current instance. As a result, where you have:
settings.WithTarget("Compile");
Is actually not doing anything. However, if you do this:
var settings = new MSBuildSettings()
{
Verbosity = Verbosity.Diagnostic,
ToolVersion = MSBuildToolVersion.VS2017,
Configuration = "Release",
PlatformTarget = PlatformTarget.MSIL
};
MSBuild("./src/Cake.sln", settings.WithTarget("Compile");
It should work how you intend it.
To help with this sort of thing, you can run Cake in diagnostic mode, to see exactly what command is being sent to the command line for execution. You can find more about that in this related question:
How to enable diagnostic verbosity for Cake

Roslyn - determine project excluded from build configuration

I am trying to figure out which project is enabled/disabled in respective build configuration/platform setup. Where could I find this "project.BuildsInCurrentConfiguration" information please?
var properties = new Dictionary<string, string>
{
{ "Configuration", "Debug" },
{ "Platform", "x86"}
};
MSBuildWorkspace workspace = MSBuildWorkspace.Create(properties);
workspace.LoadMetadataForReferencedProjects = true;
Solution solution = workspace.OpenSolutionAsync("someSolution.sln").Result;
foreach (Project project in solution.Projects)
Console.Out.WriteLine($"{project.OutputFilePath} is enabled in this build setup: {project.BuildsInCurrentConfiguration}");
workspace.CloseSolution();
I would have thought I wouldn't be offered the projects that are not part of the picked configuration/platform, but solution.Projects shows me all of them regardless build setup.
I don't think Roslyn really has most of that information right now (I'm not sure if it ever would; but I would hope it would). I don't see anything related to a "configuration" for a project with the Roslyn APIs for example. That seems to be delegated to the DTE interfaces. You can get at platform type in a Roslyn project, so conceptually you could only get projects that would apply to a given type of build:
var rolsynProjects = solution.Projects
.Where(p => p.CompilationOptions.Platform == Platform.X86);
but, things like "DEBUG" configuration seem to only be available via DTE--which isn't that hard to get at. e.g.
var project = DTE.Solution.Projects
.Where(p=>p.FullName == rolsynProjects.First().FilePath).FirstOrDefault();
And from that VS project, you can get at its ConfigurationManager

C# Get Configuration from DTE

I'm trying to build some kind of custom Configuration Manager for Visual Studio 2013. I've created a VSPackage MenuCommand and currently run it in an visual studio experimental instance. To get the projects of the current solution i use this:
public static EnvDTE80.DTE2 GetActiveIDE()
{
// Get an instance of currently running Visual Studio IDE.
var dte2 = (EnvDTE80.DTE2)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.12.0");
return dte2;
}
public static IList<Project> Projects()
{
Projects projects = GetActiveIDE().Solution.Projects;
List<Project> list = new List<Project>();
var item = projects.GetEnumerator();
while (item.MoveNext())
{
var project = item.Current as Project;
if (project == null)
{
continue;
}
list.Add(project);
}
return list;
}
When I try to access the ConfigurationManager of a project, I get a NullRefernceException:
var projects = Projects().OrderBy(p => p.Name).ToList();
foreach (var project in projects)
{
DataRow row = solutionConfigurationData.NewRow();
row[0] = project.Name;
row[1] = project.ConfigurationManager.ActiveConfiguration.ConfigurationName;
row[2] = project.ConfigurationManager.ActiveConfiguration.PlatformName;
}
The COM-Object itself (project) works fine, because if comment out row[1] and row[2] I get a list of all project names.
Don't know how else to get the project configuration, because all the posts i found use the configuration manager.
1) Do not use Marshal.GetActiveObject to get the EnvDTE instance where your extension is loaded, it could return another running instance. Use GetService(typeof(EnvDTE.DTE))
2) Navigate the projects of the solution recursively, not linearly. See HOWTO: Navigate the files of a solution from a Visual Studio .NET macro or add-in.
3) EnvDTE.Project.ConfigurationManager can return null if the project doesn't support configuration. For C# and VB.NET project it should work, though. C++ projects use a different project model (VCConfiguration). For other projects maybe don't even support configuration programmatically.

Exception thrown when adding new project into solution

I'm trying to programatically add new project into solution via Roslyn.
var msWorkspace = MSBuildWorkspace.Create();
var solution = msWorkspace.OpenSolutionAsync(Constants.pathToSolution).Result;
var projectId = ProjectId.CreateNewId();
var versionStamp = VersionStamp.Create();
var info = ProjectInfo.Create(
id: projectId,
version: versionStamp,
name: "Redux",
assemblyName: "Redux.dll",
language: LanguageNames.CSharp);
var newSolution = solution.AddProject(info);
msWorkspace.TryApplyChanges(newSolution);
After this, the exception is thrown:
"System.NotSupportedExcpetion: Adding projects is not suported."
When I iterate over changed solution before trying to apply changes, the new project is present there. Adding new documents into projects works without any issues.
Is there a way to add new project into solution and save the changed solution?
Roslyn does not have any code that writes .sln files.
(you can see their solution reader here)
You can't do that.

In a MSBuild file how to I get the referenced projects?

I have a MSBuild script file and I want to perform an action for each projects that were imported in the file.
How do I get access to the referenced projects ?
It is not clear what kind of action you want to perform on each project. Assuming you want simply to print out the paths of referenced projects, here is the sample code:
Dictionary<string, string> globalProperties = new Dictionary<string, string>();
globalProperties.Add("Configuraion", "Debug");
globalProperties.Add("Platform", "AnyCPU");
ProjectCollection pc = new ProjectCollection(globalProperties);
Project sln = pc.LoadProject(#"MyProject.csproj", "4.0");
foreach (ProjectItem pi in sln.Items)
{
if (pi.ItemType == "ProjectReference")
{
Console.WriteLine(pi.EvaluatedInclude);
}
}
The code above uses ProjectCollection and Project types from Microsoft.Build.dll, which is part of MSBuild.
Note, that in theory project references depend on build parameters, e.g. you might reference debugging library for Debug configuration, but not for release. Therefore while initializing ProjectCollection you have to pass parameters you want.

Categories