bmitc

bmitc

Hello! I am working on something where I am trying to pass data between .NET, namely F#, and Elixir through the command line. On Windows, I am getting a strange error that I can’t figure out.

Here is my F# function:

let executeProcess name arguments =
    let startInfo = System.Diagnostics.ProcessStartInfo(
        FileName = name,
        Arguments = arguments,
        UseShellExecute = false,
        RedirectStandardError = true,
        RedirectStandardOutput = true
    )
    use p = new System.Diagnostics.Process(StartInfo = startInfo)
    p.Start() |> printfn "Successfull?: %A"
    p.WaitForExit()
    p.StandardOutput.ReadToEnd()

On Ubuntu, this works without issue (you can try by copy and pasting this into a dotnet fsi session after downloading the latest .NET SDK or you can try it in a Polyglot Notebook in VS Code, which requires no install I believe as it installs F# for you):

$ dotnet fsi

Microsoft (R) F# Interactive version 12.4.0.0 for F# 7.0
Copyright (c) Microsoft Corporation. All Rights Reserved.

For help type #help;;

> <copy and paste above function>;;
val executeProcess: name: string -> arguments: string -> string

> executeProcess "dotnet" "--version";;
Successfull?: true
val it: string = "7.0.101
"

> executeProcess "elixir" "--version";;
Successfull?: true
val it: string =
  "Erlang/OTP 25 [erts-13.1.4] [source] [64-bit] [smp:20:20] [ds:20:20:10] [async-threads:1] [jit:ns]

Elixir 1.14.3 (compiled with Erlang/OTP 25)
"

>

However, on Windows, I get a strange Erlang init error but notice that Elixir works just fine on the command line:

PS > elixir.bat --version
Erlang/OTP 25 [erts-13.0.4] [source] [64-bit] [smp:20:20] [ds:20:20:10] [async-threads:1] [jit:ns]

Elixir 1.14.2 (compiled with Erlang/OTP 25)
PS > dotnet fsi

Microsoft (R) F# Interactive version 12.8.0.0 for F# 8.0
Copyright (c) Microsoft Corporation. All Rights Reserved.

For help type #help;;

> <copy and paste above command>;;
val executeProcess: name: string -> arguments: string -> string

> executeProcess "dotnet" "--version";;
Successfull?: true
val it: string = "8.0.100-preview.6.23330.14
"

> executeProcess "elixir.bat" "--version";;
Successfull?: true
val it: string =
  "{"init terminating in do_boot",{undef,[{elixir,start_cli,[],[]},{init,start_em,1,[{file,"init.erl"},{line,1220}]},{init,do_boot,3,[{file,"init.erl"},{line,910}]}]}}
"

This is where I get this weird error of {"init terminating in do_boot",{undef,[{elixir,start_cli,[],[]},{init,start_em,1,[{file,"init.erl"},{line,1220}]},{init,do_boot,3,[{file,"init.erl"},{line,910}]}]}}. Searching and even looking up the line numbers in init.erl, this error seems to be because of Erlang version issues. However, that is not an issue on my machine. Elixir and Erlang via iex and erl work just fine, as does elixir.bat --version from the command line.

There seems to be something in how the .NET process launcher is interacting with the Elixir.bat that one or the other doesn’t like. Does anyone know what’s going on here? Is this an issue with elixir.bat on Windows?

(Note: There is a workaround, and it is to actually make the filename "powershell" with arguments "elixir --version". However, I don’t know why that works and the other doesn’t. The Elixir binaries/scripts are in my path, as are the Erlang binaries.)


Edit: I went ahead and tried this on the latest versions of Elixir 1.15.4 and Erlang/OTP 26. The Erlang "init terminated in do_boot" error seems to have gone away, but nothing is written to standard out when running this code as above. However, if I remove the redirection from standard out and reading, I get the following error in FSI:

> let executeProcess name arguments =
-     let startInfo = System.Diagnostics.ProcessStartInfo(
-         FileName = name,
-         Arguments = arguments
-     )
-     use p = new System.Diagnostics.Process(StartInfo = startInfo)
-     p.Start() |> printfn "Successfull?: %A"
- ;;
val executeProcess: name: string -> arguments: string -> unit

> executeProcess "elixir.bat" "--version";;
Successfull?: true
val it: unit = ()

> Error! Failed to load module 'elixir' because it cannot be found. Make sure that the module name is correct and
that its .beam file is in the code path.

Runtime terminating during boot ({undef,[{init,start_it,1,[{_},{_}]},{init,start_em,1,[{_},{_}]},{init,do_boot,3,[{_},{_}]}]})

Crash dump is being written to: erl_crash.dump...done

Showing Posts 1 to 7

lud

lud

Did you install elixir from something that requires some environment from your shell, like asdf for instance?

bmitc

bmitc OP

The issue appears on Windows, where I installed Erlang and Elixir via the official Windows installers, and asdf is not supported on Windows. I use asdf on Ubuntu, but this works fine there.

This has to somehow be related to how on Windows, Elixir is wrapped via scripts, and one isn’t calling binaries directly. But it’s strange how it works fine on the command line. I’m not sure there’s much else I would need to or can do on the .NET side.

cmo

cmo

I believe you’re right about this. You could call erl.exe with the args that the batch script passes to it.

I presume you don’t want to flip things and have elixir call F# via a port, because that’s not too hard. There is an ETF library in F#.

bmitc

bmitc OP

I presume you don’t want to flip things and have elixir call F# via a port, because that’s not too hard. There is an ETF library in F#.

Haha. :slight_smile: The context of my question is actually to help test and verify an encoding/decoding library I wrote myself in F# for the Erlang External Term Format. My main goal is playing around with some ideas around an Elixir Port and F# interaction, and so I wrote my own ETF library in F# since it’s not too hard and gives me control when integrating it into the port abstraction. This question is to help test the F# encoding/decoding across the various OS platforms using both regular tests and property-based tests. The example function I gave is similar to the real one, which is used in tests to write out a string to Elixir, have Elixir convert it to an Erlang term, then F# decodes it and tests it against what’s expected. Something like this:

[<Fact>]
let ``Decode tuple from stream`` () =
    @"{:ok, :another}" |> writeAndDecode |> should equal (ErlangTerm.Tuple [ErlangTerm.Atom "ok"; ErlangTerm.Atom "another"])

Calling elixir.bat --version as an argument to the powershell command works, but it isn’t entirely clear to me why that works but calling the script directly doesn’t work. Mainly trying to know why to further my understanding of how both Elixir and F# interact with the command line. It also seems like an issue with the Erlang crash dump when simply calling elixir.bat --version.

cmo

cmo

Very well. You do have to think about passing env vars on to child/sub processes, something I discovered when playing with porting elixir.bat to a Zig executable.

ETF library has caused me no issues other than the poor choice of namespaces.

bmitc

bmitc OP

You do have to think about passing env vars on to child/sub processes

It’s possible that that’s what PowerShell is doing properly when I use powershell elixir.bat --version. I have no idea though.

ETF library has caused me no issues other than the poor choice of namespaces.

Which ETF F# library are you using? Last time I checked there were a couple, including one for the BERT term format. My library just does a subset of the base ETF format, since some of them don’t make sense in the context I am thinking of. The encoding/decoding is rather easy, so I’ll probably keep my own, but it would be nice to see other implementations, especially if they’ve been kept up to date.

cmo

cmo

https://github.com/erpuno/etf

After setting things up, I loop over this:

// reply ok on startup
    sendOk (encode "0")
    try
        while true do
            inputBufferSize <- stdin.Read(inputBuffer, 0, 4)
            // input buffer should be size 4, which tells us the size of the message
            match inputBufferSize with
            | 4 -> ()
            | 0 ->
                logger.Debug "Port shutdown, exiting"
                cleanup logger connection
                Environment.Exit(int ReturnCode.Ok)
            | size ->
                logger.Error $"Expected 4 bytes, got {size} containing '{Encoding.UTF8.GetString(inputBuffer)}'"
                cleanup logger connection
                Environment.Exit(int ReturnCode.BadMessageSize)
                
            let msgSizeBytes =
                if BitConverter.IsLittleEndian
                then inputBuffer |> Array.take 4 |> Array.rev
                else inputBuffer |> Array.take 4
            let msgSize = BitConverter.ToInt32(msgSizeBytes, 0)
            
            // read the ETF
            inputBufferSize <- stdin.Read(inputBuffer, 0, msgSize)
            
            // decode the ETF
            let term = ETF.Decoder.decodeTerm inputBuffer
            
            match term with
            | Term.Tuple [Term.Binary requestId; msg] ->
                match decodeMessage msg with
                | SomeMessage(arg1, arg2) -> 
                ...
— All posts loaded —

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
Blokh
Hey guys, I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly Do you guys have any suggestions what is the best prac...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
Onor.io
I have what I’ve heard referred to as a “lookup table” in my database. This is a way of assigning codes to common values. One common lo...
New
jaybe78
Hello, I’m developing a online persistent chat system (what’s app) like using elixir/dynamodb/aws for a mobile app(flutter). The diffic...
New
Trolleger
What approach to take when sending live updates to “random” users Hi! I have a question, I have a little chat app, and when I create a DM...
New
widianto
I think I’ve found a small improvement I could contribute to &lt;%= web_namespace %&gt;.CoreComponents (installer/templates/phx_web/compo...
New

Other Trending Topics Top

garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
wintermeyer
There are three potential reasons for members of this forum to have a look at https://vutuv.de You are tired or annoyed of LinkedIn. Yo...
New
webofbits
Aludel - LLM Evaluation Workbench Aludel is an embeddable Phoenix LiveView dashboard for evaluating and comparing LLM prompts across mult...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews