Skip to content

--prog-option(s) (e.g. gcc-options) CLI flags get duplicated #6183

Open
@nh2

Description

@nh2

Found in https://github.com/haskell/cabal/pull/5451/files#r310417490:

Problem

When a flag like --gcc-option or the new --ld-option is given to cabal build, the eventual gcc/ld invocation will be given that flag twice.

For example, if you cabal build --gcc-option=-v, then gcc -v -v will be called.

You can verify this by passing -v to cabal and ghc, or using strace.

This is obviously problematic when giving a flag twice results in different behaviour from the tool than giving it once.

Environment

Cabal version: 3.0.0.0 built from commit 1b324a1, on Ubuntu 16.04.

Reason

I've spent a couple hours figuring out where this comes from.

The problem is in

elabProgramArgs = Map.fromList
[ (programId prog, args)
| prog <- configuredPrograms compilerprogdb
, let args = programOverrideArgs prog
, not (null args)
]
<> perPkgOptionMapMappend pkgid packageConfigProgramArgs

In elabProgramArgs, the <> perPkgOptionMapMappend pkgid packageConfigProgramArgs is what contains the flags twice, for example fromList [("ld",["-s","-s"])].

This is due to

perPkgOptionMapMappend pkgid f = getMapMappend (lookupPerPkgOption pkgid f)

which does

lookupPerPkgOption :: (Package pkg, Monoid m)
=> pkg -> (PackageConfig -> m) -> m
lookupPerPkgOption pkg f =
-- This is where we merge the options from the project config that
-- apply to all packages, all project local packages, and to specific
-- named packages
global `mappend` local `mappend` perpkg
where
global = f allPackagesConfig
local | isLocalToProject pkg
= f localPackagesConfig
| otherwise
= mempty
perpkg = maybe mempty f (Map.lookup (packageName pkg) perPackageConfig)

In global `mappend` local `mappend` perpkg, each global and local contain MapMappend {getMapMappend = fromList [("ld",["-s"])]}.

This seems wrong.

The commit message of the commit that introduced this, 20d0026, says

Program options specified on the command line currently apply to all local packages, not just the targets of the command.

This suggests that such options should only be in local. How comes they are also in global?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions