diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,30 @@
 # Revision history for distribution-nixpkgs
 
+## 1.7.0
+
+* `Distribution.Nixpkgs.Meta`
+  * `pPrint (x :: Meta)` now renders every maintainer as a full attribute
+    path instead of using `with`.
+  * **API breaking change**: Changed types for all platform related fields /
+    lenses of `Meta`, i.e. `platforms` and `hydraPlatforms`.
+    * They are now wrapped in a `Maybe`. If `Nothing`, the respective attribute
+      is not rendered.
+    * Instead of `Platform` we now use `NixpkgsPlatform` which may also be a
+      `NixpkgsPlatformGroup`, like `lib.platforms.linux`, in addition to the
+      wrapped `Platform` in `NixpkgsPlatformSingle`.
+  * **API breaking change**: Add new fields / lenses to `Meta`:
+    * `badPlatforms`: Allows setting a list of unsupported platforms, works
+      similarly to the `platform` / `hydraPlatform` lenses.
+    * `mainProgram`: Allows setting the (base-)name of the main binary of a
+      derivation. Not rendered if `Nothing`.
+  * **API breaking change**: Remove `allKnownPlatforms`, its previous use can be
+    replaced using `badPlatforms`.
+  * Added `nixpkgsPlatformFromString` which parses a specific format used by
+    hackage2nix's config files into either `NixpkgsPlatformSingle` or
+    `NixpkgsPlatformGroup`.
+* `Language.Nix.PrettyPrinting`: Added new helpers, `listattrDoc` and
+  `toAscListSortedOn`.
+
 ## 1.6.2
 
 * Expect `MonadFailDesugaring` (or equivalent behavior) to be the default,
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -2,3 +2,25 @@
 
 [![hackage release](https://img.shields.io/hackage/v/distribution-nixpkgs.svg?label=hackage)](http://hackage.haskell.org/package/distribution-nixpkgs)
 [![stackage LTS package](http://stackage.org/package/distribution-nixpkgs/badge/lts)](http://stackage.org/lts/package/distribution-nixpkgs)
+
+## Maintainer's Notes
+
+### Keeping platform test cases up to date
+
+As nixpkgs expands its list of supported platforms, new system tuples are added.
+Therefore we need to adjust the test suite regularly in order to cover newly
+added platforms. For this purpose, the test suite checks the platforms it verifies
+against a list of system tuples generated from nixpkgs. This list needs to be
+updated manually, so running the test suite doesn't depend on Nix being available.
+
+To check if any new platforms need to be covered, do the following:
+
+1. Run `./test/data/regenerate-all-system-tuples.sh /path/to/nixpkgs/checkout`.
+   If no local nixpkgs is given, `<nixpkgs>` will be used.
+
+2. Run the test suite: `cabal v2-test`.
+
+3. If the test suite fails, add test cases for all missing system tuples.
+
+4. In all cases, change the dates of last update in `test/hspec.hs` and
+   `src/Distribution/Nixpkgs/Meta.hs` to the current day.
diff --git a/distribution-nixpkgs.cabal b/distribution-nixpkgs.cabal
--- a/distribution-nixpkgs.cabal
+++ b/distribution-nixpkgs.cabal
@@ -1,12 +1,12 @@
 name:          distribution-nixpkgs
-version:       1.6.2
+version:       1.7.0
 synopsis:      Types and functions to manipulate the Nixpkgs distribution
 description:   Types and functions to represent, query, and manipulate the Nixpkgs distribution.
 license:       BSD3
 license-file:  LICENSE
 author:        Peter Simons <simons@cryp.to>
 maintainer:    sternenseemann <sternenseemann@systemli.org>
-tested-with:   GHC == 8.6.5 || == 8.8.4 || == 8.10.4 || == 9.0.1
+tested-with:   GHC == 8.6.5 || == 8.8.4 || == 8.10.7 || == 9.0.2 || == 9.2.2
 category:      Distribution, Nix
 homepage:      https://github.com/NixOS/distribution-nixpkgs
 bug-reports:   https://github.com/NixOS/distribution-nixpkgs/issues
@@ -15,6 +15,7 @@
 data-files:    derivation-attr-paths.nix
 extra-source-files: CHANGELOG.md
                     README.md
+                    test/data/all-system-tuples.json
 
 source-repository head
   type:     git
@@ -38,7 +39,6 @@
                     , lens
                     , pretty       >= 1.1.2
                     , process
-                    , split
   default-language:   Haskell2010
   other-extensions:   CPP
                       TemplateHaskell
@@ -52,7 +52,15 @@
   type:               exitcode-stdio-1.0
   main-is:            hspec.hs
   hs-source-dirs:     test
-  build-depends:      base, deepseq, distribution-nixpkgs, hspec, lens
+  build-depends:      base
+                    , deepseq
+                    , distribution-nixpkgs
+                    , language-nix
+                    , hspec
+                    , lens
+                    , Cabal
+                    , aeson
+                    , directory
   default-language:   Haskell2010
   ghc-options:        -Wall -Wcompat -Wincomplete-uni-patterns -Wincomplete-record-updates
                       -Wredundant-constraints
diff --git a/src/Distribution/Nixpkgs/Meta.hs b/src/Distribution/Nixpkgs/Meta.hs
--- a/src/Distribution/Nixpkgs/Meta.hs
+++ b/src/Distribution/Nixpkgs/Meta.hs
@@ -10,32 +10,218 @@
  -}
 
 module Distribution.Nixpkgs.Meta
-  ( Meta, nullMeta
-  , homepage, description, license, platforms, hydraPlatforms, maintainers, broken
-  , allKnownPlatforms
+  ( -- * Representation of the Nixpkgs Meta Set
+    Meta, nullMeta
+    -- ** Lenses for 'Meta'
+  , homepage, description, license, platforms, badPlatforms, hydraPlatforms, mainProgram, maintainers, broken
+    -- * Representation of Nixpkgs Platform Descriptions
+  , NixpkgsPlatform (..)
+  , nixpkgsPlatformFromString
   ) where
 
 -- Avoid name clash with Prelude.<> exported by post-SMP versions of base.
 #if MIN_VERSION_base(4,11,0)
 import Prelude hiding ( (<>) )
 #endif
+import Control.Applicative ( (<|>) )
 import Control.DeepSeq
-import Control.Lens
+import Control.Lens hiding ( Strict )
+import Data.List ( stripPrefix )
 import Data.Set ( Set )
 import qualified Data.Set as Set
 import Distribution.Nixpkgs.License
+import qualified Distribution.Pretty as CabalPretty
 import Distribution.System
 import GHC.Generics ( Generic )
 import Language.Nix.Identifier
+import Language.Nix.Path ( path )
 import Language.Nix.PrettyPrinting
 
+-- | Representation of platform(s) as supported by nixpkgs:
+--
+--     * 'NixpkgsPlatformGroup' represents the name of a platform
+--       list as found in @lib.platforms@. For example, at the
+--       time of writing @NixpkgsPlatformGroup "darwin"@ would
+--       represent the platform tuples @x86_64-darwin@, @aarch64-darwin@,
+--       @i686-darwin@ and @armv7a-darwin@. Naturally, this is
+--       subject to change as nixpkgs updates @lib.platforms@.
+--     * 'NixpkgsPlatformSingle' indicates a single platform tuple
+--       represented using Cabal's 'Platform'.
+--
+--   The former is useful to express related groups of
+--   platforms which have similar properties. The latter
+--   can be used to, for example, exclude a single, specific
+--   platform.
+--
+--   @hackage2nix@ has used the latter approach historically
+--   and is being extended to support nixpkgs' platform
+--   groups as well for increased maintainer convenience.
+--
+--   The 'Pretty' instance allows for converting a 'NixpkgsPlatform'
+--   into a Nix expression compatible with @meta.platforms@:
+--
+--   >>> pPrint $ NixpkgsPlatformSingle $ Platform X86_64 NetBSD
+--   "x86_64-netbsd"
+--
+--   For 'NixpkgsPlatformGroup' we assume that the @lib@ attribute set is in
+--   scope:
+--
+--   >>> pPrint $ NixpkgsPlatformGroup $ ident # "riscv"
+--   lib.platforms.riscv
+data NixpkgsPlatform
+  = NixpkgsPlatformSingle Platform
+  -- ^ Single platform represented as a Cabal platform. Can be understood as
+  -- equivalent to Nix's system strings and will be converted to one usually.
+  | NixpkgsPlatformGroup Identifier
+  -- ^ 'Identifier' of the attribute name of a platform
+  --   group in nixpkgs' @lib.platforms@.
+  deriving (Show, Eq, Ord, Generic)
+
+nixpkgsPlatformFromCabal :: Platform -> String
+nixpkgsPlatformFromCabal (Platform arch os) = "\"" ++ nixArch ++ "-" ++ nixOs ++ "\""
+  where nixArch =
+          case arch of
+            I386 -> "i686" -- rendered as i386 by default
+            PPC -> "powerpc" -- rendered as ppc by default
+            PPC64 -> "powerpc64" -- rendered as ppc64 by default
+            JavaScript -> "js" -- rendered as javascript by default
+            _    -> CabalPretty.prettyShow arch
+        nixOs =
+          case os of
+            OSX -> "darwin" -- rendered as osx by default
+            _   -> CabalPretty.prettyShow os
+
+-- | Obtain a 'NixpkgsPlatform' from a string representation intended for config
+--   files.
+--
+--   * Every string starting with @lib.platforms.@ or @platforms.@ is
+--     parsed into 'NixpkgsPlatformGroup'.
+--   * All other strings are attempted to be interpreted as a nix(pkgs) style
+--     system tuple and parsed into 'NixpkgsPlatformSingle'.
+--
+--   If none of these formats match the input 'String', 'Nothing' is returned.
+--   A 'Just' result thus only indicates that the format of the platform is
+--   sound — 'nixpkgsPlatformFromString' does /not/ check if the parsed platform
+--   actually exists.
+--
+--   'NixpkgsPlatformSingle' is parsed from system tuples as understood by Nix
+--   and nixpkgs. System tuples are derived from autoconf's
+--   [target triplets](https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.70/autoconf.html#Manual-Configuration),
+--   dropping the vendor part. They have the form @cpu-os@ where @os@ can either
+--   be a single component or of the form @kernel-system@ (system is an autoconf
+--   term here, not a Nix system). Note that three component systems are very
+--   rare. The two main candidates @x86_64-linux-musl@ and @x86_64-linux-gnu@
+--   are [prohibited for historical reasons](https://github.com/NixOS/nix/blob/ec07a70979a86cc436de7e46e03789b4606d25ab/configure.ac#L26-L28)
+--   and represented as plain @x86_64-linux@ instead.
+--
+--   Note that 'nixpkgsPlatformFromString' expects to receive a /valid/ system
+--   tuple, i.e. it will accept all system tuples that have a sound format
+--   (with the caveat that it will accept n-tuples for @n >= 4@ even though
+--   they are technically invalid). This is done because the ambiguity of
+--   system tuples requires knowledge over its legal contents in order to check
+--   their validity properly. Since @lib.systems.elaborate@ from nixpkgs is the
+--   source of truth in this case, we want to avoid the need to continuously
+--   update @distribution-nixpkgs@ to reflect its inner workings.
+--
+--   'nixpkgsPlatformFromString' does, however, some conversions to alleviate some
+--   discrepancies between Cabal and nixpkgs. Parsing and rendering system tuples
+--   using 'nixpkgsPlatformFromString' and rendering them via the 'Pretty'
+--   instance of 'NixpkgsPlatform' should not change the system tuple
+--   for tuples accepted by nixpkgs. This has been tested for all known tuples
+--   (from @lib.platforms@ and @lib.systems.examples@) as of 2022-05-08.
+--   Please open an issue if any newly added ones are not recognized properly.
+--
+--   __Warning__: 'nixpkgsPlatformFromString' consequently tries to preserve all
+--   information of the passed system tuple. This means that it distinguishes
+--   between things that Cabal wouldn't, e.g. `powerpc64` and `powerpc64le`. If
+--   you use this function to obtain a 'Platform' that is later used to evaluate
+--   a @.cabal@ file, it will behave unexpectedly in some situation. It is
+--   recommended to use Cabal's own facilities or
+--   @Distribution.Nixpkgs.Haskell.Platform@, provided by @cabal2nix@, instead.
+--
+--   'nixpkgsPlatformFromString' is also /not/ the inverse operation for
+--   'NixpkgsPlatform'\'s 'Pretty' instance. It is not intended for parsing Nix
+--   expressions.
+--
+--   >>> nixpkgsPlatformFromString "x86_64-netbsd"
+--   Just (NixpkgsPlatformSingle (Platform X86_64 NetBSD))
+--   >>> nixpkgsPlatformFromString "platforms.riscv"
+--   Just (NixpkgsPlatformGroup (Identifier "riscv"))
+--   >>> nixpkgsPlatformFromString "garbage"
+--   Nothing
+nixpkgsPlatformFromString :: String -> Maybe NixpkgsPlatform
+nixpkgsPlatformFromString s = platformGroup <|> singlePlatform
+  where platformGroup = do
+          -- also accept "platform." as prefix to save some typing
+          name <- stripPrefix "lib.platforms." s <|> stripPrefix "platforms." s
+          Just $ NixpkgsPlatformGroup (ident # name)
+
+        singlePlatform = NixpkgsPlatformSingle <$> cabalPlatformFromSystem s
+
+-- | Parse a system tuple as understood by Nix and nixpkgs to a Cabal 'Platform'.
+--   Used internally by 'nixpkgsPlatformFromString'.
+--
+--   >>> cabalPlatformFromSystem "x86_64-linux"
+--   Just (Platform X86_64 Linux)
+--   >>> cabalPlatformFromSystem "x86_64-linux-musl"
+--   Just (Platform X86_64 (OtherOS "linux-musl"))
+--   >>> cabalPlatformFromSystem "powerpc-darwin"
+--   Just (Platform PPC OSX)
+--   >>> cabalPlatformFromSystem "powerpc64le-linux"
+--   Just (Platform (OtherArch "powerpc64le") Linux)
+--   >>> cabalPlatformFromSystem "js-ghcjs"
+--   Just (Platform JavaScript Ghcjs)
+cabalPlatformFromSystem :: String -> Maybe Platform
+cabalPlatformFromSystem s =
+  case break (== '-') s of
+    (arch, '-':os) ->
+      if null arch || null os
+      then Nothing
+      else Just $ Platform (parseArch arch) (parseOS os)
+    _ -> Nothing
+  where -- Use permissive classification to also recognize autoconf / nixpkgs
+        -- style OS strings, e.g. "darwin" where Cabal would expect "osx".
+        --
+        -- Note that we don't reimplement GHC_CONVERT_OS from GHC's configure
+        -- file here at the moment. Our goal is to recognize all /well formed/
+        -- nixpkgs system strings, nothing more. That this works correctly for
+        -- nixpkgs systems currently in use is confirmed by the test suite.
+        parseOS = classifyOS Permissive
+
+        -- Use Strict for arch classification and add specific guards for cases
+        -- where Cabal's naming expectations (which seems to be LLVM oriented)
+        -- clash with what nixpkgs / autoconf use (e.g. Cabal uses "ppc" instead
+        -- of "powerpc"). Using Permissive is not possible because Cabal is a bit
+        -- overzealous in arch recognition: For example, it ignores endianess in
+        -- the case of the POWER architectures, parsing "powerpcle" to "ppc" and
+        -- "powerpc64le" to "ppc64" when they are clearly different platforms.
+        --
+        -- We also don't implement GHC_CONVERT_ARCH here, for the reasons stated
+        -- above.
+        parseArch as =
+          case classifyArch Strict as of
+            OtherArch "i686" -> I386
+            OtherArch "js" -> JavaScript
+            OtherArch "powerpc" -> PPC
+            OtherArch "powerpc64" -> PPC64
+            a -> a
+
+instance Pretty NixpkgsPlatform where
+  pPrint (NixpkgsPlatformSingle p) = text $ nixpkgsPlatformFromCabal p
+  pPrint (NixpkgsPlatformGroup p)  = pPrint
+    $ path # [ ident # "lib", ident # "platforms", p ]
+
+instance NFData NixpkgsPlatform
+
 -- | A representation of the @meta@ section used in Nix expressions.
 --
 -- >>> :set -XOverloadedStrings
 -- >>> :{
 --   print (pPrint (Meta "http://example.org" "an example package" (Unknown Nothing)
---                  (Set.singleton (Platform X86_64 Linux))
---                  Set.empty
+--                  (Just (Set.singleton (NixpkgsPlatformSingle (Platform X86_64 Linux))))
+--                  Nothing
+--                  (Just Set.empty)
+--                  (Just "example-binary")
 --                  (Set.fromList ["joe","jane"])
 --                  True))
 -- :}
@@ -44,17 +230,43 @@
 -- license = "unknown";
 -- platforms = [ "x86_64-linux" ];
 -- hydraPlatforms = lib.platforms.none;
--- maintainers = with lib.maintainers; [ jane joe ];
+-- mainProgram = "example-binary";
+-- maintainers = [ lib.maintainers.jane lib.maintainers.joe ];
 -- broken = true;
-
 data Meta = Meta
-  { _homepage       :: String           -- ^ URL of the package homepage
-  , _description    :: String           -- ^ short description of the package
-  , _license        :: License          -- ^ licensing terms
-  , _platforms      :: Set Platform     -- ^ We re-use the Cabal type for convenience, but render it to conform to @pkgs\/lib\/platforms.nix@.
-  , _hydraPlatforms :: Set Platform     -- ^ list of platforms built by Hydra (render to conform to @pkgs\/lib\/platforms.nix@)
-  , _maintainers    :: Set Identifier   -- ^ list of maintainers from @pkgs\/lib\/maintainers.nix@
-  , _broken         :: Bool             -- ^ set to @true@ if the build is known to fail
+  { _homepage       :: String
+  -- ^ URL of the package homepage
+  , _description    :: String
+  -- ^ short description of the package
+  , _license        :: License
+  -- ^ licensing terms
+  , _platforms      :: Maybe (Set NixpkgsPlatform)
+  -- ^ List of platforms that are supported by the package.
+  --   'Nothing' prevents the attribute from being rendered.
+  --   See 'NixpkgsPlatform' on the precise representation of platforms.
+  , _badPlatforms   :: Maybe (Set NixpkgsPlatform)
+  -- ^ List of platforms that are known to be unsupported. This is semantically
+  --   equivalent to setting the following:
+  --
+  --   @
+  --     platforms = lib.subtractLists
+  --       (initialMeta.badPlatforms or []);
+  --       (initialMeta.platforms or lib.platforms.all)
+  --   @
+  --
+  --   'Nothing' prevents the attribute from being rendered.
+  --   See 'NixpkgsPlatform' on the precise representation of platforms.
+  , _hydraPlatforms :: Maybe (Set NixpkgsPlatform)
+  -- ^ Platforms for which the package should be tested, built and added to the
+  --   binary cache by Hydra. 'Nothing' prevents the attribute from being rendered.
+  --  See 'NixpkgsPlatform' on the precise representation of platforms.
+  , _mainProgram    :: Maybe String
+  -- ^ Filename (as in basename) of the main executable provided by the described
+  --   package. @Nothing@ if it is a library or no obvious default can be chosen.
+  , _maintainers    :: Set Identifier
+  -- ^ list of maintainers from @pkgs\/lib\/maintainers.nix@
+  , _broken         :: Bool
+  -- ^ set to @true@ if the build is known to fail
   }
   deriving (Show, Eq, Ord, Generic)
 
@@ -67,39 +279,148 @@
     [ onlyIf (not (null _homepage)) $ attr "homepage" $ string _homepage
     , onlyIf (not (null _description)) $ attr "description" $ string _description
     , attr "license" $ pPrint _license
-    , onlyIf (_platforms /= allKnownPlatforms) $ renderPlatforms "platforms" _platforms
-    , onlyIf (_hydraPlatforms /= _platforms) $ renderPlatforms "hydraPlatforms" _hydraPlatforms
-    , setattr "maintainers" (text "with lib.maintainers;") (Set.map (view ident) _maintainers)
+    , maybe mempty (renderPlatforms "platforms") _platforms
+    , maybe mempty (renderPlatforms "badPlatforms") _badPlatforms
+    , maybe mempty (renderPlatforms "hydraPlatforms") _hydraPlatforms
+    , maybe mempty (attr "mainProgram" . string) _mainProgram
+    , listattrDoc "maintainers" mempty $ renderMaintainers _maintainers
     , boolattr "broken" _broken _broken
     ]
 
-renderPlatforms :: String -> Set Platform -> Doc
+-- | This function renders an Nix attribute binding suitable for use in
+--   an attribute set representing the given set of 'NixpkgsPlatform's.
+--
+--   The @field@ argument is the name of the binding, usually either
+--   @platforms@, @hydraPlatforms@ or @badPlatforms@.
+--
+--   Platforms are rendered in the following way:
+--
+--   * If the given 'Set' is empty, the binding's value is @lib.platforms.none@.
+--     This has been preserved for “backwards compatibility” since changing this
+--     would generate a huge diff for nixpkgs' @hackage-packages.nix@ file.
+--
+--   * First we render all 'NixpkgsPlatformSingle' values. This is done by
+--     printing a Nix list containing Nix system strings. If there are no
+--     platform groups, but the 'Set' is not empty, an empty list (@[ ]@) is
+--     rendered.
+--
+--   * Finally we render all 'NixpkgsPlatformGroup's. Since these are lists, we
+--     need to append them to the (cabal) platform list via the @++@ operator.
+--     For each group we render @++ lib.platforms.<group name>@.
+--
+--   For example:
+--
+--   >>> :{
+--     renderPlatforms "badPlatforms"
+--       $ Set.fromList [
+--         NixpkgsPlatformSingle (Platform (OtherArch "armv7l") Linux),
+--         NixpkgsPlatformGroup (ident # "darwin"),
+--         NixpkgsPlatformGroup (ident # "windows")
+--       ]
+--   :}
+--   badPlatforms = [
+--     "armv7l-linux"
+--   ] ++ lib.platforms.darwin
+--     ++ lib.platforms.windows;
+--
+--   >>> :{
+--     renderPlatforms "platforms"
+--       $ Set.fromList [
+--         NixpkgsPlatformGroup (ident # "x86"),
+--         NixpkgsPlatformGroup (ident # "riscv"),
+--         NixpkgsPlatformGroup (ident # "freebsd")
+--       ]
+--   :}
+--   platforms =
+--        lib.platforms.freebsd
+--     ++ lib.platforms.riscv
+--     ++ lib.platforms.x86;
+--
+--   >>> :{
+--     renderPlatforms "platforms"
+--       $ Set.fromList [
+--         NixpkgsPlatformGroup (ident # "x86")
+--       ]
+--   :}
+--   platforms = lib.platforms.x86;
+--
+--   >>> :{
+--     renderPlatforms "platforms"
+--       $ Set.fromList [
+--         NixpkgsPlatformSingle (Platform I386 Linux),
+--         NixpkgsPlatformSingle (Platform X86_64 Linux),
+--         NixpkgsPlatformSingle (Platform AArch64 Linux),
+--         NixpkgsPlatformSingle (Platform X86_64 OSX),
+--         NixpkgsPlatformSingle (Platform AArch64 OSX)
+--       ]
+--   :}
+--   platforms = [
+--     "i686-linux" "x86_64-linux" "x86_64-darwin" "aarch64-linux"
+--     "aarch64-darwin"
+--   ];
+--
+--   >>> :{
+--     renderPlatforms "platforms"
+--       $ Set.fromList [
+--         NixpkgsPlatformSingle (Platform I386 Linux),
+--         NixpkgsPlatformSingle (Platform X86_64 Linux),
+--         NixpkgsPlatformSingle (Platform AArch64 Linux),
+--         NixpkgsPlatformSingle (Platform X86_64 OSX),
+--         NixpkgsPlatformSingle (Platform AArch64 OSX),
+--         NixpkgsPlatformGroup (ident # "riscv"),
+--         NixpkgsPlatformGroup (ident # "arm")
+--       ]
+--   :}
+--   platforms = [
+--     "i686-linux" "x86_64-linux" "x86_64-darwin" "aarch64-linux"
+--     "aarch64-darwin"
+--   ] ++ lib.platforms.arm
+--     ++ lib.platforms.riscv;
+renderPlatforms :: String -> Set NixpkgsPlatform -> Doc
 renderPlatforms field ps
+  -- preserve old behavior: no platforms -> lib.platforms.none
   | Set.null ps = sep [ text field <+> equals <+> text "lib.platforms.none" <> semi ]
-  | otherwise   = setattr field mempty $ Set.map fromCabalPlatform ps
+  | otherwise =
+    sep [ text field <+> equals <+> unless (Set.null cabalPs) lbrack
+        , unless (Set.null cabalPs) (nest 2 $ fsep renderedCabalPs)
+        , unless (Set.null cabalPs) rbrack
+        , unless (Set.null nixpkgsPs) (nest 2 renderedNixpkgsPs)
+        ]
+    <> semi
+  where -- render nixpkgs platforms and cabal platform tuples separately
+        -- since the former represents multiple platforms and meta doesn't
+        -- support nested lists.
+        (cabalPs, nixpkgsPs) = Set.partition isSinglePlatform ps
+        isSinglePlatform (NixpkgsPlatformSingle _) = True
+        isSinglePlatform _ = False
 
+        renderedCabalPs = map pPrint $ Set.toAscList cabalPs
+
+        -- append lib.platforms list via nix's ++ at the end
+        -- if there is no cabal platforms list, don't emit leading ++
+        appendNixpkgsP acc elem = acc $$
+          if isEmpty acc && Set.null cabalPs
+          then nest 3 $ pPrint elem
+          else text "++" <+> pPrint elem
+        renderedNixpkgsPs = Set.foldl' appendNixpkgsP mempty nixpkgsPs
+
+        -- Helper function, roughly the inverse of nixpkgs' optionals
+        unless False x = x
+        unless True _  = mempty
+
+renderMaintainers :: Set Identifier -> [Doc]
+renderMaintainers = map (pPrint . toPath) . toAscListSortedOn (view ident)
+  where toPath m = path # [ ident # "lib", ident # "maintainers", m]
+
 nullMeta :: Meta
 nullMeta = Meta
   { _homepage = error "undefined Meta.homepage"
   , _description = error "undefined Meta.description"
   , _license = error "undefined Meta.license"
   , _platforms = error "undefined Meta.platforms"
+  , _badPlatforms = error "undefined Meta.badPlatforms"
   , _hydraPlatforms = error "undefined Meta.hydraPlatforms"
+  , _mainProgram = error "undefined Meta.mainProgram"
   , _maintainers = error "undefined Meta.maintainers"
   , _broken = error "undefined Meta.broken"
   }
-
-allKnownPlatforms :: Set Platform
-allKnownPlatforms = Set.fromList [ Platform I386 Linux, Platform X86_64 Linux
-                                 , Platform X86_64 OSX, Platform (OtherArch "armv7l") Linux
-                                 , Platform AArch64 Linux, Platform AArch64 OSX
-                                 ]
-
-fromCabalPlatform :: Platform -> String
-fromCabalPlatform (Platform I386 Linux)                 = "\"i686-linux\""
-fromCabalPlatform (Platform X86_64 Linux)               = "\"x86_64-linux\""
-fromCabalPlatform (Platform X86_64 OSX)                 = "\"x86_64-darwin\""
-fromCabalPlatform (Platform (OtherArch "armv7l") Linux) = "\"armv7l-linux\""
-fromCabalPlatform (Platform AArch64 Linux)              = "\"aarch64-linux\""
-fromCabalPlatform (Platform AArch64 OSX)                = "\"aarch64-darwin\""
-fromCabalPlatform p                                     = error ("fromCabalPlatform: invalid Nix platform" ++ show p)
diff --git a/src/Language/Nix/PrettyPrinting.hs b/src/Language/Nix/PrettyPrinting.hs
--- a/src/Language/Nix/PrettyPrinting.hs
+++ b/src/Language/Nix/PrettyPrinting.hs
@@ -5,8 +5,9 @@
 
 module Language.Nix.PrettyPrinting
   ( onlyIf
-  , setattr, toAscList
-  , listattr
+  , toAscList, toAscListSortedOn
+  , setattr
+  , listattr, listattrDoc
   , boolattr
   , attr
   , string
@@ -36,18 +37,25 @@
 boolattr :: String -> Bool -> Bool -> Doc
 boolattr n p v = if p then attr n (bool v) else empty
 
+listattrDoc :: String -> Doc -> [Doc] -> Doc
+listattrDoc n prefix vs = onlyIf (not (null vs)) $
+  sep [ text n <+> equals <+> prefix <+> lbrack,
+        nest 2 $ fsep vs,
+        rbrack <> semi
+      ]
+
 listattr :: String -> Doc -> [String] -> Doc
-listattr n prefix vs = onlyIf (not (null vs)) $
-                sep [ text n <+> equals <+> prefix <+> lbrack,
-                      nest 2 $ fsep $ map text vs,
-                      rbrack <> semi
-                    ]
+listattr n p = listattrDoc n p . map text
 
 setattr :: String -> Doc -> Set String -> Doc
-setattr name prefix set = listattr name prefix (toAscList set)
+setattr name prefix set = listattrDoc name prefix
+  $ map text $ toAscList set
 
+toAscListSortedOn :: (a -> String) -> Set a -> [a]
+toAscListSortedOn f = sortBy (compare `on` map toLower . f) . Set.toList
+
 toAscList :: Set String -> [String]
-toAscList = sortBy (compare `on` map toLower) . Set.toList
+toAscList = toAscListSortedOn id
 
 bool :: Bool -> Doc
 bool True  = text "true"
diff --git a/test/data/all-system-tuples.json b/test/data/all-system-tuples.json
new file mode 100644
--- /dev/null
+++ b/test/data/all-system-tuples.json
@@ -0,0 +1,1 @@
+["aarch64-darwin","aarch64-genode","aarch64-linux","aarch64-netbsd","aarch64-none","aarch64_be-none","arm-none","armv5tel-linux","armv6l-linux","armv6l-netbsd","armv6l-none","armv7a-darwin","armv7a-linux","armv7a-netbsd","armv7l-linux","armv7l-netbsd","avr-none","i686-cygwin","i686-darwin","i686-freebsd","i686-genode","i686-linux","i686-netbsd","i686-none","i686-openbsd","i686-windows","js-ghcjs","m68k-linux","m68k-netbsd","m68k-none","mips-linux","mips64-linux","mips64el-linux","mipsel-linux","mipsel-netbsd","mmix-mmixware","msp430-none","or1k-none","powerpc-netbsd","powerpc-none","powerpc64-linux","powerpc64le-linux","powerpcle-none","riscv32-linux","riscv32-netbsd","riscv32-none","riscv64-linux","riscv64-netbsd","riscv64-none","s390-linux","s390-none","s390x-linux","s390x-none","vc4-none","wasm32-wasi","wasm64-wasi","x86_64-cygwin","x86_64-darwin","x86_64-freebsd","x86_64-genode","x86_64-linux","x86_64-netbsd","x86_64-none","x86_64-openbsd","x86_64-redox","x86_64-solaris","x86_64-windows"]
diff --git a/test/hspec.hs b/test/hspec.hs
--- a/test/hspec.hs
+++ b/test/hspec.hs
@@ -3,12 +3,20 @@
 import Control.DeepSeq
 import Control.Exception
 import Control.Lens
+import Control.Monad (forM_)
+import Data.Aeson (decodeFileStrict)
+import Data.Bifunctor (second)
+import Data.Maybe (fromJust)
 import Distribution.Nixpkgs.License
 import Distribution.Nixpkgs.Meta
+import Distribution.System (Platform (..), OS (..), Arch (..))
+import Language.Nix.Identifier
+import Language.Nix.PrettyPrinting
+import System.Directory (doesFileExist)
 import Test.Hspec
 
 main :: IO ()
-main = hspec $
+main = hspec $ do
   describe "DeepSeq instances work properly for" $ do
     it "License" $ mapM_ hitsBottom [Known undefined, Unknown (Just undefined)]
     it "Meta" $ mapM_ hitsBottom
@@ -19,6 +27,109 @@
                   , nullMeta & maintainers .~ undefined
                   , nullMeta & broken .~ undefined
                   ]
+
+  describe "Platform rendering and parsing:" $ do
+    it "Checks cover all systems from all-system-tuples.json" $do
+      let allSystemTuplesJson = "test/data/all-system-tuples.json"
+      available <- doesFileExist allSystemTuplesJson
+      if not available
+      then pendingWith $ "System tuple list not found at: " ++ allSystemTuplesJson
+      else do
+        allSystemTuples <- decodeFileStrict allSystemTuplesJson
+        map fst nixpkgsSystemMapping `shouldMatchList` fromJust allSystemTuples
+
+    forM_ platformMapping $ \(str, plat) -> describe str $ do
+      it "is rendered correctly" $ checkRendering plat str
+      it "is parsed correctly" $
+        nixpkgsPlatformFromString str `shouldBe` Just plat
+
+-- All system tuples from lib.platforms as of 2022-05-08. Testing these allows
+-- us to get notified about behavior change in Cabal as early as possible.
+nixpkgsSystemMapping :: [(String, Platform)]
+nixpkgsSystemMapping =
+  [ -- lib.platforms.all
+    ("aarch64-darwin", Platform AArch64 OSX)
+  , ("aarch64-genode", Platform AArch64 (OtherOS "genode"))
+  , ("aarch64-linux", Platform AArch64 Linux)
+  , ("aarch64-netbsd", Platform AArch64 NetBSD)
+  , ("aarch64-none", Platform AArch64 (OtherOS "none"))
+  , ("aarch64_be-none", Platform (OtherArch "aarch64_be") (OtherOS "none"))
+  , ("arm-none", Platform Arm (OtherOS "none"))
+  , ("armv5tel-linux", Platform (OtherArch "armv5tel") Linux)
+  , ("armv6l-linux", Platform (OtherArch "armv6l") Linux)
+  , ("armv6l-netbsd", Platform (OtherArch "armv6l") NetBSD)
+  , ("armv6l-none", Platform (OtherArch "armv6l") (OtherOS "none"))
+  , ("armv7a-darwin", Platform (OtherArch "armv7a") OSX)
+  , ("armv7a-linux", Platform (OtherArch "armv7a") Linux)
+  , ("armv7a-netbsd", Platform (OtherArch "armv7a") NetBSD)
+  , ("armv7l-linux", Platform (OtherArch "armv7l") Linux)
+  , ("armv7l-netbsd", Platform (OtherArch "armv7l") NetBSD)
+  , ("avr-none", Platform (OtherArch "avr") (OtherOS "none"))
+  , ("i686-cygwin", Platform I386 (OtherOS "cygwin"))
+  , ("i686-darwin", Platform I386 OSX)
+  , ("i686-freebsd", Platform I386 FreeBSD)
+  , ("i686-genode", Platform I386 (OtherOS "genode"))
+  , ("i686-linux", Platform I386 Linux)
+  , ("i686-netbsd", Platform I386 NetBSD)
+  , ("i686-none", Platform I386 (OtherOS "none"))
+  , ("i686-openbsd", Platform I386 OpenBSD)
+  , ("i686-windows", Platform I386 Windows)
+  , ("js-ghcjs", Platform JavaScript Ghcjs)
+  , ("m68k-linux", Platform M68k Linux)
+  , ("m68k-netbsd", Platform M68k NetBSD)
+  , ("m68k-none", Platform M68k (OtherOS "none"))
+  , ("mips64el-linux", Platform (OtherArch "mips64el") Linux)
+  , ("mipsel-linux", Platform (OtherArch "mipsel") Linux)
+  , ("mipsel-netbsd", Platform (OtherArch "mipsel") NetBSD)
+  , ("mmix-mmixware", Platform (OtherArch "mmix") (OtherOS "mmixware"))
+  , ("msp430-none", Platform (OtherArch "msp430") (OtherOS "none"))
+  , ("or1k-none", Platform (OtherArch "or1k") (OtherOS "none"))
+  , ("powerpc-netbsd", Platform PPC NetBSD)
+  , ("powerpc-none", Platform PPC (OtherOS "none"))
+  , ("powerpc64-linux", Platform PPC64 Linux)
+  , ("powerpc64le-linux", Platform (OtherArch "powerpc64le") Linux)
+  , ("powerpcle-none", Platform (OtherArch "powerpcle") (OtherOS "none"))
+  , ("riscv32-linux", Platform (OtherArch "riscv32") Linux)
+  , ("riscv32-netbsd", Platform (OtherArch "riscv32") NetBSD)
+  , ("riscv32-none", Platform (OtherArch "riscv32") (OtherOS "none"))
+  , ("riscv64-linux", Platform (OtherArch "riscv64") Linux)
+  , ("riscv64-netbsd", Platform (OtherArch "riscv64") NetBSD)
+  , ("riscv64-none", Platform (OtherArch "riscv64") (OtherOS "none"))
+  , ("s390-linux", Platform S390 Linux)
+  , ("s390-none", Platform S390 (OtherOS "none"))
+  , ("s390x-linux", Platform (OtherArch "s390x") Linux)
+  , ("s390x-none", Platform (OtherArch "s390x") (OtherOS "none"))
+  , ("vc4-none", Platform (OtherArch "vc4") (OtherOS "none"))
+  , ("wasm32-wasi", Platform (OtherArch "wasm32") (OtherOS "wasi"))
+  , ("wasm64-wasi", Platform (OtherArch "wasm64") (OtherOS "wasi"))
+  , ("x86_64-cygwin", Platform X86_64 (OtherOS "cygwin"))
+  , ("x86_64-darwin", Platform X86_64 OSX)
+  , ("x86_64-freebsd", Platform X86_64 FreeBSD)
+  , ("x86_64-genode", Platform X86_64 (OtherOS "genode"))
+  , ("x86_64-linux", Platform X86_64 Linux)
+  , ("x86_64-netbsd", Platform X86_64 NetBSD)
+  , ("x86_64-none", Platform X86_64 (OtherOS "none"))
+  , ("x86_64-openbsd", Platform X86_64 OpenBSD)
+  , ("x86_64-redox", Platform X86_64 (OtherOS "redox"))
+  , ("x86_64-solaris", Platform X86_64 Solaris)
+  , ("x86_64-windows", Platform X86_64 Windows)
+  -- lib.systems.examples
+  , ("mips-linux", Platform Mips Linux)
+  , ("mips64-linux", Platform (OtherArch "mips64") Linux)
+  ]
+
+platformMapping :: [(String, NixpkgsPlatform)]
+platformMapping = map (second NixpkgsPlatformSingle) nixpkgsSystemMapping
+  ++ map platformGroupMapping [ "riscv", "x86", "linux", "darwin" ]
+
+platformGroupMapping :: String -> (String, NixpkgsPlatform)
+platformGroupMapping name =
+  ("lib.platforms." ++ name, NixpkgsPlatformGroup (ident # name))
+
+checkRendering :: NixpkgsPlatform -> String -> Expectation
+checkRendering plat@(NixpkgsPlatformSingle _) str =
+  prettyShow plat `shouldBe` "\"" ++ str ++ "\""
+checkRendering plat str = prettyShow plat `shouldBe` str
 
 hitsBottom :: NFData a => a -> Expectation
 hitsBottom x = evaluate (rnf x) `shouldThrow` anyErrorCall
