9

I have a complex Android project consisting of multiple Java and C++ modules and using several build tools (e.g. CMake, swig). The project builds just fine when built from the command line using ./gradlew clean assembleDebug but fails to build when built from Android Studio. I cleaned, invalidated caches, synced, etc to no avail.

Important to note: this project builds fine in Android Studio too on other systems like Ubuntu (17.* and 18.*) but fails on MacOS (10.13 but also earlier if I remember correctly).

Here is the error reported by Android Studio:

org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':IndoorsLocator:runSwig'.
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:84)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:55)
    at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:62)
    at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
    at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:88)
    at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:46)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:51)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
    at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
    at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.execute(DefaultTaskGraphExecuter.java:236)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.execute(DefaultTaskGraphExecuter.java:228)
    at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:106)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:61)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:228)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:215)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:77)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:58)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:32)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:113)
    at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:37)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
    at org.gradle.execution.DefaultBuildExecuter.access$000(DefaultBuildExecuter.java:23)
    at org.gradle.execution.DefaultBuildExecuter$1.proceed(DefaultBuildExecuter.java:43)
    at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:30)
    at org.gradle.initialization.DefaultGradleLauncher$3.execute(DefaultGradleLauncher.java:196)
    at org.gradle.initialization.DefaultGradleLauncher$3.execute(DefaultGradleLauncher.java:193)
    at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:106)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:56)
    at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:193)
    at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:119)
    at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:102)
    at org.gradle.launcher.exec.GradleBuildController.run(GradleBuildController.java:71)
    at org.gradle.tooling.internal.provider.runner.BuildModelActionRunner.run(BuildModelActionRunner.java:50)
    at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
    at org.gradle.tooling.internal.provider.runner.RunAsBuildOperationBuildActionRunner$1.execute(RunAsBuildOperationBuildActionRunner.java:43)
    at org.gradle.tooling.internal.provider.runner.RunAsBuildOperationBuildActionRunner$1.execute(RunAsBuildOperationBuildActionRunner.java:40)
    at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:106)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:56)
    at org.gradle.tooling.internal.provider.runner.RunAsBuildOperationBuildActionRunner.run(RunAsBuildOperationBuildActionRunner.java:40)
    at org.gradle.tooling.internal.provider.runner.SubscribableBuildActionRunner.run(SubscribableBuildActionRunner.java:75)
    at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:41)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)
    at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:75)
    at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:49)
    at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:44)
    at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:29)
    at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:67)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:47)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72)
    at org.gradle.util.Swapper.swap(Swapper.java:38)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:60)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:72)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50)
    at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
    at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.gradle.process.internal.ExecException: A problem occurred starting process 'command 'swig''
    at org.gradle.process.internal.DefaultExecHandle.setEndStateInfo(DefaultExecHandle.java:198)
    at org.gradle.process.internal.DefaultExecHandle.failed(DefaultExecHandle.java:329)
    at org.gradle.process.internal.ExecHandleRunner.run(ExecHandleRunner.java:86)
    ... 5 more
Caused by: net.rubygrapefruit.platform.NativeException: Could not start 'swig'
    at net.rubygrapefruit.platform.internal.DefaultProcessLauncher.start(DefaultProcessLauncher.java:27)
    at net.rubygrapefruit.platform.internal.WrapperProcessLauncher.start(WrapperProcessLauncher.java:36)
    at org.gradle.process.internal.ExecHandleRunner.run(ExecHandleRunner.java:68)
    ... 5 more
Caused by: java.io.IOException: Cannot run program "swig" (in directory "/Users/tom/workspace/indoors-scripts/setup-scripts/workspace-android/IndoorsAndroid/IndoorsLocator"): error=2, No such file or directory
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
    at net.rubygrapefruit.platform.internal.DefaultProcessLauncher.start(DefaultProcessLauncher.java:25)
    ... 7 more
Caused by: java.io.IOException: error=2, No such file or directory
    at java.lang.UNIXProcess.forkAndExec(Native Method)
    at java.lang.UNIXProcess.<init>(UNIXProcess.java:247)
    at java.lang.ProcessImpl.start(ProcessImpl.java:134)
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
    ... 8 more

build failing in Android Studio

On the command line: build going through via command line (note we are passed "IndoorsLocator:runSwig" already)

Here is what the definition of "runSwig"-task looks like:

task runSwig(type: Exec) {
    commandLine 'swig'

    doFirst {
        coreWrapperDir.mkdirs()
    }

    def swigFileCore = "${projectDir}/src/" + "swig.i"
    def headerFiles = "${projectDir}/include"
    def swigWrapFile = 'src/swig_wrap.cxx'

    inputs.file swigFileCore
    inputs.dir headerFiles
    outputs.dir coreWrapperDir.absolutePath
    outputs.file swigWrapFile

    // this write the generated swig C++ file to "${projectDir}/src"
    args '-c++', '-java', '-package', javaPackage, '-noexcept', '-outdir', coreWrapperDir.absolutePath, "-I${headerFiles}", '-o', swigWrapFile, swigFileCore
}

The log indicates that Android Studio is looking for swig in the current working directory instead of looking it up inside $PATH, but I am clueless about how to tell Android Studio where to look instead. Any ideas?

