From 8c20cb2bbe7e26df929bef1c7bae5d45b06f7c5a Mon Sep 17 00:00:00 2001 From: Kouji Matsui Date: Mon, 13 May 2024 16:22:37 +0900 Subject: [PATCH] Added prepend execution base path feature. --- chibicc-cil-toolchain.sln | 7 + .../chibild.core.Tests/LinkerTestRunner.cs | 2 + ...LinkerTests.PrependSearchPath.verified.txt | 67 +++++++ chibild/chibild.core.Tests/LinkerTests.cs | 15 ++ .../chibild.core.Tests/LinkerTests_Common.cs | 7 +- .../artifacts/prependertestbed.dll | Bin 0 -> 3584 bytes .../artifacts/prependertestbed.pdb | Bin 0 -> 1716 bytes .../chibild.core.Tests.csproj | 8 - chibild/chibild.core/CilLinker.cs | 6 +- .../Generating/CodeGenerator_Emit.cs | 182 +++++++++++++----- chibild/chibild.core/LinkerOptions.cs | 3 + chibild/chibild.core/cli/CliOptions.cs | 162 +++++++--------- .../chibild/Properties/launchSettings.json | 4 +- .../prependertestbed/prependertestbed.csproj | 14 ++ chibild/misc/prependertestbed/text.cs | 18 ++ toolchain.common/IO/ObjectStreamUtilities.cs | 28 ++- 16 files changed, 365 insertions(+), 158 deletions(-) create mode 100644 chibild/chibild.core.Tests/LinkerTests.PrependSearchPath.verified.txt create mode 100644 chibild/chibild.core.Tests/artifacts/prependertestbed.dll create mode 100644 chibild/chibild.core.Tests/artifacts/prependertestbed.pdb create mode 100644 chibild/misc/prependertestbed/prependertestbed.csproj create mode 100644 chibild/misc/prependertestbed/text.cs diff --git a/chibicc-cil-toolchain.sln b/chibicc-cil-toolchain.sln index a404c3a..614f119 100644 --- a/chibicc-cil-toolchain.sln +++ b/chibicc-cil-toolchain.sln @@ -62,6 +62,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "toolchain.common", "toolcha EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "chibias.core", "chibias\chibias.core\chibias.core.csproj", "{CC1EC762-ED84-47A5-914F-5B5DD820D980}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "prependertestbed", "chibild\misc\prependertestbed\prependertestbed.csproj", "{C19D59AA-7D72-4DD0-8A0A-A5B664E0EE74}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -128,6 +130,10 @@ Global {CC1EC762-ED84-47A5-914F-5B5DD820D980}.Debug|Any CPU.Build.0 = Debug|Any CPU {CC1EC762-ED84-47A5-914F-5B5DD820D980}.Release|Any CPU.ActiveCfg = Release|Any CPU {CC1EC762-ED84-47A5-914F-5B5DD820D980}.Release|Any CPU.Build.0 = Release|Any CPU + {C19D59AA-7D72-4DD0-8A0A-A5B664E0EE74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C19D59AA-7D72-4DD0-8A0A-A5B664E0EE74}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C19D59AA-7D72-4DD0-8A0A-A5B664E0EE74}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C19D59AA-7D72-4DD0-8A0A-A5B664E0EE74}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -147,6 +153,7 @@ Global {9C384CE3-4BD5-44B9-AE59-F0159D20D302} = {5F40AA75-7382-487D-B2F7-3D07DC68C566} {EDFB3E84-7FD5-414D-9A17-378C62CA3F35} = {5F40AA75-7382-487D-B2F7-3D07DC68C566} {CC1EC762-ED84-47A5-914F-5B5DD820D980} = {A4C160C3-9D6F-4B0C-9A66-CA5FE5264672} + {C19D59AA-7D72-4DD0-8A0A-A5B664E0EE74} = {2D17624C-B2B8-4343-94BF-34056C7FD4EC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {50B7704D-EFFD-4789-90DD-F594F80C2B97} diff --git a/chibild/chibild.core.Tests/LinkerTestRunner.cs b/chibild/chibild.core.Tests/LinkerTestRunner.cs index fe672c8..8175fff 100644 --- a/chibild/chibild.core.Tests/LinkerTestRunner.cs +++ b/chibild/chibild.core.Tests/LinkerTestRunner.cs @@ -39,6 +39,7 @@ public static string RunCore( string[] chibildSourceCodes, string[]? additionalReferencePaths, string? injectToAssemblyPath, + string[]? prependExecutionSearchPaths, Func creationOptionsF, string memberName) { @@ -116,6 +117,7 @@ public static string RunCore( IsDeterministic = true, ApplyOptimization = false, CreationOptions = creationOptions, + PrependExecutionSearchPaths = prependExecutionSearchPaths ?? Array.Empty(), }, injectToAssemblyPath, basePath, diff --git a/chibild/chibild.core.Tests/LinkerTests.PrependSearchPath.verified.txt b/chibild/chibild.core.Tests/LinkerTests.PrependSearchPath.verified.txt new file mode 100644 index 0000000..396589f --- /dev/null +++ b/chibild/chibild.core.Tests/LinkerTests.PrependSearchPath.verified.txt @@ -0,0 +1,67 @@ + +// .NET IL Disassembler. Version 8.0.0 + + + +// Metadata version: v4.0.30319 +.assembly extern mscorlib +{ + .publickey = (00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 ) + .ver 4:0:0:0 +} +.assembly extern prependertestbed +{ + .ver 0:0:0:0 +} +.assembly output +{ + .custom instance void [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = ( 01 00 1A 2E 4E 45 54 46 72 61 6D 65 77 6F 72 6B // ....NETFramework + 2C 56 65 72 73 69 6F 6E 3D 76 34 2E 35 00 00 ) // ,Version=v4.5.. + .ver 1:0:0:0 +} +.module output.dll +.imagebase 0x00400000 +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 // WINDOWS_CUI +.corflags 0x00000001 // ILONLY + + +// ================== GLOBAL METHODS ========================= + +.method assembly static int32 _start() cil managed +{ + .entrypoint + // Code size 26 (0x1a) + .maxstack 8 + IL_0000: ldstr "aaa/bin" + IL_0005: call void [prependertestbed]C.text::__prepend_path_env(string) + IL_000a: ldstr "bbb/bin" + IL_000f: call void [prependertestbed]C.text::__prepend_path_env(string) + IL_0014: call int32 C.text::main() + IL_0019: ret +} // end of global method _start + + +// ============================================================= + + +// =============== CLASS MEMBERS DECLARATION =================== + +.class public abstract auto ansi sealed C.text + extends [mscorlib]System.Object +{ + .method public static int32 main() cil managed + { + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldc.i4.1 + IL_0001: ret + } // end of method text::main + +} // end of class C.text + + +// ============================================================= + +// *********** DISASSEMBLY COMPLETE *********************** diff --git a/chibild/chibild.core.Tests/LinkerTests.cs b/chibild/chibild.core.Tests/LinkerTests.cs index 63ae3ae..2bca53b 100644 --- a/chibild/chibild.core.Tests/LinkerTests.cs +++ b/chibild/chibild.core.Tests/LinkerTests.cs @@ -2980,4 +2980,19 @@ call int64_add injectToAssemblyPath); return Verify(actual); } + + [Test] + public Task PrependSearchPath() + { + var combineToAssemblyPath = Path.Combine( + LinkerTestRunner.ArtifactsBasePath, "prependertestbed.dll"); + var actual = Run(@" + .function public int32() main + ldc.i4.1 + ret", + assemblyType: AssemblyTypes.Exe, + prependExecutionSearchPaths: new[] { "aaa/bin", "bbb/bin" }, + additionalReferencePaths: new[] { combineToAssemblyPath }); + return Verify(actual); + } } diff --git a/chibild/chibild.core.Tests/LinkerTests_Common.cs b/chibild/chibild.core.Tests/LinkerTests_Common.cs index 6489562..e136811 100644 --- a/chibild/chibild.core.Tests/LinkerTests_Common.cs +++ b/chibild/chibild.core.Tests/LinkerTests_Common.cs @@ -21,11 +21,13 @@ private string Run( string[]? additionalReferencePaths = null, AssemblyTypes assemblyType = AssemblyTypes.Dll, string targetFrameworkMoniker = "net45", - [CallerMemberName] string memberName = null!) => + string[]? prependExecutionSearchPaths = null, + [CallerMemberName] string memberName = null!) => LinkerTestRunner.RunCore( chibildSourceCodes, additionalReferencePaths, null, + prependExecutionSearchPaths, () => { var appHostTemplatePath = Path.GetFullPath( @@ -49,12 +51,14 @@ private string Run( string[]? additionalReferencePaths = null, AssemblyTypes assemblyType = AssemblyTypes.Dll, string targetFrameworkMoniker = "net45", + string[]? prependExecutionSearchPaths = null, [CallerMemberName] string memberName = null!) => this.Run( new[] { chibildSourceCode }, additionalReferencePaths, assemblyType, targetFrameworkMoniker, + prependExecutionSearchPaths, memberName); private string RunInjection( @@ -66,6 +70,7 @@ private string RunInjection( new[] { chibildSourceCode }, additionalReferencePaths, injectToAssemblyPath, + null, () => null, memberName); } diff --git a/chibild/chibild.core.Tests/artifacts/prependertestbed.dll b/chibild/chibild.core.Tests/artifacts/prependertestbed.dll new file mode 100644 index 0000000000000000000000000000000000000000..18169acac0a7a7cfb7aad7c93275b6c4f38dd9de GIT binary patch literal 3584 zcmeHJO^g&p6#jbuTozeDeiSj-FyJrDjIt0R{><*qvMlajc81j$$!w#Yh zteRzGab*&PZZ3WUsmZ=t9rI2t|y0pQKKD|bNxq}t6jlXbET05x~P#x z^0t$iY&kYywH~*{af>2>0rM277i!1sDS^s=t4~Bxkv7rqgbZ@Px5+#a7ibo^ox<4^ z@c4rAZwySJdl9Ug@_|KiI#MSi%26j7Z90ML)~9+l9fW~RvyLstfo#-b#}ui~r32;q z1WK%!WfNaoV4qM97-){0{e;w&B(b%j6GfBz(GD1*yb0>T!x$(W9550O62kGmbT+*! zyX(=t;;<7g`EP8gmw_@D>SIe4qQLPgp&;I4?2=~cPyrusEZdhFJ~WbN|0(6OA`iHJ ziMx^$SKAt7Hy=tt+CZh)%IW{n9iuqlb#%Ar&z$c96BFAgUyNJ4o9y~<88fmOVihM10 zkZ-~>kwf$g#tws_8Qh zPz41Q9CvILCh2hv)`H?h>8P?J=r3z#CMm{@EI*^X<8c)qarV!i{`#fiQ+Rz(_3G#d zI!wdpZZ~0ca}v{hZIRjda7 ziO?YKHhn-w4BV3*A1W@?ct=u=C;27priJR4!zxe)5b>?vWjNmd= zzos(B{KioyGa2|&urOm+xt+GX({|jQrH12{muMp2ckQa>c(In&niJZY>knJTFCES3 z1DEks)VF&XAYCt)7{R|!g#-PM?cRf=JcYeUd8EwmUq1i#U5(+--f(}~I+$FI67XRe zn=)EX%_}sv%nbTL-gU=VulU1MN}qLYy|$fB^lP--&3{2-=-}=K=9fkz2Or4ZKrc9X zJD$q{t{l*W+_pZBrg^Wl?>8(t>ys*H7I?hq*E85E-D^SOrjXO=G z5EpO*SW_bi5Wj)0S2xY1IXcO_%t_`US)<9Wj@;3G`_i-WTNQ1aX?g9{IO5FDCbW9(qS321?-_R!&YpfW=VW15Bj}C2 zGwkiT&cb8sdjj>{S0;V1)%RG^dFAdW$Jec_dGl-)>^NL|CbznNxjJG&-QKg`6&y;M zqd-=xreJ5AW+kQE23<>HWEzF2Re};iE+ok=Xi2hIG!!v4O-8MPq~`RYvY4ev1}aGD zIE7Ua>n1i#h{YTezicwd80iL%?7X7VY0;Yb#p8qL#jJ~)v|HIf`)^z=IC5;vBR@1x zlCGbgQ1JWiTbbJ78caGP7+Nh(6`P#T!_11#snP`nFVgh3vbk6{Bu$;x&M`hFXc$<5 zayn>|K7baHC29}Y0kl-(kFmh|SiXY86+FZ|haisvoF97q<&gDaP82!6XK=5B@jfD!kW>uj#Dn2z zStJ^2sxG5_6c5%%pN++9>4fvqC+lgB#ha_+(cqkDoC4ne0KNwp+=C2mC0>bPa4$d5$ zxAo~!N9*2NGj{y@*P}%?Ga{IR&0Iy97Yf0u8_KDiC!IC>e~UkN?(V@8HnU$iNlC@y zKxlU0(8q;mYd6>2dFIEeaOL$_M_}QlU5EBxx5+bO zWTOf>;s!l`Ocm*c`?SpYBs>Ga631zN+lPB%9r@QD`W)sp*rZwHZ0Qm*Y_UFe4***D zvjdl&$PI3sk@xueQ&W%H?0A1aFpVTeknIMtLyu&LP){~EF}-`myYEe|?K%I^U)$NN zyLRY2MYf4A(hr(38cbSaX7=U(8CzMjaNq7P#pOeYq+4II+3P5~7l2odM{nGG<76oF W_4(OLcdFY*l6%*YKZ0D - - - - - - - - AssemblerTests_Common.cs diff --git a/chibild/chibild.core/CilLinker.cs b/chibild/chibild.core/CilLinker.cs index 26ae026..c3036c2 100644 --- a/chibild/chibild.core/CilLinker.cs +++ b/chibild/chibild.core/CilLinker.cs @@ -8,6 +8,7 @@ ///////////////////////////////////////////////////////////////////////////////////// using chibicc.toolchain.IO; +using chibicc.toolchain.Internal; using chibicc.toolchain.Logging; using chibild.Generating; using chibild.Internal; @@ -213,7 +214,7 @@ when Path.GetExtension(relativePath) == ".a": #endif fragments = loadedFragmentLists. - SelectMany(loadedFragments => loadedFragments). + SelectMany(loadedFragments => loadedFragments ?? CommonUtilities.Empty()). ToArray(); return caughtErrorCount == 0; } @@ -394,7 +395,8 @@ injectToAssemblyPath is { } injectPath ? loadedFragments, options.ApplyOptimization, options.DebugSymbolType == DebugSymbolTypes.Embedded, - options.CreationOptions)) + options.CreationOptions, + options.PrependExecutionSearchPaths)) { return false; } diff --git a/chibild/chibild.core/Generating/CodeGenerator_Emit.cs b/chibild/chibild.core/Generating/CodeGenerator_Emit.cs index a1ce64f..cc10310 100644 --- a/chibild/chibild.core/Generating/CodeGenerator_Emit.cs +++ b/chibild/chibild.core/Generating/CodeGenerator_Emit.cs @@ -584,9 +584,46 @@ private void OptimizeMethods( /////////////////////////////////////////////////////////////////////////////// - private ObjectFileInputFragment? LoadAndConsumeCAbiStartUpObjectIfRequired( + private bool TryLoadAndConsumeAdhocObject( InputFragment[] inputFragments, - string cabiStartUpObjectDirectoryPath) + string baseInputPath, + string relativePath, + TextReader objectReader, + out ObjectFileInputFragment fragment) + { + // Load this startup object file. + if (!ObjectFileInputFragment.TryLoad( + this.logger, + baseInputPath, + relativePath, + objectReader, + false, + out fragment)) + { + return false; + } + + // Step 1. Consume the object. + this.ConsumeFragment(fragment, inputFragments); + if (this.caughtError) + { + return false; + } + + // Step 2. Consume scheduled object referring in archives. + this.ConsumeArchivedObject(inputFragments, false); + if (this.caughtError) + { + return false; + } + + return true; + } + + private bool TryLoadAndConsumeCAbiStartUpObjectIfRequired( + InputFragment[] inputFragments, + string cabiStartUpObjectDirectoryPath, + out ObjectFileInputFragment fragment) { // Search for a set of functions built on the target module, // and if a function that is considered to be a main function exists, @@ -634,52 +671,58 @@ private void OptimizeMethods( { this.caughtError = true; this.logger.Error($"Could not find CABI startup object: {fileName}"); - return null; + fragment = null!; + return false; } - - using (var fs = ObjectStreamUtilities.OpenObjectStream( - objectPath, - false)) - { - var tr = new StreamReader(fs, Encoding.UTF8, true); - - // Load this startup object file. - if (!ObjectFileInputFragment.TryLoad( - this.logger, - cabiStartUpObjectDirectoryPath, - fileName, - tr, - false, - out var fragment)) - { - return null; - } - - // Step 1. Consume the object. - this.ConsumeFragment(fragment, inputFragments); - if (this.caughtError) - { - return null; - } - // Step 2. Consume scheduled object referring in archives. - this.ConsumeArchivedObject(inputFragments, false); - if (this.caughtError) - { - return null; - } + using var fs = ObjectStreamUtilities.OpenObjectStream( + objectPath, + false); - this.logger.Information($"Loaded CABI startup object: {fileName}"); + var tr = new StreamReader(fs, Encoding.UTF8, true); - return fragment; + if (!this.TryLoadAndConsumeAdhocObject( + inputFragments, + cabiStartUpObjectDirectoryPath, + fileName, + tr, + out fragment)) + { + return false; } + + this.logger.Information($"Loaded CABI startup object: {fileName}"); + + return true; } else { this.logger.Warning("Could not find CABI startup function."); } - return null; + fragment = null!; + return false; + } + + private bool TryUnsafeGetMethod( + ModuleDefinition targetModule, + InputFragment[] inputFragments, + IdentityNode function, + out MethodReference method) + { + foreach (var fragment in inputFragments) + { + if (fragment.TryGetMethod( + function, + null, + targetModule, + out method)) + { + return true; + } + } + method = null!; + return false; } private void AssignEntryPoint( @@ -707,6 +750,35 @@ private void AssignEntryPoint( } } + private void InsertPrependExecutionPath( + InputFragment[] inputFragments, + string[] prependExecutionSearchPaths, + MethodDefinition targetMethod) + { + if (this.TryUnsafeGetMethod( + targetModule, + inputFragments, + IdentityNode.Create("__prepend_path_env"), + out var m)) + { + var method = targetModule.SafeImport(m); + var instructions = targetMethod.Body.Instructions; + + foreach (var prependPath in prependExecutionSearchPaths.Reverse()) + { + instructions.Insert(0, Instruction.Create(OpCodes.Ldstr, prependPath)); + instructions.Insert(1, Instruction.Create(OpCodes.Call, method)); + + this.logger.Information($"Set prepend execution search path: {prependPath}"); + } + } + else + { + this.caughtError = true; + this.logger.Error($"Could not find prepender implementation."); + } + } + /////////////////////////////////////////////////////////////////////////////// private void InvokeDelayedLookingUps() @@ -741,7 +813,8 @@ public bool Emit( InputFragment[] inputFragments, bool applyOptimization, bool isEmbeddingSourceFile, - LinkerCreationOptions? creationOptions) + LinkerCreationOptions? creationOptions, + string[] prependExecutionSearchPaths) { // Try add fundamental attributes. if (creationOptions != null) @@ -779,18 +852,37 @@ public bool Emit( co.AssemblyType != AssemblyTypes.Dll && co.CAbiStartUpObjectDirectoryPath is { } cabiStartUpObjectDirectoryPath) { - if (this.LoadAndConsumeCAbiStartUpObjectIfRequired( + if (this.TryLoadAndConsumeCAbiStartUpObjectIfRequired( inputFragments, - cabiStartUpObjectDirectoryPath) is { } fragment) + cabiStartUpObjectDirectoryPath, + out var fragment1)) { // Emit this object. - this.EmitMembers(fragment); + this.EmitMembers(fragment1); // Invoke delayed looking ups. this.InvokeDelayedLookingUps(); } } + // Assign entry point. + if (creationOptions is { } co2 && + co2.AssemblyType != AssemblyTypes.Dll) + { + this.AssignEntryPoint( + co2.EntryPointSymbol); + } + + // Insert prepend search path. + if (prependExecutionSearchPaths.Length >= 1 && + targetModule.EntryPoint is { } targetMethod) + { + this.InsertPrependExecutionPath( + inputFragments, + prependExecutionSearchPaths, + targetMethod); + } + // Apply method optimization for all object fragments. if (applyOptimization) { @@ -813,14 +905,6 @@ public bool Emit( } Debug.Assert(this.delayDebuggingInsertionEntries.Count == 0); - - // Assign entry point. - if (creationOptions is { } co2 && - co2.AssemblyType != AssemblyTypes.Dll) - { - this.AssignEntryPoint( - co2.EntryPointSymbol); - } // (Completed all CIL implementations in this place.) diff --git a/chibild/chibild.core/LinkerOptions.cs b/chibild/chibild.core/LinkerOptions.cs index e72f3e3..691be63 100644 --- a/chibild/chibild.core/LinkerOptions.cs +++ b/chibild/chibild.core/LinkerOptions.cs @@ -225,6 +225,9 @@ public sealed class LinkerOptions public LinkerCreationOptions? CreationOptions = new(); + + public string[] PrependExecutionSearchPaths = + CommonUtilities.Empty(); public bool IsDryRun = false; } diff --git a/chibild/chibild.core/cli/CliOptions.cs b/chibild/chibild.core/cli/CliOptions.cs index 81f0619..24727c3 100644 --- a/chibild/chibild.core/cli/CliOptions.cs +++ b/chibild/chibild.core/cli/CliOptions.cs @@ -53,11 +53,29 @@ public static CliOptions Parse( var options = new CliOptions(); var libraryBasePaths = new List(); var inputReferences = new List(); + var prependExecutionSearchPaths = new List(); options.LinkerOptions.CreationOptions!.TargetFramework = TargetFramework.TryParse(defaultTargetFrameworkMoniker, out var tf) ? tf : TargetFramework.Default; + static bool TryGetOptionArgument( + string[] args, ref int index, out string result) + { + if (args[index].Length >= 3) + { + result = args[index].Substring(2); + return true; + } + else if (args.Length >= index) + { + result = args[++index]; + return true; + } + result = null!; + return false; + } + for (var index = 0; index < args.Length; index++) { var arg = args[index]; @@ -68,122 +86,69 @@ public static CliOptions Parse( switch (arg[1]) { case 'o': - if (arg.Length >= 3) - { - var outputAssemblyPath = - Path.GetFullPath(arg.Substring(2)); - options.OutputAssemblyPath = outputAssemblyPath; - continue; - } - else if (args.Length >= index) + if (TryGetOptionArgument(args, ref index, out var path1)) { - var outputAssemblyPath = - Path.GetFullPath(args[++index]); - options.OutputAssemblyPath = outputAssemblyPath; + options.OutputAssemblyPath = Path.GetFullPath(path1); continue; } break; case 'L': - if (arg.Length >= 3) - { - var referenceAssemblyBasePath = - Path.GetFullPath(arg.Substring(2)); - libraryBasePaths.Add(referenceAssemblyBasePath); - continue; - } - else if (args.Length >= index) + if (TryGetOptionArgument(args, ref index, out var path2)) { - var referenceAssemblyBasePath = - Path.GetFullPath(args[++index]); - libraryBasePaths.Add(referenceAssemblyBasePath); + libraryBasePaths.Add(Path.GetFullPath(path2)); continue; } break; case 'l': - if (arg.Length >= 3) - { - var referenceAssemblyName = arg.Substring(2); - inputReferences.Add(new LibraryNameReference(referenceAssemblyName)); - continue; - } - else if (args.Length >= index) + if (TryGetOptionArgument(args, ref index, out var path3)) { - var referenceAssemblyName = args[index + 1]; - inputReferences.Add(new LibraryNameReference(referenceAssemblyName)); - index++; + inputReferences.Add(new LibraryNameReference(path3)); continue; } break; case 'i': - if (arg.Length >= 3) - { - options.InjectToAssemblyPath = arg.Substring(2); - options.LinkerOptions.CreationOptions = null; - continue; - } - else if (args.Length >= index) + if (TryGetOptionArgument(args, ref index, out var path4)) { - options.InjectToAssemblyPath = args[index + 1]; + options.InjectToAssemblyPath = path4; options.LinkerOptions.CreationOptions = null; - index++; continue; } options.LinkerOptions.CreationOptions = null; continue; case 'a': - if (arg.Length >= 3) + if (TryGetOptionArgument(args, ref index, out var path5)) { if (options.LinkerOptions.CreationOptions is { } co2) { - co2.AppHostTemplatePath = arg.Substring(2); + co2.AppHostTemplatePath = path5; } continue; } - else if (args.Length >= index) - { - if (options.LinkerOptions.CreationOptions is { } co2) - { - co2.AppHostTemplatePath = args[index + 1]; - } - index++; - continue; - } break; case 'd': - if (arg.Length >= 3) - { - if (options.LinkerOptions.CreationOptions is { } co2) - { - co2.CAbiStartUpObjectDirectoryPath = arg.Substring(2); - } - continue; - } - else if (args.Length >= index) + if (TryGetOptionArgument(args, ref index, out var path6)) { if (options.LinkerOptions.CreationOptions is { } co2) { - co2.CAbiStartUpObjectDirectoryPath = args[index + 1]; + co2.CAbiStartUpObjectDirectoryPath = path6; } - index++; continue; } break; case 'e': - if (arg.Length >= 3) + if (TryGetOptionArgument(args, ref index, out var path7)) { if (options.LinkerOptions.CreationOptions is { } co2) { - co2.EntryPointSymbol = arg.Substring(2); + co2.EntryPointSymbol = path7; } continue; } - else if (args.Length >= index) + break; + case 'B': + if (TryGetOptionArgument(args, ref index, out var path8)) { - if (options.LinkerOptions.CreationOptions is { } co2) - { - co2.EntryPointSymbol = args[index + 1]; - } - index++; + prependExecutionSearchPaths.Add(path8); continue; } break; @@ -261,74 +226,72 @@ public static CliOptions Parse( else if (arg.Length == 2) { options.LinkerOptions.ApplyOptimization = true; - if (options.LinkerOptions.CreationOptions is { } co4) + if (options.LinkerOptions.CreationOptions is { } co2) { - co4.AssemblyOptions &= + co2.AssemblyOptions &= ~AssemblyOptions.DisableJITOptimization; } continue; } break; case 'v': - if (arg.Length == 2 && - Version.TryParse(args[index + 1], out var version)) + if (TryGetOptionArgument(args, ref index, out var vs)) { - index++; - if (options.LinkerOptions.CreationOptions is { } co6) + if (Version.TryParse(vs, out var version)) { - co6.Version = version; + if (options.LinkerOptions.CreationOptions is { } co2) + { + co2.Version = version; + } } continue; } break; case 'm': - var mopt = (arg.Length >= 3) ? arg.Substring(2) : - args.Length >= index ? args[++index] : - null; - if (mopt != null) + if (TryGetOptionArgument(args, ref index, out var mopt)) { if (TargetFramework.TryParse(mopt, out var tf2)) { - if (options.LinkerOptions.CreationOptions is { } co7) + if (options.LinkerOptions.CreationOptions is { } co2) { - co7.TargetFramework = tf2; + co2.TargetFramework = tf2; } continue; } if (Enum.TryParse(mopt, true, out var arch)) { - if (options.LinkerOptions.CreationOptions is { } co8) + if (options.LinkerOptions.CreationOptions is { } co2) { - co8.TargetWindowsArchitecture = arch; + co2.TargetWindowsArchitecture = arch; } continue; } if (rollforwards.TryGetValue(mopt, out var rollforward)) { - if (options.LinkerOptions.CreationOptions is { } co5) + if (options.LinkerOptions.CreationOptions is { } co2) { - co5.RuntimeConfiguration = rollforward; + co2.RuntimeConfiguration = rollforward; } continue; } switch (mopt.ToLowerInvariant()) { case "dll": - if (options.LinkerOptions.CreationOptions is { } co9) + if (options.LinkerOptions.CreationOptions is { } co2) { - co9.AssemblyType = AssemblyTypes.Dll; + co2.AssemblyType = AssemblyTypes.Dll; } continue; case "exe": - if (options.LinkerOptions.CreationOptions is { } co10) + if (options.LinkerOptions.CreationOptions is { } co3) { - co10.AssemblyType = AssemblyTypes.Exe; + co3.AssemblyType = AssemblyTypes.Exe; } continue; case "winexe": - if (options.LinkerOptions.CreationOptions is { } co11) + if (options.LinkerOptions.CreationOptions is { } co4) { - co11.AssemblyType = AssemblyTypes.WinExe; + co4.AssemblyType = AssemblyTypes.WinExe; } continue; } @@ -431,6 +394,9 @@ public static CliOptions Parse( options.InputReferences = inputReferences. Distinct(). ToArray(); + options.LinkerOptions.PrependExecutionSearchPaths = prependExecutionSearchPaths. + Distinct(). + ToArray(); return options; } @@ -474,7 +440,12 @@ public void WriteOptions(ILogger logger) { logger.Information($"InjectToAssemblyPath={this.InjectToAssemblyPath}"); } - + + foreach (var sp in this.LinkerOptions.PrependExecutionSearchPaths) + { + logger.Information($"PrependExecutionSearchPath={sp}"); + } + logger.Information($"IsDryRun={this.LinkerOptions.IsDryRun}"); } @@ -497,6 +468,7 @@ public static void WriteUsage(TextWriter tw) tw.WriteLine(" -x Will not copy required assemblies"); tw.WriteLine(" -d CABI startup object directory path"); tw.WriteLine(" -e Entry point symbol (defaulted: _start)"); + tw.WriteLine(" -B Prepend execution search path"); tw.WriteLine(" -v Apply assembly version (defaulted: 1.0.0.0)"); tw.WriteLine($" -m Target framework moniker (defaulted: {ThisAssembly.AssemblyMetadata.TargetFrameworkMoniker})"); tw.WriteLine(" -m Target Windows architecture [AnyCPU|Preferred32Bit|X86|X64|IA64|ARM|ARMv7|ARM64] (defaulted: AnyCPU)"); diff --git a/chibild/chibild/Properties/launchSettings.json b/chibild/chibild/Properties/launchSettings.json index 0003236..eb459f9 100644 --- a/chibild/chibild/Properties/launchSettings.json +++ b/chibild/chibild/Properties/launchSettings.json @@ -6,8 +6,8 @@ //"workingDirectory": "/home/kouji/Projects/chibicc-cil-toolchain/chibild/chibild.core.Tests/artifacts" //"commandLineArgs": "-o foo -mnet6.0 -a /home/kouji/.dotnet/sdk/6.0.419/AppHostTemplate/apphost -L/home/kouji/Projects/libc-cil/libc-bootstrap/bin/Debug/netstandard2.0 -L/home/kouji/.dotnet/shared/Microsoft.NETCore.App/6.0.27 /home/kouji/Projects/libc-cil/crt0/crt0_i_v.s main.o foo.a -lc-bootstrap -lSystem.Private.CoreLib", //"workingDirectory": "/home/kouji/Projects/chibicc-cil/aaa", - "commandLineArgs": "-o conftest -m net6.0 -d/home/kouji/Projects/chibicc-cil-build/libc-cil/../libc-cil/libc-bootstrap/bin/Debug/netstandard2.0/crt0 -L/home/kouji/Projects/chibicc-cil-build/libc-cil/../libc-cil/libc-bootstrap/bin/Debug/netstandard2.0 -L/home/kouji/.dotnet/shared/Microsoft.NETCore.App/6.0.29 -lSystem.Private.CoreLib -lc /tmp/chibicc-gvfcYn -a /home/kouji/.dotnet/sdk/6.0.421/AppHostTemplate/apphost", - "workingDirectory": "/home/kouji/Projects/chibicc-cil-build/libc-cil/newlib/build" + "commandLineArgs": "-o test/alignof -m net6.0 -d/home/kouji/Projects/chibicc-cil-build/chibicc-cil/../libc-cil/libc-bootstrap/bin/Debug/netstandard2.0/crt0 -L/home/kouji/Projects/chibicc-cil-build/chibicc-cil/../libc-cil/libc-bootstrap/bin/Debug/netstandard2.0 -L/home/kouji/.dotnet/shared/Microsoft.NETCore.App/6.0.29 -lSystem.Private.CoreLib -lc test/alignof.o test/common.o -a /home/kouji/.dotnet/sdk/6.0.421/AppHostTemplate/apphost", + "workingDirectory": "/home/kouji/Projects/chibicc-cil-build/chibicc-cil-toolchain/chibild/chibild/bin/Debug/net6.0" } } } diff --git a/chibild/misc/prependertestbed/prependertestbed.csproj b/chibild/misc/prependertestbed/prependertestbed.csproj new file mode 100644 index 0000000..5066546 --- /dev/null +++ b/chibild/misc/prependertestbed/prependertestbed.csproj @@ -0,0 +1,14 @@ + + + + net45 + 5.0 + disable + + + + + + + + diff --git a/chibild/misc/prependertestbed/text.cs b/chibild/misc/prependertestbed/text.cs new file mode 100644 index 0000000..670f1f1 --- /dev/null +++ b/chibild/misc/prependertestbed/text.cs @@ -0,0 +1,18 @@ +///////////////////////////////////////////////////////////////////////////////////// +// +// chibicc-toolchain - The specialized backend toolchain for chibicc-cil +// Copyright (c) Kouji Matsui(@kozy_kekyo, @kekyo @mastodon.cloud) +// +// Licensed under MIT: https://opensource.org/licenses/MIT +// +///////////////////////////////////////////////////////////////////////////////////// + +namespace C +{ + public static class text + { + public static void __prepend_path_env(string path) + { + } + } +} diff --git a/toolchain.common/IO/ObjectStreamUtilities.cs b/toolchain.common/IO/ObjectStreamUtilities.cs index c6145dc..4e3341c 100644 --- a/toolchain.common/IO/ObjectStreamUtilities.cs +++ b/toolchain.common/IO/ObjectStreamUtilities.cs @@ -10,12 +10,15 @@ using System; using System.IO; using System.IO.Compression; +using System.Reflection; +using System.Runtime.CompilerServices; namespace chibicc.toolchain.IO; public static class ObjectStreamUtilities { - public static Stream OpenObjectStream(string objectFilePath, bool writable) + public static Stream OpenObjectStream( + string objectFilePath, bool writable) { var s = StreamUtilities.OpenStream(objectFilePath, writable); if (Path.GetExtension(objectFilePath) is not ".s") @@ -29,4 +32,27 @@ public static Stream OpenObjectStream(string objectFilePath, bool writable) return s; } } + + [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] + public static Stream OpenEmbeddedObjectStream( + string objectResourcePath, + Assembly? assembly = null) + { + assembly ??= Assembly.GetCallingAssembly(); + + var s = assembly.GetManifestResourceStream(objectResourcePath); + if (s == null) + { + throw new FileNotFoundException( + $"Assembly={assembly.FullName}, Path={objectResourcePath}"); + } + if (Path.GetExtension(objectResourcePath) is not ".s") + { + return new GZipStream(s, CompressionMode.Decompress); + } + else + { + return s; + } + } }