processing icon indicating copy to clipboard operation
processing copied to clipboard

add conditional compilation to support same code w/ different modes

Open ericsoco opened this issue 12 years ago • 18 comments

maybe a pipe dream, but when writing for multiple platforms (modes), it would be nice to be able to do C-style conditional compilation to avoid having to, for example, comment out Android imports that don't work in Java mode, or comment out code that only compiles for one platform or another.

or maybe a different way around this problem, like tagging a tab as mode-specific, to keep all code in the same sketch but compile only what's needed per mode...

ericsoco avatar Feb 19 '13 19:02 ericsoco

Seconded... definitely have some game code that uses accelerometer control on android that I'd like to have work with key or mouse control on other platforms.

ElectricJack avatar Mar 07 '13 00:03 ElectricJack

To me conditionals don't sound like Processing ...

There are many ways to solve the problem you are describing, for example move shared code into a library and have separate sketches for each implementation/mode that include it. Another way could be to move mode-specific code into wrappers and an interface and switch between those depending on a variable that you set (or something like System.getProperty("os.name")?).

Here's an open bug that covers something similar, a constant that will report on which implementation your code is running in: #320

fjenett avatar Mar 07 '13 07:03 fjenett

For god's sake, different sketches using a common library? That's the exact opposite of what it's been talked about here: a sketch that would almost run seamlessly on different modes if it wasn't for a little snippet of code that needs to be different on different modes.

At the very least for Java and JavaScript modes.

There are at least 3 reasons why one needs to be able to switch forth and back constantly between Java and JabaScript modes WHILE DEVELOPING a sketch. At most 2 of them will (optimistically) disappear in the (far) future, but the third will always remain:

  1. Debugging in Processing.js is like hell. The debug information in error messages in Processing.js is extremely insufficient. It is plainly impossible to DEVELOP in Processing.js (a serious project), unless you are a supernatural genius that develops an entire project without ever making a mistake. So if your target is js, the only viable way of working is to switch to Java at least from time to time when something fails and you have no clue. That is a Processing.js issue which has to be fixed in Processing.js (but will probably take ages because it is not easy).
  2. Support for applets has been dropped, so the only way to publish a Processing sketch on the web is to switch it to JS mode. Many were written in standard (now Java) mode. There are 3rd party tools that allow to export applets, which addresses this case, and also this case will become less and less relevant while developers start using the JS mode from the beginning if the target is web, and Java if the target is a standalone application.
  3. when being able to export the sketch in both ways is just a requirement in itself. Which includes, among other cases, TEACHING. Isn't Processing supposed to be especially suitable for teaching programming? When you are teaching, you don't know what the example code you provide will be used for, so you need to create examples that can be run in both modes so that a student can take them as a starting point both for developing a project in Java and for developing a web project.

teo1978 avatar Mar 17 '13 22:03 teo1978

@fjenett the idea of mode-specific code within classes accessed only as needed by an interface is a nice way to handle things for a Java/Eclipse project. how would you do that from within the IDE, though?

since the Processing IDE already does some preprocessing, maybe this is something that could be handled with a preprocessor directive. i hear what you're saying, florian, about conditional compilation not feeling very much like Processing, and directives also seem a little awkward for Processing/Java. but, Eclipse uses them...and anyway, modes are a relatively new thing in Processing, and they obviously aren't fully mature yet. so, maybe thinking along slightly unorthodox lines is okay here...

i'm thinking something like:

@android {
    import android.view.MotionEvent;
}

void setup () {
    @java {
        size(400, 400);
    }

    init();
}

etc. the preproc could simply remove blocks not tagged with the selected mode before compiling.

ericsoco avatar Mar 17 '13 22:03 ericsoco

@matteosistisette When you are writing sketches that use platform specific code then these are valid and already currently available possibilities.

About 3): as long as you stay within the core API of the official release your code will work fine across modes.

fjenett avatar Mar 17 '13 22:03 fjenett

@ericsoco i don't speak for the team but given that there is no such thing as "one compiler" i don't think it's a good idea to use directives to solve this problem.

You can write pure .java code in tabs that have names ending in .java. Same goes for javascript where the name should end in .js. Either one will be hidden from the other mode. This allows for simple switching of implementations between java / js.

For android mode i think you should be able to write a library that would switch implementations underneath depending on mode. True, that is code that would need to be compiled outside of the PDE.

fjenett avatar Mar 17 '13 23:03 fjenett

@fjenett: valid and already currently available possibilities? Which ones?

Regarding .java and .js code, please read my comment at: https://github.com/processing/processing/issues/1689#issuecomment-15031766 .java and .js files are only a partial solution. If it were possible to include .pde files, treated the same way as they currently are in each mode, but marked as specific to a given mode only, then THAT could be a solution.

About 3): as long as you stay within the core API of the official release your code will work fine across modes.

A. There's no official release yet with both modes. There's a beta which breaks bw compatibility at each new revision and where even the core API is not yet compatible across both modes. B. Anyway, you always need to go outside the core API from time to time.

teo1978 avatar Mar 18 '13 01:03 teo1978

Just a quick note on what i imagined the usage scenario is here:

The Processing IDE aims to make switching between target platforms simple, via the modes feature.

It would be great to have a solution for this that keeps things simple, and stays within the IDE -- I'm sure that more experienced developers using Eclipse or Sublime or whatever can find their way around the issue, but it would be great for casual coders to be able to do the same, with the same Processing paradigm, without resorting to .java / .js extensions.

But, perhaps the nature of targeting different platforms is something that requires a bit more attention to detail on the part of the developer, and perhaps it's a good opportunity to bridge from the IDE to the world outside the IDE. FWIW, I'm not convinced that's the case.

Florian, are there multiple preprocessors, depending on the selected mode? I imagined the directives would not make it through to compilation but would be handled by the IDE's preproc. I understand that each mode compiles differently.

ericsoco avatar Mar 18 '13 02:03 ericsoco

@ericsoco JavaScript mode does a precompilation step and then again another preprocessor from Processing.js runs in the browser. Android has a separate preprocessor as well ...

The time spent on designing, implementing and documenting this is rather spent on more general issues given that there already are possibilities to have mode specific code right at your hand in the PDE.

fjenett avatar Mar 18 '13 09:03 fjenett

I understand you don't want to spend time to design, implement and document preprocessor directives, but please consider that a VERI SLIGHT modification of the already right-away-available way of attaching specific code in the ide via .java and .js tabs could mean a HUGE step forward: adding the possibility to add a .pde file (not .js or .java) and mark it as specific for one mode (but treated the same as pde files are treated now). That would be to us almost as powerful as the preprocessor directives being discussed, and should imply a VERY MINIMAL change and effort, or doesn't it?

teo1978 avatar Mar 18 '13 11:03 teo1978

@matteosistisette please try to keep topics as narrow as possible, you already created an issue for your proposal and it can be discussed there.

fjenett avatar Mar 18 '13 13:03 fjenett

@fjenett understood. that's why i started this enhancement report with "maybe a pipe dream, but..." at any rate, would be nice to have a simple solution to this. please keep it in mind for the future. cheers

ericsoco avatar Mar 19 '13 05:03 ericsoco

Hello everyone!

I am very new to working in an open source environment, so I'm not really sure how things are done and I hope that I don't step on any toes.

I went ahead forked the Processing repo and implemented a preprocessor that excludes Javascript code blocks. I know that there is some dissent on the issue, but I really found it to be a necessary feature while trying to develop a cross platform application.

The preprocessor is very simple and looks kinda like XNA's #IFXBOX preprocessor mixed with PHPDoc variable declaration... or something:

/* @startJS */
Put incompatible Javascript stuff here.
/* @endJS */

The Java compiler will simply ignore the code that is placed between the preprocessor tags. The only source file that I changed is the JavaBuild class. You can see my changes here (starting at line 230 and then at the EOF): https://github.com/Swordmaster2552/ProcessingR/blob/master/app/src/processing/mode/java/JavaBuild.java The edit was pretty straight forward and took less than an hour to add in once I figured out all of the git/ant issues.

I have placed an awful quality screen capture of the fork in action on Youtube if anyone wants to check it out: http://www.youtube.com/watch?v=g_ZLziNIyyo

I know that this little edit doesn't fix all of the problems with using a sketch seamlessly across modes but I do think that a system of preprocessors would be very helpful for the average user.

Swordmaster2552 avatar Aug 31 '13 05:08 Swordmaster2552

@Swordmaster2552 this is exactly how things are done in an open source environment, thanks for making the effort!

@fjenett / ben / casey et al., i hope now that we have a working example of how conditional compiling could work, and some voices in support of it, that we can reconsider its inclusion in future releases. obviously there's still more work to be done to keep things clean for the end user, but this is a step in the right direction.

thanks!

ericsoco avatar Sep 02 '13 19:09 ericsoco

OK, so let me comment with a concrete example as a question - I need to display .gifs in my Processing application, which I want to run in both Desktop (linux) and Android modes. I search a bit, and I find the https://github.com/01010101/GifAnimation library, with an example Processing sketch file, say, https://github.com/01010101/GifAnimation/blob/master/examples/gifDisplay/gifDisplay.pde - with a decently easy usage interface:

Gif loopingGif;
...
public void setup() {
  loopingGif = new Gif(this, "lavalamp.gif");
}
...
void draw() {
  image(loopingGif, 10, height / 2 - loopingGif.height / 2);
}
...

So I do something like this in my code, build for Desktop, all works fine. Then I switch to Android mode, the application .apk builds fine, installs on the device fine, and upon run, it crashes with:

FATAL EXCEPTION: Animation Thread
Process: processing.test.mytest, PID: 12371
java.lang.NoClassDefFoundError: Failed resolution of: Ljava/awt/image/BufferedImage;
	at gifAnimation.GifDecoder.readImage(Unknown Source)
	at gifAnimation.GifDecoder.readContents(Unknown Source)
	at gifAnimation.GifDecoder.read(Unknown Source)

... and indeed, GifAnimation/GifDecoder.java does:

		// create new image to receive frame data
		image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);

Ok, so if I look around a bit, it turns out AWT Java classes are not present in Android, and so, say https://stackoverflow.com/questions/6577738/drawing-a-java-awt-image-bufferedimage-in-an-android-view/6578873#6578873 recommends:

in android its a little different, instead of having an instance of BufferedImage you have an instance of Drawable. Drawable can draw a BufferedImage

Ok, then, so let's say I want to now do the hacking to gifAnimation so it supports android. Would I have to copy GifDecoder.java to GifDecoderDesktop.java, and add a new GifDecoderAndroid.java - along with changing the corresponding class names? If not at compile-time, how would I choose at runtime which of these classes to instantiate? Is this the only approach:

https://stackoverflow.com/questions/22194346/how-to-distinguish-the-mode-java-js-android-the-processing-sketch-runs

Ok, I have found quite nice way with try/catch:
I'm guessing you can also do something similar and try to instantiate an Android specific class.

Actually, even if I have separate files for Android and Java Desktop mode, Processing will still try to compile them both, and since in my Android .java file I'll have something like "import android.graphics.Bitmap;", then if Processing is in Java desktop mode, it will fail during compilation with: "The package "android" does not exist. You might be missing a library" (those packages are found if Processing is in Android mode, though)

Could I also conditionally assign classes, as in GifDecoder = GifDecoderAndroid;, so in that sense the .pde code would run unchanged, regardless if it is in Desktop or Android mode? What would be the recommended approach in this example?

sdaau avatar Sep 28 '17 12:09 sdaau

My feature request for this issue as described in [duplicate issue 6186]{https://github.com/processing/processing/issues/6186}

Feature Request: Processing does a good job of running a sketch across multiple platforms: Windows, Android, MacOS, and Linux. However I often run into problems with minor code issues in Android that prevent my sketch from compiling. I am forced to comment out some Java code and replace it with Android code and vice versa depending on the platform. Usually this is a very small part of a sketch. These sketch incompatibilities may eventually be fixed in subsequent updates, but often I can't wait. A library may only exist on one platform so include statements fail.

Often I will develop a sketch first on a Windows PC in Java mode, and then adapt it to Android. I also want to run the sketch on MacOS and Linux.

Would you please consider adding a meta comment in the source code of the first line of a PDE file indicating to include that file in a build only when it matches the mode being compiled. The code folder sketch.properities file has a mode entry for the code preprocessor.

Something like: //@java //@android //@MacOS //@Linux

This feature request would allow sketch writers to isolate their platform dependent code in a single PDE file without needing to change or replace any lines to get it to compile.

I think it is worthwhile having seamless code that can run on all Processing platforms. Google added Android apps to Chromebooks used in many educational settings, giving more incentive for artist developers to offer seamless versions of a sketch for Android. Likewise for MacOS versions.

ajavamind avatar Jun 16 '21 18:06 ajavamind

Thanks for re-posting. Java has added a lot of new syntax since this was first proposed and I wonder if there's a more elegant way to handle this with newer syntax. i.e. if there's a way to use Java's annotation mechanism to signal ignoring a chunk of code, rather than having to roll our own syntax and pre-preprocessor for it.

Fun fact: Processing itself used this in its own source code for the first few years: the “make” command was a Perl script that implemented something like #ifdef. (Having excised that from the source and the build process, the thought of bringing back something similar for code written in the PDE itself was making me a little wary…)

benfry avatar Jun 16 '21 22:06 benfry

Maybe off-topic, but is there a way to query what mode a program is running in? For example, if there were a hypothetical function called 'targetMode()', you could write something like this:

if (targetMode() == ANDROID) {
    // do this
} else {
    // do that
}

I know this isn't the same as conditional compilation (I've done some programming in C/C++ and Assembly), and it would increase the size of the code generated, but it might be useful in some situations. Maybe such a function already exists, but isn't documented?

dfkettle avatar Dec 12 '22 22:12 dfkettle