Optional Code, Approach 2: Pushing Optionality Down In Module Interface

Remove Too Much CMake Optionality

  • Remove optional descending from toplevel CMakeLists.txt

  • Remove optional dependency from libhello

  • Remove DEMO_USE_BLACKLIST from DemoConfig.h.in

  • Test (⟶ macro not defined)

    $ cmake -DUSE_BLACKLIST=ON  ~/work/jfasch-home/trainings/material/soup/cmake/code/
    $ make
    greeter-name.h:8:3: error: #error DEMO_USE_BLACKLIST not defined
    8 | # error DEMO_USE_BLACKLIST not defined
      |   ^~~~~
    
  • How to solve? Where to define macro?

TARGET_COMPILE_DEFINITIONS() (backlist Availablility)

  • Let blacklist announce its availability to its dependers

  • TARGET_COMPILE_DEFINITIONS()

    blacklist/CMakeLists.txt
    TARGET_COMPILE_DEFINITIONS(blacklist PUBLIC DEMO_USE_BLACKLIST=1)
    
  • Test

    • cmake -DUSE_BLACKLIST=ON ... ⟶ works

    • cmake -DUSE_BLACKLIST=OFF ... ⟶ blacklist still used (obviously, because we always announce is as 1)

  • ⟶ put optionality in blacklist

Push Optionality Down In blacklist (⟶ INTERFACE Targets)

  • Naive approach

    IF (${USE_BLACKLIST})
      ADD_LIBRARY(blacklist blacklist.cpp)
    
      TARGET_INCLUDE_DIRECTORIES(blacklist PUBLIC .)
      TARGET_COMPILE_DEFINITIONS(blacklist PUBLIC DEMO_USE_BLACKLIST=1)
    ELSE()
      TARGET_COMPILE_DEFINITIONS(blacklist PUBLIC DEMO_USE_BLACKLIST=0)
    ENDIF()
    
    $ cmake -DUSE_BLACKLIST=OFF  ~/work/jfasch-home/trainings/material/soup/cmake/code/
    CMake Error at blacklist/CMakeLists.txt:7 (TARGET_COMPILE_DEFINITIONS):
      Cannot specify compile definitions for target "blacklist" which is not
      built by this project.
    
    -- Configuring incomplete, errors occurred!
    
  • INTERFACE targets: dependency nodes, but without anything that’s built

  • Can have dependencies itself (TARGET_LINK_LIBRARIES())

  • Ours has TARGET_COMPILE_DEFINITIONS()

    IF (${USE_BLACKLIST})
      ADD_LIBRARY(blacklist blacklist.cpp)
    
      TARGET_INCLUDE_DIRECTORIES(blacklist PUBLIC .)
      TARGET_COMPILE_DEFINITIONS(
            blacklist INTERFACE DEMO_USE_BLACKLIST=1) # <--- INTERFACE: propagate-only
    ELSE()
      ADD_LIBRARY(blacklist INTERFACE)                # <--- INTERFACE: there is no library here
      TARGET_COMPILE_DEFINITIONS(
            blacklist INTERFACE DEMO_USE_BLACKLIST=0) # <--- INTERFACE: propagate-only
    ENDIF()
    

Good Or Bad?

Is this better than the other approach?

  • Is is more flexible

  • Optionality is local, between provider (blacklist) and consumer (libhello)

  • Is it simpler? Probably not!