ghc-tags 1.0 → 1.1
raw patch · 6 files changed
+302/−62 lines, 6 filesdep ~base
Dependency ranges changed: base
Files
- CHANGELOG.md +6/−0
- README.md +1/−0
- ghc-tags.cabal +5/−4
- src/GhcTags/Config/Args.hs +1/−1
- src/GhcTags/GhcCompat.hs +288/−0
- src/Main.hs +1/−57
CHANGELOG.md view
@@ -1,2 +1,8 @@+# ghc-tags-1.1 (2021-05-18)+* Fix compatibility with GHC 8.10.+* Drop support for GHC 8.8.+* Make output flag `ctags` compatible.+* Increase allocation area to 4MB for better performance.+ # ghc-tags-1.0 (2021-05-17) * Initial release.
README.md view
@@ -1,6 +1,7 @@ # ghc-tags [](https://github.com/arybczak/ghc-tags/actions?query=branch%3Amaster)+[](https://hackage.haskell.org/package/ghc-tags) A command line tool that generates etags (Emacs) and ctags (Vim and other editors) for efficient code navigation (jump to definition).
ghc-tags.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: ghc-tags-version: 1.0+version: 1.1 synopsis: Utility for generating ctags and etags with GHC API. description: Utility for generating etags (Emacs) and ctags (Vim and other editors) with GHC API for efficient project navigation.@@ -14,7 +14,7 @@ README.md homepage: https://github.com/arybczak/ghc-tags bug-reports: https://github.com/arybczak/ghc-tags/issues-tested-with: GHC ==8.8.4 || ==8.10.4 || ==9.0.1+tested-with: GHC ==8.10.4 || ==9.0.1 source-repository head type: git@@ -26,14 +26,14 @@ description: Use ghc-lib even when compiling with compatible GHC version. executable ghc-tags- ghc-options: -Wall -threaded -rtsopts+ ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-A4m if !flag(ghc-lib) && impl(ghc == 9.0.*) build-depends: ghc, ghc-boot else build-depends: ghc-lib == 9.0.* - build-depends: base >=4.13 && <5+ build-depends: base >=4.14 && <5 , aeson , async , attoparsec@@ -61,6 +61,7 @@ GhcTags.Config.Args GhcTags.Config.Project GhcTags.Ghc+ GhcTags.GhcCompat GhcTags.Tag GhcTags.CTag GhcTags.CTag.Header
src/GhcTags/Config/Args.hs view
@@ -51,7 +51,7 @@ <> help "Generate etags" tagFile :: Parser FilePath- tagFile = strOption $ long "output"+ tagFile = strOption $ short 'f' <> short 'o' <> metavar "FILE" <> help "Output file"
+ src/GhcTags/GhcCompat.hs view
@@ -0,0 +1,288 @@+{-# OPTIONS_GHC -Wno-missing-fields #-}+module GhcTags.GhcCompat+ ( runGhc+ , parseModule+ ) where++import Data.IORef+import GHC.Data.FastString+import GHC.Data.StringBuffer+import GHC.Driver.Main+import GHC.Driver.Monad+import GHC.Driver.Session+import GHC.Hs+import GHC.Parser.Lexer+import GHC.Paths+import GHC.Platform+import GHC.Settings+import GHC.Settings.Config+import GHC.Settings.Platform+import GHC.Settings.Utils+import GHC.SysTools+import GHC.SysTools.BaseDir+import GHC.Types.SrcLoc+import GHC.Unit.Module.Env+import GHC.Utils.Fingerprint+import System.Directory+import System.FilePath+import qualified Data.Map.Strict as Map+import qualified Data.Set as Set+import qualified GHC+import qualified GHC.Parser as Parser++parseModule+ :: FilePath+ -> DynFlags+ -> StringBuffer+ -> ParseResult (Located HsModule)+parseModule filename flags buffer = unP Parser.parseModule parseState+ where+ location = mkRealSrcLoc (mkFastString filename) 1 1+ parseState = mkPState flags buffer location++runGhc :: Ghc a -> IO a+runGhc m = do+ env <- liftIO $ do+ mySettings <- compatInitSettings libdir+ myLlvmConfig <- lazyInitLlvmConfig libdir+ dflags <- threadSafeInitDynFlags (defaultDynFlags mySettings myLlvmConfig)+ newHscEnv dflags+ ref <- newIORef env+ unGhc (GHC.withCleanupSession m) (Session ref)++----------------------------------------+-- Internal++-- | Adjusted version of 'GHC.Driver.Session.initDynFlags' that doesn't check+-- for colors as it's not thread safe.+threadSafeInitDynFlags :: DynFlags -> IO DynFlags+threadSafeInitDynFlags dflags = do+ let -- We can't build with dynamic-too on Windows, as labels before the+ -- fork point are different depending on whether we are building+ -- dynamically or not.+ platformCanGenerateDynamicToo+ = platformOS (targetPlatform dflags) /= OSMinGW32+ refCanGenerateDynamicToo <- newIORef platformCanGenerateDynamicToo+ refNextTempSuffix <- newIORef 0+ refFilesToClean <- newIORef emptyFilesToClean+ refDirsToClean <- newIORef Map.empty+ refGeneratedDumps <- newIORef Set.empty+ refRtldInfo <- newIORef Nothing+ refRtccInfo <- newIORef Nothing+ wrapperNum <- newIORef emptyModuleEnv+ pure dflags+ { canGenerateDynamicToo = refCanGenerateDynamicToo+ , nextTempSuffix = refNextTempSuffix+ , filesToClean = refFilesToClean+ , dirsToClean = refDirsToClean+ , generatedDumps = refGeneratedDumps+ , nextWrapperNum = wrapperNum+ , rtldInfo = refRtldInfo+ , rtccInfo = refRtccInfo+ }++-- | Stripped version of 'GHC.Settings.IO.initSettings' that ignores the+-- @platformConstants@ file as it's irrelevant for parsing.+compatInitSettings :: FilePath -> IO Settings+compatInitSettings top_dir = do+ -- see Note [topdir: How GHC finds its files]+ -- NB: top_dir is assumed to be in standard Unix+ -- format, '/' separated+ mtool_dir <- findToolDir top_dir+ -- see Note [tooldir: How GHC finds mingw on Windows]++ let installed :: FilePath -> FilePath+ installed file = top_dir </> file+ libexec :: FilePath -> FilePath+ libexec file = top_dir </> "bin" </> file+ settingsFile = installed "settings"++ readFileSafe :: FilePath -> IO String+ readFileSafe path = doesFileExist path >>= \case+ True -> readFile path+ False -> error $ "Missing file: " ++ path++ settingsStr <- readFileSafe settingsFile+ settingsList <- case maybeReadFuzzy settingsStr of+ Just s -> pure s+ Nothing -> error $ "Can't parse " ++ show settingsFile+ let mySettings = Map.fromList settingsList+ -- See Note [Settings file] for a little more about this file. We're+ -- just partially applying those functions and throwing 'Left's; they're+ -- written in a very portable style to keep ghc-boot light.+ let getSetting key = either error pure $+ getFilePathSetting0 top_dir settingsFile mySettings key+ getToolSetting :: String -> IO String+ getToolSetting key = expandToolDir mtool_dir <$> getSetting key+ getBooleanSetting :: String -> IO Bool+ getBooleanSetting key = either error pure $+ getBooleanSetting0 settingsFile mySettings key+ myExtraGccViaCFlags <- getSetting "GCC extra via C opts"+ -- On Windows, mingw is distributed with GHC,+ -- so we look in TopDir/../mingw/bin,+ -- as well as TopDir/../../mingw/bin for hadrian.+ -- It would perhaps be nice to be able to override this+ -- with the settings file, but it would be a little fiddly+ -- to make that possible, so for now you can't.+ cc_prog <- getToolSetting "C compiler command"+ cc_args_str <- getSetting "C compiler flags"+ cxx_args_str <- getSetting "C++ compiler flags"+ gccSupportsNoPie <- getBooleanSetting "C compiler supports -no-pie"+ cpp_prog <- getToolSetting "Haskell CPP command"+ cpp_args_str <- getSetting "Haskell CPP flags"++ platform <- either error pure $ compatGetTargetPlatform settingsFile mySettings++ let unreg_cc_args = if platformUnregisterised platform+ then ["-DNO_REGS", "-DUSE_MINIINTERPRETER"]+ else []+ cpp_args = map Option (words cpp_args_str)+ cc_args = words cc_args_str ++ unreg_cc_args+ cxx_args = words cxx_args_str+ ldSupportsCompactUnwind <- getBooleanSetting "ld supports compact unwind"+ ldSupportsBuildId <- getBooleanSetting "ld supports build-id"+ ldSupportsFilelist <- getBooleanSetting "ld supports filelist"+ ldIsGnuLd <- getBooleanSetting "ld is GNU ld"++ let globalpkgdb_path = installed "package.conf.d"+ ghc_usage_msg_path = installed "ghc-usage.txt"+ ghci_usage_msg_path = installed "ghci-usage.txt"++ -- For all systems, unlit, split, mangle are GHC utilities+ -- architecture-specific stuff is done when building Config.hs+ unlit_path <- getToolSetting "unlit command"++ windres_path <- getToolSetting "windres command"+ libtool_path <- getToolSetting "libtool command"+ ar_path <- getToolSetting "ar command"+ otool_path <- getToolSetting "otool command"+ install_name_tool_path <- getToolSetting "install_name_tool command"+ ranlib_path <- getToolSetting "ranlib command"++ -- TODO this side-effect doesn't belong here. Reading and parsing the settings+ -- should be idempotent and accumulate no resources.+ tmpdir <- liftIO $ getTemporaryDirectory++ touch_path <- getToolSetting "touch command"++ mkdll_prog <- getToolSetting "dllwrap command"+ let mkdll_args = []++ -- cpp is derived from gcc on all platforms+ -- HACK, see setPgmP below. We keep 'words' here to remember to fix+ -- Config.hs one day.+++ -- Other things being equal, as and ld are simply gcc+ cc_link_args_str <- getSetting "C compiler link flags"+ let as_prog = cc_prog+ as_args = map Option cc_args+ ld_prog = cc_prog+ ld_args = map Option (cc_args ++ words cc_link_args_str)+ ld_r_prog <- getToolSetting "Merge objects command"+ ld_r_args <- getSetting "Merge objects flags"++ -- We just assume on command line+ lc_prog <- getSetting "LLVM llc command"+ lo_prog <- getSetting "LLVM opt command"+ lcc_prog <- getSetting "LLVM clang command"++ let iserv_prog = libexec "ghc-iserv"++ return $ Settings+ { sGhcNameVersion = GhcNameVersion+ { ghcNameVersion_programName = "ghc"+ , ghcNameVersion_projectVersion = cProjectVersion+ }++ , sFileSettings = FileSettings+ { fileSettings_tmpDir = normalise tmpdir+ , fileSettings_ghcUsagePath = ghc_usage_msg_path+ , fileSettings_ghciUsagePath = ghci_usage_msg_path+ , fileSettings_toolDir = mtool_dir+ , fileSettings_topDir = top_dir+ , fileSettings_globalPackageDatabase = globalpkgdb_path+ }++ , sToolSettings = ToolSettings+ { toolSettings_ldSupportsCompactUnwind = ldSupportsCompactUnwind+ , toolSettings_ldSupportsBuildId = ldSupportsBuildId+ , toolSettings_ldSupportsFilelist = ldSupportsFilelist+ , toolSettings_ldIsGnuLd = ldIsGnuLd+ , toolSettings_ccSupportsNoPie = gccSupportsNoPie++ , toolSettings_pgm_L = unlit_path+ , toolSettings_pgm_P = (cpp_prog, cpp_args)+ , toolSettings_pgm_F = ""+ , toolSettings_pgm_c = cc_prog+ , toolSettings_pgm_a = (as_prog, as_args)+ , toolSettings_pgm_l = (ld_prog, ld_args)+ , toolSettings_pgm_lm = (ld_r_prog, map Option $ words ld_r_args)+ , toolSettings_pgm_dll = (mkdll_prog,mkdll_args)+ , toolSettings_pgm_T = touch_path+ , toolSettings_pgm_windres = windres_path+ , toolSettings_pgm_libtool = libtool_path+ , toolSettings_pgm_ar = ar_path+ , toolSettings_pgm_otool = otool_path+ , toolSettings_pgm_install_name_tool = install_name_tool_path+ , toolSettings_pgm_ranlib = ranlib_path+ , toolSettings_pgm_lo = (lo_prog,[])+ , toolSettings_pgm_lc = (lc_prog,[])+ , toolSettings_pgm_lcc = (lcc_prog,[])+ , toolSettings_pgm_i = iserv_prog+ , toolSettings_opt_L = []+ , toolSettings_opt_P = []+ , toolSettings_opt_P_fingerprint = fingerprint0+ , toolSettings_opt_F = []+ , toolSettings_opt_c = cc_args+ , toolSettings_opt_cxx = cxx_args+ , toolSettings_opt_a = []+ , toolSettings_opt_l = []+ , toolSettings_opt_lm = []+ , toolSettings_opt_windres = []+ , toolSettings_opt_lcc = []+ , toolSettings_opt_lo = []+ , toolSettings_opt_lc = []+ , toolSettings_opt_i = []++ , toolSettings_extraGccViaCFlags = words myExtraGccViaCFlags+ }++ , sTargetPlatform = platform++ -- Lots of uninitialized fields here.+ , sPlatformMisc = PlatformMisc {}+ , sPlatformConstants = PlatformConstants { pc_DYNAMIC_BY_DEFAULT = False }++ , sRawSettings = settingsList+ }++-- Stripped version of 'GHC.Settings.Platform.getTargetPlatform'. Arch info is+-- needed for CPP defines, the rest is irrelevant.+compatGetTargetPlatform+ :: FilePath -> RawSettings -> Either String Platform+compatGetTargetPlatform settingsFile mySettings = do+ let+ readSetting :: (Show a, Read a) => String -> Either String a+ readSetting = readSetting0 settingsFile mySettings++ targetArch <- readSetting "target arch"+ targetOS <- readSetting "target os"+ targetWordSize <- readSetting "target word size"++ pure $ Platform+ { platformMini = PlatformMini+ { platformMini_arch = targetArch+ , platformMini_os = targetOS+ }+ , platformWordSize = targetWordSize+ -- below is irrelevant+ , platformByteOrder = LittleEndian+ , platformUnregisterised = True+ , platformHasGnuNonexecStack = False+ , platformHasIdentDirective = False+ , platformHasSubsectionsViaSymbols = False+ , platformIsCrossCompiling = False+ , platformLeadingUnderscore = False+ , platformTablesNextToCode = False+ }
src/Main.hs view
@@ -9,26 +9,19 @@ import Data.Bifunctor import Data.Char import Data.Function-import Data.IORef import Data.List import Data.Maybe (mapMaybe) import Data.Time import Data.Time.Format.ISO8601 import GHC.Conc (getNumProcessors) import GHC.Data.Bag-import GHC.Data.FastString import GHC.Data.StringBuffer-import GHC.Driver.Main import GHC.Driver.Monad import GHC.Driver.Session import GHC.Driver.Types (HscEnv(..)) import GHC.Hs import GHC.Parser.Lexer-import GHC.Paths-import GHC.Platform-import GHC.SysTools import GHC.Types.SrcLoc-import GHC.Unit.Module.Env import GHC.Utils.Error import System.Directory import System.Environment@@ -42,20 +35,19 @@ import qualified Data.ByteString.Char8 as BS import qualified Data.Foldable as F import qualified Data.Map.Strict as Map-import qualified Data.Set as Set import qualified Data.Text as T import qualified Data.Text.Encoding as T import qualified Data.Text.IO as T import qualified Data.Vector as V import qualified GHC import qualified GHC.Driver.Pipeline as DP-import qualified GHC.Parser as Parser import qualified GHC.Utils.Outputable as Out import GhcTags import GhcTags.Config.Args import GhcTags.Config.Project import GhcTags.CTag.Header+import GhcTags.GhcCompat import qualified GhcTags.CTag as CTag import qualified GhcTags.ETag as ETag @@ -392,51 +384,3 @@ headers = if null tHeaders then defaultHeaders else tHeaders--------------------------------------------runGhc :: Ghc a -> IO a-runGhc m = do- env <- liftIO $ do- mySettings <- initSysTools libdir- myLlvmConfig <- lazyInitLlvmConfig libdir- dflags <- threadSafeInitDynFlags (defaultDynFlags mySettings myLlvmConfig)- newHscEnv dflags- ref <- newIORef env- unGhc (GHC.withCleanupSession m) (Session ref)- where- threadSafeInitDynFlags dflags = do- let -- We can't build with dynamic-too on Windows, as labels before the- -- fork point are different depending on whether we are building- -- dynamically or not.- platformCanGenerateDynamicToo- = platformOS (targetPlatform dflags) /= OSMinGW32- refCanGenerateDynamicToo <- newIORef platformCanGenerateDynamicToo- refNextTempSuffix <- newIORef 0- refFilesToClean <- newIORef emptyFilesToClean- refDirsToClean <- newIORef Map.empty- refGeneratedDumps <- newIORef Set.empty- refRtldInfo <- newIORef Nothing- refRtccInfo <- newIORef Nothing- wrapperNum <- newIORef emptyModuleEnv- pure dflags- { canGenerateDynamicToo = refCanGenerateDynamicToo- , nextTempSuffix = refNextTempSuffix- , filesToClean = refFilesToClean- , dirsToClean = refDirsToClean- , generatedDumps = refGeneratedDumps- , nextWrapperNum = wrapperNum- , rtldInfo = refRtldInfo- , rtccInfo = refRtccInfo- }--parseModule- :: FilePath- -> DynFlags- -> StringBuffer- -> ParseResult (Located HsModule)-parseModule filename flags buffer =- unP Parser.parseModule parseState- where- location = mkRealSrcLoc (mkFastString filename) 1 1- parseState = mkPState flags buffer location