1

I am trying to write a script that will build multiple cppUtes lib.a files for different sanitizers with a bash script.

When trying to pass the compiler flags as variables to cmake I am unable to correctly format them. Please see the brief example below.

#!/bin/sh
set -euo pipefail
COMMON_OPTS='-fno-common -g -fno-omit-frame-pointer'
ASAN_OPT='-fsanitize=address'
ASAN_C_FLAGS="-DCMAKE_C_FLAGS=\"$ASAN_OPT $COMMON_OPTS\""

echo "cmake ../ $ASAN_C_FLAGS"
cmake ../ $ASAN_C_FLAGS
make

The output of echo is what I expect, and what works for setting flags when not running in a bash script:

cmake ../ -DCMAKE_C_FLAGS="-fsanitize=address -fno-common -g -fno-omit-frame-pointer"

However, when I run the script cmake is not interpreting the flags correctly. They do not appear in the cmake flags that are displayed during the configuration:

CppUTest CFLAGS: -include "/home/ubuntu/cpputest/include/CppUTest/MemoryLeakDetectorMallocMacros.h" -Wall -Wextra -pedantic -Wshadow -Wswitch-default -Wswitch-enum -Wconversion -Wsign-conversion -Wno-padded -Wno-long-long -Wstrict-prototypes

and finally, I get the following compilation error from make:

c++: error: unrecognized argument to '-fsanitize=' option: 'address -g -fno-omit-frame-pointer'

Any help would be kindly appreciated.

Buoy
  • 111
  • I think it's related to the difference between $* and $@ ie your arguments are getting bunched up. How to unbunch... Not sure – Rusi Jan 08 '20 at 04:34
  • Also see comment by Carlo Wood – Rusi Jan 08 '20 at 04:40
  • Thank you for you coments @Rusi I am not sure how to interpret the answers from those questions as I am not using any command line inputs. Tying to wrap the cmake argument in quotes eg: cmake ../ "$ASAN_C_FLAGS" gives the same results. – Buoy Jan 08 '20 at 16:02
  • I'm away from a machine (on phone) and can't try hence only comments... Sorry! What I would try is to write a bash function as in @artswri answer, receive them as "$@" and ensure that the count is as you expect. In any case you can use that approach to verify counts. – Rusi Jan 08 '20 at 16:09

2 Answers2

0

The problem here is that due to escaped quotes in your ASAN_C_FLAGS, CMake sees a quoted value for its CMAKE_C_FLAGS variable, and thus passes the entire thing as a single argument to your compiler. After removing those escaped quotes, CMake should correctly split the passed arguments at their whitespace before passing them to the compiler.

  • That is frustrating... removing the quotes entirely dose work. It dose not show that they have been appended in the cmake output but after building I can see they were appended. Thanks for your answer. – Buoy Jan 08 '20 at 17:58
0

Do consider using an array to hold the options. That way, you would still be able to properly give them to cmake as separate argument, and not as a single string that the shell will split on whitespaces and perform filename globbing on.

The sh shell generally does not support arrays, so I have changed the #!-line to invoke bash instead:

#!/bin/bash
set -euo pipefail

common_opts=( -fno-common -g -fno-omit-frame-pointer )
asan_opt='-fsanitize=address'
asan_c_cflags=( -DCMAKE_C_FLAGS="$asan_opt" "${common_opts[@]}" )

echo "cmake ${asan_c_cflags[@]} ../"
cmake "${asan_c_cflags[@]}" ../
make

Here, the array allows us to pass multiple quoted arguments to cmake without demoting these to a single string and relying on the shell to split+glob it correctly. This also allows us to properly pass argument potentially consisting of strings with spaces in them.

Related:

Kusalananda
  • 333,661
  • Thank you for your solution. This helped clean up the script and make it more readable. Cheers! – Buoy Jan 08 '20 at 18:20