From c0108673d34c5f1727994b421a2aabe407901373 Mon Sep 17 00:00:00 2001 From: fmaste Date: Thu, 11 Aug 2016 14:34:10 +0000 Subject: [PATCH] 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. --- Cabal/Cabal.cabal | 16 +++ Cabal/Distribution/PackageDescription.hs | 4 + .../Distribution/PackageDescription/Check.hs | 58 ++++++++++ .../Distribution/PackageDescription/Parse.hs | 3 + Cabal/Distribution/ParseUtils.hs | 1 + Cabal/Distribution/Simple/Build.hs | 2 +- .../Distribution/Simple/Build/PathsModule.hs | 2 +- Cabal/Distribution/Simple/BuildPaths.hs | 8 +- Cabal/Distribution/Simple/SrcDist.hs | 24 ++-- Cabal/Distribution/Types/Benchmark.hs | 6 + Cabal/Distribution/Types/BuildInfo.hs | 3 + Cabal/Distribution/Types/Executable.hs | 6 + Cabal/Distribution/Types/Library.hs | 6 + Cabal/Distribution/Types/TestSuite.hs | 6 + Cabal/changelog | 11 ++ Cabal/doc/developing-packages.markdown | 44 +++++++- .../AutogenModules/Package/Check.hs | 51 +++++++++ .../AutogenModules/Package/Dummy.hs | 4 + .../AutogenModules/Package/LICENSE | 1 + .../AutogenModules/Package/MyBenchModule.hs | 4 + .../AutogenModules/Package/MyExeModule.hs | 4 + .../AutogenModules/Package/MyLibModule.hs | 4 + .../AutogenModules/Package/MyLibrary.hs | 4 + .../AutogenModules/Package/MyTestModule.hs | 4 + .../AutogenModules/Package/my.cabal | 60 ++++++++++ .../PackageTests/AutogenModules/Package/tmp | 0 .../AutogenModules/SrcDist/Check.hs | 104 ++++++++++++++++++ .../AutogenModules/SrcDist/Dummy.hs | 4 + .../AutogenModules/SrcDist/LICENSE | 1 + .../AutogenModules/SrcDist/MyBenchModule.hs | 4 + .../AutogenModules/SrcDist/MyExeModule.hs | 4 + .../AutogenModules/SrcDist/MyLibModule.hs | 4 + .../AutogenModules/SrcDist/MyLibrary.hs | 4 + .../AutogenModules/SrcDist/MyTestModule.hs | 4 + .../AutogenModules/SrcDist/list-sources.txt | 0 .../AutogenModules/SrcDist/my.cabal | 60 ++++++++++ Cabal/tests/PackageTests/Tests.hs | 7 ++ 37 files changed, 516 insertions(+), 16 deletions(-) create mode 100644 Cabal/tests/PackageTests/AutogenModules/Package/Check.hs create mode 100644 Cabal/tests/PackageTests/AutogenModules/Package/Dummy.hs create mode 100644 Cabal/tests/PackageTests/AutogenModules/Package/LICENSE create mode 100644 Cabal/tests/PackageTests/AutogenModules/Package/MyBenchModule.hs create mode 100644 Cabal/tests/PackageTests/AutogenModules/Package/MyExeModule.hs create mode 100644 Cabal/tests/PackageTests/AutogenModules/Package/MyLibModule.hs create mode 100644 Cabal/tests/PackageTests/AutogenModules/Package/MyLibrary.hs create mode 100644 Cabal/tests/PackageTests/AutogenModules/Package/MyTestModule.hs create mode 100644 Cabal/tests/PackageTests/AutogenModules/Package/my.cabal create mode 100644 Cabal/tests/PackageTests/AutogenModules/Package/tmp create mode 100644 Cabal/tests/PackageTests/AutogenModules/SrcDist/Check.hs create mode 100644 Cabal/tests/PackageTests/AutogenModules/SrcDist/Dummy.hs create mode 100644 Cabal/tests/PackageTests/AutogenModules/SrcDist/LICENSE create mode 100644 Cabal/tests/PackageTests/AutogenModules/SrcDist/MyBenchModule.hs create mode 100644 Cabal/tests/PackageTests/AutogenModules/SrcDist/MyExeModule.hs create mode 100644 Cabal/tests/PackageTests/AutogenModules/SrcDist/MyLibModule.hs create mode 100644 Cabal/tests/PackageTests/AutogenModules/SrcDist/MyLibrary.hs create mode 100644 Cabal/tests/PackageTests/AutogenModules/SrcDist/MyTestModule.hs create mode 100644 Cabal/tests/PackageTests/AutogenModules/SrcDist/list-sources.txt create mode 100644 Cabal/tests/PackageTests/AutogenModules/SrcDist/my.cabal diff --git a/Cabal/Cabal.cabal b/Cabal/Cabal.cabal index 82d0ee12083..8d5b583f222 100644 --- a/Cabal/Cabal.cabal +++ b/Cabal/Cabal.cabal @@ -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 diff --git a/Cabal/Distribution/PackageDescription.hs b/Cabal/Distribution/PackageDescription.hs index 423ad21c72f..dc74121b548 100644 --- a/Cabal/Distribution/PackageDescription.hs +++ b/Cabal/Distribution/PackageDescription.hs @@ -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(..), diff --git a/Cabal/Distribution/PackageDescription/Check.hs b/Cabal/Distribution/PackageDescription/Check.hs index 757ff7eff79..25299b5302e 100644 --- a/Cabal/Distribution/PackageDescription/Check.hs +++ b/Cabal/Distribution/PackageDescription/Check.hs @@ -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! diff --git a/Cabal/Distribution/PackageDescription/Parse.hs b/Cabal/Distribution/PackageDescription/Parse.hs index 8b728b939ea..3ee906b245e 100644 --- a/Cabal/Distribution/PackageDescription/Parse.hs +++ b/Cabal/Distribution/PackageDescription/Parse.hs @@ -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 diff --git a/Cabal/Distribution/ParseUtils.hs b/Cabal/Distribution/ParseUtils.hs index 3d5e5e4b177..9c8a72f019a 100644 --- a/Cabal/Distribution/ParseUtils.hs +++ b/Cabal/Distribution/ParseUtils.hs @@ -288,6 +288,7 @@ ppField name fielddoc , "includes" , "install-includes" , "other-modules" + , "autogen-modules" , "depends" ] diff --git a/Cabal/Distribution/Simple/Build.hs b/Cabal/Distribution/Simple/Build.hs index 350e725f546..598c00932f7 100644 --- a/Cabal/Distribution/Simple/Build.hs +++ b/Cabal/Distribution/Simple/Build.hs @@ -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 diff --git a/Cabal/Distribution/Simple/Build/PathsModule.hs b/Cabal/Distribution/Simple/Build/PathsModule.hs index e31a4527d52..3149eecb64e 100644 --- a/Cabal/Distribution/Simple/Build/PathsModule.hs +++ b/Cabal/Distribution/Simple/Build/PathsModule.hs @@ -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 diff --git a/Cabal/Distribution/Simple/BuildPaths.hs b/Cabal/Distribution/Simple/BuildPaths.hs index 717f98452ac..68f9b895907 100644 --- a/Cabal/Distribution/Simple/BuildPaths.hs +++ b/Cabal/Distribution/Simple/BuildPaths.hs @@ -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 '-' = '_' diff --git a/Cabal/Distribution/Simple/SrcDist.hs b/Cabal/Distribution/Simple/SrcDist.hs index 54a2f3f4e18..2703e6c7126 100644 --- a/Cabal/Distribution/Simple/SrcDist.hs +++ b/Cabal/Distribution/Simple/SrcDist.hs @@ -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 () diff --git a/Cabal/Distribution/Types/Benchmark.hs b/Cabal/Distribution/Types/Benchmark.hs index 7f6a5032915..ce7c0bfe6f6 100644 --- a/Cabal/Distribution/Types/Benchmark.hs +++ b/Cabal/Distribution/Types/Benchmark.hs @@ -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) diff --git a/Cabal/Distribution/Types/BuildInfo.hs b/Cabal/Distribution/Types/BuildInfo.hs index b3e57248527..2b849e89a55 100644 --- a/Cabal/Distribution/Types/BuildInfo.hs +++ b/Cabal/Distribution/Types/BuildInfo.hs @@ -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, diff --git a/Cabal/Distribution/Types/Executable.hs b/Cabal/Distribution/Types/Executable.hs index 66de813984d..2baeffd11a3 100644 --- a/Cabal/Distribution/Types/Executable.hs +++ b/Cabal/Distribution/Types/Executable.hs @@ -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) diff --git a/Cabal/Distribution/Types/Library.hs b/Cabal/Distribution/Types/Library.hs index 8e9a17694d3..a8f40126296 100644 --- a/Cabal/Distribution/Types/Library.hs +++ b/Cabal/Distribution/Types/Library.hs @@ -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) diff --git a/Cabal/Distribution/Types/TestSuite.hs b/Cabal/Distribution/Types/TestSuite.hs index 27f415cdf37..df33e1e4dba 100644 --- a/Cabal/Distribution/Types/TestSuite.hs +++ b/Cabal/Distribution/Types/TestSuite.hs @@ -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) diff --git a/Cabal/changelog b/Cabal/changelog index a64f00da3e6..30eadaa4041 100644 --- a/Cabal/changelog +++ b/Cabal/changelog @@ -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 March 2016 * Support GHC 8. diff --git a/Cabal/doc/developing-packages.markdown b/Cabal/doc/developing-packages.markdown index 7bfcc6bcbdc..932384fd6b6 100644 --- a/Cabal/doc/developing-packages.markdown +++ b/Cabal/doc/developing-packages.markdown @@ -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 diff --git a/Cabal/tests/PackageTests/AutogenModules/Package/Check.hs b/Cabal/tests/PackageTests/AutogenModules/Package/Check.hs new file mode 100644 index 00000000000..652bf372c86 --- /dev/null +++ b/Cabal/tests/PackageTests/AutogenModules/Package/Check.hs @@ -0,0 +1,51 @@ +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 () diff --git a/Cabal/tests/PackageTests/AutogenModules/Package/Dummy.hs b/Cabal/tests/PackageTests/AutogenModules/Package/Dummy.hs new file mode 100644 index 00000000000..2e87d262bd1 --- /dev/null +++ b/Cabal/tests/PackageTests/AutogenModules/Package/Dummy.hs @@ -0,0 +1,4 @@ +module Dummy where + +main :: IO () +main = error "" diff --git a/Cabal/tests/PackageTests/AutogenModules/Package/LICENSE b/Cabal/tests/PackageTests/AutogenModules/Package/LICENSE new file mode 100644 index 00000000000..6b1d0bfabc3 --- /dev/null +++ b/Cabal/tests/PackageTests/AutogenModules/Package/LICENSE @@ -0,0 +1 @@ +LICENSE diff --git a/Cabal/tests/PackageTests/AutogenModules/Package/MyBenchModule.hs b/Cabal/tests/PackageTests/AutogenModules/Package/MyBenchModule.hs new file mode 100644 index 00000000000..a27eb85951e --- /dev/null +++ b/Cabal/tests/PackageTests/AutogenModules/Package/MyBenchModule.hs @@ -0,0 +1,4 @@ +module MyBenchModule where + +main :: IO () +main = error "" diff --git a/Cabal/tests/PackageTests/AutogenModules/Package/MyExeModule.hs b/Cabal/tests/PackageTests/AutogenModules/Package/MyExeModule.hs new file mode 100644 index 00000000000..d1f79ce0c83 --- /dev/null +++ b/Cabal/tests/PackageTests/AutogenModules/Package/MyExeModule.hs @@ -0,0 +1,4 @@ +module MyExeModule where + +main :: IO () +main = error "" diff --git a/Cabal/tests/PackageTests/AutogenModules/Package/MyLibModule.hs b/Cabal/tests/PackageTests/AutogenModules/Package/MyLibModule.hs new file mode 100644 index 00000000000..4bba184d1db --- /dev/null +++ b/Cabal/tests/PackageTests/AutogenModules/Package/MyLibModule.hs @@ -0,0 +1,4 @@ +module MyLibModule where + +main :: IO () +main = error "" diff --git a/Cabal/tests/PackageTests/AutogenModules/Package/MyLibrary.hs b/Cabal/tests/PackageTests/AutogenModules/Package/MyLibrary.hs new file mode 100644 index 00000000000..e8af803726e --- /dev/null +++ b/Cabal/tests/PackageTests/AutogenModules/Package/MyLibrary.hs @@ -0,0 +1,4 @@ +module MyLibrary where + +main :: IO () +main = error "" diff --git a/Cabal/tests/PackageTests/AutogenModules/Package/MyTestModule.hs b/Cabal/tests/PackageTests/AutogenModules/Package/MyTestModule.hs new file mode 100644 index 00000000000..95c94a93184 --- /dev/null +++ b/Cabal/tests/PackageTests/AutogenModules/Package/MyTestModule.hs @@ -0,0 +1,4 @@ +module MyTestModule where + +main :: IO () +main = error "" diff --git a/Cabal/tests/PackageTests/AutogenModules/Package/my.cabal b/Cabal/tests/PackageTests/AutogenModules/Package/my.cabal new file mode 100644 index 00000000000..ff5f42ca4d9 --- /dev/null +++ b/Cabal/tests/PackageTests/AutogenModules/Package/my.cabal @@ -0,0 +1,60 @@ +name: AutogenModules +version: 0.1 +license: BSD3 +license-file: LICENSE +author: Federico Mastellone +maintainer: Federico Mastellone +synopsis: AutogenModules +category: PackageTests +build-type: Simple +cabal-version: >= 1.25 + +description: + Check that Cabal recognizes the autogen-modules fields below. + +Library + default-language: Haskell2010 + build-depends: base + exposed-modules: + MyLibrary + Paths_AutogenModules + MyLibHelperModule + other-modules: + MyLibModule + autogen-modules: + MyHelperModule + +Executable Exe + default-language: Haskell2010 + main-is: Dummy.hs + build-depends: base + other-modules: + MyExeModule + Paths_AutogenModules + MyExeHelperModule + autogen-modules: + MyHelperModule + +Test-Suite Test + default-language: Haskell2010 + main-is: Dummy.hs + type: exitcode-stdio-1.0 + build-depends: base + other-modules: + MyTestModule + Paths_AutogenModules + MyTestHelperModule + autogen-modules: + MyHelperModule + +Benchmark Bench + default-language: Haskell2010 + main-is: Dummy.hs + type: exitcode-stdio-1.0 + build-depends: base + other-modules: + MyBenchModule + Paths_AutogenModules + MyBenchHelperModule + autogen-modules: + MyHelperModule diff --git a/Cabal/tests/PackageTests/AutogenModules/Package/tmp b/Cabal/tests/PackageTests/AutogenModules/Package/tmp new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Cabal/tests/PackageTests/AutogenModules/SrcDist/Check.hs b/Cabal/tests/PackageTests/AutogenModules/SrcDist/Check.hs new file mode 100644 index 00000000000..cfaae18173e --- /dev/null +++ b/Cabal/tests/PackageTests/AutogenModules/SrcDist/Check.hs @@ -0,0 +1,104 @@ +module PackageTests.AutogenModules.SrcDist.Check where + +import Distribution.ModuleName +import Distribution.Simple.LocalBuildInfo +import Distribution.PackageDescription +import PackageTests.PackageTester + +suite :: TestM () +suite = do + + dist_dir <- distDir + + -- Calling sdist without running configure first makes test fail with: + -- "Exception: Run the 'configure' command first." + -- This is becuase we are calling getPersistBuildConfig + + configureResult <- cabal' "configure" [] + sdistResult <- cabal' "sdist" [] + + -- Now check that all the correct modules were parsed. + lbi <- liftIO $ getPersistBuildConfig dist_dir + let (Just gotLibrary) = library (localPkgDescr lbi) + let gotExecutable = head $ executables (localPkgDescr lbi) + let gotTestSuite = head $ testSuites (localPkgDescr lbi) + let gotBenchmark = head $ benchmarks (localPkgDescr lbi) + assertEqual "library 'autogen-modules' field does not match expected" + [fromString "MyLibHelperModule"] + (libModulesAutogen gotLibrary) + assertEqual "executable 'autogen-modules' field does not match expected" + [fromString "MyExeHelperModule"] + (exeModulesAutogen gotExecutable) + assertEqual "test-suite 'autogen-modules' field does not match expected" + [fromString "MyTestHelperModule"] + (testModulesAutogen gotTestSuite) + assertEqual "benchmark 'autogen-modules' field does not match expected" + [fromString "MyBenchHelperModule"] + (benchmarkModulesAutogen gotBenchmark) + + -- 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 undesired check messages after configure. + assertOutputDoesNotContain libAutogenMsg configureResult + assertOutputDoesNotContain exeAutogenMsg configureResult + assertOutputDoesNotContain testAutogenMsg configureResult + assertOutputDoesNotContain benchAutogenMsg configureResult + assertOutputDoesNotContain pathsAutogenMsg configureResult + + -- Asserts for the undesired check messages after sdist. + assertOutputDoesNotContain "Distribution quality errors:" sdistResult + assertOutputDoesNotContain libAutogenMsg sdistResult + assertOutputDoesNotContain exeAutogenMsg sdistResult + assertOutputDoesNotContain testAutogenMsg sdistResult + assertOutputDoesNotContain benchAutogenMsg sdistResult + assertOutputDoesNotContain "Distribution quality warnings:" sdistResult + assertOutputDoesNotContain pathsAutogenMsg sdistResult + + -- Assert sdist --list-sources output. + -- If called before configure fails, dist directory is not created. + let listSourcesFileGot = dist_dir ++ "/" ++ "list-sources.txt" + cabal "sdist" ["--list-sources=" ++ listSourcesFileGot] + let listSourcesStrExpected = +#if defined(mingw32_HOST_OS) + ".\\MyLibrary.hs\n" + ++ ".\\MyLibModule.hs\n" + ++ ".\\Dummy.hs\n" + ++ ".\\MyExeModule.hs\n" + ++ ".\\Dummy.hs\n" + ++ ".\\MyTestModule.hs\n" + ++ ".\\Dummy.hs\n" + ++ ".\\MyBenchModule.hs\n" + ++ "LICENSE\n" + ++ ".\\my.cabal\n" +#else + "./MyLibrary.hs\n" + ++ "./MyLibModule.hs\n" + ++ "./Dummy.hs\n" + ++ "./MyExeModule.hs\n" + ++ "./Dummy.hs\n" + ++ "./MyTestModule.hs\n" + ++ "./Dummy.hs\n" + ++ "./MyBenchModule.hs\n" + ++ "LICENSE\n" + ++ "./my.cabal\n" +#endif + listSourcesStrGot <- liftIO $ readFile listSourcesFileGot + assertEqual "sdist --list-sources does not match the expected files" + listSourcesStrExpected + listSourcesStrGot + + return () diff --git a/Cabal/tests/PackageTests/AutogenModules/SrcDist/Dummy.hs b/Cabal/tests/PackageTests/AutogenModules/SrcDist/Dummy.hs new file mode 100644 index 00000000000..2e87d262bd1 --- /dev/null +++ b/Cabal/tests/PackageTests/AutogenModules/SrcDist/Dummy.hs @@ -0,0 +1,4 @@ +module Dummy where + +main :: IO () +main = error "" diff --git a/Cabal/tests/PackageTests/AutogenModules/SrcDist/LICENSE b/Cabal/tests/PackageTests/AutogenModules/SrcDist/LICENSE new file mode 100644 index 00000000000..6b1d0bfabc3 --- /dev/null +++ b/Cabal/tests/PackageTests/AutogenModules/SrcDist/LICENSE @@ -0,0 +1 @@ +LICENSE diff --git a/Cabal/tests/PackageTests/AutogenModules/SrcDist/MyBenchModule.hs b/Cabal/tests/PackageTests/AutogenModules/SrcDist/MyBenchModule.hs new file mode 100644 index 00000000000..a27eb85951e --- /dev/null +++ b/Cabal/tests/PackageTests/AutogenModules/SrcDist/MyBenchModule.hs @@ -0,0 +1,4 @@ +module MyBenchModule where + +main :: IO () +main = error "" diff --git a/Cabal/tests/PackageTests/AutogenModules/SrcDist/MyExeModule.hs b/Cabal/tests/PackageTests/AutogenModules/SrcDist/MyExeModule.hs new file mode 100644 index 00000000000..d1f79ce0c83 --- /dev/null +++ b/Cabal/tests/PackageTests/AutogenModules/SrcDist/MyExeModule.hs @@ -0,0 +1,4 @@ +module MyExeModule where + +main :: IO () +main = error "" diff --git a/Cabal/tests/PackageTests/AutogenModules/SrcDist/MyLibModule.hs b/Cabal/tests/PackageTests/AutogenModules/SrcDist/MyLibModule.hs new file mode 100644 index 00000000000..4bba184d1db --- /dev/null +++ b/Cabal/tests/PackageTests/AutogenModules/SrcDist/MyLibModule.hs @@ -0,0 +1,4 @@ +module MyLibModule where + +main :: IO () +main = error "" diff --git a/Cabal/tests/PackageTests/AutogenModules/SrcDist/MyLibrary.hs b/Cabal/tests/PackageTests/AutogenModules/SrcDist/MyLibrary.hs new file mode 100644 index 00000000000..e8af803726e --- /dev/null +++ b/Cabal/tests/PackageTests/AutogenModules/SrcDist/MyLibrary.hs @@ -0,0 +1,4 @@ +module MyLibrary where + +main :: IO () +main = error "" diff --git a/Cabal/tests/PackageTests/AutogenModules/SrcDist/MyTestModule.hs b/Cabal/tests/PackageTests/AutogenModules/SrcDist/MyTestModule.hs new file mode 100644 index 00000000000..95c94a93184 --- /dev/null +++ b/Cabal/tests/PackageTests/AutogenModules/SrcDist/MyTestModule.hs @@ -0,0 +1,4 @@ +module MyTestModule where + +main :: IO () +main = error "" diff --git a/Cabal/tests/PackageTests/AutogenModules/SrcDist/list-sources.txt b/Cabal/tests/PackageTests/AutogenModules/SrcDist/list-sources.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Cabal/tests/PackageTests/AutogenModules/SrcDist/my.cabal b/Cabal/tests/PackageTests/AutogenModules/SrcDist/my.cabal new file mode 100644 index 00000000000..75b2d43eebb --- /dev/null +++ b/Cabal/tests/PackageTests/AutogenModules/SrcDist/my.cabal @@ -0,0 +1,60 @@ +name: AutogenModules +version: 0.1 +license: BSD3 +license-file: LICENSE +author: Federico Mastellone +maintainer: Federico Mastellone +synopsis: AutogenModules +category: PackageTests +build-type: Simple +cabal-version: >= 1.24 + +description: + Check that Cabal recognizes the autogen-modules fields below. + +Library + default-language: Haskell2010 + build-depends: base + exposed-modules: + MyLibrary + Paths_AutogenModules + MyLibHelperModule + other-modules: + MyLibModule + autogen-modules: + MyLibHelperModule + +Executable Exe + default-language: Haskell2010 + main-is: Dummy.hs + build-depends: base + other-modules: + MyExeModule + Paths_AutogenModules + MyExeHelperModule + autogen-modules: + MyExeHelperModule + +Test-Suite Test + default-language: Haskell2010 + main-is: Dummy.hs + type: exitcode-stdio-1.0 + build-depends: base + other-modules: + MyTestModule + Paths_AutogenModules + MyTestHelperModule + autogen-modules: + MyTestHelperModule + +Benchmark Bench + default-language: Haskell2010 + main-is: Dummy.hs + type: exitcode-stdio-1.0 + build-depends: base + other-modules: + MyBenchModule + Paths_AutogenModules + MyBenchHelperModule + autogen-modules: + MyBenchHelperModule diff --git a/Cabal/tests/PackageTests/Tests.hs b/Cabal/tests/PackageTests/Tests.hs index 9ec1f388c18..9ebe68fbfb3 100644 --- a/Cabal/tests/PackageTests/Tests.hs +++ b/Cabal/tests/PackageTests/Tests.hs @@ -2,6 +2,8 @@ module PackageTests.Tests(tests) where import PackageTests.PackageTester +import qualified PackageTests.AutogenModules.Package.Check +import qualified PackageTests.AutogenModules.SrcDist.Check import qualified PackageTests.BenchmarkStanza.Check import qualified PackageTests.TestStanza.Check import qualified PackageTests.DeterministicAr.Check @@ -40,6 +42,11 @@ tests config = do -- Test that Cabal determinstically generates object archives tc "DeterministicAr" PackageTests.DeterministicAr.Check.suite + -- Test that cabal shows all the 'autogen-modules' warnings. + tc "AutogenModules/Package" PackageTests.AutogenModules.Package.Check.suite + -- Test that Cabal parses and uses 'autogen-modules' fields correctly + tc "AutogenModules/SrcDist" PackageTests.AutogenModules.SrcDist.Check.suite + --------------------------------------------------------------------- -- * Test suite tests