ããã¯ããªã«ãããããŠæžãããã®ïŒ
ã¡ãã£ãšåãããpicocliãšããJavaã§ã®ã³ãã³ãã©ã€ã³ã¢ããªã±ãŒã·ã§ã³åãã®ãã¬ãŒã ã¯ãŒã¯ãããã®ãæ°ã«ãªã£ãŠããŸããŠã
picocli - a mighty tiny command line interface
ãããŸã§Javaã®ã³ãã³ãã©ã€ã³ã¢ããªã±ãŒã·ã§ã³åãã®ã©ã€ãã©ãªãªã©ãšããã°ããã¡ãã䜿ã£ãŠããŸããã
å人çã«ã¯args4jããã䜿ã£ãŠããŸãããã
picocliãããªãè¯ããããªã®ã§ã1床詊ããŠãããããªãšã
picocli
ç¹°ãè¿ããŸãããJavaã®ã³ãã³ãã©ã€ã³ã¢ããªã±ãŒã·ã§ã³åãã®ãã¬ãŒã ã¯ãŒã¯ã§ãã
picocli - a mighty tiny command line interface
GNUãPOSIXãMS-DOSãªã©ã®ã³ãã³ãã©ã€ã³æ§æã®ãµããŒããã«ã©ãŒããã«ãã®çæããããªãã·ã§ã³ãåŒæ°ïŒãã©ã¡ãŒã¿ãŒïŒã
ãµãã³ãã³ããæ±ããããã§ã
ããã«ãGraalVMã«ãããã€ãã£ãã€ã¡ãŒãžã®äœæããµããŒãããŠããã®ã§ãããCLIãã¬ã³ããªãŒã§ããã
ããã¥ã¡ã³ãããšãŠãå å®ããŠããã®ããã€ã³ãã§ãããªãæ©èœãããããšãããããããŸãã
picocli - a mighty tiny command line interface
åèèšäºãGitHubäžã§ãªã³ã¯ãããŠãããã
Articles & Presentations / æ¥æ¬èª
説æã¯ãããããã«ããŠãè©ŠããŠãã£ãŠã¿ãŸãããã
ç°å¢
ä»åã®ç°å¢ã¯ããã¡ãã
$ java --version openjdk version "11.0.6" 2020-01-14 OpenJDK Runtime Environment GraalVM CE 19.3.1 (build 11.0.6+9-jvmci-19.3-b07) OpenJDK 64-Bit Server VM GraalVM CE 19.3.1 (build 11.0.6+9-jvmci-19.3-b07, mixed mode, sharing) $ mvn --version Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f) Maven home: $HOME/.sdkman/candidates/maven/current Java version: 11.0.6, vendor: Oracle Corporation, runtime: /usr/local/graalvm-ce Default locale: ja_JP, platform encoding: UTF-8 OS name: "linux", version: "5.3.0-40-generic", arch: "amd64", family: "unix"
ãã€ãã£ãã€ã¡ãŒãžãäœãããšæãã®ã§ãGraalVMã䜿ããŸãã
æºåãšãé¡
ãŸãã¯ã·ã³ãã«ã«ãMavenäŸåé¢ä¿ã¯ãã¡ãã
<dependency> <groupId>info.picocli</groupId> <artifactId>picocli</artifactId> <version>4.2.0</version> </dependency>
ãé¡ã§ããããããç°¡æãªcatãgrepã³ãã³ããäœããããã«catãgrepããµãã³ãã³ãã«ããã©ã³ãã£ãŒãäœããŸããæåŸã«ãã€ãã£ã
ã€ã¡ãŒãžãäœã£ãŠå®äºãšããŸããããã
Getting Startedçã«
ç°¡åãªCatã³ãã³ããããããã®ãäœã£ãŠã¿ãŸãããã
åŒæ°ãšããŠãã¡ã€ã«ãä»»ææ°æå®å¯èœããã¡ã€ã«ãæå®ããªãã£ããæšæºå
¥åããèªã¿ããªãã·ã§ã³ãšããŠã¯ã-nãã®ä»£ããã«
ã-p trueããšãããšè¡çªå·ã衚瀺ããããã«ããŸãããªãã·ã§ã³ã«åé·æãããŸããã©ããŸãã¯ãã©ã¡ãŒã¿ãŒããã®ãªãã·ã§ã³
ãšããããšã§ã
åŒæ°ããªãã·ã§ã³ãªã©ã¯ã¢ãããŒã·ã§ã³ã§è¡šçŸããŠããã®ã§ãããåºæ¬ã¯ãã¡ããèŠããšãããæ°ãããŸãã
äœæãããœãŒã¹ã³ãŒãã¯ããã¡ãã
src/main/java/org/littlewings/picocli/Cat.java
package org.littlewings.picocli; import java.io.BufferedReader; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import java.util.concurrent.Callable; import java.util.stream.Stream; import picocli.CommandLine; @CommandLine.Command(name = "cat") public class Cat implements Callable<Integer> { @CommandLine.Option(names = {"-h", "--help"}, description = "show this help", usageHelp = true) boolean showHelp; @CommandLine.Option(names = {"-p", "--print-line-number"}, paramLabel = "true or false", description = "number all output lines", defaultValue = "false") String printLineNumber; @CommandLine.Parameters(paramLabel = "FILE") List<Path> paths; int lineCount = 1; @Override public Integer call() throws Exception { if (paths != null) { for (Path path : paths) { try (Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8)) { if ("true".equals(printLineNumber)) { lines.forEach(line -> System.out.printf("%d: %s%n", lineCount++, line)); } else { lines.forEach(line -> System.out.printf("%s%n", line)); } } } } else { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8)); if ("true".equals(printLineNumber)) { reader.lines().forEach(line -> System.out.printf("%d: %s%n", lineCount++, line)); } else { reader.lines().forEach(line -> System.out.printf("%s%n", line)); } } return 0; } public static void main(String... args) { System.exit(new CommandLine(new Cat()).execute(args)); } }
Callableãå®è£ ããã¯ã©ã¹ãäœæãåãã©ã¡ãŒã¿ãŒã«ã¯ãIntegerãæå®ãcallã®æ»ãå€ãã³ãã³ãã®çµäºã¹ããŒã¿ã¹ãšããŠäœ¿ããŸãã
@CommandLine.Command(name = "cat") public class Cat implements Callable<Integer> {
@Commandã¢ãããŒã·ã§ã³ãä»äžããŠãnameããcatããšããŸãããã®nameã®å€ãããµãã³ãã³ãããã«ãã§äœ¿ãããŸãã
@Optionã¢ãããŒã·ã§ã³ã§æåéããªãã·ã§ã³ãã@Parametersã§ã³ãã³ãåŒæ°ãè¡šããŸãã
@CommandLine.Option(names = {"-h", "--help"}, description = "show this help", usageHelp = true) boolean showHelp; @CommandLine.Option(names = {"-p", "--print-line-number"}, paramLabel = "true or false", description = "number all output lines", defaultValue = "false") String printLineNumber; @CommandLine.Parameters(paramLabel = "FILE") List<Path> paths;
ã¢ãããŒã·ã§ã³ãä»äžãããã£ãŒã«ãã«ã¯ããªãã·ã§ã³ãåŒæ°ã§æå®ããå€ãå ¥ããŸãã
String以å€ã®åã§ãåãåããŸãã
Listãé åãªã©ã䜿ããšãè€æ°åæå®ã§ãããªãã·ã§ã³ãåŒæ°ãšããŠäœ¿ããããŸãã
@Optionã§ãusageHelpããtrueã«ãããšããã«ããªãã·ã§ã³ãšããŠæ±ãããŸãã
ããšã¯callã¡ãœããã®äžãå®è£ ããŠ
@Override public Integer call() throws Exception { if (paths != null) { for (Path path : paths) { try (Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8)) { if ("true".equals(printLineNumber)) { lines.forEach(line -> System.out.printf("%d: %s%n", lineCount++, line)); } else { lines.forEach(line -> System.out.printf("%s%n", line)); } } } } else { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8)); if ("true".equals(printLineNumber)) { reader.lines().forEach(line -> System.out.printf("%d: %s%n", lineCount++, line)); } else { reader.lines().forEach(line -> System.out.printf("%s%n", line)); } } return 0; }
mainã¡ãœãããäœæã
public static void main(String... args) { System.exit(new CommandLine(new Cat()).execute(args)); }
ãã®Callableã®ã€ã³ã¹ã¿ã³ã¹ããCommandLineã®ã³ã³ã¹ãã©ã¯ã¿ã«æž¡ããŠexecuteãåŒã³åºããŸãããã®æã«ãmainã¡ãœããã®åŒæ°ã
æž¡ããš@Optionã@Parametersã¢ãããŒã·ã§ã³ãä»äžãããã£ãŒã«ãã«å€ãå
¥ã£ãç¶æ
ã§callã¡ãœãããåŒã³åºãããŸãã
executeã®æ»ãå€ã¯ãcallã¡ãœããã®æ»ãå€ã«ãªããŸãã
ã§ã¯ãè©ŠããŠã¿ãŸãããã
ãµã³ãã«ã®ãã¡ã€ã«ãäœæã
$ python3 -c 'import this' > zen_of_python.txt
å®è¡ã倧çããŠãŸããããmvn exec:javaãã§å®è¡ããŸãã
$ mvn compile exec:java -Dexec.mainClass=org.littlewings.picocli.Cat -Dexec.args='zen_of_python.txt' ãçç¥ã The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're Dutch. Now is better than never. Although never is often better than *right* now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea -- let's do more of those!
è¡çªå·ã衚瀺ããŠã¿ãŸãã
$ mvn compile exec:java -Dexec.mainClass=org.littlewings.picocli.Cat -Dexec.args='-p true zen_of_python.txt' ãçç¥ã 1: The Zen of Python, by Tim Peters 2: 3: Beautiful is better than ugly. 4: Explicit is better than implicit. 5: Simple is better than complex. 6: Complex is better than complicated. 7: Flat is better than nested. 8: Sparse is better than dense. 9: Readability counts. 10: Special cases aren't special enough to break the rules. 11: Although practicality beats purity. 12: Errors should never pass silently. 13: Unless explicitly silenced. 14: In the face of ambiguity, refuse the temptation to guess. 15: There should be one-- and preferably only one --obvious way to do it. 16: Although that way may not be obvious at first unless you're Dutch. 17: Now is better than never. 18: Although never is often better than *right* now. 19: If the implementation is hard to explain, it's a bad idea. 20: If the implementation is easy to explain, it may be a good idea. 21: Namespaces are one honking great idea -- let's do more of those!
OKããã§ããã
ããã²ãšã€ãã¡ã€ã«ãå¢ãããŠã¿ãŸãããã
$ lsb_release -a > ubuntu_version.txt
è€æ°ã®ãã¡ã€ã«ã察象ã«ããŠã¿ãŸãããªãã·ã§ã³ã¯ããã³ã°ãªãã·ã§ã³ã§æå®ããŠã¿ãŸãã
$ mvn compile exec:java -Dexec.mainClass=org.littlewings.picocli.Cat -Dexec.args='--print-line-number true zen_of_python.txt ubuntu_version.txt' ãçç¥ã 1: The Zen of Python, by Tim Peters 2: 3: Beautiful is better than ugly. 4: Explicit is better than implicit. 5: Simple is better than complex. 6: Complex is better than complicated. 7: Flat is better than nested. 8: Sparse is better than dense. 9: Readability counts. 10: Special cases aren't special enough to break the rules. 11: Although practicality beats purity. 12: Errors should never pass silently. 13: Unless explicitly silenced. 14: In the face of ambiguity, refuse the temptation to guess. 15: There should be one-- and preferably only one --obvious way to do it. 16: Although that way may not be obvious at first unless you're Dutch. 17: Now is better than never. 18: Although never is often better than *right* now. 19: If the implementation is hard to explain, it's a bad idea. 20: If the implementation is easy to explain, it may be a good idea. 21: Namespaces are one honking great idea -- let's do more of those! 22: Distributor ID: Ubuntu 23: Description: Ubuntu 18.04.4 LTS 24: Release: 18.04 25: Codename: bionic
ãã¡ã€ã«ãæå®ããã«ãæšæºåºåããå ¥åããŠã¿ãŸãããã
$ cat ubuntu_version.txt | mvn compile exec:java -Dexec.mainClass=org.littlewings.picocli.Cat ãçç¥ã Distributor ID: Ubuntu Description: Ubuntu 18.04.4 LTS Release: 18.04 Codename: bionic
æåŸã«ããã«ãã衚瀺ã
$ mvn compile exec:java -Dexec.mainClass=org.littlewings.picocli.Cat -Dexec.args='-h' ãçç¥ã Usage: cat [-h] [-p=true or false] [FILE...] [FILE...] -h, --help show this help -p, --print-line-number=true or false number all output lines
ã¡ãªã¿ã«ããã®ãã«ãã¯ã«ã©ãŒã§èŠããŸãã
OKã§ããã
ããã²ãšã€ãµã³ãã«ã
ç¶ããŠãgrepãã©ããäœæããŠã¿ãŸãããã
ãœãŒã¹ã³ãŒãã¯ããã¡ãã
src/main/java/org/littlewings/picocli/Grep.java
package org.littlewings.picocli; import java.io.BufferedReader; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.concurrent.Callable; import java.util.regex.Matcher; import java.util.regex.Pattern; import picocli.CommandLine; @CommandLine.Command(name = "grep") public class Grep implements Callable<Integer> { @CommandLine.Option(names = {"-h", "--help"}, description = "show this help", usageHelp = true) boolean showHelp; @CommandLine.Option(names = {"-n", "--line-number"}, description = "display match line number", defaultValue = "false") boolean printLineNumber; @CommandLine.Option(names = {"-v", "--invert-match"}, description = "print invert match") boolean printInvertMatch; @CommandLine.Parameters(index = "0", paramLabel = "PATTERN") String pattern; @CommandLine.Parameters(index = "1", paramLabel = "FILE") Path path; @Override public Integer call() throws Exception { Pattern p = Pattern.compile(pattern); try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) { String line; int lineCount = 1; while ((line = reader.readLine()) != null) { lineCount++; Matcher m = p.matcher(line); boolean match = m.find(); if (match && !printInvertMatch) { if (printLineNumber) { System.out.printf("%d: %s%n", lineCount, line); } else { System.out.printf("%s%n", line); } } else if (!match && printInvertMatch) { if (printLineNumber) { System.out.printf("%d: %s%n", lineCount, line); } else { System.out.printf("%s%n", line); } } } } return 0; } public static void main(String... args) { System.exit(new CommandLine(new Grep()).execute(args)); } }
å
ã»ã©ãšéãã®ã¯ãbooleanã®ãªãã·ã§ã³ãèšããŠãæå®ããã°trueãšãªãããã«ããŸããããªãã·ã§ã³ãšããŠã¯ãã-nããšã-vããå®çŸ©
ããŠããŸãã
@CommandLine.Option(names = {"-n", "--line-number"}, description = "display match line number", defaultValue = "false") boolean printLineNumber; @CommandLine.Option(names = {"-v", "--invert-match"}, description = "print invert match") boolean printInvertMatch;
ãŸããåŒæ°ã®äœçœ®ãæå®ããããã«ããŠã¿ãŸããå
¥åãšãªããã¡ã€ã«ã¯ãè€æ°æå®ã§ããªãããã«ããŸããããŸãããã¡ã€ã«ã
æå®ããªããšæšæºå
¥åããèªã¿èŸŒããããªåããããŸããã
@CommandLine.Parameters(index = "0", paramLabel = "PATTERN") String pattern; @CommandLine.Parameters(index = "1", paramLabel = "FILE") Path path;
ãã®ä»ã¯ããããªã«catã®äŸãšå€ãããªãã®ã§ã説æã¯çç¥ã
確èªã
$ mvn compile exec:java -Dexec.mainClass=org.littlewings.picocli.Grep -Dexec.args='better zen_of_python.txt' ãçç¥ã Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Now is better than never. Although never is often better than *right* now.
è¡çªå·ãåºåã
$ mvn compile exec:java -Dexec.mainClass=org.littlewings.picocli.Grep -Dexec.args='-n better zen_of_python.txt' ãçç¥ã 4: Beautiful is better than ugly. 5: Explicit is better than implicit. 6: Simple is better than complex. 7: Complex is better than complicated. 8: Flat is better than nested. 9: Sparse is better than dense. 18: Now is better than never. 19: Although never is often better than *right* now.
ããããã-vãããã³ã°ãªãã·ã§ã³ã§æå®ã
$ mvn compile exec:java -Dexec.mainClass=org.littlewings.picocli.Grep -Dexec.args='-n --invert-match better zen_of_python.txt' ãçç¥ã 2: The Zen of Python, by Tim Peters 3: 10: Readability counts. 11: Special cases aren't special enough to break the rules. 12: Although practicality beats purity. 13: Errors should never pass silently. 14: Unless explicitly silenced. 15: In the face of ambiguity, refuse the temptation to guess. 16: There should be one-- and preferably only one --obvious way to do it. 17: Although that way may not be obvious at first unless you're Dutch. 20: If the implementation is hard to explain, it's a bad idea. 21: If the implementation is easy to explain, it may be a good idea. 22: Namespaces are one honking great idea -- let's do more of those!
ãã«ãã
$ mvn compile exec:java -Dexec.mainClass=org.littlewings.picocli.Grep -Dexec.args='--help' ãçç¥ã Usage: grep [-hnv] PATTERN FILE PATTERN FILE -h, --help show this help -n, --line-number display match line number -v, --invert-match print invert match
ãµãã³ãã³ãã䜿ã
äœæããã³ãã³ãã®æåŸãšããŠããµãã³ãã³ãã䜿ã£ãŠã¿ãŸãããã
å ã»ã©äœã£ãcatãgrepããµãã³ãã³ãã«ãããã®ãäœã£ãŠã¿ãŸãã
ãããªæãã§ã src/main/java/org/littlewings/picocli/Launcher.java
package org.littlewings.picocli; import java.util.concurrent.Callable; import picocli.CommandLine; @CommandLine.Command(name = "launcher", subcommands = {Cat.class, Grep.class}) public class Launcher implements Callable<Integer> { @CommandLine.Option(names = {"-h", "--help"}, description = "show this help", usageHelp = true) boolean showHelp; @Override public Integer call() throws Exception { return 0; } public static void main(String... args) { System.exit(new CommandLine(new Launcher()).execute(args)); } }
@Commandã¢ãããŒã·ã§ã³ã®subcommandsã«ãå ã»ã©ãŸã§äœæããŠããã³ãã³ããããµãã³ãã³ããšããŠç»é²ããŸãã
@CommandLine.Command(name = "launcher", subcommands = {Cat.class, Grep.class}) public class Launcher implements Callable<Integer> {
callã¡ãœããã®äžèº«ã¯ãç¹ã«ãªã«ããªããŠãåããŸãã
ãšããããããã«ããèŠãŠã¿ãŸãããã
$ mvn compile exec:java -Dexec.mainClass=org.littlewings.picocli.Launcher -Dexec.args='-h' ãçç¥ã Usage: launcher [-h] [COMMAND] -h, --help show this help Commands: cat grep
ãã«ãã§ãµãã³ãã³ããèŠããŸããã
ãµãã³ãã³ãã§ãgrepããæå®ããŠããã«ããèŠãŠã¿ãŸãããã
$ mvn compile exec:java -Dexec.mainClass=org.littlewings.picocli.Launcher -Dexec.args='grep -h' ãçç¥ã Usage: launcher grep [-hnv] PATTERN FILE PATTERN FILE -h, --help show this help -n, --line-number display match line number -v, --invert-match print invert match
grepã®ãã«ããèŠããŸããã
ãã¡ããããµãã³ãã³ããæå®ããŠå®è¡ãã§ããŸãã
$ mvn compile exec:java -Dexec.mainClass=org.littlewings.picocli.Launcher -Dexec.args='grep -n Python zen_of_python.txt' ãçç¥ã 2: The Zen of Python, by Tim Peters
è£è¶³
ä»åã¯ã³ãã³ãã®äžèº«ãCallable#callãšããŠå®è£
ããŸãããããã®ä»ã«ãRunnableãšIExitCodeGeneratorã€ã³ã¿ãŒãã§ãŒã¹ãå®è£
ããããã
æ¹æ³ããã£ãã
ãªãã·ã§ã³ãåŒæ°ã®ããŒã¹çµæããã£ãšçŽ°ããã³ã³ãããŒã«ããæ¹æ³ããã£ããããããã§ãã
ã©ã£ã¡ã«ãããæ©èœããšãŠãå€ããŠæžããããªãã®ã§ãä»åã¯ãã®ãããã«ããŠãããŸãã
ãã€ãã£ãã€ã¡ãŒãžãäœã
æåŸã«ãGraalVMã䜿ã£ãŠãã€ãã£ãã€ã¡ãŒãžãäœã£ãŠã¿ãŸãããã
Pluggable Annotation Processing APIã䜿ã£ãã¢ãžã¥ãŒã«ãããã®ã§ããã¡ããpom.xmlã«èšå®ããŸãã
Maven Compiler Pluginã®ãannotationProcessorPathsãšããŠæå®ããŸãã
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <annotationProcessorPaths> <path> <groupId>info.picocli</groupId> <artifactId>picocli-codegen</artifactId> <version>4.2.0</version> </path> </annotationProcessorPaths> <compilerArgs> <arg>-Aproject=${groupId}/${artifactId}</arg> </compilerArgs> </configuration> </plugin> </plugins> </build>
ãã®ç¶æ ã§ãã«ããããš
$ mvn compile
ãcompilerArgsãã§æå®ãããã¹ïŒãMETA-INF/native-image/picocli-generatedãé äžã§ããïŒã«ããã¡ã€ã«ãçæãããŸãã
$ find target/classes/META-INF/native-image/picocli-generated/org.example/picocli-example -type f target/classes/META-INF/native-image/picocli-generated/org.example/picocli-example/proxy-config.json target/classes/META-INF/native-image/picocli-generated/org.example/picocli-example/reflect-config.json target/classes/META-INF/native-image/picocli-generated/org.example/picocli-example/resource-config.json
ä»åã¯ããªãã¬ã¯ã·ã§ã³ã«é¢ããèšå®ã ããæå³ã®ããå€ãçæãããŸããã
target/classes/META-INF/native-image/picocli-generated/org.example/picocli-example/reflect-config.json
[ { "name" : "org.littlewings.picocli.Cat", "allDeclaredConstructors" : true, "allPublicConstructors" : true, "allDeclaredMethods" : true, "allPublicMethods" : true, "fields" : [ { "name" : "paths" }, { "name" : "printLineNumber" }, { "name" : "showHelp" } ] }, { "name" : "org.littlewings.picocli.Grep", "allDeclaredConstructors" : true, "allPublicConstructors" : true, "allDeclaredMethods" : true, "allPublicMethods" : true, "fields" : [ { "name" : "path" }, { "name" : "pattern" }, { "name" : "printInvertMatch" }, { "name" : "printLineNumber" }, { "name" : "showHelp" } ] }, { "name" : "org.littlewings.picocli.Launcher", "allDeclaredConstructors" : true, "allPublicConstructors" : true, "allDeclaredMethods" : true, "allPublicMethods" : true, "fields" : [ { "name" : "showHelp" } ] } ]
ããšã¯ãGraalVMã®Native Image Maven Pluginã䜿ããŸãã
ãããªæãã§ã
<plugins> <plugin> <groupId>org.graalvm.nativeimage</groupId> <artifactId>native-image-maven-plugin</artifactId> <version>19.3.1</version> <executions> <execution> <goals> <goal>native-image</goal> </goals> <phase>package</phase> </execution> </executions> <configuration> <skip>false</skip> <imageName>cat</imageName> <buildArgs> --no-fallback </buildArgs> <mainClass>org.littlewings.picocli.Cat</mainClass> </configuration> </plugin> </plugins>
ã³ãã³ãã3ã€ããã®ã§ãä»åã¯Profileã§åããŸããã
<profiles> <profile> <id>native-cat</id> <build> <plugins> <plugin> <groupId>org.graalvm.nativeimage</groupId> <artifactId>native-image-maven-plugin</artifactId> <version>19.3.1</version> <executions> <execution> <goals> <goal>native-image</goal> </goals> <phase>package</phase> </execution> </executions> <configuration> <skip>false</skip> <imageName>cat</imageName> <buildArgs> --no-fallback </buildArgs> <mainClass>org.littlewings.picocli.Cat</mainClass> </configuration> </plugin> </plugins> </build> </profile> <profile> <id>native-grep</id> <build> <plugins> <plugin> <groupId>org.graalvm.nativeimage</groupId> <artifactId>native-image-maven-plugin</artifactId> <version>19.3.1</version> <executions> <execution> <goals> <goal>native-image</goal> </goals> <phase>package</phase> </execution> </executions> <configuration> <skip>false</skip> <imageName>grep</imageName> <buildArgs> --no-fallback </buildArgs> <mainClass>org.littlewings.picocli.Grep</mainClass> </configuration> </plugin> </plugins> </build> </profile> <profile> <id>native-launcher</id> <build> <plugins> <plugin> <groupId>org.graalvm.nativeimage</groupId> <artifactId>native-image-maven-plugin</artifactId> <version>19.3.1</version> <executions> <execution> <goals> <goal>native-image</goal> </goals> <phase>package</phase> </execution> </executions> <configuration> <skip>false</skip> <imageName>launcher</imageName> <buildArgs> --no-fallback </buildArgs> <mainClass>org.littlewings.picocli.Launcher</mainClass> </configuration> </plugin> </plugins> </build> </profile> </profiles>
ã§ã¯ããã«ãã
$ mvn -P native-cat package && mvn -P native-grep package && mvn -P native-launcher package
確èªã
$ ./target/cat -p true zen_of_python.txt 1: The Zen of Python, by Tim Peters 2: 3: Beautiful is better than ugly. 4: Explicit is better than implicit. 5: Simple is better than complex. 6: Complex is better than complicated. 7: Flat is better than nested. 8: Sparse is better than dense. 9: Readability counts. 10: Special cases aren't special enough to break the rules. 11: Although practicality beats purity. 12: Errors should never pass silently. 13: Unless explicitly silenced. 14: In the face of ambiguity, refuse the temptation to guess. 15: There should be one-- and preferably only one --obvious way to do it. 16: Although that way may not be obvious at first unless you're Dutch. 17: Now is better than never. 18: Although never is often better than *right* now. 19: If the implementation is hard to explain, it's a bad idea. 20: If the implementation is easy to explain, it may be a good idea. 21: Namespaces are one honking great idea -- let's do more of those! $ ./target/grep -v Ubuntu ubuntu_version.txt Release: 18.04 Codename: bionic $ ./target/launcher --help Usage: launcher [-h] [COMMAND] -h, --help show this help Commands: cat grep
OKã§ããã
ãŸãšã
Javaã®ã³ãã³ãã©ã€ã³ã¢ããªã±ãŒã·ã§ã³åãã®ãã¬ãŒã ã¯ãŒã¯ã§ãããpicocliãè©ŠããŠã¿ãŸããã
æåã¯ããã¥ã¡ã³ãã®éãèŠãŠããããªãŒãšæããŸããããããããããæžãããŠããŠãšã£ã€ããããã£ããšæããŸãã
GraalVMã«ããããã€ãã£ãã€ã¡ãŒãžã®äœæã«å¯Ÿå¿ããŠãããšãããããã§ããã
CLIãäœãæã«ã¯ãä»åºŠãããã¡ãã掻çšããŠãããŸãããã