Skip to content

Migrated to the Gradle build system#126

Merged
itdelatrisu merged 3 commits intoitdelatrisu:masterfrom
Lemmmy:lemmmyfixes
Aug 27, 2015
Merged

Migrated to the Gradle build system#126
itdelatrisu merged 3 commits intoitdelatrisu:masterfrom
Lemmmy:lemmmyfixes

Conversation

@Lemmmy
Copy link
Contributor

@Lemmmy Lemmmy commented Aug 26, 2015

It took a while, but I've migrated the project to Gradle. IntelliJ has built in support for gradle, I'm not sure about Eclipse but it probably does.

IntelliJ Usage

To use this in IntelliJ, you first need to reopen the project. File -> Open, then navigate to the build.gradle file and simply open that. Next, make sure that you have selected a valid JAVA_HOME location and you can optionally enable Auto import if you don't want to have to run gradle build every time the build file changes. Click Next or Finish or whatever.

The project will sync for a few minutes, and the structure will change a few times during this process. Don't panic, it should work when the import is over. Next, go into Run -> Edit Configurations and click the green +, choose Gradle. Name the configuration run, set the Gradle Project to the build.gradle file, and set the task to run.

Next, you need to unpack the LWJGL natives. You will only ever have to do this once, unless you clean the project or delete the target folder. In the gradle panel on the right of the screen, double click opsu -> Tasks -> other -> unpackNatives. It should take a few seconds to unpack the natives, and that is all. You can now run the project.

Finally, to compile a fat jar, you can run the build -> build task. It will build to target/libs/opsu-(version).jar.

Eclipse usage

I'm not too sure about Eclipse usage, but it should be as simple as importing the build.gradle similar to above, and running the tasks.

Gradle tasks

unpackNatives
Unpacks the LWJGL natives from the jar and places them in target/natives

run
Builds and runs the project

build
Builds the project and produces a fat jar containing the libraries and natives. NativeLoader is a class that works similar to the JarSplice launcher - it looks for top level dll, so, jnilib and dylib files inside the jar and extracts them to a temporary directory, which is finally set as the classpath.

You can run a gradle task in the CLI by running gradle <task>.

build.gradle explanation

The gradle file is initially a bit complicated, but it's actually pretty simple.

// Loads the Java plugin
apply plugin: 'java'
// Loads the Maven plugin, used to import Maven dependencies
apply plugin: 'maven'
// Loads the Eclipse plugin, if you run the task 'gradle eclipse' it will create Eclipse project files for you.
apply plugin: 'eclipse'
// Loads the IntelliJ Idea plugin. If you run the task 'gradle idea' it will create IntelliJ project files for you.
apply plugin: 'idea'
// Loads the application plugin. This is used for creating runnable jars and fat jars.
apply plugin: 'application'

// The Group ID
group = 'itdelatrisu'
// The project version
version = '0.10.1'

// The main class
mainClassName = 'itdelatrisu.opsu.Opsu'
// By default, gradle builds to (root)/build. I just made this (root)/target for compatibility
buildDir = new File(rootProject.projectDir, "target/")

// Java version to use when compiling the java source
sourceCompatibility = 1.7
// Java version to use for the classes
targetCompatibility = 1.7

// The source directories
sourceSets {
    main {
        java {
            // The main module's java source is in (root)/src
            srcDir 'src'
        }
        // Files to be copied to the root of the jar
        resources {
            // The resources are in (root)/res
            srcDir 'res'
             // Also copies the natives to the jar for NativeLoader to load them.
            include 'target/natives'
        }
    }
}

// Load repositories from Maven
repositories {
    mavenCentral()
}

// The dependencies, of course
dependencies {
    compile 'org.lwjgl.lwjgl:lwjgl:2.9.3'
    compile 'org.slick2d:slick2d-core:1.0.1'
    compile 'org.jcraft:jorbis:0.0.17'
    compile 'net.lingala.zip4j:zip4j:1.3.2'
    compile 'com.googlecode.soundlibs:jlayer:1.0.1-1'
    compile 'com.googlecode.soundlibs:mp3spi:1.9.5-1'
    compile 'com.googlecode.soundlibs:tritonus-share:0.3.7-2'
    compile 'org.xerial:sqlite-jdbc:3.8.6'
    compile 'org.json:json:20140107'
    compile 'net.java.dev.jna:jna:4.1.0'
    compile 'net.java.dev.jna:jna-platform:4.1.0'
    compile 'org.apache.maven:maven-artifact:3.3.3'
    compile 'org.apache.commons:commons-compress:1.9'
    compile 'org.tukaani:xz:1.5'
    compile 'com.github.jponge:lzma-java:1.3'
}

// A list of folders that lwjgl hides the natives in
def nativePlatforms = ['windows', 'linux', 'osx']
// For each platform, and disable some weird false warning in IntelliJ
nativePlatforms.each { platform -> //noinspection GroovyAssignabilityCheck
    // Adds additional tasks for single-platform native unpacking
    task "${platform}Natives" {
        // Outputs to target/natives
        def outputDir = "${buildDir}/natives/"
        inputs.files(configurations.compile)
        outputs.dir(outputDir)
        doLast {
            copy {
                def artifacts = configurations.compile.resolvedConfiguration.resolvedArtifacts
                        .findAll { it.classifier == "natives-$platform" }
                artifacts.each {
                    from zipTree(it.file)
                }
                into outputDir
            }
        }
    }
}

// Adds the unpackNatives task, which looks for other xNatives tasks and 'depends on' them, essentially executing them before this one
task unpackNatives {
    description "Copies native libraries to the build directory."
    dependsOn nativePlatforms.collect { "${it}Natives" }.findAll { tasks[it] } }
}

// Defines the format for the jar when running the 'jar' task, this is a function added by the application plugin
jar {
    manifest {
        attributes 'Implementation-Title': 'opsu!',
                'Implementation-Version': version,
                'Main-Class': mainClassName
    }

    // This allows us to override the slick classes
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
    // Base filename
    baseName = "opsu"
    // Marks everything in the source directories to be added to the jar
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}

@itdelatrisu
Copy link
Owner

I'll try this when I get home -- thanks for the thorough explanations! The build file really does look a lot simpler than the current pom.xml...

Do you mind reverting 3a751a2 and squashing, or making a new pull request? You deleted and re-added a bunch of files there (not sure if you noticed). Also, I appreciate the cursor animations, but could you put that in a different PR too? xD

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 26, 2015 via email

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 26, 2015

I may have caused a few issues, such as your commit now appearing as mine, can you let me know if that's what you wanted? Also I'm not sure how to remove the cursor animations without making another commit in this branch, let me know.

@itdelatrisu
Copy link
Owner

Okay, finally got a chance to try this out; it mostly looks good. Comments:

  • gradle jar doesn't package anything from the res folder into the jar.
  • Did you write NativeLoader yourself, or did you mostly copy it from JarSplice? Either way, add an @author annotation to the file and copy any license statements if necessary.
  • Previously, Maven was adding properties into the version file that gets included in the jar, used for error reporting and checking for updates. The current Gradle build file isn't doing this (I think).
  • You added *.ipr into .gitignore but didn't delete opsu.ipr. (This might have gotten messed up by the squashing...)

Less important things:

  • I'd prefer that you remove the res_new folder and the cursor-related changes from this PR, even if it takes another commit (and you can squash it anyway). Also, take a look at the new animation classes (itdelatrisu.opsu.ui.animations.AnimationEquation) instead of adding easeInOut into Utils.
  • You're indenting with spaces everywhere, but everything else is currently using tabs. :P

Questions:

  • What are your opinions about leaving pom.xml so that you can build with either Gradle or Maven? It shouldn't conflict as long as the two are using different build folders, right? You mentioned that you'd have to duplicate the dependencies in both build files, but that doesn't seem like an immediate concern.
  • What's the purpose of gradlew? My internet's incredibly slow where I'm living right now so the script never finishes downloading https://services.gradle.org/distributions/gradle-2.3-all.zip, but it seems like the Gradle tasks work fine without this?

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

Something is weird about those, but I'll get to work

eh

  • gradle jar includes the resources for me, but try gradle build in place of gradle jar, perhaps as a permanent replacement. I learned a short amount of time ago accidentally that gradle build runs the jar task anyway.
  • I've never indented with spaces in my life (IDE screwed up?)
  • gradlew is required by convention as it is a gradle wrapper, similar to the one you have installed on your system. Most IDEs use the gradlew so that it does not require gradle to be installed in the environment, and this is also incredibly useful for continuous integration
  • res-new and the cursor animations are really not supposed to be here, I have no clue what happened

i'll do

  • I'll add @author and copyrights for NativeLoader
  • I'll have an extremely intense look at the build file to see why it's not including the resources for you
  • I'll try to include the pom, but some things might explode (especially when depending on some future files that my PRs might need)
  • I'll take a look at AnimationEquation
  • I'll force a re-indent on all the files I changed

@itdelatrisu
Copy link
Owner

gradle build isn't including them either. (Also a lot slower for me, probably because of the distTar and distZip tasks.) Am I looking in the right place (target/libs/opsu-0.10.1.jar)?

Let me know if there's anything you'd like me to help with!

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

Yeah, that's the right place. I can't find anything in the pom.xml that creates a version. Can you tell me where it fetches the properties from, especially the file property?

@itdelatrisu
Copy link
Owner

The raw file is res/version. There are two relevant sections in the pom:

    <properties>
        <!-- this replaces ${timestamp} in the version file -->
        <timestamp>${maven.build.timestamp}</timestamp>
        <maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
    </properties>
            <resource>
                <filtering>true</filtering> <!-- enable filtering of the file -->
                <directory>res</directory>
                <includes>
                    <include>**/version</include>
                </includes>
            </resource>

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

Ah, this is something I can fix then. Give me a second

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

Also, let me know if resources work on this new commit

@itdelatrisu
Copy link
Owner

It still isn't. I'll also look into why it isn't working on my end...

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

I cleaned my build directory and now I'm getting the same result, so it's reproducible. Looking into this now.

Edit: Fixed it locally, just adding version now.

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

Let me know if the gradle works now, I have everything working on my end.

@itdelatrisu
Copy link
Owner

Okay, will try it in a moment. Alternatively, I got it working by adding this line under resources in sourceSets:

            include '**/*.*'

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

I've removed the resources in sourceSets completely, and this change also allowed me to add the version to the version file. It's now in processResources.

@itdelatrisu
Copy link
Owner

Yeah, I see. I'm getting this when I try to run the jar:

** Uncaught Exception! **
java.lang.UnsatisfiedLinkError: C:\Users\...\AppData\Local\Temp\natives1773156282\lwjgl64.dll: Can't find dependent libraries
    at java.lang.ClassLoader$NativeLibrary.load(Native Method)
    at java.lang.ClassLoader.loadLibrary0(Unknown Source)
    at java.lang.ClassLoader.loadLibrary(Unknown Source)
    at java.lang.Runtime.load0(Unknown Source)
    at java.lang.System.load(Unknown Source)
    at org.lwjgl.Sys$1.run(Sys.java:70)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.lwjgl.Sys.doLoadLibrary(Sys.java:66)
    at org.lwjgl.Sys.loadLibrary(Sys.java:87)
    at org.lwjgl.Sys.<clinit>(Sys.java:117)
    at org.lwjgl.opengl.Display.<clinit>(Display.java:135)
    at org.newdawn.slick.AppGameContainer$1.run(AppGameContainer.java:39)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.newdawn.slick.AppGameContainer.<clinit>(AppGameContainer.java:36)
    at itdelatrisu.opsu.Opsu.main(Opsu.java:168)

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

I got a completely different error:

An error occurred while creating the game container.
org.newdawn.slick.SlickException: Failed to set the icon
    at org.newdawn.slick.AppGameContainer.setIcons(AppGameContainer.java:530)
    at itdelatrisu.opsu.Opsu.main(Opsu.java:173)

Just gonna quickly try a clean then re-run

edit: I think I know the problem. The resources are in buildDir/natives, so they might be placed in ./natives. Stand by for verification

edit2: This is not the case.

(and yes, there is no ! in the directory name)

edit3:

Thu Aug 27 03:19:41 BST 2015 ERROR:Error reading PNG image data
javax.imageio.IIOException: Error reading PNG image data
    at com.sun.imageio.plugins.png.PNGImageReader.readImage(Unknown Source)
    at com.sun.imageio.plugins.png.PNGImageReader.read(Unknown Source)
    at javax.imageio.ImageIO.read(Unknown Source)
    at javax.imageio.ImageIO.read(Unknown Source)
    at org.newdawn.slick.opengl.ImageIOImageData.loadImage(ImageIOImageData.java:117)
    at org.newdawn.slick.AppGameContainer.setIcons(AppGameContainer.java:527)
    at itdelatrisu.opsu.Opsu.main(Opsu.java:173)
Caused by: java.util.zip.ZipException: incorrect header check
    at java.util.zip.InflaterInputStream.read(Unknown Source)
    at java.io.BufferedInputStream.fill(Unknown Source)
    at java.io.BufferedInputStream.read(Unknown Source)
    at java.io.FilterInputStream.read(Unknown Source)
    at com.sun.imageio.plugins.png.PNGImageReader.decodePass(Unknown Source)
    at com.sun.imageio.plugins.png.PNGImageReader.decodeImage(Unknown Source)
    ... 7 more
Thu Aug 27 03:19:41 BST 2015 ERROR:An error occurred while creating the game container.
Thu Aug 27 03:19:41 BST 2015 ERROR:Failed to set the icon
org.newdawn.slick.SlickException: Failed to set the icon
    at org.newdawn.slick.AppGameContainer.setIcons(AppGameContainer.java:530)
    at itdelatrisu.opsu.Opsu.main(Opsu.java:173)

okay, I have a feeling that @Version@ is being replaced in the icon png somewhere, so I'm gonna try changing their names

@itdelatrisu
Copy link
Owner

Unrelated, but to fill in the remaining parts of pom, a few last changes:

  • Wrap the filter in a filesMatching condition (just to be safe):
    filesMatching('version') {
        filter ReplaceTokens, tokens: [
                "version": project.property("version"),
                "timestamp": new Date().format("yyyy-MM-dd HH:mm")
        ]
    }
  • Add exclude '**/Thumbs.db' to the processResources and jar tasks.

Looking into my exception now...

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

Right, that should hopefully fix both of our exceptions, give me a min to test

@itdelatrisu
Copy link
Owner

Okay, odd, the jar executes fine now (without applying any other changes). The temporary natives folder isn't deleted when I close the program, though.

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

Hmm, seems that deleteOnExit() didn't work then. Any suggestions for that?

@itdelatrisu
Copy link
Owner

I'll look into it in a moment.

I noticed that when running a jar generated by JarSplice, only the natives for the current OS are extracted to the temporary folder; your native loader extracts all of them.

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

Yeah, that was part of my "I give up" debugging, let me quickly fix that
Also, should I squash all these gradle commits? x.x

@itdelatrisu
Copy link
Owner

Yeah, probably (backup and) squash everything at the end, not now.

Honestly, if we just take the native loader from the JarSplicePlus project I've been working from, everything should be fine: https://github.com/itdelatrisu/JarSplicePlus/blob/master/src/org/ninjacave/jarsplice/JarSpliceLauncher.java

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

Yeah, that's what I've been referencing (except I had to change the first method, like we don't need to run a new jar, just setting the classpath works)

@itdelatrisu
Copy link
Owner

You aren't calling deleteNativeDirectory() anywhere. We should probably add a shutdown hook for it. Also, deleteOnExit() doesn't work for non-empty directories, I think, so it might work if we just call it for every file in the directory (after the directory itself, since they get deleted in reverse order).

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

Got it. I'll add a shutdown hook that calls deleteNativeDirectory().

@itdelatrisu
Copy link
Owner

Okay, it almost worked... seems like lwjgl64.dll and OpenAL64.dll couldn't be deleted so the directory couldn't either. x-x

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

What exception was thrown?

@itdelatrisu
Copy link
Owner

None, the files were probably locked. delete() just returns false.

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

Okay, is that a change I need to make in this last commit?

@itdelatrisu
Copy link
Owner

You should merge my last commit from master (git merge master) like I did in the PR; that'll fix the issues with that commit.

@itdelatrisu
Copy link
Owner

No, you don't need to make the change; I can do it later.

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

Okay, let me just finish up here, merge and rebase. My JDK just disappeared so I can't test the native loader, but it's identical to yours so it should be okay.

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

There, knocked out the billion commits. Does that look good?

@itdelatrisu
Copy link
Owner

Yup, and everything seems to be working. Is this ready to be merged?

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

Go ahead! If you want me to update the readme prior to that, I can.

@itdelatrisu
Copy link
Owner

Sure, if you want (though I might edit it later as well).

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

Right, should I squash that commit too?

@itdelatrisu
Copy link
Owner

No, don't bother.

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

Got it, give me a min then

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

Go ahead and merge!

@itdelatrisu
Copy link
Owner

Great, thanks!

One last thing from that commit, the jar task shouldn't depend on unpackNatives since it isn't copying the natives from that directory, but from the dependencies (I think I mentioned this a while ago).

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

Oh yep, sorry, I have less memory than my nokia phone

@itdelatrisu
Copy link
Owner

No problem. :P Thanks so much for working on this with me and making this relatively painless. I'll try to get any follow-ups with this done later today (only fixing XDG, I think...). (I'm glad we don't need JarSplice anymore, too. XD)

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

Awesome! And yeah, I've had endless problems with jarsplice in my lifetime, this native loader should be reusable in other projects too, which is nice.

itdelatrisu added a commit that referenced this pull request Aug 27, 2015
Added Gradle build system, removed JarSplice from build cycle.
@itdelatrisu itdelatrisu merged commit fdf8e3c into itdelatrisu:master Aug 27, 2015
@Lemmmy Lemmmy mentioned this pull request Aug 27, 2015
@itdelatrisu
Copy link
Owner

By the way, please make another PR for your cursor animations when you're free. xD

@chong601
Copy link

LOL

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

Oh yeah, I forgot to PR that, I finished those earlier

@Lemmmy
Copy link
Contributor Author

Lemmmy commented Aug 27, 2015

I'll also make another PR for my hi-res textures when I have a decent set of them. I'll continue working on those now. Check #127.

@itdelatrisu
Copy link
Owner

I'm not sure how I feel about adding HD images since it'll really increase the loading time/memory usage/file size. Maybe just as a separate download...

itdelatrisu added a commit that referenced this pull request Aug 27, 2015
- Fix the XDG directory flag that got removed with JarSplice. To enable XDG directories, set the 'Use-XDG' property in either build file to 'true'.
- Always re-build jars in the Gradle script (disable "up to date" for the task).
- Delete JarSplicePlus.jar since it's no longer being used.

Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants