From 7ea6ca3d651cb11234c9b2f062a2435c2e7fe05e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Prante?= Date: Tue, 9 Jan 2024 22:30:26 +0100 Subject: [PATCH] add cmake plugin --- gradle-plugin-cmake/build.gradle | 30 +++ gradle-plugin-cmake/gradle.properties | 2 + .../gradle/plugin/cmake/CMakeBuildTask.java | 100 +++++++++ .../plugin/cmake/CMakeConfigureTask.java | 191 ++++++++++++++++++ .../gradle/plugin/cmake/CMakeExecutor.java | 83 ++++++++ .../xbib/gradle/plugin/cmake/CMakePlugin.java | 141 +++++++++++++ .../plugin/cmake/CMakePluginExtension.java | 121 +++++++++++ .../gradle/plugin/cmake/TargetExtension.java | 174 ++++++++++++++++ .../plugin/cmake/TargetListExtension.java | 31 +++ settings.gradle | 7 +- 10 files changed, 877 insertions(+), 3 deletions(-) create mode 100644 gradle-plugin-cmake/build.gradle create mode 100644 gradle-plugin-cmake/gradle.properties create mode 100644 gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakeBuildTask.java create mode 100644 gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakeConfigureTask.java create mode 100644 gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakeExecutor.java create mode 100644 gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakePlugin.java create mode 100644 gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakePluginExtension.java create mode 100644 gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/TargetExtension.java create mode 100644 gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/TargetListExtension.java diff --git a/gradle-plugin-cmake/build.gradle b/gradle-plugin-cmake/build.gradle new file mode 100644 index 0000000..002fb90 --- /dev/null +++ b/gradle-plugin-cmake/build.gradle @@ -0,0 +1,30 @@ +plugins { + alias(libs.plugins.publish) +} + +apply plugin: 'com.gradle.plugin-publish' + +apply from: rootProject.file('gradle/compile/java.gradle') +apply from: rootProject.file('gradle/test/junit5.gradle') + +dependencies { + api gradleApi() + testImplementation gradleTestKit() +} + +if (project.hasProperty('gradle.publish.key')) { + gradlePlugin { + website = 'https://xbib.org/joerg/gradle-plugins/src/branch/main/gradle-plugin-cmake' + vcsUrl = 'https://xbib.org/joerg/gradle-plugins' + plugins { + cmakePlugin { + id = 'org.xbib.gradle.plugin.cmake' + implementationClass = 'org.xbib.gradle.plugin.cmake.CMakePlugin' + version = project.version + description = 'Gradle plugin for build with cmake' + displayName = 'Gradle Plugin for build with cmake' + tags.set(['cmake']) + } + } + } +} diff --git a/gradle-plugin-cmake/gradle.properties b/gradle-plugin-cmake/gradle.properties new file mode 100644 index 0000000..f0c5e72 --- /dev/null +++ b/gradle-plugin-cmake/gradle.properties @@ -0,0 +1,2 @@ +name = gradle-plugin-docker +version = 3.1.0 diff --git a/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakeBuildTask.java b/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakeBuildTask.java new file mode 100644 index 0000000..e70e24e --- /dev/null +++ b/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakeBuildTask.java @@ -0,0 +1,100 @@ +package org.xbib.gradle.plugin.cmake; + +import java.util.ArrayList; +import java.util.List; +import org.gradle.api.DefaultTask; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputDirectory; +import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.TaskAction; + +/** + * Build a configured Build with CMake + */ +public class CMakeBuildTask extends DefaultTask { + + private final Property executable; + + private final DirectoryProperty workingFolder; + + private final Property buildConfig; + + private final Property buildTarget; + + private final Property buildClean; + + public CMakeBuildTask() { + setGroup("cmake"); + setDescription("Build a configured Build with CMake"); + executable = getProject().getObjects().property(String.class); + workingFolder = getProject().getObjects().directoryProperty(); + buildConfig = getProject().getObjects().property(String.class); + buildTarget = getProject().getObjects().property(String.class); + buildClean = getProject().getObjects().property(Boolean.class); + } + + public void configureFromProject() { + CMakePluginExtension ext = (CMakePluginExtension) getProject().getExtensions().getByName("cmake"); + executable.set(ext.getExecutable()); + workingFolder.set(ext.getWorkingFolder()); + buildConfig.set(ext.getBuildConfig()); + buildTarget.set(ext.getBuildTarget()); + buildClean.set(ext.getBuildClean()); + } + + @Input + @Optional + public Property getExecutable() { + return executable; + } + + @InputDirectory + public DirectoryProperty getWorkingFolder() { + return workingFolder; + } + + @Input + @Optional + public Property getBuildConfig() { + return buildConfig; + } + + @Input + @Optional + public Property getBuildTarget() { + return buildTarget; + } + + @Input + @Optional + public Property getBuildClean() { + return buildClean; + } + + private List buildCmdLine() { + List parameters = new ArrayList<>(); + parameters.add(executable.getOrElse("cmake")); + parameters.add("--build"); + parameters.add("."); + if (buildConfig.isPresent()) { + parameters.add("--config"); + parameters.add(buildConfig.get()); + } + if (buildTarget.isPresent()) { + parameters.add("--target"); + parameters.add(buildTarget.get()); + } + if (buildClean.getOrElse(Boolean.FALSE)) { + parameters.add("--clean-first"); + } + return parameters; + } + + @TaskAction + public void build() { + CMakeExecutor executor = new CMakeExecutor(getLogger(), getName()); + executor.exec(buildCmdLine(), workingFolder.getAsFile().get()); + } +} diff --git a/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakeConfigureTask.java b/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakeConfigureTask.java new file mode 100644 index 0000000..6cd3fc0 --- /dev/null +++ b/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakeConfigureTask.java @@ -0,0 +1,191 @@ +package org.xbib.gradle.plugin.cmake; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.gradle.api.DefaultTask; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.provider.MapProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputDirectory; +import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.OutputDirectory; +import org.gradle.api.tasks.TaskAction; + +public class CMakeConfigureTask extends DefaultTask { + + private final Property executable; + + private final DirectoryProperty workingFolder; + + private final DirectoryProperty sourceFolder; + + private final Property configurationTypes; + + private final Property installPrefix; + + private final Property generator; // for example: "Visual Studio 16 2019" + + private final Property platform; // for example "x64" or "Win32" or "ARM" or "ARM64", supported on vs > 8.0 + + private final Property toolset; // for example "v142", supported on vs > 10.0 + + private final Property buildSharedLibs; + + private final Property buildStaticLibs; + + private final MapProperty def; + + public CMakeConfigureTask() { + setGroup("cmake"); + setDescription("Configure a Build with CMake"); + executable = getProject().getObjects().property(String.class); + workingFolder = getProject().getObjects().directoryProperty(); + sourceFolder = getProject().getObjects().directoryProperty(); + configurationTypes = getProject().getObjects().property(String.class); + installPrefix = getProject().getObjects().property(String.class); + generator = getProject().getObjects().property(String.class); + platform = getProject().getObjects().property(String.class); + toolset = getProject().getObjects().property(String.class); + buildSharedLibs = getProject().getObjects().property(Boolean.class); + buildStaticLibs = getProject().getObjects().property(Boolean.class); + def = getProject().getObjects().mapProperty(String.class, String.class); + // default values + workingFolder.set(new File(getProject().getLayout().getBuildDirectory().get().getAsFile(), "cmake")); + sourceFolder.set(new File(getProject().getLayout().getBuildDirectory().get().getAsFile(), "src" + File.separator + "main" + File.separator + "cpp")); + } + + public void configureFromProject() { + CMakePluginExtension ext = (CMakePluginExtension) getProject().getExtensions().getByName("cmake"); + executable.set(ext.getExecutable()); + workingFolder.set(ext.getWorkingFolder()); + sourceFolder.set(ext.getSourceFolder()); + configurationTypes.set(ext.getConfigurationTypes()); + installPrefix.set(ext.getInstallPrefix()); + generator.set(ext.getGenerator()); + platform.set(ext.getPlatform()); + toolset.set(ext.getToolset()); + buildSharedLibs.set(ext.getBuildSharedLibs()); + buildStaticLibs.set(ext.getBuildStaticLibs()); + def.set(ext.getDefs()); + } + + /// region getters + @Input + @Optional + public Property getExecutable() { + return executable; + } + + @OutputDirectory + public DirectoryProperty getWorkingFolder() { + return workingFolder; + } + + @InputDirectory + public DirectoryProperty getSourceFolder() { + return sourceFolder; + } + + @Input + @Optional + public Property getConfigurationTypes() { + return configurationTypes; + } + + @Input + @Optional + public Property getInstallPrefix() { + return installPrefix; + } + + @Input + @Optional + public Property getGenerator() { + return generator; + } + + @Input + @Optional + public Property getPlatform() { + return platform; + } + + @Input + @Optional + public Property getToolset() { + return toolset; + } + + @Input + @Optional + public Property getBuildSharedLibs() { + return buildSharedLibs; + } + + @Input + @Optional + public Property getBuildStaticLibs() { + return buildStaticLibs; + } + + @Input + @Optional + public MapProperty getDef() { + return def; + } + /// endregion + + private List buildCmdLine() { + List parameters = new ArrayList<>(); + + parameters.add(executable.getOrElse("cmake")); + + if (generator.isPresent() && !generator.get().isEmpty()) { + parameters.add("-G"); + parameters.add(generator.get()); + } + + if (platform.isPresent() && !platform.get().isEmpty()) { + parameters.add("-A"); + parameters.add(platform.get()); + } + + if (toolset.isPresent() && !toolset.get().isEmpty()) { + parameters.add("-T"); + parameters.add(toolset.get()); + } + + if (configurationTypes.isPresent() && !configurationTypes.get().isEmpty()) + parameters.add("-DCMAKE_CONFIGURATION_TYPES=" + configurationTypes.get()); + + if (installPrefix.isPresent() && !installPrefix.get().isEmpty()) + parameters.add("-DCMAKE_INSTALL_PREFIX=" + installPrefix.get()); + + + if (buildSharedLibs.isPresent()) + parameters.add("-DBUILD_SHARED_LIBS=" + (buildSharedLibs.get() ? "ON" : "OFF")); + + if (buildStaticLibs.isPresent()) + parameters.add("-DBUILD_STATIC_LIBS=" + (buildStaticLibs.get() ? "ON" : "OFF")); + + + if (def.isPresent()) { + for (Map.Entry entry : def.get().entrySet()) + parameters.add("-D" + entry.getKey() + "=" + entry.getValue()); + } + + parameters.add(sourceFolder.getAsFile().get().getAbsolutePath()); + + return parameters; + } + + @TaskAction + public void configure() { + CMakeExecutor executor = new CMakeExecutor(getLogger(), getName()); + executor.exec(buildCmdLine(), workingFolder.getAsFile().get()); + } + +} diff --git a/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakeExecutor.java b/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakeExecutor.java new file mode 100644 index 0000000..9fe582d --- /dev/null +++ b/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakeExecutor.java @@ -0,0 +1,83 @@ +package org.xbib.gradle.plugin.cmake; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.stream.Stream; +import org.gradle.api.GradleException; +import org.gradle.api.GradleScriptException; +import org.gradle.api.logging.Logger; + +public class CMakeExecutor { + + private final Logger logger; + private final String taskName; + + CMakeExecutor(final Logger logger, final String taskName) { + this.logger = logger; + this.taskName = taskName; + } + + protected void exec(final List cmdLine, final File workingFolder) throws GradleException { + // log command line parameters + StringBuilder sb = new StringBuilder(" CMakePlugin.task " + taskName + " - exec: "); + for (String s : cmdLine) { + sb.append(s).append(" "); + } + logger.info(sb.toString()); + ProcessBuilder pb = new ProcessBuilder(cmdLine); + pb.directory(workingFolder); + try (ExecutorService executor = Executors.newFixedThreadPool(2)) { + // make sure working folder exists + boolean b = workingFolder.mkdirs(); + // start + Process process = pb.start(); + Future stdoutFuture = executor.submit(() -> { + readStream(process.getInputStream(), true); + return null; + }); + Future stderrFuture = executor.submit(() -> { + readStream(process.getErrorStream(), false); + return null; + }); + int retCode = process.waitFor(); + warnIfTimeout(stdoutFuture, + "CMakeExecutor[" + taskName + "]Warn: timed out waiting for stdout to be closed."); + warnIfTimeout(stderrFuture, + "CMakeExecutor[" + taskName + "]Warn: timed out waiting for stderr to be closed."); + if (retCode != 0) { + throw new GradleException("[" + taskName + "]Error: CMAKE returned " + retCode); + } + } catch (IOException | InterruptedException | ExecutionException e) { + throw new GradleScriptException("CMakeExecutor[" + taskName + "].", e); + } + } + + private void readStream(final InputStream inputStream, boolean isStdOut) { + final Stream lines = new BufferedReader(new InputStreamReader(inputStream)).lines(); + if (isStdOut) { + lines.forEach(logger::info); + } else { + lines.forEach(logger::error); + } + } + + private void warnIfTimeout(final Future future, final String message) + throws ExecutionException, InterruptedException { + try { + future.get(3, TimeUnit.SECONDS); + } catch (TimeoutException e) { + logger.warn(message); + } + } +} + diff --git a/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakePlugin.java b/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakePlugin.java new file mode 100644 index 0000000..4e36adc --- /dev/null +++ b/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakePlugin.java @@ -0,0 +1,141 @@ +package org.xbib.gradle.plugin.cmake; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import org.gradle.api.GradleException; +import org.gradle.api.GradleScriptException; +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.logging.LogLevel; +import org.gradle.api.tasks.TaskContainer; + +public class CMakePlugin implements Plugin { + + private static final String CMAKE_CONFIGURE = "cmakeConfigure"; + + private static final String CMAKE_BUILD = "cmakeBuild"; + + private boolean deleteDirectory(File directoryToBeDeleted) { + File[] allContents = directoryToBeDeleted.listFiles(); + if (allContents != null) { + for (File file : allContents) { + deleteDirectory(file); + } + } + return directoryToBeDeleted.delete(); + } + + @Override + public void apply(Project project) { + project.getPlugins().apply("base"); + final CMakePluginExtension extension = project.getExtensions() + .create("cmake", CMakePluginExtension.class, project); + final Task cmakeClean = project.task("cmakeClean").doFirst(task -> { + File workingFolder = extension.getWorkingFolder().getAsFile().get().getAbsoluteFile(); + if (workingFolder.exists()) { + project.getLogger().info("Deleting folder " + workingFolder); + if (!deleteDirectory(workingFolder)) { + throw new GradleException("Could not delete working folder " + workingFolder); + } + } + }); + cmakeClean.setGroup("cmake"); + cmakeClean.setDescription("Clean CMake configuration"); + final Task cmakeGenerators = project.task("cmakeGenerators").doFirst(task -> { + ProcessBuilder pb = new ProcessBuilder(extension.getExecutable().getOrElse("cmake"), + "--help"); + try { + // start + Process process = pb.start(); + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + boolean foundGenerators = false; + while ((line = reader.readLine()) != null) { + if (line.equals("Generators")) { + foundGenerators = true; + } + if (foundGenerators) { + project.getLogger().log(LogLevel.QUIET, line); + } + } + process.waitFor(); + } catch (IOException | InterruptedException e) { + throw new GradleScriptException("cmake --help failed.", e); + } + }); + cmakeGenerators.setGroup("cmake"); + cmakeGenerators.setDescription("List available CMake generators"); + project.afterEvaluate(p -> { + final TaskContainer tasks = project.getTasks(); + if (extension.getTargets().getTargetContainer().isEmpty()) { + p.getTasks().register(CMAKE_CONFIGURE, CMakeConfigureTask.class, task -> { + task.getExecutable().set(extension.getExecutable()); + task.getWorkingFolder().set(extension.getWorkingFolder()); + task.getSourceFolder().set(extension.getSourceFolder()); + task.getConfigurationTypes().set(extension.getConfigurationTypes()); + task.getInstallPrefix().set(extension.getInstallPrefix()); + task.getGenerator().set(extension.getGenerator()); + task.getPlatform().set(extension.getPlatform()); + task.getToolset().set(extension.getToolset()); + task.getBuildSharedLibs().set(extension.getBuildSharedLibs()); + task.getBuildStaticLibs().set(extension.getBuildStaticLibs()); + task.getDef().set(extension.getDefs().isPresent() ? extension.getDefs() : extension.getDef()); + }); + + p.getTasks().register(CMAKE_BUILD, CMakeBuildTask.class, task -> { + task.getExecutable().set(extension.getExecutable()); + task.getWorkingFolder().set(extension.getWorkingFolder()); + task.getBuildConfig().set(extension.getBuildConfig()); + task.getBuildTarget().set(extension.getBuildTarget()); + task.getBuildClean().set(extension.getBuildClean()); + }); + } else { + extension.getTargets().getTargetContainer().getAsMap() + .forEach((name, target) -> { + tasks.register(CMAKE_CONFIGURE + name, CMakeConfigureTask.class, task -> { + task.configureFromProject(); + if (target.getExecutable().isPresent()) + task.getExecutable().set(target.getExecutable()); + if (target.getWorkingFolder().isPresent()) + task.getWorkingFolder().set(target.getWorkingFolder()); + if (target.getSourceFolder().isPresent()) + task.getSourceFolder().set(target.getSourceFolder()); + if (target.getConfigurationTypes().isPresent()) + task.getConfigurationTypes().set(target.getConfigurationTypes()); + if (target.getInstallPrefix().isPresent()) + task.getInstallPrefix().set(target.getInstallPrefix()); + if (target.getGenerator().isPresent()) task.getGenerator().set(target.getGenerator()); + if (target.getPlatform().isPresent()) task.getPlatform().set(target.getPlatform()); + if (target.getToolset().isPresent()) task.getToolset().set(target.getToolset()); + if (target.getBuildSharedLibs().isPresent()) + task.getBuildSharedLibs().set(target.getBuildSharedLibs()); + if (target.getBuildStaticLibs().isPresent()) + task.getBuildStaticLibs().set(target.getBuildStaticLibs()); + if (target.getDefs().isPresent()) task.getDef().set(target.getDefs()); + }); + tasks.register(CMAKE_BUILD + name, CMakeBuildTask.class, task -> { + task.configureFromProject(); + if (target.getExecutable().isPresent()) + task.getExecutable().set(target.getExecutable()); + if (target.getWorkingFolder().isPresent()) + task.getWorkingFolder().set(target.getWorkingFolder()); + if (target.getBuildConfig().isPresent()) + task.getBuildConfig().set(target.getBuildConfig()); + if (target.getBuildTarget().isPresent()) + task.getBuildTarget().set(target.getBuildTarget()); + if (target.getBuildClean().isPresent()) + task.getBuildClean().set(target.getBuildClean()); + }); + }); + } + tasks.withType(CMakeBuildTask.class) + .forEach(task -> task.dependsOn(tasks.withType(CMakeConfigureTask.class))); + p.getTasks().named("clean").configure(task -> task.dependsOn("cmakeClean")); + p.getTasks().named("build").configure(task -> task.dependsOn(tasks.withType( + CMakeBuildTask.class))); + }); + } +} diff --git a/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakePluginExtension.java b/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakePluginExtension.java new file mode 100644 index 0000000..17e0996 --- /dev/null +++ b/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/CMakePluginExtension.java @@ -0,0 +1,121 @@ +package org.xbib.gradle.plugin.cmake; + +import java.io.File; +import org.gradle.api.Project; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.provider.MapProperty; +import org.gradle.api.provider.Property; + +public class CMakePluginExtension { + + // parameters used by config and build step + private final Property executable; + private final DirectoryProperty workingFolder; + + // parameters used by config step + private final DirectoryProperty sourceFolder; + private final Property configurationTypes; + private final Property installPrefix; + private final Property generator; // for example: "Visual Studio 16 2019" + + private final Property platform; // for example "x64" or "Win32" or "ARM" or "ARM64", supported on vs > 8.0 + private final Property toolset; // for example "v142", supported on vs > 10.0 + private final Property buildSharedLibs; + private final Property buildStaticLibs; + private final MapProperty defs; + private final MapProperty def; + + // parameters used on build step + private final Property buildConfig; + private final Property buildTarget; + private final Property buildClean; + private final TargetListExtension targets; + private final Project project; + + public CMakePluginExtension(Project project) { + executable = project.getObjects().property(String.class); + workingFolder = project.getObjects().directoryProperty(); + sourceFolder = project.getObjects().directoryProperty(); + configurationTypes = project.getObjects().property(String.class); + installPrefix = project.getObjects().property(String.class); + generator = project.getObjects().property(String.class); + platform = project.getObjects().property(String.class); + toolset = project.getObjects().property(String.class); + buildSharedLibs = project.getObjects().property(Boolean.class); + buildStaticLibs = project.getObjects().property(Boolean.class); + defs = project.getObjects().mapProperty(String.class, String.class); + def = project.getObjects().mapProperty(String.class, String.class); // for backwards compat + buildConfig = project.getObjects().property(String.class); + buildTarget = project.getObjects().property(String.class); + buildClean = project.getObjects().property(Boolean.class); + this.targets = project.getObjects().newInstance(TargetListExtension.class, project); + // default values + workingFolder.set(new File(project.getLayout().getBuildDirectory().get().getAsFile(), "cmake")); + sourceFolder.set(new File(project.getLayout().getBuildDirectory().get().getAsFile(), "src" + File.separator + "main" + File.separator + "cpp")); + this.project = project; + } + + public Property getExecutable() { + return executable; + } + + public DirectoryProperty getWorkingFolder() { + return workingFolder; + } + + public DirectoryProperty getSourceFolder() { + return sourceFolder; + } + + public Property getConfigurationTypes() { + return configurationTypes; + } + + public Property getInstallPrefix() { + return installPrefix; + } + + public Property getGenerator() { + return generator; + } + + public Property getPlatform() { + return platform; + } + + public Property getToolset() { + return toolset; + } + + public Property getBuildSharedLibs() { + return buildSharedLibs; + } + + public Property getBuildStaticLibs() { + return buildStaticLibs; + } + + public MapProperty getDef() { + return def; + } + + public MapProperty getDefs() { + return defs; + } + + public Property getBuildConfig() { + return buildConfig; + } + + public Property getBuildTarget() { + return buildTarget; + } + + public Property getBuildClean() { + return buildClean; + } + + public TargetListExtension getTargets() { + return targets; + } +} diff --git a/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/TargetExtension.java b/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/TargetExtension.java new file mode 100644 index 0000000..650a15d --- /dev/null +++ b/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/TargetExtension.java @@ -0,0 +1,174 @@ +package org.xbib.gradle.plugin.cmake; + +import java.io.File; +import java.util.Map; +import org.gradle.api.Project; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.provider.MapProperty; +import org.gradle.api.provider.Property; + +public class TargetExtension { + + // parameters used by config and build step + private final Property executable; + private final DirectoryProperty workingFolder; + + // parameters used by config step + private final DirectoryProperty sourceFolder; + private final Property configurationTypes; + private final Property installPrefix; + private final Property generator; // for example: "Visual Studio 16 2019" + private final Property platform; // for example "x64" or "Win32" or "ARM" or "ARM64", supported on vs > 8.0 + private final Property toolset; // for example "v142", supported on vs > 10.0 + private final Property buildSharedLibs; + private final Property buildStaticLibs; + private final MapProperty defs; + + // parameters used on build step + private final Property buildConfig; + private final Property buildTarget; + private final Property buildClean; + private final String name; + + public TargetExtension(final Project project, final String name) { + executable = project.getObjects().property(String.class); + workingFolder = project.getObjects().directoryProperty(); + sourceFolder = project.getObjects().directoryProperty(); + configurationTypes = project.getObjects().property(String.class); + installPrefix = project.getObjects().property(String.class); + generator = project.getObjects().property(String.class); + platform = project.getObjects().property(String.class); + toolset = project.getObjects().property(String.class); + buildSharedLibs = project.getObjects().property(Boolean.class); + buildStaticLibs = project.getObjects().property(Boolean.class); + defs = project.getObjects().mapProperty(String.class, String.class); + buildConfig = project.getObjects().property(String.class); + buildTarget = project.getObjects().property(String.class); + buildClean = project.getObjects().property(Boolean.class); + this.name = name; + } + + public Property getExecutable() { + return executable; + } + + public DirectoryProperty getWorkingFolder() { + return workingFolder; + } + + public DirectoryProperty getSourceFolder() { + return sourceFolder; + } + + public Property getConfigurationTypes() { + return configurationTypes; + } + + public Property getInstallPrefix() { + return installPrefix; + } + + public Property getGenerator() { + return generator; + } + + public Property getPlatform() { + return platform; + } + + public Property getToolset() { + return toolset; + } + + public Property getBuildSharedLibs() { + return buildSharedLibs; + } + + public Property getBuildStaticLibs() { + return buildStaticLibs; + } + + public MapProperty getDefs() { + return defs; + } + + public Property getBuildConfig() { + return buildConfig; + } + + public Property getBuildTarget() { + return buildTarget; + } + + public Property getBuildClean() { + return buildClean; + } + + public String getName() { + return name; + } + + public void setExecutable(String executable) { + this.executable.set(executable); + } + + public void setWorkingFolder(File workingFolder) { + this.workingFolder.set(workingFolder); + } + + public void setWorkingFolder(String workingFolder) { + this.workingFolder.set(new File(workingFolder)); + } + + public void setSourceFolder(File sourceFolder) { + this.sourceFolder.set(sourceFolder); + } + + public void setSourceFolder(String sourceFolder) { + this.sourceFolder.set(new File(sourceFolder)); + } + + public void setConfigurationTypes(String configurationTypes) { + this.configurationTypes.set(configurationTypes); + } + + public void setInstallPrefix(String installPrefix) { + this.installPrefix.set(installPrefix); + } + + public void setGenerator(String generator) { + this.generator.set(generator); + } + + public void setPlatform(String platform) { + this.platform.set(platform); + } + + public void setToolset(String toolset) { + this.toolset.set(toolset); + } + + public void setBuildSharedLibs(Boolean buildSharedLibs) { + this.buildSharedLibs.set(buildSharedLibs); + } + + public void setBuildStaticLibs(Boolean buildStaticLibs) { + this.buildStaticLibs.set(buildStaticLibs); + } + + public void setDefs(Map defs) { + this.defs.set(defs); + } + + public void setBuildConfig(String buildConfig) { + this.buildConfig.set(buildConfig); + } + + public void setBuildTarget(String buildTarget) { + this.buildTarget.set(buildTarget); + } + + public void setBuildClean(Boolean buildClean) { + this.buildClean.set(buildClean); + } +} diff --git a/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/TargetListExtension.java b/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/TargetListExtension.java new file mode 100644 index 0000000..c2002ad --- /dev/null +++ b/gradle-plugin-cmake/src/main/java/org/xbib/gradle/plugin/cmake/TargetListExtension.java @@ -0,0 +1,31 @@ +package org.xbib.gradle.plugin.cmake; + +import groovy.lang.Closure; +import groovy.lang.MissingMethodException; +import javax.inject.Inject; +import org.gradle.api.NamedDomainObjectContainer; +import org.gradle.api.Project; + +public class TargetListExtension { + + @Inject + public TargetListExtension(Project project) { + targetContainer = project.container(TargetExtension.class, name -> new TargetExtension(project, name)); + } + + private final NamedDomainObjectContainer targetContainer; + + public NamedDomainObjectContainer getTargetContainer() { + return targetContainer; + } + + public Object methodMissing(String name, Object args) { + if (args instanceof Object[] && ((Object[]) args)[0] instanceof Closure closure) { + return targetContainer.create(name, closure); + } else { + final Object[] normalizedArgs; + normalizedArgs = args instanceof Object[] ? (Object[]) args : new Object[]{args}; + throw new MissingMethodException(name, this.getClass(), normalizedArgs); + } + } +} diff --git a/settings.gradle b/settings.gradle index 22f4a18..7edea19 100644 --- a/settings.gradle +++ b/settings.gradle @@ -41,10 +41,11 @@ dependencyResolutionManagement { } } -include 'gradle-plugin-git' -include 'gradle-plugin-rpm' -include 'gradle-plugin-docker' include 'gradle-plugin-asciidoctor' +include 'gradle-plugin-cmake' +include 'gradle-plugin-docker' +include 'gradle-plugin-git' include 'gradle-plugin-jacc' include 'gradle-plugin-jflex' +include 'gradle-plugin-rpm' include 'gradle-plugin-shadow'