Is it possible to have a custom availability macro like the __OSX_AVAILABLE_STARTING for instance. I need it to perform in the same way, I just need to change its name and the versions and number of parameters?
Yes, certainly. Objective-C is a strict superset of C, so C macros are very much at your disposal, and that facility is simply a set of C macros that eventually expand to
gcc's __attribute__ keyword to declare special attributes of a function.
The relevant declarations are all in
Availability.h
AvailabilityInternal.h
To refresh, you use the __OSX_AVAILABLE_STARTING macro to tag a function declaration as being supported for a particular version, like this:
extern void mymacfunc() __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_NA);
So what do we need to implement this ourselves? If you strip their
support for two different OS (mac, iphone), the availability facility boils down to:
A macro that takes a version argument like __MY_AVAILABLE_STARTING(<version>):
#define __MY_AVAILABLE_STARTING(_myversion) __MY_AVAILABILITY_INTERNAL##_myversion
Set of version arguments, like those in Availability.h, that are valid arguments for the above:
#define __MYVER_2_0 20000
#define __MYVER_2_1 20100
#define __MYVER_2_2 20200
#define __MYVER_3_0 30000
Another set of macros, like thos in AvailabilityInternal.h that specifies what should happen for each version (regular support, deprecated, unavailable, weak, etc). Again, this is a function of the compiler, see gcc docs (there are lots of other interesting options):
#define __MY_AVAILABILITY_INTERNAL__MYVER_2_0 __AVAILABILITY_INTERNAL_UNAVAILABLE
#define __MY_AVAILABILITY_INTERNAL__MYVER_2_1 __AVAILABILITY_INTERNAL_WEAK_IMPORT
#define __MY_AVAILABILITY_INTERNAL__MYVER_2_1 __AVAILABILITY_INTERNAL_REGULAR
And finally, where the buck ends, the macros that expand to the __attribute__ facility.
For the ones I have above, you can just keep using Apple's macros:
#define __AVAILABILITY_INTERNAL_DEPRECATED __attribute__((deprecated,visibility("default")))
#define __AVAILABILITY_INTERNAL_UNAVAILABLE __attribute__((unavailable,visibility("default")))
#define __AVAILABILITY_INTERNAL_WEAK_IMPORT __attribute__((weak_import,visibility("default")))
#define __AVAILABILITY_INTERNAL_REGULAR __attribute__((visibility("default")))
Or, of course, you can define your own craziness.
C Macros are powerful stuff, often overlooked. Good luck!
Related
I'm trying to concatenate a word in the source code with the expansion of a preprocessor macro. Basically I have foo somewhere in the code, and with a #define EXPANSION bar I want to obtain foobar. However, I'm struggling to find a way to do this, which works with all compilers. For the moment I would be happy if it works with gfortran and ifort.
According to its documentation, the gfortran preprocessor is a C preprocessor running in "traditional mode", which does not have the ## token paste operator. However, the same effect can be obtained with an empty C-style /**/ comment. The ifort preprocessor seems to behave more like the normal C preprocessor, so normal token pasting does the trick in ifort. Unfortunately the empty /**/ comment does not work in ifort, as the comment is replaced by a single space instead.
Here is a little example:
#define EXPANSION bar
#define CAT(x,y) PASTE(x,y)
#define PASTE(x,y) x ## y
foo/**/EXPANSION
CAT(foo,EXPANSION)
For which gfortran produces:
foobar
foo ## bar
While ifort gives me:
foo bar
foobar
Of course I could choose the right way by checking the predefined macros for both compilers:
#ifdef __GFORTRAN__
foo/**/EXPANSION
#else
CAT(foo,EXPANSION)
#endif
This works for both of them, but it's rather ugly to have the preprocessor conditional for every expansion. I would much rather avoid this and have some macro magic only once in the beginning.
I have seen this answer to another question, which would probably allow me to work around this issue, but I would rather find a solution that does not invoke the preprocessor separately.
I'm not too familiar with the C preprocessor. Maybe there is a simple way to do what I want. Any ideas?
EDIT: I've already tried something like this:
#define EXPANSION bar
#define CAT(x,y) PASTE(x,y)
#ifdef __GFORTRAN__
#define PASTE(x,y) x/**/y
#else
#define PASTE(x,y) x ## y
#endif
CAT(foo,EXPANSION)
Unfortunately this does not work in gfortran where it produces fooEXPANSION. I'm not entirely sure how this works, but apparently the expansion of the CAT macro prevents the expansion of EXPANSION in the same line. I suspect that this is a feature of the "traditional" C preprocessor ...
I have done some research and it seems that basically most Fortran compilers (i.e. Intel and PGI) use a relatively normal C-preprocessor with a token pasting operator. We only need a special treatment for gfortran, which uses a C preprocessor in traditional mode without a token pasting operator.
Thanks to an entry on c-faq.com I found this definition of a CAT macro that works with all compilers I tested so far:
#ifdef __GFORTRAN__
#define PASTE(a) a
#define CAT(a,b) PASTE(a)b
#else
#define PASTE(a) a ## b
#define CAT(a,b) PASTE(a,b)
#endif
Another solution (that still uses the /**/ trick) was posted by Jonathan Leffler in this answer to a related question.
I have a macro DDLogDebug(...) and I would like to do the following
#define _DDLogDebug(arg...) DDLogDebug(args)
#undef DDLogDebug
#define DDLogDebug(args...) doSomething(); _DDLogDebug(arg...)
But it does not work. Instead of #define _DDLogDebug(arg...) DDLogDebug(args), I would need a command that "stores" the content of the macro DDLogDebug to _DDLogDebug.
Does something like that exist?
How should one do when one wants to modify a macro whose definition is not exposed?
You can't do something like this with the purely standard preprocessor.
The reason is that macro definition doesn't work like e.g. function definition in the main language: at the time when you define _DDLogDebug, it isn't actually linking to the definition of DDLogDebug - it's storing exactly what you wrote. It won't attempt to actually find an expansion for any names until the macro is being used in the program outside of any definitions. By that point, the definition for DDLogDebug is already gone.
This is actually a valuable and intended behaviour, because it allows the use of techniques like X-macros: one definition can provide a framework and let different calling contexts decide how to actually use it in different ways. Not only is the outer macro not dependent on definitions available at the time it was written, but meaning of its contents can change throughout the program without having to change its structure.
If you can't work around this problem, you might have some luck with the non-standard but widely-supported push_macro and pop_macro directives.
Example of the use of push and pop:
#define FOO 123
#pragma push_macro("FOO")
#undef FOO
FOO
#pragma pop_macro("FOO")
FOO
Run this through gcc -E and you'll see it emits FOO (newline) 123. Works with Clang.
I'd like to be able to ensure I don't accidentally statically link any proprietary modules into the kernel. I was thinking of making MODULE_LICENSE("Proprietary") fail at compile time if MODULE was not defined. (or even better, fail if MODULE_LICENSE("GPL") was not defined...).
But I can't find a good way to compare strings within a macro -- anyone have any good solutions to this?
I don't think you can do this.
The way it's usually done is by defining preprocessor symbols, and comparing their (integer) values:
#define LICENSE_PROPRIETARY 1
#define LICENSE_GPL 2
#define LICENSE_MIT 3
#define MODULE_LICENSE LICENSE_GPL
#if MODULE_LICENSE != LICENSE_GPL
#error "Not GPL, fail fail"
#endif
I have a library that has several options defined as this:
#define shouldShowToolbar YES
#define shouldAlignToLeft YES
etc..
and I'm looking for a way to actually replace those from outside (without modifying the library, because the future updates will break it). Is it possible, or am I doomed to change the library source code (which I do have) every time an update comes out.
There is #undef
#include "library_header.h" /* Which defines the macro. */
#undef shouldShowToolbar /* You undef it. */
#define shouldShowToolbar NO /* If you want, you can redefine it. */
http://gcc.gnu.org/onlinedocs/cpp/Undefining-and-Redefining-Macros.html
If you don't want a particular macro to take effect for a section of code and you know that macro name too, you can use
#undef shouldShowToolbar
/* Your code */
#define shouldShowToolbar
This wont totally undef the macro, cos you never know which part of your code might actually want it
These are values that are hardcoded at compile time. If you compile the library with your project then you should be able to redefine them in a file that compiles later in the compile list, I think there is a special keyword for it. Otherwise it is like saying I want to replace YES in the library.
As far as i know, preprocessor directives executes before compilation. So after that, there's no chance to change something.
I want to realize logging in my project.
I have macro, smth like
__LOG_TRACE(lg, expr,...) LOG_TRACE_STREAM(lg) << expr;
So I want to realize interface for this macro - another macro, but I want to support 2 types:
LOG_TRACE(msg);
LOG_TRACE(my_logger, msg);
I have some global logger, and first macro will write msg using global logger.
Second macro will take my_logger and write msg using it.
I can make it with LOG_TRACE(msg, my_logger); - but it's not good, it's harder to read in code. Order of arguments in __LOG_TRACE is not necessary.
Upd:
I don't mean overloading macros.
Look - for example I can do this
#define LOG_TRACE(...) __LOG_TRACE(__VA_ARGS__, current_active)
Now I can write
LOG_TRACE(msg);
LOG_TRACE(msg, logger);
But I want not msg,logger and logger,msg
Macro overloading is not allowed in C or C++. But there are workarounds. Here's an article that will help you "overload" your macro: http://cplusplus.co.il/2010/08/31/overloading-macros/
If you don't have a variable number of loggers, i recommend you to make a macro for each logger. ex (LOG_TRACE_XML, LOG_TRACE_OUT, LOG_TRACE_TXT). Because simpler is better.
But a better way to do this is to have LOG_TRACE_ERROR/ LOG_TRACE_WARNING/ LOG_TRACE_INFO and manage the way these macros behave using IPC or another macro (SET_MODE(XML/TXT/OUT))
You cannot overload pre-processor macros, your compiler will consider this a redeclaration, rather than an overload, and so only the 2nd will be valid.
You should attempt to name your macros differently, both for readability and because that's the only way you'll get the functionality you want.
Why not make it a function + do and stringify expression macro?
#define DO_AND_RETURN_STRING_EXPR(x) (x,#x)
ov(DO_AND_RETURN_STRING_EXPR(y))
ov(my_logger, DO_AND_RETURN_STRING_EXPR(y))
(note I haven't tested this code).
__VA_ARGS__ is an extension to the current C++ standard, but if you are willing to play with this P99 has a lot of utility macros to achieve what you want. In particular macros that implement conditionals according to the number of arguments they are called.
#define LOG_TRACE(...) \
P99_IF_EQ_1(P99_NARG(__VA_ARGS__)) \
(LOG_TRACE_(my_logger, __VA_ARGS__)) \
(LOG_TRACE_(__VA_ARGS__))
P99 is not really C++ compatible, so you'd have to adapt things a bit.
BTW, identifiers that start with _ and a capital letter or another underscore are reserved by C and C++. Double underscores in general are not allowed for C++ because they could interfere with name mangling. So you'd better chose a different name for your base macro.