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 OpenBSD and NetBSD? #707

Closed
hasufell opened this issue Dec 8, 2022 · 14 comments · Fixed by #1138
Closed

Add OpenBSD and NetBSD? #707

hasufell opened this issue Dec 8, 2022 · 14 comments · Fixed by #1138

Comments

@hasufell
Copy link
Member

hasufell commented Dec 8, 2022

haskell/unix#262

But we have no bindists so far.

@habibalamin
Copy link
Collaborator

habibalamin commented Oct 10, 2024

I've been messing around with GHCup on OpenBSD (7.5), and these are the roadblocks to getting GHCup to compile and run:

  • lzma-static dependency's vendored liblzma doesn't compile on OpenBSD (though upstream liblzma does).
    • Solution 1: switch to lzma, which doesn't vendor liblzma (funnily enough, in cabal.project.release, we pass +static as a build flag constraint to lzma in some environments, but it doesn't seem to do anything with it, not even do a static build, which is what I expected; if you can explain why we pass it that build flag, I'd appreciate it).

      libarchive has a transitive dependency on lzma-static, so the above solution alone doesn't entirely solve the problem; you'd also have to enable the tar build flag to use zip and tar dependencies instead of libarchive.

    • Solution 2: generate the platform-specific config.h file for OpenBSD.

      lzma-static vendors liblzma from the xz source tree. Due to liblzma disallowing compilation on architectures other than 32- or 64-bit, and the inability to use the sizeof() macro during the preprocessing phase to test for this condition before runtime, it requires the use of a configure script to define SIZEOF_SIZE_T. liblzma upstream includes this configure script, but lzma-static opts instead to vendor platform-specific config.h header files, which it has a gen-header.sh script to generate (the script fetches an xz source tarball to use the configure script from it to and copies the generated config.h file).

      diff -ru a/gen-header.sh b/gen-header.sh
      --- a/gen-header.sh
      +++ b/gen-header.sh
      @@ -13,7 +13,7 @@ XZ_URL="https://tukaani.org/xz/${XZ_BALL}"
       
       [ -f "${XZ_BALL}" ] || curl -LO "${XZ_URL}"
       
      -[ -d "xz-${XZ_VER}" ] || tar xf "${XZ_BALL}"
      +[ -d "xz-${XZ_VER}" ] || bzcat "${XZ_BALL}" | tar xf -
       
       cd "xz-${XZ_VER}"
       ./configure
      @@ -69,6 +69,28 @@ case "$(uname -s)" in
                     cp config.h ../autoconf-freebsd-aarch64/config.h ;;
          esac
          ;;
      +	"OpenBSD"|"openbsd")
      +		case "$(uname -m)" in
      +			x86_64|amd64)
      +				if [ "$(getconf LONG_BIT)" = "32" ] ; then
      +					cp config.h ../autoconf-openbsd-i386/config.h
      +				else
      +					cp config.h ../autoconf-openbsd-x86_64/config.h
      +				fi
      +				;;
      +			i*86)
      +				cp config.h ../autoconf-openbsd-i386/config.h ;;
      +			armv7*)
      +				cp config.h ../autoconf-openbsd-arm/config.h ;;
      +			aarch64|arm64|armv8l)
      +				if [ "$(getconf LONG_BIT)" = "32" ] ; then
      +					cp config.h ../autoconf-openbsd-arm/config.h
      +				else
      +					cp config.h ../autoconf-openbsd-aarch64/config.h
      +				fi
      +				;;
      +		esac
      +		;;
        *) die "Unknown platform" ;;
       esac
       
      diff -ru a/lzma-static.cabal b/lzma-static.cabal
      --- a/lzma-static.cabal
      +++ b/lzma-static.cabal
      @@ -91,6 +91,15 @@ library
             include-dirs: autoconf-freebsd
           elif arch(aarch64)
             include-dirs: autoconf-freebsd-aarch64
      +  elif os(openbsd)
      +    if arch(x86_64)
      +      include-dirs: autoconf-openbsd-x86_64
      +    elif arch(i386)
      +      include-dirs: autoconf-openbsd-i386
      +    elif arch(arm)
      +      include-dirs: autoconf-openbsd-arm
      +    elif arch(aarch64)
      +      include-dirs: autoconf-openbsd-aarch64
         else
           build-depends: unbuildable<0
           buildable: False

      (I've only built on OpenBSD amd64.)

    • Solution 3: we can go further and use a generic fallback config.h file to make the vendored liblzma (which hasn't been updated since the initial commit) easily buildable on OpenBSD, and other arbitrary platforms which don't have their own config.h file. (We can still also use an OpenBSD-specific config.h file if we want.)

      diff -ru a/lzma-static.cabal b/lzma-static.cabal
      --- a/lzma-static.cabal
      +++ b/lzma-static.cabal
      @@ -92,8 +92,7 @@ library
           elif arch(aarch64)
             include-dirs: autoconf-freebsd-aarch64
         else
      -    build-depends: unbuildable<0
      -    buildable: False
      +    include-dirs: autoconf-generic
       
         c-sources:
           cbits/lzma_wrapper.c

      Most of the platform-specific definitions seem to be unnecessary (liblzma has fallback behaviour, and the generated config.h even comments out some definitions instead of defining them as 0), but SIZEOF_SIZE_T is required and can't simply be set to a reasonable default.

      // Incorrect(?) SIZE_MAX:
      //   - Interix headers typedef size_t to unsigned long,
      //     but a few lines later define SIZE_MAX to INT32_MAX.
      //   - SCO OpenServer (x86) headers typedef size_t to unsigned int
      //     but define SIZE_MAX to INT32_MAX.
      #if defined(__INTERIX) || defined(_SCO_DS)
      #	undef SIZE_MAX
      #endif
      
      // The code currently assumes that size_t is either 32-bit or 64-bit.
      #ifndef SIZE_MAX
      #	if SIZEOF_SIZE_T == 4
      #		define SIZE_MAX UINT32_MAX
      #	elif SIZEOF_SIZE_T == 8
      #		define SIZE_MAX UINT64_MAX
      #	else
      #		error size_t is not 32-bit or 64-bit
      #	endif
      #endif
      #if SIZE_MAX != UINT32_MAX && SIZE_MAX != UINT64_MAX
      #	error size_t is not 32-bit or 64-bit
      #endif

      There is a way to solve this to prevent compilation on non-32- or 64-bit platforms without requiring a configure script, but it involves a preprocessor macro to emit uncompilable code if a certain condition is met, which produces an error message unrelated to the actual failing condition (though, in practice, the macro name and its arguments are shown, so having something like FAIL_BUILD_IF(sizeof(size_t) < 4) makes it pretty obvious why the build failed). It basically involves inserting something like the following code somewhere, maybe in cbits/lzma_wrapper.c before the C code which provides the Haskell wrapper:

      #define FAIL_BUILD_IF(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
      
      // This function should never be called, it's simply a container so that
      // `FAIL_BUILD_IF` can emit uncompilable code into it.
      void _fail_build_if() {
        // The code currently assumes that size_t is either 32-bit or 64-bit.
        FAIL_BUILD_IF(sizeof(size_t) < 4);
      #		define SIZEOF_SIZE_T 4
        FAIL_BUILD_IF(sizeof(size_t) > 4 && sizeof(size_t) < 8);
      #		undef SIZEOF_SIZE_T
      #		define SIZEOF_SIZE_T 8
        FAIL_BUILD_IF(sizeof(size_t) > 8);
      
      // Incorrect(?) SIZE_MAX:
      //   - Interix headers typedef size_t to unsigned long,
      //     but a few lines later define SIZE_MAX to INT32_MAX.
      //   - SCO OpenServer (x86) headers typedef size_t to unsigned int
      //     but define SIZE_MAX to INT32_MAX.
      #if defined(__INTERIX) || defined(_SCO_DS)
      #	undef SIZE_MAX
      #endif
      
      #	ifndef SIZE_MAX
      #		if SIZEOF_SIZE_T == 8
      #			define SIZE_MAX UINT64_MAX
      #		elif SIZEOF_SIZE_T == 4
      #			define SIZE_MAX UINT32_MAX
      #		else
      #			error size_t is not 32-bit or 64-bit
      #		endif
      #	endif
      #	if SIZE_MAX != UINT32_MAX && SIZE_MAX != UINT64_MAX
      #		error size_t is not 32-bit or 64-bit
      #	endif
      }

      Apart from the SIZEOF_SIZE_T issue, a generic config.h which lacks HAVE__BOOL & HAVE_STDBOOL_H causes the following compilation error:

      cbits/common/sysdefs.h:144:23: error:
           error: cannot combine with previous 'char' declaration specifier
          |
      144 | typedef unsigned char _Bool;
          |                       ^
      typedef unsigned char _Bool;
                            ^
      
      cbits/common/sysdefs.h:144:1: error:
           warning: typedef requires a name [-Wmissing-declarations]
          |
      144 | typedef unsigned char _Bool;
          | ^

      (The terminal colours on the first error highlight the underscore, so the caret isn't just pointing to the whole word _Bool, that's how I figured out the fix). This has a simple fix:

      diff -ru a/cbits/common/sysdefs.h b/cbits/common/sysdefs.h
      --- a/cbits/common/sysdefs.h
      +++ b/cbits/common/sysdefs.h
      @@ -140,10 +140,10 @@
       #ifdef HAVE_STDBOOL_H
       #	include <stdbool.h>
       #else
      +#	define bool _Bool
       #	if ! HAVE__BOOL
      -typedef unsigned char _Bool;
      +typedef unsigned char bool;
       #	endif
      -#	define bool _Bool
       #	define false 0
       #	define true 1
       #	define __bool_true_false_are_defined 1
  • GHCup itself refuses to run on any platform it doesn't explicitly recognise.
    • Solution 1: add OpenBSD as a supported platform in lib/GHCup/Types.hs, and lib/GHCup/Platform.hs.
    • Solution 2: like with lzma-static's liblzma, I feel it would be best to simply allow it to build and run on any platform (which GHC & GHCup themselves can run on). Is there a reason GHCup doesn't do that?
  • As mentioned, bindists. Building GHC on OpenBSD has some special considerations.
    • OpenBSD tar doesn't support the -T flag, used by binary-dist Make target.

    • GNU Make is required.

    • OpenBSD's autoconf & automake are shell scripts which delegate to the versions specified by AUTOCONF_VERSION & AUTOMAKE_VERSION. It fails to run without specifying those environment variables.

    • ln doesn't recognise the -v flag, so I use this shim:

      #!/usr/bin/env sh
      
      error() {
        >&2 echo "$@"
      }
      
      without_v() {
        printf '%s' "$1" | sed 's:v::'
      }
      
      without_verbose_flags() {
        for arg in "$@"; do
          case "$arg" in
            -*)
              # `local` is not strictly POSIX shell, but it's available
              # on OpenBSD ksh, and it's essential if we want code that
              # isn't too buggy, IMO.
              local flags="$(without_v "$arg")"
      
              if [ "$flags" != '-' ]; then
                printf '%s ' "$flags"
              fi;;
            *) printf '%s ' "$arg";;
          esac
        done | sed 's: $::'
      }
      
      verbose_flag_given() {
        for arg in "$@"; do
          case "$arg" in
            -*)
              if [ "$(without_v "$arg")" != "$arg" ]; then
                return 0
              fi
          esac
        done
      
        return 1
      }
      
      if verbose_flag_given "$@"; then
        error "WARNING: ln given \`-v\`, but doesn't understand; using dumb shim to ignore!"
      fi
      
      /bin/ln $(without_verbose_flags "$@")

      I'm sure one could improve it by actually acting on the -v flag, but you obviously don't need that for the build to work. (I tweaked the shim slightly from what I originally wrote in my build scripts, to better name certain functions, so apologies if I broke it; I do have my original scripts if needed.)

    • Some older GHC & OpenBSD versions also require patching. Some OpenBSD versions have different package or symlink requirements. I have some build scripts for some older versions:

      • GHC 8.2.2 on OpenBSD 6.6:

        diff -ru a/libraries/Cabal/Cabal/Distribution/PackageDescription/Configuration.hs b/libraries/Cabal/Cabal/Distribution/PackageDescription/Configuration.hs
        --- a/libraries/Cabal/Cabal/Distribution/PackageDescription/Configuration.hs
        +++ b/libraries/Cabal/Cabal/Distribution/PackageDescription/Configuration.hs
        @@ -56,7 +56,8 @@
         import Distribution.Types.Condition
         import Distribution.Types.DependencyMap
         
        -import qualified Data.Map as Map
        +import qualified Data.Map.Lazy as Map
        +import qualified Data.Map.Strict as Map.Strict
         import Data.Tree ( Tree(Node) )
         
         ------------------------------------------------------------------------------
        @@ -219,7 +220,7 @@
             mp m@(Right _) _           = m
             mp _           m@(Right _) = m
             mp (Left xs)   (Left ys)   =
        -        let union = Map.foldrWithKey (Map.insertWith' combine)
        +        let union = Map.foldrWithKey (Map.Strict.insertWith combine)
                             (unDepMapUnion xs) (unDepMapUnion ys)
                     combine x y = simplifyVersionRange $ unionVersionRanges x y
                 in union `seq` Left (DepMapUnion union)
      • GHC 8.6.5 on OpenBSD 6.6:

        diff -ru a/rts/RtsSymbols.c b/rts/RtsSymbols.c
        --- a/rts/RtsSymbols.c
        +++ b/rts/RtsSymbols.c
        @@ -278,9 +278,7 @@
         #endif
         
         #if defined(openbsd_HOST_OS)
        -#define RTS_OPENBSD_ONLY_SYMBOLS                            \
        -     SymE_NeedsProto(__guard_local)                         \
        -     SymE_NeedsProto(_DYNAMIC)
        +#define RTS_OPENBSD_ONLY_SYMBOLS SymE_NeedsProto(__guard_local)
         #else
         #define RTS_OPENBSD_ONLY_SYMBOLS
         #endif
      • GHC 8.8.4 on OpenBSD 6.8:

        • diff -ru a/utils/iserv/ghc.mk b/utils/iserv/ghc.mk
          --- a/utils/iserv/ghc.mk
          +++ b/utils/iserv/ghc.mk
          @@ -32,7 +32,7 @@
           # need it there's no alternative.
           # Don't do this on FreeBSD to work around #17962.
           ifeq "$(TargetElf)" "YES"
          -ifeq "$(findstring $(TargetOS_CPP), solaris2 freebsd)" ""
          +ifeq "$(findstring $(TargetOS_CPP), solaris2 freebsd openbsd)" ""
           # The Solaris linker does not support --export-dynamic option. It also
           # does not need it since it exports all dynamic symbols by default
           utils/iserv_stage2_MORE_HC_OPTS += -optl-Wl,--export-dynamic
        • GCC must be installed (not Clang).
        • python3 is not symlinked to python3.$MINOR by default.

@hasufell
Copy link
Member Author

This is great work.

A few comments:

switch to lzma

I don't really trust OpenBSD/NetBSD to care about binary compatibility. So I want to have as few C libraries linked as possible. We can't really fix ghcup linkage and distribute it, because ghcup upgrade would simply fail.

But it could be a stop-gap.

we pass +static as a build flag constraint to lzma in some environments, but it doesn't seem to do anything with it, not even do a static build, which is what I expected; if you can explain why we pass it that build flag, I'd appreciate it).

That would be odd, since the build would then fail on windows.

It's per platform:

if os(linux)
  if arch(x86_64) || arch(i386)
    package *
      ghc-options: -split-sections -optl-static
elif os(darwin)
  constraints: zlib +bundled-c-zlib,
               lzma +static
elif os(mingw32)
  constraints: zlib +bundled-c-zlib,
               lzma +static,
               text -simdutf,
               vty-windows >=0.2.0.2
  if impl(ghc >= 9.4)
    constraints: language-c >= 0.9.3
elif os(freebsd)
  constraints: zlib +bundled-c-zlib,
               zip +disable-zstd
  package *
    ghc-options: -split-sections

libarchive has a transitive dependency on lzma-static, so the above solution alone doesn't entirely solve the problem; you'd also have to enable the tar build flag to use zip and tar dependencies instead of libarchive.

I'm ok switching to tar for some platforms. It has most bugs fixed that caused me to migrate to libarchive.


As for lzma-static: I'd be fine to switch to autoconf based build. I've done that for libarchive too, but it's some maintenance overhead to e.g. clean up the configure.ac and make adjustments.

@habibalamin
Copy link
Collaborator

we pass +static as a build flag constraint to lzma in some environments, but it doesn't seem to do anything with it, not even do a static build, which is what I expected; if you can explain why we pass it that build flag, I'd appreciate it).

That would be odd, since the build would then fail on windows.

It's per platform:

To clarify: macOS doesn't support static linking, too, so I was confused, but I just assumed, “if it's not a build flag that configures whether to compile a vendored liblzma like lzma-static does, then it's maybe a flag that Cabal understands by default that configures whether to use static linking?”,

but I couldn't find any Cabal documentation that said that, and I knew macOS, which we enable the flag on, doesn't support static linking, so that's how I discounted that possibility.

I'm ok switching to tar for some platforms. It has most bugs fixed that caused me to migrate to libarchive.

What kind of bugs are we talking about? If they're relevant for GHCup (cause specific issues/breakages under some conditions for GHCup itself), we should link to them from our own issues, so people can tackle them.

As for lzma-static: I'd be fine to switch to autoconf based build. I've done that for libarchive too, but it's some maintenance overhead to e.g. clean up the configure.ac and make adjustments.

Adjustments are already being made for Darwin's config.h in gen-header.sh (in lzma-static). Since the output of gen-header.sh is committed anyway, that part can be removed, but if we switch to an Autoconf-based build, we can remove gen-header.sh entirely,

but keep that portion of the script which seds whatever it needs to in the resulting config.h header file for whatever platforms it needs to do it for (or just fix whatever files need to be fixed pre-configure step so that the config.h header file just comes out correctly on Darwin without the need to sed it).

