Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cabal/src/Distribution/Simple/GHC.hs
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,6 @@ compilerProgramDb verbosity comp progdb1 hcPkgPath = do
-- in the GHC settings file
progdb3 =
Internal.configureToolchain
(ghcVersionImplInfo ghcVersion)
ghcProg
(compilerProperties comp)
progdb2
Expand Down
71 changes: 55 additions & 16 deletions Cabal/src/Distribution/Simple/GHC/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ import Distribution.Types.GivenComponent
import Distribution.Types.LocalBuildInfo
import Distribution.Types.TargetInfo
import Distribution.Types.UnitId
import Distribution.Types.Version
import Distribution.Utils.NubList (NubListR, toNubListR)
import Distribution.Utils.Path
import Distribution.Verbosity
import Distribution.Version (Version)
import Language.Haskell.Extension
import System.Directory (listDirectory)
import System.Environment (getEnv)
Expand All @@ -100,12 +100,11 @@ targetPlatform ghcInfo = platformFromTriple =<< lookup "Target platform" ghcInfo

-- | Adjust the way we find and configure gcc and ld
configureToolchain
:: GhcImplInfo
-> ConfiguredProgram
:: ConfiguredProgram
-> Map String String
-> ProgramDb
-> ProgramDb
configureToolchain _implInfo ghcProg ghcInfo =
configureToolchain ghcProg ghcInfo =
addKnownProgram
gccProgram
{ programFindLocation = findProg gccProgramName extraGccPath
Expand Down Expand Up @@ -415,10 +414,19 @@ componentCxxGhcOptions verbosity lbi bi clbi odir filename =
MaximalDebugInfo -> ["-g3"]
)
++ cxxOptions bi
, ghcOptCcProgram =
maybeToFlag $
programPath
<$> lookupProgram gccProgram (withPrograms lbi)
, -- Similarly, you need to add a split for cxx-sources in the configure script.
-- The configure split can be found here: https://github.com/haskell/cabal/pull/10844
ghcOptGppProgram =
ghcOptionsSince
(mkVersion [9, 4])
(compiler lbi)
(maybeToFlag $ programPath <$> lookupProgram gppProgram (withPrograms lbi))
, -- The assumption that the C++ compiler is part of the toolchain is only since ghc-9.4.
ghcOptCcProgram =
ghcOptionsBefore
(mkVersion [9, 4])
(compiler lbi)
(maybeToFlag $ programPath <$> lookupProgram gccProgram (withPrograms lbi))
, ghcOptObjDir = toFlag odir
, ghcOptExtra = hcOptions GHC bi
}
Expand All @@ -431,17 +439,15 @@ componentAsmGhcOptions
-> SymbolicPath Pkg (Dir Artifacts)
-> SymbolicPath Pkg File
-> GhcOptions
componentAsmGhcOptions verbosity lbi bi clbi odir filename =
componentAsmGhcOptions verbosity lbi bi _clbi odir filename =
mempty
{ -- Respect -v0, but don't crank up verbosity on GHC if
-- Cabal verbosity is requested. For that, use --ghc-option=-v instead!
ghcOptVerbosity = toFlag (min verbosity Normal)
, ghcOptMode = toFlag GhcModeCompile
, ghcOptInputFiles = toNubListR [filename]
, ghcOptCppIncludePath = includePaths lbi bi clbi odir
, ghcOptHideAllPackages = toFlag True
, ghcOptPackageDBs = withPackageDB lbi
, ghcOptPackages = toNubListR $ mkGhcOptPackages (promisedPkgs lbi) clbi
, ghcOptAsmOptions =
( case withOptimization lbi of
NoOptimisation -> []
Expand All @@ -454,6 +460,7 @@ componentAsmGhcOptions verbosity lbi bi clbi odir filename =
MaximalDebugInfo -> ["-g3"]
)
++ asmOptions bi
, ghcOptAsProgram = maybeToFlag $ programPath <$> lookupProgram gccProgram (withPrograms lbi)
, ghcOptObjDir = toFlag odir
, ghcOptExtra = hcOptions GHC bi
}
Expand Down Expand Up @@ -482,6 +489,25 @@ componentJsGhcOptions verbosity lbi bi clbi odir filename =
, ghcOptExtra = hcOptions GHC bi
}

-- Applies options only if the GHC version is greater than or
-- equal to the given one.
ghcOptionsSince :: Monoid a => Version -> Compiler -> a -> a
ghcOptionsSince ver comp defOptions =
case compilerCompatVersion GHC comp of
Just v
| v >= ver -> defOptions
| otherwise -> mempty
Nothing -> mempty

