Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for cross-compilation with Nix #44

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ Run `./build.sh`* to build. The first time you run this, it could take a while,

\* On Windows, it's `.\build.ps1`. Though you may need `powershell.exe -executionpolicy bypass -file .\build.ps1` due to permissions issues. I don't personally know a thing about Windows permissions, so if anyone has a better idea please let me know.

## Cross-compiling

If we're on x86-64 Linux, we can use `nix develop` to enter a shell from which we can cross-compile:
```sh
~/.ghcup/bin/runghc Build.hs --target=x86_64-w64-mingw32
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weirdly, we have to remove the Windows target from crossPlatforms in order for plain ~/.ghcup/bin/runghc Build.hs to work, i.e. to build for the host platform. This seems like a Haskell.nix bug. It's not a huge issue though, as we don't have much reason to use Nix at all for such a build. It would be nice to get cached dependencies though.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This command actually fails quickly for TH reasons. It may be salvageable, but the fact it doesn't "just work" seems a limitation of the shell-based approach, as opposed to nix build.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we just use nix build .#x86_64-w64-mingw32:monpad:exe:monpad, we would need to add some Nix config for compiling the non-Haskell parts of the project.

Perhaps it could just shell out to runghc Build.hs assets.

~/.ghcup/bin/runghc Build.hs --target=x86_64-unknown-linux-musl
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works, but isn't actually useful without passing some extra flags, since ldd shows just as many dependencies as the GCC version.

Again, this is a drawback of the shell-based approach.

Copy link
Owner Author

@georgefst georgefst Aug 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the other hand nix build .#x86_64-unknown-linux-musl:monpad:exe:monpad fails building libevdev, whereas interestingly the shell+cabal approach does not.

I assume the issue is getting hold of a statically-linked libevdev. I've asked about this on r/haskell.

If this is a real sticking point, we could somehow (separate branch, or Nix-based override) compile without --system-device support for now. It isn't actually necessary for my immediate use case. It's enough (though hacky) to replace the fields under os(linux) with just hs-source-dirs: windows.

It's possible that my Haskell evdev library is in some way not totally Musl compatible. I'd hope it would be, but it's untested. I recall the evdev-rs needing changes to explicitly support it. Otherwise maybe Haskell.nix just needs to be told about the native dependency.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have static musl builds working now, after providing a static libevdev. cabal build doesn't produce a static exe because the magic is in nix build somewhere. Another killer for nix develop+cabal approach I originally desired.

~/.ghcup/bin/runghc Build.hs --target=aarch64-unknown-linux-gnu
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed aarch64-multiplatform from crossPlatforms because this doesn't actually work. It causes mysterious evaluation-time failures (nix develop or nix build).

```
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the system GHC here is pretty odd. Can we just use cabal run (or even ./Build.hs)?


Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could do with a section on deploying the resulting artefacts.

Copy link
Owner Author

@georgefst georgefst Aug 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we'll manage to fully statically link everything, meaning we'll just have a single executable file to deploy.

If we are stuck with shared libraries, we'll need commands like:

  • TARGET_DIR=... sh -c 'rsync result/ $TARGET_DIR/ -a --copy-links && rsync dist/rsc/ $TARGET_DIR/bin/rsc/ -a --copy-links'
  • TARGET_NAME=... sh -c 'nix copy --to ssh://$TARGET_NAME .#aarch64-unknown-linux-gnu:monpad:exe:monpad && scp ./result/bin/monpad $TARGET_NAME:tmp/monpad-cross-nix'

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We now have static Linux builds, but Windows needs a load of DLLs (weirdly this is an inversion of the usual non-Nix state of things). Can we compile statically with MinGW?

# Run

Run `./dist/monpad` to start the server (you can pass the `-h` flag to see all options).
Expand Down
Loading