You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The macro expansion for #if (and possibly other statements) is not recursive. Only the first expansion is performed. In this case, evaluation results in a non empty string (the expanded string containing another macro) which is True causing the inclusion of the header. Ref: #4623 (comment)
SConstruct file:
import SCons.Scanner.C
env = Environment()
env['CPPPATH'] = [Dir('.')]
expected_deps = []
c_scanner = SCons.Scanner.C.CConditionalScanner()
deps = c_scanner(File('main.c'), env, env['CPPPATH'])
print("deps: ", [d.get_path() for d in deps])
print("expected_deps: ", [d.get_path() for d in expected_deps])
# Compare deps with expected_deps
if deps == expected_deps:
print("Dependencies match expected dependencies.")
else:
raise("!!! Dependencies do not match expected dependencies !!!")
main.c file:
#defineFEATURE_A_ENABLED 0
/** * @brief Macro for checking if the specified identifier is defined and it has * a non-zero value. * * Normally, preprocessors treat all undefined identifiers as having the value * zero. However, some tools, like static code analyzers, can issue a warning * when such identifier is evaluated. This macro gives the possibility to suppress * such warnings only in places where this macro is used for evaluation, not in * the whole analyzed code. */#defineIS_ENABLED(config_macro) _IS_ENABLED1(config_macro)
/* IS_ENABLED() helpers *//* This is called from IS_ENABLED(), and sticks on a "_XXXX" prefix, * it will now be "_XXXX1" if config_macro is "1", or just "_XXXX" if it's * undefined. * ENABLED: IS_ENABLED2(_XXXX1) * DISABLED IS_ENABLED2(_XXXX) */#define_IS_ENABLED1(config_macro) _IS_ENABLED2(_XXXX##config_macro)
/* Here's the core trick, we map "_XXXX1" to "_YYYY," (i.e. a string * with a trailing comma), so it has the effect of making this a * two-argument tuple to the preprocessor only in the case where the * value is defined to "1" * ENABLED: _YYYY, <--- note comma! * DISABLED: _XXXX */#define_XXXX1 _YYYY,
/* Then we append an extra argument to fool the gcc preprocessor into * accepting it as a varargs macro. * arg1 arg2 arg3 * ENABLED: IS_ENABLED3(_YYYY, 1, 0) * DISABLED IS_ENABLED3(_XXXX 1, 0) */#define_IS_ENABLED2(one_or_two_args) _IS_ENABLED3(one_or_two_args 1, 0)
/* And our second argument is thus now cooked to be 1 in the case * where the value is defined to 1, and 0 if not: */#define_IS_ENABLED3(ignore_this, val, ...) val
#ifIS_ENABLED(FEATURE_A_ENABLED)
#include"header1.h"#endifintmain()
{
}
output:
$ scons -Qn --tree=all
deps: ['header1.h']
expected_deps: []
TypeError: exceptions must derive from BaseException:
File "/hfv/test_battery/scons_bug/SConstruct", line 19:
raise("!!! Dependencies do not match expected dependencies !!!")
The text was updated successfully, but these errors were encountered:
relfock
changed the title
Recursive C/C++ macro expansion for SConsCPPConditionalScanner
Add recursive macro expansion for SConsCPPConditionalScanner
Nov 26, 2024
The macro expansion for #if (and possibly other statements) is not recursive. Only the first expansion is performed. In this case, evaluation results in a non empty string (the expanded string containing another macro) which is True causing the inclusion of the header. Ref: #4623 (comment)
SConstruct file:
main.c file:
output:
More info can be found in the bug #4623
The text was updated successfully, but these errors were encountered: