target_compile_options: SHELL prefix not working in generator expression

Hi, I’m setting up my first project with CMake and am struggling with compile options specific to the armasm.exe we’re using in the company.

The goal is to get the following command line (stripped down) for assembly files:
armasm.exe --pd "__UVISION_VERSION SETA 536" --pd "STM32F427xx SETA 1" (etc.)

I tried various approaches but either it works for ASM files or C files.

1. SHELL: in generator expression

target_compile_options(${thisTarget}
    PUBLIC
        $<$<COMPILE_LANGUAGE:ASM>:"SHELL:--pd \"__UVISION_VERSION SETA 536\"">
        $<$<COMPILE_LANGUAGE:ASM>:"SHELL:--pd \"STM32F427xx SETA 1\"">
)

yields

[build] C:\Keil_v5\ARM\ARMCC\bin\armasm.exe "\"SHELL:--pd \"__UVISION_VERSION SETA 536\"\"" "\"SHELL:--pd \"STM32F427xx SETA 1\"\"" -o CMakeFiles\AmuTarget.dir\Debug\RTE\Device\STM32F427ZITx\startup_stm32f427xx.o D:\Projects\Misc\BuildSystem\Source\RTE\Device\STM32F427ZITx\startup_stm32f427xx.s

and armasm fails.

2. Without generator expression

target_compile_options(${thisTarget}
    PUBLIC
        "SHELL:--pd \"__UVISION_VERSION SETA 536\""
        "SHELL:--pd \"STM32F427xx SETA 1\""
)

which works for armasm but obviously not for armcc (C/C++):

[build] C:\Keil_v5\ARM\ARMCC\bin\armcc.exe -DSTM32F427xx -D_RTE_ -D__UVISION_VERSION=\"536\" -DCMAKE_INTDIR=\"Debug\" --pd "__UVISION_VERSION SETA 536" --pd "STM32F427xx SETA 1" --depend=CMakeFiles\AmuTarget.dir\Debug\MyClass.o.d --depend_single_line --no_depend_system_headers -o CMakeFiles\AmuTarget.dir\Debug\MyClass.o -c D:\Projects\Misc\BuildSystem\Source\MyClass.cpp

3. With brackets

target_compile_options(${thisTarget}
    PUBLIC
        $<$<COMPILE_LANGUAGE:ASM>:[=[--p "__UVISION_VERSION SETA 536" --pd "STM32F427xx SETA 1"]=]>
)

where armasm interprets “[=[…]=]” as a filename:

[build] C:\Keil_v5\ARM\ARMCC\bin\armasm.exe "[=[--p;__UVISION_VERSION SETA 536;--pd;STM32F427xx SETA 1;]=]" -o CMakeFiles\AmuTarget.dir\Debug\RTE\Device\STM32F427ZITx\startup_stm32f427xx.o D:\Projects\Misc\BuildSystem\Source\RTE\Device\STM32F427ZITx\startup_stm32f427xx.s

:question:
What am I missing?

For the correct interpretation of the genex and SHELL: prefix, specify the whole genex inside quotes. Try this version:

target_compile_options(${thisTarget}
    PUBLIC
        "$<$<COMPILE_LANGUAGE:ASM>:SHELL:--pd \"__UVISION_VERSION SETA 536\">"
        "$<$<COMPILE_LANGUAGE:ASM>:SHELL:--pd \"STM32F427xx SETA 1\">"
)

Spot on, thank you very much.
Are the quotes required because of the SHELL: prefix? I added other options (without prefixes) with unquoted genex, and those work fine.

The quotes are required due to the spaces in the value. Without the overall quoting, there will be $<GENEX:SHELL:--pd and \"value\"> arguments to target_compile_options (essentially injecting a ; into the value).

1 Like

Thanks for pointing that out. Then
$<$<OR:$<COMPILE_LANGUAGE:CXX>,$<COMPILE_LANGUAGE:C>>:--asm -c --interleave>
only works without quotes because the individual options do not take any additional values.

I’d still quote that myself, but yeah, that seems plausible.

I’ll also note that $<COMPILE_LANGUAGE:CXX,C> will make the $<OR> unnecessary.

1 Like

Nice, to get rid of that OR.
However, quoting breaks the function in this case, interestingly:

$<$<COMPILE_LANGUAGE:CXX,C>:--signed_chars --split_sections --no_exceptions --no_rtti>
"$<$<COMPILE_LANGUAGE:CXX,C>:--asm -c --interleave>"

:arrow_down:
[build] Fatal error: C3900U: Unrecognized option ‘–asm -c --interleave’.

[build] C:\Keil_v5\ARM\ARMCC\bin\armcc.exe --signed_chars --split_sections --no_exceptions --no_rtti "--asm -c --interleave" --depend=CMakeFiles\AmuTarget.dir\Debug\MyClass.o.d --depend_single_line --no_depend_system_headers -o CMakeFiles\AmuTarget.dir\Debug\MyClass.o -c D:\Projects\Misc\BuildSystem\Source\MyClass.cpp

I am surprised that $<$<COMPILE_LANGUAGE:CXX,C>:--signed_chars --split_sections --no_exceptions --no_rtti> works as expected because it will be seen as the following list:

$<$<COMPILE_LANGUAGE:CXX,C>:--signed_chars
--split_sections
--no_exceptions
--no_rtti>

So, the genex is malformed and cannot be evaluated…

For the second ex[pression, this is because you don’t use correctly the genex. What is expected by the genex is a CMake list, and you specify a string. Correct expression is:

"$<$<COMPILE_LANGUAGE:CXX,C>:--asm;-c;--interleave>"

The malformed genex indeed creates a working result as I can see in compile_commands.json.
I changed it to a list, and of course, it works like a charm now.
Thank you