diff --git a/Cabal/src/Distribution/Simple/GHC/Build.hs b/Cabal/src/Distribution/Simple/GHC/Build.hs
index 1f88f07552bf976e4f120bfaaaa288c5adcb050c..f62cdcf8b665b5ebdeefa54af067852ae0a5eea9 100644
--- a/Cabal/src/Distribution/Simple/GHC/Build.hs
+++ b/Cabal/src/Distribution/Simple/GHC/Build.hs
@@ -12,11 +12,14 @@ import Distribution.Simple.Flag (Flag)
 import Distribution.Simple.GHC.Build.ExtraSources
 import Distribution.Simple.GHC.Build.Link
 import Distribution.Simple.GHC.Build.Modules
+import Distribution.Simple.GHC.Build.Utils (isHaskell)
 import Distribution.Simple.LocalBuildInfo
 import Distribution.Simple.Program.Builtin (ghcProgram)
 import Distribution.Simple.Program.Db (requireProgram)
 import Distribution.Simple.Utils
+
 import Distribution.Types.ComponentLocalBuildInfo
+import Distribution.Types.PackageName.Magic (fakePackageId)
 import Distribution.Types.ParStrat
 import Distribution.Utils.NubList (fromNubListR)
 import Distribution.Utils.Path
@@ -114,8 +117,18 @@ build numJobs pkg_descr pbci = do
   -- We need a separate build and link phase, and C sources must be compiled
   -- after Haskell modules, because C sources may depend on stub headers
   -- generated from compiling Haskell modules (#842, #3294).
-  buildOpts <- buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir (wantedLibWays isIndef) pbci
-  extraSources <- buildAllExtraSources ghcProg buildTargetDir wantedWays pbci
+  (mbMainFile, inputModules) <- componentInputs buildTargetDir pkg_descr pbci
+  let (hsMainFile, nonHsMainFile) =
+        case mbMainFile of
+          Just mainFile
+            | PD.package pkg_descr == fakePackageId
+                || isHaskell (getSymbolicPath mainFile) ->
+                (Just mainFile, Nothing)
+            | otherwise ->
+                (Nothing, Just mainFile)
+          Nothing -> (Nothing, Nothing)
+  buildOpts <- buildHaskellModules numJobs ghcProg hsMainFile inputModules buildTargetDir (wantedLibWays isIndef) pbci
+  extraSources <- buildAllExtraSources nonHsMainFile ghcProg buildTargetDir wantedWays pbci
   linkOrLoadComponent
     ghcProg
     pkg_descr
diff --git a/Cabal/src/Distribution/Simple/GHC/Build/ExtraSources.hs b/Cabal/src/Distribution/Simple/GHC/Build/ExtraSources.hs
index 83bcf9a6bca30e92a802a509a91e63d2a29ee139..31aa92a3b2a92fbd4fd4453bddbd29df1716b8be 100644
--- a/Cabal/src/Distribution/Simple/GHC/Build/ExtraSources.hs
+++ b/Cabal/src/Distribution/Simple/GHC/Build/ExtraSources.hs
@@ -25,14 +25,15 @@ import Distribution.Simple.LocalBuildInfo
 import Distribution.Simple.Program.Types
 import Distribution.System (Arch (JavaScript), Platform (..))
 import Distribution.Types.ComponentLocalBuildInfo
-import Distribution.Types.Executable
 import Distribution.Utils.Path
 import Distribution.Verbosity (Verbosity)
 
 -- | An action that builds all the extra build sources of a component, i.e. C,
 -- C++, Js, Asm, C-- sources.
 buildAllExtraSources
-  :: ConfiguredProgram
+  :: Maybe (SymbolicPath Pkg File)
+  -- ^ An optional non-Haskell Main file
+  -> ConfiguredProgram
   -- ^ The GHC configured program
   -> SymbolicPath Pkg (Dir Artifacts)
   -- ^ The build directory for this target
@@ -56,7 +57,9 @@ buildCSources
   , buildJsSources
   , buildAsmSources
   , buildCmmSources
-    :: ConfiguredProgram
+    :: Maybe (SymbolicPath Pkg File)
+    -- ^ An optional non-Haskell Main file
+    -> ConfiguredProgram
     -- ^ The GHC configured program
     -> SymbolicPath Pkg (Dir Artifacts)
     -- ^ The build directory for this target
@@ -66,37 +69,33 @@ buildCSources
     -- ^ The context and component being built in it.
     -> IO (NubListR (SymbolicPath Pkg File))
     -- ^ Returns the list of extra sources that were built
-buildCSources =
+buildCSources mbMainFile =
   buildExtraSources
     "C Sources"
     Internal.componentCcGhcOptions
     ( \c -> do
         let cFiles = cSources (componentBuildInfo c)
         case c of
-          CExe exe
-            | let mainPath = getSymbolicPath $ modulePath exe
-            , isC mainPath ->
-                cFiles ++ [makeSymbolicPath mainPath]
-          -- NB: Main.hs is relative to hs-source-dirs, but Main.c
-          -- is relative to the package.
+          CExe{}
+            | Just main <- mbMainFile
+            , isC $ getSymbolicPath main ->
+                cFiles ++ [main]
           _otherwise -> cFiles
     )
-buildCxxSources =
+buildCxxSources mbMainFile =
   buildExtraSources
     "C++ Sources"
     Internal.componentCxxGhcOptions
     ( \c -> do
         let cxxFiles = cxxSources (componentBuildInfo c)
         case c of
-          CExe exe
-            | let mainPath = getSymbolicPath $ modulePath exe
-            , isCxx mainPath ->
-                do cxxFiles ++ [makeSymbolicPath mainPath]
-          -- NB: Main.hs is relative to hs-source-dirs, but Main.c++
-          -- is relative to the package.
+          CExe{}
+            | Just main <- mbMainFile
+            , isCxx $ getSymbolicPath main ->
+                cxxFiles ++ [main]
           _otherwise -> cxxFiles
     )
-buildJsSources ghcProg buildTargetDir neededWays = do
+buildJsSources _mbMainFile ghcProg buildTargetDir neededWays = do
   Platform hostArch _ <- hostPlatform <$> localBuildInfo
   let hasJsSupport = hostArch == JavaScript
   buildExtraSources
@@ -114,12 +113,12 @@ buildJsSources ghcProg buildTargetDir neededWays = do
     ghcProg
     buildTargetDir
     neededWays
-buildAsmSources =
+buildAsmSources _mbMainFile =
   buildExtraSources
     "Assembler Sources"
     Internal.componentAsmGhcOptions
     (asmSources . componentBuildInfo)
-buildCmmSources =
+buildCmmSources _mbMainFile =
   buildExtraSources
     "C-- Sources"
     Internal.componentCmmGhcOptions
diff --git a/Cabal/src/Distribution/Simple/GHC/Build/Modules.hs b/Cabal/src/Distribution/Simple/GHC/Build/Modules.hs
index 0c89d860a1bfe049f1013de877834946f3c8bea5..2e8ba35ccb6743cd6a955a8d70ad014e7d271497 100644
--- a/Cabal/src/Distribution/Simple/GHC/Build/Modules.hs
+++ b/Cabal/src/Distribution/Simple/GHC/Build/Modules.hs
@@ -5,7 +5,12 @@
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE TupleSections #-}
 
-module Distribution.Simple.GHC.Build.Modules (buildHaskellModules, BuildWay (..), buildWayPrefix) where
+module Distribution.Simple.GHC.Build.Modules
+  ( buildHaskellModules
+  , BuildWay (..)
+  , buildWayPrefix
+  , componentInputs
+  ) where
 
 import Control.Monad.IO.Class
 import Distribution.Compat.Prelude
@@ -98,8 +103,10 @@ buildHaskellModules
   -- ^ The parallelism strategy (e.g. num of jobs)
   -> ConfiguredProgram
   -- ^ The GHC configured program
-  -> PD.PackageDescription
-  -- ^ The package description
+  -> Maybe (SymbolicPath Pkg File)
+  -- ^ Optional path to a Haskell Main file to build
+  -> [ModuleName]
+  -- ^ The Haskell modules to build
   -> SymbolicPath Pkg ('Dir Artifacts)
   -- ^ The path to the build directory for this target, which
   -- has already been created.
@@ -112,7 +119,7 @@ buildHaskellModules
   -- invocation used to compile the component in that 'BuildWay'.
   -- This can be useful in, eg, a linker invocation, in which we want to use the
   -- same options and list the same inputs as those used for building.
-buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir neededLibWays pbci = do
+buildHaskellModules numJobs ghcProg mbMainFile inputModules buildTargetDir neededLibWays pbci = do
   -- See Note [Building Haskell Modules accounting for TH]
 
   let
@@ -141,13 +148,14 @@ buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir neededLibWays pbci
         | isCoverageEnabled = Flag $ Hpc.mixDir (coerceSymbolicPath $ coerceSymbolicPath buildTargetDir </> extraCompilationArtifacts) way
         | otherwise = mempty
 
-  (inputFiles, inputModules) <- componentInputs buildTargetDir pkg_descr pbci
-
   let
     mbWorkDir = mbWorkDirLBI lbi
     runGhcProg = runGHC verbosity ghcProg comp platform mbWorkDir
     platform = hostPlatform lbi
 
+    (hsMains, scriptMains) =
+      partition (isHaskell . getSymbolicPath) (maybeToList mbMainFile)
+
     -- We define the base opts which are shared across different build ways in
     -- 'buildHaskellModules'
     baseOpts way =
@@ -161,16 +169,8 @@ buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir neededLibWays pbci
             ghcOptNoLink = if isLib then NoFlag else toFlag True
           , ghcOptNumJobs = numJobs
           , ghcOptInputModules = toNubListR inputModules
-          , ghcOptInputFiles =
-              toNubListR $
-                if PD.package pkg_descr == fakePackageId
-                  then filter (isHaskell . getSymbolicPath) inputFiles
-                  else inputFiles
-          , ghcOptInputScripts =
-              toNubListR $
-                if PD.package pkg_descr == fakePackageId
-                  then filter (not . isHaskell . getSymbolicPath) inputFiles
-                  else []
+          , ghcOptInputFiles = toNubListR hsMains
+          , ghcOptInputScripts = toNubListR scriptMains
           , ghcOptExtra = buildWayExtraHcOptions way GHC bi
           , ghcOptHiSuffix = optSuffixFlag (buildWayPrefix way) "hi"
           , ghcOptObjSuffix = optSuffixFlag (buildWayPrefix way) "o"
@@ -248,7 +248,7 @@ buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir neededLibWays pbci
       ProfDynWay -> profDynOpts
 
   -- If there aren't modules, or if we're loading the modules in repl, don't build.
-  unless (forRepl || (null inputFiles && null inputModules)) $ liftIO $ do
+  unless (forRepl || (isNothing mbMainFile && null inputModules)) $ liftIO $ do
     -- See Note [Building Haskell Modules accounting for TH]
     let
       neededLibWaysSet = Set.fromList neededLibWays
@@ -348,25 +348,26 @@ buildWayExtraHcOptions = \case
   DynWay -> hcSharedOptions
   ProfDynWay -> hcProfSharedOptions
 
--- | Returns a pair of the Haskell input files and Haskell modules of the
--- component being built.
+-- | Returns a pair of the main file and Haskell modules of the component being
+-- built. The main file is not necessarily a Haskell file. It could also be
+-- e.g. a C source, or, a Haskell repl script (that does not necessarily have
+-- an extension).
 --
--- The "input files" are either the path to the main Haskell module, or a repl
--- script (that does not necessarily have an extension).
+-- The main file is Nothing if the component is not executable.
 componentInputs
   :: SymbolicPath Pkg (Dir Artifacts)
   -- ^ Target build dir
   -> PD.PackageDescription
   -> PreBuildComponentInputs
   -- ^ The context and component being built in it.
-  -> IO ([SymbolicPath Pkg File], [ModuleName])
-  -- ^ The Haskell input files, and the Haskell modules
+  -> IO (Maybe (SymbolicPath Pkg File), [ModuleName])
+  -- ^ The main input file, and the Haskell modules
 componentInputs buildTargetDir pkg_descr pbci =
   case component of
     CLib lib ->
-      pure ([], allLibModules lib clbi)
+      pure (Nothing, allLibModules lib clbi)
     CFLib flib ->
-      pure ([], foreignLibModules flib)
+      pure (Nothing, foreignLibModules flib)
     CExe Executable{buildInfo = bi', modulePath} ->
       exeLikeInputs bi' modulePath
     CTest TestSuite{testBuildInfo = bi', testInterface = TestSuiteExeV10 _ mainFile} ->
@@ -405,6 +406,6 @@ componentInputs buildTargetDir pkg_descr pbci =
                 "Enabling workaround for Main module '"
                   ++ prettyShow mainModName
                   ++ "' listed in 'other-modules' illegally!"
-              return ([main], filter (/= mainModName) otherModNames)
-            else return ([main], otherModNames)
-        else return ([], otherModNames)
+              return (Just main, filter (/= mainModName) otherModNames)
+            else return (Just main, otherModNames)
+        else return (Just main, otherModNames)
diff --git a/Cabal/src/Distribution/Simple/GHC/Build/Utils.hs b/Cabal/src/Distribution/Simple/GHC/Build/Utils.hs
index c87d074c2020ae0756239417791a36832640b44d..e61fc50c9c4c8d5a04179033dba32ff331404f97 100644
--- a/Cabal/src/Distribution/Simple/GHC/Build/Utils.hs
+++ b/Cabal/src/Distribution/Simple/GHC/Build/Utils.hs
@@ -31,7 +31,7 @@ import System.FilePath
   )
 
 -- | Find the path to the entry point of an executable (typically specified in
--- @main-is@, and found in @hs-source-dirs@).
+-- @main-is@, and found in @hs-source-dirs@ -- yes, even when @main-is@ is not a Haskell file).
 findExecutableMain
   :: Verbosity
   -> Maybe (SymbolicPath CWD (Dir Pkg))
diff --git a/cabal-testsuite/PackageTests/CMain/10168/Setup.hs b/cabal-testsuite/PackageTests/CMain/10168/Setup.hs
new file mode 100644
index 0000000000000000000000000000000000000000..9a994af677b0dfd41b4e3b76b3e7e604003d64e1
--- /dev/null
+++ b/cabal-testsuite/PackageTests/CMain/10168/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/cabal-testsuite/PackageTests/CMain/10168/app/Main.hs b/cabal-testsuite/PackageTests/CMain/10168/app/Main.hs
new file mode 100644
index 0000000000000000000000000000000000000000..718f1d5a74c9884c42aa11f14ebd2907cd21819f
--- /dev/null
+++ b/cabal-testsuite/PackageTests/CMain/10168/app/Main.hs
@@ -0,0 +1,6 @@
+module Main ( main ) where
+
+import Lib ( myMax )
+
+main :: IO ()
+main = print $ myMax 10 100
diff --git a/cabal-testsuite/PackageTests/CMain/10168/c-app/main.c b/cabal-testsuite/PackageTests/CMain/10168/c-app/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..2cf1d456e33186f4cb94d4b18fcce5f5cfb839a1
--- /dev/null
+++ b/cabal-testsuite/PackageTests/CMain/10168/c-app/main.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <HsFFI.h>
+#ifdef __GLASGOW_HASKELL__
+#include "Lib_stub.h"
+#endif
+
+int main(int argc, char *argv[]) {
+  hs_init(&argc, &argv);
+  printf("%lld\n", myMax(10,100));
+  hs_exit();
+  return 0;
+}
diff --git a/cabal-testsuite/PackageTests/CMain/10168/haskell-c-tests.cabal b/cabal-testsuite/PackageTests/CMain/10168/haskell-c-tests.cabal
new file mode 100644
index 0000000000000000000000000000000000000000..9f5f9e1dff2f99ea0bb068ea71e777746d267485
--- /dev/null
+++ b/cabal-testsuite/PackageTests/CMain/10168/haskell-c-tests.cabal
@@ -0,0 +1,27 @@
+cabal-version: 2.0
+
+name:           haskell-c-tests
+version:        0.1.0.0
+build-type:     Simple
+
+library
+  exposed-modules: Lib
+  hs-source-dirs: src
+  ghc-options: -stubdir autogen-stubs
+  build-depends: base
+  default-language: Haskell2010
+
+executable c-exe
+  main-is: main.c
+  hs-source-dirs: c-app
+  ghc-options: -no-hs-main
+  include-dirs: autogen-stubs
+  build-depends: base, haskell-c-tests
+  default-language: Haskell2010
+
+executable haskell-exe
+  main-is: Main.hs
+  hs-source-dirs: app
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N
+  build-depends: base, haskell-c-tests
+  default-language: Haskell2010
diff --git a/cabal-testsuite/PackageTests/CMain/10168/setup.out b/cabal-testsuite/PackageTests/CMain/10168/setup.out
new file mode 100644
index 0000000000000000000000000000000000000000..bb075774c776ff35a62e60dee6434862111f12cc
--- /dev/null
+++ b/cabal-testsuite/PackageTests/CMain/10168/setup.out
@@ -0,0 +1,10 @@
+# Setup configure
+Configuring haskell-c-tests-0.1.0.0...
+Warning: [unknown-directory] 'include-dirs: autogen-stubs' specifies a directory which does not exist.
+# Setup build
+Preprocessing library for haskell-c-tests-0.1.0.0...
+Building library for haskell-c-tests-0.1.0.0...
+Preprocessing executable 'c-exe' for haskell-c-tests-0.1.0.0...
+Building executable 'c-exe' for haskell-c-tests-0.1.0.0...
+Preprocessing executable 'haskell-exe' for haskell-c-tests-0.1.0.0...
+Building executable 'haskell-exe' for haskell-c-tests-0.1.0.0...
diff --git a/cabal-testsuite/PackageTests/CMain/10168/setup.test.hs b/cabal-testsuite/PackageTests/CMain/10168/setup.test.hs
new file mode 100644
index 0000000000000000000000000000000000000000..bcefa0b29bea285b23f2ed37efb7f52bfaab366c
--- /dev/null
+++ b/cabal-testsuite/PackageTests/CMain/10168/setup.test.hs
@@ -0,0 +1,7 @@
+import Test.Cabal.Prelude
+-- Test building an executable whose main-is is a C source found in the hs-source-dirs.
+-- It is a bit counter intuitive that we look for non-haskell sources in
+-- `hs-source-dirs`, but that is a behaviour that users rely on (see #10168)
+-- and there's no good reason to break it.
+main = setupTest $ do
+  setup_build []
diff --git a/cabal-testsuite/PackageTests/CMain/10168/src/Lib.hs b/cabal-testsuite/PackageTests/CMain/10168/src/Lib.hs
new file mode 100644
index 0000000000000000000000000000000000000000..ba1bcce7ab93fa724a0b71696ef22e4f9003e67a
--- /dev/null
+++ b/cabal-testsuite/PackageTests/CMain/10168/src/Lib.hs
@@ -0,0 +1,6 @@
+module Lib ( myMax ) where
+
+myMax :: Int -> Int -> Int
+myMax x1 x2 = if x1 > x2 then x1 else x2
+
+foreign export ccall myMax :: Int -> Int -> Int
diff --git a/cabal-testsuite/PackageTests/CMain/Bar.hs b/cabal-testsuite/PackageTests/CMain/Simple/Bar.hs
similarity index 100%
rename from cabal-testsuite/PackageTests/CMain/Bar.hs
rename to cabal-testsuite/PackageTests/CMain/Simple/Bar.hs
diff --git a/cabal-testsuite/PackageTests/CMain/foo.c b/cabal-testsuite/PackageTests/CMain/Simple/foo.c
similarity index 100%
rename from cabal-testsuite/PackageTests/CMain/foo.c
rename to cabal-testsuite/PackageTests/CMain/Simple/foo.c
diff --git a/cabal-testsuite/PackageTests/CMain/my.cabal b/cabal-testsuite/PackageTests/CMain/Simple/my.cabal
similarity index 100%
rename from cabal-testsuite/PackageTests/CMain/my.cabal
rename to cabal-testsuite/PackageTests/CMain/Simple/my.cabal
diff --git a/cabal-testsuite/PackageTests/CMain/setup.cabal.out b/cabal-testsuite/PackageTests/CMain/Simple/setup.cabal.out
similarity index 100%
rename from cabal-testsuite/PackageTests/CMain/setup.cabal.out
rename to cabal-testsuite/PackageTests/CMain/Simple/setup.cabal.out
diff --git a/cabal-testsuite/PackageTests/CMain/setup.out b/cabal-testsuite/PackageTests/CMain/Simple/setup.out
similarity index 100%
rename from cabal-testsuite/PackageTests/CMain/setup.out
rename to cabal-testsuite/PackageTests/CMain/Simple/setup.out
diff --git a/cabal-testsuite/PackageTests/CMain/setup.test.hs b/cabal-testsuite/PackageTests/CMain/Simple/setup.test.hs
similarity index 100%
rename from cabal-testsuite/PackageTests/CMain/setup.test.hs
rename to cabal-testsuite/PackageTests/CMain/Simple/setup.test.hs