8

When running groovyc in a Windows env, I am running into issues due to the length of the classpath, in my situation. I would like to work around this by creating a pathing jar, and then put that jar on the cp. How can I create a pathing jar w/ all of the classpath entries specified automatically in gradle and then add that jar to the cp?

Ray Nicholus
  • 19,538
  • 14
  • 59
  • 82

3 Answers3

12

Here is a tested solution:

task pathingJar(type: Jar) {
  appendix = "pathing"
  doFirst {
    manifest {
      attributes "Class-Path": configurations.compile.files.join(" ")
    }
  }
}

compileGroovy {
    dependsOn(pathingJar)
    classpath = files(pathingJar.archivePath)
}    

Depending on your exact requirements, you might have to tweak this a bit. For example, if you have tests written in Groovy, you will also need a pathing Jar for the test compile class path. In this case you'll need to repeat above configuration as follows:

task testPathingJar(type: Jar) {
  appendix = "testPathing"
  doFirst {
    manifest {
      attributes "Class-Path": configurations.testCompile.files.join(" ")
    }
  }
}

compileTestGroovy {
    dependsOn(testPathingJar)
    classpath = files(testPathingJar.archivePath)
}    
Peter Niederwieser
  • 121,412
  • 21
  • 324
  • 259
  • Follow-up question: this doesn't appear to work as expected. The pathing jar is created, but when I add the pathing jar to the classpath when compiling, for some reason, the compile fails and complains about missing jars that are already referenced in the pathing jar... – Ray Nicholus Apr 04 '11 at 14:16
  • I'm thinking that this will not work, as this specifies absolute paths of the jars in the manifest. It isn't clear that absolute paths are valid in this case. – Ray Nicholus Apr 04 '11 at 15:15
  • The problem wasn't the absolute paths but that colon instead of space was used as the path separator. I've updated the code and tested it to make sure it works. – Peter Niederwieser Apr 05 '11 at 10:00
  • I seem to remember testing with a space without any luck. I'll give it a shot again today and report back. – Ray Nicholus Apr 07 '11 at 13:13
  • Yep, this is not working for me. When I used the pathing jar, the compile fails due to an inability to locate dependencies. – Ray Nicholus Apr 07 '11 at 14:41
  • Strange, works for me. I even had a solution that used relative paths but discarded it after I found that absolute paths weren't the cause of the problem. How big is your project that you run into this kind of problem? – Peter Niederwieser Apr 07 '11 at 17:39
  • I'd say we have a fairly large group of libraries/dependencies. Any idea what might be wrong? If I bypass gradle entirely and attempt to compile from the command line using javac & the pathing jar, I still run into the same problem. – Ray Nicholus Apr 07 '11 at 20:40
  • Which problem? That the pathing Jar doesn't work or that some class path is too long? Maybe absolute paths in the Class-Path attribute work on some platforms but not on others. I tested it on Mac OS X. – Peter Niederwieser Apr 08 '11 at 08:33
  • Another way to tackle this problem would be to shorten the class path by substituting common path parts with an environment variable (say GRADLE_USER_HOME). – Peter Niederwieser Apr 08 '11 at 08:39
  • I'll admit I've only tested this on Windows. Actually, I only need to test it on Windows as Windows is the reason for the use of a pathing jar in the first place, due to the single-command size limit. Regarding the env variable suggestion, I have considered that, but see the pathing jar idea as more elegant. That's a moot point because the pathing jar idea doesn't seem to work for me though. In the meantime, we have a workaround. Thanks for your input on this Peter. – Ray Nicholus Apr 08 '11 at 18:05
  • 1
    Class-path entries are ALWAYS relative see the jar spec: The value of this attribute specifies the relative URLs of the extensions or libraries that this application or extension needs [cited: http://docs.oracle.com/javase/1.4.2/docs/guide/jar/jar.html] – default_avatar Apr 08 '13 at 22:26
  • @RichardJohnson updated link for malformed/old link in previous comment: https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html – JimLohse Dec 30 '15 at 00:29
  • 1
    If using Spring Boot and gradle 4.x or later, and attempting to start the application with the bootRun task, then the configuration should be "runtimeClasspath." – Philippe Apr 18 '19 at 12:52
5

I finally got the "pathing jar" idea to work. I consider this to be a permanent workaround. This could be considered a solution if it is made part of gradle itself.

The original pathing jar code was provided by Peter, but it didn't work. The problem: classpath elements referenced in the pathing jar must be relative to the location of the pathing jar. So, this appears to work for me.

task pathingJar(type: Jar , dependsOn: 'cleanPathingJar') {
/**
 * If the gradle_user_home env var has been set to 
     * C:\ on a Win7 machine, we may not have permission to write the jar to
 * this directory, so we will write it to the caches subdir instead.  
     * This assumes a caches subdir containing the jars
 * will always exist.
 */
gradleUserHome = new File(gradle.getGradleUserHomeDir(), "caches")

relativeClasspathEntries = configurations.compile.files.collect {
    new File(gradleUserHome.getAbsolutePath()).toURI().
                  relativize(new File(it.getAbsolutePath()).toURI()).getPath()
}
appendix = "pathing"
destinationDir = gradleUserHome
doFirst {
    manifest {
        attributes "Class-Path": relativeClasspathEntries.join(" ")
    }
}
}

compileGroovy {
    dependsOn(pathingJar)
    classpath = files(pathingJar.archivePath)
}
Ray Nicholus
  • 19,538
  • 14
  • 59
  • 82
  • 1
    But this doesn't seem to contain currently project's jar file in the classpath? – Baiyan Huang Jan 13 '14 at 07:08
  • 2
    This [didn't work in Groovy versions between 3.0.5 in 3.0.8](https://github.com/grails/grails-core/issues/9300). The linked Grails issue also includes a full workaround, using this approach. – Damir Arh Nov 26 '15 at 13:50
  • I'm new to Gradle, but when I tried this solution it complained about gradleUserHome and relativeClasspathEntries not being defined, so I have added a def declaration in each line. – Constantino Cronemberger Oct 15 '20 at 10:48
0

This is what helped me:

"The filename or extension is too long error" using gradle

In other words: use the com.github.ManifestClasspath plugin.

The other solutions did not work for me because the actual project main class ended up no being included in the classpath at execution time.