-
Notifications
You must be signed in to change notification settings - Fork 704
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix c2hs handling in Cabal #6233
base: master
Are you sure you want to change the base?
Changes from 33 commits
fbef0e3
c3e9b87
e74115e
cca903b
2290218
625423e
71b6d32
16b00a2
8358fdf
6338732
c018b57
f721560
64c7d1a
6281535
bc1ed2c
0dc1c71
a4a2448
f71b5af
a8c95ae
5f2814f
746ae57
2154c2c
eb3d592
b616f0e
243e6b8
e9cb223
7b2c729
0d0ec9e
0812063
34f3ff0
280e647
f4c354a
d6f6feb
6b461de
6ae37b0
fe760c5
6031b43
ca7537b
5bc4c03
0bba20f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
{-# LANGUAGE RankNTypes #-} | ||
{-# LANGUAGE FlexibleContexts #-} | ||
|
||
module Distribution.C2Hs ( reorderC2Hs ) where | ||
|
||
import Prelude() | ||
import Distribution.Compat.Graph | ||
import Distribution.Compat.Prelude | ||
import Distribution.C2Hs.Lexer | ||
import Distribution.ModuleName (ModuleName, toFilePath) | ||
import Distribution.Parsec (simpleParsec) | ||
import Distribution.Simple.Utils (warn, findFileWithExtension) | ||
import Distribution.Verbosity (Verbosity) | ||
|
||
-- | Given a list of 'ModuleName's, sort it according to @c2hs@ @{\#import\#}@ | ||
-- declarations. | ||
reorderC2Hs :: Verbosity | ||
-> [FilePath] -- ^ Source directories | ||
-> [ModuleName] -- ^ Module names | ||
-> IO [ModuleName] -- ^ Sorted modules | ||
reorderC2Hs v dirs preMods = do | ||
|
||
chsFiles <- traverse findCHS preMods | ||
|
||
modDeps <- traverse (extractDeps v) (zip preMods chsFiles) | ||
|
||
pure $ fmap (\(N m _ _) -> m) (revTopSort $ fromDistinctList modDeps) | ||
|
||
where findCHS = findFileWithExtension [".chs"] dirs . toFilePath | ||
|
||
|
||
-- | Given a 'ModuleName' and its corresponding filepath, return a 'Node' | ||
-- with its associated @c2hs@ dependencies | ||
extractDeps :: Verbosity -> (ModuleName, Maybe FilePath) -> IO (Node ModuleName ModuleName) | ||
-- If the 'FilePath' is 'Nothing', it's not a @.chs@ file | ||
extractDeps _ (m, Nothing) = pure (N m m []) | ||
extractDeps v (m, Just f) = do | ||
con <- readFile f | ||
mods <- case getImports con of | ||
Right ms -> case traverse simpleParsec ms of | ||
Just ms' -> pure ms' | ||
Nothing -> do { warn v ("Cannot parse module name in c2hs file " ++ f) ; pure [] } | ||
Left err -> do { warn v ("Cannot parse c2hs import in " ++ f ++ ": " ++ err) ; pure [] } | ||
pure (N m m mods) |
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
{-# LANGUAGE DeriveAnyClass #-} | ||
{-# LANGUAGE DeriveGeneric #-} | ||
|
||
module Codec.Archive.Types.Foreign ( -- * Callbacks | ||
ArchiveReadCallback | ||
, ArchiveSkipCallback | ||
, ArchiveSeekCallback | ||
, ArchiveWriteCallback | ||
, ArchiveCloseCallbackRaw | ||
, ArchiveOpenCallbackRaw | ||
, ArchiveSwitchCallbackRaw | ||
, ArchivePassphraseCallback | ||
-- * Abstract types | ||
, Archive | ||
, ArchiveEntry | ||
, Stat | ||
, LinkResolver | ||
-- * Enum types | ||
, ArchiveResult (..) | ||
-- * Macros | ||
, Flags (..) | ||
, ArchiveFilter (..) | ||
, ArchiveFormat (..) | ||
, FileType (..) | ||
, ArchiveCapabilities (..) | ||
, ReadDiskFlags (..) | ||
, TimeFlag (..) | ||
, EntryACL (..) | ||
-- * libarchive types | ||
, LaInt64 | ||
, LaSSize | ||
, Dev | ||
) where | ||
|
||
import Control.DeepSeq (NFData) | ||
import Data.Bits (Bits (..)) | ||
import Data.Int (Int64) | ||
import Data.Semigroup | ||
import Foreign.C.String (CString) | ||
import Foreign.C.Types (CInt, CSize) | ||
import Foreign.Ptr (Ptr) | ||
import GHC.Generics (Generic) | ||
import System.Posix.Types (CMode) | ||
|
||
#include <archive.h> | ||
|
||
type LaInt64 = {# type la_int64_t #} | ||
type LaSSize = {# type la_ssize_t #} | ||
type Dev = {# type dev_t #} | ||
|
||
|
||
{# enum define ArchiveResult { ARCHIVE_OK as ArchiveOk | ||
, ARCHIVE_EOF as ArchiveEOF | ||
, ARCHIVE_RETRY as ArchiveRetry | ||
, ARCHIVE_WARN as ArchiveWarn | ||
, ARCHIVE_FAILED as ArchiveFailed | ||
, ARCHIVE_FATAL as ArchiveFatal | ||
} deriving (Eq, Show, Generic, NFData) | ||
#} | ||
|
||
-- | Abstract type | ||
data Archive | ||
|
||
-- | Abstract type | ||
data ArchiveEntry | ||
|
||
data Stat | ||
|
||
data LinkResolver | ||
|
||
type ArchiveReadCallback a b = Ptr Archive -> Ptr a -> Ptr (Ptr b) -> IO LaSSize | ||
type ArchiveSkipCallback a = Ptr Archive -> Ptr a -> Int64 -> IO LaInt64 | ||
type ArchiveSeekCallback a = Ptr Archive -> Ptr a -> Int64 -> CInt -> IO LaInt64 | ||
type ArchiveWriteCallback a b = Ptr Archive -> Ptr a -> Ptr b -> CSize -> IO LaSSize | ||
type ArchiveOpenCallbackRaw a = Ptr Archive -> Ptr a -> IO CInt | ||
type ArchiveCloseCallbackRaw a = Ptr Archive -> Ptr a -> IO CInt | ||
type ArchiveSwitchCallbackRaw a b = Ptr Archive -> Ptr a -> Ptr b -> IO CInt | ||
type ArchivePassphraseCallback a = Ptr Archive -> Ptr a -> IO CString | ||
|
||
newtype ArchiveFormat = ArchiveFormat CInt | ||
deriving (Eq) | ||
|
||
newtype FileType = FileType CMode | ||
deriving (Eq) | ||
|
||
newtype Flags = Flags CInt | ||
|
||
newtype ReadDiskFlags = ReadDiskFlags CInt | ||
|
||
newtype TimeFlag = TimeFlag CInt | ||
|
||
newtype EntryACL = EntryACL CInt | ||
|
||
newtype ArchiveFilter = ArchiveFilter CInt | ||
|
||
newtype ArchiveCapabilities = ArchiveCapabilities CInt | ||
deriving (Eq) | ||
|
||
instance Semigroup ArchiveCapabilities where | ||
(<>) (ArchiveCapabilities x) (ArchiveCapabilities y) = ArchiveCapabilities (x .|. y) | ||
|
||
instance Monoid ArchiveCapabilities where | ||
mempty = ArchiveCapabilities 0 | ||
mappend = (<>) | ||
|
||
instance Semigroup ReadDiskFlags where | ||
(<>) (ReadDiskFlags x) (ReadDiskFlags y) = ReadDiskFlags (x .|. y) | ||
|
||
instance Semigroup Flags where | ||
(<>) (Flags x) (Flags y) = Flags (x .|. y) | ||
|
||
instance Monoid Flags where | ||
mempty = Flags 0 | ||
mappend = (<>) | ||
|
||
instance Semigroup EntryACL where | ||
(<>) (EntryACL x) (EntryACL y) = EntryACL (x .|. y) | ||
|
||
-- TODO: `has` function for EntryACL |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{-# LANGUAGE OverloadedStrings #-} | ||
|
||
module UnitTests.Distribution.C2Hs ( tests ) where | ||
|
||
import Distribution.C2Hs | ||
import Distribution.Verbosity (normal) | ||
|
||
import Test.Tasty | ||
import Test.Tasty.HUnit | ||
|
||
tests :: [TestTree] | ||
tests = [ testCase "libarchive" $ | ||
reorderC2Hs normal ["tests/C2Hs/src"] ["Codec.Archive.Foreign.Archive", "Codec.Archive.Types.Foreign"] | ||
>>= (@?= ["Codec.Archive.Types.Foreign", "Codec.Archive.Foreign.Archive"]) | ||
, testCase "libarchive" $ | ||
reorderC2Hs normal ["tests/C2Hs/src"] ["Codec.Archive.Types.Foreign", "Codec.Archive.Foreign.Archive"] | ||
>>= (@?= ["Codec.Archive.Types.Foreign", "Codec.Archive.Foreign.Archive"]) | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
module UnitTests.Distribution.C2Hs.Lexer ( tests ) where | ||
|
||
import Distribution.C2Hs.Lexer | ||
|
||
import Test.Tasty | ||
import Test.Tasty.HUnit | ||
|
||
tests :: [TestTree] | ||
tests = [ testCase "simple import" $ | ||
getImports "{# import Data.Char #}" @?= Right ["Data.Char"] | ||
, testCase "line comment" $ | ||
getImports "-- {# import Data.Char #}" @?= Right [] | ||
, testCase "nested block comment" $ | ||
getImports "{- nested {- comment -} -} {# import Data.Char #}" @?= Right ["Data.Char"] | ||
, testCase "Not find spurious imports" $ | ||
getImports "import Data.Word\n{# import Data.Char #}" @?= Right ["Data.Char"] | ||
, testCase "Work with qualified imports + spaces" $ | ||
getImports "{# import qualified Data.Char #}" @?= Right ["Data.Char"] | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
.PHONY : cabal-install-dev cabal-install-prod | ||
|
||
LEXER_HS:=Cabal/Distribution/Fields/Lexer.hs | ||
LEXER_CHS:=Cabal/Distribution/C2Hs/Lexer.hs | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We still need to commit in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be done. |
||
SPDX_LICENSE_HS:=Cabal/Distribution/SPDX/LicenseId.hs | ||
SPDX_EXCEPTION_HS:=Cabal/Distribution/SPDX/LicenseExceptionId.hs | ||
|
||
|
@@ -13,21 +14,26 @@ CABALRUN := cabal new-run --enable-tests | |
|
||
all : exe lib | ||
|
||
lib : $(LEXER_HS) | ||
lib : $(LEXER_HS) $(LEXER_CHS) | ||
$(CABALBUILD) Cabal:libs | ||
|
||
exe : $(LEXER_HS) | ||
exe : $(LEXER_HS) $(LEXER_CHS) | ||
$(CABALBUILD) cabal-install:exes | ||
|
||
# source generation: Lexer | ||
|
||
lexer : $(LEXER_HS) | ||
lexer : $(LEXER_HS) $(LEXER_CHS) | ||
|
||
$(LEXER_HS) : boot/Lexer.x | ||
alex --latin1 --ghc -o $@ $^ | ||
cat -s $@ > Lexer.tmp | ||
mv Lexer.tmp $@ | ||
|
||
$(LEXER_CHS) : boot/C2HsLexer.x | ||
alex --latin1 --ghc -o $@ $^ | ||
cat -s $@ > C2HsLexer.tmp | ||
mv C2HsLexer.tmp $@ | ||
|
||
# source generation: SPDX | ||
|
||
spdx : $(SPDX_LICENSE_HS) $(SPDX_EXCEPTION_HS) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this file actually compiled, or is it only an input for tests?
Can we place it's somewhere where it doesn't look like real file.
I value that we have "real life" tests inputs, but we also should have something more minimal.
Also negative examples.