-
Notifications
You must be signed in to change notification settings - Fork 105
Foreign Library Stanza #518
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
base: main
Are you sure you want to change the base?
Changes from all commits
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 |
|---|---|---|
|
|
@@ -151,6 +151,7 @@ library: | |
| | `custom-setup` | · | | See [Custom setup](#custom-setup) | | | | ||
| | `flags` | `flag <name>` | | Map from flag name to flag (see [Flags](#flags)) | | | | ||
| | `library` | · | | See [Library fields](#library-fields) | | | | ||
| | `foreign-libraries` | `foreign-library <name>` | | Map from foreign library name to a dict of [Foreign library fields](#foreign-library-fields) and global top-level fields. | | UNRELEASED | | ||
| | `internal-libraries` | `library <name>` | | Map from internal library name to a dict of [library fields](#library-fields) and global top-level fields. | | `0.21.0` | | ||
| | `executables` | `executable <name>` | | Map from executable name to executable (see [Executable fields](#executable-fields)) | | | | ||
| | `executable` | `executable <package-name>` | | Shortcut for `executables: { package-name: ... }` | | `0.18.0` | | ||
|
|
@@ -328,6 +329,17 @@ This is done to allow compatibility with a wider range of `Cabal` versions. | |
| | `reexported-modules` | · | | | | ||
| | `signatures` | · | | | | ||
|
|
||
| #### Foreign library fields | ||
|
|
||
| | Hpack | Cabal | Default | Notes | | ||
| | --- | --- | --- | --- | | ||
| | `type` | . | | | | ||
|
Owner
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.
|
||
| | `lib-version-info` | . | | | | ||
| | `options` | . | | | | ||
|
Owner
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. The Cabal documentation says "Currently we only support So again here, maybe we just remove that field and produce .cabal files that meet those requirements? |
||
| | `mod-def-file` | . | | | | ||
|
Owner
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. Even though Cabal and GHC support this, I don't really see a use case for it. Why the hell would you add a My verdict is, unless we can come up with a sensible use case for this, remove it. |
||
| | `other-modules` | · | All modules in `source-dirs` less `main` less any modules mentioned in `when` | | | ||
|
Owner
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. Is the documentation actually correct? |
||
| | `generated-other-modules` | | | Added to `other-modules` and `autogen-modules`. Since `0.23.0`. | ||
|
Owner
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. I think this was just copied from executables! At least the |
||
|
|
||
| #### Executable fields | ||
|
|
||
| | Hpack | Cabal | Default | Notes | | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -61,6 +61,7 @@ module Hpack.Config ( | |
| , Section(..) | ||
| , Library(..) | ||
| , Executable(..) | ||
| , ForeignLibrary(..) | ||
| , Conditional(..) | ||
| , Cond(..) | ||
| , Flag(..) | ||
|
|
@@ -167,6 +168,7 @@ package name version = Package { | |
| , packageCustomSetup = Nothing | ||
| , packageLibrary = Nothing | ||
| , packageInternalLibraries = mempty | ||
| , packageForeignLibraries = mempty | ||
| , packageExecutables = mempty | ||
| , packageTests = mempty | ||
| , packageBenchmarks = mempty | ||
|
|
@@ -176,6 +178,7 @@ package name version = Package { | |
| renamePackage :: String -> Package -> Package | ||
| renamePackage name p@Package{..} = p { | ||
| packageName = name | ||
| , packageForeignLibraries = fmap (renameDependencies packageName name) packageForeignLibraries | ||
|
Owner
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. Same here, internal libraries are not handled here. If internal libraries cannot depend on the main library, then we are actually good. I'm not sure what's the situation here. I think currently nobody is using this code, so maybe not a big issue. We could potentially deprecate it. |
||
| , packageExecutables = fmap (renameDependencies packageName name) packageExecutables | ||
| , packageTests = fmap (renameDependencies packageName name) packageTests | ||
| , packageBenchmarks = fmap (renameDependencies packageName name) packageBenchmarks | ||
|
|
@@ -194,6 +197,7 @@ renameDependencies old new sect@Section{..} = sect {sectionDependencies = (Depen | |
| packageDependencies :: Package -> [(String, DependencyInfo)] | ||
| packageDependencies Package{..} = nub . sortBy (comparing (lexicographically . fst)) $ | ||
| (concatMap deps packageExecutables) | ||
| ++ (concatMap deps packageForeignLibraries) | ||
|
Owner
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. Not related to this pull request, but I think this code does not handle internal libraries correctly. I think we need a separate issue or PR for that. |
||
| ++ (concatMap deps packageTests) | ||
| ++ (concatMap deps packageBenchmarks) | ||
| ++ maybe [] deps packageLibrary | ||
|
|
@@ -237,6 +241,29 @@ instance Semigroup LibrarySection where | |
| , librarySectionSignatures = librarySectionSignatures a <> librarySectionSignatures b | ||
| } | ||
|
|
||
| data ForeignLibrarySection = ForeignLibrarySection { | ||
| foreignLibrarySectionType :: Last String | ||
| , foreignLibrarySectionLibVersionInfo :: Last String | ||
| , foreignLibrarySectionOptions :: Maybe (List String) | ||
| , foreignLibrarySectionModDefFile :: Last String | ||
| , foreignLibrarySectionOtherModules :: Maybe (List Module) | ||
| , foreignLibrarySectionGeneratedOtherModules :: Maybe (List Module) | ||
| } deriving (Eq, Show, Generic, FromValue) | ||
|
|
||
| instance Monoid ForeignLibrarySection where | ||
| mempty = ForeignLibrarySection mempty mempty Nothing mempty Nothing Nothing | ||
| mappend = (<>) | ||
|
|
||
| instance Semigroup ForeignLibrarySection where | ||
| a <> b = ForeignLibrarySection { | ||
| foreignLibrarySectionType = foreignLibrarySectionType a <> foreignLibrarySectionType b | ||
| , foreignLibrarySectionLibVersionInfo = foreignLibrarySectionLibVersionInfo a <> foreignLibrarySectionLibVersionInfo b | ||
| , foreignLibrarySectionOptions = foreignLibrarySectionOptions a <> foreignLibrarySectionOptions b | ||
| , foreignLibrarySectionModDefFile = foreignLibrarySectionModDefFile a <> foreignLibrarySectionModDefFile b | ||
| , foreignLibrarySectionOtherModules = foreignLibrarySectionOtherModules a <> foreignLibrarySectionOtherModules b | ||
| , foreignLibrarySectionGeneratedOtherModules = foreignLibrarySectionGeneratedOtherModules a <> foreignLibrarySectionGeneratedOtherModules b | ||
| } | ||
|
|
||
| data ExecutableSection = ExecutableSection { | ||
| executableSectionMain :: Alias 'True "main-is" (Last FilePath) | ||
| , executableSectionOtherModules :: Maybe (List Module) | ||
|
|
@@ -570,10 +597,12 @@ type SectionConfigWithDefaults asmSources cSources cxxSources jsSources a = Prod | |
|
|
||
| type PackageConfigWithDefaults asmSources cSources cxxSources jsSources = PackageConfig_ | ||
| (SectionConfigWithDefaults asmSources cSources cxxSources jsSources LibrarySection) | ||
| (SectionConfigWithDefaults asmSources cSources cxxSources jsSources ForeignLibrarySection) | ||
| (SectionConfigWithDefaults asmSources cSources cxxSources jsSources ExecutableSection) | ||
|
|
||
| type PackageConfig asmSources cSources cxxSources jsSources = PackageConfig_ | ||
| (WithCommonOptions asmSources cSources cxxSources jsSources LibrarySection) | ||
| (WithCommonOptions asmSources cSources cxxSources jsSources ForeignLibrarySection) | ||
| (WithCommonOptions asmSources cSources cxxSources jsSources ExecutableSection) | ||
|
|
||
| data PackageVersion = PackageVersion {unPackageVersion :: String} | ||
|
|
@@ -584,7 +613,7 @@ instance FromValue PackageVersion where | |
| String s -> return (T.unpack s) | ||
| _ -> typeMismatch "Number or String" v | ||
|
|
||
| data PackageConfig_ library executable = PackageConfig { | ||
| data PackageConfig_ library foreignLib executable = PackageConfig { | ||
| packageConfigName :: Maybe String | ||
| , packageConfigVersion :: Maybe PackageVersion | ||
| , packageConfigSynopsis :: Maybe String | ||
|
|
@@ -611,6 +640,8 @@ data PackageConfig_ library executable = PackageConfig { | |
| , packageConfigCustomSetup :: Maybe CustomSetupSection | ||
| , packageConfigLibrary :: Maybe library | ||
| , packageConfigInternalLibraries :: Maybe (Map String library) | ||
| , packageConfigForeignLibraries :: Maybe (Map String foreignLib) | ||
| , packageConfigForeignLibrary :: Maybe foreignLib | ||
|
Owner
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. So the idea here is that in addition to I'm still undecided whether I think this is a good idea or not, but if you're gonna do that, then we need a test for it.
Owner
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. I guess it is actually a good idea, so let's add the test. |
||
| , packageConfigExecutable :: Maybe executable | ||
| , packageConfigExecutables :: Maybe (Map String executable) | ||
| , packageConfigTests :: Maybe (Map String executable) | ||
|
|
@@ -639,13 +670,17 @@ traversePackageConfig :: Traversal PackageConfig | |
| traversePackageConfig t p@PackageConfig{..} = do | ||
| library <- traverse (traverseWithCommonOptions t) packageConfigLibrary | ||
| internalLibraries <- traverseNamedConfigs t packageConfigInternalLibraries | ||
| foreignLibrary <- traverse (traverseWithCommonOptions t) packageConfigForeignLibrary | ||
| foreignLibraries <- traverseNamedConfigs t packageConfigForeignLibraries | ||
| executable <- traverse (traverseWithCommonOptions t) packageConfigExecutable | ||
| executables <- traverseNamedConfigs t packageConfigExecutables | ||
| tests <- traverseNamedConfigs t packageConfigTests | ||
| benchmarks <- traverseNamedConfigs t packageConfigBenchmarks | ||
| return p { | ||
| packageConfigLibrary = library | ||
| , packageConfigInternalLibraries = internalLibraries | ||
| , packageConfigForeignLibrary = foreignLibrary | ||
| , packageConfigForeignLibraries = foreignLibraries | ||
| , packageConfigExecutable = executable | ||
| , packageConfigExecutables = executables | ||
| , packageConfigTests = tests | ||
|
|
@@ -739,6 +774,7 @@ addPathsModuleToGeneratedModules pkg | |
| | otherwise = pkg { | ||
| packageLibrary = fmap mapLibrary <$> packageLibrary pkg | ||
| , packageInternalLibraries = fmap mapLibrary <$> packageInternalLibraries pkg | ||
| , packageForeignLibraries = fmap mapForeignLibrary <$> packageForeignLibraries pkg | ||
| , packageExecutables = fmap mapExecutable <$> packageExecutables pkg | ||
| , packageTests = fmap mapExecutable <$> packageTests pkg | ||
| , packageBenchmarks = fmap mapExecutable <$> packageBenchmarks pkg | ||
|
|
@@ -755,6 +791,15 @@ addPathsModuleToGeneratedModules pkg | |
| where | ||
| generatedModules = libraryGeneratedModules lib | ||
|
|
||
| mapForeignLibrary :: ForeignLibrary -> ForeignLibrary | ||
| mapForeignLibrary foreignLibrary | ||
| | pathsModule `elem` foreignLibraryOtherModules foreignLibrary = foreignLibrary { | ||
| foreignLibraryGeneratedModules = if pathsModule `elem` generatedModules then generatedModules else pathsModule : generatedModules | ||
| } | ||
| | otherwise = foreignLibrary | ||
| where | ||
| generatedModules = foreignLibraryGeneratedModules foreignLibrary | ||
|
|
||
| mapExecutable :: Executable -> Executable | ||
| mapExecutable executable | ||
| | pathsModule `elem` executableOtherModules executable = executable { | ||
|
|
@@ -836,6 +881,7 @@ ensureRequiredCabalVersion inferredLicense pkg@Package{..} = pkg { | |
| , makeVersion [3,14] <$ guard (not (null packageExtraFiles)) | ||
| , packageLibrary >>= libraryCabalVersion | ||
| , internalLibsCabalVersion packageInternalLibraries | ||
| , foreignLibsCabalVersion packageForeignLibraries | ||
| , executablesCabalVersion packageExecutables | ||
| , executablesCabalVersion packageTests | ||
| , executablesCabalVersion packageBenchmarks | ||
|
|
@@ -859,6 +905,15 @@ ensureRequiredCabalVersion inferredLicense pkg@Package{..} = pkg { | |
| where | ||
| versions = libraryCabalVersion <$> Map.elems internalLibraries | ||
|
|
||
| foreignLibsCabalVersion :: Map String (Section ForeignLibrary) -> Maybe CabalVersion | ||
| foreignLibsCabalVersion = foldr max Nothing . map foreignLibCabalVersion . Map.elems | ||
|
|
||
| foreignLibCabalVersion :: Section ForeignLibrary -> Maybe CabalVersion | ||
| foreignLibCabalVersion sect = maximum [ | ||
| makeVersion [2,0] <$ guard (foreignLibraryHasGeneratedModules sect) | ||
| , sectionCabalVersion (concatMap getForeignLibraryModules) sect | ||
| ] | ||
|
|
||
| executablesCabalVersion :: Map String (Section Executable) -> Maybe CabalVersion | ||
| executablesCabalVersion = foldr max Nothing . map executableCabalVersion . Map.elems | ||
|
|
||
|
|
@@ -868,6 +923,9 @@ ensureRequiredCabalVersion inferredLicense pkg@Package{..} = pkg { | |
| , sectionCabalVersion (concatMap getExecutableModules) sect | ||
| ] | ||
|
|
||
| foreignLibraryHasGeneratedModules :: Section ForeignLibrary -> Bool | ||
| foreignLibraryHasGeneratedModules = any (not . null . foreignLibraryGeneratedModules) | ||
|
|
||
| executableHasGeneratedModules :: Section Executable -> Bool | ||
| executableHasGeneratedModules = any (not . null . executableGeneratedModules) | ||
|
|
||
|
|
@@ -1034,6 +1092,7 @@ data Package = Package { | |
| , packageCustomSetup :: Maybe CustomSetup | ||
| , packageLibrary :: Maybe (Section Library) | ||
| , packageInternalLibraries :: Map String (Section Library) | ||
| , packageForeignLibraries :: Map String (Section ForeignLibrary) | ||
| , packageExecutables :: Map String (Section Executable) | ||
| , packageTests :: Map String (Section Executable) | ||
| , packageBenchmarks :: Map String (Section Executable) | ||
|
|
@@ -1054,6 +1113,15 @@ data Library = Library { | |
| , librarySignatures :: [String] | ||
| } deriving (Eq, Show) | ||
|
|
||
| data ForeignLibrary = ForeignLibrary { | ||
| foreignLibraryType :: Maybe String | ||
| , foreignLibraryLibVersionInfo :: Maybe String | ||
| , foreignLibraryOptions :: Maybe [String] | ||
| , foreignLibraryModDefFile :: Maybe String | ||
| , foreignLibraryOtherModules :: [Module] | ||
| , foreignLibraryGeneratedModules :: [Module] | ||
| } deriving (Eq, Show) | ||
|
|
||
| data Executable = Executable { | ||
| executableMain :: Maybe FilePath | ||
| , executableOtherModules :: [Module] | ||
|
|
@@ -1177,13 +1245,17 @@ expandSectionDefaults | |
| expandSectionDefaults formatYamlParseError userDataDir dir p@PackageConfig{..} = do | ||
| library <- traverse (expandDefaults formatYamlParseError userDataDir dir) packageConfigLibrary | ||
| internalLibraries <- traverse (traverse (expandDefaults formatYamlParseError userDataDir dir)) packageConfigInternalLibraries | ||
| foreignLibrary <- traverse (expandDefaults formatYamlParseError userDataDir dir) packageConfigForeignLibrary | ||
| foreignLibraries <- traverse (traverse (expandDefaults formatYamlParseError userDataDir dir)) packageConfigForeignLibraries | ||
| executable <- traverse (expandDefaults formatYamlParseError userDataDir dir) packageConfigExecutable | ||
| executables <- traverse (traverse (expandDefaults formatYamlParseError userDataDir dir)) packageConfigExecutables | ||
| tests <- traverse (traverse (expandDefaults formatYamlParseError userDataDir dir)) packageConfigTests | ||
| benchmarks <- traverse (traverse (expandDefaults formatYamlParseError userDataDir dir)) packageConfigBenchmarks | ||
| return p{ | ||
| packageConfigLibrary = library | ||
| , packageConfigInternalLibraries = internalLibraries | ||
| , packageConfigForeignLibrary = foreignLibrary | ||
| , packageConfigForeignLibraries = foreignLibraries | ||
| , packageConfigExecutable = executable | ||
| , packageConfigExecutables = executables | ||
| , packageConfigTests = tests | ||
|
|
@@ -1241,25 +1313,28 @@ type GlobalOptions = CommonOptions AsmSources CSources CxxSources JsSources Empt | |
|
|
||
| toPackage_ :: (MonadIO m, Warnings m, State m) => FilePath -> Product GlobalOptions (PackageConfig AsmSources CSources CxxSources JsSources) -> m Package | ||
| toPackage_ dir (Product g PackageConfig{..}) = do | ||
| foreignLibraryMap <- toExecutableMap packageName packageConfigForeignLibraries packageConfigForeignLibrary | ||
| executableMap <- toExecutableMap packageName packageConfigExecutables packageConfigExecutable | ||
| let | ||
| globalVerbatim = commonOptionsVerbatim g | ||
| globalOptions = g {commonOptionsVerbatim = Nothing} | ||
|
|
||
| executableNames = maybe [] Map.keys executableMap | ||
| componentNames = maybe [] Map.keys executableMap ++ maybe [] Map.keys foreignLibraryMap | ||
|
Owner
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. I don't think this is correct.
Owner
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. Specifically I think the old is just fine, we don't need to update this. |
||
|
|
||
| toSect :: (Warnings m, Monoid a) => WithCommonOptions AsmSources CSources CxxSources JsSources a -> m (Section a) | ||
| toSect = toSection packageName executableNames . first ((mempty <$ globalOptions) <>) | ||
| toSect = toSection packageName componentNames . first ((mempty <$ globalOptions) <>) | ||
|
|
||
| toSections :: (Warnings m, Monoid a) => Maybe (Map String (WithCommonOptions AsmSources CSources CxxSources JsSources a)) -> m (Map String (Section a)) | ||
| toSections = maybe (return mempty) (traverse toSect) | ||
|
|
||
| toLib = toLibrary dir packageName | ||
| toForeignLibraries = toSections >=> traverse (toForeignLibrary dir packageName) | ||
| toExecutables = toSections >=> traverse (toExecutable dir packageName) | ||
|
|
||
| mLibrary <- traverse (toSect >=> toLib) packageConfigLibrary | ||
| internalLibraries <- toSections packageConfigInternalLibraries >>= traverse toLib | ||
|
|
||
| foreignLibraries <- toForeignLibraries foreignLibraryMap | ||
| executables <- toExecutables executableMap | ||
| tests <- toExecutables packageConfigTests | ||
| benchmarks <- toExecutables packageConfigBenchmarks | ||
|
|
@@ -1269,6 +1344,7 @@ toPackage_ dir (Product g PackageConfig{..}) = do | |
| missingSourceDirs <- liftIO $ nub . sort <$> filterM (fmap not <$> doesDirectoryExist . (dir </>)) ( | ||
| maybe [] sectionSourceDirs mLibrary | ||
| ++ concatMap sectionSourceDirs internalLibraries | ||
| ++ concatMap sectionSourceDirs foreignLibraries | ||
| ++ concatMap sectionSourceDirs executables | ||
| ++ concatMap sectionSourceDirs tests | ||
| ++ concatMap sectionSourceDirs benchmarks | ||
|
|
@@ -1328,6 +1404,7 @@ toPackage_ dir (Product g PackageConfig{..}) = do | |
| , packageCustomSetup = mCustomSetup | ||
| , packageLibrary = mLibrary | ||
| , packageInternalLibraries = internalLibraries | ||
| , packageForeignLibraries = foreignLibraries | ||
| , packageExecutables = executables | ||
| , packageTests = tests | ||
| , packageBenchmarks = benchmarks | ||
|
|
@@ -1437,6 +1514,9 @@ getMentionedLibraryModules (LibrarySection _ _ exposedModules generatedExposedMo | |
| getLibraryModules :: Library -> [Module] | ||
| getLibraryModules Library{..} = libraryExposedModules ++ libraryOtherModules | ||
|
|
||
| getForeignLibraryModules :: ForeignLibrary -> [Module] | ||
| getForeignLibraryModules ForeignLibrary{..} = foreignLibraryOtherModules | ||
|
|
||
| getExecutableModules :: Executable -> [Module] | ||
| getExecutableModules Executable{..} = executableOtherModules | ||
|
|
||
|
|
@@ -1522,6 +1602,28 @@ fromLibrarySectionPlain LibrarySection{..} = Library { | |
| , librarySignatures = fromMaybeList librarySectionSignatures | ||
| } | ||
|
|
||
| getMentionedForeignLibraryModules :: ForeignLibrarySection -> [Module] | ||
| getMentionedForeignLibraryModules (ForeignLibrarySection _ _ _ _ otherModules generatedModules)= | ||
| fromMaybeList (otherModules <> generatedModules) | ||
|
|
||
| toForeignLibrary :: (MonadIO m, State m) => FilePath -> String -> Section ForeignLibrarySection -> m (Section ForeignLibrary) | ||
| toForeignLibrary dir packageName_ = | ||
| inferModules dir packageName_ getMentionedForeignLibraryModules getForeignLibraryModules fromForeignLibrarySection (fromForeignLibrarySection []) | ||
| where | ||
| fromForeignLibrarySection :: [Module] -> [Module] -> ForeignLibrarySection -> ForeignLibrary | ||
| fromForeignLibrarySection pathsModule inferableModules ForeignLibrarySection{..} = | ||
| (ForeignLibrary | ||
| (getLast foreignLibrarySectionType) | ||
| (getLast foreignLibrarySectionLibVersionInfo) | ||
| (fromList <$> foreignLibrarySectionOptions) | ||
| (getLast foreignLibrarySectionModDefFile) | ||
| (otherModules ++ generatedModules) | ||
| generatedModules | ||
| ) | ||
| where | ||
| otherModules = maybe (inferableModules ++ pathsModule) fromList foreignLibrarySectionOtherModules | ||
| generatedModules = maybe [] fromList foreignLibrarySectionGeneratedOtherModules | ||
|
|
||
| getMentionedExecutableModules :: ExecutableSection -> [Module] | ||
| getMentionedExecutableModules (ExecutableSection (Alias (Last main)) otherModules generatedModules)= | ||
| maybe id (:) (toModule . Path.fromFilePath <$> main) $ fromMaybeList (otherModules <> generatedModules) | ||
|
|
||
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.
Documentation for
foreign-libraryis missing here.