I am thinking about building a tool to use from the command line.
The tool would provide a set of commands that interact with a remote API (from a bug tracking service, imagine something like Jira). The objective of the tool is to provide an alternative way to perform simple modifications directly from the terminal, instead of having to open the page in the web browser, etc.
Ideally I want the tool to be distributed as a single binary that can be put in the $PATH and executed.
I’ve seen that Go and Rust (apart from the always beloved C) are adequate for this requirements. But the thing is: I’m in love with Elixir and I would love to write this tool in it. Would Elixir allow me to generate a ready-to-run binary file?
You’d still need the VM installed in the machine and to start up before the CLI tool can be run so it’s not an “independent” binary like Go, C, or Rust.
I have written several CLI tools in Elixir now using escript, including the specific one you mentioned (remote API) and I love it enough that I’ve been using it instead of Ruby. I’m not certain about distribution though since I haven’t had any reason to share it.
Set up the project for CLI:
# add to mix.exs in the project function
escript: [main_module: YourProjectName.CLI],
Create the entry point:
defmodule YourProjectName.CLI do
def main(args) do
# - use OptionParser to parse args
# - use IO.ANSI for color
# - use System.halt(code) to exit with an error code
# - use ExUnit.CaptureIO to capture terminal output for testing
IO.puts "Howdy Earth!"
Build and run
# build it
# install it into your path
If you use a release though the VM is indeed bundled in.
There’s no way to get a single exe file with Elixir (or indeed Erlang) but you don’t need the entire development environment installed either. Even with Escript (which is as close as I think you’ll come to a standalone binary) you’ll need some files from the Erlang runtime.
To me, it’s 6 of one and half-a-dozen of the other because even with a “standalone” binary you’ll often still need shared objects/dll’s to be installed for things to work. One could, I suppose, build a single statically linked binary but that’s not a panacea either because the exe will be rather large.
Good point, but shipping a whole VM for a small CLI app doesn’t sit right with me.
I would just use Rust if it was a little project that I could spend some time learning the proper Rust libraries for (still learning the language when I get time… randomly…), otherwise I would just use C++, which has almost too many libraries to handle about anything and I already would know which I would use. ^.^
Really though, it depends on the purpose, like if Python will be on the destinations then a simple Python script would be best, or if Windows then use powershell, etc… etc…
So you don’t use any Ruby, Perl or Python?
As far as I know, only the only choice for a completely stand alone binary these days is Go.
( I’ve no idea what Rust’s runtime, need to check that out).
Even boring old C is dependent on shared libraries.
Everything I’ve written in Elixir is a cli more or less. Where Elixir really shines for this kind of stuff is when you have a 24 core server and enough work to keep those cores busy. That’s not every cli app, but if you have that scale of problem, it’s so much easier to deal with in Elixir.
While the default erlang runtime is 200meg, there is a lot that can be trimmed; escripts only require the erlang runtime. While maybe not comparable to a minimal Ruby or Python installation, it’s certainly the same as any Java app. Elixir cli’s at least start much faster than most java apps I’ve used, they do have a minimal runup time that makes them less than ideal for some uses.
For a CLI tool? Probably not, but it depends on the context. Ruby, Perl, Python (latter two especially) are almost universal in Unix boxes. It’s a good bet they’re installed. If you’re making a simple CLI tool for many different kinds of users and platforms, I do think shipping a whole VM or expecting a runtime isn’t the best way to go, but I’m not that strict about it (I use Node CLI tools!). If it’s more complex and Elixir, Ruby, or Python can be expected to generally be available, go ahead.
youtube-dl, a famous CLI tool uses Python and it hasn’t hurt its adoption.
Thank you all for your replies! This is why I love this community
As @bbense says, I could use Ruby, Perl or Python. In fact the tool I am going to build is a replacement for an existing one that is currently written in Ruby. I am choosing to replace it because if I want to use the tool everywhere on my system, I have to add the gem in the global Ruby installation. This should not be a problem if the tool did not require other gems which get also installed globally. I consider this a little dirty and it is what I would like to avoid.
The idea of @brainbag and @Onor.io resembles more closely what I have in mind. Building an escript would allow me to distribute my package as a single binary with its dependencies bundle (it would still require the Erlang VM, but so happens with JARs).
I am going to opt for Go or Rust (I like more the Rust approach because it is more close to functional programming) because I want to keep the dependencies absolutely minimum, the ideal would be to distribute a binary that could be run as is. I am a little bit sad about not using Elixir, but @bbsense has a point when he says that “Where Elixir really shines for this kind of stuff is when you have a 24 core server and enough work to keep those cores busy”.
So, Go or Rust it is. Thank you all!
I’ve been using a cli project as an excuse to learn Rust. I considered a lot of the same things at first. Since my project has zero network interfacing, Elixir seemed like overkill. I’ve used Go before and although it was kinda fun, I didn’t get hooked in any where near the same way Rust or Elixir got me. FWIW, there is a lot of fast software written in Go.
My 2 cents on this. Imho elixir is just fine for a CLI tool. Installing a erlang vm in a Linux distro is straightforward and imho you can provide a container in case needed. I have been developing client in go etc. In long-term imho you should look at what is easy to maintain, imho functional lang it is easier then the objected world. So IMHO even if the 1 binary at 1st glance can be a killer feature imho should not be the fondamental factor for the choice.
Caveat: “escripts will only work for pure Elixir/Erlang” (at least in their portable/vanilla forma), because of limitations with respect to NIF:
I’d say use Rust. You can distribute a binary and learn a lot of cool stuff