Gradle executing dex Error command line too long

2019-05-05 18:24发布

问题:

I'm building an Android app on windows using gradle and when it comes to last module I'm facing the following error :

* What went wrong:
Execution failed for task ':client:test:dexApiPhoneDebug'.
> com.android.ide.common.internal.LoggedErrorException: Failed to run command:
        C:\adt-bundle-windows\sdk\build-tools\19.1.0\dx.bat --dex --num-threads= 
.....
Error Code:
    1
Output:
        The command line is too long.

I'm using the command line to build. I know that a similar issue can be solve if using Maven by mapping you project to a disk letter as described here : The command line is too long. in java project with maven

Do you have any idea how can I solve that issue using Gradle?

回答1:

I figured out a workaround, it's not perfect but at least do the job.

Basically the project I had was under a long directory like : C:\Development\cloud\my.cloud\main\mycompany\android.

So as a workaround I mapped this folder to a network location, you can do that by using SUBST MS-DOS command or in Explorer under your computer use the GUI "Map a Network Drive". Actually I mapped it to a letter Z: and run my gradle command from there and it worked like a charm.

As I said it's not perfect but at least allowed me to move forward.



回答2:

Making a network drive works but seems slower.

Instead of that, I found it better to create a link to the real directory. In Windows it goes like that:

mklink /j "D:\myshortname" "D:\my\long\directory\name\causing\trouble\but\its\not\my\fault\leave\me\alone"

Then I simply open the project from the symlinked directory instead of the real one.



回答3:

I managed to fix it by changing the configuration of the Dex task in gradle. In our project, we found that Dex basically takes as input the output files of the "preDex" task. As Dex accepts a folder as input, overriding the list of jars with the folder did the trick for us.

Here is the code we added in the root build.gradle

task (configureDex) {
  gradle.taskGraph.beforeTask { Task task ->
      if (task.name.contains("dex") && !task.name.contains("predex")) {
        task.libraries = findPredexTask().outputFolder
      }
  }
}

def findPredexTask(){
  gradle.taskGraph.getAllTasks().findAll{ task ->
    task.name.toLowerCase().contains('predex')
  }
}

The drawback of this solution is that it will fail if you disable pre-dexing, but it could be easily adapted.

Also note that you cannot search "dex" or "predex" directly as the android gradle plugin automatically adds the variant of the execution to the task name.