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.

  • I think it's related to the difference between $* and $@ ie your arguments are getting bunched up. How to unbunch... Not sure – Rusi Jan 8 at 4:34
  • Also see comment by Carlo Wood – Rusi Jan 8 at 4: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. – Pistanic Jan 8 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 8 at 16:09
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:

|improve this answer|||||
  • Thank you for your solution. This helped clean up the script and make it more readable. Cheers! – Pistanic Jan 8 at 18:20
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.

|improve this answer|||||
  • 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. – Pistanic Jan 8 at 17:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.