-- Applies options only if the GHC version is less than the given one.
ghcOptionsBefore :: Monoid a => Version -> Compiler -> a -> a
ghcOptionsBefore ver comp defOptions =
case compilerCompatVersion GHC comp of
Just v
| v < ver -> defOptions
| otherwise -> mempty
Nothing -> mempty

componentGhcOptions
:: VerbosityLevel
-> LocalBuildInfo
Expand Down Expand Up @@ -555,6 +581,23 @@ componentGhcOptions verbosity lbi bi clbi odir =
, -- Unsupported extensions have already been checked by configure
ghcOptExtensions = toNubListR $ usedExtensions bi
, ghcOptExtensionMap = Map.fromList . compilerExtensions $ (compiler lbi)
, -- Use -pgmc to ensure that Cabal always passes cc-options, ld-options to GHC (#4435, #9801)
-- We can only do this on GHC >= 9.4, as we need https://gitlab.haskell.org/ghc/ghc/-/merge_requests/6949
-- Without that GHC MR, this change would cause GHC to never pass -no-pie when linking,
-- which can cause breakage depending on the C toolchain use. We would have to appropriately
-- pass -pgmc-supports-no-pie as appropriate to avoid this regression.
ghcOptCcProgram =
ghcOptionsSince
(mkVersion [9, 4])
(compiler lbi)
(maybeToFlag $ programPath <$> lookupProgram gccProgram (withPrograms lbi))
, -- The assumption that the C++ compiler is part of the toolchain is only since ghc-9.4.
ghcOptGppProgram =
ghcOptionsSince
(mkVersion [9, 4])
(compiler lbi)
(maybeToFlag $ programPath <$> lookupProgram gppProgram (withPrograms lbi))
, ghcOptAsProgram = maybeToFlag $ programPath <$> lookupProgram gccProgram (withPrograms lbi)
}
where
exe_paths =
Expand All @@ -577,20 +620,16 @@ componentCmmGhcOptions
-> SymbolicPath Pkg (Dir Artifacts)
-> SymbolicPath Pkg File
-> GhcOptions
componentCmmGhcOptions verbosity lbi bi clbi odir filename =
componentCmmGhcOptions verbosity lbi bi _clbi odir filename =
mempty
{ -- Respect -v0, but don't crank up verbosity on GHC if
-- Cabal verbosity is requested. For that, use --ghc-option=-v instead!
ghcOptVerbosity = toFlag (min verbosity Normal)
, ghcOptMode = toFlag GhcModeCompile
, ghcOptInputFiles = toNubListR [filename]
, ghcOptCppIncludePath = includePaths lbi bi clbi odir
, ghcOptCppOptions = cppOptions bi
, ghcOptCppIncludes =
toNubListR [autogenComponentModulesDir lbi clbi </> makeRelativePathEx cppHeaderName]
, ghcOptHideAllPackages = toFlag True
, ghcOptPackageDBs = withPackageDB lbi
, ghcOptPackages = toNubListR $ mkGhcOptPackages (promisedPkgs lbi) clbi
, ghcOptOptimisation = toGhcOptimisation (withOptimization lbi)
, ghcOptDebugInfo = toFlag (withDebugInfo lbi)
, ghcOptExtra = hcOptions GHC bi <> cmmOptions bi
Expand Down
9 changes: 8 additions & 1 deletion Cabal/src/Distribution/Simple/Program/GHC.hs
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,12 @@ data GhcOptions = GhcOptions
, ghcOptFfiIncludes :: NubListR FilePath
-- ^ Extra header files to include for old-style FFI; the @ghc -#include@ flag.
, ghcOptCcProgram :: Flag FilePath
-- ^ Program to use for the C and C++ compiler; the @ghc -pgmc@ flag.
-- ^ Program to use for the C compiler; the @ghc -pgmc@ flag and also
-- program to use for the C++ compiler before 9.4.
, ghcOptGppProgram :: Flag FilePath
-- ^ Program to use for the C++ compiler; the @ghc -pgmcxx@ flag.
, ghcOptAsProgram :: Flag FilePath
-- ^ Program to use for the Assembler; the @ghc -pgma@ flag.
, ----------------------------
-- Language and extensions

Expand Down Expand Up @@ -874,6 +879,8 @@ renderGhcOptions comp _platform@(Platform _arch os) opts
in [cxxflag ++ opt | opt <- ghcOptCxxOptions opts]
, ["-opta" ++ opt | opt <- ghcOptAsmOptions opts]
, concat [["-pgmc", cc] | cc <- flag ghcOptCcProgram]
, concat [["-pgmcxx", cxx] | cxx <- flag ghcOptGppProgram]
, concat [["-pgma", as] | as <- flag ghcOptAsProgram]
, -----------------
-- Linker stuff

Expand Down
15 changes: 15 additions & 0 deletions cabal-testsuite/PackageTests/FFI/ForeignOptsPgma/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{-# LANGUAGE ForeignFunctionInterface #-}

module Main where

import Foreign.C (CInt (..))

foreign import ccall "pgma.h meaning_of_life_asm"
meaning_of_life_asm :: IO CInt

main :: IO ()
main = do
secret <- meaning_of_life_asm
if (secret == 33)
then putStrLn ("The secret is " ++ show secret)
else error ("Expected value 33, got " ++ show secret)
7 changes: 7 additions & 0 deletions cabal-testsuite/PackageTests/FFI/ForeignOptsPgma/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# ForeignOptsPgma

This test case asserts that cabal passes the `-pgma` GHC option to override the assembler program.

The cabal file sets `ghc-options: -pgma scripts/as-wrapper.sh`, pointing GHC at a shell script wrapper (`scripts/as-wrapper.sh`) instead of the system assembler program. The wrapper adds `--defsym meaning_of_life_val=33` to every compilation and then delegates to the real `as`. The assembler source requires `meaning_of_life_val` to be defined; if the wrapper is not used as the assembler program, the build fails.

This test is skipped on Windows (no POSIX shell).
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# macOS/AArch64 (Mach-O)
.macro func name
.globl _\name
_\name:
.endm

.text
func meaning_of_life_asm

mov w0, #MEANING_OF_LIFE_VAL
ret
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.text
.globl meaning_of_life_asm
.type meaning_of_life_asm, @function
meaning_of_life_asm:
movl $MEANING_OF_LIFE_VAL, %eax
ret
.size meaning_of_life_asm, .-meaning_of_life_asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.text
.globl meaning_of_life_asm

meaning_of_life_asm:
movl $MEANING_OF_LIFE_VAL, %eax
ret
6 changes: 6 additions & 0 deletions cabal-testsuite/PackageTests/FFI/ForeignOptsPgma/abits/pgma.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef PGMALIB_H
#define PGMALIB_H

int meaning_of_life_asm();

#endif
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
packages: .
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Test.Cabal.Prelude

main = do
cabalTest $ recordMode DoNotRecord $ do
cwd <- fmap testCurrentDir getTestEnv
let wrapper = cwd </> "scripts/as-wrapper.sh"
cabal "v2-build" ["foreign-opts-pgma-exe"]
withPlan $ runPlanExe "foreign-opts-pgma" "foreign-opts-pgma-exe" []
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
cabal-version: 3.0
name: foreign-opts-pgma
version: 0.1
build-type: Simple

executable foreign-opts-pgma-exe
main-is: Main.hs
build-depends: base
default-language: Haskell2010
include-dirs: abits
if os(windows)
asm-sources: abits/asmlib_x86_64_windows.S
elif os(darwin)
asm-sources: abits/asmlib_x86_64_darwin.S
elif os(linux)
asm-sources: abits/asmlib_x86_64_linux.S
ghc-options: -pgma scripts/as-wrapper.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
# Wrapper around `as` that adds --defsym meaning_of_life_val=33 to every compilation.
# Used by the ForeignOptsPgma test to verify that -pgma selects this wrapper.
exec cc -c -DMEANING_OF_LIFE_VAL=33 "$@"
16 changes: 16 additions & 0 deletions cabal-testsuite/PackageTests/FFI/ForeignOptsPgmc/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{-# LANGUAGE ForeignFunctionInterface #-}

module Main where

import Foreign.C (CInt (..))

foreign import ccall "pgmclib.h meaning_of_life_pgmc"
meaning_of_life_pgmc :: IO CInt

main :: IO ()
main = do
secret <- meaning_of_life_pgmc
-- The value 66 comes from __TESTOPT_PGMC__ - see cc-wrapper.sh.
if (secret == 66)
then putStrLn ("The secret is " ++ show secret)
else error ("Expected value 66, got " ++ show secret)
7 changes: 7 additions & 0 deletions cabal-testsuite/PackageTests/FFI/ForeignOptsPgmc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# ForeignOptsPgmc

This test case asserts that cabal passes the `-pgmc` GHC option to override the C compiler program.

The cabal file sets `ghc-options: -pgmc scripts/cc-wrapper.sh`, pointing GHC at a shell script wrapper (`scripts/cc-wrapper.sh`) instead of the system C compiler. The wrapper adds `-D__TESTOPT_PGMC__=66` to every compilation and then delegates to the real `cc`. The C source requires `__TESTOPT_PGMC__` to be defined; if the wrapper is not used as the C compiler, the build fails with a `#error`.

This test is skipped on Windows (no POSIX shell).
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
packages: .
15 changes: 15 additions & 0 deletions cabal-testsuite/PackageTests/FFI/ForeignOptsPgmc/cabal.test.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Test.Cabal.Prelude

main = do
skipIfWindows "requires a POSIX shell script as the C compiler wrapper"
-- Use -pgmc to ensure that Cabal always passes cc-options, ld-options to GHC (#4435, #9801)
-- We can only do this on GHC >= 9.4, as we need https://gitlab.haskell.org/ghc/ghc/-/merge_requests/6949
-- Without that GHC MR, this change would cause GHC to never pass -no-pie when linking,
-- which can cause breakage depending on the C toolchain use. We would have to appropriately
-- pass -pgmc-supports-no-pie as appropriate to avoid this regression.
cabalTest $ recordMode DoNotRecord $ do
skipUnlessGhcVersion ">= 9.4"
cwd <- fmap testCurrentDir getTestEnv
let wrapper = cwd </> "scripts/cc-wrapper.sh"
cabal "v2-build" ["foreign-opts-pgmc-exe"]
withPlan $ runPlanExe "foreign-opts-pgmc" "foreign-opts-pgmc-exe" []
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include "pgmclib.h"

#ifndef __TESTOPT_PGMC__
#error "Did not get required __TESTOPT_PGMC__ from the -pgmc wrapper"
#endif

int meaning_of_life_pgmc() {
return __TESTOPT_PGMC__;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef PGMCLIB_H
#define PGMCLIB_H

int meaning_of_life_pgmc();

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
cabal-version: 2.2
name: foreign-opts-pgmc
version: 0.1
build-type: Simple

executable foreign-opts-pgmc-exe
main-is: Main.hs
build-depends: base
default-language: Haskell2010
include-dirs: cbits
c-sources: cbits/pgmclib.c
ghc-options: -pgmc scripts/cc-wrapper.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
# Wrapper around cc that adds -D__TESTOPT_PGMC__=66 to every compilation.
# Used by the ForeignOptsPgmc test to verify that -pgmc selects this wrapper.
exec cc -D__TESTOPT_PGMC__=66 "$@"
16 changes: 16 additions & 0 deletions cabal-testsuite/PackageTests/FFI/ForeignOptsPgmcxx/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{-# LANGUAGE ForeignFunctionInterface #-}

module Main where

import Foreign.C (CInt (..))

foreign import ccall "pgmcxxlib.h meaning_of_life_pgmcxx"
meaning_of_life_pgmcxx :: IO CInt

main :: IO ()
main = do
secret <- meaning_of_life_pgmcxx
-- The value 67 comes from __TESTOPT_PGMCXX__ - see cxx-wrapper.sh.
if (secret == 67)
then putStrLn ("The secret is " ++ show secret)
else error ("Expected value 67, got " ++ show secret)
7 changes: 7 additions & 0 deletions cabal-testsuite/PackageTests/FFI/ForeignOptsPgmcxx/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# ForeignOptsPgmcxx

This test case asserts that cabal passes the `-pgmcxx` GHC option to override the C++ compiler program.

The cabal file sets `ghc-options: -pgmcxx scripts/cxx-wrapper.sh`, pointing GHC at a shell script wrapper (`scripts/cxx-wrapper.sh`) instead of the system C++ compiler. The wrapper adds `-D__TESTOPT_PGMCXX__=67` to every compilation and then delegates to the real `g++`. The C++ source requires `__TESTOPT_PGMCXX__` to be defined; if the wrapper is not used as the C++ compiler, the build fails with a `#error`.

This test is skipped on Windows (no POSIX shell).
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
packages: .
11 changes: 11 additions & 0 deletions cabal-testsuite/PackageTests/FFI/ForeignOptsPgmcxx/cabal.test.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Test.Cabal.Prelude

main = do
skipIfWindows "requires a POSIX shell script as the C++ compiler wrapper"
-- The assumption that the C++ compiler is part of the toolchain is only since ghc-9.4.
cabalTest $ recordMode DoNotRecord $ do
skipUnlessGhcVersion ">= 9.4"
cwd <- fmap testCurrentDir getTestEnv
let wrapper = cwd </> "scripts/cxx-wrapper.sh"
cabal "v2-build" ["foreign-opts-pgmcxx-exe"]
withPlan $ runPlanExe "foreign-opts-pgmcxx" "foreign-opts-pgmcxx-exe" []
Loading
Loading