-
-
Notifications
You must be signed in to change notification settings - Fork 320
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SConsCPPConditionalScanner fails evaluate nested defines #4623
Comments
I cleaned the example up a little bit, and yes, I can see the same thing happen.
Well, yes. Internally, it converts the @ivankravets any thoughts? I think you knew this code fairly well... |
A quick hack shows that one level of substitution on
|
There is another issue tightly coupled with this one: The
and with this main.c file: /**
* @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.
*/
#define IS_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
#if IS_ENABLED(FEATURE_A_ENABLED)
#include "header1.h"
#endif
int main()
{
} |
It doesn't do any macro expansion on the contents of CPPDEFINES. That's not limited to the "new" conditional scanner. |
Will it do macro expansion if a define is inside the file instead, e.g |
Just terminology - the conditional scanner is much newer. I haven't really thought about what happens to defines in the file, I think that works - I think that was the intent of the conditional scanner in the first place. |
Thanks for clarifying. |
I don't seem to get the same results, this works out for me even with the old scanner:
|
I'd argue overcomplicated pre-processor logic to determine defines and includes might be better replaced with logic in your SConstruct. |
Yes, the old one works since it always picks all includes ignoring any pre-processor stuff. My experiment was with conditional scanner. My expectation is that if in the code I have
$ cat main.c
#define FEATURE_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.
*/
#define IS_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
#if IS_ENABLED(FEATURE_A_ENABLED)
#include "header1.h"
#endif
int main()
{
} $ 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 !!!")
|
ah, I see. yes, setting it to 0 still picks the header. |
@bdbaddog : Sure, I just wanted to know what currently is possible / supported before I dive and implement an alternative solution for non supported part. I really like the SCons pre-processor stuff since it is way faster then calling gcc's -MM, -MD to get dependency list and manipulate with it. |
Another issue, and this time it's pretty simple and silly :) I still can't understand what kind of bug can cause this.
$ cat main.c
#if defined (A1L)
#include "header1.h"
#endif
int main()
{
} $ scons -Q
deps: []
expected_deps: ['header1.h']
TypeError: exceptions must derive from BaseException:
File "/home/andrey/scons_bug/SConstruct", line 21:
raise("!!! Dependencies do not match expected dependencies !!!") |
Pretty sure the magic is there's a digit followed by |
And indeed that wasn't too hard to find...
That will turn the |
I just confirmed as well that without any digit in it, it does work. Also ending with |
Hmm. so the symbol needs to be all numeric followed by L or UL for this transformation to be correct? |
I don't know about correct, but for it to take place, yes. The intent it to recognize numeric strings like |
Here are some examples in which case scons fails to evaluate:
All these are valid C/C++ define names but SCons fails to deal with them. So basically any string which contains a number followed by |
Wonder if it's good enough to just add beginning whitespace (and maybe ending space-or-newline) to the regexes? Or will that mess up other things?
|
I think this should fix it.. |
Fix for this UL/L issue in #4624 |
Uh.. Yes it does. Check the PR. #4624 I added a test to cover x1233l x1234UL, and left the other 123l, 124ul.. which was working. Are you checking via https://regex101.com/ ? Check in the match information section of the page. |
Please don't post screenshots.. Also move these comments over to the PR.. #4624 |
@relfock - updated code in PR. Please take a look and comment there. |
Simplistic macro replacement is now done on the contents of CPPDEFINES, to improve accuracy of conditional inclusion as compared to the real preprocessor (ref: issue SCons#4623). Signed-off-by: Mats Wichmann <[email protected]>
Simplistic macro replacement is now done on the contents of CPPDEFINES, to improve accuracy of conditional inclusion as compared to the real preprocessor (ref: issue SCons#4623). Signed-off-by: Mats Wichmann <[email protected]>
I can confirm that the macro expansion for The |
@relfock See #4629 (comment) for some notes concerning the SCons C preprocessor implementation. Disclaimer: it is possible that some of the information presented may be erroneous. Maintain a healthy skepticism. |
@jcbrill : Thank you for the notes and fixes for the possible ones. I'll let you know if I see any other issue which is not listed in your 'Known/Potential issues' notes. @bdbaddog: Seems like most of the issues described in this issue has been fixed. Should we close this issue now or you would like to keep it open for the recursive expansion of the macro issue ? |
Simplistic macro replacement is now done on the contents of CPPDEFINES, to improve accuracy of conditional inclusion as compared to the real preprocessor (ref: issue SCons#4623). Signed-off-by: Mats Wichmann <[email protected]>
@relfock - can you create an enhancement request for any remaining issues, and then we'll close this one? |
Simplistic macro replacement is now done on the contents of CPPDEFINES, to improve accuracy of conditional inclusion as compared to the real preprocessor (ref: issue SCons#4623). Signed-off-by: Mats Wichmann <[email protected]>
Simplistic macro replacement is now done on the contents of CPPDEFINES, to improve accuracy of conditional inclusion as compared to the real preprocessor (ref: issue SCons#4623). Signed-off-by: Mats Wichmann <[email protected]>
Simplistic macro replacement is now done on the contents of CPPDEFINES, to improve accuracy of conditional inclusion as compared to the real preprocessor (ref: issue SCons#4623). Signed-off-by: Mats Wichmann <[email protected]>
The SConsCPPConditionalScanner fails to evaluate a
#if
pre-processor directive to True if the following defines are passed:env['CPPDEFINES'] = ['A=1', 'B=C', 'C=1']
and if I have a code with the following line:
main.c contains this
SConstruct:
The
SConsCPPConditionalScanner
seems to treat the value of B define as a string instead of another define thus resulting in the evaluation of#if
False instead of True.The text was updated successfully, but these errors were encountered: