Skip to content

Commit b98a1b0

Browse files
alt-romessheaf
authored andcommitted
Lookup main-is C sources in hs-source-dirs
In the 2decb0e refactor we stopped looking for non-Haskell `main-is` files in the hs-source-dirs and other appropriate directories. This commit fixes that oversight. Even if it is not intuitive that main-is-C-sources are searched in the hs-source-dirs, we don't wish to break users relying on this behaviour as there does not exist that strong of a motivation to do so. Fixes haskell#10168 Co-authored-by: sheaf <[email protected]>
1 parent 634fba2 commit b98a1b0

File tree

17 files changed

+134
-51
lines changed

17 files changed

+134
-51
lines changed

Cabal/src/Distribution/Simple/GHC/Build.hs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@ import Distribution.Simple.Flag (Flag)
1212
import Distribution.Simple.GHC.Build.ExtraSources
1313
import Distribution.Simple.GHC.Build.Link
1414
import Distribution.Simple.GHC.Build.Modules
15+
import Distribution.Simple.GHC.Build.Utils (isHaskell)
1516
import Distribution.Simple.LocalBuildInfo
1617
import Distribution.Simple.Program.Builtin (ghcProgram)
1718
import Distribution.Simple.Program.Db (requireProgram)
1819
import Distribution.Simple.Utils
20+
1921
import Distribution.Types.ComponentLocalBuildInfo
22+
import Distribution.Types.PackageName.Magic (fakePackageId)
2023
import Distribution.Types.ParStrat
2124
import Distribution.Utils.NubList (fromNubListR)
2225
import Distribution.Utils.Path
@@ -114,8 +117,18 @@ build numJobs pkg_descr pbci = do
114117
-- We need a separate build and link phase, and C sources must be compiled
115118
-- after Haskell modules, because C sources may depend on stub headers
116119
-- generated from compiling Haskell modules (#842, #3294).
117-
buildOpts <- buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir (wantedLibWays isIndef) pbci
118-
extraSources <- buildAllExtraSources ghcProg buildTargetDir wantedWays pbci
120+
(mbMainFile, inputModules) <- componentInputs buildTargetDir pkg_descr pbci
121+
let (hsMainFile, nonHsMainFile) =
122+
case mbMainFile of
123+
Just mainFile
124+
| PD.package pkg_descr == fakePackageId
125+
|| isHaskell (getSymbolicPath mainFile) ->
126+
(Just mainFile, Nothing)
127+
| otherwise ->
128+
(Nothing, Just mainFile)
129+
Nothing -> (Nothing, Nothing)
130+
buildOpts <- buildHaskellModules numJobs ghcProg hsMainFile inputModules buildTargetDir (wantedLibWays isIndef) pbci
131+
extraSources <- buildAllExtraSources nonHsMainFile ghcProg buildTargetDir wantedWays pbci
119132
linkOrLoadComponent
120133
ghcProg
121134
pkg_descr

Cabal/src/Distribution/Simple/GHC/Build/ExtraSources.hs

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,15 @@ import Distribution.Simple.LocalBuildInfo
2525
import Distribution.Simple.Program.Types
2626
import Distribution.System (Arch (JavaScript), Platform (..))
2727
import Distribution.Types.ComponentLocalBuildInfo
28-
import Distribution.Types.Executable
2928
import Distribution.Utils.Path
3029
import Distribution.Verbosity (Verbosity)
3130

3231
-- | An action that builds all the extra build sources of a component, i.e. C,
3332
-- C++, Js, Asm, C-- sources.
3433
buildAllExtraSources
35-
:: ConfiguredProgram
34+
:: Maybe (SymbolicPath Pkg File)
35+
-- ^ An optional non-Haskell Main file
36+
-> ConfiguredProgram
3637
-- ^ The GHC configured program
3738
-> SymbolicPath Pkg (Dir Artifacts)
3839
-- ^ The build directory for this target
@@ -56,7 +57,9 @@ buildCSources
5657
, buildJsSources
5758
, buildAsmSources
5859
, buildCmmSources
59-
:: ConfiguredProgram
60+
:: Maybe (SymbolicPath Pkg File)
61+
-- ^ An optional non-Haskell Main file
62+
-> ConfiguredProgram
6063
-- ^ The GHC configured program
6164
-> SymbolicPath Pkg (Dir Artifacts)
6265
-- ^ The build directory for this target
@@ -66,37 +69,33 @@ buildCSources
6669
-- ^ The context and component being built in it.
6770
-> IO (NubListR (SymbolicPath Pkg File))
6871
-- ^ Returns the list of extra sources that were built
69-
buildCSources =
72+
buildCSources mbMainFile =
7073
buildExtraSources
7174
"C Sources"
7275
Internal.componentCcGhcOptions
7376
( \c -> do
7477
let cFiles = cSources (componentBuildInfo c)
7578
case c of
76-
CExe exe
77-
| let mainPath = getSymbolicPath $ modulePath exe
78-
, isC mainPath ->
79-
cFiles ++ [makeSymbolicPath mainPath]
80-
-- NB: Main.hs is relative to hs-source-dirs, but Main.c
81-
-- is relative to the package.
79+
CExe{}
80+
| Just main <- mbMainFile
81+
, isC $ getSymbolicPath main ->
82+
cFiles ++ [main]
8283
_otherwise -> cFiles
8384
)
84-
buildCxxSources =
85+
buildCxxSources mbMainFile =
8586
buildExtraSources
8687
"C++ Sources"
8788
Internal.componentCxxGhcOptions
8889
( \c -> do
8990
let cxxFiles = cxxSources (componentBuildInfo c)
9091
case c of
91-
CExe exe
92-
| let mainPath = getSymbolicPath $ modulePath exe
93-
, isCxx mainPath ->
94-
do cxxFiles ++ [makeSymbolicPath mainPath]
95-
-- NB: Main.hs is relative to hs-source-dirs, but Main.c++
96-
-- is relative to the package.
92+
CExe{}
93+
| Just main <- mbMainFile
94+
, isCxx $ getSymbolicPath main ->
95+
cxxFiles ++ [main]
9796
_otherwise -> cxxFiles
9897
)
99-
buildJsSources ghcProg buildTargetDir neededWays = do
98+
buildJsSources _mbMainFile ghcProg buildTargetDir neededWays = do
10099
Platform hostArch _ <- hostPlatform <$> localBuildInfo
101100
let hasJsSupport = hostArch == JavaScript
102101
buildExtraSources
@@ -114,12 +113,12 @@ buildJsSources ghcProg buildTargetDir neededWays = do
114113
ghcProg
115114
buildTargetDir
116115
neededWays
117-
buildAsmSources =
116+
buildAsmSources _mbMainFile =
118117
buildExtraSources
119118
"Assembler Sources"
120119
Internal.componentAsmGhcOptions
121120
(asmSources . componentBuildInfo)
122-
buildCmmSources =
121+
buildCmmSources _mbMainFile =
123122
buildExtraSources
124123
"C-- Sources"
125124
Internal.componentCmmGhcOptions

Cabal/src/Distribution/Simple/GHC/Build/Modules.hs

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
{-# LANGUAGE RankNTypes #-}
66
{-# LANGUAGE TupleSections #-}
77

8-
module Distribution.Simple.GHC.Build.Modules (buildHaskellModules, BuildWay (..), buildWayPrefix) where
8+
module Distribution.Simple.GHC.Build.Modules
9+
( buildHaskellModules
10+
, BuildWay (..)
11+
, buildWayPrefix
12+
, componentInputs
13+
) where
914

1015
import Control.Monad.IO.Class
1116
import Distribution.Compat.Prelude
@@ -98,8 +103,10 @@ buildHaskellModules
98103
-- ^ The parallelism strategy (e.g. num of jobs)
99104
-> ConfiguredProgram
100105
-- ^ The GHC configured program
101-
-> PD.PackageDescription
102-
-- ^ The package description
106+
-> Maybe (SymbolicPath Pkg File)
107+
-- ^ Optional path to a Haskell Main file to build
108+
-> [ModuleName]
109+
-- ^ The Haskell modules to build
103110
-> SymbolicPath Pkg ('Dir Artifacts)
104111
-- ^ The path to the build directory for this target, which
105112
-- has already been created.
@@ -112,7 +119,7 @@ buildHaskellModules
112119
-- invocation used to compile the component in that 'BuildWay'.
113120
-- This can be useful in, eg, a linker invocation, in which we want to use the
114121
-- same options and list the same inputs as those used for building.
115-
buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir neededLibWays pbci = do
122+
buildHaskellModules numJobs ghcProg mbMainFile inputModules buildTargetDir neededLibWays pbci = do
116123
-- See Note [Building Haskell Modules accounting for TH]
117124

118125
let
@@ -141,13 +148,14 @@ buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir neededLibWays pbci
141148
| isCoverageEnabled = Flag $ Hpc.mixDir (coerceSymbolicPath $ coerceSymbolicPath buildTargetDir </> extraCompilationArtifacts) way
142149
| otherwise = mempty
143150

144-
(inputFiles, inputModules) <- componentInputs buildTargetDir pkg_descr pbci
145-
146151
let
147152
mbWorkDir = mbWorkDirLBI lbi
148153
runGhcProg = runGHC verbosity ghcProg comp platform mbWorkDir
149154
platform = hostPlatform lbi
150155

156+
(hsMains, scriptMains) =
157+
partition (isHaskell . getSymbolicPath) (maybeToList mbMainFile)
158+
151159
-- We define the base opts which are shared across different build ways in
152160
-- 'buildHaskellModules'
153161
baseOpts way =
@@ -161,16 +169,8 @@ buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir neededLibWays pbci
161169
ghcOptNoLink = if isLib then NoFlag else toFlag True
162170
, ghcOptNumJobs = numJobs
163171
, ghcOptInputModules = toNubListR inputModules
164-
, ghcOptInputFiles =
165-
toNubListR $
166-
if PD.package pkg_descr == fakePackageId
167-
then filter (isHaskell . getSymbolicPath) inputFiles
168-
else inputFiles
169-
, ghcOptInputScripts =
170-
toNubListR $
171-
if PD.package pkg_descr == fakePackageId
172-
then filter (not . isHaskell . getSymbolicPath) inputFiles
173-
else []
172+
, ghcOptInputFiles = toNubListR hsMains
173+
, ghcOptInputScripts = toNubListR scriptMains
174174
, ghcOptExtra = buildWayExtraHcOptions way GHC bi
175175
, ghcOptHiSuffix = optSuffixFlag (buildWayPrefix way) "hi"
176176
, ghcOptObjSuffix = optSuffixFlag (buildWayPrefix way) "o"
@@ -248,7 +248,7 @@ buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir neededLibWays pbci
248248
ProfDynWay -> profDynOpts
249249

250250
-- If there aren't modules, or if we're loading the modules in repl, don't build.
251-
unless (forRepl || (null inputFiles && null inputModules)) $ liftIO $ do
251+
unless (forRepl || (isNothing mbMainFile && null inputModules)) $ liftIO $ do
252252
-- See Note [Building Haskell Modules accounting for TH]
253253
let
254254
neededLibWaysSet = Set.fromList neededLibWays
@@ -348,25 +348,26 @@ buildWayExtraHcOptions = \case
348348
DynWay -> hcSharedOptions
349349
ProfDynWay -> hcProfSharedOptions
350350

351-
-- | Returns a pair of the Haskell input files and Haskell modules of the
352-
-- component being built.
351+
-- | Returns a pair of the main file and Haskell modules of the component being
352+
-- built. The main file is not necessarily a Haskell file. It could also be
353+
-- e.g. a C source, or, a Haskell repl script (that does not necessarily have
354+
-- an extension).
353355
--
354-
-- The "input files" are either the path to the main Haskell module, or a repl
355-
-- script (that does not necessarily have an extension).
356+
-- The main file is Nothing if the component is not executable.
356357
componentInputs
357358
:: SymbolicPath Pkg (Dir Artifacts)
358359
-- ^ Target build dir
359360
-> PD.PackageDescription
360361
-> PreBuildComponentInputs
361362
-- ^ The context and component being built in it.
362-
-> IO ([SymbolicPath Pkg File], [ModuleName])
363-
-- ^ The Haskell input files, and the Haskell modules
363+
-> IO (Maybe (SymbolicPath Pkg File), [ModuleName])
364+
-- ^ The main input file, and the Haskell modules
364365
componentInputs buildTargetDir pkg_descr pbci =
365366
case component of
366367
CLib lib ->
367-
pure ([], allLibModules lib clbi)
368+
pure (Nothing, allLibModules lib clbi)
368369
CFLib flib ->
369-
pure ([], foreignLibModules flib)
370+
pure (Nothing, foreignLibModules flib)
370371
CExe Executable{buildInfo = bi', modulePath} ->
371372
exeLikeInputs bi' modulePath
372373
CTest TestSuite{testBuildInfo = bi', testInterface = TestSuiteExeV10 _ mainFile} ->
@@ -405,6 +406,6 @@ componentInputs buildTargetDir pkg_descr pbci =
405406
"Enabling workaround for Main module '"
406407
++ prettyShow mainModName
407408
++ "' listed in 'other-modules' illegally!"
408-
return ([main], filter (/= mainModName) otherModNames)
409-
else return ([main], otherModNames)
410-
else return ([], otherModNames)
409+
return (Just main, filter (/= mainModName) otherModNames)
410+
else return (Just main, otherModNames)
411+
else return (Just main, otherModNames)

Cabal/src/Distribution/Simple/GHC/Build/Utils.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import System.FilePath
3131
)
3232

3333
-- | Find the path to the entry point of an executable (typically specified in
34-
-- @main-is@, and found in @hs-source-dirs@).
34+
-- @main-is@, and found in @hs-source-dirs@ -- yes, even when @main-is@ is not a Haskell file).
3535
findExecutableMain
3636
:: Verbosity
3737
-> Maybe (SymbolicPath CWD (Dir Pkg))
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import Distribution.Simple
2+
main = defaultMain
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module Main ( main ) where
2+
3+
import Lib ( myMax )
4+
5+
main :: IO ()
6+
main = print $ myMax 10 100
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include <stdio.h>
2+
#include <HsFFI.h>
3+
#ifdef __GLASGOW_HASKELL__
4+
#include "Lib_stub.h"
5+
#endif
6+
7+
int main(int argc, char *argv[]) {
8+
hs_init(&argc, &argv);
9+
printf("%lld\n", myMax(10,100));
10+
hs_exit();
11+
return 0;
12+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
cabal-version: 2.0
2+
3+
name: haskell-c-tests
4+
version: 0.1.0.0
5+
build-type: Simple
6+
7+
library
8+
exposed-modules: Lib
9+
hs-source-dirs: src
10+
ghc-options: -stubdir autogen-stubs
11+
build-depends: base
12+
default-language: Haskell2010
13+
14+
executable c-exe
15+
main-is: main.c
16+
hs-source-dirs: c-app
17+
ghc-options: -no-hs-main
18+
include-dirs: autogen-stubs
19+
build-depends: base, haskell-c-tests
20+
default-language: Haskell2010
21+
22+
executable haskell-exe
23+
main-is: Main.hs
24+
hs-source-dirs: app
25+
ghc-options: -threaded -rtsopts -with-rtsopts=-N
26+
build-depends: base, haskell-c-tests
27+
default-language: Haskell2010
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Setup configure
2+
Configuring haskell-c-tests-0.1.0.0...
3+
Warning: [unknown-directory] 'include-dirs: autogen-stubs' specifies a directory which does not exist.
4+
# Setup build
5+
Preprocessing library for haskell-c-tests-0.1.0.0...
6+
Building library for haskell-c-tests-0.1.0.0...
7+
Preprocessing executable 'c-exe' for haskell-c-tests-0.1.0.0...
8+
Building executable 'c-exe' for haskell-c-tests-0.1.0.0...
9+
Preprocessing executable 'haskell-exe' for haskell-c-tests-0.1.0.0...
10+
Building executable 'haskell-exe' for haskell-c-tests-0.1.0.0...
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import Test.Cabal.Prelude
2+
-- Test building an executable whose main-is is a C source found in the hs-source-dirs.
3+
-- It is a bit counter intuitive that we look for non-haskell sources in
4+
-- `hs-source-dirs`, but that is a behaviour that users rely on (see #10168)
5+
-- and there's no good reason to break it.
6+
main = setupTest $ do
7+
setup_build []
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module Lib ( myMax ) where
2+
3+
myMax :: Int -> Int -> Int
4+
myMax x1 x2 = if x1 > x2 then x1 else x2
5+
6+
foreign export ccall myMax :: Int -> Int -> Int

0 commit comments

Comments
 (0)