gccclangcommand-line-arguments

gcc OR clang command line invocation argument / parameter order precidence Last or First wins?


Search engines and reading the manuals are failing me. I'm not sure if there's a way to have E.G. gcc or clang output the final 'configuration' result of parsed command line arguments to check myself (nor what keywords might be matches for that in the manuals).

NOT -I includes (don't see a negative for keywords :( )

When running gcc (or) clang, does the Last specified version of an option or the First specified win?

E.G. gcc -O3 -Os -O1 ... -- Would gcc build the result with -O3 or -O1 ?

My guess is that the last / most recent parameter would win, but I'd really prefer knowledge of where in the documentation the behavior is specified and thus made part of the usage contract rather than an undefined and undocumented behavior that happens to work whenever it's tested.

This behavior would differ from the well documented "Include path management" behavior, where (as in most western writing) matches are scanned from 'left to right' (first to last in the specified parameters). However given overriding Includes it also logically makes sense that the first specified version of a singular flag type might win with later redundant specifications ignored.


Solution

  • When running gcc (or) clang, does the Last specified version of an option or the First specified win?

    It is not the case that all options, even excluding -I options, that can assume multiple values assume mutually exclusive values, so which ones wins does not necessarily arise. In an answer to a related question I classified options as mutex, cumulative or positional (although this classification is not endorsed by GCC or Clang documentation and is empirically based). You may find that answer helpful.

    GCC/Clang documentation does not provide an overall procedure for determining how the effect of each option is related to that of others before or after it. The answers vary depending on the nature of the option and you must turn to the documentation pertaining to a class of options.

    For example:

    In concluding the documention of the -O? options controlling optimisation level you can read:

    If you use multiple -O options, with or without level numbers, the last such option is the one that is effective.

    For any pair of mutually exclusive options of equal generality you can rely on it that the compiler will either diagnose the conflict or take the last one with no diagnostic. You may have to find out experimentally whether you get a diagnostic (e.g. -DX -DX=Y) or not (-fPIC -fno-PIC).

    And equal generality is a complication. For example, in concluding the documention of the -Wwarning options to request or suppress Warnings you can read:

    You can request many specific warnings with options beginning with ‘-W’, for example -Wunused-variable to request warnings on declarations of variables that are never used. Each of these specific warning options also has a negative form beginning with ‘-Wno-’ to turn off warnings; for example, -Wno-unused-variable. This manual lists only one of the two forms, whichever is not the default...

    The combined effect of positive and negative forms is that more specific options have priority over less specific ones, independently of their position in the command line. For options of the same specificity, the last one takes effect.

    My emphasis.


    I'm not sure if there's a way to have E.G. gcc or clang output the final 'configuration' result of parsed command line arguments to check myself.

    Yes, you can find out the final operative options consumed by the compiler using the option -frecord-gcc-switches. This option emits in the object file a string section called .GCC.command.line that contains the residual commandline options. For example:

    $ cat main.c
    int main(void)
    {
        return 0;
    }
    
    $ gcc -c main.c -O0 -O3 -fPIC -fno-PIC -frecord-gcc-switches
    

    Then:

    $ objdump -s -j .GCC.command.line main.o
    
    main.o:     file format elf64-x86-64
    
    Contents of section .GCC.command.line:
     0000 474e5520 43313720 31332e33 2e30202d  GNU C17 13.3.0 -
     0010 6d74756e 653d6765 6e657269 63202d6d  mtune=generic -m
     0020 61726368 3d783836 2d363420 2d4f3320  arch=x86-64 -O3 
     0030 2d666e6f 2d504943 202d6661 73796e63  -fno-PIC -fasync
     0040 68726f6e 6f75732d 756e7769 6e642d74  hronous-unwind-t
     0050 61626c65 73202d66 73746163 6b2d7072  ables -fstack-pr
     0060 6f746563 746f722d 7374726f 6e67202d  otector-strong -
     0070 66737461 636b2d63 6c617368 2d70726f  fstack-clash-pro
     0080 74656374 696f6e20 2d666366 2d70726f  tection -fcf-pro
     0090 74656374 696f6e00                    tection.
     
    

    or more legibly:

    $ strings main.o
    GNU C17 13.3.0 -mtune=generic -march=x86-64 -O3 -fno-PIC -fasynchronous-unwind-tables -fstack-protector-strong -fstack-clash-protection -fcf-protection
    ...
    

    shows you the operative options. Here you will see boilerplate options that you did not explicitly pass:

    -mtune=generic -march=x86-64 -fasynchronous-unwind-tables -fstack-protector-strong -fstack-clash-protection -fcf-protection
    

    in addition to ones that you did pass, but if you discount the boilerplate options then the ones you are left with:

    -O3 -fno-PIC
    

    are the ones that remained from:

    -O0 -O3 -fPIC -fno-PIC
    

    after the compiler had "picked the winners". Note the -frecord-gcc-switches is not itself recorded. This option is accepted by Clang as well as GCC.