55

I want to check whether a lists contains a specific entry like in the following code snippet:

macro(foo)
if ($(ARGN} contains "bar")
  ...
endif
endmacro()

CMake does not offer a contains. What is best / easiest way to get the desired result?

In CMake's wiki, I found a LIST_CONTAINS macro, but the wiki page is outdated. Is this still the best way to go, or has CMake gained new capabilities?

starball
  • 20,030
  • 7
  • 43
  • 238
usr1234567
  • 21,601
  • 16
  • 108
  • 128

4 Answers4

85

With CMake 3.3 or later, the if command supports an IN_LIST operator, e.g.:

if ("bar" IN_LIST _list)
 ...
endif()

For older versions of CMake, you can use the built-in list(FIND) function:

list (FIND _list "bar" _index)
if (${_index} GREATER -1)
  ...
endif()
sakra
  • 62,199
  • 16
  • 168
  • 151
  • 3
    I didn't recommend this for a couple of reasons. In the scope of a macro (as per the OP), you'd have to copy `ARGN` or this would fail silently. Also, this is significantly slower for large lists than my answer. – Fraser Apr 27 '14 at 15:06
  • @Fraser Why would this silently fail? – usr1234567 Apr 27 '14 at 16:28
  • I had to add quotation marks around the first argument `"${ARGN}"`. Maybe this is related to to Fraser's comment. – usr1234567 Apr 27 '14 at 17:23
  • 2
    The [docs for `macro`](http://www.cmake.org/cmake/help/v3.0/command/macro.html#macro-argument-caveats), particularly the caveats, explain it. If you try `list(FIND ARGN "bar" _index)` inside a `macro` it will always set `_index` to -1 since `ARGN` isn't a normal variable here. – Fraser Apr 27 '14 at 20:08
  • 1
    I've found that these commands are very fragile, e.g. `if("cxx_std_20" IN_LIST ${CMAKE_CXX_COMPILER_FEATURES})` fails, while `if("cxx_std_20" IN_LIST my_list)` works. – einpoklum Mar 25 '23 at 14:48
12

Fewer lines:

if (";${ARGN};" MATCHES ";bar;")
  #  ...
endif()

But see the IN_LIST syntax from @sakra for a more-modern syntax.

steveire
  • 10,694
  • 1
  • 37
  • 48
7

I have been using one liner like if ("${PLATFORM}" MATCHES "^(os|ios|android|linux|win32)$") to check if PLATFORM is in the list

Jifeng Zhang
  • 5,037
  • 4
  • 30
  • 43
  • It might be ok for your use case, but does not work in general. (a) You have to know the list, a dynamic list does not work. (b) The list is limited to a dozen of entries, otherwise it is difficult to maintain. (c) It is less obvious to the reader, what this cold is supposed to do. (d) MATCHES is slow, because it uses a regular expression. – usr1234567 Nov 28 '16 at 14:42
4

If the intention here is to add a value to a list but only if it's not already in the list, then an alternative approach is to just add it to the list and immediately remove possible duplicates again:

list(APPEND            SOME_LIST "value")
list(REMOVE_DUPLICATES SOME_LIST)
tanius
  • 14,003
  • 3
  • 51
  • 63