-
Notifications
You must be signed in to change notification settings - Fork 2.1k
core/kernel_defines: Introduce 'IS_ACTIVE' macro #12626
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
core/kernel_defines: Introduce 'IS_ACTIVE' macro #12626
Conversation
Well,
still fails to compile:
|
And it's correct, the function does not exist. If that was an |
Just to clarify, I'm not proposing to remove all our |
This makes sense to me. The approach will simply not work in any case (e.g. additional cases in a Also: If the generated boolean is a compile time constant, any compiler called with To me, the improvement in readability is worth the effort of getting to know a second tool; especially as its use is rather trivial. |
I know. Just wanted to point out that it can only applied in some cases.
Yes, we're relying on that already in the DEBUG macro.
I'd like to add a convention to only use this if it can actually be used in all cases throughout a file. Otherwise we'll have some occurrences using What's wrong with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should work, but only when the macros are defined to 1
and not to e.g. (1)
or 1U
. It would not hurt to document this so that noone changes the way the build system defines those modules without adapting this header.
Update: There was a not missing in a crucial place of the sentence before.
Personally I would like to keep |
Here or on |
I personally have no strong feelings about this, but I would do it like this: Document it here and add a short reference to that doc in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
documentation wise this looks good to me, quite clear and elaborate 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to get more opinions on this.
I'm usually advertising RIOT as "mostly macro-free". And it is.
ARRAY_SIZE
was simple, usable everywhere and also automatically enforcable. This is neither.
My gut feeling is that the slight benefits in syntax-checking code (and subjective readability) for some cases is not worth the downsides of using the macro.
(Blocking to get more time for discussion.)
Just to name some:
I'd like to suggest to use, where possible, something explicit like:
|
I personally like the idea of get rid of I don't remember where, but I remember seeing some cases where the static checks didn't detect a dereferenced NULL pointer because they were surrounded by I think it would be a huge overhead to define |
Of course!
I don't see this as inconsistency, they are meant for different things. We should encourage the usage of C conditionals where possible, so we can get the benefits of checking and readability, and allow the author to use
If used as intended (not just limited to "only use if can actually be used in all cases throughout a file") I think the benefits are not slight.
Again, I don't think having multiple ways is inconsistent, as we can clearly define in which cases to use each of the alternatives.
I can understand this seems more explicit than a macro, but I think it will create a lot of overhead to define this every time we want to check for a module or submodule, compared to having a single macro to do it. |
How many submodule dependencies do we expect per file / subsystem header (that would get checked either by
I agree with that. The syntax checks helped a lot for cleaning up broken Still, macros are bad. They should be avoided, if possible. In this case, it is possible. The overhead of a couple of clear |
Yes, but the code base will not reflect what we define. |
I understand many of the concerns with using macros in general, but I think that they are also an useful tool, and when used with caution they can simplify the code a lot. Which are your concerns regarding introducing this particular macro? |
What it does is simple: Turn How it works, I don't understand (yet). Its definition is spread over 5 lines, doing, in my eyes, preprocessor magic. If it breaks, I cannot debug or fix it. I cannot forsee if it can or will be misused (what happens on |
Something that comes to mind:
... will happily compile even if the module is actually named MODULE_GNRC_SIXLOWPAN_IPHC. Because by definition, Same with the current |
It will work with any preprocessor that is fully C99 compliant.
For anything that the preprocessor does not replace by the literal
If the build system would be aware of all possible module (and pseudo-module) names, it could simple define For "real" modules traversing the filesystem could yield the list (but would come with a performance penalty?). For pseudomodules we could parse the |
Yup. I'm experimenting with that. One big thing is getting out the information which module uses which other modules "optionally", as in, it does not depend on it but is changed by it. I did that with scripts grepping for |
Maybe we could bring a solution to that upstream. In that case we can actually use I think @leandrolanzieri, @smlng, and @jia200x would also be fine with this, right? This would be basically the same idea as presented here, only implemented a bit different. |
My two cents: extensive usage of conditional compilation using preprocessor statements is bad for several reasons:
IMO, the
I don't see how such a long list can be maintained. Modules are added and removed and the list has to stay in sync. Without any sophisticated, scripted auto generation of such a list, I would be against hardcoding. Especially since
Out of curiosity, what is this script used for? Grepping for |
@maribu what do you mean by this?
|
if (MODULE_FOO) {
...
}
#if MODULE_FOO
#endif vs if (IS_ACTIVE(MODULE_FOO)) {
...
}
#if MODULE_FOO
...
#endif |
I see, actually if we include the list: #ifndef MODULE_FOO
#define MODULE_FOO 0
#endif
if (MODULE_FOO) {
...
}
#if MODULE_FOO
#endif vs. if (IS_ACTIVE(MODULE_FOO)) {
...
}
#if MODULE_FOO
...
#endif |
if the problem is about consistency, the example could also be written like: if (IS_ACTIVE(MODULE_FOO)) {
...
}
#if IS_ACTIVE(MODULE_FOO)
...
#endif vs #ifndef MODULE_FOO
#define MODULE_FOO 0
#endif
if (MODULE_FOO) {
...
}
#if MODULE_FOO
#endif |
@maribu thanks for the summary. looking from the outside, I don't see syntax inconsistency in (2). i also don't see that (1) is simpler; in fact, i would argue the contrary (see @cgundogan comments) Therefore, 👍 for this PR (#12626) from my side. |
@kaspar030 how should we proceed with this PR now? The 10-day discussion seems to converge towards an ACK. The only thing missing is now to resolve the block .. |
I got my discussuon, thanks everyone!
👍 @leandrolanzieri could you squash the commits? |
IS_ACTIVE allows to evaluate macro definitions in non-preprocessor expressions. It takes a macro that may be defined to 1 or not defined at all and expands to 1 or 0 respectively.
9eada9f
to
62b6e5e
Compare
@cgundogan squashed |
The approach is well tested in the Linux community. I guess this can count as tested. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK. The macro works as promised and will allow reducing the number of code chunks disabled by #ifdef
and friends. The majority of maintainers favored this approach of the alternatives that were discussed.
thanks all for reviewing! Let's go with this one |
Thank you all for the thorough reviews and discussion. |
Contribution description
This introduces the
IS_ACTIVE
macro tokernel_defines.h
. It is based onIS_BUILTIN
defined in Linux. The main idea behind it is to allow to check macro definitions directly in C expressions (i.e. not with preprocessor directives), even when the macro is not defined (e.g.MODULE_<module>
macros, which will be defined to 1 when the module is used, but won't be defined when it is not).The main advantage is that we can get rid of lots of
#ifdef
s in the code and useif
statements instead, so the compiler can see this code and check for errors. If not used, the compiler will remove those blocks.EDIT
Problem statement
#ifdef
logic is really hard to follow most of times and hides the code from the tooling (e.g. cppcheck, coccinelle, IDEs) which prevents from checking syntax, types, symbol references, etc.This is adopted by different communities (GNU, Linux).
There is a tendency towards using C conditionals where possible.
Example
With the current approach:
Using this macro:
Testing procedure
Issues/PRs references
None.