Obviously, the ideal solution is to fix the issue upstream in xz. If their configure script for liblzma is producing incorrect/less-optimal header files for some platforms, that should be fixed. This is a tricky issue, though; with the recent developments in xz upstream, I'm not sure if the maintainer would be willing at this time to look at contributions that allow it to build (or improve it) on Darwin w/o patching or seding or whatever.

Either way, if we're switching to an Autoconf-based build, that suggests you're trying to remove the arbitrary restriction lzma-static has on only supporting whitelisted platforms, in which case you'd probably want to do the same for GHCup. Perhaps we can have whitelisted supported platforms, but only emit a first-launch warning instead of preventing people from using GHCup entirely, and maybe emit a warning for GHC versions which don't explicitly support the platform and we don't have patches for.

Otherwise, if you want to keep the whitelisted-platforms approach, we can just add the OpenBSD-specific config.h header file to lzma-static, which entirely fixes that build issue for OpenBSD, and we can postpone the project of opening up unofficial support for arbitrary (UNIXy/POSIXy) platforms, or decide not to do that at all.

@hasufell
Copy link
Member Author

Yes, I think the next step is to have lzma-static with proper autoconf.

@habibalamin
Copy link
Collaborator

habibalamin commented Oct 12, 2024

I think GHCup codebase should also be modified to support shims to make GHC build on certain platforms; I'm sure it supports patches to allow older GHC versions to build on officially unsupported platforms, so this would be a similar thing, it would even be setup before the patch phase of the build.

All it would take is prepending some shim directory to the PATH before running the build steps, and allowing the manifests or whatever they're called to add custom shims (and specify what platforms they're needed on, but a shim can without too much difficulty forward to the original command except on the platforms it's needed on).

I'm happy to do the tedious work (over a long span of time, bit by bit) to figure out all the problems with getting (mostly older) versions of GHC to build on (mostly older) versions of OpenBSD and write the build scripts to generate bindists and incorporate those patches, shims, etc. into the GHCup manifests, too (my focus will probably be equally split between amd64 and arm64, but hey, I might play around with other architectures that OpenBSD supports).

That said, GHC versions will probably be released at a faster rate than I could keep up, unless the newer versions don't require too much work to get to build on newer versions of OpenBSD and/or I let support for older GHC and/or OpenBSD versions languish.

I think there's some work upstream to get OpenBSD better supported, so hopefully, it shouldn't be an issue at some point.

@dfordivam
Copy link
Collaborator

@habibalamin I see that you have mostly figured out the steps for getting ghcup to compile on openbsd (including generation of lzma-staticautoconf). Could you push the code on forks or open PRs on https://github.com/hasufell/lzma-static and ghcup

@dfordivam
Copy link
Collaborator

lzma-static with proper autoconf.

Oh I missed the "proper autoconf" part, so get rid of all config.h and use build-type: Configure.
In that case its a bit more work..

@habibalamin
Copy link
Collaborator

Appreciate you taking on the job of switching lzma-static's build method to autoconf (though I was happy to do it and still am if you like).

I'll make the changes to GHCup when I get a chance hopefully before this weekend.

@habibalamin
Copy link
Collaborator

habibalamin commented Oct 20, 2024

I was able to build GHCup on OpenBSD 6.8 amd64 only a few days ago, but then I upgraded my installation to 7.5 right afterwards, as it was woefully out of date (latest is 7.6, never got around to finishing).

That was right before I left the message about getting this working on OpenBSD. Now, it would involve getting this building on GHC 9.6 (and OpenBSD 7.6 may be on GHC 9.8 on its ports).

I am now getting a lot of missing imports (“variable not in scope”) build errors on my OpenBSD 7.5 amd64 machine when making my changes on master that I don't get on master on my macOS aarch64 machine.

It seems to mostly be Control.Monad stuff (forM, when, join, …) in different modules, but every time I fix the errors that show up and rebuild, more missing imports in other modules shows up.

I don't have the time to finish this right now and I don't even know how many errors I'll have to fix given how GHC hides some until I fix previous (dependency?) modules, but I'll get back to it at some point in the coming week if I can.

I also got a missing Alternative (Either String) instance.

My OpenBSD machine is running GHC 9.6.4, and my macOS is running GHC 9.6.2, however, I think the real issue is that, for whatever reason, I have to add base to allow-newer: in the Cabal project file (cabal.project.release) (for both machines, since both are on GHC 9.6 series) to get the build plan solver to even allow building to begin.

The proper solution to this is to figure out what's holding the base dependency back, because our explicit version bounds for it should be fine for GHC 9.6 series and later, so we don't have to allow-newer: base and presumably cause a bunch of other packages to upgrade as well (I'm not sure exactly how allow-newer: works).

This means my transformers on OpenBSD is >= 1.6.something, and on my macOS machine, it's 1.5.6.2, which gets rid of the orphan Alternative (Either String) instance in Control.Monad.Trans.Error or something, maybe because my base is 4.18.0.0 on my macOS machine due to using GHC 9.6.2 but my OpenBSD uses base 4.18.2.0 which affects which other packages the solver chooses? (I'm doing allow-newer: base on both machines).

I haven't tracked down why the sudden need to import Control.Monad everywhere, though, or how it works without it on my macOS package versions.

@habibalamin
Copy link
Collaborator

Anyway, this is the diff needed for OpenBSD separate from the concern of getting it to build with recent OpenBSD versions which come with packages of recent GHC versions. If I don't get round to dealing with that stuff, which is not really particular to OpenBSD, then someone can create a PR by starting with these changes.

