0

I'm facing an error when compiling my Java sources to produce C++ headers recently: javah spits a package does not exist error for some file.

tl;dr: javah works fine for a Java source but not another one – which import clauses are pretty close; gradle does not process some libraries but even the packages of the processed ones get flagged as missing.


I don't know why javah has started spitting that error since it worked well until recently and I did not change anything special. I'm using gradle with Android Studio's gradle-wrapper. I recently updated the wrapper's distribution from 2.2.1 to 2.10 but I don't think that's why javah fails now.

According to the logs and the present files, javah doesn't find the packages from libraries I'm using as it compiles ClassB but not ClassA.

Let's take two examples: com.batch.android and com.adjust.sdk

  • com.batch.android library does get processed by gradle so its jars are in my build/intermediates/exploded-aar folder (under com.batch.android/batch-sdk/1.5.3/jars/classes.jar and com.batch.android/batch-sdk/1.5.3/jars/libs/batch.jar)
  • com.adjust.sdk library does not get processed by gradle so its jars are not in my build/intermediates/exploded-aar
  • both are in my ~/.gradle/cache/ folder
  • both packages fail as missing by javah
  • both packages are not imported from ClassA and ClassB java files

Thanks for your help!


The gradle logs (sorry guys, it's super long):

Executing tasks: [:app:clean, :app:generateDevAmazonDebugSources, :app:generateDevAmazonDebugAndroidTestSources, :app:mockableAndroidJar, :app:prepareDevAmazonDebugUnitTestDependencies,     :app:assembleDevAmazonDebug]

Configuration on demand is an incubating feature.
:buildSrc:compileJava UP-TO-DATE
:buildSrc:compileGroovy UP-TO-DATE
:buildSrc:processResources UP-TO-DATE
:buildSrc:classes UP-TO-DATE
:buildSrc:jar UP-TO-DATE
:buildSrc:assemble UP-TO-DATE
:buildSrc:compileTestJava UP-TO-DATE
:buildSrc:compileTestGroovy UP-TO-DATE
:buildSrc:processTestResources UP-TO-DATE
:buildSrc:testClasses UP-TO-DATE
:buildSrc:test UP-TO-DATE
:buildSrc:check UP-TO-DATE
:buildSrc:build UP-TO-DATE
Generating assets binaries
Incremental java compilation is an incubating feature.
Cleaning project...
:app:clean
:app:processAssets
:app:copyFiles
:app:preBuild
:app:preDevAmazonDebugBuild
:app:checkDevAmazonDebugManifest
:app:preDevAmazonReleaseBuild
:app:preDevGoogleDebugBuild
:app:preDevGoogleReleaseBuild
:app:preProdAmazonDebugBuild
:app:preProdAmazonReleaseBuild
:app:preProdGoogleDebugBuild
:app:preProdGoogleReleaseBuild
:app:prepareComAndroidSupportAppcompatV72311Library
:app:prepareComAndroidSupportCardviewV72320Library
:app:prepareComAndroidSupportMediarouterV72220Library
:app:prepareComAndroidSupportMultidex100Library
:app:prepareComAndroidSupportRecyclerviewV72311Library
:app:prepareComAndroidSupportSupportV42320Library
:app:prepareComBatchAndroidBatchSdk153Library
:app:prepareComCrashlyticsSdkAndroidAnswers136Library
:app:prepareComCrashlyticsSdkAndroidBeta114Library
:app:prepareComCrashlyticsSdkAndroidCrashlytics255Library
:app:prepareComCrashlyticsSdkAndroidCrashlyticsCore238Library
:app:prepareComCrashlyticsSdkAndroidCrashlyticsNdk112Library
:app:prepareComFacebookAndroidFacebookAndroidSdk4101Library
:app:prepareComGoogleAndroidExoplayerExoplayerR142Library
:app:prepareComGoogleAndroidGmsPlayServices780Library
:app:prepareComGoogleAndroidGmsPlayServicesAds780Library
:app:prepareComGoogleAndroidGmsPlayServicesAnalytics780Library
:app:prepareComGoogleAndroidGmsPlayServicesAppindexing780Library
:app:prepareComGoogleAndroidGmsPlayServicesAppinvite780Library
:app:prepareComGoogleAndroidGmsPlayServicesAppstate780Library
:app:prepareComGoogleAndroidGmsPlayServicesBase780Library
:app:prepareComGoogleAndroidGmsPlayServicesCast780Library
:app:prepareComGoogleAndroidGmsPlayServicesDrive780Library
:app:prepareComGoogleAndroidGmsPlayServicesFitness780Library
:app:prepareComGoogleAndroidGmsPlayServicesGames780Library
:app:prepareComGoogleAndroidGmsPlayServicesGcm780Library
:app:prepareComGoogleAndroidGmsPlayServicesIdentity780Library
:app:prepareComGoogleAndroidGmsPlayServicesLocation780Library
:app:prepareComGoogleAndroidGmsPlayServicesMaps780Library
:app:prepareComGoogleAndroidGmsPlayServicesNearby780Library
:app:prepareComGoogleAndroidGmsPlayServicesPanorama780Library
:app:prepareComGoogleAndroidGmsPlayServicesPlus780Library
:app:prepareComGoogleAndroidGmsPlayServicesSafetynet780Library
:app:prepareComGoogleAndroidGmsPlayServicesVision780Library
:app:prepareComGoogleAndroidGmsPlayServicesWallet780Library
:app:prepareComGoogleAndroidGmsPlayServicesWearable780Library
:app:prepareComMopubMopubSdk440Library
:app:prepareComZendeskBelvedere1011Library
:app:prepareComZendeskSdk1512Library
:app:prepareComZendeskSdkProviders1512Library
:app:prepareIoBranchSdkAndroidLibrary1112Library
:app:prepareIoFabricSdkAndroidFabric1310Library
:app:prepareDevAmazonDebugDependencies
:app:compileDevAmazonDebugAidl
:app:compileDevAmazonDebugRenderscript
:app:generateDevAmazonDebugBuildConfig
:app:generateDevAmazonDebugAssets UP-TO-DATE
:app:mergeDevAmazonDebugAssets
:app:processDevAmazonDebugManifest
:app:fabricGenerateResourcesDevAmazonDebug
:app:generateDevAmazonDebugResValues UP-TO-DATE
:app:processDevAmazonDebugGoogleServices
:app:generateDevAmazonDebugResources
:app:mergeDevAmazonDebugResources
:app:processDevAmazonDebugResources
:app:generateDevAmazonDebugSources
:app:preDevAmazonDebugAndroidTestBuild
:app:prepareDevAmazonDebugAndroidTestDependencies
:app:compileDevAmazonDebugAndroidTestAidl
:app:processDevAmazonDebugAndroidTestManifest
:app:compileDevAmazonDebugAndroidTestRenderscript
:app:generateDevAmazonDebugAndroidTestBuildConfig
:app:generateDevAmazonDebugAndroidTestAssets UP-TO-DATE
:app:mergeDevAmazonDebugAndroidTestAssets
:app:generateDevAmazonDebugAndroidTestResValues UP-TO-DATE
:app:generateDevAmazonDebugAndroidTestResources
:app:mergeDevAmazonDebugAndroidTestResources
:app:processDevAmazonDebugAndroidTestResources
:app:generateDevAmazonDebugAndroidTestSources
:app:mockableAndroidJar UP-TO-DATE
:app:preDevAmazonDebugUnitTestBuild
:app:prepareDevAmazonDebugUnitTestDependencies
:app:javahBuild_ClassA
:app:javahBuild_ClassB
Error: package com.adjust.sdk does not exist
Error: package com.adjust.sdk does not exist
Error: package com.amazon.ags.api does not exist
Error: package com.batch.android does not exist
Error: package com.batch.android does not exist
Error: package com.crashlytics.android does not exist
Error: package com.crashlytics.android.answers does not exist
Error: package com.crashlytics.android.answers does not exist
Error: package com.crashlytics.android.answers does not exist
Error: package com.mopub.common does not exist
Error: package com.zendesk.sdk.feedback.impl does not exist
Error: package com.zendesk.sdk.model.access does not exist
Error: package com.zendesk.sdk.model.access does not exist
Error: package com.zendesk.sdk.model.push does not exist
Error: package com.zendesk.sdk.network.impl does not exist
Error: package com.zendesk.sdk.network.impl does not exist
Error: package com.zendesk.sdk.network.impl does not exist
Error: package com.zendesk.sdk.network.impl does not exist
Error: package com.zendesk.sdk.network.impl does not exist
Error: package com.zendesk.sdk.requests does not exist
Error: package com.zendesk.sdk.storage does not exist
Error: package com.zendesk.sdk.support does not exist
Error: package com.zendesk.service does not exist
Error: package com.zendesk.service does not exist
Error: package org.joda.time does not exist
Error: package org.joda.time does not exist
Error: package org.joda.time does not exist
Error: package org.joda.time does not exist
Error: package org.joda.time.format does not exist
Error: package org.joda.time.format does not exist
Error: package io.branch.indexing does not exist
Error: package io.branch.referral does not exist
Error: package io.branch.referral does not exist
Error: package io.branch.referral does not exist
Error: package io.branch.referral.util does not exist
Error: package io.branch.referral.util does not exist
Error: package com.adjust.sdk does not exist
Error: package com.amazon.ags.api does not exist
Error: package com.amazon.ags.api does not exist
Error: package com.amazon.ags.api does not exist
Error: package com.amazon.ags.api does not exist
Error: package com.applovin.sdk does not exist
Error: package com.batch.android does not exist
Error: package com.crashlytics.android does not exist
Error: package com.crashlytics.android.ndk does not exist
Error: package io.branch.referral does not exist
Error: package io.branch.referral does not exist
Error: package io.fabric.sdk.android does not exist
Error: package com.google.android.gms.analytics does not exist
Error: package com.google.android.gms.analytics does not exist
Error: package com.google.android.gms.analytics does not exist
Error: package com.google.android.gms.ads.identifier does not exist
Error: package com.google.android.gms.common does not exist
Error: package com.mopub.common does not exist
Error: package com.mopub.common does not exist
Error: cannot find symbol
  symbol:   class MoPubErrorCode
  location: package com.mopub.mobileads
Error: cannot find symbol
  symbol:   class MoPubRewardedVideoListener
  location: package com.mopub.mobileads
Error: package com.chartboost.sdk does not exist
Error: package com.adjust.sdk does not exist
Error: package com.adjust.sdk does not exist
Error: package com.adjust.sdk does not exist
Error: package com.adjust.sdk does not exist
Error: cannot find symbol
  symbol:   class BaseZendeskFeedbackConfiguration
  location: class my.super.project.Renderer
Error: cannot find symbol
  symbol:   class BuildConfig
  location: package my.super.project
Error: cannot find symbol
  symbol:   class Tracker
  location: class my.super.project.Main
Error: ';' expected
Error: package com.facebook does not exist
Error: package com.facebook does not exist
Error: package com.facebook does not exist
Error: package com.facebook does not exist
Error: package com.facebook does not exist
Error: package com.facebook does not exist
Error: package com.facebook does not exist
Error: package com.facebook does not exist
Error: package com.facebook does not exist
Error: package com.facebook does not exist
Error: package com.facebook.appevents does not exist
Error: package com.facebook.login does not exist
Error: package com.facebook.login does not exist
Error: package com.facebook.share.model does not exist
Error: package com.facebook.share.model does not exist
Error: package com.facebook.share.model does not exist
Error: package com.facebook.share.widget does not exist
Error: package com.facebook.share.widget does not exist
Error: package com.facebook.share.widget does not exist
Error: package twitter4j does not exist
Error: package twitter4j does not exist
Error: package twitter4j does not exist
Error: package twitter4j does not exist
Error: package twitter4j does not exist
Error: package twitter4j does not exist
Error: package twitter4j does not exist
Error: package twitter4j does not exist
Error: package twitter4j.auth does not exist
Error: cannot find symbol
  symbol:   class R
  location: package my.super.project
Error: cannot find symbol
  symbol:   class AmazonGamesClient
  location: class my.super.project.Main
Error: cannot find symbol
  symbol:   class MoPubRewardedVideoListener
  location: class my.super.project.Main
Error: cannot find symbol
  symbol:   class ChartBoostDelegate
  location: class my.super.project.Main
Error: cannot find symbol
  symbol:   class CallbackManager
  location: class my.super.project.ClassA
Error: cannot find symbol
  symbol:   class ProfileTracker
  location: class my.super.project.ClassA

 FAILED

FAILURE: Build failed with an exception.

My build.gradle has the following tasks:

android {
    <snip>
    ['Main', 'Renderer', 'ClassA', 'ClassB'].each {
        def targetName ->
            tasks.create(name: "javahBuild_$targetName", type: Exec) {
                Properties properties = new Properties()
                properties.load(project.rootProject.file('local.properties').newDataInputStream())
                String sdkDir = properties.getProperty('sdk.dir')
                String flavorFolder = getCurrentFlavorFolder()
                commandLine 'javah', '-classpath', "libs/:src/main/java/:$sdkDir/platforms/android-23/android.jar:build/intermediates/classes/$flavorFolder/$config:$sdkDir/platforms/android-23/optional/org.apache.http.legacy.jar/:$config/", '-d', 'src/main/jni/Main/', "my.super.project.${targetName}"
            }
    }

    task javahBuildAll(dependsOn: tasks.matching { Task task -> task.name.startsWith("javahBuild_") })

    tasks.withType(JavaCompile) {
        compileTask -> compileTask.dependsOn javahBuildAll
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')

    compile('com.crashlytics.sdk.android:crashlytics:2.5.5@aar') {
        transitive = true;
    }
    compile('com.crashlytics.sdk.android:crashlytics-ndk:1.1.2@aar') {
        transitive = true
    }
    compile('com.mopub:mopub-sdk:4.4.0@aar') {
        transitive = true
    }

    compile group: 'com.zendesk', name: 'sdk', version: '1.5.1.2'

    compile('com.android.support:multidex:1.0.0')
    compile('com.google.android.gms:play-services:7.8.0')
    compile('com.google.android.gms:play-services-analytics:7.8.0')
    compile('com.google.android.gms:play-services-gcm:7.8.0')
    compile('com.android.support:appcompat-v7:23.1.0')
    compile('com.android.support:support-v4:23.1.0')
    compile('com.facebook.android:facebook-android-sdk:4.10.+')
    compile('io.branch.sdk.android:library:1.+')
    compile('com.batch.android:batch-sdk:1.5+')
    compile('com.adjust.sdk:adjust-android:4.2.3')
    compile('joda-time:joda-time:2.9.2')
}
Kyone
  • 513
  • 5
  • 17
  • I don't think your output should be interpreted as "javah works fine for a Java source but not another one". The visible result seems to be a result of running javah on two targets in parallel. If you run these tasks manually, you can verify or reject my assessment. – Alex Cohn Apr 23 '16 at 13:03
  • Hi Alex, thanks for your response. It was what I though first but running javah from the command line gives the same results: it works fine for ClassA, but not for ClassB. – Kyone Apr 23 '16 at 13:16
  • To the best of my knowledge, javah does not care about imports, and will only complain if it cannot determine a signature of a native method of the class that you ask it to process, and then the message in log is "Error: Cannot determine signature for …". Try to set `-classpath src/main/java` and you will see that yourself. – Alex Cohn Apr 23 '16 at 13:43
  • I do specify the class path actually and it doesn't help in any way, ClassA and ClassB are processed exactly the same way... – Kyone Apr 23 '16 at 21:45
  • I am sure that javah cannot complain about non-existing packages. You can copy your ClassB outside the whole project and javah will process it just the same: `mkdir -p /tmp/my/super/project && cp src/main/java/my/super/project/ClassB.java /tmp/my/super/project && javah -cp /tmp my.super.project.ClassB` – Alex Cohn Apr 24 '16 at 04:26
  • Oh it's getting funnier: I did what you explained for both classes and now ClassB "compiles" just fine, but ClassA generates errors... I just realized I could forget about those errors since the header files still get generated. Ahem. – Kyone Apr 24 '16 at 12:22

2 Answers2

0

OK it didn't understand why I'm getting those errors but I just realized I could ignore them since the C++ header files are still getting generated.

So I decide to modify my javah gradle task to ignore errors and write those into a dedicated log file. I've added the following line:

errorOutput = project.file("build/javah_error_${targetName}.log").newDataOutputStream()
ignoreExitValue = true

My javah task now looks like this:

['Main', 'Renderer', 'ClassA', 'ClassB'].each {
    def targetName ->
        tasks.create(name: "javahBuild_$targetName", type: Exec) {
            Properties properties = new Properties()
            properties.load(project.rootProject.file('local.properties').newDataInputStream())
            String sdkDir = properties.getProperty('sdk.dir')
            String flavorFolder = getCurrentFlavorFolder()
            errorOutput = project.file("build/javah_error_${targetName}.log").newDataOutputStream()
            ignoreExitValue = true
            commandLine 'javah', '-classpath', "libs/:src/main/java/:$sdkDir/platforms/android-23/android.jar:build/intermediates/classes/$flavorFolder/$config:$sdkDir/platforms/android-23/optional/org.apache.http.legacy.jar/:$config/", '-d', 'src/main/jni/Main/', "my.super.project.${targetName}"
        }
}
Kyone
  • 513
  • 5
  • 17
0

After multiple hours of searching, researching, trial and error, and other things, I’ve finally got it.

javah is gone, one must use javac […] -h <destdir> […] now.

I already had the following snippet in my top-level build.gradle (not the one under app/ or so!) to add javac arguments

tasks.withType(JavaCompile) {
    options.compilerArgs << "-Xlint:all"
}

… and “just” had to extend that. (This section goes into the allprojects { block which you already have in your top-level build.gradle, I put it after the repositories { […] } block.)

In my case, I merely wanted to let the .h files be created but not actively #include them in the C code (because I use the RegisterNatives method to register my functions), which would be… tricky, as one would additionally to this have to:

  • figure out which of the (possibly multiple) tasks should create the .h files used in the actual build
  • give that a stable pathname
  • add that path to the include directories in the native build (again tricky)

For mere manual introspection, I just add the javac -h <destdir> option to all javac invocations, creating per-task result directories, and then just look at them in Midnight Commander:

tasks.withType(JavaCompile) {
    options.compilerArgs << "-Xlint:all"
    options.getHeaderOutputDirectory().value(project.layout.buildDirectory.dir("headers/" + getName()))
}

(The compilerArgs change is, of course, copied unchanged from the above.)

mirabilos
  • 5,123
  • 2
  • 46
  • 72