0

I'm trying to set a cmake variable to a list from the commandline (bash, but probably the same problem with other shells). This MRE script sort of describes my work flow (which is more complicated: I drive cmake from a makefile):

#!/bin/bash

# dummy programs
rm -rf a b a.cxx b.xx
touch a.cxx b.cxx

# cmake file
cat >CMakeLists.txt <<'EOF'
cmake_minimum_required( VERSION 3.20 )
project( args VERSION 1.0 )

option( PROGRAMS "list of programs" OFF )
if( PROGRAMS )
    message( NOTICE "for programs: ${PROGRAMS}" )
else()
    message( NOTICE "no programs: ${PROGRAMS}" )
endif()

foreach( program IN ITEMS ${PROGRAMS} )
    message( NOTICE "program: ${program}" )
    add_executable( ${program} ${program}.cxx )
    target_compile_features( ${program} PRIVATE cxx_std_17 )
    install( TARGETS ${program} DESTINATION . )
endforeach()
EOF

# drive cmake
programs="a b"
rm -rf build
mkdir -p build
cd build
set -x
cmake -D CMAKE_VERBOSE_MAKEFILE=ON \
      -D PROGRAMS="${programs}" \
      ..

leads to:

for programs: a b
program: a b
CMake Error at CMakeLists.txt:13 (add_executable):
  The target name "a b" is reserved or not valid for certain CMake features,
  such as generator expressions, and may result in undefined behavior.

I'm pretty sure I need double quotes in the invocation of cmake, so how do I make cmake lose them in that variable?

Victor Eijkhout
  • 5,088
  • 2
  • 22
  • 23

1 Answers1

1

A list in CMake is a semicolon separated list of items. You can replace space with semicolon, either on shell or on CMake side. CMake is not shell, there are different rules.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • Ok, using semicolons I can do. But that lists are semicolon separated? I can write `foreach( x IN ITEMS a b c d )` and not a semicolon in sight. Ditto `set( PROGRAMS a b )` thoush interestingly that outputs `for programs: a;b` so cmake converts space lists to semicolon lists. – Victor Eijkhout Jul 17 '22 at 16:48
  • 1
    Multiple arguments to `set` command are joined with semicolons and then assigned to the variable. `foreach(IN ITEMS` iterates over arguments. It is_similar_ (but different) to shell and word splitting - arguments are not equal to space separated elements, they are different syntactically. `But that lists are semicolon separated` Yes, CMake has no lists, no arrays. It's just text separated with semicolons. – KamilCuk Jul 17 '22 at 16:56
  • Thanks. Mental model adjusted and answer accepted. Aside: so many people are using cmake from an IDE that shell interaction is rather undocumented. The unjustly vaunted Professional Cmake book has basically squat-all about use of cmake from commandline. But that aside. – Victor Eijkhout Jul 17 '22 at 17:03