Hannes Siebenhandl pushed to branch wip/fendor/dep-json at Glasgow Haskell Compiler / GHC
Commits:
11 changed files:
- compiler/GHC/Driver/MakeFile.hs
- ghc/Main.hs
- testsuite/driver/testlib.py
- testsuite/tests/driver/T24384/Makefile
- testsuite/tests/driver/T24384/T24384a.stdout
- testsuite/tests/driver/T24384/T24384b.stdout
- + testsuite/tests/driver/T24384/T24384b.stdout-mingw
- + testsuite/tests/driver/T24384/T24384c.stdout
- testsuite/tests/driver/T24384/all.T
- + testsuite/tests/driver/T24384/format_json.sh
- + testsuite/tests/driver/T24384/format_makefile.sh
Changes:
| ... | ... | @@ -11,7 +11,8 @@ |
| 11 | 11 | {-# LANGUAGE RecordWildCards #-}
|
| 12 | 12 | |
| 13 | 13 | module GHC.Driver.MakeFile
|
| 14 | - ( doMkDependHS
|
|
| 14 | + ( doMkDepend
|
|
| 15 | + , doMkDependHS
|
|
| 15 | 16 | , doMkDependModuleGraph
|
| 16 | 17 | )
|
| 17 | 18 | where
|
| ... | ... | @@ -80,6 +81,8 @@ import System.IO.Error (isEOFError) |
| 80 | 81 | import qualified System.OsString as OsString
|
| 81 | 82 | import qualified Data.Monoid as Monoid
|
| 82 | 83 | import qualified System.FilePath as FilePath
|
| 84 | +import GHC.Unit.Home.Graph (HomeUnitEnv(homeUnitEnv_dflags))
|
|
| 85 | +import GHC (setProgramHUG)
|
|
| 83 | 86 | |
| 84 | 87 | -----------------------------------------------------------------
|
| 85 | 88 | --
|
| ... | ... | @@ -117,7 +120,39 @@ doMkDependHS srcs = do |
| 117 | 120 | module_graph <- GHC.depanal excl_mods True {- Allow dup roots -}
|
| 118 | 121 | doMkDependModuleGraph dflags module_graph
|
| 119 | 122 | |
| 123 | +doMkDepend :: GhcMonad m => m ()
|
|
| 124 | +doMkDepend = do
|
|
| 125 | + hug_ <- hsc_HUG <$> getSession
|
|
| 126 | + |
|
| 127 | + let hug =
|
|
| 128 | + fmap (\ hue ->
|
|
| 129 | + let
|
|
| 130 | + -- We kludge things a bit for dependency generation. Rather than
|
|
| 131 | + -- generating dependencies for each way separately, we generate
|
|
| 132 | + -- them once and then duplicate them for each way's osuf/hisuf.
|
|
| 133 | + -- We therefore do the initial dependency generation with an empty
|
|
| 134 | + -- way and .o/.hi extensions, regardless of any flags that might
|
|
| 135 | + -- be specified.
|
|
| 136 | + dflags1 = (homeUnitEnv_dflags hue)
|
|
| 137 | + { targetWays_ = Set.empty
|
|
| 138 | + , hiSuf_ = "hi"
|
|
| 139 | + , objectSuf_ = "o"
|
|
| 140 | + }
|
|
| 141 | + in
|
|
| 142 | + hue {homeUnitEnv_dflags = dflags1}
|
|
| 143 | + ) hug_
|
|
| 144 | + |
|
| 145 | + _ <- setProgramHUG hug
|
|
| 146 | + |
|
| 147 | + dflagsGlobal <- GHC.getSessionDynFlags
|
|
| 148 | + -- If no suffix is provided, use the default -- the empty one
|
|
| 149 | + let dflags = if null (depSuffixes dflagsGlobal)
|
|
| 150 | + then dflagsGlobal { depSuffixes = [""] }
|
|
| 151 | + else dflagsGlobal
|
|
| 120 | 152 | |
| 153 | + let excl_mods = depExcludeMods dflags
|
|
| 154 | + module_graph <- GHC.depanal excl_mods True {- Allow dup roots -}
|
|
| 155 | + doMkDependModuleGraph dflags module_graph
|
|
| 121 | 156 | |
| 122 | 157 | doMkDependModuleGraph :: GhcMonad m => DynFlags -> ModuleGraph -> m ()
|
| 123 | 158 | doMkDependModuleGraph dflags module_graph = do
|
| ... | ... | @@ -610,127 +645,188 @@ writeJsonFile doc p = do |
| 610 | 645 | --------------------------------------------------------------------------------
|
| 611 | 646 | -- Payload for -dep-json
|
| 612 | 647 | |
| 613 | -newtype PackageDeps
|
|
| 614 | - = PackageDeps (Map.Map (String, UnitId, DPackageId) DepsImports)
|
|
| 615 | - deriving newtype (Monoid)
|
|
| 616 | - |
|
| 617 | 648 | newtype DPackageId = DPackageId PackageId
|
| 618 | 649 | deriving newtype (Eq)
|
| 619 | 650 | |
| 620 | 651 | instance Ord DPackageId where
|
| 621 | 652 | DPackageId (PackageId d1) `compare` DPackageId (PackageId d2) = d1 `lexicalCompareFS` d2
|
| 622 | 653 | |
| 623 | -instance Semigroup PackageDeps where
|
|
| 624 | - PackageDeps l <> PackageDeps r = PackageDeps (Map.unionWith (Semigroup.<>) l r)
|
|
| 625 | - |
|
| 626 | -data Deps = Deps
|
|
| 627 | - { sources :: Set.Set OsPath
|
|
| 628 | - , moduleImports :: DepsImports
|
|
| 629 | - , sourceImports :: DepsImports
|
|
| 630 | - , packages :: PackageDeps
|
|
| 654 | +data ModuleNodeDeps = ModuleNodeDeps
|
|
| 655 | + { source :: OsPath
|
|
| 656 | + , imports :: ImportDeps
|
|
| 631 | 657 | , cpp :: Set.Set OsPath
|
| 632 | 658 | , options :: [String]
|
| 633 | 659 | , preprocessor :: Maybe FilePath
|
| 634 | 660 | }
|
| 635 | 661 | deriving stock (Generic)
|
| 636 | - deriving (Semigroup, Monoid) via (Generically Deps)
|
|
| 662 | + deriving (Semigroup, Monoid) via (Generically ModuleNodeDeps)
|
|
| 637 | 663 | |
| 638 | -data DepsImports
|
|
| 639 | - = DepsImports
|
|
| 640 | - { normalImport :: Set.Set Module
|
|
| 641 | - , spliceImport :: Set.Set Module
|
|
| 642 | - , quoteImport :: Set.Set Module
|
|
| 643 | - }
|
|
| 664 | +addImport :: ImportDep -> ModuleNodeDeps -> ModuleNodeDeps
|
|
| 665 | +addImport import_dep mod_node_deps =
|
|
| 666 | + mod_node_deps
|
|
| 667 | + { imports = ImportDeps $ Map.insertWith Set.union uid (Set.singleton import_dep) (getImports $ imports mod_node_deps)
|
|
| 668 | + }
|
|
| 669 | + where
|
|
| 670 | + uid = toUnitId $ moduleUnit $ imp_mod import_dep
|
|
| 671 | + |
|
| 672 | +addCpp :: OsPath -> ModuleNodeDeps -> ModuleNodeDeps
|
|
| 673 | +addCpp p mod_node_deps =
|
|
| 674 | + mod_node_deps
|
|
| 675 | + { cpp = Set.insert p (cpp mod_node_deps)
|
|
| 676 | + }
|
|
| 677 | + |
|
| 678 | +newtype ImportDeps = ImportDeps { getImports :: Map.Map UnitId (Set.Set ImportDep) }
|
|
| 644 | 679 | deriving stock (Generic)
|
| 645 | - deriving (Semigroup, Monoid) via (Generically DepsImports)
|
|
| 680 | + deriving (Semigroup, Monoid) via (Generically ImportDeps)
|
|
| 681 | + |
|
| 682 | +data ImportDep = ImportDep
|
|
| 683 | + { imp_mod :: Module
|
|
| 684 | + , imp_level :: ImportLevel
|
|
| 685 | + , imp_isBoot :: IsBootInterface
|
|
| 686 | + } deriving (Eq, Ord)
|
|
| 687 | + |
|
| 688 | +mkImportDep :: Module -> ImportLevel -> IsBootInterface -> ImportDep
|
|
| 689 | +mkImportDep modl level isBoot = ImportDep
|
|
| 690 | + { imp_mod = modl
|
|
| 691 | + , imp_level = level
|
|
| 692 | + , imp_isBoot = isBoot
|
|
| 693 | + }
|
|
| 646 | 694 | |
| 647 | -newtype DepJson = DepJson (Map.Map ModuleWithIsBoot Deps)
|
|
| 695 | +data HomeUnitDeps = HomeUnitDeps
|
|
| 696 | + { homeModules :: Map.Map ModuleWithIsBoot ModuleNodeDeps
|
|
| 697 | + }
|
|
| 698 | + deriving stock (Generic)
|
|
| 699 | + deriving (Semigroup, Monoid) via (Generically HomeUnitDeps)
|
|
| 700 | + |
|
| 701 | +data ExtUnitDep = ExtUnitDep
|
|
| 702 | + { extUnitId :: UnitId
|
|
| 703 | + -- ^ The 'UnitId' of a unit. This is assumed to be globally unique.
|
|
| 704 | + , extUnitName :: String
|
|
| 705 | + , extUnitPackageId :: DPackageId
|
|
| 706 | + } deriving (Eq, Ord)
|
|
| 707 | + |
|
| 708 | +data DepJson = DepJson
|
|
| 709 | + { homeUnitDeps :: Map.Map UnitId HomeUnitDeps
|
|
| 710 | + , externalDeps :: Set.Set ExtUnitDep
|
|
| 711 | + }
|
|
| 648 | 712 | |
| 649 | 713 | instance ToJson DepJson where
|
| 650 | - json (DepJson m) =
|
|
| 651 | - JSObject
|
|
| 652 | - [ (homeUnitModuleKey target, homeUnitModule deps)
|
|
| 653 | - | (target, deps) <- Map.toList m
|
|
| 714 | + json (DepJson homeUnits extDeps) =
|
|
| 715 | + JSObject $
|
|
| 716 | + [ homeUnit huid hud
|
|
| 717 | + | (huid, hud) <- Map.toList homeUnits
|
|
| 718 | + ] ++
|
|
| 719 | + [ mkExtDepObj dep
|
|
| 720 | + | dep <- Set.toList extDeps
|
|
| 654 | 721 | ]
|
| 655 | 722 | where
|
| 723 | + homeUnit uid hud =
|
|
| 724 | + ( unitIdString uid
|
|
| 725 | + , JSObject
|
|
| 726 | + [
|
|
| 727 | + ( "modules"
|
|
| 728 | + , JSObject
|
|
| 729 | + [ (homeUnitModuleKey modl, homeUnitModule deps)
|
|
| 730 | + | (modl, deps) <- Map.toList $ homeModules hud
|
|
| 731 | + ]
|
|
| 732 | + )
|
|
| 733 | + ]
|
|
| 734 | + )
|
|
| 735 | + |
|
| 656 | 736 | homeUnitModuleKey :: ModuleWithIsBoot -> String
|
| 657 | - homeUnitModuleKey t = moduleNameString (moduleName (gwib_mod t)) ++ case gwib_isBoot t of
|
|
| 737 | + homeUnitModuleKey t = moduleKey (gwib_mod t) (gwib_isBoot t)
|
|
| 738 | + |
|
| 739 | + moduleKey :: Module -> IsBootInterface -> String
|
|
| 740 | + moduleKey t b = moduleNameString (moduleName t) ++ case b of
|
|
| 658 | 741 | IsBoot -> "[boot]"
|
| 659 | 742 | NotBoot -> ""
|
| 660 | 743 | |
| 661 | - homeUnitModule :: Deps -> JsonDoc
|
|
| 662 | - homeUnitModule Deps {packages = PackageDeps packages, ..} =
|
|
| 744 | + homeUnitModule :: ModuleNodeDeps -> JsonDoc
|
|
| 745 | + homeUnitModule ModuleNodeDeps {source, imports, cpp, options, preprocessor} =
|
|
| 663 | 746 | JSObject
|
| 664 | - [ ("sources", array sources (showOsPath . normalise))
|
|
| 665 | - , ("modules", JSObject $ importsObj moduleImports)
|
|
| 666 | - , ("modules-boot", JSObject $ importsObj sourceImports)
|
|
| 667 | - , ("packages", JSArray
|
|
| 668 | - [ package name unit_id package_id mods
|
|
| 669 | - | ((name, unit_id, dpkd_id), mods) <- Map.toList packages
|
|
| 670 | - , let DPackageId package_id = dpkd_id
|
|
| 671 | - ]
|
|
| 672 | - )
|
|
| 673 | - , ("cpp", array cpp showOsPath)
|
|
| 747 | + [ ("source", JSString . showOsPath $ normalise source)
|
|
| 748 | + , ("imports", importsObj imports)
|
|
| 749 | + , ("includes", strArray cpp showOsPath)
|
|
| 674 | 750 | , ("options", JSArray $ map JSString options)
|
| 675 | 751 | , ("preprocessor", maybe JSNull JSString preprocessor)
|
| 676 | 752 | ]
|
| 677 | 753 | |
| 678 | - package :: String -> UnitId -> PackageId -> DepsImports -> JsonDoc
|
|
| 679 | - package name unit_id (PackageId package_id) mods =
|
|
| 754 | + importsObj :: ImportDeps -> JsonDoc
|
|
| 755 | + importsObj importDeps = JSArray $ map importObj (Map.toList $ getImports importDeps)
|
|
| 756 | + |
|
| 757 | + importObj :: (UnitId, Set.Set ImportDep) -> JsonDoc
|
|
| 758 | + importObj (uid, importSet) =
|
|
| 680 | 759 | JSObject
|
| 681 | - [ ("id", JSString (unitIdString unit_id))
|
|
| 682 | - , ("name", JSString name)
|
|
| 683 | - , ("package-id", JSString (unpackFS package_id))
|
|
| 684 | - , ("modules", JSObject $ importsObj mods)
|
|
| 760 | + [ (unitIdString uid, array importSet importDepObj )
|
|
| 685 | 761 | ]
|
| 686 | 762 | |
| 687 | - array values render = JSArray (fmap (JSString . render) (Set.toList values))
|
|
| 763 | + importDepObj :: ImportDep -> JsonDoc
|
|
| 764 | + importDepObj ImportDep {imp_mod, imp_level, imp_isBoot}
|
|
| 765 | + | NormalLevel <- imp_level = JSString (moduleKey imp_mod imp_isBoot)
|
|
| 766 | + | otherwise = JSObject
|
|
| 767 | + [ ("module", JSString (moduleKey imp_mod imp_isBoot))
|
|
| 768 | + , ("level" , importLevel imp_level)
|
|
| 769 | + ]
|
|
| 688 | 770 | |
| 689 | - showOsPath = unsafeDecodeUtf
|
|
| 771 | + importLevel :: ImportLevel -> JsonDoc
|
|
| 772 | + importLevel lvl =
|
|
| 773 | + JSString $ case lvl of
|
|
| 774 | + NormalLevel -> "normal"
|
|
| 775 | + SpliceLevel -> "splice"
|
|
| 776 | + QuoteLevel -> "quote"
|
|
| 777 | + |
|
| 778 | + mkExtDepObj :: ExtUnitDep -> (String, JsonDoc)
|
|
| 779 | + mkExtDepObj ExtUnitDep{..} =
|
|
| 780 | + ( unitIdString extUnitId
|
|
| 781 | + , JSObject
|
|
| 782 | + [ ("package-name", JSString extUnitName)
|
|
| 783 | + , ("package-id", JSString $ showPackageId extUnitPackageId)
|
|
| 784 | + ]
|
|
| 785 | + )
|
|
| 786 | + |
|
| 787 | + array values render = JSArray (fmap render (Set.toList values))
|
|
| 788 | + strArray values render = JSArray (fmap (JSString . render) (Set.toList values))
|
|
| 690 | 789 | |
| 691 | - importsObj :: DepsImports -> [(String, JsonDoc)]
|
|
| 692 | - importsObj DepsImports{..} =
|
|
| 693 | - [ ("normal", array normalImport (moduleNameString . moduleName))
|
|
| 694 | - , ("quote" , array quoteImport (moduleNameString . moduleName))
|
|
| 695 | - , ("splice", array spliceImport (moduleNameString . moduleName))
|
|
| 696 | - ]
|
|
| 790 | + showOsPath = unsafeDecodeUtf
|
|
| 791 | + showPackageId (DPackageId (PackageId pid)) = unpackFS pid
|
|
| 697 | 792 | |
| 698 | 793 | initDepJson :: IO (IORef DepJson)
|
| 699 | -initDepJson = newIORef $ DepJson Map.empty
|
|
| 794 | +initDepJson = newIORef $ DepJson Map.empty Set.empty
|
|
| 700 | 795 | |
| 701 | -insertDepJson :: [ModuleWithIsBoot] -> Deps -> DepJson -> DepJson
|
|
| 702 | -insertDepJson targets dep (DepJson m0) =
|
|
| 796 | +insertDepJson :: ModuleWithIsBoot -> ModuleNodeDeps -> Set.Set ExtUnitDep -> DepJson -> DepJson
|
|
| 797 | +insertDepJson target modNode extUnits (DepJson m0 e0) =
|
|
| 703 | 798 | DepJson
|
| 704 | - $ foldl'
|
|
| 705 | - ( \acc target ->
|
|
| 706 | - Map.insertWithKey
|
|
| 707 | - (\ k _l _r -> pprPanic "insertDepJson" (text "Conflicting entries for: " <+> ppr k))
|
|
| 708 | - target
|
|
| 709 | - dep
|
|
| 710 | - acc
|
|
| 711 | - )
|
|
| 712 | - m0
|
|
| 713 | - targets
|
|
| 799 | + { homeUnitDeps =
|
|
| 800 | + Map.insertWith
|
|
| 801 | + (Semigroup.<>)
|
|
| 802 | + modUnitId
|
|
| 803 | + (HomeUnitDeps $ Map.singleton target modNode)
|
|
| 804 | + m0
|
|
| 805 | + , externalDeps =
|
|
| 806 | + Set.union e0 extUnits
|
|
| 807 | + }
|
|
| 808 | + where
|
|
| 809 | + modUnitId = toUnitId $ moduleUnit $ gwib_mod target
|
|
| 714 | 810 | |
| 715 | 811 | updateDepJson :: Bool -> DepNode -> [Dep] -> DepJson -> DepJson
|
| 716 | 812 | updateDepJson include_pkgs DepNode {..} deps =
|
| 717 | - insertDepJson [dn_mod] payload
|
|
| 813 | + insertDepJson dn_mod payload externalDeps
|
|
| 718 | 814 | where
|
| 719 | - payload = node_data Semigroup.<> foldMap mkDep deps
|
|
| 815 | + (externalDeps, payload) = foldl' go (Set.empty, initial_node_data) deps
|
|
| 720 | 816 | |
| 721 | - node_data =
|
|
| 722 | - mempty
|
|
| 723 | - { sources = Set.singleton dn_src
|
|
| 817 | + initial_node_data =
|
|
| 818 | + ModuleNodeDeps
|
|
| 819 | + { source = dn_src
|
|
| 724 | 820 | , preprocessor = pn_preprocessor dn_preprocessing
|
| 725 | 821 | , options = pn_options dn_preprocessing
|
| 822 | + , cpp = Set.empty
|
|
| 823 | + , imports = ImportDeps Map.empty
|
|
| 726 | 824 | }
|
| 727 | 825 | |
| 728 | - mkDep = \case
|
|
| 826 | + go (extDeps, node_data) = \ case
|
|
| 729 | 827 | DepHi {dep_mod, dep_local, dep_unit, dep_boot, dep_level}
|
| 730 | 828 | | dep_local
|
| 731 | - -> case dep_boot of
|
|
| 732 | - IsBoot -> mempty {sourceImports = depsImportForImport dep_mod dep_level}
|
|
| 733 | - NotBoot -> mempty {moduleImports = depsImportForImport dep_mod dep_level }
|
|
| 829 | + -> (extDeps, addImport (mkImportDep dep_mod dep_level dep_boot) node_data)
|
|
| 734 | 830 | |
| 735 | 831 | | include_pkgs
|
| 736 | 832 | , Just unit <- dep_unit
|
| ... | ... | @@ -738,19 +834,21 @@ updateDepJson include_pkgs DepNode {..} deps = |
| 738 | 834 | name = unpackFS nameFS
|
| 739 | 835 | withLibName (PackageName c) = name ++ ":" ++ unpackFS c
|
| 740 | 836 | lname = maybe name withLibName (unitComponentName unit)
|
| 741 | - key = (lname, unitId unit, DPackageId $ unitPackageId unit)
|
|
| 742 | - -> mempty {packages = PackageDeps (Map.singleton key (depsImportForImport dep_mod dep_level))}
|
|
| 837 | + newExtDep = ExtUnitDep
|
|
| 838 | + { extUnitId = unitId unit
|
|
| 839 | + , extUnitName = lname
|
|
| 840 | + , extUnitPackageId = DPackageId $ unitPackageId unit
|
|
| 841 | + }
|
|
| 842 | + ->
|
|
| 843 | + ( Set.insert newExtDep extDeps
|
|
| 844 | + , addImport (mkImportDep dep_mod dep_level dep_boot) node_data
|
|
| 845 | + )
|
|
| 743 | 846 | |
| 744 | 847 | | otherwise
|
| 745 | - -> mempty
|
|
| 848 | + -> (extDeps, node_data)
|
|
| 746 | 849 | |
| 747 | 850 | DepCpp {dep_path} ->
|
| 748 | - mempty {cpp = Set.singleton dep_path}
|
|
| 749 | - |
|
| 750 | - depsImportForImport mod_name = \ case
|
|
| 751 | - NormalLevel -> mempty { normalImport = Set.singleton mod_name }
|
|
| 752 | - SpliceLevel -> mempty { spliceImport = Set.singleton mod_name }
|
|
| 753 | - QuoteLevel -> mempty { quoteImport = Set.singleton mod_name }
|
|
| 851 | + (extDeps, addCpp dep_path node_data)
|
|
| 754 | 852 | |
| 755 | 853 | -----------------------------------------------------------------
|
| 756 | 854 | -- Module cycles
|
| ... | ... | @@ -27,7 +27,7 @@ import GHC.Driver.Phases |
| 27 | 27 | import GHC.Driver.Session
|
| 28 | 28 | import GHC.Driver.Ppr
|
| 29 | 29 | import GHC.Driver.Pipeline ( oneShot )
|
| 30 | -import GHC.Driver.MakeFile ( doMkDependHS )
|
|
| 30 | +import qualified GHC.Driver.MakeFile as MakeFile
|
|
| 31 | 31 | import GHC.Driver.Backpack ( doBackpack )
|
| 32 | 32 | import GHC.Driver.Plugins
|
| 33 | 33 | import GHC.Driver.Config.Logger (initLogFlags)
|
| ... | ... | @@ -271,7 +271,7 @@ main' postLoadMode units dflags0 args flagWarnings = do |
| 271 | 271 | f
|
| 272 | 272 | ShowByteCode f -> liftIO $ showByteCode logger hsc_env f
|
| 273 | 273 | DoMake -> doMake units srcs
|
| 274 | - DoMkDependHS -> doMkDependHS (map fst srcs)
|
|
| 274 | + DoMkDependHS -> doMkDepend units srcs
|
|
| 275 | 275 | StopBefore p -> liftIO (oneShot hsc_env p srcs)
|
| 276 | 276 | DoInteractive -> ghciUI units srcs Nothing
|
| 277 | 277 | DoEval exprs -> ghciUI units srcs $ Just $ reverse exprs
|
| ... | ... | @@ -332,6 +332,24 @@ doMake units targets = do |
| 332 | 332 | ok_flag <- GHC.load LoadAllTargets
|
| 333 | 333 | when (failed ok_flag) (liftIO $ exitWith (ExitFailure 1))
|
| 334 | 334 | |
| 335 | +-- ----------------------------------------------------------------------------
|
|
| 336 | +-- Run -M mode
|
|
| 337 | + |
|
| 338 | +doMkDepend :: [String] -> [(String, Maybe Phase)] -> Ghc ()
|
|
| 339 | +doMkDepend units targets = do
|
|
| 340 | + hs_srcs <- case NE.nonEmpty units of
|
|
| 341 | + Just ne_units -> do
|
|
| 342 | + initMulti ne_units (checkOptions DoMake)
|
|
| 343 | + Nothing -> do
|
|
| 344 | + s <- initMake targets -- TODO: @fendor: This feels wrong
|
|
| 345 | + return $ map (uncurry (,Nothing,)) s
|
|
| 346 | + case hs_srcs of
|
|
| 347 | + [] -> return ()
|
|
| 348 | + _ -> do
|
|
| 349 | + targets' <- mapM (\(src, uid, phase) -> GHC.guessTarget src uid phase) hs_srcs
|
|
| 350 | + GHC.setTargets targets'
|
|
| 351 | + MakeFile.doMkDepend
|
|
| 352 | + |
|
| 335 | 353 | -- ---------------------------------------------------------------------------
|
| 336 | 354 | -- Various banners and verbosity output.
|
| 337 | 355 |
| ... | ... | @@ -20,6 +20,7 @@ from pathlib import Path, PurePath |
| 20 | 20 | import collections
|
| 21 | 21 | import collections.abc
|
| 22 | 22 | import subprocess
|
| 23 | +import json
|
|
| 23 | 24 | |
| 24 | 25 | from testglobals import config, ghc_env, default_testopts, brokens, t, \
|
| 25 | 26 | TestRun, TestResult, TestOptions, PerfMetric
|
| ... | ... | @@ -3265,6 +3266,58 @@ def normalise_asm( s: str ) -> str: |
| 3265 | 3266 | out.append(ins[0])
|
| 3266 | 3267 | return '\n'.join(out)
|
| 3267 | 3268 | |
| 3269 | +def normalise_dep_json(s: str) -> str:
|
|
| 3270 | + """
|
|
| 3271 | + Normalise the json output of `ghc -M -dep-json output.json`
|
|
| 3272 | + """
|
|
| 3273 | + |
|
| 3274 | + def normalise_includes(j):
|
|
| 3275 | + # Only normalise proper json objects.
|
|
| 3276 | + # Strings might be parsed as json strings, but we that's not what we are looking for
|
|
| 3277 | + if not isinstance(j, dict):
|
|
| 3278 | + return j
|
|
| 3279 | + for unit in j.values():
|
|
| 3280 | + for module in unit.get("modules", {}).values():
|
|
| 3281 | + rewritten = [
|
|
| 3282 | + __replace_absolute_path(p)
|
|
| 3283 | + for p in module["includes"]
|
|
| 3284 | + ]
|
|
| 3285 | + # we sort to make sure this never
|
|
| 3286 | + module["includes"] = sorted(rewritten)
|
|
| 3287 | + return j
|
|
| 3288 | + |
|
| 3289 | + output = ""
|
|
| 3290 | + try:
|
|
| 3291 | + normalised_dep_json = normalise_includes(json.loads(s))
|
|
| 3292 | + output = json.dumps(normalised_dep_json, indent=2, sort_keys=True, ensure_ascii=False)
|
|
| 3293 | + except json.JSONDecodeError:
|
|
| 3294 | + output = s
|
|
| 3295 | + return output
|
|
| 3296 | + |
|
| 3297 | +def normalise_dep_makefile(s: str) -> str:
|
|
| 3298 | + """
|
|
| 3299 | + Normalise the Makefile output of `ghc -M`
|
|
| 3300 | + """
|
|
| 3301 | + |
|
| 3302 | + output = []
|
|
| 3303 | + rules = []
|
|
| 3304 | + for line in s.split("\n"):
|
|
| 3305 | + target, sep, dep = line.partition(" : ")
|
|
| 3306 | + if sep:
|
|
| 3307 | + rules.append(target + sep + __replace_absolute_path(dep))
|
|
| 3308 | + else:
|
|
| 3309 | + # sort each block of rules so the order doesn't depend on the original absolute paths
|
|
| 3310 | + output.extend(sorted(rules))
|
|
| 3311 | + rules = []
|
|
| 3312 | + output.append(line)
|
|
| 3313 | + output.extend(sorted(rules))
|
|
| 3314 | + return "\n".join(output)
|
|
| 3315 | + |
|
| 3316 | +def __replace_absolute_path(s: str) -> str:
|
|
| 3317 | + if s.startswith("/"):
|
|
| 3318 | + return "<absolute-path>/" + s.rsplit("/", 1)[-1]
|
|
| 3319 | + return s
|
|
| 3320 | + |
|
| 3268 | 3321 | def safe_print(s: str) -> None:
|
| 3269 | 3322 | s2 = s.encode(sys.stdout.encoding, errors='replace').decode(sys.stdout.encoding)
|
| 3270 | 3323 | print(s2)
|
| ... | ... | @@ -45,4 +45,12 @@ T24384b: T24384_prep |
| 45 | 45 | -package-db ./$(PKGCONF_LOCAL) -package-id dep-1-XXX -package-id dep-public-1-XXX \
|
| 46 | 46 | A.hs lib/B.hs C.hs D.hs E.hs
|
| 47 | 47 | |
| 48 | - cat dep.json | jq --sort-keys |
|
| 48 | + cat dep.json
|
|
| 49 | + |
|
| 50 | +T24384c: T24384_prep
|
|
| 51 | + '$(TEST_HC)' -M -dep-json dep.json \
|
|
| 52 | + -hide-all-packages -package base -package containers -package template-haskell \
|
|
| 53 | + -package-db ./$(PKGCONF_LOCAL) -package-id dep-1-XXX -package-id dep-public-1-XXX \
|
|
| 54 | + A.hs lib/B.hs C.hs D.hs E.hs
|
|
| 55 | + |
|
| 56 | + cat dep.json |
| 1 | 1 | # DO NOT DELETE: Beginning of Haskell dependencies
|
| 2 | -E.o : E.hs
|
|
| 3 | -E.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/Prelude.hi
|
|
| 4 | -E.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/GHC/Essentials.hi
|
|
| 5 | -E.o : dep-public/outdir/DepPublic.hi
|
|
| 6 | -E.o : dep/outdir/Dep.hi
|
|
| 7 | -E.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/template-haskell-2.25.0.0-inplace/Language/Haskell/TH/Syntax.hi
|
|
| 8 | -C.o-boot : C.hs-boot
|
|
| 9 | -C.o : C.hi-boot
|
|
| 10 | -C.o-boot : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/Prelude.hi
|
|
| 11 | -C.o-boot : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/GHC/Essentials.hi
|
|
| 12 | -C.o-boot : E.hi
|
|
| 2 | +A.o : <absolute-path>/Essentials.hi
|
|
| 3 | +A.o : <absolute-path>/Prelude.hi
|
|
| 4 | +A.o : <absolute-path>/ghcversion.h
|
|
| 5 | +A.o : <absolute-path>/stdc-predef.h
|
|
| 13 | 6 | A.o : A.hs
|
| 14 | -A.o : foo.h
|
|
| 15 | -A.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/rts-1.0.3/include/ghcversion.h
|
|
| 16 | -A.o : /usr/include/stdc-predef.h
|
|
| 17 | -A.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/Prelude.hi
|
|
| 18 | -A.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/GHC/Essentials.hi
|
|
| 19 | 7 | A.o : C.hi-boot
|
| 20 | -C.o : C.hs
|
|
| 21 | -C.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/Prelude.hi
|
|
| 22 | -C.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/GHC/Essentials.hi
|
|
| 23 | -C.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/containers-0.8-inplace/Data/Set.hi
|
|
| 8 | +A.o : foo.h
|
|
| 9 | +C.o : <absolute-path>/Essentials.hi
|
|
| 10 | +C.o : <absolute-path>/Prelude.hi
|
|
| 11 | +C.o : <absolute-path>/Set.hi
|
|
| 24 | 12 | C.o : A.hi
|
| 25 | -lib/B.o : lib/B.hs
|
|
| 26 | -lib/B.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/Prelude.hi
|
|
| 27 | -lib/B.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/GHC/Essentials.hi
|
|
| 28 | -lib/B.o : A.hi
|
|
| 29 | -D.o : D.hs
|
|
| 30 | -D.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/Prelude.hi
|
|
| 31 | -D.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/GHC/Essentials.hi
|
|
| 13 | +C.o : C.hi-boot
|
|
| 14 | +C.o : C.hs
|
|
| 15 | +C.o-boot : <absolute-path>/Essentials.hi
|
|
| 16 | +C.o-boot : <absolute-path>/Prelude.hi
|
|
| 17 | +C.o-boot : C.hs-boot
|
|
| 18 | +C.o-boot : E.hi
|
|
| 19 | +D.o : <absolute-path>/Essentials.hi
|
|
| 20 | +D.o : <absolute-path>/Prelude.hi
|
|
| 32 | 21 | D.o : C.hi
|
| 22 | +D.o : D.hs
|
|
| 33 | 23 | D.o : lib/B.hi
|
| 24 | +E.o : <absolute-path>/Essentials.hi
|
|
| 25 | +E.o : <absolute-path>/Prelude.hi
|
|
| 26 | +E.o : <absolute-path>/Syntax.hi
|
|
| 27 | +E.o : E.hs
|
|
| 28 | +E.o : dep-public/outdir/DepPublic.hi
|
|
| 29 | +E.o : dep/outdir/Dep.hi
|
|
| 30 | +lib/B.o : <absolute-path>/Essentials.hi
|
|
| 31 | +lib/B.o : <absolute-path>/Prelude.hi
|
|
| 32 | +lib/B.o : A.hi
|
|
| 33 | +lib/B.o : lib/B.hi-boot
|
|
| 34 | +lib/B.o : lib/B.hs
|
|
| 35 | +lib/B.o-boot : <absolute-path>/Essentials.hi
|
|
| 36 | +lib/B.o-boot : <absolute-path>/Prelude.hi
|
|
| 37 | +lib/B.o-boot : A.hi
|
|
| 38 | +lib/B.o-boot : lib/B.hs-boot
|
|
| 34 | 39 | # DO NOT DELETE: End of Haskell dependencies |
| 1 | 1 | {
|
| 2 | - "A": {
|
|
| 3 | - "cpp": [
|
|
| 4 | - "/home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/rts-1.0.3/include/ghcversion.h",
|
|
| 5 | - "/usr/include/stdc-predef.h",
|
|
| 6 | - "foo.h"
|
|
| 7 | - ],
|
|
| 8 | - "modules": {
|
|
| 9 | - "normal": [],
|
|
| 10 | - "quote": [],
|
|
| 11 | - "splice": []
|
|
| 12 | - },
|
|
| 13 | - "modules-boot": {
|
|
| 14 | - "normal": [
|
|
| 15 | - "C"
|
|
| 16 | - ],
|
|
| 17 | - "quote": [],
|
|
| 18 | - "splice": []
|
|
| 19 | - },
|
|
| 20 | - "options": [
|
|
| 21 | - "-XStrict",
|
|
| 22 | - "-XCPP",
|
|
| 23 | - "-fexpose-all-unfoldings"
|
|
| 24 | - ],
|
|
| 25 | - "packages": [
|
|
| 26 | - {
|
|
| 27 | - "id": "base-4.23.0.0-inplace",
|
|
| 28 | - "modules": {
|
|
| 29 | - "normal": [
|
|
| 30 | - "GHC.Essentials",
|
|
| 31 | - "Prelude"
|
|
| 32 | - ],
|
|
| 33 | - "quote": [],
|
|
| 34 | - "splice": []
|
|
| 35 | - },
|
|
| 36 | - "name": "base",
|
|
| 37 | - "package-id": "base-4.23.0.0"
|
|
| 38 | - }
|
|
| 39 | - ],
|
|
| 40 | - "preprocessor": null,
|
|
| 41 | - "sources": [
|
|
| 42 | - "A.hs"
|
|
| 43 | - ]
|
|
| 2 | + "base-<VERSION>-<HASH>": {
|
|
| 3 | + "package-id": "base-<VERSION>-<HASH>",
|
|
| 4 | + "package-name": "base"
|
|
| 44 | 5 | },
|
| 45 | - "B": {
|
|
| 46 | - "cpp": [],
|
|
| 47 | - "modules": {
|
|
| 48 | - "normal": [
|
|
| 49 | - "A"
|
|
| 50 | - ],
|
|
| 51 | - "quote": [],
|
|
| 52 | - "splice": []
|
|
| 53 | - },
|
|
| 54 | - "modules-boot": {
|
|
| 55 | - "normal": [],
|
|
| 56 | - "quote": [],
|
|
| 57 | - "splice": []
|
|
| 58 | - },
|
|
| 59 | - "options": [
|
|
| 60 | - "-F",
|
|
| 61 | - "-pgmF",
|
|
| 62 | - "./preproc.sh"
|
|
| 63 | - ],
|
|
| 64 | - "packages": [
|
|
| 65 | - {
|
|
| 66 | - "id": "base-4.23.0.0-inplace",
|
|
| 67 | - "modules": {
|
|
| 68 | - "normal": [
|
|
| 69 | - "GHC.Essentials",
|
|
| 70 | - "Prelude"
|
|
| 71 | - ],
|
|
| 72 | - "quote": [],
|
|
| 73 | - "splice": []
|
|
| 74 | - },
|
|
| 75 | - "name": "base",
|
|
| 76 | - "package-id": "base-4.23.0.0"
|
|
| 77 | - }
|
|
| 78 | - ],
|
|
| 79 | - "preprocessor": "./preproc.sh",
|
|
| 80 | - "sources": [
|
|
| 81 | - "lib/B.hs"
|
|
| 82 | - ]
|
|
| 6 | + "containers-<VERSION>-<HASH>": {
|
|
| 7 | + "package-id": "containers-<VERSION>-<HASH>",
|
|
| 8 | + "package-name": "containers"
|
|
| 83 | 9 | },
|
| 84 | - "B[boot]": {
|
|
| 85 | - "cpp": [],
|
|
| 86 | - "modules": {
|
|
| 87 | - "normal": [
|
|
| 88 | - "A"
|
|
| 89 | - ],
|
|
| 90 | - "quote": [],
|
|
| 91 | - "splice": []
|
|
| 92 | - },
|
|
| 93 | - "modules-boot": {
|
|
| 94 | - "normal": [],
|
|
| 95 | - "quote": [],
|
|
| 96 | - "splice": []
|
|
| 97 | - },
|
|
| 98 | - "options": [
|
|
| 99 | - "-F",
|
|
| 100 | - "-pgmF",
|
|
| 101 | - "./preproc.sh"
|
|
| 102 | - ],
|
|
| 103 | - "packages": [
|
|
| 104 | - {
|
|
| 105 | - "id": "base-4.23.0.0-inplace",
|
|
| 106 | - "modules": {
|
|
| 107 | - "normal": [
|
|
| 108 | - "GHC.Essentials",
|
|
| 109 | - "Prelude"
|
|
| 110 | - ],
|
|
| 111 | - "quote": [],
|
|
| 112 | - "splice": []
|
|
| 113 | - },
|
|
| 114 | - "name": "base",
|
|
| 115 | - "package-id": "base-4.23.0.0"
|
|
| 116 | - }
|
|
| 117 | - ],
|
|
| 118 | - "preprocessor": "./preproc.sh",
|
|
| 119 | - "sources": [
|
|
| 120 | - "lib/B.hs-boot"
|
|
| 121 | - ]
|
|
| 10 | + "dep-1-XXX": {
|
|
| 11 | + "package-id": "dep-1",
|
|
| 12 | + "package-name": "dep"
|
|
| 122 | 13 | },
|
| 123 | - "C": {
|
|
| 124 | - "cpp": [],
|
|
| 125 | - "modules": {
|
|
| 126 | - "normal": [
|
|
| 127 | - "A"
|
|
| 128 | - ],
|
|
| 129 | - "quote": [],
|
|
| 130 | - "splice": []
|
|
| 131 | - },
|
|
| 132 | - "modules-boot": {
|
|
| 133 | - "normal": [],
|
|
| 134 | - "quote": [],
|
|
| 135 | - "splice": []
|
|
| 136 | - },
|
|
| 137 | - "options": [],
|
|
| 138 | - "packages": [
|
|
| 139 | - {
|
|
| 140 | - "id": "base-4.23.0.0-inplace",
|
|
| 141 | - "modules": {
|
|
| 142 | - "normal": [
|
|
| 143 | - "GHC.Essentials",
|
|
| 144 | - "Prelude"
|
|
| 145 | - ],
|
|
| 146 | - "quote": [],
|
|
| 147 | - "splice": []
|
|
| 148 | - },
|
|
| 149 | - "name": "base",
|
|
| 150 | - "package-id": "base-4.23.0.0"
|
|
| 151 | - },
|
|
| 152 | - {
|
|
| 153 | - "id": "containers-0.8-inplace",
|
|
| 154 | - "modules": {
|
|
| 155 | - "normal": [
|
|
| 156 | - "Data.Set"
|
|
| 157 | - ],
|
|
| 158 | - "quote": [],
|
|
| 159 | - "splice": []
|
|
| 160 | - },
|
|
| 161 | - "name": "containers",
|
|
| 162 | - "package-id": "containers-0.8"
|
|
| 163 | - }
|
|
| 164 | - ],
|
|
| 165 | - "preprocessor": null,
|
|
| 166 | - "sources": [
|
|
| 167 | - "C.hs"
|
|
| 168 | - ]
|
|
| 14 | + "dep-public-1-XXX": {
|
|
| 15 | + "package-id": "dep-public-1",
|
|
| 16 | + "package-name": "dep-public"
|
|
| 169 | 17 | },
|
| 170 | - "C[boot]": {
|
|
| 171 | - "cpp": [],
|
|
| 18 | + "main": {
|
|
| 172 | 19 | "modules": {
|
| 173 | - "normal": [
|
|
| 174 | - "E"
|
|
| 175 | - ],
|
|
| 176 | - "quote": [],
|
|
| 177 | - "splice": []
|
|
| 178 | - },
|
|
| 179 | - "modules-boot": {
|
|
| 180 | - "normal": [],
|
|
| 181 | - "quote": [],
|
|
| 182 | - "splice": []
|
|
| 183 | - },
|
|
| 184 | - "options": [],
|
|
| 185 | - "packages": [
|
|
| 186 | - {
|
|
| 187 | - "id": "base-4.23.0.0-inplace",
|
|
| 188 | - "modules": {
|
|
| 189 | - "normal": [
|
|
| 190 | - "GHC.Essentials",
|
|
| 191 | - "Prelude"
|
|
| 192 | - ],
|
|
| 193 | - "quote": [],
|
|
| 194 | - "splice": []
|
|
| 195 | - },
|
|
| 196 | - "name": "base",
|
|
| 197 | - "package-id": "base-4.23.0.0"
|
|
| 198 | - }
|
|
| 199 | - ],
|
|
| 200 | - "preprocessor": null,
|
|
| 201 | - "sources": [
|
|
| 202 | - "C.hs-boot"
|
|
| 203 | - ]
|
|
| 204 | - },
|
|
| 205 | - "D": {
|
|
| 206 | - "cpp": [],
|
|
| 207 | - "modules": {
|
|
| 208 | - "normal": [
|
|
| 209 | - "B",
|
|
| 210 | - "C"
|
|
| 211 | - ],
|
|
| 212 | - "quote": [],
|
|
| 213 | - "splice": []
|
|
| 214 | - },
|
|
| 215 | - "modules-boot": {
|
|
| 216 | - "normal": [],
|
|
| 217 | - "quote": [],
|
|
| 218 | - "splice": []
|
|
| 219 | - },
|
|
| 220 | - "options": [],
|
|
| 221 | - "packages": [
|
|
| 222 | - {
|
|
| 223 | - "id": "base-4.23.0.0-inplace",
|
|
| 224 | - "modules": {
|
|
| 225 | - "normal": [
|
|
| 226 | - "GHC.Essentials",
|
|
| 227 | - "Prelude"
|
|
| 228 | - ],
|
|
| 229 | - "quote": [],
|
|
| 230 | - "splice": []
|
|
| 231 | - },
|
|
| 232 | - "name": "base",
|
|
| 233 | - "package-id": "base-4.23.0.0"
|
|
| 234 | - }
|
|
| 235 | - ],
|
|
| 236 | - "preprocessor": null,
|
|
| 237 | - "sources": [
|
|
| 238 | - "D.hs"
|
|
| 239 | - ]
|
|
| 240 | - },
|
|
| 241 | - "E": {
|
|
| 242 | - "cpp": [],
|
|
| 243 | - "modules": {
|
|
| 244 | - "normal": [],
|
|
| 245 | - "quote": [],
|
|
| 246 | - "splice": []
|
|
| 247 | - },
|
|
| 248 | - "modules-boot": {
|
|
| 249 | - "normal": [],
|
|
| 250 | - "quote": [],
|
|
| 251 | - "splice": []
|
|
| 252 | - },
|
|
| 253 | - "options": [],
|
|
| 254 | - "packages": [
|
|
| 255 | - {
|
|
| 256 | - "id": "base-4.23.0.0-inplace",
|
|
| 257 | - "modules": {
|
|
| 258 | - "normal": [
|
|
| 259 | - "GHC.Essentials",
|
|
| 260 | - "Prelude"
|
|
| 261 | - ],
|
|
| 262 | - "quote": [],
|
|
| 263 | - "splice": []
|
|
| 264 | - },
|
|
| 265 | - "name": "base",
|
|
| 266 | - "package-id": "base-4.23.0.0"
|
|
| 20 | + "A": {
|
|
| 21 | + "imports": [
|
|
| 22 | + {
|
|
| 23 | + "base-<VERSION>-<HASH>": [
|
|
| 24 | + "GHC.Essentials",
|
|
| 25 | + "Prelude"
|
|
| 26 | + ]
|
|
| 27 | + },
|
|
| 28 | + {
|
|
| 29 | + "main": [
|
|
| 30 | + "C[boot]"
|
|
| 31 | + ]
|
|
| 32 | + }
|
|
| 33 | + ],
|
|
| 34 | + "includes": [
|
|
| 35 | + "<absolute-path>/ghcversion.h",
|
|
| 36 | + "<absolute-path>/stdc-predef.h",
|
|
| 37 | + "foo.h"
|
|
| 38 | + ],
|
|
| 39 | + "options": [
|
|
| 40 | + "-XStrict",
|
|
| 41 | + "-XCPP",
|
|
| 42 | + "-fexpose-all-unfoldings"
|
|
| 43 | + ],
|
|
| 44 | + "preprocessor": null,
|
|
| 45 | + "source": "A.hs"
|
|
| 267 | 46 | },
|
| 268 | - {
|
|
| 269 | - "id": "dep-1-XXX",
|
|
| 270 | - "modules": {
|
|
| 271 | - "normal": [
|
|
| 272 | - "Dep"
|
|
| 273 | - ],
|
|
| 274 | - "quote": [],
|
|
| 275 | - "splice": []
|
|
| 276 | - },
|
|
| 277 | - "name": "dep",
|
|
| 278 | - "package-id": "dep-1"
|
|
| 47 | + "B": {
|
|
| 48 | + "imports": [
|
|
| 49 | + {
|
|
| 50 | + "base-<VERSION>-<HASH>": [
|
|
| 51 | + "GHC.Essentials",
|
|
| 52 | + "Prelude"
|
|
| 53 | + ]
|
|
| 54 | + },
|
|
| 55 | + {
|
|
| 56 | + "main": [
|
|
| 57 | + "A"
|
|
| 58 | + ]
|
|
| 59 | + }
|
|
| 60 | + ],
|
|
| 61 | + "includes": [],
|
|
| 62 | + "options": [
|
|
| 63 | + "-F",
|
|
| 64 | + "-pgmF",
|
|
| 65 | + "./preproc.sh"
|
|
| 66 | + ],
|
|
| 67 | + "preprocessor": "./preproc.sh",
|
|
| 68 | + "source": "lib/B.hs"
|
|
| 279 | 69 | },
|
| 280 | - {
|
|
| 281 | - "id": "dep-public-1-XXX",
|
|
| 282 | - "modules": {
|
|
| 283 | - "normal": [
|
|
| 284 | - "DepPublic"
|
|
| 285 | - ],
|
|
| 286 | - "quote": [],
|
|
| 287 | - "splice": []
|
|
| 288 | - },
|
|
| 289 | - "name": "dep-public",
|
|
| 290 | - "package-id": "dep-public-1"
|
|
| 70 | + "B[boot]": {
|
|
| 71 | + "imports": [
|
|
| 72 | + {
|
|
| 73 | + "base-<VERSION>-<HASH>": [
|
|
| 74 | + "GHC.Essentials",
|
|
| 75 | + "Prelude"
|
|
| 76 | + ]
|
|
| 77 | + },
|
|
| 78 | + {
|
|
| 79 | + "main": [
|
|
| 80 | + "A"
|
|
| 81 | + ]
|
|
| 82 | + }
|
|
| 83 | + ],
|
|
| 84 | + "includes": [],
|
|
| 85 | + "options": [
|
|
| 86 | + "-F",
|
|
| 87 | + "-pgmF",
|
|
| 88 | + "./preproc.sh"
|
|
| 89 | + ],
|
|
| 90 | + "preprocessor": "./preproc.sh",
|
|
| 91 | + "source": "lib/B.hs-boot"
|
|
| 291 | 92 | },
|
| 292 | - {
|
|
| 293 | - "id": "template-haskell-2.25.0.0-inplace",
|
|
| 294 | - "modules": {
|
|
| 295 | - "normal": [
|
|
| 296 | - "Language.Haskell.TH.Syntax"
|
|
| 297 | - ],
|
|
| 298 | - "quote": [],
|
|
| 299 | - "splice": []
|
|
| 300 | - },
|
|
| 301 | - "name": "template-haskell",
|
|
| 302 | - "package-id": "template-haskell-2.25.0.0"
|
|
| 93 | + "C": {
|
|
| 94 | + "imports": [
|
|
| 95 | + {
|
|
| 96 | + "base-<VERSION>-<HASH>": [
|
|
| 97 | + "GHC.Essentials",
|
|
| 98 | + "Prelude"
|
|
| 99 | + ]
|
|
| 100 | + },
|
|
| 101 | + {
|
|
| 102 | + "containers-<VERSION>-<HASH>": [
|
|
| 103 | + "Data.Set"
|
|
| 104 | + ]
|
|
| 105 | + },
|
|
| 106 | + {
|
|
| 107 | + "main": [
|
|
| 108 | + "A"
|
|
| 109 | + ]
|
|
| 110 | + }
|
|
| 111 | + ],
|
|
| 112 | + "includes": [],
|
|
| 113 | + "options": [],
|
|
| 114 | + "preprocessor": null,
|
|
| 115 | + "source": "C.hs"
|
|
| 116 | + },
|
|
| 117 | + "C[boot]": {
|
|
| 118 | + "imports": [
|
|
| 119 | + {
|
|
| 120 | + "base-<VERSION>-<HASH>": [
|
|
| 121 | + "GHC.Essentials",
|
|
| 122 | + "Prelude"
|
|
| 123 | + ]
|
|
| 124 | + },
|
|
| 125 | + {
|
|
| 126 | + "main": [
|
|
| 127 | + "E"
|
|
| 128 | + ]
|
|
| 129 | + }
|
|
| 130 | + ],
|
|
| 131 | + "includes": [],
|
|
| 132 | + "options": [],
|
|
| 133 | + "preprocessor": null,
|
|
| 134 | + "source": "C.hs-boot"
|
|
| 135 | + },
|
|
| 136 | + "D": {
|
|
| 137 | + "imports": [
|
|
| 138 | + {
|
|
| 139 | + "base-<VERSION>-<HASH>": [
|
|
| 140 | + "GHC.Essentials",
|
|
| 141 | + "Prelude"
|
|
| 142 | + ]
|
|
| 143 | + },
|
|
| 144 | + {
|
|
| 145 | + "main": [
|
|
| 146 | + "B",
|
|
| 147 | + "C"
|
|
| 148 | + ]
|
|
| 149 | + }
|
|
| 150 | + ],
|
|
| 151 | + "includes": [],
|
|
| 152 | + "options": [],
|
|
| 153 | + "preprocessor": null,
|
|
| 154 | + "source": "D.hs"
|
|
| 155 | + },
|
|
| 156 | + "E": {
|
|
| 157 | + "imports": [
|
|
| 158 | + {
|
|
| 159 | + "base-<VERSION>-<HASH>": [
|
|
| 160 | + "GHC.Essentials",
|
|
| 161 | + "Prelude"
|
|
| 162 | + ]
|
|
| 163 | + },
|
|
| 164 | + {
|
|
| 165 | + "dep-1-XXX": [
|
|
| 166 | + "Dep"
|
|
| 167 | + ]
|
|
| 168 | + },
|
|
| 169 | + {
|
|
| 170 | + "dep-public-1-XXX": [
|
|
| 171 | + "DepPublic"
|
|
| 172 | + ]
|
|
| 173 | + },
|
|
| 174 | + {
|
|
| 175 | + "template-haskell-<VERSION>-<HASH>": [
|
|
| 176 | + "Language.Haskell.TH.Syntax"
|
|
| 177 | + ]
|
|
| 178 | + }
|
|
| 179 | + ],
|
|
| 180 | + "includes": [],
|
|
| 181 | + "options": [],
|
|
| 182 | + "preprocessor": null,
|
|
| 183 | + "source": "E.hs"
|
|
| 303 | 184 | }
|
| 304 | - ],
|
|
| 305 | - "preprocessor": null,
|
|
| 306 | - "sources": [
|
|
| 307 | - "E.hs"
|
|
| 308 | - ]
|
|
| 185 | + }
|
|
| 186 | + },
|
|
| 187 | + "template-haskell-<VERSION>-<HASH>": {
|
|
| 188 | + "package-id": "template-haskell-<VERSION>-<HASH>",
|
|
| 189 | + "package-name": "template-haskell"
|
|
| 309 | 190 | }
|
| 310 | 191 | } |
| 1 | +{
|
|
| 2 | + "base-<VERSION>-<HASH>": {
|
|
| 3 | + "package-id": "base-<VERSION>-<HASH>",
|
|
| 4 | + "package-name": "base"
|
|
| 5 | + },
|
|
| 6 | + "containers-<VERSION>-<HASH>": {
|
|
| 7 | + "package-id": "containers-<VERSION>-<HASH>",
|
|
| 8 | + "package-name": "containers"
|
|
| 9 | + },
|
|
| 10 | + "dep-1-XXX": {
|
|
| 11 | + "package-id": "dep-1",
|
|
| 12 | + "package-name": "dep"
|
|
| 13 | + },
|
|
| 14 | + "dep-public-1-XXX": {
|
|
| 15 | + "package-id": "dep-public-1",
|
|
| 16 | + "package-name": "dep-public"
|
|
| 17 | + },
|
|
| 18 | + "main": {
|
|
| 19 | + "modules": {
|
|
| 20 | + "A": {
|
|
| 21 | + "imports": [
|
|
| 22 | + {
|
|
| 23 | + "base-<VERSION>-<HASH>": [
|
|
| 24 | + "GHC.Essentials",
|
|
| 25 | + "Prelude"
|
|
| 26 | + ]
|
|
| 27 | + },
|
|
| 28 | + {
|
|
| 29 | + "main": [
|
|
| 30 | + "C[boot]"
|
|
| 31 | + ]
|
|
| 32 | + }
|
|
| 33 | + ],
|
|
| 34 | + "includes": [
|
|
| 35 | + "<absolute-path>/ghcversion.h",
|
|
| 36 | + "<absolute-path>/stdc-predef.h",
|
|
| 37 | + "foo.h"
|
|
| 38 | + ],
|
|
| 39 | + "options": [
|
|
| 40 | + "-XStrict",
|
|
| 41 | + "-XCPP",
|
|
| 42 | + "-fexpose-all-unfoldings"
|
|
| 43 | + ],
|
|
| 44 | + "preprocessor": null,
|
|
| 45 | + "source": "A.hs"
|
|
| 46 | + },
|
|
| 47 | + "B": {
|
|
| 48 | + "imports": [
|
|
| 49 | + {
|
|
| 50 | + "base-<VERSION>-<HASH>": [
|
|
| 51 | + "GHC.Essentials",
|
|
| 52 | + "Prelude"
|
|
| 53 | + ]
|
|
| 54 | + },
|
|
| 55 | + {
|
|
| 56 | + "main": [
|
|
| 57 | + "A"
|
|
| 58 | + ]
|
|
| 59 | + }
|
|
| 60 | + ],
|
|
| 61 | + "includes": [],
|
|
| 62 | + "options": [
|
|
| 63 | + "-F",
|
|
| 64 | + "-pgmF",
|
|
| 65 | + "./preproc.sh"
|
|
| 66 | + ],
|
|
| 67 | + "preprocessor": "./preproc.sh",
|
|
| 68 | + "source": "lib/B.hs"
|
|
| 69 | + },
|
|
| 70 | + "B[boot]": {
|
|
| 71 | + "imports": [
|
|
| 72 | + {
|
|
| 73 | + "base-<VERSION>-<HASH>": [
|
|
| 74 | + "GHC.Essentials",
|
|
| 75 | + "Prelude"
|
|
| 76 | + ]
|
|
| 77 | + },
|
|
| 78 | + {
|
|
| 79 | + "main": [
|
|
| 80 | + "A"
|
|
| 81 | + ]
|
|
| 82 | + }
|
|
| 83 | + ],
|
|
| 84 | + "includes": [],
|
|
| 85 | + "options": [
|
|
| 86 | + "-F",
|
|
| 87 | + "-pgmF",
|
|
| 88 | + "./preproc.sh"
|
|
| 89 | + ],
|
|
| 90 | + "preprocessor": "./preproc.sh",
|
|
| 91 | + "source": "lib/B.hs-boot"
|
|
| 92 | + },
|
|
| 93 | + "C": {
|
|
| 94 | + "imports": [
|
|
| 95 | + {
|
|
| 96 | + "base-<VERSION>-<HASH>": [
|
|
| 97 | + "GHC.Essentials",
|
|
| 98 | + "Prelude"
|
|
| 99 | + ]
|
|
| 100 | + },
|
|
| 101 | + {
|
|
| 102 | + "containers-<VERSION>-<HASH>": [
|
|
| 103 | + "Data.Set"
|
|
| 104 | + ]
|
|
| 105 | + },
|
|
| 106 | + {
|
|
| 107 | + "main": [
|
|
| 108 | + "A"
|
|
| 109 | + ]
|
|
| 110 | + }
|
|
| 111 | + ],
|
|
| 112 | + "includes": [],
|
|
| 113 | + "options": [],
|
|
| 114 | + "preprocessor": null,
|
|
| 115 | + "source": "C.hs"
|
|
| 116 | + },
|
|
| 117 | + "C[boot]": {
|
|
| 118 | + "imports": [
|
|
| 119 | + {
|
|
| 120 | + "base-<VERSION>-<HASH>": [
|
|
| 121 | + "GHC.Essentials",
|
|
| 122 | + "Prelude"
|
|
| 123 | + ]
|
|
| 124 | + },
|
|
| 125 | + {
|
|
| 126 | + "main": [
|
|
| 127 | + "E"
|
|
| 128 | + ]
|
|
| 129 | + }
|
|
| 130 | + ],
|
|
| 131 | + "includes": [],
|
|
| 132 | + "options": [],
|
|
| 133 | + "preprocessor": null,
|
|
| 134 | + "source": "C.hs-boot"
|
|
| 135 | + },
|
|
| 136 | + "D": {
|
|
| 137 | + "imports": [
|
|
| 138 | + {
|
|
| 139 | + "base-<VERSION>-<HASH>": [
|
|
| 140 | + "GHC.Essentials",
|
|
| 141 | + "Prelude"
|
|
| 142 | + ]
|
|
| 143 | + },
|
|
| 144 | + {
|
|
| 145 | + "main": [
|
|
| 146 | + "B",
|
|
| 147 | + "C"
|
|
| 148 | + ]
|
|
| 149 | + }
|
|
| 150 | + ],
|
|
| 151 | + "includes": [],
|
|
| 152 | + "options": [],
|
|
| 153 | + "preprocessor": null,
|
|
| 154 | + "source": "D.hs"
|
|
| 155 | + },
|
|
| 156 | + "E": {
|
|
| 157 | + "imports": [
|
|
| 158 | + {
|
|
| 159 | + "base-<VERSION>-<HASH>": [
|
|
| 160 | + "GHC.Essentials",
|
|
| 161 | + "Prelude"
|
|
| 162 | + ]
|
|
| 163 | + },
|
|
| 164 | + {
|
|
| 165 | + "dep-1-XXX": [
|
|
| 166 | + "Dep"
|
|
| 167 | + ]
|
|
| 168 | + },
|
|
| 169 | + {
|
|
| 170 | + "dep-public-1-XXX": [
|
|
| 171 | + "DepPublic"
|
|
| 172 | + ]
|
|
| 173 | + },
|
|
| 174 | + {
|
|
| 175 | + "template-haskell-<VERSION>-<HASH>": [
|
|
| 176 | + "Language.Haskell.TH.Syntax"
|
|
| 177 | + ]
|
|
| 178 | + }
|
|
| 179 | + ],
|
|
| 180 | + "includes": [],
|
|
| 181 | + "options": [],
|
|
| 182 | + "preprocessor": null,
|
|
| 183 | + "source": "E.hs"
|
|
| 184 | + }
|
|
| 185 | + }
|
|
| 186 | + },
|
|
| 187 | + "template-haskell-<VERSION>-<HASH>": {
|
|
| 188 | + "package-id": "template-haskell-<VERSION>-<HASH>",
|
|
| 189 | + "package-name": "template-haskell"
|
|
| 190 | + }
|
|
| 191 | +} |
| 1 | +{
|
|
| 2 | + "main": {
|
|
| 3 | + "modules": {
|
|
| 4 | + "A": {
|
|
| 5 | + "imports": [
|
|
| 6 | + {
|
|
| 7 | + "main": [
|
|
| 8 | + "C[boot]"
|
|
| 9 | + ]
|
|
| 10 | + }
|
|
| 11 | + ],
|
|
| 12 | + "includes": [],
|
|
| 13 | + "options": [
|
|
| 14 | + "-XStrict",
|
|
| 15 | + "-XCPP",
|
|
| 16 | + "-fexpose-all-unfoldings"
|
|
| 17 | + ],
|
|
| 18 | + "preprocessor": null,
|
|
| 19 | + "source": "A.hs"
|
|
| 20 | + },
|
|
| 21 | + "B": {
|
|
| 22 | + "imports": [
|
|
| 23 | + {
|
|
| 24 | + "main": [
|
|
| 25 | + "A"
|
|
| 26 | + ]
|
|
| 27 | + }
|
|
| 28 | + ],
|
|
| 29 | + "includes": [],
|
|
| 30 | + "options": [
|
|
| 31 | + "-F",
|
|
| 32 | + "-pgmF",
|
|
| 33 | + "./preproc.sh"
|
|
| 34 | + ],
|
|
| 35 | + "preprocessor": "./preproc.sh",
|
|
| 36 | + "source": "lib/B.hs"
|
|
| 37 | + },
|
|
| 38 | + "B[boot]": {
|
|
| 39 | + "imports": [
|
|
| 40 | + {
|
|
| 41 | + "main": [
|
|
| 42 | + "A"
|
|
| 43 | + ]
|
|
| 44 | + }
|
|
| 45 | + ],
|
|
| 46 | + "includes": [],
|
|
| 47 | + "options": [
|
|
| 48 | + "-F",
|
|
| 49 | + "-pgmF",
|
|
| 50 | + "./preproc.sh"
|
|
| 51 | + ],
|
|
| 52 | + "preprocessor": "./preproc.sh",
|
|
| 53 | + "source": "lib/B.hs-boot"
|
|
| 54 | + },
|
|
| 55 | + "C": {
|
|
| 56 | + "imports": [
|
|
| 57 | + {
|
|
| 58 | + "main": [
|
|
| 59 | + "A"
|
|
| 60 | + ]
|
|
| 61 | + }
|
|
| 62 | + ],
|
|
| 63 | + "includes": [],
|
|
| 64 | + "options": [],
|
|
| 65 | + "preprocessor": null,
|
|
| 66 | + "source": "C.hs"
|
|
| 67 | + },
|
|
| 68 | + "C[boot]": {
|
|
| 69 | + "imports": [
|
|
| 70 | + {
|
|
| 71 | + "main": [
|
|
| 72 | + "E"
|
|
| 73 | + ]
|
|
| 74 | + }
|
|
| 75 | + ],
|
|
| 76 | + "includes": [],
|
|
| 77 | + "options": [],
|
|
| 78 | + "preprocessor": null,
|
|
| 79 | + "source": "C.hs-boot"
|
|
| 80 | + },
|
|
| 81 | + "D": {
|
|
| 82 | + "imports": [
|
|
| 83 | + {
|
|
| 84 | + "main": [
|
|
| 85 | + "B",
|
|
| 86 | + "C"
|
|
| 87 | + ]
|
|
| 88 | + }
|
|
| 89 | + ],
|
|
| 90 | + "includes": [],
|
|
| 91 | + "options": [],
|
|
| 92 | + "preprocessor": null,
|
|
| 93 | + "source": "D.hs"
|
|
| 94 | + },
|
|
| 95 | + "E": {
|
|
| 96 | + "imports": [],
|
|
| 97 | + "includes": [],
|
|
| 98 | + "options": [],
|
|
| 99 | + "preprocessor": null,
|
|
| 100 | + "source": "E.hs"
|
|
| 101 | + }
|
|
| 102 | + }
|
|
| 103 | + }
|
|
| 104 | +} |
| 1 | + |
|
| 2 | +json_normalisers = [ normalise_version('base', 'containers', 'template-haskell')
|
|
| 3 | + , normalise_slashes
|
|
| 4 | + , normalise_fun(normalise_dep_json)
|
|
| 5 | + ]
|
|
| 6 | + |
|
| 7 | +makefile_normalisers = [ normalise_slashes, normalise_fun(normalise_dep_makefile) ]
|
|
| 8 | + |
|
| 1 | 9 | test_extras = extra_files(
|
| 2 | 10 | ['A.hs', 'lib/', 'C.hs', 'C.hs-boot', 'D.hs', 'E.hs',
|
| 3 | 11 | 'foo.h',
|
| ... | ... | @@ -5,7 +13,8 @@ test_extras = extra_files( |
| 5 | 13 | 'preproc.sh'
|
| 6 | 14 | ])
|
| 7 | 15 | |
| 8 | -normalisers = normalise_version('base', 'containers', 'template-haskell')
|
|
| 16 | +skip_on_mingw = when(opsys('mingw32'), skip)
|
|
| 9 | 17 | |
| 10 | -test('T24384a', [ test_extras, normalisers, pre_cmd('$MAKE -s --no-print-directory T24384_prep') ], makefile_test, [])
|
|
| 11 | -test('T24384b', [ test_extras, normalisers, pre_cmd('$MAKE -s --no-print-directory T24384_prep') ], makefile_test, []) |
|
| 18 | +test('T24384a', [ test_extras, pre_cmd('$MAKE -s --no-print-directory T24384_prep'), *makefile_normalisers ], makefile_test, [])
|
|
| 19 | +test('T24384b', [ test_extras, pre_cmd('$MAKE -s --no-print-directory T24384_prep'), skip_on_mingw, *json_normalisers ], makefile_test, [])
|
|
| 20 | +test('T24384c', [ test_extras, pre_cmd('$MAKE -s --no-print-directory T24384_prep'), skip_on_mingw, *json_normalisers ], makefile_test, []) |
| 1 | +#! /usr/bin/env bash
|
|
| 2 | +set -euo pipefail
|
|
| 3 | + |
|
| 4 | +# Packages whose ids are rewritten to <pkg>-<VERSION>-<HASH>
|
|
| 5 | +pkgs='base|containers|template-haskell'
|
|
| 6 | + |
|
| 7 | +usage() {
|
|
| 8 | + cat <<EOF
|
|
| 9 | +Usage: $(basename "$0") FILE
|
|
| 10 | + |
|
| 11 | +Format one of the test -dep-json output file with jq and normalise it:
|
|
| 12 | + - absolute paths in "includes" become <absolute-path>/<filename>,
|
|
| 13 | + and the "includes" lists are sorted
|
|
| 14 | + - ids of the packages ${packages[*]}
|
|
| 15 | + (e.g. base-4.23.0.0-inplace) become <pkg>-<VERSION>-<HASH>
|
|
| 16 | + |
|
| 17 | +Writes the output to FILE
|
|
| 18 | +EOF
|
|
| 19 | +}
|
|
| 20 | + |
|
| 21 | +case "${1:-}" in -h|--help) usage; exit 0 ;; esac
|
|
| 22 | +[ $# -eq 1 ] || { usage >&2; exit 1; }
|
|
| 23 | + |
|
| 24 | +# Escape regex metacharacters (and the / delimiter) for sed
|
|
| 25 | +esc() { sed 's/[][\.*^$+?(){}|/]/\\&/g'; }
|
|
| 26 | + |
|
| 27 | +json=$(jq --sort-keys '
|
|
| 28 | + (.. | objects | select(has("includes")) | .includes) |=
|
|
| 29 | + (map(if startswith("/") then "<absolute-path>/" + (split("/") | last) else . end) | sort)
|
|
| 30 | +' "$1")
|
|
| 31 | + |
|
| 32 | +tmp=$(mktemp "$1.XXXXXX")
|
|
| 33 | +trap 'rm -f "$tmp"' EXIT
|
|
| 34 | +sed -E "s/($pkgs)-[0-9.]+(-[0-9a-zA-Z+]+)?(-[0-9a-zA-Z]+)?/\\1-<VERSION>-<HASH>/g" <<<"$json" > "$tmp"
|
|
| 35 | +mv "$tmp" "$1" |
| 1 | +#! /usr/bin/env bash
|
|
| 2 | +set -euo pipefail
|
|
| 3 | + |
|
| 4 | +usage() {
|
|
| 5 | + cat <<EOF
|
|
| 6 | +Usage: $(basename "$0") FILE
|
|
| 7 | + |
|
| 8 | +Normalise a Makefile written by 'ghc -M':
|
|
| 9 | + - absolute dependency paths become <absolute-path>/<filename>
|
|
| 10 | + - each block of "target : dependency" rules is sorted
|
|
| 11 | + |
|
| 12 | +Writes the output to FILE
|
|
| 13 | +EOF
|
|
| 14 | +}
|
|
| 15 | + |
|
| 16 | +case "${1:-}" in -h|--help) usage; exit 0 ;; esac
|
|
| 17 | +[ $# -eq 1 ] || { usage >&2; exit 1; }
|
|
| 18 | + |
|
| 19 | +tmp=$(mktemp "$1.XXXXXX")
|
|
| 20 | +trap 'rm -f "$tmp"' EXIT
|
|
| 21 | + |
|
| 22 | +sed -E 's#^(.* : )/.*/#\1<absolute-path>/#' "$1" |
|
|
| 23 | + awk '
|
|
| 24 | + / : / { print | "LC_ALL=C sort"; next }
|
|
| 25 | + { close("LC_ALL=C sort"); print; fflush() }
|
|
| 26 | + END { close("LC_ALL=C sort") }
|
|
| 27 | + ' > "$tmp"
|
|
| 28 | +mv "$tmp" "$1" |