j2objc-contrib / j2objc-gradle

This plugin is no longer actively maintained. J2ObjC Gradle Plugin: enables Java source to be part of an iOS application's build so you can write an app's non-UI code (such as application logic and data models) in Java, which is then shared by Android apps (natively Java) and iOS apps (using J2ObjC), all as part of your usual Android Gradle build.
https://github.com/j2objc-contrib/j2objc-gradle
Apache License 2.0
139 stars 43 forks source link

Support use of ProGuard dead code removal #247

Open advayDev1 opened 9 years ago

advayDev1 commented 9 years ago

j2objc allows you to pass in a proguard report to remove dead code. Android Gradle projects will create such reports within their 'proguardRelease' task.

We should add a j2objcConfig DSL method that allow you to set this up. This method configures the right j2objc argument, and also causes j2objcPreBuild to depend on the android project's proguardRelease task.

Note when this functionality is used, the build will proceed as follows:

  1. :shared java build
  2. :app java build
  3. :app proguard
  4. :shared j2objc build
confile commented 9 years ago

Doesn't the Java compile remove unused code on its own?

advayDev1 commented 9 years ago

Can you cite that claim? I don't know of anything like that.

confile commented 9 years ago

I am not sure about that but I thought that Java compiles only the code you are using and removes unused code. Isn't that the case?

advayDev1 commented 9 years ago

i don't see how that is possible. javac doesn't automatically know what endpoints your code has - that is why you have to configure ProGuard with endpoints. then you can figure out what code is statically reachable from those endpoints.

i'd really like to see a reference about what you're talking about.

confile commented 9 years ago

Or was it GWT which removes unused codes. Not sure.

advayDev1 commented 9 years ago

Please do find a reference, then we won't be guessing...

advayDev1 commented 9 years ago

@confile - javac eliminates only if (true) { x } else { y } style constructs, and that only optionally, per http://stackoverflow.com/questions/17965562/javac-code-elimination-capabilities/17966917#17966917

confile commented 9 years ago

@advayDev1 may be you are right. I am not an expert on that. You had a good idea.

advayDev1 commented 9 years ago

impl note: Depend on app:proguardRelease Add translate arg --dead-code-report APP_PROJECT_DIR/build/outputs/mapping/release/usage.txt

confile commented 9 years ago

@advayDev1 Are you working on a proguard task? If so there is a proguard.gradle file in the proguard sample folder.

advayDev1 commented 9 years ago

There's no need for a task. This is just about hooking up the right argument to our existing tasks.

The reason this didn't go anywhere for me is that I could not get j2objcc to succeed with my proguard files. It seemed like too many methods were always removed, so compilation would not succeed. I assume it has something to do with build-closure. If you would like to try this out, please feel free - I don't have time atm.

confile commented 9 years ago

So you say. ProGuard does not work for you?

advayDev1 commented 9 years ago

no, proguard for my app on Android works perfectly. Taking that proguard dead-code file from the Android build, and piping it into j2objc eliminates too many methods (it seems), and the compile fails with missing methods.

confile commented 9 years ago

Do you see any solution for that?

advayDev1 commented 9 years ago

haven't had time to investigate yet. if you do, please update the thread.

confile commented 9 years ago

@advayDev1 Could you please post your ProGuard config file is it is open. Then I can try to start with.

advayDev1 commented 9 years ago

i'm not sure what you mean. i use the default proguard rules that come with android sdk. nothing special.

confile commented 9 years ago

I am just interested which libs you configure in the proguard config file. I have no clue how ProGuard works yet.

confile commented 9 years ago

@advayDev1 what I meant was that I need a little help with how and which libs I have to specify. One of your examples would be very helpful.

confile commented 9 years ago

I have no idea how proguard works but from the example here

-injars app-bin.jar
-libraryjars <java.home>/lib/rt.jar

-dontoptimize
-dontobfuscate
-dontpreverify
-printusage
-dontnote

-keep public class com.foo.app.Main {
    public static void main(java.lang.String[]);
}

-keepclassmembers class * {
    static final % *;
    static final java.lang.String *;
}

it looks like we have to specify all the endpoints to Objecive-c in order to get them not being removed. It is similar to the main function I guess.

@advayDev1 @brunobowden The simples way to do this automatically might be with an annotation. Something like

@ObjectiveCEndpoint

This can be used to annotate classes and functions in Java. Next, an annotation processor could collect all the functions and print then in a proguard config file.

What do you think?

confile commented 9 years ago

@advayDev1 @brunobowden I would like to here your thoughts on my idea?

advayDev1 commented 9 years ago

