Skip to content
Closed
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
7 changes: 4 additions & 3 deletions .hlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@
- --ignore-glob=Cabal-tests/tests/custom-setup/CabalDoctestSetup.hs
- --ignore-glob=Cabal-tests/tests/custom-setup/IdrisSetup.hs
- --ignore-glob=cabal-testsuite/PackageTests/BuildWays/q/app/Main.hs
- --ignore-glob=cabal-testsuite/PackageTests/CppOptions/CppOpts/Main.hs
- --ignore-glob=cabal-testsuite/PackageTests/CMain/10168/src/Lib.hs
- --ignore-glob=cabal-testsuite/PackageTests/CmmSources/src/Demo.hs
- --ignore-glob=cabal-testsuite/PackageTests/CmmSourcesDyn/src/Demo.hs
- --ignore-glob=cabal-testsuite/PackageTests/CmmSourcesExe/src/Demo.hs
- --ignore-glob=cabal-testsuite/PackageTests/Cmm/CmmSources/src/Demo.hs
- --ignore-glob=cabal-testsuite/PackageTests/Cmm/CmmSourcesDyn/src/Demo.hs
- --ignore-glob=cabal-testsuite/PackageTests/Cmm/CmmSourcesExe/src/Demo.hs
- --ignore-glob=cabal-testsuite/PackageTests/NewBuild/CmdRun/Script/script.hs
- --ignore-glob=cabal-testsuite/PackageTests/NewBuild/CmdRun/ScriptLiterate/script.lhs
- --ignore-glob=cabal-testsuite/PackageTests/Regression/T5309/lib/Bio/Character/Exportable/Class.hs
Expand Down
22 changes: 21 additions & 1 deletion 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 Down Expand Up @@ -482,6 +482,16 @@ 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

componentGhcOptions
:: VerbosityLevel
-> LocalBuildInfo
Expand Down Expand Up @@ -555,6 +565,16 @@ 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))
}
where
exe_paths =
Expand Down
15 changes: 15 additions & 0 deletions cabal-testsuite/PackageTests/CppOptions/CppOpts/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{-# LANGUAGE CPP #-}

module Main where

#ifndef __TESTOPT_CPP__
#error "Did not get required __TESTOPT_CPP__ from cpp-options"
#endif

main :: IO ()
main = do
-- The value 44 comes from __TESTOPT_CPP__ - see the cabal file.
let secret = __TESTOPT_CPP__ :: Int
if secret == 44
then putStrLn ("The secret is " ++ show secret)
else error ("Expected value 44, got " ++ show secret)
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
packages: .
5 changes: 5 additions & 0 deletions cabal-testsuite/PackageTests/CppOptions/CppOpts/cabal.test.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Test.Cabal.Prelude

main = cabalTest $ recordMode DoNotRecord $ do
cabal "v2-build" ["cpp-opts-exe"]
withPlan $ runPlanExe "cpp-opts" "cpp-opts-exe" []
10 changes: 10 additions & 0 deletions cabal-testsuite/PackageTests/CppOptions/CppOpts/cpp-opts.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
cabal-version: 2.2
name: cpp-opts
version: 0.1
build-type: Simple

executable cpp-opts-exe
main-is: Main.hs
build-depends: base
default-language: Haskell2010
cpp-options: -D__TESTOPT_CPP__=44
16 changes: 16 additions & 0 deletions cabal-testsuite/PackageTests/FFI/ForeignOptsAsm/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 "asmlib.h meaning_of_life_asm"
meaning_of_life_asm :: IO CInt

main :: IO ()
main = do
secret <- meaning_of_life_asm
-- The value 33 comes from meaning_of_life_val - see asm-options in the cabal file.
if (secret == 33)
then putStrLn ("The secret is " ++ show secret)
else error ("Expected value 33, got " ++ show secret)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef ASMLIB_H
#define ASMLIB_H

int meaning_of_life_asm();

#endif
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
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
packages: .
12 changes: 12 additions & 0 deletions cabal-testsuite/PackageTests/FFI/ForeignOptsAsm/cabal.test.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Test.Cabal.Prelude
import Distribution.System (Arch (..), buildArch, OS (..), buildOS)

main = do
skipUnlessIO "needs x86_64 or aarch64"
( (buildArch == X86_64 && buildOS == Windows)
|| (buildArch == X86_64 && buildOS == Linux)
|| (buildArch == AArch64 && buildOS == OSX)
)
cabalTest $ recordMode DoNotRecord $ do
cabal "v2-build" ["foreign-opts-asm-exe"]
withPlan $ runPlanExe "foreign-opts-asm" "foreign-opts-asm-exe" []
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
cabal-version: 3.0
name: foreign-opts-asm
version: 0.1
build-type: Simple

executable foreign-opts-asm-exe
main-is: Main.hs
build-depends: base
default-language: Haskell2010
include-dirs: abits
if os(windows) && arch(x86_64)
asm-sources: abits/asmlib_x86_64_windows.S
elif os(darwin) && arch(aarch64)
asm-sources: abits/asmlib_aarch64_darwin.S
elif os(linux) && arch(x86_64)
asm-sources: abits/asmlib_x86_64_linux.S
asm-options: -DMEANING_OF_LIFE_VAL=33
2 changes: 1 addition & 1 deletion cabal-testsuite/PackageTests/FFI/ForeignOptsCxx/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ main :: IO ()
main = do
secret <- meaning_of_life_cxx
-- The value 22 comes from __TESTOPT_CXX__ - see the cabal file.
if (secret == 22)
if secret == 22
then putStrLn ("The secret is " ++ show secret)
else error ("Expected value 22, got " ++ show secret)
18 changes: 18 additions & 0 deletions cabal-testsuite/PackageTests/FFI/ForeignOptsLd/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{-# LANGUAGE ForeignFunctionInterface #-}

module Main where

import Foreign.C (CInt (..))

-- With ld-options: -Wl,--wrap=meaning_of_life_ld_real, the linker redirects
-- this call to __wrap_meaning_of_life_ld_real, which returns 55.
foreign import ccall "ldlib.h meaning_of_life_ld_real"
meaning_of_life_ld_real :: IO CInt

main :: IO ()
main = do
secret <- meaning_of_life_ld_real
-- The value 55 comes from __wrap_meaning_of_life_ld_real - see ld-options in the cabal file.
if secret == 55
then putStrLn ("The secret is " ++ show secret)
else error ("Expected value 55, got " ++ show secret)
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
packages: .
8 changes: 8 additions & 0 deletions cabal-testsuite/PackageTests/FFI/ForeignOptsLd/cabal.test.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Test.Cabal.Prelude

main = do
skipIfOSX "Apple linker does not support --wrap"
skipIfWindows "Windows linker does not support --wrap"
cabalTest $ recordMode DoNotRecord $ do
cabal "v2-build" ["foreign-opts-ld-exe"]
withPlan $ runPlanExe "foreign-opts-ld" "foreign-opts-ld-exe" []
14 changes: 14 additions & 0 deletions cabal-testsuite/PackageTests/FFI/ForeignOptsLd/cbits/ldlib.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include "ldlib.h"

/* The "real" implementation - returns 0, the wrong value.
* With ld-options: -Wl,--wrap=meaning_of_life_ld_real, the linker redirects
* all calls to this function to __wrap_meaning_of_life_ld_real below. */
int meaning_of_life_ld_real() {
return 0;
}

/* The wrapper that the linker substitutes in place of the real function.
* Returns 55 - see ld-options in the cabal file. */
int __wrap_meaning_of_life_ld_real() {
return 55;
}
10 changes: 10 additions & 0 deletions cabal-testsuite/PackageTests/FFI/ForeignOptsLd/cbits/ldlib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifndef LDLIB_H
#define LDLIB_H

/* The "real" function; with --wrap, calls to this are redirected by the linker. */
int meaning_of_life_ld_real();

/* The wrapper that the linker calls instead of the real function. */
int __wrap_meaning_of_life_ld_real();

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

executable foreign-opts-ld-exe
main-is: Main.hs
build-depends: base
default-language: Haskell2010
include-dirs: cbits
c-sources: cbits/ldlib.c
-- Redirect calls to meaning_of_life_ld_real to __wrap_meaning_of_life_ld_real.
-- If ld-options are not passed the real function (returning 0) is called instead
-- of the wrapper (returning 55), and the test fails at runtime.
ld-options: -Wl,--wrap=meaning_of_life_ld_real
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: .
13 changes: 13 additions & 0 deletions cabal-testsuite/PackageTests/FFI/ForeignOptsPgmc/cabal.test.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
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"
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 "$@"
Loading
Loading