Commit c0108673 authored by fmaste's avatar fmaste
Browse files

Add new 'autogen-modules' field

Modules that are built automatically at setup, like Paths_PACKAGENAME or others created with a build-type custom, appear on 'other-modules' for the Library, Executable, Test-Suite or Benchmark stanzas or also on 'exposed-modules' for libraries but are not really on the package when distributed. This makes commands like sdist fail because the file is not found, so with this new field modules that appear there are treated the same way as Paths_PACKAGENAME was and there is no need to create complex build hooks.
Just add the module names on 'other-modules' and 'exposed-modules' as always and on the new 'autogen-modules' besides.
parent 6309f825
......@@ -38,6 +38,20 @@ extra-source-files:
tests/PackageTests/AllowOlder/benchmarks/Bench.hs
tests/PackageTests/AllowOlder/src/Foo.hs
tests/PackageTests/AllowOlder/tests/Test.hs
tests/PackageTests/AutogenModules/Package/Dummy.hs
tests/PackageTests/AutogenModules/Package/MyBenchModule.hs
tests/PackageTests/AutogenModules/Package/MyExeModule.hs
tests/PackageTests/AutogenModules/Package/MyLibModule.hs
tests/PackageTests/AutogenModules/Package/MyLibrary.hs
tests/PackageTests/AutogenModules/Package/MyTestModule.hs
tests/PackageTests/AutogenModules/Package/my.cabal
tests/PackageTests/AutogenModules/SrcDist/Dummy.hs
tests/PackageTests/AutogenModules/SrcDist/MyBenchModule.hs
tests/PackageTests/AutogenModules/SrcDist/MyExeModule.hs
tests/PackageTests/AutogenModules/SrcDist/MyLibModule.hs
tests/PackageTests/AutogenModules/SrcDist/MyLibrary.hs
tests/PackageTests/AutogenModules/SrcDist/MyTestModule.hs
tests/PackageTests/AutogenModules/SrcDist/my.cabal
tests/PackageTests/BenchmarkExeV10/Foo.hs
tests/PackageTests/BenchmarkExeV10/benchmarks/bench-Foo.hs
tests/PackageTests/BenchmarkExeV10/my.cabal
......@@ -435,6 +449,8 @@ test-suite package-tests
type: exitcode-stdio-1.0
main-is: PackageTests.hs
other-modules:
PackageTests.AutogenModules.Package.Check
PackageTests.AutogenModules.SrcDist.Check
PackageTests.BenchmarkStanza.Check
PackageTests.TestStanza.Check
PackageTests.DeterministicAr.Check
......
......@@ -36,6 +36,7 @@ module Distribution.PackageDescription (
hasPublicLib,
hasLibs,
libModules,
libModulesAutogen,
-- ** Executables
Executable(..),
......@@ -43,6 +44,7 @@ module Distribution.PackageDescription (
withExe,
hasExes,
exeModules,
exeModulesAutogen,
-- * Tests
TestSuite(..),
......@@ -54,6 +56,7 @@ module Distribution.PackageDescription (
hasTests,
withTest,
testModules,
testModulesAutogen,
-- * Benchmarks
Benchmark(..),
......@@ -65,6 +68,7 @@ module Distribution.PackageDescription (
hasBenchmarks,
withBenchmark,
benchmarkModules,
benchmarkModulesAutogen,
-- * Build information
BuildInfo(..),
......
......@@ -41,6 +41,7 @@ import Distribution.PackageDescription.Configuration
import Distribution.Compiler
import Distribution.System
import Distribution.License
import Distribution.Simple.BuildPaths (autogenPathsModuleName)
import Distribution.Simple.CCompiler
import Distribution.Simple.Utils hiding (findPackageDesc, notice)
import Distribution.Version
......@@ -245,6 +246,14 @@ checkLibrary pkg lib =
PackageDistInexcusable $
"To use the 'required-signatures' field the package needs to specify "
++ "at least 'cabal-version: >= 1.21'."
-- check that all autogen-modules appear on other-modules or exposed-modules
, check
(not $ and $ map (flip elem (libModules lib)) (libModulesAutogen lib)) $
PackageBuildImpossible $
"An 'autogen-module' is neither on 'exposed-modules' or "
++ "'other-modules'."
]
where
......@@ -282,6 +291,14 @@ checkExecutable pkg exe =
PackageBuildImpossible $
"Duplicate modules in executable '" ++ exeName exe ++ "': "
++ commaSep (map display moduleDuplicates)
-- check that all autogen-modules appear on other-modules
, check
(not $ and $ map (flip elem (exeModules exe)) (exeModulesAutogen exe)) $
PackageBuildImpossible $
"On executable '" ++ exeName exe ++ "' an 'autogen-module' is not "
++ "on 'other-modules'"
]
where
moduleDuplicates = dups (exeModules exe)
......@@ -319,6 +336,16 @@ checkTestSuite pkg test =
PackageDistInexcusable $
"The package uses a C/C++/obj-C source file for the 'main-is' field. "
++ "To use this feature you must specify 'cabal-version: >= 1.18'."
-- check that all autogen-modules appear on other-modules
, check
(not $ and $ map
(flip elem (testModules test))
(testModulesAutogen test)
) $
PackageBuildImpossible $
"On test suite '" ++ testName test ++ "' an 'autogen-module' is not "
++ "on 'other-modules'"
]
where
moduleDuplicates = dups $ testModules test
......@@ -358,6 +385,16 @@ checkBenchmark _pkg bm =
PackageBuildImpossible $
"The 'main-is' field must specify a '.hs' or '.lhs' file "
++ "(even if it is generated by a preprocessor)."
-- check that all autogen-modules appear on other-modules
, check
(not $ and $ map
(flip elem (benchmarkModules bm))
(benchmarkModulesAutogen bm)
) $
PackageBuildImpossible $
"On benchmark '" ++ benchmarkName bm ++ "' an 'autogen-module' is "
++ "not on 'other-modules'"
]
where
moduleDuplicates = dups $ benchmarkModules bm
......@@ -1110,6 +1147,18 @@ checkCabalVersion pkg =
++ "that specifies the dependencies of the Setup.hs script itself. "
++ "The 'setup-depends' field uses the same syntax as 'build-depends', "
++ "so a simple example would be 'setup-depends: base, Cabal'."
, check (specVersion pkg >= Version [1,25] []
&& elem (autogenPathsModuleName pkg) allModuleNames
&& not (elem (autogenPathsModuleName pkg) allModuleNamesAutogen) ) $
PackageDistInexcusable $
"Packages using 'cabal-version: >= 1.25' and the autogenerated "
++ "module Paths_* must include it also on the 'autogen-modules' field "
++ "besides 'exposed-modules' and 'other-modules'. This specifies that "
++ "the module does not come with the package and is generated on "
++ "setup. Modules built with a custom Setup.hs script also go here "
++ "to ensure that commands like sdist don't fail."
]
where
-- Perform a check on packages that use a version of the spec less than
......@@ -1244,6 +1293,15 @@ checkCabalVersion pkg =
map DisableExtension
[MonoPatBinds]
allModuleNames =
(case library pkg of
Nothing -> []
(Just lib) -> libModules lib
)
++ concatMap otherModules (allBuildInfo pkg)
allModuleNamesAutogen = concatMap autogenModules (allBuildInfo pkg)
-- | A variation on the normal 'Text' instance, shows any ()'s in the original
-- textual syntax. We need to show these otherwise it's confusing to users when
-- we complain of their presence but do not pretty print them!
......
......@@ -443,6 +443,9 @@ binfoFieldDescrs =
, listFieldWithSep vcat "other-modules"
disp parseModuleNameQ
otherModules (\val binfo -> binfo{otherModules=val})
, listFieldWithSep vcat "autogen-modules"
disp parseModuleNameQ
autogenModules (\val binfo -> binfo{autogenModules=val})
, optsField "ghc-prof-options" GHC
profOptions (\val binfo -> binfo{profOptions=val})
, optsField "ghcjs-prof-options" GHCJS
......
......@@ -288,6 +288,7 @@ ppField name fielddoc
, "includes"
, "install-includes"
, "other-modules"
, "autogen-modules"
, "depends"
]
......
......@@ -583,7 +583,7 @@ writeAutogenFiles verbosity pkg lbi clbi = do
createDirectoryIfMissingVerbose verbosity True (autogenComponentModulesDir lbi clbi)
let pathsModulePath = autogenComponentModulesDir lbi clbi
</> ModuleName.toFilePath (autogenModuleName pkg) <.> "hs"
</> ModuleName.toFilePath (autogenPathsModuleName pkg) <.> "hs"
rewriteFile pathsModulePath (Build.PathsModule.generate pkg lbi clbi)
let cppHeaderPath = autogenComponentModulesDir lbi clbi </> cppHeaderName
......
......@@ -226,7 +226,7 @@ generate pkg_descr lbi clbi =
_ -> False
supportsRelocatableProgs _ = False
paths_modulename = autogenModuleName pkg_descr
paths_modulename = autogenPathsModuleName pkg_descr
get_prefix_stuff = get_prefix_win32 buildArch
......
......@@ -19,6 +19,7 @@ module Distribution.Simple.BuildPaths (
autogenComponentModulesDir,
autogenModuleName,
autogenPathsModuleName,
cppHeaderName,
haddockName,
......@@ -87,9 +88,14 @@ autogenComponentModulesDir lbi clbi = componentBuildDir lbi clbi </> "autogen"
cppHeaderName :: String
cppHeaderName = "cabal_macros.h"
{-# DEPRECATED autogenModuleName "Use autogenPathsModuleName instead" #-}
-- |The name of the auto-generated module associated with a package
autogenModuleName :: PackageDescription -> ModuleName
autogenModuleName pkg_descr =
autogenModuleName = autogenPathsModuleName
-- | The name of the auto-generated Paths_* module associated with a package
autogenPathsModuleName :: PackageDescription -> ModuleName
autogenPathsModuleName pkg_descr =
ModuleName.fromString $
"Paths_" ++ map fixchar (display (packageName pkg_descr))
where fixchar '-' = '_'
......
......@@ -136,7 +136,7 @@ listPackageSources verbosity pkg_descr0 pps = do
maybeExecutable <- listPackageSourcesMaybeExecutable pkg_descr
return (ordinary, maybeExecutable)
where
pkg_descr = filterAutogenModule pkg_descr0
pkg_descr = filterAutogenModules pkg_descr0
-- | List those source files that may be executable (e.g. the configure script).
listPackageSourcesMaybeExecutable :: PackageDescription -> IO [FilePath]
......@@ -259,7 +259,7 @@ prepareTree verbosity pkg_descr0 mb_lbi targetDir pps = do
maybeCreateDefaultSetupScript targetDir
where
pkg_descr = filterAutogenModule pkg_descr0
pkg_descr = filterAutogenModules pkg_descr0
-- | Find the setup script file, if it exists.
findSetupFile :: FilePath -> IO (Maybe FilePath)
......@@ -305,21 +305,24 @@ findIncludeFile (d:ds) f = do
b <- doesFileExist path
if b then return (f,path) else findIncludeFile ds f
-- | Remove the auto-generated module ('Paths_*') from 'exposed-modules' and
-- 'other-modules'.
filterAutogenModule :: PackageDescription -> PackageDescription
filterAutogenModule pkg_descr0 = mapLib filterAutogenModuleLib $
-- | Remove the auto-generated modules (like 'Paths_*') from 'exposed-modules'
-- and 'other-modules'.
filterAutogenModules :: PackageDescription -> PackageDescription
filterAutogenModules pkg_descr0 = mapLib filterAutogenModuleLib $
mapAllBuildInfo filterAutogenModuleBI pkg_descr0
where
mapLib f pkg = pkg { library = fmap f (library pkg)
, subLibraries = map f (subLibraries pkg) }
filterAutogenModuleLib lib = lib {
exposedModules = filter (/=autogenModule) (exposedModules lib)
exposedModules = filter (filterFunction (libBuildInfo lib)) (exposedModules lib)
}
filterAutogenModuleBI bi = bi {
otherModules = filter (/=autogenModule) (otherModules bi)
otherModules = filter (filterFunction bi) (otherModules bi)
}
autogenModule = autogenModuleName pkg_descr0
pathsModule = autogenPathsModuleName pkg_descr0
filterFunction bi = \mn ->
mn /= pathsModule
&& not (elem mn (autogenModules bi))
-- | Prepare a directory tree of source files for a snapshot version.
-- It is expected that the appropriate snapshot version has already been set
......@@ -437,7 +440,8 @@ allSourcesBuildInfo bi pps modules = do
nonEmpty _ f xs = f xs
suffixes = ppSuffixes pps ++ ["hs", "lhs"]
notFound m = die $ "Error: Could not find module: " ++ display m
++ " with any suffix: " ++ show suffixes
++ " with any suffix: " ++ show suffixes ++ ". If the module "
++ "is autogenerated it should be added to 'autogen-modules'."
printPackageProblems :: Verbosity -> PackageDescription -> IO ()
......
......@@ -6,6 +6,7 @@ module Distribution.Types.Benchmark (
emptyBenchmark,
benchmarkType,
benchmarkModules,
benchmarkModulesAutogen
) where
import Prelude ()
......@@ -60,3 +61,8 @@ benchmarkType benchmark = case benchmarkInterface benchmark of
-- | Get all the module names from a benchmark.
benchmarkModules :: Benchmark -> [ModuleName]
benchmarkModules benchmark = otherModules (benchmarkBuildInfo benchmark)
-- | Get all the auto generated module names from a benchmark.
-- This are a subset of 'benchmarkModules'.
benchmarkModulesAutogen :: Benchmark -> [ModuleName]
benchmarkModulesAutogen benchmark = autogenModules (benchmarkBuildInfo benchmark)
......@@ -40,6 +40,7 @@ data BuildInfo = BuildInfo {
jsSources :: [FilePath],
hsSourceDirs :: [FilePath], -- ^ where to look for the Haskell module hierarchy
otherModules :: [ModuleName], -- ^ non-exposed or non-main modules
autogenModules :: [ModuleName], -- ^ not present on sdist, Paths_* or user-generated with a custom Setup.hs
defaultLanguage :: Maybe Language,-- ^ language used when not explicitly specified
otherLanguages :: [Language], -- ^ other languages used within the package
......@@ -80,6 +81,7 @@ instance Monoid BuildInfo where
jsSources = [],
hsSourceDirs = [],
otherModules = [],
autogenModules = [],
defaultLanguage = Nothing,
otherLanguages = [],
defaultExtensions = [],
......@@ -114,6 +116,7 @@ instance Semigroup BuildInfo where
jsSources = combineNub jsSources,
hsSourceDirs = combineNub hsSourceDirs,
otherModules = combineNub otherModules,
autogenModules = combineNub autogenModules,
defaultLanguage = combineMby defaultLanguage,
otherLanguages = combineNub otherLanguages,
defaultExtensions = combineNub defaultExtensions,
......
......@@ -5,6 +5,7 @@ module Distribution.Types.Executable (
Executable(..),
emptyExecutable,
exeModules,
exeModulesAutogen
) where
import Prelude ()
......@@ -46,3 +47,8 @@ emptyExecutable = mempty
-- | Get all the module names from an exe
exeModules :: Executable -> [ModuleName]
exeModules exe = otherModules (buildInfo exe)
-- | Get all the auto generated module names from an exe
-- This are a subset of 'exeModules'.
exeModulesAutogen :: Executable -> [ModuleName]
exeModulesAutogen exe = autogenModules (buildInfo exe)
......@@ -5,6 +5,7 @@ module Distribution.Types.Library (
Library(..),
emptyLibrary,
libModules,
libModulesAutogen
) where
import Prelude ()
......@@ -58,3 +59,8 @@ libModules :: Library -> [ModuleName]
libModules lib = exposedModules lib
++ otherModules (libBuildInfo lib)
++ requiredSignatures lib
-- | Get all the auto generated module names from the library, exposed or not.
-- This are a subset of 'libModules'.
libModulesAutogen :: Library -> [ModuleName]
libModulesAutogen lib = autogenModules (libBuildInfo lib)
......@@ -6,6 +6,7 @@ module Distribution.Types.TestSuite (
emptyTestSuite,
testType,
testModules,
testModulesAutogen
) where
import Prelude ()
......@@ -65,3 +66,8 @@ testModules test = (case testInterface test of
TestSuiteLibV09 _ m -> [m]
_ -> [])
++ otherModules (testBuildInfo test)
-- | Get all the auto generated module names from a test suite.
-- This are a subset of 'testModules'.
testModulesAutogen :: TestSuite -> [ModuleName]
testModulesAutogen test = autogenModules (testBuildInfo test)
......@@ -50,6 +50,17 @@
* 'getComponentLocalBuildInfo', 'withComponentsInBuildOrder'
and 'componentsInBuildOrder' are deprecated in favor of a
new interface in "Distribution.Types.LocalBuildInfo".
* New 'autogen-modules' field. Modules that are built automatically at
setup, like Paths_PACKAGENAME or others created with a build-type
custom, appear on 'other-modules' for the Library, Executable,
Test-Suite or Benchmark stanzas or also on 'exposed-modules' for
libraries but are not really on the package when distributed. This
makes commands like sdist fail because the file is not found, so with
this new field modules that appear there are treated the same way as
Paths_PACKAGENAME was and there is no need to create complex build
hooks. Just add the module names on 'other-modules' and
'exposed-modules' as always and on the new 'autogen-modules' besides.
(#3656).
1.24.0.0 Ryan Thomas <ryan@ryant.org> March 2016
* Support GHC 8.
......
......@@ -1955,6 +1955,43 @@ custom-setup
[`build-depends`](#build-information) section for a description of the
syntax expected by this field.
## Autogenerated modules
Modules that are built automatically at setup, created with a custom setup
script, must appear on `other-modules` for the library, executable, test-suite
or benchmark stanzas or also on `exposed-modules` for libraries to be used, but
are not really on the package when distributed. This makes commands like sdist
fail because the file is not found.
This special modules must appear again on the `autogen-modules` field of the
stanza that is using it, besides `other-modules` or `exposed-modules`. With
this there is no need to create complex build hooks for this poweruser case.
Right now `main-is` modules are not supported on `autogen-modules`.
~~~~~~~~~~~~~~~~
Library
default-language: Haskell2010
build-depends: base
exposed-modules:
MyLibrary
MyLibHelperModule
other-modules:
MyLibModule
autogen-modules:
MyLibHelperModule
Executable Exe
default-language: Haskell2010
main-is: Dummy.hs
build-depends: base
other-modules:
MyExeModule
MyExeHelperModule
autogen-modules:
MyExeHelperModule
~~~~~~~~~~~~~~~~
## Accessing data files from package code ##
The placement on the target system of files listed in the `data-files`
......@@ -1976,10 +2013,11 @@ program is running.
Note: If you decide to import the `Paths_`_pkgname_ module then it
*must* be listed in the `other-modules` field just like any other module
in your package.
in your package and on `autogen-modules` as the file is autogenerated.
The `Paths_`_pkgname_ module is not platform independent so it does not
get included in the source tarballs generated by `sdist`.
The `Paths_`_pkgname_ module is not platform independent, as any other
autogenerated module, so it does not get included in the source tarballs
generated by `sdist`.
The `Paths_`_pkgname_ module also includes some other useful functions
and values, which record the version of the package and some other
......
module PackageTests.AutogenModules.Package.Check where
import PackageTests.PackageTester
suite :: TestM ()
suite = do
configureResult <- shouldFail $ cabal' "configure" []
sdistResult <- shouldFail $ cabal' "sdist" []
-- Package check messages.
let libAutogenMsg =
"An 'autogen-module' is neither on 'exposed-modules' or "
++ "'other-modules'"
let exeAutogenMsg =
"On executable 'Exe' an 'autogen-module' is not on "
++ "'other-modules'"
let testAutogenMsg =
"On test suite 'Test' an 'autogen-module' is not on "
++ "'other-modules'"
let benchAutogenMsg =
"On benchmark 'Bench' an 'autogen-module' is not on "
++ "'other-modules'"
let pathsAutogenMsg =
"Packages using 'cabal-version: >= 1.25' and the autogenerated"
-- Asserts for the desired check messages after configure.
assertOutputContains libAutogenMsg configureResult
assertOutputContains exeAutogenMsg configureResult
assertOutputContains testAutogenMsg configureResult
assertOutputContains benchAutogenMsg configureResult
-- Asserts for the desired check messages after sdist.
assertOutputContains "Distribution quality errors:" sdistResult
assertOutputContains libAutogenMsg sdistResult
assertOutputContains exeAutogenMsg sdistResult
assertOutputContains testAutogenMsg sdistResult
assertOutputContains benchAutogenMsg sdistResult
assertOutputContains pathsAutogenMsg sdistResult
-- Asserts for the undesired check messages after sdist.
assertOutputDoesNotContain "Distribution quality warnings:" sdistResult
-- Asserts for the error messages of the modules not found.
assertOutputContains
"Error: Could not find module: MyLibHelperModule with any suffix"
sdistResult
assertOutputContains
"module is autogenerated it should be added to 'autogen-modules'"
sdistResult
return ()
module Dummy where
main :: IO ()
main = error ""
module MyBenchModule where
main :: IO ()
main = error ""
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment