fix: cleaner gdx stuff bundling
This commit is contained in:
parent
067b2e537d
commit
2e26856016
3 changed files with 10 additions and 390 deletions
13
build.gradle
13
build.gradle
|
@ -81,10 +81,17 @@ jar {
|
|||
|
||||
shadowJar {
|
||||
archiveFileName = simpleFileName
|
||||
relocate('com.badlogicgames.gdx', 'b') { //needed for luajava
|
||||
include 'com.badlogicgames.gdx.utils.SharedLibraryLoad*'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
include(dependency {
|
||||
it.moduleGroup == 'party.iroiro.luajava'
|
||||
})
|
||||
include(
|
||||
dependency {
|
||||
it.moduleGroup == 'party.iroiro.luajava'
|
||||
|| it.moduleGroup == 'com.badlogicgames.gdx'
|
||||
}
|
||||
)
|
||||
}
|
||||
manifest {
|
||||
attributes([
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2011 See AUTHORS file.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
package com.badlogic.gdx.utils;
|
||||
|
||||
public class SharedLibraryLoadRuntimeException extends RuntimeException {
|
||||
private static final long serialVersionUID = 8263101105331379889L;
|
||||
|
||||
public SharedLibraryLoadRuntimeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SharedLibraryLoadRuntimeException(Throwable t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
public SharedLibraryLoadRuntimeException(String message, Throwable t) {
|
||||
super(message, t);
|
||||
}
|
||||
}
|
|
@ -1,355 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2011 See AUTHORS file.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
|
||||
package com.badlogic.gdx.utils;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
/** Loads shared libraries from a natives jar file (desktop) or arm folders (Android). For desktop projects, have the natives jar
|
||||
* in the classpath, for Android projects put the shared libraries in the libs/armeabi and libs/armeabi-v7a folders.
|
||||
* @author mzechner
|
||||
* @author Nathan Sweet */
|
||||
public class SharedLibraryLoader {
|
||||
static public boolean isWindows = System.getProperty("os.name").contains("Windows");
|
||||
static public boolean isLinux = System.getProperty("os.name").contains("Linux");
|
||||
static public boolean isMac = System.getProperty("os.name").contains("Mac");
|
||||
static public boolean isIos = false;
|
||||
static public boolean isAndroid = false;
|
||||
static public boolean isARM = System.getProperty("os.arch").startsWith("arm") || System.getProperty("os.arch").startsWith("aarch64");
|
||||
static public boolean is64Bit = System.getProperty("os.arch").contains("64") || System.getProperty("os.arch").startsWith("armv8");
|
||||
|
||||
static {
|
||||
boolean isMOEiOS = System.getProperty("moe.platform.name") != null;
|
||||
String vm = System.getProperty("java.runtime.name");
|
||||
if (vm != null && vm.contains("Android Runtime")) {
|
||||
isAndroid = true;
|
||||
isWindows = false;
|
||||
isLinux = false;
|
||||
isMac = false;
|
||||
is64Bit = false;
|
||||
}
|
||||
if (isMOEiOS || (!isAndroid && !isWindows && !isLinux && !isMac)) {
|
||||
isIos = true;
|
||||
isAndroid = false;
|
||||
isWindows = false;
|
||||
isLinux = false;
|
||||
isMac = false;
|
||||
is64Bit = false;
|
||||
}
|
||||
}
|
||||
|
||||
static private final HashSet<String> loadedLibraries = new HashSet<>();
|
||||
static private final Random random = new Random();
|
||||
|
||||
private String nativesJar;
|
||||
|
||||
public SharedLibraryLoader () {
|
||||
}
|
||||
|
||||
static String randomUUID () {
|
||||
return new UUID(random.nextLong(), random.nextLong()).toString();
|
||||
}
|
||||
|
||||
/** Fetches the natives from the given natives jar file. Used for testing a shared lib on the fly.
|
||||
* @param nativesJar */
|
||||
public SharedLibraryLoader (String nativesJar) {
|
||||
this.nativesJar = nativesJar;
|
||||
}
|
||||
|
||||
/** Returns a CRC of the remaining bytes in the stream. */
|
||||
public String crc (InputStream input) {
|
||||
if (input == null) throw new IllegalArgumentException("input cannot be null.");
|
||||
CRC32 crc = new CRC32();
|
||||
byte[] buffer = new byte[4096];
|
||||
try {
|
||||
while (true) {
|
||||
int length = input.read(buffer);
|
||||
if (length == -1) break;
|
||||
crc.update(buffer, 0, length);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
} finally {
|
||||
closeQuietly(input);
|
||||
}
|
||||
return Long.toString(crc.getValue(), 16);
|
||||
}
|
||||
|
||||
/** Maps a platform independent library name to a platform dependent name. */
|
||||
public String mapLibraryName (String libraryName) {
|
||||
if (isWindows) return libraryName + (is64Bit ? "64.dll" : ".dll");
|
||||
if (isLinux) return "lib" + libraryName + (isARM ? "arm" : "") + (is64Bit ? "64.so" : ".so");
|
||||
if (isMac) return "lib" + libraryName + (isARM ? "arm" : "") + (is64Bit ? "64.dylib" : ".dylib");
|
||||
return libraryName;
|
||||
}
|
||||
|
||||
/** Loads a shared library for the platform the application is running on.
|
||||
* @param libraryName The platform independent library name. If not contain a prefix (eg lib) or suffix (eg .dll). */
|
||||
public void load (String libraryName) {
|
||||
// in case of iOS, things have been linked statically to the executable, bail out.
|
||||
if (isIos) return;
|
||||
|
||||
synchronized (SharedLibraryLoader.class) {
|
||||
if (isLoaded(libraryName)) return;
|
||||
String platformName = mapLibraryName(libraryName);
|
||||
try {
|
||||
if (isAndroid)
|
||||
System.loadLibrary(platformName);
|
||||
else
|
||||
loadFile(platformName);
|
||||
setLoaded(libraryName);
|
||||
} catch (Throwable ex) {
|
||||
throw new SharedLibraryLoadRuntimeException("Couldn't load shared library '" + platformName + "' for target: "
|
||||
+ (isAndroid ? "Android" : (System.getProperty("os.name") + (isARM ? ", ARM" : "") + (is64Bit ? ", 64-bit" : ", 32-bit"))),
|
||||
ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private InputStream readFile (String path) {
|
||||
if (nativesJar == null) {
|
||||
InputStream input = SharedLibraryLoader.class.getResourceAsStream("/" + path);
|
||||
if (input == null) throw new SharedLibraryLoadRuntimeException("Unable to read file for extraction: " + path);
|
||||
return input;
|
||||
}
|
||||
|
||||
// Read from JAR.
|
||||
try {
|
||||
ZipFile file = new ZipFile(nativesJar);
|
||||
ZipEntry entry = file.getEntry(path);
|
||||
if (entry == null) throw new SharedLibraryLoadRuntimeException("Couldn't find '" + path + "' in JAR: " + nativesJar);
|
||||
return file.getInputStream(entry);
|
||||
} catch (IOException ex) {
|
||||
throw new SharedLibraryLoadRuntimeException("Error reading '" + path + "' in JAR: " + nativesJar, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/** Extracts the specified file to the specified directory if it does not already exist or the CRC does not match. If file
|
||||
* extraction fails and the file exists at java.library.path, that file is returned.
|
||||
* @param sourcePath The file to extract from the classpath or JAR.
|
||||
* @param dirName The name of the subdirectory where the file will be extracted. If null, the file's CRC will be used.
|
||||
* @return The extracted file. */
|
||||
public File extractFile (String sourcePath, String dirName) throws IOException {
|
||||
try {
|
||||
String sourceCrc = crc(readFile(sourcePath));
|
||||
if (dirName == null) dirName = sourceCrc;
|
||||
|
||||
File extractedFile = getExtractedFile(dirName, new File(sourcePath).getName());
|
||||
if (extractedFile == null) {
|
||||
extractedFile = getExtractedFile(randomUUID(), new File(sourcePath).getName());
|
||||
if (extractedFile == null) throw new SharedLibraryLoadRuntimeException(
|
||||
"Unable to find writable path to extract file. Is the user home directory writable?");
|
||||
}
|
||||
return extractFile(sourcePath, sourceCrc, extractedFile);
|
||||
} catch (RuntimeException ex) {
|
||||
// Fallback to file at java.library.path location, eg for applets.
|
||||
File file = new File(System.getProperty("java.library.path"), sourcePath);
|
||||
if (file.exists()) return file;
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
/** Extracts the specified file into the temp directory if it does not already exist or the CRC does not match. If file
|
||||
* extraction fails and the file exists at java.library.path, that file is returned.
|
||||
* @param sourcePath The file to extract from the classpath or JAR.
|
||||
* @param dir The location where the extracted file will be written. */
|
||||
public void extractFileTo (String sourcePath, File dir) throws IOException {
|
||||
extractFile(sourcePath, crc(readFile(sourcePath)), new File(dir, new File(sourcePath).getName()));
|
||||
}
|
||||
|
||||
/** Returns a path to a file that can be written. Tries multiple locations and verifies writing succeeds.
|
||||
* @return null if a writable path could not be found. */
|
||||
private File getExtractedFile (String dirName, String fileName) {
|
||||
// Temp directory with username in path.
|
||||
File idealFile = new File(
|
||||
System.getProperty("java.io.tmpdir") + "/libgdx" + System.getProperty("user.name") + "/" + dirName, fileName);
|
||||
if (canWrite(idealFile)) return idealFile;
|
||||
|
||||
// System provided temp directory.
|
||||
try {
|
||||
File file = File.createTempFile(dirName, null);
|
||||
if (file.delete()) {
|
||||
file = new File(file, fileName);
|
||||
if (canWrite(file)) return file;
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
|
||||
// User home.
|
||||
File file = new File(System.getProperty("user.home") + "/.libgdx/" + dirName, fileName);
|
||||
if (canWrite(file)) return file;
|
||||
|
||||
// Relative directory.
|
||||
file = new File(".temp/" + dirName, fileName);
|
||||
if (canWrite(file)) return file;
|
||||
|
||||
// We are running in the OS X sandbox.
|
||||
if (System.getenv("APP_SANDBOX_CONTAINER_ID") != null) return idealFile;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Returns true if the parent directories of the file can be created and the file can be written. */
|
||||
private boolean canWrite (File file) {
|
||||
File parent = file.getParentFile();
|
||||
File testFile;
|
||||
if (file.exists()) {
|
||||
if (!file.canWrite() || !canExecute(file)) return false;
|
||||
// Don't overwrite existing file just to check if we can write to directory.
|
||||
testFile = new File(parent, randomUUID().toString());
|
||||
} else {
|
||||
parent.mkdirs();
|
||||
if (!parent.isDirectory()) return false;
|
||||
testFile = file;
|
||||
}
|
||||
try {
|
||||
new FileOutputStream(testFile).close();
|
||||
if (!canExecute(testFile)) return false;
|
||||
return true;
|
||||
} catch (Throwable ex) {
|
||||
return false;
|
||||
} finally {
|
||||
testFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canExecute (File file) {
|
||||
try {
|
||||
Method canExecute = File.class.getMethod("canExecute");
|
||||
if ((Boolean)canExecute.invoke(file)) return true;
|
||||
|
||||
Method setExecutable = File.class.getMethod("setExecutable", boolean.class, boolean.class);
|
||||
setExecutable.invoke(file, true, false);
|
||||
|
||||
return (Boolean)canExecute.invoke(file);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private File extractFile (String sourcePath, String sourceCrc, File extractedFile) throws IOException {
|
||||
String extractedCrc = null;
|
||||
if (extractedFile.exists()) {
|
||||
try {
|
||||
extractedCrc = crc(new FileInputStream(extractedFile));
|
||||
} catch (FileNotFoundException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
// If file doesn't exist or the CRC doesn't match, extract it to the temp dir.
|
||||
if (extractedCrc == null || !extractedCrc.equals(sourceCrc)) {
|
||||
InputStream input = null;
|
||||
FileOutputStream output = null;
|
||||
try {
|
||||
input = readFile(sourcePath);
|
||||
extractedFile.getParentFile().mkdirs();
|
||||
output = new FileOutputStream(extractedFile);
|
||||
byte[] buffer = new byte[4096];
|
||||
while (true) {
|
||||
int length = input.read(buffer);
|
||||
if (length == -1) break;
|
||||
output.write(buffer, 0, length);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new SharedLibraryLoadRuntimeException("Error extracting file: " + sourcePath + "\nTo: " + extractedFile.getAbsolutePath(),
|
||||
ex);
|
||||
} finally {
|
||||
closeQuietly(input);
|
||||
closeQuietly(output);
|
||||
}
|
||||
}
|
||||
|
||||
return extractedFile;
|
||||
}
|
||||
|
||||
/** Extracts the source file and calls System.load. Attemps to extract and load from multiple locations. Throws runtime
|
||||
* exception if all fail. */
|
||||
private void loadFile (String sourcePath) {
|
||||
String sourceCrc = crc(readFile(sourcePath));
|
||||
|
||||
String fileName = new File(sourcePath).getName();
|
||||
|
||||
// Temp directory with username in path.
|
||||
File file = new File(System.getProperty("java.io.tmpdir") + "/libgdx" + System.getProperty("user.name") + "/" + sourceCrc,
|
||||
fileName);
|
||||
Throwable ex = loadFile(sourcePath, sourceCrc, file);
|
||||
if (ex == null) return;
|
||||
|
||||
// System provided temp directory.
|
||||
try {
|
||||
file = File.createTempFile(sourceCrc, null);
|
||||
if (file.delete() && loadFile(sourcePath, sourceCrc, file) == null) return;
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
// User home.
|
||||
file = new File(System.getProperty("user.home") + "/.libgdx/" + sourceCrc, fileName);
|
||||
if (loadFile(sourcePath, sourceCrc, file) == null) return;
|
||||
|
||||
// Relative directory.
|
||||
file = new File(".temp/" + sourceCrc, fileName);
|
||||
if (loadFile(sourcePath, sourceCrc, file) == null) return;
|
||||
|
||||
// Fallback to java.library.path location, eg for applets.
|
||||
file = new File(System.getProperty("java.library.path"), sourcePath);
|
||||
if (file.exists()) {
|
||||
System.load(file.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
|
||||
throw new SharedLibraryLoadRuntimeException(ex);
|
||||
}
|
||||
|
||||
/** @return null if the file was extracted and loaded. */
|
||||
private Throwable loadFile (String sourcePath, String sourceCrc, File extractedFile) {
|
||||
try {
|
||||
System.load(extractFile(sourcePath, sourceCrc, extractedFile).getAbsolutePath());
|
||||
return null;
|
||||
} catch (Throwable ex) {
|
||||
return ex;
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets the library as loaded, for when application code wants to handle libary loading itself. */
|
||||
static public synchronized void setLoaded (String libraryName) {
|
||||
loadedLibraries.add(libraryName);
|
||||
}
|
||||
|
||||
static public synchronized boolean isLoaded (String libraryName) {
|
||||
return loadedLibraries.contains(libraryName);
|
||||
}
|
||||
|
||||
public static void closeQuietly (Closeable c) {
|
||||
if (c != null) {
|
||||
try {
|
||||
c.close();
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue