26

I'm writing a CMakeLists.txt to generate files and compile the generated files. I create a function to add some file path strings to a global list variable.

My CMakeLists.txt:

set(source_list "nothing")
function(test file_path)
    list(APPEND source_list ${file_path})
endfunction(test)
test(abc.txt)
test(def.txt)
message("At last, the source_list is:\"${source_list}\"")

The cmake output:

At last, the source_list is:"nothing"

Someone suggested that to use macro instead of function, but I do need use local variable, so I need to use the function instead of macro.

How can I correctly set the global variable source_list in the function test()? Can't cmake do it in a simple and normal way?

sean
  • 1,252
  • 3
  • 14
  • 29

6 Answers6

43

PARENT_SCOPE is only for parent, it won't work if you have other non-parent script that want to see it as well.

You need cache for the true "global-like" variable. In your case, use:

SET(source_list  "${source_list}" CACHE INTERNAL "source_list")
Ding-Yi Chen
  • 2,830
  • 33
  • 27
24

Another approach is to use global properties. Once you set it:

set_property(GLOBAL PROPERTY source_list_property "${source_list}")

you can read it from everywhere:

get_property(source_list GLOBAL PROPERTY source_list_property)

I used in examples above the different names for property (source_list_property) and for variable (source_list). Maybe it is better to use the same name. But point is to use a property as global variables, and not about naming.

Such global properties aren't in cache.

Maxim Suslov
  • 4,335
  • 1
  • 35
  • 29
23

You need to use set instead of list to affect the variable in the parent scope.

So replace your list command with:

set(source_list ${source_list} ${file_path} PARENT_SCOPE)
Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
Fraser
  • 74,704
  • 20
  • 238
  • 215
  • 6
    It's not global though, siblings will not see. – 0xbaadf00d Apr 04 '17 at 06:32
  • @JoachimW: Why incorporate two answers into the single one? You seems to misunderstand Question/Answer model on Stack Overflow. We do NOT tend to have **all solutions** in the **single accepted answer**. Instead, having **one answer per solution** is perfect. And an answer's quality is primarily measured by the **voting**, good answers needn't to be marked with the green accept mark. Please, revert this answers merging. – Tsyvarev Oct 01 '18 at 10:37
11

Building upon Maxim Suslov's answer, the following code worked for a similar problem I faced:

set_property(GLOBAL PROPERTY source_list)
function(add_source)
    get_property(tmp GLOBAL PROPERTY source_list)
    foreach(arg ${ARGV})
        set(tmp "${tmp} ${arg}")
    endforeach()
    set_property(GLOBAL PROPERTY source_list "${tmp}")
endfunction(add_source)

add_source(a_file)
add_source(b_file c_file)

get_property(local_prop GLOBAL PROPERTY source_list)
message("list: ${local_prop}")

Function add_source can be called from inside any sub-directory.

Marios V
  • 1,174
  • 9
  • 15
4

Another way to address this issue is using macro instead of function - this way all variables inside macro will be evaluated in context of caller.

Andrey Starodubtsev
  • 5,139
  • 3
  • 32
  • 46
1

You can also work with environment variables.

  SET(ENV{SOURCE_LIST} "$ENV{SOURCE_LIST} newSource")

Test:

  message(STATUS "GLOBAL: $ENV{SOURCE_LIST}")
  -- GLOBAL: newSource /unittest/demo1 /unittest/demo2
Role
  • 86
  • 4