conditional compilation

1832 views
Skip to first unread message

Dilip Dilip

unread,
Mar 30, 2010, 5:57:06 AM3/30/10
to android-d...@googlegroups.com
Hi All,
 How to do conditional compilation in JAVA.
 
something like in C, C++ :
 
#ifdef TRUE_CONDITION
 
#else
 
#endif
 
Thanks and Regards,
  Dileep

Bob Kerns

unread,
Mar 30, 2010, 6:36:26 AM3/30/10
to Android Developers
You do not do that in Java.

I suggest you should not do that in C++, as there are better ways to
do it.

I suggest you do not use C.

Bob Kerns

unread,
Mar 30, 2010, 6:42:10 AM3/30/10
to Android Developers
I suppose I should elaborate...

In C++, you should use const to declare TRUE_CONDITION to be true, and
then use regular 'if' statements. The compiler will eliminate the
clauses that can't be reached.

In Java, you can do the same thing. But since Java code generally can
run on any platform, you generally do not WANT conditional
compilation, as it would make your code break when you moved it to
another environment.

This isn't an issue for C++ or C because the compiled files aren't
portable anyway.

Kevin S.

unread,
Mar 30, 2010, 11:12:32 AM3/30/10
to Android Developers
It really isn't very easy to do this. In general, you can do
something like

public class MyClass
{
public static final boolean HAS_CHEEZBURGER=true;

public void someMethod()
{
if( MyClass.HAS_CHEEZBURGER)
{
doCheezburger();
} else
{
noCheezBurger();
}
}
}

The compiler I think will see that HAS_CHEEZBURGER is constant and
can never change, and may optimize away the branch not taken. Perhaps
some more knowledgeable folk could comment on that.

If on the otherhand, you really really think you need to do
preprocessing using eclipse and Java, you can. See the following
link.

http://www.boldinventions.com/index.php?option=com_content&view=article&id=81:javapreprocessorusingeclipse&catid=34:category-electronics-articles&Itemid=53

-Kevin

Bob Kerns

unread,
Mar 30, 2010, 12:42:24 PM3/30/10
to Android Developers
You can download a Java decompiler and investigate yourself. I suggest
this one:
http://java.decompiler.free.fr/?q=jdgui

You'll see that it does indeed optimize when it can.

However, unlike a C file which gets linked into a .so or .dll or an
executable, Java classes may be combined in different ways.

So it cannot optimize away static final references in other classes,
because those may change.

However, tools like ProGuard can do so, because they work on an entire
application.

But remember, once you do something like this, that code can never be
used in a context with a different valiue.

It virtually never makes sense to do this for conditional compilation
reasons. Sometimes it makes sense to generate code (the Android tools
do in fact generate a couple of files). In the rare case you do need
to eliminate code due to extremely tight performance constraints or
size constraints, I'd recommend the ProGuard route, as it will do a
FAR more thorough job than you can do manually with conditional
compilation.

On Mar 30, 8:12 am, "Kevin S." <dada...@gmail.com> wrote:
>   It really isn't very easy to do this.  In general, you can do
> something like
>
> public class MyClass
> {
>    public static final boolean  HAS_CHEEZBURGER=true;
>
>    public void someMethod()
>    {
>        if( MyClass.HAS_CHEEZBURGER)
>        {
>            doCheezburger();
>        } else
>        {
>            noCheezBurger();
>        }
>    }
>
> }
>
>    The compiler I think will see that HAS_CHEEZBURGER is constant and
> can never change, and may optimize away the branch not taken.  Perhaps
> some more knowledgeable folk could comment on that.
>
>   If on the otherhand, you really really think you need to do
> preprocessing using eclipse and Java, you can.   See the following
> link.
>

> http://www.boldinventions.com/index.php?option=com_content&view=artic...

John Seghers

unread,
Mar 30, 2010, 8:45:54 PM3/30/10
to Android Developers
In the J2ME world of wildly non-conforming implementations,
conditional compilation is the norm. Sun even admited it by adding
"configurations" (IIRC) to NetBeans 5. EclipseMe (Now the official
Eclipse Mobile Tools for Java project--MTJ) has support for it, as
does the Antenna extension to Ant.

The most common method currently is to use a construction such as
//#if CONDITIONAL
...
//#endif
This shields the conditional statement from language-aware but
conditional-unaware editors. The build system then comments out the
intervening lines of code if the condition is not met. I've used
everything from ant processing to running the full Java code (and even
XML files) through the C++ preprocessor for macro expansion.

