I'm trying to disable automated crash logs reports when one or both of two defines are set: DEBUG for our debug builds and INTERNATIONAL for the international builds. When I try to do that in the #ifndef case, however, I get the warning Extra tokens at end of #ifndef directive and running with DEBUG defined will trigger Crittercism.
#ifndef defined(INTERNATIONAL) || defined(DEBUG)
// WE NEED TO REGISTER WITH THE CRITTERCISM APP ID ON THE CRITTERCISM WEB PORTAL
[Crittercism enableWithAppID:#"hahayoudidntthinkidleavetherealonedidyou"];
#else
DDLogInfo(#"Crash log reporting is unavailable in the international build");
// Since Crittercism is disabled for international builds, go ahead and
// registers our custom exception handler. It's not as good sadly
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
DDLogInfo(#"Registered exception handler");
#endif
This truth table shows what I expect:
INTL defined | DEBUG defined | Crittercism Enabled
F | F | T
F | T | F
T | F | F
T | T | F
This worked before when it was just #ifndef INTERNATIONAL. I've also tried without the defined(blah) and with parentheses around the whole statement (same warning and an error respectively).
How do I get the behavior I want from the compiler?
You want:
#if !defined(INTERNATIONAL) && !defined(DEBUG)
// neither defined - setup Crittercism
#else
// one or both defined
#endif
Or you can do:
#if defined(INTERNATIONAL) || defined(DEBUG)
// one or both defined
#else
// neither defined - setup Crittercism
#endif
I just found one post Conditional Compilation which can be better explained the differences between #if/#elif and #ifdef/#ifndeffrom syntax level:
#if constant-expression newline
#ifdef identifier newline
#ifndef identifier newline
#else newline
#elif constant-expression newline
#endif newline
So here we can see #ifndef must be followed by 'identifier', that was often the macro defined by #define directive, or #rmaddy said 'a single value'.
But if can be followed by 'constant-expression' so that the conditional expression defined(INTERNATIONAL) || defined(DEBUG) or !defined(INTERNATIONAL) && !defined(DEBUG) can be used.
Related
I'm coding a code in modern Fortran, and I want to do some like:
IF (you are compiling the code with gfortran) Do something...
IF (you are compiling the code with ifort) Do other thing...
but I haven't found a way to verify those logic conditions in the IF statements inside the code.
The easiest way is to look at compiler-specific macros.
For gfortran, you can look at __GNUC__ as described here.
For ifort, you can look at __INTEL_COMPILER as described here.
If you have the file test.F90 (note the .F90 rather than .f90, it's important that this file is preprocessed), then you can have something like
program test
implicit none
#ifdef __GNUC__
logical, parameter :: gfortran = .true.
#else
logical, parameter :: gfortran = .false.
#endif
#ifdef __INTEL_COMPILER
logical, parameter :: ifort = .true.
#else
logical, parameter :: ifort = .false.
#endif
if (gfortran) then
write(*,*) 'gfortran'
elseif (ifort) then
write(*,*) 'ifort'
else
write(*,*) 'Unknown compiler'
endif
end program
First question here.
I have some troubles with the XCode Build System, specifically with preprocessor definitions.
I'm trying to define a macro for the objective-c runtime to avoid enforcing the dispatch functions to be cast to an appropriate function pointer type. The usual way to go would be to use #define OBJC_OLD_DISPATCH_PROTOTYPES and then include the header on the next line. Once the header gets included, the macro is already defined and the header is configured accordingly.
But that's where it starts to get weird!
The macro is not recognized at all and the header gets included as if the #define statement was not there so it fails to #define OBJC_OLD_DISPATCH_PROTOTYPES and it gets (re?)defined as 0.
main.c
#include <stdio.h>
#define OBJC_OLD_DISPATCH_PROTOTYPES 1
#include <objc/objc-runtime.h>
int main(int argc, const char * argv[]) {
// From there:
// - Build System: OBJC_OLD_DISPATCH_PROTOTYPES is always 0, except if defined in build settings
// - Clang (only): OBJC_OLD_DISPATCH_PROTOTYPES is 1
printf("%d\n", OBJC_OLD_DISPATCH_PROTOTYPES);
}
The build system acts as expected when the preprocessor macro is defined in the project build settings under the "Apple Clang - Preprocessing" section. It defines the global macro using the -D parameter of clang making it available to any files used by the project.
However, source code compiles correctly when I use clang from a terminal using clang main.c.
Could someone tell me what I need to configure for the build system to behave normally?
It gives a warning when building with Xcode IDE:
Ambiguous expansion of macro 'OBJC_OLD_DISPATCH_PROTOTYPES'
and the output is indeed 0 using Xcode directly, but 1 with clang main.c. The difference is that Xcode uses clang with enabled modules by default: You get the same warning on the command line if you enable modules there:
clang -fmodules main.c
Solution
In Xcode, select the target, go to the "Build Settings" tab and in the "Apple Clang - Language - Modules" section, switch the "Enable Modules (C and Objective-C)" entry to 'NO':
Then you get the expected result in both cases, regardless of whether you use Xcode or Clang on the command line.
Explanation:
If you use modules the following happens:
instead of the preprocessor including the text and compiling the result, a binary representation of the module is used
modules are (independently) precompiled, i.e. they use the definitions from the time the module was precompiled
consequently, preprocess definitions from the code before the include/import statement have no effect on the module (nor on other imported modules).
if modules are enabled, not only #imports are affected, but also #includes are translated into module imports under the hood
So you have a contradictory definitions for the OBJC_OLD_DISPATCH_PROTOTYPES.
The precompiled module uses a 0 for OBJC_OLD_DISPATCH_PROTOTYPES and you redefine it as 1.
BTW: if you use
#define OBJC_OLD_DISPATCH_PROTOTYPES 0
then you use the same definition that the precompiled module is using and therefore there is no warning about an ambiguous expansion of the macro even if modules are enabled.
Without enabled modules, the preprocessor includes the text, compiles the result and returns the expected result, i.e. in objc.h the desired typedef are used.
I have a fair bit of code written to compile under various build systems (e.g. CCS, Visual C, Embarcadero CBuilder, Microchip XCn). Since the various compilers differ in how they define things like inline or interrupt routines, I use #if/#elif/#else constructs to satisfy their requirements. The GCC preprocessor documentation even suggests this as a good use for #if etc.
In the case of my microprocessor build tools, the CCS family of compilers, and XC16 (gcc-based) deal with this just fine, but XC8 insists on looking inside a non-active #if blocks and generating warnings.
For example, the code
#ifdef _COMPILER_CCS
#INT_RDA
void RDA_ISR(void)
#elif defined (_COMPILER_MCHIP_XC16)
void __attribute__((__interrupt__(_ISR_SPECIAL_SAVE), __auto_psv__)) _U1RXInterrupt(void)
#elif defined (_COMPILER_MCHIP_XC8)
void vU1RXInterruptHandler(void)
#else
#error Problem with defines
#endif
{
...
}
generates the warning
warning: (107) illegal # directive "INT_RDA"
There are hundreds of these warnings generated, making it hard to see legitimate warnings and/or errors.
Does anyone have suggestions on how to make XC8 shut up about things it's not even supposed to be parsing? I cannot find a flag to turn off this warning.
I use macros with xc8, but use #if
not just #ifdef as it seems to sometimes think undefined 'C'
macros are simply 0. Also I never give a compiler option the value 0.
Bit scary, but I tend to do stuff like:
//#define COMP_OPT 1
//#define COMP_OPT 2
#define COMP_OPT 3
then in the code
#if ( COMP_OPT == 0 )
#error COMP_OPT NOT DEFINED
#endif
#if ( COMP_OPT == 2 )
{
// code for compile option 2
// blah blah
}
#endif
That way I don't unintentionally produce code compiled for the wrong option (or none)
in same file we want to write code which supports ARC and non-ARC. For that some macro required.
#ifdef ARC_ENABLED
NSLog(#" ARC enabled ");
#else
NSLog(#" ARC disabled ");
[self release];
#endif
How to achieve this macro, Does any kind of macro available?
Please let me know. Advance thanks for support
Note: ARC_ENABLED Just i have written for example
There is an objective C macro __has_feature, you can use that to check whether arc is enabled for not.
From Clang Language Extension documentation
Automatic reference counting
Clang provides support for automated reference counting in
Objective-C, which eliminates the need for manual
retain/release/autorelease message sends. There are two feature macros
associated with automatic reference counting:
__has_feature(objc_arc) indicates the availability of automated
reference counting in general, while __has_feature(objc_arc_weak)
indicates that automated reference counting also includes support for
__weak pointers to Objective-C objects.
The section Feature checking macro's is a very good read.
You can use it like this..
#if !__has_feature(objc_arc)
//Do manual memory management...
#else
//Usually do nothing...
#endif
The code part shamelessly copied from this answer.
The following will define USING_ARC, USING_MRC & USING_GC to be 0 or 1, along with a few sanity checks:
// Utility macros (undefined below)
#define PREFIX_ONE(a) 1##a
#define EMPTY_DEFINE(a) (PREFIX_ONE(a) == 1)
// Memory management kind
#if !defined(USING_GC)
# if defined(__OBJC_GC__)
# define USING_GC 1
# else
# define USING_GC 0
# endif
#elif EMPTY_DEFINE(USING_GC)
# undef USING_GC
# define USING_GC 1
#endif
#if !defined(USING_ARC)
# if __has_feature(objc_arc)
# define USING_ARC 1
# else
# define USING_ARC 0
# endif
#elif EMPTY_DEFINE(USING_ARC)
# undef USING_ARC
# define USING_ARC 1
#endif
#if !defined(USING_MRC)
# if USING_ARC || USING_GC
# define USING_MRC 0
# else
# define USING_MRC 1
# endif
#elif EMPTY_DEFINE(USING_MRC)
# undef USING_MRC
# define USING_MRC 1
#endif
// Remove utility
#undef PREFIX_ONE
#undef EMPTY_DEFINE
// Sanity checks
#if USING_GC
# if USING_ARC || USING_MRC
# error "Cannot specify GC and RC memory management"
# endif
#elif USING_ARC
# if USING_MRC
# error "Cannot specify ARC and MRC memory management"
# endif
#elif !USING_MRC
# error "Must specify GC, ARC or MRC memory management"
#endif
#if USING_ARC
# if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6
# error "ARC requires at least 10.6"
# endif
#endif
Place that in a suitable .h included in your project .pch
You can now #if USING_x to control conditional compilation anywhere.
Also you can rule out some files from compiling under certain memory models by including, for example, at the top of the file:
#if USING_GC | USING_ARC
#error "Sorry, this file only works with MRC"
#endif
Could you tell me please how can I do the following:
#if __unix__
#define path_sep='/'
#elif __windows__
#define path_sep='\'
#else
#error "path_sep not defined."
#endif
using gfortran compiler.
This can be done in combination with conditional compilation and using the "D" option on the command line. Here is some example code:
program test_Dopt
character (len=1) :: pathsep
pathsep = "?"
#ifdef WOS
pathsep = "\"
#endif
#ifdef UOS
pathsep = "/"
#endif
write (*, '( "pathsep is >", A1, "<")' ) pathsep
end program test_Dopt
Name the program with filetype F90 to cause gfortran to run the preprocessor or use -cpp on the compile line. Then pass options to the prepreprocessor by including them after D on the compile line, e.g., gfortran -DWOS. (This is more general then gfortran -- most Fortran compilers will process C-style pre-processor directives.) Then you can identify the OS outside of Fortran and pass the information to the Fortran program.
You can compile your code via using the filetype F90 or -cpp.