Cannot run program "swig" (in directory "/Users/tom/workspace/indoors-scripts/setup-scripts/workspace-android/IndoorsAndroid/IndoorsLocator")
TomTasche
  • 5,448
  • 7
  • 41
  • 67
  • 1
    https://stackoverflow.com/questions/31403573/specify-path-environment-does-not-work-when-running-gradle-exec checked this? – PolishCivil Jul 22 '18 at 01:50

3 Answers3

2

There is a need for some debugging to get more info about the problem. Add the code below to your build.gradle file of IndoorsLocator module and run it again. This should print the path environment variable and also run a java command which I'm assuming is also within the path. Then perform a gradle sync and compile or run the code. Open the build window as in your first image and when the build stops, find the testPath within the Run tasks list and share it's output. Or more preferably, switch the Build to text view as in the image below and share the complete log. Testing it from the command would also help to make sure that it's running as expected.

tasks.whenTaskAdded { addedTask ->
    if (addedTask.name.startsWith("preDebugBuild")) {
        addedTask.dependsOn 'testPath'
    }
}

task testPath {
    mustRunBefore 'checkDebugManifest'
    doLast {
        exec {
            commandLine 'echo', '$PATH'
        }
        exec {
            commandLine 'java', '-version'
        }
    }
}

enter image description here

Update 1

Based on your first comment, this is a weird outcome! Java is supposed to be in the path, so $PATH must've been set somehow yet echo $PATH didn't work. Updated the code to further go down the rabbit hole.

tasks.whenTaskAdded { addedTask ->
    if (addedTask.name.startsWith("preDebugBuild")) {
        addedTask.dependsOn 'testPath'
    }
}

task testPath {
    doLast {
        exec {
            commandLine 'printenv'
        }
        exec {
            commandLine 'which', 'java'
        }
        exec {
            commandLine 'which', 'swig'
        }
    }
}

PS: my mistake on the mustRunBefore, it doesn't exist and I added it accident!

ahasbini
  • 6,761
  • 2
  • 29
  • 45
  • Thanks for the tip about switching to text view for the Build-panel! That's really useful. I had to remove the line starting with "mustRunBefore" - I think it's because we are forced to use an old version of gradle plugin. This is the output without that line: `:IndoorsLocator:testPath $PATH java version "1.8.0_172" Java(TM) SE Runtime Environment (build 1.8.0_172-b11) Java HotSpot(TM) 64-Bit Server VM (build 25.172-b11, mixed mode)` Seems like he is not evaluating the $PATH variable at all? – TomTasche Jul 25 '18 at 08:02
  • 1
    Thanks a lot for your help so far, you did a great job helping me to investigate this issue! I found the root cause (OSX bug) and decided to workaround it since there does not seem to be a clean solution as I had hoped for. (see my answer below) – TomTasche Jul 25 '18 at 09:46
  • That's great, I still have a solution in mind which I hope is clean but need the result from my last code update to make sure – ahasbini Jul 25 '18 at 20:03
  • There you go: https://pastebin.com/TMm0g1PE - `PATH=/usr/bin:/bin:/usr/sbin:/sbin SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.DWsBI8UTnd/Listeners SHELL=/bin/bash XPC_FLAGS=0x0 __CF_USER_TEXT_ENCODING=0x1F5:0x0:0x0 Apple_PubSub_Socket_Render=/private/tmp/com.apple.launchd.HqXv61LKKS/Render LOGNAME=tom XPC_SERVICE_NAME=com.google.android.studio.6548 USER=tom HOME=/Users/tom TMPDIR=/var/folders/3l/j87th09j2jzdpbg_96w2kcd80000gn/T/ /usr/bin/java` – TomTasche Jul 26 '18 at 07:02
2

Turns out this is due to a "bug" in OSX: https://github.com/gradle/gradle/issues/5631#issuecomment-401775152

I did not find a way to easily fix it for the latest version of OSX (https://apple.stackexchange.com/questions/106355/setting-the-system-wide-path-environment-variable-in-mavericks) but worked around it by hardcoding the path in build.gradle:

task runSwig(type: Exec) {
    // workaround for OSX, see https://stackoverflow.com/q/51383822/198996
    File testFile = new File('/usr/local/bin/swig');
    if (testFile.isFile()) {
        commandLine '/usr/local/bin/swig'
    } else {
        commandLine 'swig'
    }
}

That's an awful workaround if you ask me, so I would be happy to award the bounty to whoever comes up with a cleaner solution.

TomTasche
  • 5,448
  • 7
  • 41
  • 67
1

Have you added this line in your build.gradle?

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

Anyway you can refer to this github's project that uses swig: https://github.com/sureshjoshi/android-ndk-swig-example

Roberto Manfreda
  • 2,345
  • 3
  • 25
  • 39
  • 1
    `runSwig` is being executed already as shown in the images, hence it 's dependency is already made and is not the problem – ahasbini Jul 25 '18 at 00:27
  • Right, as mentioned by @ahasbini the task is being executed just fine. As I've said before, it does work on other platforms (i.e. Linux). Thanks for the link to ndk-swig, that is our last option I guess if nobody can help me fix the current issue. – TomTasche Jul 25 '18 at 07:59