Skip to content

CLI User Guide

oleg.shilo edited this page Sep 28, 2019 · 32 revisions

Deployment

As many other tools CS-Script provides an intensive command line interface that can be used from shell/terminal (e.g. Bash, PowerShell, command-prompt). This interface is particularly useful fo environments like Linux, where working from terminal is a predominate development approach.

CS-Script deployment model exist in two distinctive distribution forms:

  • Simple
    Applicable for Windows, Linux, Mac. Basically it is an XCopy approach when yuo can bring on the target system CS-Script binaries that you need. Typically it is the script engine executable (cscs.exe). While you may also want to bring CSSRoslynProvider.dll along but strictly speaking cscs.exe is all you need ro run C# scripts.

  • Complete
    Applicable for Windows only. This model involves much dipper integration with the host OS. It involves bringing the software package (7z archive) from GitHub Releases folder unpacking it and launching the config console (css_config.exe), which performs all necessary configuration steps. Alternatively you can perform a single step deployment via the Chocolatey CS-Script package. The Complete deployment/distro contains much more than CS-Script binaries (Simple distro). It also includes extra utilities and binaries targeting various rintimes and the documentation.

    Full distro content (click to expand)   - Integration with OS: system path, envars, shell-extensions, default editor association
      - GUI configuration console
      - NuGet and Wsdl third-party tools
      - Collection of utility scripts
      - Binaries targeting legacy runtimes (e.g. .NET 3.5)
      - Complete set of Roslyn binaries
      - Intensive _Samples_ library
      - Documentation

While Complete distro contains many useful resources the Simple one is what you would need in 90% of the cases. The script engine CLI is designed in such a way that it (single executable) can produce the minimal set of CS-Script documentation, samples and required configuration. The Simple distro is applicable for all OSs and as such it is perfect as a basic environment for a crash-course in CS-Script.

Quick Start

Note, if you are running CS-Script on Mono you will always need to supply the mono token for all commands: mono cscs.exe -ver instead of cscs -ver. However this document contains all samples written in the short form for the sake of simplicity.

Creating and executing sample script

  • cscs -s - prints sample script. For C# 7 sample use -s:7 switch.
  • cscs -s > sample.cs - redirects sample script content into sample.cs file.
  • cscs sample.cs - execute sample.cs file

Produced sample.cs file

using System;
using System.Windows.Forms;

class Script
{
    static void Main(string[] args)
    {
        for (int i = 0; i < args.Length; i++)
            Console.WriteLine(args[i]);

        MessageBox.Show("Just a test!");
    }
}

Hints and tips

  • You can print the list of all supported commands with cscs -cmd

  • You can access help for a specific command by typing ? after the command name (e.g. cscs -syntax -?)

  • You can print the whole overview of CS-Script specific C# directives with cscs -syntax

  • The most common/useful CS-Script directives that you can specify directly in the script are:

  • When referencing external files with //css_ directives (e.g. //css_inc) it is important to be aware about the way CS-Script resolves relative paths.

    If a relative file path is specified with a single-dot prefix it will be automatically converted into an absolute path with respect to the location of the file containing the directive being resolved. Otherwise it will be resolved with respect to the process current directory.

    If for whatever reason it is preferred to always resolve path expression with respect to the parent script location you can configure the script engine to do it with the following command:

    cscs -config:set:ResolveRelativeFromParentScriptLocation=true
    
  • With the -pc switch you can define a precompiler script that allows pre-processing the primary script content prior its execution. Precompilation allows achieving pretty advanced functionality usually available in some advanced AOP framework. For example code decoration, macros unfolding etc.

  • Instead of passing arguments from the command line you specify them directly in the script code with //css_args directive.

  • The most frequently used command line arguments can be specified in the global configuration so they will be automatically added during an the execution for all scripts (e.g. suppressing warnings).

  • On Windows/.NET you can pass //x as the very last argument of the script and this will trigger a Debug.Assert on entering the script code. This way you can attach system wide debugger and debug the script:

    cscs print.cs "Hello World!" //x
    

C# 7 Support

CS-Script uses at runtime C# compiling infrastructure available with .NET/Mono. The highest supported C# syntax version available out of box is C# 5 on .NET and C# 6 on Mono. The support for C# 7 on both platforms is available via a separate compiling infrastructure - Roslyn. Read more...

CS-Script integrates with Roslyn via special CS-Script code provider assembly CSSRoslynProvider.dll

This is how you can enable CS-Script C# 7 support (Roslyn integration):

  • On Mono:
    Since Roslyn is a part of Mono you only need to place CSSRoslynProvider.dll in the same location where your cscs.exe is.
    Alternatively specify the location of the provider dll in the global configuration as the UseAlternativeCompiler config value.

  • On .NET:
    Roslyn is not a part of .NET binaries and it needs to be installed separately. CS-Script Complete Distro includes Rolsyn and it is enabled by default on all fresh installations. If you need to enable Roslyn manually read about the procedure in this dedicated guide

Command Line Interface

Note, this section does not cover the whole CLI but only highlights its most important elements. The whole CLI documentation can be generated with cscs -? command. You can also access its latest copy here.


Command: "version"

Syntax: cscs -ver (or just cscs)

Description: Prints full information about the current CS-Script environment.


Command: "commands"

Syntax: cscs -cmd

Description: Prints list of supported commands (arguments).

Syntax: cscs -cmd ?

Description: Prints description of an individual command.


Command: "build executable - EXE"

Syntax: cscs -e <script_file>

Description: Compiles script into an application executable.

Command: "build class library - DLL"

Syntax: cscs -cd <script_file>

Description: Compiles script into a class library assembly.


Command: "compiler options"

Syntax: cscs -co:<options> <script_file>

Description: Passes user specified options into C# compiler.

The sample below demonstrates how to compile unsafe code. Any unsafe code requires passing /unsafe parameter to the C# compiler:

using System;
using static dbg;

unsafe void main()
{
    int i = 25;
    SquarePtrParam(&i);
    print(i);
}

unsafe void SquarePtrParam(int* p)
{
    *p *= *p;
}


Command: "auto-class"

Syntax: cscs -ac[:<0|1|2|out>] <script_file>

Description: Decorates classless C# script code with a class definition prior the execution.

You can also

-ac      enables auto-class decoration (which might be disabled globally); 
-ac:0    disables auto-class decoration (which might be enabled globally);
-ac:1    same as as `-ac`
-ac:out  prints auto-class decoration for a given script file. The argument must be 
         followed by the path to script file.\n" +

In this mode script engine automatically generates 'static entry point' class if the script doesn't define any.

The engine inserts two unformatted lines of decoration code that define a class start and class end. The injected lines are clearly marked with the special line ending so they can be excluded from the line counting when classless code is handle by IDEs.

Classless script sample:

using System;
             
void Main()
{
    Console.WriteLine("Hello World!");
}

Thus the code above will be decorated just before passing it to the C# compiler as below:

using System;
public class ScriptClass { public static ///CS-Script auto-class generation
void Main() { Console.WriteLine("Hello World!"); }
} ///CS-Script auto-class generation

You can always test the decoration outcome with -ac:out switch:

Using an alternative 'instance entry point' is even more convenient (and reliable). The acceptable 'instance entry point' signatures are:

    void main()
    void main(string[] args)
    int main()
    int main(string[] args)

The convention for the classless (auto-class) code structure is as follows:

  • set of 'using' statements
  • classless 'main'
  • user code
  • optional //css_ac_end directive
  • optional user code that is not a subject of auto-class decoration

By default CS-Script decorates the script by adding a class declaration statement to the start of the script routine and a class closing bracket to the end. This may have an unintended effect as any class declared in the script becomes a 'nested class'. While it is acceptable for practically all use-cases it may be undesired for just a few scenarios. For example, any class containing method extensions must be a top level static class, what conflicts with the auto-class decoration algorithm.

The solution to this problem is to allow some user code to be protected from being included into auto-class decoration. User can achieve this by placing '//css_ac_end' statement into the code. Any user code below this statement will be excluded from the decoration and stay unchanged:

using System;
using System.Linq;
using System.Collections.Generic;
using static dbg;

void main()
{
    var words = "The quick brown fox jumps over the lazy dog".GetWords();
    print(words);
}

//css_ac_end
static class Extensions
{
    public static IEnumerable<string> GetWords(this string text)
    {
        return text.Split(".,;:?!\t\n\r ".ToCharArray())
                   .Where(x => !string.IsNullOrWhiteSpace(x));
    }
}

You can also define auto-class by placing the auto-class directive in the script code:

//css_autoclass [style]

Alias - //css_ac

//css_ac
using System;
 
void Main()
{
    Console.WriteLine("Hello World!");
}

A special case of auto-class use case is a free style C# code that has no entry point 'main' at all:

//css_ac freestyle
using System;
using System.IO;
 
foreach (var file in Directory.GetFiles(@".\"))
    Console.WriteLine(file);

Since it's problematic to reliable auto-detect free style auto-classes, they must be defined with the special parameter 'freestyle' after the '//css_ac' directive.


Command: "pre-compiler"

Syntax: cscs -pc:<precompiler_file> <script_file>

Description: Specifies custom precompiler. This can be either script or assembly an file. (see https://www.cs-script.net/cs-script/help-legacy/precompilers.html)

-pc           - If no file specified it prints the code template for the custom precompiler.
-pc:print     - Prints the code template for the custom precompiler.
-pc:nodefault - Prevents loading any built-in precompilers. 
                (E.g. The one for removing shebang before the execution. Auto-class precompiler 
                - classless script decorator)
-pc:<file 1>[,<file N>]
              - Precompiles the script with the specified precompiler(s).

Script recompilation is a powerful mechanism somewhat similar to the C++ precompilation. It gives user an unrestricted ability to massage (modify) the source code just before it's fed to the compiler. The feature can be extremely valuable for adding language features that are not directly available in C#. Anything from executing encrypted scripts to advanced DSL features. Thus, CS-Script itself uses a built-in precompiler to decorate classless scripts with the class declaration on-fly (auto-class feature)

The following is a script sample that uses heshdef.cs prcompiler to support C++ style #define macros for C#:

Note, the sample uses //css_pc directive directly in the script C# code. This directive is a full equivalent of -pc CLI command.

//css_pc hashdef
using System;

#define PRINT Console.WriteLine
#define USER Environment.UserName.GetHashCode()
#define GRITTING $"Hello {USER}!"

class Script
{
    static public void Main()
    {
        PRINT(GRITTING);
    }
}


Command: "code provider"

Syntax: cscs -pvdr:<provider_file> <script_file>

Description: Executes script compiled with the specified custom compiler (code provider).

By default CS-Script uses the default C# compiler implemented in System.dll. However CS-Script allows user to integrate any code compiler that can be exposed as System.CodeDom.Compiler.ICodeCompiler. And this is exactly how CS-Script supports C# 7 syntax, which is not supported by the CLR just out of box.

Thus CS-Script implements relatively simple adapter (CSSRoslynProvider.dll) that delegates the actual code compilation to Roslyn services. Such a compiler adapter can be specified either globally in the settings or as a command line argument for a script.

A 'code provider' is an ordinary assembly that implements public type with public static method ICodeCompiler CreateCompiler(string sourceFile). The code below is a complete implementation of the "code provider" that creates an appropriate compiler for a file depending on the file extension. This provider allows execution of the scripts written in C#, VB.NET or JScript.NET syntax.

provider.cs

// CS-Script default ref assemblies are not processed so need to add them explicitly
//css_ref System.Core  
using System;
using System.Collections;
using System.Linq;
using System.IO;
using System.Collections.Generic;
using System.Text;

public class HashDefPrecompiler
{
    static public bool Compile(ref string code, string scriptFile, bool IsPrimaryScript, Hashtable context)
    {
        var hashDefs = new Dictionary<string, string>();

        var content = new StringBuilder();

        string line;

        using (var sr = new StringReader(code))
            while ((line = sr.ReadLine()) != null)
            {
                if (line.Trim().StartsWith("#define ")) //#define <pattern> <replacement> 
                {
                    string[] tokens = line.Split(" ".ToCharArray(), 3, StringSplitOptions.RemoveEmptyEntries);

                    if (tokens.Count() > 2)
                    {
                        hashDefs.Add(tokens[1], tokens[2]);
                        content.AppendLine("//" + line);
                        continue;
                    }
                }
                content.AppendLine(line);
            }

        code = content.ToString();
        foreach (string key in hashDefs.Keys.Cast<string>().Reverse())
            code = code.Replace(key, hashDefs[key]);

        return true;
    }
}

The code provider above allows executing VB.NET scripts with CS-Script engine:

script.vb

Imports System
Imports System.Windows.Forms

Module Module1
    Sub Main()
        Console.WriteLine("Hello World! (VB)")
    End Sub
End Module

Hint: you may prefer to have the command line parameters being specified directly in the script. This is how you can do it in the VB code:

' //css_args -pvdr:provider.dll
' //css_ref System.Windows.Forms.dll
Imports System