diff --git a/Cabal/src/Distribution/PackageDescription/Check/Paths.hs b/Cabal/src/Distribution/PackageDescription/Check/Paths.hs
index 5b2df1f18fa95ca9c7443f63f63bf70192904571..28e1e3815e2f41d7586a13fbadf8e9a4a7259361 100644
--- a/Cabal/src/Distribution/PackageDescription/Check/Paths.hs
+++ b/Cabal/src/Distribution/PackageDescription/Check/Paths.hs
@@ -10,6 +10,7 @@
module Distribution.PackageDescription.Check.Paths
( checkGlob
, checkPath
+ , checkPackageFileNamesWithGlob
, fileExtensionSupportedLanguage
, isGoodRelativeDirectoryPath
, isGoodRelativeFilePath
diff --git a/Cabal/src/Distribution/PackageDescription/Check/Target.hs b/Cabal/src/Distribution/PackageDescription/Check/Target.hs
index 0bf173cb980b54f84822ba76e815c17c2063150b..9e23b0af91742b7147c4202c4ec63ad662532c30 100644
--- a/Cabal/src/Distribution/PackageDescription/Check/Target.hs
+++ b/Cabal/src/Distribution/PackageDescription/Check/Target.hs
@@ -21,7 +21,7 @@ import Prelude ()
import Distribution.CabalSpecVersion
import Distribution.Compat.Lens
import Distribution.Compiler
-import Distribution.ModuleName (ModuleName)
+import Distribution.ModuleName (ModuleName, toFilePath)
import Distribution.Package
import Distribution.PackageDescription
import Distribution.PackageDescription.Check.Common
@@ -61,6 +61,8 @@ checkLibrary
_libVisibility_
libBuildInfo_
) = do
+ mapM_ checkModuleName (explicitLibModules lib)
+
checkP
(libName_ == LMainLibName && isSub)
(PackageBuildImpossible UnnamedInternal)
@@ -144,6 +146,8 @@ checkExecutable
let cet = CETExecutable exeName_
modulePath_ = getSymbolicPath symbolicModulePath_
+ mapM_ checkModuleName (exeModules exe)
+
-- § Exe specific checks
checkP
(null modulePath_)
@@ -205,6 +209,9 @@ checkTestSuite
TestSuiteUnsupported tt ->
tellP (PackageBuildWarning $ TestsuiteNotSupported tt)
_ -> return ()
+
+ mapM_ checkModuleName (testModules ts)
+
checkP
mainIsWrongExt
(PackageBuildImpossible NoHsLhsMain)
@@ -257,6 +264,8 @@ checkBenchmark
-- Target type/name (benchmark).
let cet = CETBenchmark benchmarkName_
+ mapM_ checkModuleName (benchmarkModules bm)
+
-- § Interface & bm specific tests.
case benchmarkInterface_ of
BenchmarkUnsupported tt@(BenchmarkTypeUnknown _ _) ->
@@ -294,6 +303,11 @@ checkBenchmark
BenchmarkExeV10 _ f -> takeExtension (getSymbolicPath f) `notElem` [".hs", ".lhs"]
_ -> False
+-- | Check if a module name is valid on both Windows and Posix systems
+checkModuleName :: Monad m => ModuleName -> CheckM m ()
+checkModuleName moduleName =
+ checkPackageFileNamesWithGlob PathKindFile (toFilePath moduleName)
+
-- ------------------------------------------------------------
-- Build info
-- ------------------------------------------------------------
diff --git a/cabal-testsuite/PackageTests/Check/InvalidModuleName/InvalidModuleName.cabal b/cabal-testsuite/PackageTests/Check/InvalidModuleName/InvalidModuleName.cabal
new file mode 100644
index 0000000000000000000000000000000000000000..e298eece9b6efd71b7b91a42e5b4f6bccb33adad
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Check/InvalidModuleName/InvalidModuleName.cabal
@@ -0,0 +1,44 @@
+name: InvalidModuleName
+version: 0.1.0.0
+license: BSD3
+license-file: LICENSE
+category: development
+author: Foo Bar
+maintainer: cabal-dev@haskell.org
+build-type: Simple
+cabal-version: >=1.10
+synopsis: Test for invalid module names
+description: Tests that invalid module names are properly rejected by cabal check
+
+library
+ exposed-modules: Aux
+ build-depends: base < 5
+ hs-source-dirs: src
+ default-language: Haskell2010
+
+executable invalid-exe
+ main-is: Main.hs
+ other-modules: Exe.Aux
+ , Exe.Aux.Test
+ build-depends: base < 5
+ hs-source-dirs: exe
+ default-language: Haskell2010
+
+test-suite invalid-test
+ type: exitcode-stdio-1.0
+ main-is: Main.hs
+ other-modules: Test.Aux
+ , Test.Aux.Test
+ build-depends: base < 5
+ hs-source-dirs: test
+ default-language: Haskell2010
+
+benchmark invalid-bench
+ type: exitcode-stdio-1.0
+ main-is: Main.hs
+ other-modules: Bench.Aux
+ , Bench.Aux.Test
+ build-depends: base < 5
+ hs-source-dirs: bench
+ default-language: Haskell2010
+
diff --git a/cabal-testsuite/PackageTests/Check/InvalidModuleName/LICENSE b/cabal-testsuite/PackageTests/Check/InvalidModuleName/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/cabal-testsuite/PackageTests/Check/InvalidModuleName/bench/.file b/cabal-testsuite/PackageTests/Check/InvalidModuleName/bench/.file
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/cabal-testsuite/PackageTests/Check/InvalidModuleName/cabal.out b/cabal-testsuite/PackageTests/Check/InvalidModuleName/cabal.out
new file mode 100644
index 0000000000000000000000000000000000000000..3093fce3d24086ca5d44db03730ac43864fc51ca
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Check/InvalidModuleName/cabal.out
@@ -0,0 +1,10 @@
+# cabal check
+The following errors will cause portability problems on other environments:
+Error: [invalid-path-win] The path 'Aux' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|", and there are a few reserved names including "aux", "nul", "con", "prn", "com{1-9}", "lpt{1-9}" and "clock$".
+Error: [invalid-path-win] The path 'Bench/Aux' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|", and there are a few reserved names including "aux", "nul", "con", "prn", "com{1-9}", "lpt{1-9}" and "clock$".
+Error: [invalid-path-win] The path 'Bench/Aux/Test' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|", and there are a few reserved names including "aux", "nul", "con", "prn", "com{1-9}", "lpt{1-9}" and "clock$".
+Error: [invalid-path-win] The path 'Exe/Aux' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|", and there are a few reserved names including "aux", "nul", "con", "prn", "com{1-9}", "lpt{1-9}" and "clock$".
+Error: [invalid-path-win] The path 'Exe/Aux/Test' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|", and there are a few reserved names including "aux", "nul", "con", "prn", "com{1-9}", "lpt{1-9}" and "clock$".
+Error: [invalid-path-win] The path 'Test/Aux' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|", and there are a few reserved names including "aux", "nul", "con", "prn", "com{1-9}", "lpt{1-9}" and "clock$".
+Error: [invalid-path-win] The path 'Test/Aux/Test' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|", and there are a few reserved names including "aux", "nul", "con", "prn", "com{1-9}", "lpt{1-9}" and "clock$".
+Error: Hackage would reject this package.
diff --git a/cabal-testsuite/PackageTests/Check/InvalidModuleName/cabal.test.hs b/cabal-testsuite/PackageTests/Check/InvalidModuleName/cabal.test.hs
new file mode 100644
index 0000000000000000000000000000000000000000..8756cdecc852fd4234b6fd0efbb74faca0c54983
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Check/InvalidModuleName/cabal.test.hs
@@ -0,0 +1,5 @@
+import Test.Cabal.Prelude
+
+main = cabalTest $
+ fails $ cabal "check" []
+
diff --git a/cabal-testsuite/PackageTests/Check/InvalidModuleName/exe/.file b/cabal-testsuite/PackageTests/Check/InvalidModuleName/exe/.file
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/cabal-testsuite/PackageTests/Check/InvalidModuleName/src/.file b/cabal-testsuite/PackageTests/Check/InvalidModuleName/src/.file
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/cabal-testsuite/PackageTests/Check/InvalidModuleName/test/.file b/cabal-testsuite/PackageTests/Check/InvalidModuleName/test/.file
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/changelog.d/pr-10816.md b/changelog.d/pr-10816.md
new file mode 100644
index 0000000000000000000000000000000000000000..06118ecbb5b08477890131427cc00e9ca4bcc70a
--- /dev/null
+++ b/changelog.d/pr-10816.md
@@ -0,0 +1,23 @@
+synopsis: "Add checks for Windows reserved filenames in module paths"
+packages: Cabal cabal-install
+prs: #10816
+issues: #10295
+
+description: {
+
+On Windows, certain filenames are reserved by the operating system such as
+"aux", "con", "prn", "nul", etc. When these names appear in module paths they
+can cause build failures on Windows systems.
+
+`cabal check` now properly warns about module paths that contain Windows reserved
+filenames, not just filepaths which contain these reserved tokens. These warnings
+are controlled by the existing `invalid-win-path` category.
+
+For example, module paths like:
+- `Exe.Aux.Test`
+- `Test.Aux.Module`
+- `Bench.Aux.Helpers`
+
+will now trigger appropriate warnings during `cabal check`.
+
+}