Skip to content

Repository files navigation

Stickle

The Stickle Workflow has a streamlined Terminal User Interface (TUI) and example code for using the Rusty Compiler.

tui demo

The example Structured Text project unlocks plain-text Source Control and Unit Testing.

Develop and troubleshoot your Automation projects while decoupling from any manufacturers ecosystem.

Setting up the Development Environment

Compiling on Windows

  • Install LLVM 21.1.7 and add it's bin folder to your PATH environment variable.

  • Install plc.zip from the Windows Build Pipeline.

    • Add it's location to the PATH environment variable. An AppData location is recommended for installation.
  • Install stdlib.lib from the same pipeline and install it to the same folder.

  • Install the Windows SDK and MSVC. You can use the Visual Studio Installer to do this or install them as standalone packages.

  • Create a LIB environment variable containing paths to iec61131std.lib, ws2_32.lib, ntdll.lib, userenv.lib, libcmt.lib, oldnames.lib and libucrt.lib.

    • Your environment variable should look something like this:
    C:/Users/<USERNAME>/AppData/Local/rustycompiler;
    C:\Program Files (x86)\Windows Kits\10\Lib\10.0.26100.0\um\x64;
    C:\Program Files (x86)\Windows Kits\10\Lib\10.0.26100.0\ucrt\x64;
    C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.43.34808\lib\x64;
    
  • Restart your terminals to refresh the environment.

  • Proceed with compilation:

    plc ./source/* -c -l iec61131std -l ws2_32 -l ntdll -l userenv -o ./compiled/lib_structured_text.o
    
    clang ./compiled/lib_structured_text.o --shared -l iec61131std -l ws2_32 -l ntdll -l userenv -fuse-ld=lld-link "-Wl,/DEF:exports.def" -o ./compiled/lib_structured_text.dll
    
  • Finally, link everything together and execute the unit test:

    dotnet test
    

You can perform this compilation procedure by running the Powershell script, instead.

./build.ps1

Structured Text can also be compiled to IEC 61131-10 XML, which imports into Omron Sysmac Studio.

plc ./source/clampandsaw.st --xml-omron --generate-external-constructors -i ./source/externals.st -l iec61131std -l ws2_32 -l ntdll -l userenv -o ./compiled/lib_structured_text.xml

Compiling on Linux

  • Install the following packages:

    sudo apt update && sudo apt install build-essential
    
    sudo snap install --classic dotnet && sudo snap install dotnet-sdk-100 && sudo snap install dotnet-runtime-100 && sudo snap install aspnetcore-runtime-100
    
  • Download plc.zip from the Linux Build Pipeline and decompress it into the /usr/bin. Each build pipeline for the Rusty Compiler produces a plc executable.

    cd /mnt/c/Users/<USERNAME>
    
    7z e ./Downloads/plc.zip
    
    sudo cp ./Downloads/plc /usr/bin
    
  • Download stdlib.zip from the Linux Build Pipeline and decompress it into the /lib folder.

    Ensure you take the libiec61131std.so file that corresponds with your microprocessor architecture (most likely x86_64-linux-gnu).

    sudo cp ~/Downloads/stdlib/x86_64-linux-gnu/libiec61131std.so /lib
    
  • Build the Omron library, then compile the project against it:

    plc ./libNX1P2/*.st --shared --linker=cc -l iec61131std -o ./compiled/libNX1P2.so
    
    plc ./source/*.st --shared --linker=cc --generate-external-constructors -i ./externals/stdlib_externals.st -i ./externals/omron_externals.st -L ./compiled -l iec61131std -l NX1P2 --linker-arg=--rpath='$ORIGIN' -o ./compiled/lib_structured_text.so
    

    The -i includes declare the Omron system variables and the stdlib function blocks. Without them the sources will not compile. Note that on Linux the lib prefix is implicit, so libNX1P2.so is linked with -l NX1P2.

    The {external} types in those includes are declared here but defined in libNX1P2, which does not export their compiler-generated __ctor symbols. --generate-external-constructors makes the compiler emit those constructors into this build instead, so the link resolves without adding internal symbols to libNX1P2/exports.def. Without it the link fails with undefined symbol: _sNXUNIT_ID__ctor.

    lib_structured_text.so records a dependency on libNX1P2.so, and -L is only a link-time search path, so without a runtime search path the dynamic loader cannot find it and dotnet test fails with DllNotFoundException. --linker-arg=--rpath='$ORIGIN' writes a RUNPATH of $ORIGIN into the library, which resolves relative to the library itself, so libNX1P2.so is found next to it regardless of the working directory. Note that --linker-arg is passed straight to ld.lld, so the -Wl, prefixed form is rejected, and $ORIGIN must be quoted to survive the shell.

Structured Text can also be compiled to IEC 61131-10 XML, which imports into Omron Sysmac Studio.

plc ./source/clampandsaw.st ./source/testallbuiltins.st --xml-omron --generate-external-constructors -i ./externals/stdlib_externals.st -i ./externals/omron_externals.st -L ./compiled -l iec61131std -l NX1P2 -o ./compiled/lib_structured_text.xml

You can perform this compilation procedure by running the Bash script, instead.

./build.sh

Link the dynamic library with dotnet and execute the unit test:

dotnet test

Compiling with Docker

  • Install Docker Desktop using the WSL2 backend and ensure it is running.

  • On Windows, run this:

docker run --rm --mount type=bind,src=./source,dst=/source --mount type=bind,src=./compiled,dst=/compiled --mount type=bind,src=C:/Users/Sam/AppData/Local/rustycompiler,dst=/copiedlibs  ghcr.io/doublecouponday/rusty:master "plc /source/* --linker=cc --target=x86_64 -L /copiedlibs -l iec61131std --shared -o /compiled/lib_structured_text.dll"
  • On Linux, run this:
docker run --rm --mount type=bind,src=./source,dst=/source --mount type=bind,src=./compiled,dst=/compiled --mount type=bind,src=/lib,dst=/copiedlibs  ghcr.io/doublecouponday/rusty:master "plc /source/* --linker=cc --target=x86_64 -L /copiedlibs -l iec61131std --shared -o /compiled/l
ib_structured_text.so"

Compiling as a standalone executable

This can be useful if you need to debug a ST file and log directly to console using the puts or printf function. Please note that for whatever reason, printf does not accept CRLF or LF as newline sequences. Use printf to append to the current line and puts to write a new line.

Windows:

plc ./examples/hello_world.st -l iec61131std -l ws2_32 -l ntdll -l userenv -o ./compiled/hello_world.exe

./compiled/hello_world.exe

Linux:

plc ./examples/hello_world.st -L /lib -l iec61131std --linker=cc -o ./compiled/hello_world

./compiled/hello_world

Compiling the TUI

Literally just cargo build.

Further Reading

Rusty Compiler - Documentation

Rusty Compiler - Community

Foreign Function Invocations

FAQ - Frequently Asked Questions

Why use Docker Desktop?

Docker provides a package manager for retrieving the latest updates to the Rusty Compiler. You can download it from Github Build Pipeline but you will need to maintain that installation manually. With Docker, simply run docker pull ghcr.io/doublecouponday/rusty:master to retrieve the latest updates.

stdlib still needs to be maintained manually but the compiler maintainer has signalled, in future, it will be bundled into the docker image.

Why did you convert the Rusty Xml Nodes to all take String instead of &str?

InitialValue AstNodes needed to be converted to Strings at runtime. Those strings must pass ownership to the Node Tree which won't work when passing references. The lifetime of those &strs would have been greater than their owned Strings.

Why did you change all the Xml Nodes children fields to Vec<Box<dyn IntoNode>>?

I couldn't create a collection of Vec<dyn IntoNode> because their size is not known at compile time. This prevented me from iteratively adding to a Vec of child nodes, then using the .children() function.

The Structured Text Intellisense for VS Code has annoying autocomplete for POU end braces. How can I disable it?

Assuming use of the "Structured Text language Support" extension for vscode

CTRL + SHIFT + P > open user settings (json)

add this to your settings.json:

"[st]": {
    "editor.autoClosingBrackets": "never"
}

Why does the compiler say "LLVM ERROR: Invalid size request on a scalable vector." when my first enum option does not have a value of 0?

This is a known bug in the compiler as it is crashing with the following error message:

error: process didn't exit successfully: `target\debug\plc.exe ./examples/source/clampandsaw.st ./examples/source/externals.st -ir -l iec61131std -l ws2_32 -l ntdll -l userenv` (exit code: 0xc0000409, STATUS_STACK_BUFFER_OVERRUN)

Nice to have

  • Network Publish Mode parsing to enum.

  • Global pattern input files for xml conversion.

    This works for -c so why not other compilation modes?

  • Support network publish modes for globals.

  • Support Unions.

  • stdlib bundled inside docker image.

  • Explore XML Generation for Sysmac Safety PLCs.

  • Explore XML Generation for Codesys.

  • add lit tests for Windows.

  • Bring DLLs up to feature parity with LIBs.

  • Remove the tabs in the first indentation column.

    This is due to copying from source code which has an indentation on the first column.

  • What libs are required to link with in order to fully pass the Windows Workspace unit tests in Rusty-Fork?

    kernel32.lib ntdll.lib userenv.lib ws2_32.lib dbghelp.lib

About

Streamlined Terminal User Interface (TUI) and example code for using the Rusty Compiler.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages