Skip to content

Commit fb15a3d

Browse files
vitek-karasMichalStrehovsky
authored andcommitted
Add support for feature switches (#123)
This adds command line and test support for feature switches. And enables them in descriptors. Some tests added, no properties/events as our descriptor parsing doesn't support properties/events yet.
1 parent 5074c41 commit fb15a3d

13 files changed

Lines changed: 167 additions & 13 deletions

File tree

src/coreclr/tools/ILTrim/ILTrim.Exe/Program.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ static void Main(string[] args)
2323
string logFile = null;
2424
int? parallelism = null;
2525
bool libraryMode = false;
26+
IReadOnlyList<KeyValuePair<string, bool>> featureSwitches = null;
2627

2728
ArgumentSyntax argSyntax = ArgumentSyntax.Parse(args, syntax =>
2829
{
@@ -64,17 +65,30 @@ static void Main(string[] args)
6465

6566
syntax.DefineOption("library", ref libraryMode, "Use library mode for the input assembly");
6667

68+
syntax.DefineOptionList<KeyValuePair<string, bool>>("feature", ref featureSwitches, requireValue: false, help: "Feature switch", valueConverter: (value) =>
69+
{
70+
int sep = value.IndexOf('=');
71+
if (sep == -1)
72+
throw new CommandLineException("The format of --feature value is <featureswitch>=<value>");
73+
74+
string fsName = value.Substring(0, sep);
75+
string fsValue = value.Substring(sep + 1);
76+
return new KeyValuePair<string, bool>(fsName, bool.Parse(fsValue));
77+
});
78+
6779
syntax.DefineParameter("input", ref input, "The input assembly");
6880
});
6981

7082
if (input == null)
7183
throw new CommandLineException("Input assembly is required");
7284

85+
Dictionary<string, bool> featureSwitchesDictionary = new(featureSwitches);
7386
var settings = new TrimmerSettings(
7487
MaxDegreeOfParallelism: parallelism,
7588
LogStrategy: logStrategy,
7689
LogFile: logFile,
77-
LibraryMode: libraryMode);
90+
LibraryMode: libraryMode,
91+
FeatureSwitches: featureSwitchesDictionary);
7892
Trimmer.TrimAssembly(
7993
input.Trim(),
8094
trimAssemblies,
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using System;
2+
using Mono.Linker.Tests.Cases.Expectations.Assertions;
3+
using Mono.Linker.Tests.Cases.Expectations.Metadata;
4+
5+
namespace Mono.Linker.Tests.Cases.FeatureSettings
6+
{
7+
#pragma warning disable 169
8+
#pragma warning disable 67
9+
10+
//[SetupLinkerDescriptorFile ("FeatureDescriptorsGlobalTrue.xml")]
11+
//[SetupLinkerDescriptorFile ("FeatureDescriptorsGlobalFalse.xml")]
12+
[SetupCompileResource ("FeatureDescriptors.xml", "ILLink.Descriptors.xml")]
13+
//[SetupLinkerArgument ("--feature", "GlobalCondition", "true")]
14+
[SetupLinkerArgument ("--feature", "AssemblyCondition", "false")]
15+
[SetupLinkerArgument ("--feature", "TypeCondition", "true")]
16+
[SetupLinkerArgument ("--feature", "MethodCondition", "false")]
17+
[SetupLinkerArgument ("--feature", "FieldCondition", "true")]
18+
[SetupLinkerArgument ("--feature", "PropertyCondition", "false")]
19+
[SetupLinkerArgument ("--feature", "EventCondition", "true")]
20+
public class FeatureDescriptors
21+
{
22+
public static void Main ()
23+
{
24+
}
25+
26+
[Kept]
27+
static bool DefaultConditionTrue;
28+
static bool DefaultConditionFalse;
29+
30+
//[Kept] // Disabled for now since we don't support multiple descriptors (command line passed descriptors)
31+
//static bool GlobalConditionTrue;
32+
//static bool GlobalConditionFalse;
33+
34+
static bool AssemblyConditionTrue;
35+
[Kept]
36+
static bool AssemblyConditionFalse;
37+
38+
[Kept]
39+
static bool TypeConditionTrue;
40+
static bool TypeConditionFalse;
41+
42+
43+
static void MethodConditionTrue ()
44+
{
45+
}
46+
47+
[Kept]
48+
static void MethodConditionFalse ()
49+
{
50+
}
51+
52+
[Kept]
53+
static bool FieldConditionTrue;
54+
static bool FieldConditionFalse;
55+
56+
static bool PropertyConditionTrue { get; set; }
57+
//[Kept]
58+
//[KeptBackingField]
59+
static bool PropertyConditionFalse { /*[Kept]*/ get; /*[Kept]*/ set; }
60+
61+
//[Kept]
62+
//[KeptBackingField]
63+
//[KeptEventAddMethod]
64+
//[KeptEventRemoveMethod]
65+
static event EventHandler EventConditionTrue;
66+
static event EventHandler EVentConditionFalse;
67+
}
68+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<linker>
2+
<!-- Check that the feature attribute can be used on the assembly element. -->
3+
<assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" feature="AssemblyCondition" featurevalue="false">
4+
<type fullname="Mono.Linker.Tests.Cases.FeatureSettings.FeatureDescriptors">
5+
<field name="AssemblyConditionFalse" />
6+
</type>
7+
<!-- Or on the type element. -->
8+
<type fullname="Mono.Linker.Tests.Cases.FeatureSettings.FeatureDescriptors" feature="TypeCondition" featurevalue="true">
9+
<field name="TypeConditionTrue" />
10+
<!-- Or on the method element. -->
11+
<method signature="System.Void MethodConditionFalse()" feature="MethodCondition" featurevalue="false" />
12+
<!-- Else case -->
13+
<method signature="System.Void MethodConditionTrue()" feature="MethodCondition" featurevalue="true" />
14+
<!-- Or on the field element. -->
15+
<field name="FieldConditionTrue" feature="FieldCondition" featurevalue="true" />
16+
<!-- Else case -->
17+
<field name="FieldConditionFalse" feature="FieldCondition" featurevalue="false" />
18+
<!-- Or on the property element. -->
19+
<property name="PropertyConditionFalse" feature="PropertyCondition" featurevalue="false" />
20+
<!-- Else case -->
21+
<property name="PropertyConditionTrue" feature="PropertyCondition" featurevalue="true" />
22+
<!-- Or on the event element. -->
23+
<event name="EventConditionTrue" feature="EventCondition" featurevalue="true" />
24+
<!-- Else case -->
25+
<event name="EventConditionFalse" feature="EventCondition" featurevalue="false" />
26+
</type>
27+
<!-- Else case for the type feature attribute -->
28+
<type fullname="Mono.Linker.Tests.Cases.FeatureSettings.FeatureDescriptors" feature="TypeCondition" featurevalue="false">
29+
<field name="TypeConditionFalse" />
30+
</type>
31+
</assembly>
32+
<!-- Else case for the assembly feature attribute -->
33+
<assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" feature="AssemblyCondition" featurevalue="true">
34+
<type fullname="Mono.Linker.Tests.Cases.FeatureSettings.FeatureDescriptors">
35+
<field name="AssemblyConditionTrue" />
36+
</type>
37+
</assembly>
38+
<!-- Check that a feature condition can be used by default -->
39+
<assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" feature="DefaultCondition" featurevalue="true" featuredefault="true">
40+
<type fullname="Mono.Linker.Tests.Cases.FeatureSettings.FeatureDescriptors">
41+
<field name="DefaultConditionTrue" />
42+
</type>
43+
</assembly>
44+
<!-- Else case for the default condition -->
45+
<assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" feature="DefaultCondition" featurevalue="false">
46+
<type fullname="Mono.Linker.Tests.Cases.FeatureSettings.FeatureDescriptors">
47+
<field name="DefaultConditionFalse" />
48+
</type>
49+
</assembly>
50+
</linker>

src/coreclr/tools/ILTrim/ILTrim.Tests/TestCases/TestDatabase.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ public static IEnumerable<object[]> LinkXml()
2525
return TestNamesBySuiteName("LinkXml");
2626
}
2727

28+
public static IEnumerable<object[]> FeatureSettings()
29+
{
30+
return TestNamesBySuiteName("FeatureSettings");
31+
}
32+
2833
public static TestCaseCollector CreateCollector ()
2934
{
3035
GetDirectoryPaths (out string rootSourceDirectory, out string testCaseAssemblyPath);

src/coreclr/tools/ILTrim/ILTrim.Tests/TestCases/TestSuites.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ public void LinkXml(string t)
2727
Run(t);
2828
}
2929

30+
[Theory]
31+
[MemberData(nameof(TestDatabase.FeatureSettings), MemberType = typeof(TestDatabase))]
32+
public void FeatureSettings(string t)
33+
{
34+
Run(t);
35+
}
36+
3037
protected virtual void Run (string testName)
3138
{
3239
TestCase testCase = TestDatabase.GetTestCaseFromName(testName) ?? throw new InvalidOperationException ($"Unknown test {testName}");

src/coreclr/tools/ILTrim/ILTrim.Tests/TestCasesRunner/TrimmerDriver.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ public class TrimmerDriver
1212
public void Trim (TrimmerOptions options)
1313
{
1414
TrimmerSettings settings = new TrimmerSettings(
15-
LibraryMode: options.IsLibraryMode);
15+
LibraryMode: options.IsLibraryMode,
16+
FeatureSwitches: options.FeatureSwitches);
1617
Trimmer.TrimAssembly(
1718
options.InputPath,
1819
options.AdditionalLinkAssemblies,

src/coreclr/tools/ILTrim/ILTrim.Tests/TestCasesRunner/TrimmerOptions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ public class TrimmerOptions
1212
public string? OutputDirectory { get; set; }
1313
public List<string> ReferencePaths { get; set; } = new List<string> ();
1414
public bool IsLibraryMode { get; set; } = false;
15+
public Dictionary<string, bool> FeatureSwitches { get; set; } = new Dictionary<string, bool>();
1516
}
1617
}

src/coreclr/tools/ILTrim/ILTrim.Tests/TestCasesRunner/TrimmerOptionsBuilder.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ public virtual void AddAdditionalArgument (string flag, string[] values)
118118
{
119119
if(flag == "-a" && values.Contains("library"))
120120
Options.IsLibraryMode = true;
121+
else if (flag == "--feature")
122+
{
123+
Options.FeatureSwitches.Add(values[0], bool.Parse(values[1]));
124+
}
121125
}
122126

123127
public virtual void ProcessTestInputAssembly (NPath inputAssemblyPath)

src/coreclr/tools/ILTrim/ILTrim/DependencyAnalysis/NodeFactory.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ namespace ILTrim.DependencyAnalysis
1818
public sealed class NodeFactory
1919
{
2020
IReadOnlySet<string> _trimAssemblies { get; }
21-
bool _libraryTrimMode { get; }
21+
public TrimmerSettings Settings { get; }
2222

23-
public NodeFactory(IEnumerable<string> trimAssemblies, bool libraryTrimMode)
23+
public NodeFactory(IEnumerable<string> trimAssemblies, TrimmerSettings settings)
2424
{
2525
_trimAssemblies = new HashSet<string>(trimAssemblies);
26-
_libraryTrimMode = libraryTrimMode;
26+
Settings = settings;
2727
}
2828

2929
/// <summary>
@@ -288,7 +288,7 @@ public bool IsModuleTrimmed(EcmaModule module)
288288

289289
public bool IsModuleTrimmedInLibraryMode()
290290
{
291-
return _libraryTrimMode;
291+
return Settings.LibraryMode;
292292
}
293293

294294
private struct HandleKey<T> : IEquatable<HandleKey<T>> where T : struct, IEquatable<T>

src/coreclr/tools/ILTrim/ILTrim/DependencyAnalysis/TokenBased/ILLinkDescriptorDependencyAnalyzer.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,20 @@ namespace ILTrim.DependencyAnalysis
1616
internal class ILLinkDescriptorDependencyAnalyzer : ManifestResourceNode.IManifestResourceDependencyAnalyzer
1717
{
1818
private readonly EcmaModule _module;
19-
private readonly IReadOnlyDictionary<string, bool> _featureSwitches;
2019

21-
public ILLinkDescriptorDependencyAnalyzer(EcmaModule module, IReadOnlyDictionary<string, bool> featureSwitches)
20+
public ILLinkDescriptorDependencyAnalyzer(EcmaModule module)
2221
{
2322
_module = module;
24-
_featureSwitches = featureSwitches;
2523
}
2624

2725
public DependencyList GetDependencies(NodeFactory factory, Stream content)
2826
{
29-
return DescriptorReader.GetDependencies(_module.Context, XmlReader.Create(content), _module, _featureSwitches, factory);
27+
return DescriptorReader.GetDependencies(
28+
_module.Context,
29+
XmlReader.Create(content),
30+
_module,
31+
factory.Settings.FeatureSwitches,
32+
factory);
3033
}
3134

3235
private class DescriptorReader : ILCompiler.ProcessLinkerXmlBase

0 commit comments

Comments
 (0)