In Android, especially when trying to maintain two versions of a
product (Free vs. Paid, for example) conditional compilation (or
parallel code trees) is mandatory because the package names must
change (at least in the manifest). This is one case where the if
(const) blocks will not work. If there is a better way of handling
this, please enlighten us.

I haven't yet tackled this problem in the Android dev environment
because it tends to disrupt the debug part of the edit-compile-debug-
edit cycle. What I have done is to add an eclipse builder to run a
perl script to generate a Java interface (in the gen/ directory) that
defines constants for build time/number pulled from Team Foundation
Server. This allows automatic version stamping for the about screen--
though does not yet modify the version name/number in the manifest.

> > >   Dileep- Hide quoted text -
>
> - Show quoted text -

Bob Kerns

unread,
Mar 31, 2010, 2:16:48 AM3/31/10
to Android Developers
There is a much better way to do this. I have outlined it in a prior
post, but I don't have time to dig it out or recreate it tonight.

I'm planning to turn it into a blog post at some point.

Basically, you do not need conditional compilation. The *only* Java
code which needs to change is the generated R.java file -- and even
that you should be able to generate correctly, though I wasn't able to
get it to work.

It can all be done with an ant script. The manifest needs to be
processed. It's helpful to process some resource files -- for example,
to embed the version number, etc. XSLT is your friend here, it's much
easier to manipulate XML than to deal with all the issues with
preprocessing -- including completely screwing up line numbers, in
most cases, but commenting out rather than omitting lines should avoid
that!

To avoid screwing up the debug cycle, I produce by default a dev
version, which gives access to both free and pro functionality for
test and debug.

It works really well, but there's a few quirks I wish I had time to
explain just now; I hope I covered them in my earlier message, which I
hope you can find...

Feel free to bug me more on the topic after April 1.

Emmanuel

unread,
Mar 31, 2010, 7:50:54 PM3/31/10
to Android Developers
Waooo...

I think you are a little bit expeditive on this one !

I really think #ifdef are a very important thing in C / C++, and I
missed so much in any other languages I am using !

Using static / constant data can't achieve the same thing : for
instance you can't have different data in a class without ifdef...
It makes programs more difficult to read, but you really can switch
from different versions of your programs much more easily, and it's a
real gain of time !

Emmanuel
http://androidblogger.blogspot.com/
http://www.alocaly.com/

Dilip Dilip

unread,
Apr 1, 2010, 3:58:54 AM4/1/10
to android-d...@googlegroups.com
Hi All,
  Thanks for the reply.
I will try out.

Thanks and Regards,
  Dileep


--
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-d...@googlegroups.com
To unsubscribe from this group, send email to
android-develop...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

To unsubscribe, reply using "remove me" as the subject.

Bob Kerns

unread,
Apr 1, 2010, 12:28:33 PM4/1/10
to Android Developers
My first response was to say "OF COURSE YOU CAN!" -- but then I
realized you must be talking about including or excluding data
members, rather than the actual data.

All I can say is, if you're doing that in C++, you're doing it wrong,
and you should read up on object-oriented design patterns.

C++ goes out of its way to make #ifdef unnecessary. But a lot of C++
programmers come from a C background, or read a lot of C in the
process of learning C++, that they never learn to properly use it. It
doesn't help that the language is insanely complicated, and it takes a
LOT of time and effort to become really proficient.

Adding or not adding fields and methods to classes should be handled
through subclassing and/or interfaces. And you should consider
refactoring into collaborations of separate objects, rather than large
flat classes.

Guy Steele, the author of the Java standard, cowrote a popular book on
C, and was a key member of Tartan Laboratories, which created
optimizing C compilers for a wide range of platforms. James Gossling
had a huge amount of C experience as well, implementing Gossling
Emacs, and of course, Java. Hell, Guy used to write maintain a huge
amount of ITS PDP-10 macro assembler, code that I also worked on as
part of the same group at MIT, so I can say with absolute certainty --
the designers of the Java language and its standard are VERY aware of
conditional compilation, and the reasons it is not in the language are
to make it a better language.

I can also speak from my own personal experience. It's hard to
quantify my C/C++ experience, but it goes back to the 1970's, long
before there was even a dream of C++, and Java since relatively soon
after it came out in 1995. I've mentored a lot of people both in C++
and Java. I've also participated in language standardization efforts,
maintained and written compilers and language runtimes.

Now, all that constitutes "argument by authority", and proves nothing,
of course. But I'm not trying to get you to switch off your mind and
just believe what I'm telling you. On the contrary -- when there's a
consensus of experts, you should poke around, kick the tires, explore,
try things, look for counter-examples, etc.

One of the best type of counter-example is "X is a real gain of time",
as you put it. My guess is that it's a gain of time for you because
you're not familiar with other techniques, but if you'd like to post a
more concrete example, we can discuss it and alternatives.

I won't waste your time with examples of how conditional compilation
can waste your time, as the solution is generally "don't use it that
way".

But I'm generally in favor of things that save you time. Sometimes,
even things that save you time up front but cost you more time later.

On Mar 31, 4:50 pm, Emmanuel <emmanuel.ast...@gmail.com> wrote:
> Waooo...
>
> I think you are a little bit expeditive on this one !
>
> I really think #ifdef are a very important thing in C / C++, and I
> missed so much in any other languages I am using !
>
> Using static / constant data can't achieve the same thing : for
> instance you can't have different data in a class without ifdef...
> It makes programs more difficult to read, but you really can switch
> from different versions of your programs much more easily, and it's a
> real gain of time !
>

> Emmanuelhttp://androidblogger.blogspot.com/http://www.alocaly.com/

Frank Weiss

unread,
Apr 1, 2010, 1:01:37 PM4/1/10
to android-d...@googlegroups.com

A concrete example from the OP would help. I can think of cases where conditional compilation (as done in C/C++) is and is not needed in Java.

> I think you are a li...

> Emmanuelhttp://androidblogger.blogspot.com/http://www.alocaly.com/

>
> On Mar 30, 12:36 pm, Bob Kerns <r...@acm.org> wrote:
>
>
>
> > You do not do that in Java.
>

> >...

Emmanuel

unread,
Apr 2, 2010, 10:01:30 PM4/2/10
to Android Developers
Interesting...

Working for some years on multiplatform / multi compiler big
performance sensitive projects( console games actually), I always find
that macro / conditional compilation WAS the consensus !
Using this for distinctions between platform specifics + version
specific + switching between several versions of the code is soooo
common ( but, obviously, not the only used tool )
In no way I'm saying we're using this in all situations : we can have
distinct specific code in several libraries or different per platform
implementation files or using interfaces... But there are many cases
where I honestly think macro use is the very best situation...

Using interfaces adds unnecessary virtual that are really costy on
some processors.
Adding some classes make the project more complex to handle, read,
debug, maintain... Using too much macro also make the project more
complex to handle / read / debug / maintain, so you have to find a
balance between those two...
As much as we can, we try to maintain a good level on performance on
the debug versions too, in order to have them usable in the first
time, so counting on the optimiser is not a good idea !
We have a assert macro that makes use of the __line__ and __file__
special symbols
...

Beside that, I tried to open some files given with my compiler ( here
at home, so it's Visual C++ Express 2005 ) : stdlib.h, stl
implementations, etc...
They contain macro usage...
I looked into Android C++ code ( this is an android ML after
all :) )... And find macro usage...
Looked into linux sources... and find macro usage...

I'm quite suspicious thinking both My projects AND microsoft + google
+ linux developers all get it so wrong...

Bob Kerns

unread,
Apr 3, 2010, 5:27:30 PM4/3/10
to Android Developers
I'm a bit puzzled at your response, as you seem to be addressing C/C++
rather than Java? I've probably contributed to the confusion by
talking a little bit about C++ vs C. Perhaps you intend your response
to just refer to some aspect of those remarks?

But let me try to sort it out by context.

You're clearly talking about C/C++ code -- everywhere. This discussion
is about Java code. But let me address the C++ issues you raise,
first. C++ does provide a useful point of comparison and contrast.
I'll then contrast each point with Java.

First, there is no trade-off between virtual / non-virtual vs macro.
Macros are entirely compile-time, and so are non-virtual calls.
Whatever you're doing with macros, you can do without virtual method
calls.

With Java, we don't have the same distinction between virtual and non-
virtual. We do have a performance difference between private and
package-private (default) vs protected and public. I don't think
there's anything useful you can do with macros to really enhance
performance here -- certainly not worth the complexity.

If adding some classes seriously makes your project more complex, then
it's likely your class hierarchy isn't well-designed. This was a
common problem with a lot of early UI frameworks -- for example, MFC.
A well-designed class hierarchy actually helps you break your project
files up according to functionality. But early on in the world of
object-oriented program, everyone tried to do everything through
inheritance. It turns out, this isn't a good idea. Inheritance is
good, but so is delegation and collaboration, and a good design will
use these together to keep contracts tightly focused. Inheritance
works better when used with a well-factored collaboration of objects,
and collaboration works better when when key objects can be separately
specialized via inheritance.

There ARE some costs to debugging virtual method calls because you
don't know statically what method will be called, but we're talking
about static calls here, if we're comparing what you can do with
macros vs class hierarchy.

Let's say the differences you want to deal with are related to
platform. A better approach than scattering conditionals or even
function-like macros through your code, are to segregate those
platform differences into a Platform class. Methods on this class can
be in-lined. This is better than a macro -- FAR better from a
debugging standpoint, because macros always obscure what code you're
debugging.

You can do the same thing with Java. And, with tools like ProGuard,
you can even get the benefit of inlining.

And I disagree about counting on the optimizer. Optimizers optimize
things that humans pessimize. Humans really aren't very good at
optimization. Oftentimes, humans make the mistake of inlining blindly,
and bloat the instruction cache, resulting in WORSE overall
performance. And the human effort spent toward small optimizations
like this is better spent focusing on making the basic approach more
efficient, or other more productive tasks.

In Java, the optimization conditions are well-defined. The conditions
under which IF can drop unreachable code are even part of the
specification, at least partially. ProGuard can go beyond that,
because it allows you to make global assumptions about what code will
be used together.

I didn't say that C++ was entirely successful in its goal of
eliminating the need for macros or conditional compilation. In
addition to your example of the assert macro, there's also the example
of header file guards. But the need for header file guards is entirely
due to the presence of macros in the language! Otherwise, the compiler
could simply skip redundant headers, and the ordering of includes
wouldn't matter.

And, in fact, that is exactly the situation with Java. The order of
imports can and should be entirely based on readability. We lack any
equivalent of __line__ and __file__, but our stack traces generally
have that information, unless we decide to do away with it to save
space.

And back to the trade-off of complexity -- since Java and Java tools
assume there is NOT a preprocessor, you're always introducing a
SUBSTANTIAL element of complexity, with the very first use of
preprocessing.

Further, C/C++ macros result in a huge number of bugs. This is a HUGE
problem -- you probably have gotten so used to it you don't notice.
Somebody defines a macro somewhere in a header file, and it breaks
some code that doesn't even use that macro, because it indirectly
includes some other header file, that doesn't use that macro either --
but does use a local variable that happens to have the name of that
macro. People spend HOURS sorting these things out. I've had to teach
GENERATIONS of programmers how to track down such problems, because
usually they're absolutely baffled. And how to do it, exactly depends
on the toolset you're using. And even when you know, it's a royal
pain, because of all the unreadable preprocessed CRAP you have to sort
through.

Now, about whether Microsoft, Google, and Linux can be getting it
wrong: Well, let's look at that.

First, stdlib.h is a C library. It has to work with C. It's not even
recommended to use with C++ if you can avoid it! One of the biggest
reasons for the use of macros in C++ is compatibility with C. That
applies to Microsoft headers, and Linux headers. I don't know if
Android includes much C code above the OS level, but the JNI interface
at least supports C.

Microsoft's STL implementation, at least the last time I seriously
looked at it, was of EXTREMELY poor quality. I would both guess and
hope it is vastly improved by now, but my point is that Microsoft
certainly CAN get stuff wrong. Ignoring all the myriad violations of
the standard -- Microsoft's implementation of std::string was not only
not THREAD safe -- it was not even DLL safe. (A lack of DLL safety is
something I've never encountered ANYWHERE else!) Under some
circumstances, passing a std::string from code in one DLL to another
would cause failure. The stl classes would often have to be carefully
ordered -- sometimes incompatibly with the order imposed by OTHER
platforms -- to avoid macro conflicts with various system header
files.

As for Linux? Well, the kernel is in C, not C++. Even if you're
talking about C++ code in the context of Linux, this drives the
overall outlook and expectation.

But a well-done C++ project will seek to minimize the use of macros
and conditional compilation, and reap great benefits by doing so. The
C legacy will still bite you once in a while, but to the extent you
can isolate OS dependencies in a few platform-specific files, you'll
contain and minimize these problems.

Another aspect I've observed is that the problems with C macros and
conditional compilation tend to grow with time. They don't seem so bad
at the start of a project. As a project grows and matures, however,
and as it is ported to an ever longer list of platforms, the problems
become worse and much harder to deal with. By the time you port to
Windows (several versions), Macintosh, a dozen flavors of Unix and
Linux, things will have gotten very much out of hand, if you haven't
taken steps to address the issue by isolating platform dependencies.

Have you ever worked on a body of C/C++ code that was 15 years or more
old?

These sorts of issues arise MUCH less in Java. A part of that is
because Java doesn't have preprocessor macros and conditional
compilation, and so doesn't have platform or environment differences
in those areas. The other big reason is that Java offers a lot of
cross-platform facilities. However, differences do arise on occasion,
dealing with things like filesystem layout, availability of third-
party libraries, Java version (Apple lags seriously behind on Java
version -- as does Android), etc. So while the problems are less, the
same solutions of isolating platform dependencies still prove valuable
in large projects. (Small projects may not encounter enough
differences to be worth any measures -- often none at al).

There's always room for improvement in software projects. Just because
you find a technique used in some projects doesn't mean it wouldn't be
better with a different technique -- and often this would be strongly
acknowledged by the authors themselves. Sometimes it's just too hard
to change from the course you're already on. And this is even more
true when there are factors working against you -- such as the
prevalence of C interfaces in C++ code.

I think it's fair to say that despite the standard encouraging people
to use better techniques, few C++ projects completely eschew
conditional compilation and preprocessor macros.

As a final note, I'll point out that the problem with C macros are not
true of all types of macros. C preprocessor macros are particularly
nasty because they are non-syntactic. They violate the language's own
syntax. The C++ preprocessor cleans this up a little bit, but only a
bit. They combine this with extremely limited power. I'm not down on
macros as a class -- I met my wife while teaching a class on Macros in
Lisp back in 1992. There are definitely times I miss having Macros in
Java -- but C macros would almost never satisfy those needs anyway.

By contrast, with XSLT, you do very powerful transformations on XML,
and you can even generate Java code from XML fairly cleanly and
reliably -- and then be able to work with the XML using any XML tools.
Android chose the approach of generating small bits of Java from XML,
rather than processing Java to get the same information. They could
have used Java annotations, but this approach has many benefits --
centralizing this information, making it easier to customize for
locale and configuration, the ability to work with it using any XML
toolsets, etc.

Every use of preprocessing in Java that I have worked with over the
years has soon been replaced, with something better that did not
involve preprocessing. So have some uses of code generation -- but not
all. Code generation appears to be a more robust and less
problematical approach. To the extent that code generation is a viable
alternative to preprocessing, it is definitely to be preferred.

That also applies to C/C++, BTW. Data-driven code generation presents
fewer problems than the ubiquitous-but-problematic preprocessor.

> Emmanuelhttp://androidblogger.blogspot.com/http://www.alocaly.com/

Bob Kerns

unread,
Apr 3, 2010, 5:38:30 PM4/3/10
to Android Developers
One other observation -- Java, having a well-defined platform-
independent output format for the compiler, makes practical another
approach -- postprocessing.

That, in fact, is what ProGuard does -- it takes the .class files, and
postprocesses them.

Likewise, the Android toolset does the same, converting the Java
standard JVM byte codes into Dalvik byte codes. This process could, in
fact, perform the same sorts of optimizations that ProGuard does. I
don't think it does the sort of dead code elimination we're talking
about here, but it could be enhanced to do so in the future, based on
knowing what code you will be running with. So any references to
static final constants in your code could be handled --- while any
from the system runtime would be left to runtime.

You get this benefit without taking any special measures in your code,
and without any loss of generality.

adorilson

unread,
Dec 15, 2011, 9:14:39 AM12/15/11
to Bob Kerns, Android Developers

On Mar 31 2010, 3:16 am, Bob Kerns <r...@acm.org> wrote:
> There is a much better way to do this. I have outlined it in a prior
> post, but I don't have time to dig it out or recreate it tonight.
>
> I'm planning to turn it into a blog post at some point.
>

> Basically, you do not needconditional compilation. The *only* Java


> code which needs to change is the generated R.java file -- and even
> that you should be able to generate correctly, though I wasn't able to
> get it to work.
>
> It can all be done with an ant script. The manifest needs to be
> processed. It's helpful to process some resource files -- for example,
> to embed the version number, etc. XSLT is your friend here, it's much
> easier to manipulate XML than to deal with all the issues with
> preprocessing -- including completely screwing up line numbers, in
> most cases, but commenting out rather than omitting lines should avoid
> that!
>
> To avoid screwing up the debug cycle, I produce by default a dev
> version, which gives access to both free and pro functionality for
> test and debug.

Can you show us how you management these version?
Some piece of code... or a link to a full code will be wonderful.


--
Adorilson

Reply all
Reply to author
Forward
0 new messages