4

I am a bit confused about scoping rules of cmake. I do have files and directories like

 ├── test
 │    CMakeLists.txt 
 │   ├── cmake
 │   │       MyCMake 
 │   │       MyCMake2 
 │   ├── child
 │   │       CMakeLists.txt 

The contents are:

cmake/MyCMake:

set(MY_NAME MyName)
message("MyCMake: " ${MY_NAME} " " ${YOUR_NAME} " " ${HIS_NAME})

cmake/MyCMake2:

set(HIS_NAME NewName)
message("MyCMake2: " ${MY_NAME} " " ${YOUR_NAME} " " ${HIS_NAME})

child/CMakeLists.txt:

set(YOUR_NAME YourName)
set(HIS_NAME HisName PARENT_SCOPE)
message("Child: " ${MY_NAME} " " ${YOUR_NAME} " " ${HIS_NAME})

test/CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
include(MyCMake)
add_subdirectory(child)
message("Parent1: " ${MY_NAME} " " ${YOUR_NAME} " " ${HIS_NAME})
include(MyCMake2)
message("Parent2: " ${MY_NAME} " " ${YOUR_NAME} " " ${HIS_NAME})

The result is

MyCMake: MyName  
Child: MyName YourName 
Parent1: MyName  HisName
MyCMake2: MyName  NewName
Parent2: MyName  NewName

This first line is OK, the 2nd and third variables are not yet defined. With the second line, it looks like it is a parent-only setting, i.e. the defined variable has a scope ONLY in the parent. (So, I can/shall the same variable with local scope?) The third line shows only variable with parent scope, OK. The 4th line shows that I set a LOCAL scope variable. In the 5th line, however, I see that the PARENT scope value has changed, which I expected to be changed ONLY locally, in the child subdirectory. What is going on here? (it looks like I can overwrite a value of the variable, which is not in my scope)

Why I started to experiment: under some conditions I do not see in the parent directory the variables (like include directories, library names, etc.) defined in the child directory. Is there a standard way to use say a library name for building in one child, and use the same name in another child for linking?

Also a question: I have an application, consisting of a library and an executable. It looks like that CMake does not allow to use the same target name for both. In my eyes, if I use name 'A' both for binary target and library target, it should not result in confusion, because the real second target is 'libA'. Am I wrong?

katang
  • 2,474
  • 5
  • 24
  • 48
  • For the first question see [What's the CMake syntax to set and use variables?](http://stackoverflow.com/questions/31037882). For your second question I suppose you are searching for [Check for optionally targets in cmake that are not in the correct order](http://stackoverflow.com/questions/32766151). For your third question you may want to take a look at [add_custom_command is not generating a target](http://stackoverflow.com/questions/30719275) – Florian Dec 22 '15 at 15:04

1 Answers1

16

The basic rule is simple: add_subdirectory establishes a new scope, include does not. So your example has just two scopes involved:

  • The scope of the top-level CMakeList, which is affected by the set(...) commands in MyCMake and MyCMake2, and by the set(... PARENT_SCOPE) command inside child/CMakeLists.txt.
  • The scope of the child CMakeList child/CMakeLists.txt, which is affected by the set(...) commands inside child/CMakeLists.txt which do not use PARENT_SCOPE.

You are correct that PARENT_SCOPE sets the value in the parent scope only. If you want to set the value both for the current scope and for the parent, you have to issue two set commands:

set(var Value)
set(var Value PARENT_SCOPE)

We generally prefer one question per question here on Stack Overflow, but I will answer the target naming question as well: CMake target names are logical names of the targets for CMake, and they have to be unique. Imagine if that was not the case:

add_library(L STATIC ...)
add_library(A SHARED ...)
add_executable(A ...)

target_link_libraries(A L)

What would be the effect of the last line? Would the library A link against L, or would the executable A do so? Or both? Dtto for setting properties etc.

You can control the name of the produced binary independently from its target name: refer to target properties like OUTPUT_NAME for details.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • Basically, I agree with the "one question per question" rule, but this time the three questions are interrelated and the mandatory delay between questions means I need 4.5 hours to post three questions. Concerning the logical names: you are right, but this scheme prevents to create a binary with name A using library libA. – katang Dec 22 '15 at 19:01
  • 1
    @katang No, it does not prevent the binary-library scheme at all. You just give the targets logical names `A_bin` and `A_lib`, and set both of their `OUTPUT_NAME` properties to `A`. *Nothing* prevents you from doing that. – Angew is no longer proud of SO Dec 23 '15 at 09:59