Optional Code, Approach 1: Optional blacklist, C Macro (Global Flags)

Optional blacklist, C Macro

  • Descend into blacklist directory optionally

    Toplevel CMakeLists.txt
    IF (${USE_BLACKLIST})
      ADD_SUBDIRECTORY(blacklist)
    ENDIF()
    
  • Provide C macro for occasional C macro orgies

    Toplevel CMakeLists.txt
    # for configure-file macro, define parallel variable with real bool
    # values
    IF (${USE_BLACKLIST})
      SET(MACRO_USE_BLACKLIST 1)
    ELSE()
      SET(MACRO_USE_BLACKLIST 0)
    ENDIF()
    
    DemoConfig.h.in
    #define DEMO_USE_BLACKLIST @MACRO_USE_BLACKLIST@
    

Optional Dependency In libhello

  • Optional TARGET_LINK_LIBRARIES()

    libhello/CMakeLists.txt
    IF (${USE_BLACKLIST})
      TARGET_LINK_LIBRARIES(hello blacklist)
    ENDIF()
    

Note

This is a massacre!

Optional Dependency In libhello Header File

Note

This is a software design choice. Putting optional code in header file leads to messy code, no matter which build system.

  • Designer’s / Architect’s choice: dependency in greeter-name.h header file

  • ⟶ massacre

  • All users (“dependers”) of libhello need to have include path to blacklist.h

  • Macro-conditionals all over the place

#include <DemoConfig.h>                                // <--- dependency in header file!!!
#ifndef DEMO_USE_BLACKLIST
# error DEMO_USE_BLACKLIST not defined                 // <--- guard against build system bugs
#endif
#if DEMO_USE_BLACKLIST == 1
#  include <blacklist.h>                               // <--- dependency in header file!!!
#endif

#include <string>

class NameGreeter : public Greeter
{
private:
#if DEMO_USE_BLACKLIST == 1                            // <--- dependency in header file!!!
    Blacklist _blacklist;
#endif
};

Note

All users of libhello need to be aware!

Optional Dependency In libhello CPP File

  • If one likes macros, then this is normal business

  • No implications on users, as opposed to conditional code in header file

void NameGreeter::sayhello()
{
#if DEMO_USE_BLACKLIST == 1
    if (_blacklist.is_forbidden(_name))
        std::cout << "Goodbye " << _name << '\n';
#else
    std::cout << "Hello " << _name << '\n';
#endif
}

Good Or Bad?

What is this approach?

  • ⟶ Using “globals” a lot

    • USE_BACKLIST defined toplevel, and used in libhello to conditionally add dependency on blacklist

    • C macro defined toplevel - in DemoConfig.h.in

Is there a better way?

  • Almost always 🥷