# Re-export private compile definitions as interface definitions (cmake 3.12)

**URL:** <https://discourse.cmake.org/t/re-export-private-compile-definitions-as-interface-definitions-cmake-3-12/498>\
**Category:** Code\
**Created:** [January 14, 2020, 8:20pm UTC](https://discourse.cmake.org/t/re-export-private-compile-definitions-as-interface-definitions-cmake-3-12/498 "2020-01-14T20:20:11Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![reuk](https://discourse.cmake.org/user_avatar/discourse.cmake.org/reuk/32/294_2.png) [@reuk](https://discourse.cmake.org/u/reuk)\
**Post date:** [January 14, 2020, 8:20pm UTC](https://discourse.cmake.org/t/re-export-private-compile-definitions-as-interface-definitions-cmake-3-12/498/1 "2020-01-14T20:20:11Z")

</div>

Given the following CMakeLists, I would expect the ‘genexdebug’ target to print out “foo bar” when run, but it only prints “foo”. Can anyone tell me why? What’s the best way to check for specific private definitions, and to reexport them as interface definitions if they exist?

Thanks for your help!

```auto
cmake_minimum_required(VERSION 3.12)
project(test)

add_library(foo INTERFACE)
target_compile_definitions(foo INTERFACE foo)

add_library(bar INTERFACE)
target_compile_definitions(bar INTERFACE bar)

set(source ${CMAKE_CURRENT_BINARY_DIR}/main.cpp)
file(TOUCH ${source})

add_library(combined ${source})
target_link_libraries(combined PRIVATE foo bar)

set(combined_defs $<TARGET_PROPERTY:combined,COMPILE_DEFINITIONS>)

foreach(def IN ITEMS foo bar)
    target_compile_definitions(combined INTERFACE $<$<IN_LIST:${def},${combined_defs}>:${def}>)
endforeach()

add_custom_target(genexdebug COMMAND ${CMAKE_COMMAND} -E echo $<TARGET_PROPERTY:combined,INTERFACE_COMPILE_DEFINITIONS>)

```

---

<div class="post-metadata">

**Author:** ![McMartin](https://discourse.cmake.org/user_avatar/discourse.cmake.org/mcmartin/32/150_2.png) [@McMartin](https://discourse.cmake.org/u/McMartin)\
**Post date:** [January 14, 2020, 11:12pm UTC](https://discourse.cmake.org/t/re-export-private-compile-definitions-as-interface-definitions-cmake-3-12/498/2 "2020-01-14T23:12:21Z")

</div>

This seems to be a bug in CMake.

It took me quite some time to debug, but this is what is happening:

- `$<TARGET_PROPERTY:combined,INTERFACE_COMPILE_DEFINITIONS>` is parsed and evaluated to  
`$<$<IN_LIST:foo,$<TARGET_PROPERTY:combined,COMPILE_DEFINITIONS>>:foo>;$<$<IN_LIST:bar,$<TARGET_PROPERTY:combined,COMPILE_DEFINITIONS>>:bar>`.

- The first occurrence of `$<TARGET_PROPERTY:combined,COMPILE_DEFINITIONS>` is parsed and evaluated to `"foo;bar"` as expected. So we get `$<$<IN_LIST:foo,foo;bar>:foo>` which is evaluated to `"foo"`, all good.

- The second occurrence of `$<TARGET_PROPERTY:combined,COMPILE_DEFINITIONS>` is parsed and evaluated to `""`, not good. What is happening?

I don’t know how to fix this bug, but to workaround it you’ll need to find a way to call `target_compile_definitions(combined INTERFACE ...)` with a generator expression that contains `$<TARGET_PROPERTY:combined,COMPILE_DEFINITIONS>` only once.

---

<div class="post-metadata">

**Author:** ![reuk](https://discourse.cmake.org/user_avatar/discourse.cmake.org/reuk/32/294_2.png) [@reuk](https://discourse.cmake.org/u/reuk)\
**Post date:** [January 14, 2020, 11:30pm UTC](https://discourse.cmake.org/t/re-export-private-compile-definitions-as-interface-definitions-cmake-3-12/498/3 "2020-01-14T23:30:05Z")

</div>

Wow, thanks for the detailed response! I wasn’t expecting a cmake bug…

The 'single evaluation of `$<TARGET_PROPERTY:combined,COMPILE_DEFINITIONS>`’ is very awkward. I think in cmake 3.15+ the FILTER generator expression would work. However, I can’t think of a way of achieving anything similiar in 3.12, as the list-processing generator expressions are more limited in that version. I’m going to sleep on it, but in the meantime, if anyone has any idea how this might be achieved in 3.12, I’d be incredibly grateful!

---

<div class="post-metadata">

**Author:** ![marc.chevrier](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/ecb155/32.png) [@marc.chevrier](https://discourse.cmake.org/u/marc.chevrier)\
**Post date:** [January 15, 2020, 2:57pm UTC](https://discourse.cmake.org/t/re-export-private-compile-definitions-as-interface-definitions-cmake-3-12/498/4 "2020-01-15T14:57:16Z")

</div>

The result can be done without using generator expressions:

```cmake
cmake_minimum_required(VERSION 3.12)
project(test)

add_library(foo INTERFACE)
target_compile_definitions(foo INTERFACE foo)

add_library(bar INTERFACE)
target_compile_definitions(bar INTERFACE bar)

set(source ${CMAKE_CURRENT_BINARY_DIR}/main.cpp)
file(TOUCH ${source})

add_library(combined ${source})
target_link_libraries(combined PRIVATE foo bar)

get_property (deps TARGET combined PROPERTY LINK_LIBRARIES)
foreach (dep IN LISTS deps)
  get_property (defs TARGET ${dep} PROPERTY INTERFACE_COMPILE_DEFINITIONS)
  list (FILTER defs INCLUDE REGEX "^(foo|bar)$")
  target_compile_definitions (combined INTERFACE ${defs})
endforeach()

add_custom_target(genexdebug COMMAND ${CMAKE_COMMAND} -E echo "\"$<TARGET_PROPERTY:combined,INTERFACE_COMPILE_DEFINITIONS>\"")

```

---

<div class="post-metadata">

**Author:** ![reuk](https://discourse.cmake.org/user_avatar/discourse.cmake.org/reuk/32/294_2.png) [@reuk](https://discourse.cmake.org/u/reuk)\
**Post date:** [January 15, 2020, 3:31pm UTC](https://discourse.cmake.org/t/re-export-private-compile-definitions-as-interface-definitions-cmake-3-12/498/5 "2020-01-15T15:31:02Z")

</div>

Thanks for the reply! Unfortunately I don’t think this will work for my use-case, as in my project `combined` is created/configured by a factory function for a custom target type, and users may link extra libraries to it at any point after this factory function has returned. That is, at the point where `combined` is created, we don’t know the full set of libraries that it will link against, and I was using generator expressions so that the full set of transitive compile definitions would be available.

---

<div class="post-metadata">

**Author:** ![marc.chevrier](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/ecb155/32.png) [@marc.chevrier](https://discourse.cmake.org/u/marc.chevrier)\
**Post date:** [January 15, 2020, 3:34pm UTC](https://discourse.cmake.org/t/re-export-private-compile-definitions-as-interface-definitions-cmake-3-12/498/6 "2020-01-15T15:34:08Z")

</div>

In this case, apply my example snippet as the end of the main CMakeLists.txt., after **all** `CMakeLists.txt` had been processed.
