Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Universal Install Script (2016) (xkcd.com)
82 points by guessmyname on April 14, 2023 | hide | past | favorite | 37 comments



I'm trying to build the same Rust program for Linux, Windows, and MacOS. Cross-compiling isn't the hard part. Rust can make Windows executables on Linux. Making an installer is. Most of the installer builders only run on Windows and use Microsoft components. "Inno", an ancient freeware program, will run under Wine. But it outputs an old-style .exe installer, not a newer .msi installer.

Packaging for Linux isn't much better. There's .deb, for which you need a "repository". There are "snaps", which is Canonical's scheme for getting developers under control of their App Store. There was Flatpak, but Canonical is trying to kill that off. There's AppImage, but the code to build those hasn't been updated in two years. There's always .zip files.

Not sure how to package for MacOS yet.


This is why i don't think the concept of an "installer" should be the way software gets published and distributed to end users. Very few software packages actually _need_ to have installers - things like system/hardware drivers are the ones that come to mind.

Instead, use the portable apps model (https://portableapps.com/) , where you have a single binary that runs, and can be deployed by a simple copy/extract. Ditto with uninstallation.

This is what MacOS has, so that's why mac software is just a bundle inside a directory (that ends in `.app`).


For Windows installers from Linux, check out NSIS...

https://nsis.sourceforge.io/Main_Page

From the features page:

"The NSIS compiler can be compiled for POSIX platforms like Linux and *BSD. Generated installer will still run on Windows only, but this way they can be generated without Windows or WINE."


Oh, Nullsoft. Hadn't heard of them in decades.

That generates an executable installer, not a .msi file or its more recent successor. But the installers will run on Windows 95!


Flatpak is still alive and well: it's commercially supported by Red Hat and has quite a following, especially in the GNOME world. It's last release was last month. Usually a user of Debian packages, I must admit that for desktop use Flatpak is a very slick solution.


Yeah, but I don't want to buy into the Flatpak vs Snap war.

Does anyone still use AppImage, or is it dying out?


As a side-note, the snap vs flatpak war is essentially canonical vs everyone else. It's easy enough to install flatpak on ubuntu distros, it's harder to install snap on some other distros where flatpak works wonders.

If you're worried, you can also just, do both. A packaging overhead of 2 is still better than maintaining your own distro- and version-specific packages, unless you submit it to the distros yourself or get others to package it for you.


AppImages are still widely used, it's just that the tooling surrounding them sucks.

At the end of the day, they're glorified zip files, not much different to self-extracting .exe files, and you'll have to figure out what libraries your application needs to run on various distros. Some bundlers attempt to do this for you but they're not infallible, so be prepared to test in different VMs.


> AppImages are still widely used, it's just that the tooling surrounding them sucks.

I just discovered that the hard way.[1]

[1] https://users.rust-lang.org/t/packaging-a-rust-application-f...


You can use WiX Toolset version 4 to create Windows installers. Version 3 is Windows-only, but Version 4 runs under .NET "the-one-that-runs-on-Linux". It produces MSI files.

https://wixtoolset.org/docs/intro/


You can just rename the macos binary to .app and it'll work. But generally you want an actual .app bundle, I made a tool for that in the past (in rust too!) slmjkdbtl/packapp you can check it out, i think the official apple docs are referenced in the source as well


I scripted Inno Setup running on Wine with bash for a really hacky internal CI thing for a while. The compiler will even run (via Wine) without X!


Just statically include everything in one executable. Or release the source and let others build & package it for their favourite OS.


This is an application for end users. Remember them?


Using a single executable file will make their life easier. And some users will be "power" users and will know how to package something. Make use of your user community.


There's only one executable, with no .dll or .so files. It needs some text and image assets that don't need to be in memory all the time, so I don't want to nail them into the running executable. (You can do that in Rust, and I do it for a few minor icons such as arrows that aren't going to change. But not for big stuff.)


According to the "Last-Modified" header on the png, and https://news.ycombinator.com/item?id=11264755 and https://news.ycombinator.com/item?id=11278013 this should have (2016) on it


Added. Thanks! Related:

Universal Install Script by XKCD – Combat Test - https://news.ycombinator.com/item?id=11522478 - April 2016 (17 comments)

Universal install script - https://news.ycombinator.com/item?id=11278013 - March 2016 (1 comment)

Universal Install Script - https://news.ycombinator.com/item?id=11264755 - March 2016 (4 comments)



Won't work at all without a `/bin/bash` executable. Maybe `/bin/sh` is even more universal? I always use `/usr/bin/env bash`, which looks in $PATH rather than relying on "global" namespaces (/, /usr, /usr/local, etc.)


I prefer just /bin/sh too, it's portable and generally faster. When I get to a point where I'd need bash extensions, it's a sign that I should be using another language.


Except where /bin/sh is actually a link to the "ash" shell, and stuff suddenly doesn't work the right way anymore.

I'm looking at you, Alpine Linux.


This reminds me of my package manager package manager

The idea you would chain together multiple package managers such as this:

  mpm install 
    script/https://get.rvm.io \
    rvm/1.9.3 \ 
   script/git@github.com/rubygems/rubygems/setup.rb \
   gem/rails \
   apt/mysql-server \
   apt/mysql-client \
 
   bundle/http://typosphere.org/stable.tgz
https://github.com/samsquire/ideas#12-the-package-manager-pa...


The curl one made me chuckle!

Might there be a case in which the git one and curl one both work?


Seems unlikely it could work for both. GitHub does not allow . in user or org name, so a $1 that works for GitHub would generally not work as a hostname for curl.


The 2023 version of this just sends chatgpt a prompt saying produce a bash script that installs $1 onto my machine.

The result of the prompt is evaluated by a root shell, naturally.


Once you have it installations, you can keep it up-to-date with https://github.com/topgrade-rs/topgrade


Probably should add a "wait" to the end. Otherwise lgtm, go ahead and ship.



Won't it break when one of the commands returns non-zero? I think you can replace the & with ;


No, & isn't the same as && which I think is what you're thinking.

& is for backgrounding:

    #!/bin/sh
    date
    sleep 5 &   # forks the command into the background, we proceed immediately
    date
    wait        # pauses until the backgrounded sleep returns
    date
has output

    Fri Apr 14 13:17:00 PDT 2023
    Fri Apr 14 13:17:00 PDT 2023
    Fri Apr 14 13:17:05 PDT 2023


Definitely missing one & after the git clone, else the cd into the directory after will fail, assuming the git clone takes non-zero time to execute.


yeah that one should definitely be more like

  { git clone ... ; cd "$1"; ./configure; make; make install } &
to run the group command (I had to look up the term in man bash) all in the background.

Using group commands can be kind of weird though because they're run in the environment of the running shell, so

  % mkdir -p /tmp/foo && cd /tmp/foo && pwd
  /tmp/foo
  % { mkdir bar; cd bar; echo $BASH_SUBSHELL ; }
  0
  % pwd
  /tmp/foo/bar
but if you do the group command in the background, bash runs it in a subshell[0] and the current directory for your shell doesn't change:

  % mkdir -p /tmp/foo && cd /tmp/foo && pwd
  /tmp/foo
  % { mkdir bar; cd bar; echo $BASH_SUBSHELL ; } &
  1
  % pwd
  /tmp/foo
[0] From man bash:

  If a command is terminated by the control operator &, the shell executes the command in the background in a subshell.


The script has single `&` which means the respective commands will run in background (and in parallel!) which effectively ignores their return codes.


&& would

& detaches them essentially running them in parallel?


No, first because it's put in background.

Second because there's no `-e`.


the github one got a laugh out of me




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: