Skip to content

Commit c8e7eb3

Browse files
committed
Support $-interpolation in modern .NET 9-6, Span, Memory, ...
configure in the Wizard; +New [Ref] packages control and related options
1 parent f03d66c commit c8e7eb3

25 files changed

+955
-76
lines changed

.tools/net.r_eg.DllExport.targets

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,21 @@
4646
<DllExportOurILAsmPath Condition="'$(DllExportOurILAsmPath)'==''">$(DllExportRootPkg)$(DllExportToolsPath)coreclr\</DllExportOurILAsmPath>
4747
<DllExportILAsmCustomPath Condition="'$(DllExportILAsmCustomPath)'==''"></DllExportILAsmCustomPath>
4848

49+
<DllExportTypeRefOptions Condition="'$(DllExportTypeRefOptions)'==''"></DllExportTypeRefOptions>
50+
<DllExportOptClrTypesPath Condition="'$(DllExportOptClrTypesPath)'==''">$(DllExportRootPkg)$(DllExportToolsPath)clrtypes\</DllExportOptClrTypesPath>
51+
4952
<DllExportAttributeFullName Condition="'$(DllExportNamespace)'!=''">$(DllExportNamespace).$(DllExportMetaLibAttr)</DllExportAttributeFullName>
5053
<DllExportAttributeFullName Condition="'$(DllExportNamespace)'==''">$(DllExportMetaLibAttr)</DllExportAttributeFullName>
5154

5255
<DllExportDefPlatform>$(PlatformTarget.ToLower())</DllExportDefPlatform>
5356
<DllExportDefPlatform Condition="'$(DllExportDefPlatform)'==''">anycpu</DllExportDefPlatform>
57+
5458
</PropertyGroup>
5559

60+
<ItemGroup Condition="'$(DllExportTypeRefOptions)'!='' Or '$(DllExportTypeRefOptions)'&gt;'0'">
61+
<Compile Condition="'$([MSBuild]::BitwiseAnd($(DllExportTypeRefOptions), 1))'=='1'" Include="$(DllExportOptClrTypesPath)DefaultInterpolatedStringHandler\.cs" Visible="false" InProject="false" />
62+
</ItemGroup>
63+
5664
<PropertyGroup>
5765
<DllExportCopyToPublishDirectoryType Condition="'$(DllExportCopyToPublishDirectoryType)'==''">PreserveNewest</DllExportCopyToPublishDirectoryType>
5866
</PropertyGroup>
@@ -151,6 +159,7 @@
151159
<DllExportPatches Condition="'$(DllExportPatches)'==''"></DllExportPatches>
152160
<DllExportILAsmExternAsm Condition="'$(DllExportILAsmExternAsm)'==''"></DllExportILAsmExternAsm>
153161
<DllExportILAsmTypeRef Condition="'$(DllExportILAsmTypeRef)'==''"></DllExportILAsmTypeRef>
162+
<DllExportRefPackages Condition="'$(DllExportRefPackages)'==''"></DllExportRefPackages>
154163
</PropertyGroup>
155164

156165
<PropertyGroup Label="EmitDebugSymbols" Condition="'$(DllExportEmitDebugSymbols)'==''">

.vssbe

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,8 @@
331331
"#[IO copy.file(\"$(OutDir:MetaFx)*.dll\", \"$(odir)/tools/raw/lib/net20/\", true)]",
332332
"#[IO copy.file(\"$(OutDir:MetaCor)*.dll\", \"$(odir)/tools/raw/lib/netstd/\", true)]",
333333
"",
334+
"#[IO copy.directory(\"$(dirsrc)DllExport/clrtypes\", \"$(odir)/tools/clrtypes\", true)]",
335+
"",
334336
"##[IO copy.file(\".tools/build.targets\", \"$(odir)/build/net/DllExport.targets\", true)]",
335337
"",
336338
"#[IO copy.file({",

src/DllExport/Core/ILAsm/AsmDirectiveExtension.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,21 @@ internal static class AsmDirectiveExtension
1616
{
1717
public static string Serialize(this IEnumerable<AsmDirectiveAbstract> src)
1818
{
19+
if(src == null) return null;
20+
1921
StringBuilder sb = new();
20-
foreach(AsmDirectiveAbstract directive in src) sb.Append(directive.Serialize());
22+
foreach(AsmDirectiveAbstract directive in src)
23+
{
24+
sb.Append(directive.Serialize());
25+
}
2126
return sb.ToString();
2227
}
2328

2429
public static IEnumerable<T> Deserialize<T>(this string serialized)
2530
where T : AsmDirectiveAbstract, new()
2631
{
2732
if(string.IsNullOrWhiteSpace(serialized)) yield break;
33+
2834
foreach(string raw in serialized.Split([';'], StringSplitOptions.RemoveEmptyEntries))
2935
{
3036
if(string.IsNullOrWhiteSpace(raw)) continue;

src/DllExport/Core/Parsing/Actions/NormalParserAction.cs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System;
1010
using System.Collections.Generic;
1111
using System.Globalization;
12+
using System.IO;
1213
using net.r_eg.DllExport.ILAsm;
1314

1415
namespace net.r_eg.DllExport.Parsing.Actions
@@ -63,32 +64,34 @@ private void EmitCustomExternalAssemlies(ParserStateValues state)
6364

6465
private bool IsExternalAssemblyReference(string trimmedLine, out string assemblyName, out string aliasName)
6566
{
66-
assemblyName = (string)null;
67-
aliasName = (string)null;
68-
if(trimmedLine.Length < ".assembly extern ".Length || !trimmedLine.StartsWith(".assembly extern ", StringComparison.Ordinal))
67+
const string _ASM_EXT_D = ".assembly extern ";
68+
assemblyName = aliasName = null;
69+
70+
if(trimmedLine.Length < _ASM_EXT_D.Length || !trimmedLine.StartsWith(_ASM_EXT_D, StringComparison.Ordinal))
6971
{
7072
return false;
7173
}
72-
List<string> identifiers = new List<string>();
73-
IlParsingUtils.ParseIlSnippet(trimmedLine.Substring(".assembly extern ".Length), ParsingDirection.Forward, (Func<IlParsingUtils.IlSnippetLocation, bool>)(current => {
74-
if(!current.WithinString && (int)current.CurrentChar == 39 && current.LastIdentifier != null)
74+
75+
List<string> identifiers = [];
76+
IlParsingUtils.ParseIlSnippet
77+
(
78+
trimmedLine.Substring(_ASM_EXT_D.Length),
79+
ParsingDirection.Forward,
80+
current =>
7581
{
76-
identifiers.Add(current.LastIdentifier);
77-
if(identifiers.Count > 1)
82+
if(!current.WithinString && current.CurrentChar == '\'' && current.LastIdentifier != null)
7883
{
79-
return false;
84+
identifiers.Add(current.LastIdentifier);
85+
if(identifiers.Count > 1) return false;
8086
}
81-
}
82-
return true;
83-
}), (Action<IlParsingUtils.IlSnippetFinalizaton>)null);
84-
if(identifiers.Count == 0)
85-
{
86-
return false;
87-
}
88-
if(identifiers.Count > 0)
89-
{
90-
assemblyName = identifiers[0];
91-
}
87+
return true;
88+
},
89+
finalization: null
90+
);
91+
92+
if(identifiers.Count < 1) return false;
93+
94+
assemblyName = identifiers[0];
9295
aliasName = identifiers.Count > 1 ? identifiers[1] : identifiers[0];
9396
return true;
9497
}

src/DllExport/Core/TypeRefOptions.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*!
2+
* Copyright (c) Robert Giesecke
3+
* Copyright (c) Denis Kuzmin <[email protected]> github/3F
4+
* Copyright (c) DllExport contributors https://github.com/3F/DllExport/graphs/contributors
5+
* Licensed under the MIT License (MIT).
6+
* See accompanying LICENSE.txt file or visit https://github.com/3F/DllExport
7+
*/
8+
9+
using System;
10+
11+
namespace net.r_eg.DllExport
12+
{
13+
[Flags]
14+
public enum TypeRefOptions: long
15+
{
16+
None,
17+
18+
/// <summary>
19+
/// $-interpolation using predefined DllExport's stub implementation.
20+
/// </summary>
21+
DefaultInterpolatedStringHandler = 0x01,
22+
}
23+
}

src/DllExport/Core/Utilities.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
using System;
10+
using System.Collections.Generic;
1011
using System.IO;
1112
using System.Linq.Expressions;
1213
using System.Reflection;

src/DllExport/Wizard/Gears/PreProcGear.cs

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
using System;
99
using System.Collections.Generic;
10+
using System.IO;
1011
using System.Linq;
1112
using System.Text;
1213
using Microsoft.Build.Construction;
@@ -54,6 +55,7 @@ public void Uninstall(bool hardReset)
5455
{
5556
prj.RemovePackageReferences(tool.name);
5657
}
58+
prj.RemovePackageReferences(id: null, wzstrict: true);
5759
}
5860

5961
private void CfgPreProc(CmdType type)
@@ -65,6 +67,8 @@ private void CfgPreProc(CmdType type)
6567

6668
_FxCorArgBuilder sb = new(capacity: 100);
6769

70+
sb.AppendBoth(Path.Combine(ILMERGE_TMP, "$(TargetName).dll")); //F-315, keep it first
71+
6872
if((type & CmdType.Conari) == CmdType.Conari)
6973
{
7074
Log.send(this, $"Merge Conari: {incConari}");
@@ -78,6 +82,17 @@ private void CfgPreProc(CmdType type)
7882
sb.AppendCor("/lib:\"$(_PathToResolvedTargetingPack)\"");
7983
}
8084

85+
if((type & CmdType.MergeRefPkg) == CmdType.MergeRefPkg)
86+
{
87+
foreach(RefPackage rp in Config.RefPackages)
88+
{
89+
Log.send(this, $"Merge [Ref]: {rp.Name} {rp.Version}");
90+
// NOTE: PrivateAssets cannot guarantee delivery of assemblies because some packages contains `_._` stubs
91+
XProject.AddPackageIfNotExists(rp.Name, rp.Version, prj.GetMeta(generatePath: true));
92+
sb.AppendBoth(rp.Name + ".dll");
93+
}
94+
}
95+
8196
if((type & (CmdType.ILMerge | CmdType.ILRepack)) != 0)
8297
{
8398
_MergeTool tool = GetMergeTool(type);
@@ -118,13 +133,21 @@ private void AddPreProcTarget(string fxCmd, string corCmd, CmdType type)
118133

119134
bool ignoreErr = (type & CmdType.IgnoreErr) == CmdType.IgnoreErr;
120135

121-
target.AddTask("Copy", ignoreErr, t =>
136+
if((type & CmdType.MergeRefPkg) == CmdType.MergeRefPkg)
122137
{
123-
t.SetParameter("SourceFiles", $"$({MSBuildProperties.DXP_METALIB_FPATH})");
124-
t.SetParameter("DestinationFolder", $"$({MSBuildProperties.PRJ_TARGET_DIR})");
125-
t.SetParameter("SkipUnchangedFiles", "true");
126-
t.SetParameter("OverwriteReadOnlyFiles", "true");
127-
});
138+
foreach(RefPackage rp in Config.RefPackages)
139+
{
140+
string src = $"$(Pkg{rp.Name.Trim().Replace('.', '_')})";
141+
src = !rp.HasPath
142+
? src = Path.Combine(src, "lib", rp.TfmOrPath, rp.Name + ".dll")
143+
: Path.Combine(src, rp.TfmOrPath ?? rp.Name + ".dll");
144+
145+
Log.send(this, $"[Ref] Add Copy Task for {rp.Name}: {src}", Message.Level.Trace);
146+
AddCopyTo(target, src, "$(TargetDir)", ignoreErr);
147+
}
148+
}
149+
150+
AddCopyTo(target, $"$({MSBuildProperties.DXP_METALIB_FPATH})", $"$({MSBuildProperties.PRJ_TARGET_DIR})", ignoreErr);
128151

129152
AddILMergeWrapper(target, ignoreErr, _=>
130153
{
@@ -146,29 +169,40 @@ private void AddPreProcTarget(string fxCmd, string corCmd, CmdType type)
146169

147170
private void AddILMergeWrapper(ProjectTargetElement target, bool continueOnError, Action<ProjectTargetElement> act)
148171
{
149-
AddMoveTask(target, "$(TargetPath)", $"$(TargetDir){ILMERGE_TMP}\\$(TargetName).dll", continueOnError);
150-
AddMoveTask(target, "$(TargetDir)$(TargetName).pdb", $"$(TargetDir){ILMERGE_TMP}\\$(TargetName).pdb", continueOnError);
172+
AddMoveAs(target, "$(TargetPath)", $"$(TargetDir){ILMERGE_TMP}\\$(TargetName).dll", continueOnError);
173+
AddMoveAs(target, "$(TargetDir)$(TargetName).pdb", $"$(TargetDir){ILMERGE_TMP}\\$(TargetName).pdb", continueOnError);
151174

152175
act?.Invoke(target);
153176
target.AddTask("RemoveDir", continueOnError, t => t.SetParameter("Directories", "$(TargetDir)" + ILMERGE_TMP));
154177
}
155178

156-
private void AddMoveTask(ProjectTargetElement target, string src, string dst, bool continueOnError)
179+
private ProjectTaskElement AddExecTask(ProjectTargetElement target, string cmd, string condition, bool continueOnError)
157180
{
158-
target.AddTask("Move", continueOnError, t =>
181+
return target.AddTask("Exec", condition, continueOnError, t =>
159182
{
160-
t.SetParameter("SourceFiles", src);
161-
t.SetParameter("DestinationFiles", dst);
162-
t.SetParameter("OverwriteReadOnlyFiles", "true");
183+
t.SetParameter("Command", cmd ?? throw new ArgumentNullException(nameof(cmd)));
184+
t.SetParameter("WorkingDirectory", $"$({MSBuildProperties.PRJ_TARGET_DIR})");
163185
});
164186
}
165187

166-
private ProjectTaskElement AddExecTask(ProjectTargetElement target, string cmd, string condition, bool continueOnError)
188+
private void AddCopyTo(ProjectTargetElement target, string src, string dstFolder, bool ignoreErr)
189+
=> AddCopyOrMoveTask(copy: true, target, src, dstFolder, ignoreErr);
190+
191+
private void AddMoveAs(ProjectTargetElement target, string src, string dstFiles, bool ignoreErr)
192+
=> AddCopyOrMoveTask(copy: false, target, src, dstFiles, ignoreErr);
193+
194+
private void AddCopyOrMoveTask(bool copy, ProjectTargetElement target, string src, string dst, bool ignoreErr)
167195
{
168-
return target.AddTask("Exec", condition, continueOnError, t =>
196+
target.AddTask(copy ? "Copy" : "Move", ignoreErr, t =>
169197
{
170-
t.SetParameter("Command", cmd ?? throw new ArgumentNullException(nameof(cmd)));
171-
t.SetParameter("WorkingDirectory", $"$({MSBuildProperties.PRJ_TARGET_DIR})");
198+
t.SetParameter("SourceFiles", src);
199+
if(copy)
200+
{
201+
t.SetParameter("DestinationFolder", dst);
202+
t.SetParameter("SkipUnchangedFiles", "true");
203+
}
204+
else t.SetParameter("DestinationFiles", dst);
205+
t.SetParameter("OverwriteReadOnlyFiles", "true");
172206
});
173207
}
174208

@@ -198,8 +232,7 @@ private string FormatPreProcCmd(CmdType type, StringBuilder sb)
198232
StringBuilder ilm = new(100);
199233
ilm.Append($"{tool.exe} ");
200234
ilm.Append(cmd);
201-
ilm.Append(" " + ILMERGE_TMP);
202-
ilm.Append("\\$(TargetName).dll /out:$(TargetFileName)");
235+
ilm.Append(" /out:$(TargetFileName)");
203236
if((type & CmdType.DebugInfo) == 0) ilm.Append(" /ndebug");
204237
if((type & CmdType.Log) == CmdType.Log) ilm.Append($" /log:$(TargetFileName).{tool.name}.log");
205238
return ilm.ToString();

src/DllExport/Wizard/IProjectSvc.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ internal interface IProjectSvc: IProject
2828

2929
IProjectSvc RemovePackageReferences(string id, Func<Item, bool> opt = null, bool wzstrict = true);
3030

31-
IEnumerable<KeyValuePair<string, string>> GetMeta(bool privateAssets = false, bool hide = false);
31+
IEnumerable<KeyValuePair<string, string>> GetMeta
32+
(
33+
bool privateAssets = false, bool hide = false, bool generatePath = false
34+
);
3235
}
3336
}

src/DllExport/Wizard/IUserConfig.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,17 @@ public interface IUserConfig
8585
/// </summary>
8686
List<ILAsm.TypeRefDirective> TypeRefDirectives { get; set; }
8787

88+
/// <summary>
89+
/// Options for .typeref like $-interpolation using predefined stub implementation etc.
90+
/// </summary>
91+
TypeRefOptions TypeRefOptions { get; set; }
92+
93+
/// <summary>
94+
/// List of package references to provide the specified assemblies along with the module being modified
95+
/// at the pre-processing stage.
96+
/// </summary>
97+
List<RefPackage> RefPackages { get; set; }
98+
8899
/// <summary>
89100
/// Adds to top new namespace into Namespaces property.
90101
/// </summary>
@@ -111,5 +122,12 @@ public interface IUserConfig
111122
/// <param name="onFailed">Execute action if the directive is invalid.</param>
112123
/// <returns>true if all directives are valid.</returns>
113124
bool ValidateTypeRefDirectives(Func<string, bool> onFailed);
125+
126+
/// <summary>
127+
/// Validate <see cref="RefPackages"/> records.
128+
/// </summary>
129+
/// <param name="onFailed">Execute action if record is invalid.</param>
130+
/// <returns>true if all records are valid.</returns>
131+
bool ValidateRefPackages(Func<string, bool> onFailed);
114132
}
115133
}

src/DllExport/Wizard/MSBuildProperties.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,27 @@ public struct MSBuildProperties
136136
/// <summary>
137137
/// .assembly extern ...
138138
/// </summary>
139+
/// <remarks>Serialized array.</remarks>
139140
public const string DXP_ILASM_EXTERN_ASM = "DllExportILAsmExternAsm";
140141

141142
/// <summary>
142143
/// .typeref ...
143144
/// </summary>
145+
/// <remarks>Serialized array.</remarks>
144146
public const string DXP_ILASM_TYPEREF = "DllExportILAsmTypeRef";
145147

148+
/// <summary>
149+
/// Package references at the pre-processing stage.
150+
/// </summary>
151+
/// <remarks>Serialized array.</remarks>
152+
public const string DXP_REF_PACKAGES = "DllExportRefPackages";
153+
154+
/// <summary>
155+
/// Additional features for .typeref like supporting $ interpolation using predefined stub implementation etc.
156+
/// </summary>
157+
/// <remarks>Flags.</remarks>
158+
public const string DXP_TYPEREF_OPTIONS = "DllExportTypeRefOptions";
159+
146160
/// <summary>
147161
/// Meta library full path to file.
148162
/// </summary>

0 commit comments

Comments
 (0)