org.bytedeco.gradle.javacpp.BuildPlugin Maven / Gradle / Ivy
Show all versions of gradle-javacpp Show documentation
/*
* Copyright (C) 2020-2022 Samuel Audet
*
* Licensed either under the Apache License, Version 2.0, or (at your option)
* under the terms of the GNU General Public License as published by
* the Free Software Foundation (subject to the "Classpath" exception),
* either version 2, or any later version (collectively, 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
* http://www.gnu.org/licenses/
* http://www.gnu.org/software/classpath/license.html
*
* or as provided in the LICENSE.txt file that accompanied this code.
* 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 org.bytedeco.gradle.javacpp;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Properties;
import java.util.Set;
import org.bytedeco.javacpp.Loader;
import org.gradle.api.Action;
import org.gradle.api.Project;
import org.gradle.api.Plugin;
import org.gradle.api.Task;
import org.gradle.api.file.FileTreeElement;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.provider.Property;
import org.gradle.api.specs.Spec;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.WriteProperties;
import org.gradle.api.tasks.bundling.Jar;
import org.gradle.api.tasks.compile.JavaCompile;
/**
* This plugin creates new packages containing native libraries using JavaCPP.
* It defines the following extra property:
*
* - "javacppPlatform", which defaults to {@link Loader#getPlatform()},
*
- "javacppPlatformExtension", which defaults to an empty string,
*
*
* creates the following extension:
*
* - "javacppBuild", an instance of {@link BuildExtension},
*
*
* as well as the following configuration:
*
* - "javacppPlatform", to be used to specify dependencies for the "-platform" artifact,
*
*
* and registers the following tasks:
*
* - "javacppBuildCommand" to execute {@link BuildTask#buildCommand},
*
- "javacppCompileJava" to compile classes needed by the parser,
*
- "javacppBuildParser" to run the parser on these classes,
*
- "javacppBuildCompiler" to generate and compile JNI code,
*
- "javacppPomProperties" to write version information to pom.properties,
*
- "javacppJar" to archive the native libraries in a separate JAR file,
*
- "javacppPlatformJar", to create an empty JAR file for the main "-platform" artifact,
*
- "javacppPlatformJavadocJar", to create an empty JAR file for the "-platform" javadoc artifact, and
*
- "javacppPlatformSourcesJar", to create an empty JAR file for the "-platform" sources artifact,
*
*
* @author Samuel Audet
*/
public class BuildPlugin implements Plugin {
Project project;
String getPlatform() {
return (String)project.findProperty("javacppPlatform");
}
String getPlatformExtension() {
return (String)project.findProperty("javacppPlatformExtension");
}
boolean isLibraryPath(String path) {
String p = (String)project.findProperty("javacpp.platform.library.path");
return p != null && p.length() > 0 ? path.startsWith(p) : path.contains("/" + getPlatform() + getPlatformExtension() + "/");
}
private void setProperty(String originalMethod, String propertyField, Object target, T value) {
Method method = findMethod(target.getClass(), originalMethod, value.getClass());
if (method != null) {
try {
invoke(method, target, value);
} catch (Exception e) {
throw new RuntimeException("Cannot set property " + method.getName() + " in " + target.getClass(), e);
}
} else {
Method propertyGetter = findMethod(target.getClass(), propertyField);
if (propertyGetter == null) {
throw new RuntimeException("Cannot find property getter method " + propertyField + " in " + target.getClass());
}
((Property) invoke(propertyGetter, target)).set(value);
}
}
private T getProperty(String originalMethod, String propertyMethod, Object target) {
Method method = findMethod(target.getClass(), originalMethod);
if (method != null) {
return (T) invoke(method, target);
}
Method propertyGetter = findMethod(target.getClass(), propertyMethod);
if (propertyGetter == null) {
throw new RuntimeException("Cannot find property getter method " + propertyMethod + " in " + target.getClass());
}
return ((Property) invoke(propertyGetter, target)).get();
}
private Method findMethod(Class> cls, String methodName) {
for (Method method : cls.getMethods()) {
if (method.getName().equals(methodName)) {
return method;
}
}
return null;
}
private Method findMethod(Class> cls, String methodName, Class>... parameterTypes) {
try {
return cls.getMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e) {
return null;
}
}
private T invoke(Method method, Object target, Object... parameter) {
try {
return (T) method.invoke(target, parameter);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
@Override public void apply(final Project project) {
this.project = project;
if (!project.hasProperty("javacppPlatform")) {
project.getExtensions().getExtraProperties().set("javacppPlatform", Loader.Detector.getPlatform());
}
if (!project.hasProperty("javacppPlatformExtension")) {
project.getExtensions().getExtraProperties().set("javacppPlatformExtension", "");
}
if (project.getExtensions().findByName("javacppBuild") == null) {
project.getExtensions().create("javacppBuild", BuildExtension.class, this);
}
project.getPlugins().withType(JavaPlugin.class, new Action() { public void execute(JavaPlugin javaPlugin) {
final JavaPluginConvention jc = project.getConvention().getPlugin(JavaPluginConvention.class);
final SourceSet main = jc.getSourceSets().getByName("main");
final Set files = main.getOutput().getClassesDirs().getFiles();
final String[] paths = new String[files.size()];
int n = 0;
for (File file : files) {
try {
paths[n++] = file.getCanonicalPath();
} catch (IOException ex) {
paths[n++] = file.getAbsolutePath();
}
}
project.getTasks().register("javacppBuildCommand",
BuildTask.class, new Action() { public void execute(BuildTask task) {
task.classPath = paths;
task.properties = getPlatform();
if (getPlatformExtension() != null && getPlatformExtension().length() > 0) {
task.propertyKeysAndValues = new Properties();
task.propertyKeysAndValues.setProperty("platform.extension", getPlatformExtension());
}
task.classOrPackageNames = new String[0];
task.workingDirectory = project.getProjectDir();
}});
project.getTasks().register("javacppCompileJava",
JavaCompile.class, new Action() { public void execute(JavaCompile task) {
task.setSource(main.getJava());
task.setClasspath(main.getCompileClasspath());
setProperty(
"setDestinationDir", // Deprecated in 7.1, will be removed in Gradle 9.0
"getDestinationDirectory", // Since 6.1
task,
getProperty(
"getOutputDir", // Deprecated in 7.1, removed in Gradle 8.0
"getClassesDirectory", // Since 6.1
main.getJava()
)
);
task.dependsOn("javacppBuildCommand");
}});
project.getTasks().register("javacppBuildParser",
BuildTask.class, new Action() { public void execute(final BuildTask task) {
task.classPath = paths;
task.properties = getPlatform();
if (getPlatformExtension() != null && getPlatformExtension().length() > 0) {
task.propertyKeysAndValues = new Properties();
task.propertyKeysAndValues.setProperty("platform.extension", getPlatformExtension());
}
if (task.outputDirectory == null) {
task.outputDirectory = main.getJava().getSrcDirs().iterator().next();
}
task.dependsOn("javacppCompileJava");
task.doFirst(new Action() { public void execute(Task t) { main.getJava().srcDir(task.outputDirectory); }});
}});
project.getTasks().getByName("compileJava").dependsOn("javacppBuildParser");
project.getTasks().register("javacppBuildCompiler",
BuildTask.class, new Action() { public void execute(BuildTask task) {
task.classPath = paths;
task.properties = getPlatform();
if (getPlatformExtension() != null && getPlatformExtension().length() > 0) {
task.propertyKeysAndValues = new Properties();
task.propertyKeysAndValues.setProperty("platform.extension", getPlatformExtension());
}
task.dependsOn("compileJava");
}});
project.getTasks().getByName("classes").dependsOn("javacppBuildCompiler");
project.getTasks().register("javacppPomProperties",
WriteProperties.class, new Action() { public void execute(WriteProperties task) {
Object group = project.findProperty("group");
Object name = project.findProperty("name");
Object version = project.findProperty("version");
task.property("groupId", group);
task.property("artifactId", name);
task.property("version", version);
task.setOutputFile(new File(main.getOutput().getResourcesDir(), "META-INF/maven/" + group + "/" + name + "/pom.properties"));
}});
Jar jarTask = (Jar)project.getTasks().getByName("jar");
jarTask.dependsOn("javacppPomProperties");
jarTask.exclude(new Spec() { public boolean isSatisfiedBy(FileTreeElement file) {
return isLibraryPath(file.getPath());
}});
TaskProvider javacppJarTask = project.getTasks().register("javacppJar",
Jar.class, new Action() { public void execute(Jar task) {
task.from(main.getOutput());
setProperty(
"setClassifier", // Deprecated in 7.0, removed in 8.0
"getArchiveClassifier", // Since 5.1
task,
getPlatform() + getPlatformExtension());
task.include(new Spec() { public boolean isSatisfiedBy(FileTreeElement file) {
return file.isDirectory() || isLibraryPath(file.getPath());
}});
task.dependsOn("jar");
}});
project.getArtifacts().add("archives", javacppJarTask);
TaskProvider javacppPlatformJarTask = project.getTasks().register("javacppPlatformJar",
Jar.class, new Action() { public void execute(Jar task) {
setProperty(
"setBaseName", // Deprecated in 7.0, removed in 8.0
"getArchiveBaseName", // Since 5.1
task,
project.getName() + "-platform");
task.dependsOn("javacppJar");
}});
TaskProvider javacppPlatformJavadocJarTask = project.getTasks().register("javacppPlatformJavadocJar",
Jar.class, new Action() { public void execute(Jar task) {
setProperty(
"setBaseName", // Deprecated in 7.0, removed in 8.0
"getArchiveBaseName", // Since 5.1
task,
project.getName() + "-platform");
setProperty(
"setClassifier", // Deprecated in 7.0, removed in 8.0
"getArchiveClassifier", // Since 5.1
task,
"javadoc");
task.dependsOn("javacppPlatformJar");
}});
TaskProvider javacppPlatformSourcesTask = project.getTasks().register("javacppPlatformSourcesJar",
Jar.class, new Action() { public void execute(Jar task) {
setProperty(
"setBaseName", // Deprecated in 7.0, removed in 8.0
"getArchiveBaseName", // Since 5.1
task,
project.getName() + "-platform");
setProperty("setClassifier", "getArchiveClassifier", task, "sources");
task.dependsOn("javacppPlatformJar");
}});
project.getConfigurations().maybeCreate("javacppPlatform");
project.getArtifacts().add("javacppPlatform", javacppPlatformJarTask);
project.getArtifacts().add("javacppPlatform", javacppPlatformJavadocJarTask);
project.getArtifacts().add("javacppPlatform", javacppPlatformSourcesTask);
}});
}
}