sorry forgot to update; my internal implementation has proguard + j2objc working for the most part. however, we should definitely not make annotation processors a part of this plugin - they are unnecessary complexity. you can add an annotation like ObjectiveCEndpoint (I use a more general DontShrink(value=reason) named after proguard's dead code removal option), but then add the following to your proguard (replace VisibleForTesting with the FQN of your annotation class)

-keep @com.google.common.annotations.VisibleForTesting class *

-keepclasseswithmembers class * {
  @com.google.common.annotations.VisibleForTesting *;
}
advayDev1 commented 9 years ago

also, i have not PR-ed my proguard code because to do it right requires first splitting the main and test source sets and having them built and translated separately. why? because the proguard report you get by default does not consider code you use defined in main used only in test. so your j2objc translate step with such a proguard usage report fails.

splitting our sourcesets is a substantial refactor #112 which i do not have time for right now. if @confile or @brunobowden do have time, by all means please do

confile commented 9 years ago

@advayDev1 I would like to help but I am totally blocked unless I get the plugin to run. Otherwise my code would be alway untested.

brunobowden commented 9 years ago

@Confile - please reduce your code down to a failure case that you can share with us. It's very difficult to assist you without something like this.

On Thu, Jul 23, 2015 at 3:49 PM Michael Gorski notifications@github.com wrote:

@advayDev1 https://github.com/advayDev1 I would like to help but I am totally blocked unless I get the plugin to run. Otherwise my code would be alway untested.

— Reply to this email directly or view it on GitHub https://github.com/j2objc-contrib/j2objc-gradle/issues/247#issuecomment-124259747 .

confile commented 9 years ago

@advayDev1 I know :-) I will do my best.

confile commented 8 years ago

@advayDev1 What do you think about proguard-annotations? https://github.com/yongjhih/proguard-annotations

advayDev1 commented 8 years ago

I don't see why we should bind ourselves to a particular Proguard annotations library. That library is not a community standard (looking at the number of forks/etc.) and I don't see it recommended by Google/Android/Proguard etc.

Proguard already has a way of denoting what to keep: the rules file.

confile commented 8 years ago

@advayDev1 How did you proceed in making your j2objc translated which was reduced with proguard work?

I guess you compile in xcode, see what was missing and add keep rules. Is this the way to do it?

advayDev1 commented 8 years ago

No. Assume my application is one android Java app project, one iOS Xcode project, one iOS Java j2objc project, and many shared Java j2objc support projects. All of the API used by my iOS Xcode project is exposed solely via the public API of the iOS Java j2objc project. I keep all of that project's public endpoints. Then by running Proguard against the iOS Java j2objc project, I'm guaranteed to keep all the correct transitively used code in all shared j2objc projects as well.

confile commented 8 years ago

So this means when you have an interface:

public interface MyInterface {}

which you implement in objective-c, than you add a keep rule for the whole interface?

advayDev1 commented 8 years ago

No, I keep the whole public API of any class that I use in objective-c.

confile commented 8 years ago

@advayDev1 I try to build a proguard task for the plugin. Hope to make a first push later

confile commented 8 years ago

Which task should the proguard task depends on?

advayDev1 commented 8 years ago

What do you mean you built a proguard task? Proguard already has a Gradle tasks. We don't need a new task. What you need to do is just pass the proguard output dead code report to j2objc TranslateTask.

confile commented 8 years ago

Don't we need a task which runs the following?

java -jar $PRO_GUARD_HOME/proguard.jar @proguard-rules.pro > usage.log
confile commented 8 years ago

A ProGuardTask should also auto include the dependencies.

advayDev1 commented 8 years ago

We should use the standard Proguard task: http://proguard.sourceforge.net/manual/gradle.html It is also what Android uses.

confile commented 8 years ago

Ok great. Could you please post your pro guard task you are using for j2obc?

What "depends on" should this task have or finalized by? I mean where do I have to put this task into?

advayDev1 commented 8 years ago

@confile - I think you are misunderstanding something. There is no task for us to write - it has already been implemented, see the link above. While I did have a version of hooking up this task to j2objc internally a while back, I do not have time to clean it up to open-source it right now.

You are welcome to submit a PR yourself, but you will have to do the research yourself - unfortunately I just don't have time. If you would like to do the investigation and implementation, let me know and I'll assign the bug to you.

confile commented 8 years ago

Could you at least tell me on what task the proguard task should depend on?

advayDev1 commented 8 years ago

@confile - maybe the 'jar' task or the 'classes' task? please do the research, it is part of solving the issue...

advayDev1 commented 8 years ago

Voting to punt post 1.0 unless someone has cycles to implement this. I do not.