开发者

How to manually throw a compiler error in GCC and Xcode

In xcode, while compiling apps with gcc, I want to throw compilation time errors if things like NSZombieEnabled is on for a distribution release, thus ensuring that compilati开发者_运维技巧on will fail and I won't accidentally do something stupid.

I did some googling, but could not figure out how to cause the compiler to bail if a certain condition is met. Surely it must be easy, am I just not finding it?


Use the #error directive:

#if SHOULD_FAIL
#error "bad compiler!"
#endif

int main()
{
    return 0;
}
$ gcc a.c -DSHOULD_FAIL=0 # passes fine
$ gcc a.c -DSHOULD_FAIL=1
a.c:2:2: error: #error "bad compiler!"

Since NSZombieEnabled is an environment variable, you'll need to do something clever in your build script to define your macro as zero or one.

Strictly speaking, the #error directive occurs in the C Preprocessor, not gcc. But that shouldn't matter in the case you've described.


NSZombieEnabled is an environment flag and, to my knowledge, should not affect the resulting binary (though it may affect the speed of the compilation.)


A complile-time assert()--a.k.a. static assert--may be helpful. Here is mine, derived mostly from http://www.pixelbeat.org/programming/gcc/static_assert.html:

/*-----------------------------------------------------------------------------
 *  Compile-time ASSERT(). Similar to the BOOST_STATIC_ASSERT(). And the C++0x
 *  static_assert(), which also has a parameter for a useless error message
 *  (see correction!). Our ASSERT() can be placed anywhere in the code, except:
 *
 *  o In a twice-included header file, without a #ifndef...#endif wrapper.
 *  o In the middle of a structure definition (or enum definition).
 *  o In C89 or C90, after a statement. But you can wrap it in braces!
 *
 *  If you want stick something in the middle of a structure definition
 *  you'll need to use the ugly, three-line construct #if...#error...#endif.
 *  And if you do do this, the pre-processor has a much more limited idea of
 *  what a "constant expression" is.
 *
 *  This is a refinement of ideas from the web (www.pixebeat.org is good). It
 *  is shorter than BOOST. And, I believe, is better than Linus Torvald's
 *  suggestion for an improved BUILD_BUG_ON(). And the do{...}while(0) wrapper
 *  you commonly see is totally inapplicable here: it limits permissible
 *  locations.
 *
 *  The web has many suggestions using arrays with a negative index. But with
 *  GCC, most of these do not detect a NON-CONSTANT arg (which is easy enough
 *  to do in error), except for the attractive 'extern int foo[expression]',
 *  which also gives an 'unused variable' warning (which might be fixable via
 *  (void)foo). GCC 4.3 apparently has a built-in static_assert(). Update:
 *  typedef int array[expression] seems also to be good.
 */
#define CONCAT_TOKENS(a, b) a ## b
#define EXPAND_THEN_CONCAT(a,b) CONCAT_TOKENS(a, b)
#define ASSERT(e) enum {EXPAND_THEN_CONCAT(ASSERT_line_,__LINE__) = 1/!!(e)}

But I corrected my opinion about the 'useless' message in C++0x:

/*-----------------------------------------------------------------------------
 *  Correction!: The message in static_assert() isn't quite useless, and we've
 *  added it to ASSERTM(). This is needed for the case where two different
 *  header files happen by chance to have two ASSERT()'s on the same line, or
 *  likewise for a source file and a header file.
 *
 *  We could also handle this via __COUNTER__, but this isn't supported by
 *  the SGI compiler (and is uglier). And we can't use __FILE__, because it
 *  doesn't usually expand to a valid C token (e.g. it has a dot c or dot h).
 */
#define ASSERTM(e,m) enum{EXPAND_THEN_CONCAT(m##_ASSERT_line_,__LINE__)=1/!!(e)}

Some examples:

/*-----------------------------------------------------------------------------
 *  Example:
 */
ASSERTM (sizeof (int16) == 2, my_global_header_h);
ASSERTM (sizeof (ord32) == 4, my_global_header_h);
ASSERTM (sizeof (int64) == 8, my_global_header_h);

/*-----------------------------------------------------------------------------
 *  Equally good, I believe, is the following variant, but it is slightly
 *  longer (and not used by us at the present time):
 */
#define ASSERTt(e) typedef int EXPAND_THEN_CONCAT(ASSERT_line_,__LINE__)[1-2*!(e)]


Another interesting thing you can do is manipulate the output of your build script. If you're using a custom build script as part of your build process, you can do something like:

echo "error: this build step failed!"

Or:

echo "warning: this build step could be potentially faulty"

Those will produce errors or warnings (respectively) that will show up in the build results window. I've used this a couple times, and it's really useful.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