Successfully Preprocessed Build Breaks Plugin Source Code Visibility

Issue #29 wontfix
Rob Smith created an issue

I have an issue using a preprocessor with NBAndroid, which causes the plugin to lose visibility of the source code. However, I believe there may be a simple fix - please see below.

I've created a working NBAndroid build which includes a preprocessor step, to allow the source code to be filtered before compilation. I don't want to overwrite my source code, so create a preprocessed copy and point the system to that copy, instead of the real source, for compilation.

I've attached an example to illustrate the issue - HelloPreprocess - which is HelloWorld with a preprocessing step. The app displays text to say whether it is the preprocessed version or not to simplify analysis.

  1. When the example project is loaded up unmodified, the plugin will correctly identify the source code under Source Packages and show that the project structure is good.

  2. Building the project will correctly create the preprocessed source in the build/src directory, and then incorrectly use the non-preprocessed source code to build the app. The app should confirm that it is 'not preprocessed' when run.

  3. Uncomment the source.dir line in Window->Projects->HelloPreprocess->Important files->Build properties (ant.properties) to tell the plugin to use the preprocessed code and make a clean build. Now running the app should confirm that it is the preprocessed version.

  4. Clean the project again and close it. Note that the only change from step 1 has been to uncomment that single source.dir line in ant.properties.

  5. Finally, reopen the project to force the plugin to rescan it. Note that the Source Packages item has completely disappeared from the project. The build works, but the plugin fails, so I believe this is a bug.

The process is totally reversible by recommenting the source.dir line (breaking the preprocessor build step again), closing the project and reopening it to force a plugin rescan.

I attempted a workaround by updating source.dir during the build, using the bundled nb-overrideproperty, but NBAndroid seems unaware that this property has changed. However, my approach may be very close to a fix. When does NBAndroid read source.dir to determine the directory for compilation during a build? Could this be delayed in the build process, so source.dir can be updated first? Please let me know your thoughts.

Comments (9)

  1. Rob Smith reporter

    My alternative suggestion is to add a preprocessed.dir Ant property to specify the location of the preprocessed source code for compilation, in a similar way to the source.dir implementation. This would leave source.dir pointing to the real source code and solve the plugin visibility issue.

    If preprocessed.dir is not set, the plugin could assume that no preprocessing is being done and use the source.dir location, as it currently does anyway.

    Also, I should have mentioned that I'm still using NetBeans 7.4, as I feel 8.0 is immature for now.

  2. Rob Smith reporter

    Hi Radim,

    I've just spent a couple of weeks considering migration to Android Studio, which included a move to Gradle and flavors. My ported solution uses sourceSets to play the same trick as source.dir and I think it will run into exactly the same issue.

    My Android project is a port of a mature J2ME code, so I'm reluctant to make unnecessary changes as I'm sure you'll appreciate.

    To answer your source question: the original file is always the source, not the preprocessed one. Preprocessors should only be used for minor changes, otherwise things get ugly quickly. As you can see from my code, the unpreprocessed source uses standard Java syntax, so will not affect any parser. The 'ifdef' code won't be parsed, but I can live with that and it encourages me not to make too many conditional sections. The advantage is that I have a single source file for different variants, without having to duplicate changes.

    Why does my nb-overrideproperty workaround fail? I feel this could be close to a simple solution. Please let me know.

    Rob

  3. Radim Kubacki

    I am more willing to make changes in Android/Gradle support area than for the Ant based project. Classpath updating based on selected build variant should already work. Even with Gradle I'd recommend you to use different source/resource files scoped by flavors than pre-processing.

    While this seems important for you you are the only user demanding such a feature. And I really do not like the conditional ifdef's. This is not standard J2ME but something added by Mobility support in NetBeans. There are more important features from my point of view for much larger user base. And last but not least: I still have no profit from this project hence my reluctance.

    BTW: Android Ant projects do not use common features of NetBeans Java SE/ME/EE projects and relies on simple use of Android SDK toolchain. That's why nb-overrideproperty does not work there.

  4. Rob Smith reporter

    Thanks for confirming that nb-overrideproperty will fail. I realise that it's a Mobility feature, but is still bundled with NetBeans. That's a pity.

    The key to a good tool is flexibility. Whether preprocessors are to your personal taste or not, they are widely used for a variety of reasons. Supporting them may be the unique selling point that attracts customers to your product. Currently, my build works but the plugin fails, which doesn't seem such a good advert.

    I take your point about the need to prioritise your time. However, I believe this could be a quick win, if done in two simple steps:

    1. Use your existing routine that checks for and parses source.dir Ant property, to check and parse preprocessed.dir.

    2. At your Java compiler step, where you already check whether source.dir overrides the default value, add a check for whether preprocessed.dir overrides them both, i.e. preprocessed overrides source overrides default.

    It's a very simple solution, and avoids any code parser issues by retaining your existing functionality, i.e. source.dir always gives the definitive location, regardless of other factors.

  5. Rob Smith reporter

    Having investigated your suggested migration to a Gradle build, I can see that this alternative suffers from a number of issues (#31, #32, #33, #34) associated with flavours and testing. Currently, it would be a significant backward step for me from an Ant build, and will also suffer from the lack of preprocessor support - this issue - despite flavours.

    Currently, I am able to run tests, build variants and substitute tokens in source code using Ant, and I urge you to add simple preprocessor support to the NBAndroid plugin, as suggested in the two steps above.

    It's clear to me that your Gradle integration needs some significant development to bring it up to the maturity of your Ant support. While I appreciate that Gradle is the preferred future Android build system, it is still maturing and I feel that reducing your support for Ant builds now would be premature and counterproductive.

    I await developments with interest.

  6. Rob Smith reporter

    Update

    Issue #31: This is still an issue and I am awaiting a response to my comment of 19-05-14 on it.

    Issue #32: Resolved. Thank you for your support.

    Issue #33: This is partially resolved, as it now runs the correct Gradle task. However, running tests using the plugin is unreliable, giving spurious failures or no results at all from the IDE, in contrast to the consistent results produced by both adb command line and Android Studio IDE.

    Issue #34: Resolved. Thank you for your support.

    I believe Gradle flavours are currently too immature to achieve what I want. For conditional code compilation, I can see two possibilities:

    1. Use a flavour-determined (final static) constant to include/exclude code blocks in shared source code. However, the bytecode shows that this includes all code blocks in the apk file, which is undesirable for a paid-free app model. It would be stupid to freely give away the paid app by including its code with the free one. This can be readily demonstrated using my HelloFlavours example attached to issue #31.

    2. Duplicate flavour-specific source code with the relevant (minor) modifications. This creates a maintenance overhead to ensure that the (majority of the) code is kept in step when any changes are made to either of the duplicate files. This is not good practice and prone to error.

    Please add the simple preprocessor feature described in my comment of 09-05-14 above, or suggest a way of making flavours achieve the result I'm after. Perhaps there is a compiler optimisation I'm unaware of.

    I await developments with interest.

    Rob

  7. Radim Kubacki

    javac does not support dead code elimination. IFAICT dex will not bother as well. Proguard or similar tool can do it as a side-effect.

    Moving stuff to flavors without heavy duplication is a matter of designing proper API and application of dependency injection.

    I will not add pre-processor support. I'd be hesitant to do it even if you offered to pay for this feature a reasonable daily rate.

  8. Log in to comment