diff --git a/Data/Text/ICU/Calendar.hsc b/Data/Text/ICU/Calendar.hsc
--- a/Data/Text/ICU/Calendar.hsc
+++ b/Data/Text/ICU/Calendar.hsc
@@ -1,4 +1,4 @@
-{-# LANGUAGE ImportQualifiedPost, RankNTypes, BangPatterns, ForeignFunctionInterface, RecordWildCards #-}
+{-# LANGUAGE RankNTypes, BangPatterns, ForeignFunctionInterface, RecordWildCards #-}
 -- |
 -- Module      : Data.Text.ICU.Calendar
 -- Copyright   : (c) 2021 Torsten Kemps-Benedix
@@ -47,8 +47,8 @@
 import Data.Text.ICU.Enumerator
 import Data.Text.ICU.Error.Internal (UErrorCode, handleError)
 import Data.Text.ICU.Internal (LocaleName(..), UChar, withLocaleName, newICUPtr, useAsUCharPtr)
-import Data.Time.Calendar qualified as Cal
-import Data.Time.Clock qualified as Clock
+import qualified Data.Time.Calendar as Cal
+import qualified Data.Time.Clock as Clock
 import Foreign.C.String (CString)
 import Foreign.C.Types (CInt(..))
 import Foreign.ForeignPtr (withForeignPtr, ForeignPtr)
diff --git a/Data/Text/ICU/DateFormatter.hsc b/Data/Text/ICU/DateFormatter.hsc
--- a/Data/Text/ICU/DateFormatter.hsc
+++ b/Data/Text/ICU/DateFormatter.hsc
@@ -1,4 +1,4 @@
-{-# LANGUAGE EmptyDataDecls, BlockArguments, ImportQualifiedPost, RankNTypes, BangPatterns, ForeignFunctionInterface, RecordWildCards #-}
+{-# LANGUAGE EmptyDataDecls, RankNTypes, BangPatterns, ForeignFunctionInterface, RecordWildCards #-}
 -- |
 -- Module      : Data.Text.ICU.DateFormatter
 -- Copyright   : (c) 2021 Torsten Kemps-Benedix
@@ -31,7 +31,7 @@
 import Control.Monad (forM)
 import Data.Int (Int32)
 import Data.Text (Text)
-import Data.Text qualified as T
+import qualified Data.Text as T
 import Data.Text.ICU.Error.Internal (UErrorCode, handleError, handleOverflowError)
 import Data.Text.ICU.Internal (LocaleName(..), UChar, withLocaleName, newICUPtr, fromUCharPtr, useAsUCharPtr)
 import Data.Text.ICU.Calendar
@@ -189,10 +189,10 @@
 -- >>> dateSymbols dfAt Months
 -- ["J\228nner","Februar","M\228rz","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"]
 dateSymbols :: DateFormatter -> DateFormatSymbolType -> [Text]
-dateSymbols (DateFormatter df) symType = unsafePerformIO do
+dateSymbols (DateFormatter df) symType = unsafePerformIO $ do
   withForeignPtr df $ \dfPtr -> do
     n <- udat_countSymbols dfPtr (toUDateFormatSymbolType symType)
-    syms <- forM [0..(n-1)] \i -> do
+    syms <- forM [0..(n-1)] $ \i -> do
       handleOverflowError (fromIntegral (64 :: Int))
         (\dptr dlen -> udat_getSymbols dfPtr (toUDateFormatSymbolType symType) (fromIntegral i) dptr dlen)
         (\dptr dlen -> fromUCharPtr dptr (fromIntegral dlen))
diff --git a/Data/Text/ICU/Enumerator.hsc b/Data/Text/ICU/Enumerator.hsc
--- a/Data/Text/ICU/Enumerator.hsc
+++ b/Data/Text/ICU/Enumerator.hsc
@@ -1,4 +1,4 @@
-{-# LANGUAGE ImportQualifiedPost, EmptyDataDecls, BangPatterns, ForeignFunctionInterface, RecordWildCards #-}
+{-# LANGUAGE EmptyDataDecls, BangPatterns, ForeignFunctionInterface, RecordWildCards #-}
 -- |
 -- Module      : Data.Text.ICU.Calendar
 -- Copyright   : (c) 2021 Torsten Kemps-Benedix
diff --git a/Data/Text/ICU/Locale.hsc b/Data/Text/ICU/Locale.hsc
--- a/Data/Text/ICU/Locale.hsc
+++ b/Data/Text/ICU/Locale.hsc
@@ -1,4 +1,4 @@
-{-# LANGUAGE BlockArguments, ImportQualifiedPost, RankNTypes, BangPatterns, ForeignFunctionInterface, RecordWildCards #-}
+{-# LANGUAGE RankNTypes, BangPatterns, ForeignFunctionInterface, RecordWildCards #-}
 -- |
 -- Module      : Data.Text.ICU.Locale
 -- Copyright   : (c) 2021 Torsten Kemps-Benedix
@@ -27,7 +27,7 @@
 availableLocales :: IO [String]
 availableLocales = do
   n <- uloc_countAvailable
-  forM [0..n-1] \i -> uloc_getAvailable i >>= peekCString
+  forM [0..n-1] $ \i -> uloc_getAvailable i >>= peekCString
 
 foreign import ccall unsafe "hs_text_icu.h __hs_uloc_getAvailable" uloc_getAvailable
     :: Int32 -> IO CString
diff --git a/Data/Text/ICU/Normalize2.hsc b/Data/Text/ICU/Normalize2.hsc
--- a/Data/Text/ICU/Normalize2.hsc
+++ b/Data/Text/ICU/Normalize2.hsc
@@ -1,4 +1,4 @@
-{-# LANGUAGE EmptyDataDecls, BlockArguments, ImportQualifiedPost, CPP, DeriveDataTypeable, ForeignFunctionInterface #-}
+{-# LANGUAGE EmptyDataDecls, CPP, DeriveDataTypeable, ForeignFunctionInterface #-}
 -- |
 -- Module      : Data.Text.ICU.Normalize
 -- Copyright   : (c) 2009, 2010 Bryan O'Sullivan
@@ -248,31 +248,31 @@
 --
 -- >>> pack "a\x301" `compareUnicode'` pack "á"
 nfc :: Text -> Text
-nfc t = unsafePerformIO do
+nfc t = unsafePerformIO $ do
   nf <- nfcNormalizer
   pure $ normalizeWith nf t
 
 -- | Create an NFKC normalizer and apply this to the given text.
 nfkc :: Text -> Text
-nfkc t = unsafePerformIO do
+nfkc t = unsafePerformIO $ do
   nf <- nfkcNormalizer
   pure $ normalizeWith nf t
 
 -- | Create an NFD normalizer and apply this to the given text.
 nfd :: Text -> Text
-nfd t = unsafePerformIO do
+nfd t = unsafePerformIO $ do
   nf <- nfdNormalizer
   pure $ normalizeWith nf t
 
 -- | Create an NFC normalizer and apply this to the given text.
 nfkd :: Text -> Text
-nfkd t = unsafePerformIO do
+nfkd t = unsafePerformIO $ do
   nf <- nfkdNormalizer
   pure $ normalizeWith nf t
 
 -- | Create an NFKCCasefold normalizer and apply this to the given text.
 nfkcCasefold :: Text -> Text
-nfkcCasefold t = unsafePerformIO do
+nfkcCasefold t = unsafePerformIO $ do
   nf <- nfkcCasefoldNormalizer
   pure $ normalizeWith nf t
 
@@ -294,19 +294,19 @@
     fmap toNCR . handleError $ unorm2_quickCheck nfPtr sptr (fromIntegral slen)
 
 quickCheck :: NormalizationMode -> Text -> Maybe Bool
-quickCheck NFD t = unsafePerformIO do
+quickCheck NFD t = unsafePerformIO $ do
   nf <- nfdNormalizer
   pure $ quickCheckWith nf t
-quickCheck NFC t = unsafePerformIO do
+quickCheck NFC t = unsafePerformIO $ do
   nf <- nfcNormalizer
   pure $ quickCheckWith nf t
-quickCheck NFKD t = unsafePerformIO do
+quickCheck NFKD t = unsafePerformIO $ do
   nf <- nfkdNormalizer
   pure $ quickCheckWith nf t
-quickCheck NFKC t = unsafePerformIO do
+quickCheck NFKC t = unsafePerformIO $ do
   nf <- nfkcNormalizer
   pure $ quickCheckWith nf t
-quickCheck NFKCCasefold t = unsafePerformIO do
+quickCheck NFKCCasefold t = unsafePerformIO $ do
   nf <- nfkcCasefoldNormalizer
   pure $ quickCheckWith nf t
 
@@ -323,19 +323,19 @@
     fmap asBool . handleError $ unorm2_isNormalized nfPtr sptr (fromIntegral slen)
 
 isNormalized :: NormalizationMode -> Text -> Bool
-isNormalized NFD t = unsafePerformIO do
+isNormalized NFD t = unsafePerformIO $ do
   nf <- nfdNormalizer
   pure $ isNormalizedWith nf t
-isNormalized NFC t = unsafePerformIO do
+isNormalized NFC t = unsafePerformIO $ do
   nf <- nfcNormalizer
   pure $ isNormalizedWith nf t
-isNormalized NFKD t = unsafePerformIO do
+isNormalized NFKD t = unsafePerformIO $ do
   nf <- nfkdNormalizer
   pure $ isNormalizedWith nf t
-isNormalized NFKC t = unsafePerformIO do
+isNormalized NFKC t = unsafePerformIO $ do
   nf <- nfkcNormalizer
   pure $ isNormalizedWith nf t
-isNormalized NFKCCasefold t = unsafePerformIO do
+isNormalized NFKCCasefold t = unsafePerformIO $ do
   nf <- nfkcCasefoldNormalizer
   pure $ isNormalizedWith nf t
 
@@ -384,7 +384,7 @@
 -- are relatively long, is memory allocated temporarily.  For 'FCD'
 -- strings and short non-'FCD' strings there is no memory allocation.
 compareUnicode :: [CompareOption] -> Text -> Text -> Ordering
-compareUnicode opts a b = unsafePerformIO do
+compareUnicode opts a b = unsafePerformIO $ do
   useAsUCharPtr a $ \aptr alen ->
     useAsUCharPtr b $ \bptr blen ->
       fmap asOrdering . handleError $
diff --git a/Data/Text/ICU/NumberFormatter.hsc b/Data/Text/ICU/NumberFormatter.hsc
--- a/Data/Text/ICU/NumberFormatter.hsc
+++ b/Data/Text/ICU/NumberFormatter.hsc
@@ -1,4 +1,4 @@
-{-# LANGUAGE EmptyDataDecls, BlockArguments, ImportQualifiedPost, RankNTypes, BangPatterns, ForeignFunctionInterface, RecordWildCards #-}
+{-# LANGUAGE EmptyDataDecls, RankNTypes, BangPatterns, ForeignFunctionInterface, RecordWildCards #-}
 -- |
 -- Module      : Data.Text.ICU.NumberFormatter
 -- Copyright   : (c) 2021 Torsten Kemps-Benedix
@@ -90,7 +90,7 @@
 -- >>> formatIntegral nf2 12345
 -- "12\8239\&345"
 formatIntegral :: Integral a => NumberFormatter -> a -> Text
-formatIntegral (NumberFormatter nf) x = unsafePerformIO do
+formatIntegral (NumberFormatter nf) x = unsafePerformIO $ do
   withForeignPtr nf $ \nfPtr -> do
     resultPtr <- newResult
     withForeignPtr resultPtr $ \resPtr -> do
@@ -102,7 +102,7 @@
 
 -- | Create a number formatter and apply it to an integral number.
 formatIntegral' :: (Integral a) => Text -> LocaleName -> a -> Text
-formatIntegral' skel loc x = unsafePerformIO do
+formatIntegral' skel loc x = unsafePerformIO $ do
   nf <- numberFormatter skel loc
   pure $ formatIntegral nf x
 
@@ -116,7 +116,7 @@
 -- >>> formatDouble nf3 12345.6789
 -- "12.345,68"
 formatDouble :: NumberFormatter -> Double -> Text
-formatDouble (NumberFormatter nf) x = unsafePerformIO do
+formatDouble (NumberFormatter nf) x = unsafePerformIO $ do
   withForeignPtr nf $ \nfPtr -> do
     resultPtr <- newResult
     withForeignPtr resultPtr $ \resPtr -> do
@@ -128,7 +128,7 @@
 
 -- | Create a number formatter and apply it to a Double.
 formatDouble' :: Text -> LocaleName -> Double -> Text
-formatDouble' skel loc x = unsafePerformIO do
+formatDouble' skel loc x = unsafePerformIO $ do
   nf <- numberFormatter skel loc
   pure $ formatDouble nf x
 
diff --git a/README.markdown b/README.markdown
--- a/README.markdown
+++ b/README.markdown
@@ -12,28 +12,73 @@
 
 * Comparison and collation
 
-# Prerequisites
+## Prerequisites
 
 This library is implemented as bindings to the well-respected [ICU
-library](http://www.icu-project.org/) (which is not bundled, and must
+library](https://icu.unicode.org/) (which is not bundled, and must
 be installed separately).
 
-For Ubuntu `apt-get install libicu-dev` should suffice.
+### macOS
 
+    brew install icu4c
+    brew link icu4c --force
 
-# Compatibility
+You might need:
 
+    export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig"
+
+### Debian/Ubuntu
+
+    sudo apt-get update
+    sudo apt-get install libicu-dev
+
+### Fedora/CentOS
+
+    sudo dnf install unzip libicu-devel
+
+### Nix/NixOS
+
+    nix-shell --packages icu
+
+### Windows/MSYS2
+
+Under MSYS2, `ICU` can be installed via `pacman`.
+
+    pacman --noconfirm -S mingw-w64-x86_64-icu
+
+Depending on the age of the MSYS2 installation, the keyring might need
+to be updated to avoid certification issues, and `pkg-config` might
+need to be added.  In this case, do this first:
+
+    pacman --noconfirm -Sy msys2-keyring
+    pacman --noconfirm -S mingw-w64-x86_64-pkg-config
+
+### Windows/stack
+
+With `stack` on Windows, which comes with its _own_ bundled MSYS2, the
+following commands give up-to-date system dependencies for
+`text-icu-0.8.0` (tested 2022-02-07):
+
+    stack exec -- pacman --noconfirm -Sy msys2-keyring
+    stack exec -- pacman --noconfirm -S mingw-w64-x86_64-icu
+    stack exec -- pacman --noconfirm -S mingw-w64-x86_64-pkg-config
+
+
+## Compatibility
+
 Upstream ICU occasionally introduces backwards-incompatible API
-breaks.  This package tries to stay up to date with upstream, and is
-currently more or less in sync with ICU 69.
+breaks. This package tries to stay up to date with upstream, and is
+currently more or less in sync with ICU 70.
 
+Minimum required version is ICU 62.
 
-# Get involved!
 
+## Get involved!
+
 Please report bugs via the
 [github issue tracker](https://github.com/haskell/text-icu/issues).
 
 
-# Authors
+## Authors
 
 This library was written by Bryan O'Sullivan.
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,8 @@
+0.8.0.1
+
+* Restore build with GHC 7.10 - 8.8 (#61)
+* New CI for Linux, macOS and Windows (#63, #64, #66, #69)
+
 0.8.0
 
 * Support for text-2.0 (#57)
diff --git a/tests/Properties.hs b/tests/Properties.hs
--- a/tests/Properties.hs
+++ b/tests/Properties.hs
@@ -4,6 +4,7 @@
 -- return results, without checking whether the results are correct.
 -- Weak tests are described as such.
 
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE OverloadedStrings, LambdaCase #-}
 {-# OPTIONS_GHC -fno-warn-missing-signatures #-}
 module Properties (propertyTests, testCases) where
@@ -35,6 +36,10 @@
 import qualified Data.Text.ICU.Shape as S
 import System.IO.Unsafe (unsafePerformIO)
 
+#if !MIN_VERSION_base(4,11,0)
+import Data.Semigroup ((<>))
+#endif
+
 {-# ANN module ("HLint: use camelCase"::String) #-}
 
 t_rnf :: (NFData b) => (a -> b) -> a -> Bool
@@ -63,8 +68,6 @@
 
 -- Normalization
 
-t_normalize mode = t_nonEmpty $ I.normalize mode
-
 t_quickCheck_isNormalized mode normMode txt
   | mode `elem` [NFD, NFKD] =          quickCheck == Just isNormalized
   | otherwise = fromMaybe isNormalized quickCheck ==      isNormalized
@@ -130,7 +133,6 @@
   , testProperty "t_charIterator_String" t_charIterator_String
   , testProperty "t_charIterator_Text" t_charIterator_Text
   , testProperty "t_charIterator_Utf8" t_charIterator_Utf8
-  , testProperty "t_normalize" t_normalize
   , testProperty "t_quickCheck_isNormalized" t_quickCheck_isNormalized
   , testProperty "t_collate" t_collate
   , testProperty "t_convert" t_convert
diff --git a/tests/QuickCheckUtils.hs b/tests/QuickCheckUtils.hs
--- a/tests/QuickCheckUtils.hs
+++ b/tests/QuickCheckUtils.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE CPP #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module QuickCheckUtils (NonEmptyText(..), LatinSpoofableText(..),
@@ -13,6 +14,10 @@
 import qualified Data.Text as T
 import qualified Data.Text.ICU as I
 
+#if !MIN_VERSION_base(4,11,0)
+import Data.Semigroup ((<>))
+#endif
+
 instance Arbitrary T.Text where
     arbitrary = T.pack `fmap` arbitrary
     shrink = map T.pack . shrink . T.unpack
@@ -48,8 +53,8 @@
   ['\x0445'..'\x0446'] ++
   "\x044A" ++
   ['\x0454'..'\x0456'] ++
-  "\x0458\x045B\x048D\x0491\x0493\x049B\x049F\x04AB\x04AD\x04AF\x04B1\x04BB\
-  \\x04BD\x04BF" ++
+  "\x0458\x045B\x048D\x0491\x0493\x049B\x049F\x04AB\x04AD\x04AF\x04B1\x04BB" ++
+  "\x04BD\x04BF" ++
   ['\x04CE'..'\x04CF'] ++
   "\x04D5\x04D9\x04E9\x0501\x0511\x051B\x051D")
 
diff --git a/text-icu.cabal b/text-icu.cabal
--- a/text-icu.cabal
+++ b/text-icu.cabal
@@ -1,5 +1,5 @@
 name:           text-icu
-version:        0.8.0
+version:        0.8.0.1
 synopsis:       Bindings to the ICU library
 homepage:       https://github.com/haskell/text-icu
 bug-reports:    https://github.com/haskell/text-icu/issues
@@ -50,15 +50,26 @@
   changelog.md
   include/hs_text_icu.h
 
+tested-with:
+  GHC == 7.10.3
+  GHC == 8.0.2
+  GHC == 8.2.2
+  GHC == 8.4.4
+  GHC == 8.6.5
+  GHC == 8.8.4
+  GHC == 8.10.7
+  GHC == 9.0.2
+  GHC == 9.2.1
+
 library
   default-language:  Haskell98
   build-depends:
-    base >= 4 && < 5,
+    base >= 4.8 && < 5,
     bytestring,
     deepseq >= 1.4.3.0,
     text >=0.9.1.0 && <1.3 || >=2.0 && <2.1,
     time >=1.5 && <1.13
-  pkgconfig-depends: icu-uc, icu-i18n
+  pkgconfig-depends: icu-i18n >= 62.1
 
   exposed-modules:
       Data.Text.ICU
@@ -116,7 +127,9 @@
   else
     extra-libraries: icui18n icudata
 
-  ghc-options: -Wall -fwarn-tabs -Wcompat
+  ghc-options: -Wall -fwarn-tabs
+  if impl(ghc >= 8.0)
+    ghc-options:  -Wcompat
 
 test-suite tests
   default-language: Haskell98
@@ -143,6 +156,8 @@
     test-framework-quickcheck2 >= 0.2,
     text,
     text-icu
+  if impl(ghc <= 8.2)
+    build-depends: semigroups
 
 source-repository head
   type:     git