diff --git a/lib-opt/GHCup/OptParse/ChangeLog.hs b/lib-opt/GHCup/OptParse/ChangeLog.hs
index 97bf9d2..797cfef 100644
--- a/lib-opt/GHCup/OptParse/ChangeLog.hs
+++ b/lib-opt/GHCup/OptParse/ChangeLog.hs
@@ -136,6 +136,7 @@ changelog ChangeLogOptions{..} runAppState runLogger = do
               Darwin  -> exec "open" [T.unpack $ decUTF8Safe $ serializeURIRef' uri] Nothing Nothing
               Linux _ -> exec "xdg-open" [T.unpack $ decUTF8Safe $ serializeURIRef' uri] Nothing Nothing
               FreeBSD -> exec "xdg-open" [T.unpack $ decUTF8Safe $ serializeURIRef' uri] Nothing Nothing
+              OpenBSD -> exec "xdg-open" [T.unpack $ decUTF8Safe $ serializeURIRef' uri] Nothing Nothing
               Windows -> do
                 let args = "start \"\" " ++ (T.unpack $ decUTF8Safe $ serializeURIRef' uri)
                 c <- liftIO $ system $ args
diff --git a/lib-tui/GHCup/Brick/Actions.hs b/lib-tui/GHCup/Brick/Actions.hs
index 020ce0b..7e528e4 100644
--- a/lib-tui/GHCup/Brick/Actions.hs
+++ b/lib-tui/GHCup/Brick/Actions.hs
@@ -458,6 +458,7 @@ changelog' (_, ListResult {..}) = do
             Darwin  -> exec "open" [T.unpack $ decUTF8Safe $ serializeURIRef' uri] Nothing Nothing
             Linux _ -> exec "xdg-open" [T.unpack $ decUTF8Safe $ serializeURIRef' uri] Nothing Nothing
             FreeBSD -> exec "xdg-open" [T.unpack $ decUTF8Safe $ serializeURIRef' uri] Nothing Nothing
+            OpenBSD -> exec "xdg-open" [T.unpack $ decUTF8Safe $ serializeURIRef' uri] Nothing Nothing
             Windows -> do
               let args = "start \"\" " ++ (T.unpack $ decUTF8Safe $ serializeURIRef' uri)
               c <- liftIO $ system $ args
diff --git a/lib/GHCup/Platform.hs b/lib/GHCup/Platform.hs
index 93dcd05..15669e6 100644
--- a/lib/GHCup/Platform.hs
+++ b/lib/GHCup/Platform.hs
@@ -119,11 +119,17 @@ getPlatform = do
         either (const Nothing) Just . versioning . decUTF8Safe'
           <$> getFreeBSDVersion
       pure $ PlatformResult { _platform = FreeBSD, _distroVersion = ver }
+    "openbsd" -> do
+      ver <-
+        either (const Nothing) Just . versioning . decUTF8Safe'
+          <$> getOpenBSDVersion
+      pure $ PlatformResult { _platform = OpenBSD, _distroVersion = ver }
     "mingw32" -> pure PlatformResult { _platform = Windows, _distroVersion = Nothing }
     what -> throwE $ NoCompatiblePlatform what
   lift $ logDebug $ "Identified Platform as: " <> T.pack (prettyShow pfr)
   pure pfr
  where
+  getOpenBSDVersion = lift $ fmap _stdOut $ executeOut "uname" ["-r"] Nothing
   getFreeBSDVersion = lift $ fmap _stdOut $ executeOut "freebsd-version" [] Nothing
   getDarwinVersion = lift $ fmap _stdOut $ executeOut "sw_vers"
                                                         ["-productVersion"]
@@ -306,6 +312,7 @@ getStackGhcBuilds PlatformResult{..} = do
             [] -> []
             _ -> L.intercalate "-" c)
           libComponents
+      OpenBSD  -> pure []
       FreeBSD ->
         case _distroVersion of
           Just fVer
@@ -343,6 +350,8 @@ getStackOSKey PlatformRequest { .. } =
     (A_64   , Darwin ) -> pure "macosx"
     (A_32   , FreeBSD) -> pure "freebsd32"
     (A_64   , FreeBSD) -> pure "freebsd64"
+    (A_32   , OpenBSD) -> pure "openbsd32"
+    (A_64   , OpenBSD) -> pure "openbsd64"
     (A_32   , Windows) -> pure "windows32"
     (A_64   , Windows) -> pure "windows64"
     (A_ARM  , Linux _) -> pure "linux-armv7"
@@ -350,6 +359,7 @@ getStackOSKey PlatformRequest { .. } =
     (A_Sparc, Linux _) -> pure "linux-sparc"
     (A_ARM64, Darwin ) -> pure "macosx-aarch64"
     (A_ARM64, FreeBSD) -> pure "freebsd-aarch64"
+    (A_ARM64, OpenBSD) -> pure "openbsd-aarch64"
     (arch', os') -> throwE $ UnsupportedSetupCombo arch' os'
 
 getStackPlatformKey :: (MonadReader env m, MonadFail m, HasLog env, MonadCatch m, MonadIO m)
diff --git a/lib/GHCup/Types.hs b/lib/GHCup/Types.hs
index 33e496e..5406e48 100644
--- a/lib/GHCup/Types.hs
+++ b/lib/GHCup/Types.hs
@@ -229,6 +229,7 @@ data Platform = Linux LinuxDistro
               | Darwin
               -- ^ must exit
               | FreeBSD
+              | OpenBSD
               | Windows
               -- ^ must exit
   deriving (Eq, GHC.Generic, Ord, Show)
@@ -239,6 +240,7 @@ platformToString :: Platform -> String
 platformToString (Linux distro) = "linux-" ++ distroToString distro
 platformToString Darwin = "darwin"
 platformToString FreeBSD = "freebsd"
+platformToString OpenBSD = "openbsd"
 platformToString Windows = "windows"
 
 instance Pretty Platform where
diff --git a/lib/GHCup/Types/JSON.hs b/lib/GHCup/Types/JSON.hs
index d30f433..13b96d6 100644
--- a/lib/GHCup/Types/JSON.hs
+++ b/lib/GHCup/Types/JSON.hs
@@ -143,6 +143,7 @@ instance ToJSONKey Platform where
     FreeBSD -> T.pack "FreeBSD"
     Linux (OtherLinux s) -> T.pack ("Linux_" <> s)
     Linux d -> T.pack ("Linux_" <> show d)
+    OpenBSD -> T.pack "OpenBSD"
     Windows -> T.pack "Windows"
 
 instance FromJSONKey Platform where

@Bodigrim
Copy link
Collaborator

I haven't tracked down why the sudden need to import Control.Monad everywhere, though

That's because of an upgrade from mtl-2.2 to mtl-2.3, see #1132

@habibalamin
Copy link
Collaborator

habibalamin commented Oct 20, 2024

Ah, makes sense.

I'd initially started by trying to upgrade packages one by one, though I could have sworn I removed them after adding allow-newer: base, and it broke something, but I probably just made a mistake from jumping back and forth.

I just after writing my above message made an accidental change on macOS and figured out the changes to package version bounds in ghcup.cabal were no longer necessary with allow-newer: base, which is why the difference in package versions. So I guess allow-newer: works how I initially expected.

I've just got it building on OpenBSD 7.5 now very simply:

  • allow-newer: base since recent versions of OpenBSD ship recent versions of GHC in packages.

  • Upgrade lzma-static (I'm using a source-repository-package pointing to a local copy which builds on OpenBSD, but since you'll be upgrading that, I won't commit/push that; we can simply bump the lzma-static version bound when the new version is out; or you can tell me whether you'll bump the minor, patch, or major version with the build system change, and I'll commit the necessary change now).

  • Add an

    else
      package ghcup
        flags: +tar
    

    to cabal.project.release (and probably repeat for the dev Cabal project files), as libarchive, like lzma-static, only supports the specific platforms it has config.h header files for.

    This can be removed once we upgrade libarchive to also use an autotools-based build; it looks like it's maintained by vmchale, who also maintained lzma-static before it was passed on to maerwald/hasufell, so we'll have to communicate this with him (or keep using +tar to use zip and tar packages on other platforms besides the ones supported by libarchive).

    Another alternative is to use +system-libarchive to use the system headers, but that adds a dependency on the user, so I don't think it's worth it.

@habibalamin
Copy link
Collaborator

habibalamin commented Oct 20, 2024

Okay, I copied cabal.ghc948.Unix.project and cabal.ghc948.Win32.project for GHC 9.6.4 and made the same allow-newer: base change and pointing lzma-static to a local copy to get the non-release versions to build, too.

@hasufell are you happy to take a PR that adds allow-newer: base in various Cabal project files, or do you want to get the version bounds actually working properly with GHC 9.6?

The PR will also add:

else
  package ghcup
    flags: +tar

to all the GHC 9.6-specific and release-specific Cabal project files that don't already enable that flag, and upgrade lzma-static minimum version bound (though it should just use the later version with autoconf-based build and work if it's just a patch release or something).

I'll wait for @Bodigrim to make the changes to lzma-static to use autoconf and wait for a new release to come out, then I'll update the PR to use that as a minimum version.

@hasufell
Copy link
Member Author

or do you want to get the version bounds actually working properly with GHC 9.6?

See #1132

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants