Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Csproj] Multiple csproj features #172

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 39 additions & 13 deletions Sharpmake.Generators/VisualStudio/Csproj.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1179,7 +1179,7 @@ List<string> skipFiles

var preImportCustomProperties = new Dictionary<string, string>(project.PreImportCustomProperties);
AddPreImportCustomProperties(preImportCustomProperties, project, projectPath);
WriteCustomProperties(preImportCustomProperties, project, writer, resolver);
WriteCustomProperties(preImportCustomProperties, writer, resolver);

var preImportProjects = new List<ImportProject>(project.PreImportProjects);
WriteImportProjects(preImportProjects.Distinct(EqualityComparer<ImportProject>.Default), project, configurations.First(), writer, resolver);
Expand Down Expand Up @@ -1281,7 +1281,7 @@ List<string> skipFiles
Write(Template.MSBuild14PropertyGroup, writer, resolver);
}

WriteCustomProperties(project.CustomProperties, project, writer, resolver);
WriteCustomProperties(project.CustomProperties, writer, resolver);

if (project.ProjectTypeGuids == CSharpProjectType.Wcf)
{
Expand Down Expand Up @@ -1501,6 +1501,7 @@ List<string> skipFiles
}

WriteImportProjects(importProjects.Distinct(EqualityComparer<ImportProject>.Default), project, configurations.First(), writer, resolver);
WriteCustomProperties(project.PostImportCustomProperties, writer, resolver);

foreach (var element in project.UsingTasks)
{
Expand Down Expand Up @@ -1614,7 +1615,7 @@ private static void WriteImportProjects(IEnumerable<ImportProject> importProject
}

// TODO: remove this and use Sharpmake.Generators.VisualStudio.VsProjCommon.WriteCustomProperties instead
private static void WriteCustomProperties(Dictionary<string, string> customProperties, Project project, StreamWriter writer, Resolver resolver)
private static void WriteCustomProperties(Dictionary<string, string> customProperties, StreamWriter writer, Resolver resolver)
{
if (customProperties.Any())
{
Expand All @@ -1629,13 +1630,6 @@ private static void WriteCustomProperties(Dictionary<string, string> customPrope
}
}

internal enum CopyToOutputDirectory
{
Never,
Always,
PreserveNewest
}

private void GenerateFiles(
CSharpProject project,
List<Project.Configuration> configurations,
Expand All @@ -1649,7 +1643,7 @@ List<string> skipFiles
foreach (var file in project.ResolvedContentFullFileNames)
{
string include = Util.PathGetRelative(_projectPathCapitalized, file);
itemGroups.Contents.Add(new ItemGroups.Content { Include = include, LinkFolder = project.GetLinkFolder(include) });
itemGroups.Contents.Add(new ItemGroups.Content { Include = include, CopyToOutputDirectory = project.DefaultContentCopyOperation, LinkFolder = project.GetLinkFolder(include) });
}


Expand Down Expand Up @@ -1741,7 +1735,7 @@ List<string> skipFiles

HashSet<string> allContents = new HashSet<string>(itemGroups.Contents.Select(c => c.Include));
List<string> resolvedSources = project.ResolvedSourceFiles.Select(source => Util.PathGetRelative(_projectPathCapitalized, Project.GetCapitalizedFile(source))).ToList();
List<string> resolvedResources = project.ResourceFiles.Concat(project.ResolvedResourcesFullFileNames).Select(resource => Util.PathGetRelative(_projectPathCapitalized, Project.GetCapitalizedFile(resource))).Distinct().ToList();
List<string> resolvedResources = project.ResourceFiles.Concat(project.NonEmbeddedResourceFiles).Concat(project.ResolvedResourcesFullFileNames).Select(resource => Util.PathGetRelative(_projectPathCapitalized, Project.GetCapitalizedFile(resource))).Distinct().ToList();
List<string> resolvedEmbeddedResource = project.ResourceFiles.Concat(project.AdditionalEmbeddedResource).Concat(project.AdditionalEmbeddedAssemblies).Select(f => Util.PathGetRelative(_projectPathCapitalized, Project.GetCapitalizedFile(f))).Distinct().ToList();
List<string> resolvedNoneFiles =
(project.NoneFiles.Select(file => Util.PathGetRelative(_projectPathCapitalized, Project.GetCapitalizedFile(file))))
Expand Down Expand Up @@ -2169,7 +2163,7 @@ List<string> skipFiles
bool runtimeTemplate = project.AdditionalRuntimeTemplates.Contains(ttFile);
string expectedExtension =
runtimeTemplate ? ".cs" :
Util.GetTextTemplateDirectiveParam(Path.Combine(_projectPath, ttFile), "output", "extension") ?? ".cs";
Util.GetTextTemplateOutputExtension(Path.Combine(_projectPath, ttFile)) ?? ".cs";
if (!expectedExtension.StartsWith(".", StringComparison.Ordinal))
expectedExtension = "." + expectedExtension;
string fileNameWithoutExtension = ttFile.Substring(0, ttFile.Length - TTExtension.Length);
Expand Down Expand Up @@ -2285,6 +2279,16 @@ List<string> skipFiles
};
itemGroups.AddReference(dotNetFramework, referencesByName);
}
foreach (var str in conf.InteropReferencesByName)
{
var referencesByName = new ItemGroups.Reference
{
Include = str,
Private = project.DependenciesCopyLocal.HasFlag(Project.DependenciesCopyLocalTypes.DotNetReferences) ? default(bool?) : false,
EmbedInteropTypes = true
};
itemGroups.AddReference(dotNetFramework, referencesByName);
}
}
}

Expand All @@ -2300,6 +2304,16 @@ List<string> skipFiles
};
itemGroups.AddReference(dotNetFramework, referencesByNameExternal);
}
foreach (var str in conf.InteropReferencesByNameExternal)
{
var referencesByNameExternal = new ItemGroups.Reference
{
Include = str,
Private = project.DependenciesCopyLocal.HasFlag(Project.DependenciesCopyLocalTypes.DotNetExtensions),
EmbedInteropTypes = true
};
itemGroups.AddReference(dotNetFramework, referencesByNameExternal);
}
}

foreach (var conf in configurations)
Expand All @@ -2316,6 +2330,18 @@ List<string> skipFiles
};
itemGroups.AddReference(dotNetFramework, referencesByPath);
}
foreach (var str in conf.InteropReferencesByPath.Select(Util.GetCapitalizedPath))
{
var referencesByPath = new ItemGroups.Reference
{
Include = Path.GetFileNameWithoutExtension(str),
SpecificVersion = false,
HintPath = Util.PathGetRelative(_projectPathCapitalized, str),
Private = project.DependenciesCopyLocal.HasFlag(Project.DependenciesCopyLocalTypes.ExternalReferences),
EmbedInteropTypes = true
};
itemGroups.AddReference(dotNetFramework, referencesByPath);
}

foreach (var str in project.AdditionalEmbeddedAssemblies.Select(Util.GetCapitalizedPath))
{
Expand Down
1 change: 1 addition & 0 deletions Sharpmake/DebugProjectGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ public DebugProject()
// ensure that no file will be automagically added
SourceFilesExtensions.Clear();
ResourceFilesExtensions.Clear();
NonEmbeddedResourceFilesExtensions.Clear();
PRIFilesExtensions.Clear();
ResourceFiles.Clear();
NoneExtensions.Clear();
Expand Down
3 changes: 3 additions & 0 deletions Sharpmake/Project.Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2819,6 +2819,9 @@ internal void Resolve(string sourceRootPath, Resolver resolver)
public Strings ReferencesByName = new Strings();
public Strings ReferencesByNameExternal = new Strings();
public Strings ReferencesByPath = new Strings();
public Strings InteropReferencesByName = new Strings();
public Strings InteropReferencesByNameExternal = new Strings();
public Strings InteropReferencesByPath = new Strings();
public string ConditionalReferencesByPathCondition = string.Empty;
public Strings ConditionalReferencesByPath = new Strings();
public Strings ForceUsingFiles = new Strings();
Expand Down
20 changes: 19 additions & 1 deletion Sharpmake/Project.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@ public int SourceFilesFiltersCount
public Strings ResourceFiles = new Strings();
public Strings ResourceFilesExtensions = new Strings();

public Strings NonEmbeddedResourceFiles = new Strings();
public Strings NonEmbeddedResourceFilesExtensions = new Strings();

public Strings NatvisFiles = new Strings();
public Strings NatvisFilesExtensions = new Strings(".natvis");

Expand Down Expand Up @@ -233,6 +236,7 @@ internal void Resolve(string sourceRootPath, Resolver resolver)

public Dictionary<string, string> PreImportCustomProperties = new Dictionary<string, string>(); // pre import properties are added before any imports to the project xml as <Key>Value</Key>
public Dictionary<string, string> CustomProperties = new Dictionary<string, string>(); // custom properties are added to the project xml as <Key>Value</Key>
public Dictionary<string, string> PostImportCustomProperties = new Dictionary<string, string>(); // additional custom properties that are added after imports

public Dictionary<string, string> CustomFilterMapping = new Dictionary<string, string>(); /// maps relative source directory to a custom filter path for vcxproj.filter files

Expand Down Expand Up @@ -863,7 +867,7 @@ internal virtual void ResolveSourceFiles(Builder builder)
}

// Only scan directory for files if needed
if (SourceFilesExtensions.Count != 0 || ResourceFilesExtensions.Count != 0 || PRIFilesExtensions.Count != 0 || NoneExtensions.Count != 0 || NoneExtensionsCopyIfNewer.Count != 0)
if (SourceFilesExtensions.Count != 0 || ResourceFilesExtensions.Count != 0 || NonEmbeddedResourceFilesExtensions.Count != 0 || PRIFilesExtensions.Count != 0 || NoneExtensions.Count != 0 || NoneExtensionsCopyIfNewer.Count != 0)
{
string capitalizedSourceRootPath = Util.GetCapitalizedPath(SourceRootPath);

Expand Down Expand Up @@ -895,6 +899,7 @@ internal virtual void ResolveSourceFiles(Builder builder)

AddMatchExtensionFiles(additionalFiles, ref PRIFiles, PRIFilesExtensions);
AddMatchExtensionFiles(additionalFiles, ref ResourceFiles, ResourceFilesExtensions);
AddMatchExtensionFiles(additionalFiles, ref NonEmbeddedResourceFiles, NonEmbeddedResourceFilesExtensions);
AddMatchExtensionFiles(additionalFiles, ref NatvisFiles, NatvisFilesExtensions);
AddMatchExtensionFiles(additionalFiles, ref NoneFiles, NoneExtensions);
AddMatchExtensionFiles(additionalFiles, ref NoneFilesCopyIfNewer, NoneExtensionsCopyIfNewer);
Expand Down Expand Up @@ -923,6 +928,9 @@ internal virtual void ResolveSourceFiles(Builder builder)
AddMatchExtensionFiles(files, ref ResourceFiles, ResourceFilesExtensions);
Util.ResolvePath(SourceRootPath, ref ResourceFiles);

AddMatchExtensionFiles(files, ref NonEmbeddedResourceFiles, NonEmbeddedResourceFilesExtensions);
Util.ResolvePath(SourceRootPath, ref NonEmbeddedResourceFiles);

AddMatchExtensionFiles(files, ref NatvisFiles, NatvisFilesExtensions);
Util.ResolvePath(SourceRootPath, ref NatvisFiles);

Expand Down Expand Up @@ -1965,6 +1973,7 @@ public FastBuildAllProject(Type targetType)
// Disable automatic source files discovery
SourceFilesExtensions.Clear();
ResourceFilesExtensions.Clear();
NonEmbeddedResourceFilesExtensions.Clear();
PRIFilesExtensions.Clear();
}
}
Expand Down Expand Up @@ -2051,6 +2060,13 @@ public enum FileType
Assembly,
File
}

public enum CopyToOutputDirectory
{
Never,
Always,
PreserveNewest
}

public class PublishFile
{
Expand Down Expand Up @@ -2156,6 +2172,7 @@ public static void InitAspNetProject(this CSharpProject aspNetProject)
aspNetProject.ContentExtension.Add(contentExtension);

aspNetProject.ResourceFilesExtensions.Remove(contentExtension);
aspNetProject.NonEmbeddedResourceFilesExtensions.Remove(contentExtension);
aspNetProject.EmbeddedResourceExtensions.Remove(contentExtension);

aspNetProject.NoneExtensions.Add(".pubxml");
Expand Down Expand Up @@ -2248,6 +2265,7 @@ public void AddDefaultReferences(Configuration conf)
public class CSharpProject : Project
{
public Strings ContentExtension = new Strings();
public CopyToOutputDirectory? DefaultContentCopyOperation = null;
public Strings VsctExtension = new Strings(".vsct");
public CSharpProjectType ProjectTypeGuids = CSharpProjectType.Default;
public CSharpProjectSchema ProjectSchema = CSharpProjectSchema.Default;
Expand Down
63 changes: 61 additions & 2 deletions Sharpmake/Util.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,24 @@ public static int GetDeterministicHashCode(this string str)
}
}

static readonly Dictionary<string, Regex> _ttDirectiveRegexes = new Dictionary<string, Regex>();
private static string GetTextTemplateDirectiveParam(string[] templateText, string directive, string paramName)
{
Regex regex = _ttDirectiveRegexes.GetValueOrAdd($"{directive}+{paramName}", () =>
new Regex(@"<#@\s*?" + directive + @"\s+?.*?" + paramName + @"=""(?<paramValue>.*?)"".*?#>", RegexOptions.Compiled)
);

foreach (var line in templateText)
{
Match m = regex.Match(line);
Group g = m.Groups["paramValue"];
if (g != null && g.Success)
return g.Value;
}

return null;
}

/// <summary>
/// Finds the first occurrence of directive and returns the
/// requested param value. Ex:
Expand All @@ -107,14 +125,33 @@ public static int GetDeterministicHashCode(this string str)
/// and return ".txt"
/// </summary>
public static string GetTextTemplateDirectiveParam(string filePath, string directive, string paramName)
{
return GetTextTemplateDirectiveParam(File.ReadAllLines(filePath), directive, paramName);
}

/// <summary>
/// Finds the output type of a template, looking for both the directive form and the Host.SetFileExtension form
/// will match:
/// <#@ output extension=".txt" #>
/// or
/// Host.SetFileExtension(".txt")
/// and return ".txt"
/// </summary>
///
static readonly Regex _ttFileExtensionRegex = new Regex(@"Host.SetFileExtension\(""(?<paramValue>.*?)""\)", RegexOptions.Compiled);
public static string GetTextTemplateOutputExtension(string filePath)
{
string[] templateText = File.ReadAllLines(filePath);

Regex regex = new Regex(@"<#@\s*?" + directive + @"\s+?.*?" + paramName + @"=""(?<paramValue>.*?)"".*?#>");
var output = Util.GetTextTemplateDirectiveParam(templateText, "output", "extension");
if (output != null)
return output;

// alternatively look for host.SetFileExtension

foreach (var line in templateText)
{
Match m = regex.Match(line);
Match m = _ttFileExtensionRegex.Match(line);
Group g = m.Groups["paramValue"];
if (g != null && g.Success)
return g.Value;
Expand Down Expand Up @@ -1481,6 +1518,28 @@ public static Value GetValueOrAdd<Key, Value>(this IDictionary<Key, Value> dicti
return addValue;
}

/// <summary>
/// Extension GetValueOrAdd gets the value at the given key or adds at the given key the value provided by the func argument
/// </summary>
/// <typeparam name="Key">Type of the key</typeparam>
/// <typeparam name="Value">Type of the value</typeparam>
/// <param name="dictionary">dictionary in which to search</param>
/// <param name="key">key of the value</param>
/// <param name="addValueFunc">functon to create the new value</param>
/// <returns>the value at the given key (created or not in this call)</returns>
public static Value GetValueOrAdd<Key, Value>(this IDictionary<Key, Value> dictionary, Key key, Func<Value> addValueFunc)
{
Value value;
if (dictionary.TryGetValue(key, out value) == false)
{
value = addValueFunc();
dictionary.Add(key, value);
}

return value;
}


public static Value AddOrUpdateValue<Key, Value>(this IDictionary<Key, Value> dictionary, Key key, Value newValue, Func<Key, Value, Value, Value> update)
{
Value currentValue;
Expand Down