Libraries included inside conditional guard are still added to the dep graph by LDF

I think I remember that chain+ would properly ignore libraries that are #included guarded by #if and #ifdef conditions. The whole purpose of that + is to do that, right?

But now on my project whatever I do LDF just gives up and includes everything anyway. I tried putting it anywhere - in main, in H, in C files. Doing #if 0 or #ifdef RANDOM_SOEMTHING still adds the library to dep graph…

I can’t fathom the reason why LDF is inconsistent…

I think I have a clue, running with pio run -v gives me

Warning! Classic Pre Processor is used for `file.h`, 
advanced has failed with `tuple index out of range

Trying to debug the pio py script… When using stm32 board, on one project -DSTM32F4 variable without value is parsed as

[('F_CPU', '$BOARD_F_CPU'), ('PLATFORMIO', 50300), 'STM32F4', 'STM32F407xx', 'STM32F40_41xxx', 'FREERTOS_PORT_CM3']

but on another it’s:

[('PLATFORMIO', 50300), ('STM32F4',), ('STM32F407xx',), ('STM32F40_41xxx',), ('LFS_CONFIG', 'lfs_config.h'), ('CORU_CONFIG', 'coru_config.h'), ('CANOPEN_CONFIG', 'canopen_config.h'), ('CO_DRIVER_CUSTOM',), ('FREERTOS_CONFIG', 'freertos_config.h'), ('SQLITE_CUSTOM_INCLUDE', 'sqlite_config.h'), ('ACTOR_CONFIG', 'app_config.h'), ('OD_CONFIG', 'od_config.h'), ('HEAP_CONFIG', 'heap_config.h'), ('FREERTOS_PORT', 'posix'), ('FREERTOS_PORT_CM3',), ('ACTOR_NODE_MOTHERSHIP',), ('F_CPU', '$BOARD_F_CPU'), '']

Notice the tuple with one value. SCons crashes on that when trying to make a dictionary out of it… Trying to get to the root of this…

Wew… So it looks like env.AppendUnique is to blame. Full situation:

  1. Platformio inside its ProcessFlags parses defs like -DA -DB=C into ('A', ('B', 'C')) for env[“CPPDEFINES”]
  2. libopencm3.py script tries to add -DSTM32F4 def via env.ApppendUnique(CPPDEFINES=["STM32F4"]) (which is not really necessary, but that’s irrelevant)
  3. env.AppendUnique turns all previous defs without value (that were strings) into tuples with single value, and adds new values also as tuples: (('A', ), ('B', 'C'), ('STM32F4',))
  4. CPPScanner expects defs without value to be strings, but any invocation of env.AppendUnique breaks that expectation
  5. Scons crashes:
    cppdefines = env.get('CPPDEFINES', {})
    if cppdefines is None:
        return {}
    if SCons.Util.is_Sequence(cppdefines):
        result = {}
        for c in cppdefines:
            if SCons.Util.is_Sequence(c):
                result[c[0]] = c[1]
            else:
                result[c] = None
        return result
  1. PIO drops the ball here IMO and falls back to Classic Pre Processor, which you wouldn’t know without -v flag. I spent two days trying to understand what is going on before i noticed the issue. I don’t think that this silent fall back behavior is good

Need to fix AppendUnique or avoid using it in build scripts if it’s not possible to do

Filed a bug in SCons: AppendUnique breaks CPPScanner when using defs without value · Issue #4108 · SCons/scons · GitHub