-
Notifications
You must be signed in to change notification settings - Fork 257
Change request to support relative paths for css_reference #26
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
Comments
It already does. Please provide the test case if you believe that it doesn't. |
My setup still uses v3.3.0 / v3.3.5.0 and I did not find information regarding relative paths in the release notes, I only found information regarding absolute paths. And, CSScript.chm of the latest version as well as the online documentation still states to very same, i.e. "the same directory where the script is". So, I assumed that there was no relative path related change with css_reference since v3.3.0. Allow me some time to migrate from v3.3.0 to v3.19.0, I will then comment my findings. |
OK, I have updated to v3.19.0, and I could track down the issue to some degree. First I tried with a simple test DLL and script, using cscs.exe directly: However, in my application (based on CSScriptLibrary) the same thing doesn't work, it only works when the DLL is located at the very same directory as the script. My application... That invocation throws a System.IO.FileNotFoundException "the file or assambly ... has not been found":
Two things puzzle me:
Why "\%CSSCRIPT_DIR%\Lib"? "\%CSSCRIPT_DIR%" might make sense (in order to be able to control the directory using //css_searchdir ?). But why adding a fixed "\Lib"? In my case, I do not define %CSSCRIPT_DIR%, so the resulting path is either "C:\MyWorkspace\06-Test\CSScript\css_referenceTest\Script\\Lib" or "C:\MyWorkspace\06-Test\CSScript\css_referenceTest\Script\Lib"? Note that I only pass "Script.dll" to the constructor of the AsmHelper, as the help or 'asmFile' states "File name of the assembly to be loaded.". I have also tried passing the full path to the file, but that doesn't change the weird path above. By the way, I'd personally prefer more specific variable names, such as asmFileName or asmFilePath, following the System.IO.Path terminology (i.e. FileName/Path/FullPath), and FilePath for unspecific (i.e. relative or absolute) file paths. Does this piece of information help in some way? If you'd prefer, I could debug into AsmHelper by adding an additional configuration to my project which uses the CSScriptLibrary source code instead of the .dll. Let me know if that would help. |
Update: One of the assemblies of my project still referred to v3.3.0. I have just noticed and fixed that, now ProbingDirs contains an additional path:
But still, I get the System.IO.FileNotFoundException exception. I have also searched and found information on %CSSCRIPT_DIR% in the docs. But I did not find any information on %CSSCRIPT_INC%" in either CSScript.chm nor CSScriptLibrary.chm. |
The simple answer is "because .NET runtime reports any failed assembly loading this way". It refers the failed loading with the assembly The problem you are experiencing is caused by the inadequate assembly probing on the hosting solution. First of of all your script compiling was OK. No problem there. After you got the compiled script path with CompileFile your scripting is done. The rest of your actions (assembly loading) has nothing to do with scripting as such. You can even load the assembly without CS-Script's AsmHelper but directly with Assembly.Load. And this is exactly what AsmHelper does, it calls Assembly.LoadFrom. AsmHelper also does optional assembly unloading but you are not using this functionality anyway. If you indeed call Assembly.LoadFrom("script.dll") you would get the same error as if you use AsmBrowser. Your script.dll depends on library.dll, which is not in the location that Assembly.LoadFrom knows about. .NET provides the solution for the situations like this. You need to set up AsmHelper simplifies handling AppDomain.AssemblyResolve event by automatically probing directories from CSScript.GlobalSettings.SearchDirs: if (CSScript.AssemblyResolvingEnabled)
foreach (string dir in CSScript.GlobalSettings.SearchDirs.Split(';'))
if (dir != "")
dirs.Add(Environment.ExpandEnvironmentVariables(dir)); Thus you can do the probing by yourself or ensure that the required directory is in the global settings and let AsmHelper to do the job. Again, this is a common dynamic assembly loading challenge that has nothing to do with CS-Script. In fact CS-Script faces the same problem when the script is executed with cscs.exe. And it solves the the same way as I just described. By handling AppDomain.AssemblyResolve event. Now you probably have a good feel why spreading the assemblies over multiple directories is not such a good idea. :)
This directory is the result of expanding %CSSCRIPT_DIR%\Lib, you already discovered that. CSSCRIPT_DIR is the environment variable that is created by the CS-Script installation. CS-Script allows configuring the optional global probing directories via string searchDirs = "%CSSCRIPT_DIR%\lib;%CSSCRIPT_INC%;"; You can clear the defaults by setting
Because it is the directory that is dedicated for system wide script dependencies (assemblies and scripts). Having them in the cs-script root directory (which is %CSSCRIPT_DIR%) isn't really practical. As a side note, AsmHelper was developed very long time (more that 10 years) ago when there were no good way to deal with dynamically loaded assemblies. Today you have some better choices. Like Script file script.cs: //css_ref lib\child_script.dll;
using System;
using System.Windows.Forms;
public class Script
{
static public void Main()
{
new MainScript().test();
}
public void test()
{
ChildScript.test();
}
} Script host: CSScript.GlobalSettings.AddSearchDir(@"E:\Dev\lib");
dynamic script = CSScript.Load(@"E:\Dev\script.cs")
.CreateObject("*");
script.test();
It is a difficult balance between verbosity and accuracy but I do agree with you in general. I will update the signature with the next opportunity. |
For the arguments renaming I opted to improving XML documentation as an adequate compromise. |
* Added support for C#6 syntax to Mono evaluator. * Issue #33: Cleanup routine throws ArgumentException * Added extending environment variables in all parameters passed from command line. * Improved API XML documentation to address some of the Issue #26 concerns. * User experience improvements triggered by incentive Linux testing * Various improvements for stdout help. * Improved reliability of Auto-class decorating algorithm * Added support for referencing NuGet packages from the script being executed on Linux * Added -noconfig:print and -precompiler:print options for printing the content in stdout. * Extended Python-like "print" functionality: * Added params concatenation: `print(obj1, obj2,...objN)` * Added pringf for params formatting: `printf("Now: {0}", DateTime.Now)` * added support for collections: `print(Directory.GetFiles(".", "*"))` * Added decorateAutoClassAsCS6 setting for injection `using static dbg;` into auto-class decoration. * Issue#32: Inconsistent time stamp (.dll -vs- .pdb) when using `CSScript.CompileFile()` with 'debugBuild = true' * Added support for output file in //css_res. * Various obsolete code marked as error triggering. * Implemented supressing elevation during syntax checking (with `-check`) for the scripts with `//css_pre elevate` directive. * Improved settings file parsing to avoid throwing handled exceptions. * Code cleanup * Added support for CSS_RESGEN environment variable for embedding resources with //css_res. * Removed old obsolete ResolveSourceFileHandler delegate and MonoEvaluator.Configuration member. * Staretd removal of obsolete .NET1.1 code (conditional compiler directives).
Hi Oleg, yesterday I updated to v3.21.1 and have again looked at this issue. Unfortunately this issue is still not solved in my opinion, and I try to express myself better than when initially describing my request. Compilation of a script with //css_reference SomeAbsoluteOrRelativePath.SomeLibrary.dll; works fine. So far so good. But, loading the assembly results in a System.IO.FileNotFoundException "the file or assambly ... has not been found" due to the missing probing directories for the reasons you have explained above. While %CSSCRIPT_INC% may be a good solution for standalone / command line execution, I don't think it's suitable for a hosted application. So I am suggesting the following:
Could CSScript.CompileFile() return all paths that were used for looking up source code and assemblies? And, could AsmHelper provide a method to append probing dirs (instead of having to globally add CSScript.GlobalSettings.AddSearchDir())? Then, I could retrieve the resolved paths from CompileFile() and forward them to the AsmHelper, such that it will allow .NET to find all required assemblies. As a result, from the script user's point of view, //css_reference would then provide full support of absolute and relative paths. Of course, I could also manually parse the script's //css_reference items and then add the paths. But this is somewhat duplicated logic, as CSScript.CompileFile() already parses these items. |
OK, I see your point. But it's not as simple as it may seem. Assembly resolving is a global activity. It is done within the scope of the AppDomain. Meaning that even if AsmHelper had some operation specific set of probing dirs it wouldn't be able to map tham to the However nothing prevents you from attempting to implement a high resolution (non generic) assembly probing by yourself. What you need is the knowledge of the assemblies (as you already suggested) that were used during the compilation and your own AssemblyResolve handler: AppDomain.CurrentDomain.AssemblyResolve += ResolveEventHandler; Now, should you try to discover the assemblies by parsing the code you don't have to do it manually. Use already existing routine that does exactly that: string[] asms = CSScript.CodeDomEvaluator.GetReferencedAssemblies(script_code); You can have a look at the implementation of Your proposal to have some way of preserving the compiler input info (e.g. assemblies required for compilation) is also OK though there is a much better than CompileFile() candidate for that. There is a public static Dictionary<FileInfo, CompilerResults> CompilingHistory; It just makes sense to extend it and also keep Will schedule the change for the next release. |
Done. I will probably adjust the API a bit more but currently it can be used as this: CSScript.KeepCompilingHistory = true;
CSScript.CompileFile(script, null, false, null);
CompilingInfo info = CSScript.CompilingHistory
.Values
.First(item => item.ScriptFile == script);
Console.WriteLine("Script: " + info.ScriptFile);
Console.WriteLine("Referenced assemblies:");
foreach (string asm in info.Input.ReferencedAssemblies)
Console.WriteLine(asm);
if (info.Result.Errors.HasErrors)
{
Console.WriteLine("Errors:");
foreach (CompilerError err in info.Result.Errors)
if (!err.IsWarning)
Console.WriteLine("Error: " + err.ErrorText);
}
CSScript.CompilingHistory.Clear();
CSScript.KeepCompilingHistory = false; |
* Added dbg.print injection to the csws.exe to match it with cscs.exe. * Issue #39: Suggestion for minor improvement in AsmHelper.Invoke() * Issue #40: Suggestion for minor improvement in ScriptParser..ctor() * Added `CompilerParameters` to the CSScript.CompilingHistory collection. Related to issue #26 * Added -config switch for CLI * Implemented support for reversed order of parameters for the command specific help. * Fully prepared for integration with N++ (and other editors) * Added creating shadow copy of Roslyn services during first config to avoid dir locking because of running Roslyn binaries
Thanks! And thanks for the very quick v3.22! I have updated to v3.22 today but have not yet been able to adapt my code according to your directions above. I'll do that next week, but you may already close this issue as I assume it now works for me. Thanks again! |
Hi Oleg, works perfectly, thanks! I am using it as follows:
As a result, a script can now reference whatever it wants:
Thanks again! Best regards, |
//css_reference should support relative paths as //css_import and //css_resource are doing.
Rationale: Referencing an own .dll located in a different project/folder than the script itself.
The text was updated successfully, but these errors were encountered: