8166238: Update jdeps for GNU-style long form options

Reviewed-by: alanb
This commit is contained in:
Mandy Chung 2016-09-29 21:31:09 -07:00
parent f2eb960882
commit 33b751c3d4
7 changed files with 133 additions and 127 deletions

View File

@ -150,7 +150,7 @@ class JdepsTask {
task.options.help = true; task.options.help = true;
} }
}, },
new Option(true, "-dotoutput") { new Option(true, "-dotoutput", "--dot-output") {
void process(JdepsTask task, String opt, String arg) throws BadArgs { void process(JdepsTask task, String opt, String arg) throws BadArgs {
Path p = Paths.get(arg); Path p = Paths.get(arg);
if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) { if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) {
@ -191,7 +191,7 @@ class JdepsTask {
} }
} }
}, },
new Option(false, "-apionly") { new Option(false, "-apionly", "--api-only") {
void process(JdepsTask task, String opt, String arg) { void process(JdepsTask task, String opt, String arg) {
task.options.apiOnly = true; task.options.apiOnly = true;
} }
@ -203,7 +203,7 @@ class JdepsTask {
task.options.addmods.addAll(mods); task.options.addmods.addAll(mods);
} }
}, },
new Option(true, "--gen-module-info") { new Option(true, "--generate-module-info") {
void process(JdepsTask task, String opt, String arg) throws BadArgs { void process(JdepsTask task, String opt, String arg) throws BadArgs {
Path p = Paths.get(arg); Path p = Paths.get(arg);
if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) { if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) {
@ -212,7 +212,7 @@ class JdepsTask {
task.options.genModuleInfo = Paths.get(arg); task.options.genModuleInfo = Paths.get(arg);
} }
}, },
new Option(false, "-jdkinternals") { new Option(false, "-jdkinternals", "--jdk-internals") {
void process(JdepsTask task, String opt, String arg) { void process(JdepsTask task, String opt, String arg) {
task.options.findJDKInternals = true; task.options.findJDKInternals = true;
task.options.verbose = CLASS; task.options.verbose = CLASS;
@ -263,19 +263,36 @@ class JdepsTask {
task.options.addmods.add(arg); task.options.addmods.add(arg);
} }
}, },
new Option(true, "--multi-release") {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
if (arg.equalsIgnoreCase("base")) {
task.options.multiRelease = JarFile.baseVersion();
} else {
try {
int v = Integer.parseInt(arg);
if (v < 9) {
throw new BadArgs("err.invalid.arg.for.option", arg);
}
} catch (NumberFormatException x) {
throw new BadArgs("err.invalid.arg.for.option", arg);
}
task.options.multiRelease = Runtime.Version.parse(arg);
}
}
},
// ---- Target filtering options ---- // ---- Target filtering options ----
new Option(true, "-p", "-package") { new Option(true, "-p", "-package", "--package") {
void process(JdepsTask task, String opt, String arg) { void process(JdepsTask task, String opt, String arg) {
task.options.packageNames.add(arg); task.options.packageNames.add(arg);
} }
}, },
new Option(true, "-e", "-regex") { new Option(true, "-e", "-regex", "--regex") {
void process(JdepsTask task, String opt, String arg) { void process(JdepsTask task, String opt, String arg) {
task.options.regex = Pattern.compile(arg); task.options.regex = Pattern.compile(arg);
} }
}, },
new Option(true, "-requires") { new Option(true, "--require") {
void process(JdepsTask task, String opt, String arg) { void process(JdepsTask task, String opt, String arg) {
task.options.requires.add(arg); task.options.requires.add(arg);
} }
@ -336,7 +353,7 @@ class JdepsTask {
} }
}, },
new Option(false, "-I", "-inverse") { new Option(false, "-I", "--inverse") {
void process(JdepsTask task, String opt, String arg) { void process(JdepsTask task, String opt, String arg) {
task.options.inverse = true; task.options.inverse = true;
// equivalent to the inverse of compile-time view analysis // equivalent to the inverse of compile-time view analysis
@ -361,7 +378,7 @@ class JdepsTask {
} }
}, },
new Option(false, "-version") { new Option(false, "-version", "--version") {
void process(JdepsTask task, String opt, String arg) { void process(JdepsTask task, String opt, String arg) {
task.options.version = true; task.options.version = true;
} }
@ -390,23 +407,6 @@ class JdepsTask {
} }
} }
}, },
new Option(true, "--multi-release") {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
if (arg.equalsIgnoreCase("base")) {
task.options.multiRelease = JarFile.baseVersion();
} else {
try {
int v = Integer.parseInt(arg);
if (v < 9) {
throw new BadArgs("err.invalid.arg.for.option", arg);
}
} catch (NumberFormatException x) {
throw new BadArgs("err.invalid.arg.for.option", arg);
}
task.options.multiRelease = Runtime.Version.parse(arg);
}
}
},
}; };
private static final String PROGNAME = "jdeps"; private static final String PROGNAME = "jdeps";

View File

@ -13,162 +13,168 @@ warn.prefix=Warning:
main.opt.h=\ main.opt.h=\
\ -h -? -help\n\ \ -h -? -help\n\
\ --help Print this usage message \ --help Print this usage message
main.opt.version=\ main.opt.version=\
\ -version Version information \ -version --version Version information
main.opt.v=\ main.opt.v=\
\ -v -verbose Print all class level dependencies\n\ \ -v -verbose Print all class level dependences\n\
\ Equivalent to -verbose:class -filter:none.\n\ \ Equivalent to -verbose:class -filter:none.\n\
\ -verbose:package Print package-level dependencies excluding\n\ \ -verbose:package Print package-level dependences excluding\n\
\ dependencies within the same package by default\n\ \ dependences within the same package by default\n\
\ -verbose:class Print class-level dependencies excluding\n\ \ -verbose:class Print class-level dependences excluding\n\
\ dependencies within the same package by default \ dependences within the same package by default
main.opt.s=\ main.opt.s=\
\ -s -summary Print dependency summary only. \ -s -summary Print dependency summary only.
main.opt.f=\ main.opt.f=\
\ -f <regex> -filter <regex> Filter dependences matching the given\n\ \ -f <regex> -filter <regex> Filter dependences matching the given\n\
\ pattern. If given multiple times, the last\n\ \ pattern. If given multiple times, the last\n\
\ one will be used.\n\ \ one will be used.\n\
\ -filter:package Filter dependences within the same package.\n\ \ -filter:package Filter dependences within the same package.\n\
\ This is the default.\n\ \ This is the default.\n\
\ -filter:archive Filter dependences within the same archive.\n\ \ -filter:archive Filter dependences within the same archive.\n\
\ -filter:module Filter dependences within the same module.\n\ \ -filter:module Filter dependences within the same module.\n\
\ -filter:none No -filter:package and -filter:archive\n\ \ -filter:none No -filter:package and -filter:archive\n\
\ filtering. Filtering specified via the\n\ \ filtering. Filtering specified via the\n\
\ -filter option still applies.\n\ \ -filter option still applies.\n\
main.opt.p=\n\ main.opt.p=\n\
\Options to filter dependencies:\n\ \Options to filter dependences:\n\
\ -p <pkgname> -package <pkgname> Finds dependences matching the given package\n\ \ -p <pkg>\n\
\ name (may be given multiple times). \ -package <pkg>\n\
\ --package <pkg> Finds dependences matching the given package\n\
\ name (may be given multiple times).
main.opt.e=\ main.opt.e=\
\ -e <regex> -regex <regex> Finds dependences matching the given pattern. \ -e <regex>\n\
\ -regex <regex>\n\
\ --regex <regex> Finds dependences matching the given pattern.
main.opt.requires=\ main.opt.require=\
\ -requires <module-name> Finds dependences matching the given module\n\ \ --require <module-name> Finds dependences matching the given module\n\
\ name (may be given multiple times).\n\ \ name (may be given multiple times). --package,\n\
\ -package, -regex, -requires are mutual exclusive. \ --regex, --require are mutual exclusive.
main.opt.include=\n\ main.opt.include=\n\
\Options to filter classes to be analyzed:\n\ \Options to filter classes to be analyzed:\n\
\ -include <regex> Restrict analysis to classes matching pattern\n\ \ -include <regex> Restrict analysis to classes matching pattern\n\
\ This option filters the list of classes to\n\ \ This option filters the list of classes to\n\
\ be analyzed. It can be used together with\n\ \ be analyzed. It can be used together with\n\
\ -p and -e which apply pattern to the dependences \ -p and -e which apply pattern to the dependences
main.opt.P=\ main.opt.P=\
\ -P -profile Show profile containing a package \ -P -profile Show profile containing a package
main.opt.cp=\ main.opt.cp=\
\ -cp <path>\n\ \ -cp <path>\n\
\ -classpath <path>\n\ \ -classpath <path>\n\
\ --class-path <path> Specify where to find class files \ --class-path <path> Specify where to find class files
main.opt.module-path=\ main.opt.module-path=\
\ --module-path <module path>... Specify module path \ --module-path <module path> Specify module path
main.opt.upgrade-module-path=\ main.opt.upgrade-module-path=\
\ --upgrade-module-path <module path>... Specify upgrade module path \ --upgrade-module-path <module path> Specify upgrade module path
main.opt.system=\ main.opt.system=\
\ --system <java-home> Specify an alternate system module path \ --system <java-home> Specify an alternate system module path
main.opt.add-modules=\ main.opt.add-modules=\
\ --add-modules <module-name>[,<module-name>...]\n\ \ --add-modules <module-name>[,<module-name>...]\n\
\ Adds modules to the root set for analysis \ Adds modules to the root set for analysis
main.opt.m=\ main.opt.m=\
\ -m <module-name>\n\ \ -m <module-name>\n\
\ --module <module-name> Specify the root module for analysis \ --module <module-name> Specify the root module for analysis
main.opt.R=\ main.opt.R=\
\ -R -recursive Recursively traverse all run-time dependencies.\n\ \ -R -recursive Recursively traverse all run-time dependences.\n\
\ The -R option implies -filter:none. If -p,\n\ \ The -R option implies -filter:none. If -p,\n\
\ -e, -foption is specified, only the matching\n\ \ -e, -foption is specified, only the matching\n\
\ dependences are analyzed. \ dependences are analyzed.
main.opt.I=\ main.opt.I=\
\ -I -inverse Analyzes the dependences per other given options\n\ \ -I --inverse Analyzes the dependences per other given options\n\
\ and then find all artifacts that directly\n\ \ and then find all artifacts that directly\n\
\ and indirectly depend on the matching nodes.\n\ \ and indirectly depend on the matching nodes.\n\
\ This is equivalent to the inverse of\n\ \ This is equivalent to the inverse of\n\
\ compile-time view analysis and print\n\ \ compile-time view analysis and print\n\
\ dependency summary. This option must use\n\ \ dependency summary. This option must use\n\
\ with -requires, -package or -regex option. \ with --require, --package or --regex option.
main.opt.compile-time=\ main.opt.compile-time=\
\ --compile-time Compile-time view of transitive dependencies\n\ \ --compile-time Compile-time view of transitive dependences\n\
\ i.e. compile-time view of -R option.\n\ \ i.e. compile-time view of -R option.\n\
\ Analyzes the dependences per other given options\n\ \ Analyzes the dependences per other given options\n\
\ If a dependence is found from a directory,\n\ \ If a dependence is found from a directory,\n\
\ a JAR file or a module, all classes in that \n\ \ a JAR file or a module, all classes in that \n\
\ containing archive are analyzed. \ containing archive are analyzed.
main.opt.apionly=\ main.opt.apionly=\
\ -apionly Restrict analysis to APIs i.e. dependences\n\ \ -apionly\n\
\ from the signature of public and protected\n\ \ --api-only Restrict analysis to APIs i.e. dependences\n\
\ members of public classes including field\n\ \ from the signature of public and protected\n\
\ type, method parameter types, returned type,\n\ \ members of public classes including field\n\
\ checked exception types etc. \ type, method parameter types, returned type,\n\
\ checked exception types etc.
main.opt.gen-module-info=\ main.opt.generate-module-info=\
\ --gen-module-info <dir> Generate module-info.java under the specified\n\ \ --generate-module-info <dir> Generate module-info.java under the specified\n\
\ directory. The specified JAR files will be\n\ \ directory. The specified JAR files will be\n\
\ analyzed. This option cannot be used with\n\ \ analyzed. This option cannot be used with\n\
\ -dotoutput or -cp. \ --dot-output or --class-path.
main.opt.check=\ main.opt.check=\
\ --check <module-name>[,<module-name>...\n\ \ --check <module-name>[,<module-name>...\n\
\ Analyze the dependence of the specified modules\n\ \ Analyze the dependence of the specified modules\n\
\ It prints the module descriptor, the resulting\n\ \ It prints the module descriptor, the resulting\n\
\ module dependences after analysis and the\n\ \ module dependences after analysis and the\n\
\ graph after transition reduction. It also\n\ \ graph after transition reduction. It also\n\
\ identifies any unused qualified exports. \ identifies any unused qualified exports.
main.opt.dotoutput=\ main.opt.dotoutput=\
\ -dotoutput <dir> Destination directory for DOT file output \ -dotoutput <dir>\n\
\ --dot-output <dir> Destination directory for DOT file output
main.opt.jdkinternals=\ main.opt.jdkinternals=\
\ -jdkinternals Finds class-level dependences on JDK internal\n\ \ -jdkinternals\n\
\ APIs. By default, it analyzes all classes\n\ \ --jdk-internals Finds class-level dependences on JDK internal\n\
\ on -classpath and input files unless -include\n\ \ APIs. By default, it analyzes all classes\n\
\ option is specified. This option cannot be\n\ \ on --class-path and input files unless -include\n\
\ used with -p, -e and -s options.\n\ \ option is specified. This option cannot be\n\
\ WARNING: JDK internal APIs are inaccessible. \ used with -p, -e and -s options.\n\
\ WARNING: JDK internal APIs are inaccessible.
main.opt.depth=\ main.opt.depth=\
\ -depth=<depth> Specify the depth of the transitive\n\ \ -depth=<depth> Specify the depth of the transitive\n\
\ dependency analysis \ dependency analysis
main.opt.q=\ main.opt.q=\
\ -q -quiet Do not show missing dependencies from \n\ \ -q -quiet Do not show missing dependences from \n\
\ -genmoduleinfo output. \ --generate-module-info output.
main.opt.multi-release=\ main.opt.multi-release=\
\ --multi-release <version> Specifies the version when processing\n\ \ --multi-release <version> Specifies the version when processing\n\
\ multi-release jar files. <version> should\n\ \ multi-release jar files. <version> should\n\
\ be integer >= 9 or base. \ be integer >= 9 or base.
err.unknown.option=unknown option: {0} err.unknown.option=unknown option: {0}
err.missing.arg=no value given for {0} err.missing.arg=no value given for {0}
err.invalid.arg.for.option=invalid argument for option: {0} err.invalid.arg.for.option=invalid argument for option: {0}
err.option.after.class=option must be specified before classes: {0} err.option.after.class=option must be specified before classes: {0}
err.genmoduleinfo.not.jarfile={0} not valid for --gen-module-info option (must be non-modular JAR file) err.genmoduleinfo.not.jarfile={0} not valid for --generate-module-info option (must be non-modular JAR file)
err.profiles.msg=No profile information err.profiles.msg=No profile information
err.exception.message={0} err.exception.message={0}
err.invalid.path=invalid path: {0} err.invalid.path=invalid path: {0}
err.invalid.module.option=Cannot set {0} with {1} option. err.invalid.module.option=Cannot set {0} with {1} option.
err.invalid.filters=Only one of -package (-p), -regex (-e), -requires option can be set err.invalid.filters=Only one of --package (-p), --regex (-e), --require option can be set
err.module.not.found=module not found: {0} err.module.not.found=module not found: {0}
err.root.module.not.set=root module set empty err.root.module.not.set=root module set empty
err.invalid.inverse.option={0} cannot be used with -inverse option err.invalid.inverse.option={0} cannot be used with --inverse option
err.inverse.filter.not.set={0} cannot be used with -inverse option
err.multirelease.option.exists={0} is not a multi-release jar file, but the --multi-release option is set err.multirelease.option.exists={0} is not a multi-release jar file, but the --multi-release option is set
err.multirelease.option.notfound={0} is a multi-release jar file, but the --multi-release option is not set err.multirelease.option.notfound={0} is a multi-release jar file, but the --multi-release option is not set
err.multirelease.version.associated=class {0} already associated with version {1}, trying to add version {2} err.multirelease.version.associated=class {0} already associated with version {1}, trying to add version {2}
@ -178,7 +184,7 @@ warn.split.package=package {0} defined in {1} {2}
warn.replace.useJDKInternals=\ warn.replace.useJDKInternals=\
JDK internal APIs are unsupported and private to JDK implementation that are\n\ JDK internal APIs are unsupported and private to JDK implementation that are\n\
subject to be removed or changed incompatibly and could break your application.\n\ subject to be removed or changed incompatibly and could break your application.\n\
Please modify your code to eliminate dependency on any JDK internal APIs.\n\ Please modify your code to eliminate dependence on any JDK internal APIs.\n\
For the most recent update on JDK internal API replacements, please check:\n\ For the most recent update on JDK internal API replacements, please check:\n\
{0} {0}

View File

@ -135,7 +135,7 @@ public class APIDeps {
"java.util.Set", "java.util.Set",
"c.C", "d.D", "c.I", "e.E", "m.Bar"}, "c.C", "d.D", "c.I", "e.E", "m.Bar"},
new String[] {"compact1", testDirBasename, mDir.getName()}, new String[] {"compact1", testDirBasename, mDir.getName()},
new String[] {"-classpath", testDir.getPath(), "-verbose", "-P", "-apionly"}); new String[] {"-classpath", testDir.getPath(), "-verbose", "-P", "--api-only"});
return errors; return errors;
} }

View File

@ -116,7 +116,7 @@ public class ShowReplacement {
@Test @Test
public void removedPackage() { public void removedPackage() {
Path file = Paths.get("q", "RemovedPackage.class"); Path file = Paths.get("q", "RemovedPackage.class");
String[] output = JdepsUtil.jdeps("-jdkinternals", CLASSES_DIR.resolve(file).toString()); String[] output = JdepsUtil.jdeps("--jdk-internals", CLASSES_DIR.resolve(file).toString());
int i = 0; int i = 0;
// expect no replacement // expect no replacement
while (i < output.length && !output[i].contains("Suggested Replacement")) { while (i < output.length && !output[i].contains("Suggested Replacement")) {

View File

@ -23,7 +23,7 @@
/* /*
* @test * @test
* @summary Tests jdeps --gen-module-info option * @summary Tests jdeps --generate-module-info option
* @library ../lib * @library ../lib
* @build CompilerUtils JdepsUtil * @build CompilerUtils JdepsUtil
* @modules jdk.jdeps/com.sun.tools.jdeps * @modules jdk.jdeps/com.sun.tools.jdeps
@ -106,7 +106,7 @@ public class GenModuleInfo {
.map(mn -> LIBS_DIR.resolve(mn + ".jar")) .map(mn -> LIBS_DIR.resolve(mn + ".jar"))
.map(Path::toString); .map(Path::toString);
JdepsUtil.jdeps(Stream.concat(Stream.of("--gen-module-info", DEST_DIR.toString()), JdepsUtil.jdeps(Stream.concat(Stream.of("--generate-module-info", DEST_DIR.toString()),
files).toArray(String[]::new)); files).toArray(String[]::new));
// check file exists // check file exists

View File

@ -91,7 +91,7 @@ public class InverseDeps {
@DataProvider(name = "testrequires") @DataProvider(name = "testrequires")
public Object[][] expected1() { public Object[][] expected1() {
return new Object[][] { return new Object[][] {
// -requires and result // --require and result
{ "java.sql", new String[][] { { "java.sql", new String[][] {
new String[] { "java.sql", "m5" }, new String[] { "java.sql", "m5" },
} }
@ -117,7 +117,7 @@ public class InverseDeps {
@Test(dataProvider = "testrequires") @Test(dataProvider = "testrequires")
public void testrequires(String name, String[][] expected) throws Exception { public void testrequires(String name, String[][] expected) throws Exception {
String cmd1 = String.format("jdeps -inverse --module-path %s -requires %s --add-modules %s%n", String cmd1 = String.format("jdeps --inverse --module-path %s --require %s --add-modules %s%n",
MODS_DIR, name, modules.stream().collect(Collectors.joining(","))); MODS_DIR, name, modules.stream().collect(Collectors.joining(",")));
try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd1)) { try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd1)) {
@ -128,7 +128,7 @@ public class InverseDeps {
runJdeps(jdeps, expected); runJdeps(jdeps, expected);
} }
String cmd2 = String.format("jdeps -inverse --module-path %s -requires %s" + String cmd2 = String.format("jdeps --inverse --module-path %s --require %s" +
" --add-modules ALL-MODULE-PATH%n", LIBS_DIR, name); " --add-modules ALL-MODULE-PATH%n", LIBS_DIR, name);
// automatic module // automatic module
@ -164,7 +164,7 @@ public class InverseDeps {
@Test(dataProvider = "testpackage") @Test(dataProvider = "testpackage")
public void testpackage(String name, String[][] expected) throws Exception { public void testpackage(String name, String[][] expected) throws Exception {
String cmd = String.format("jdeps -inverse --module-path %s -package %s --add-modules %s%n", String cmd = String.format("jdeps --inverse --module-path %s -package %s --add-modules %s%n",
MODS_DIR, name, modules.stream().collect(Collectors.joining(","))); MODS_DIR, name, modules.stream().collect(Collectors.joining(",")));
try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd)) { try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd)) {
jdeps.appModulePath(MODS_DIR.toString()) jdeps.appModulePath(MODS_DIR.toString())
@ -195,7 +195,7 @@ public class InverseDeps {
@Test(dataProvider = "testregex") @Test(dataProvider = "testregex")
public void testregex(String name, String[][] expected) throws Exception { public void testregex(String name, String[][] expected) throws Exception {
String cmd = String.format("jdeps -inverse --module-path %s -regex %s --add-modules %s%n", String cmd = String.format("jdeps --inverse --module-path %s -regex %s --add-modules %s%n",
MODS_DIR, name, modules.stream().collect(Collectors.joining(","))); MODS_DIR, name, modules.stream().collect(Collectors.joining(",")));
try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd)) { try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd)) {
@ -240,7 +240,7 @@ public class InverseDeps {
Path jarfile = LIBS_DIR.resolve("m7.jar"); Path jarfile = LIBS_DIR.resolve("m7.jar");
String cmd1 = String.format("jdeps -inverse -classpath %s -regex %s %s%n", String cmd1 = String.format("jdeps --inverse -classpath %s -regex %s %s%n",
cpath, name, jarfile); cpath, name, jarfile);
try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd1)) { try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd1)) {
jdeps.verbose("-verbose:class") jdeps.verbose("-verbose:class")
@ -253,7 +253,7 @@ public class InverseDeps {
Set<Path> paths = modules.stream() Set<Path> paths = modules.stream()
.map(mn -> LIBS_DIR.resolve(mn + ".jar")) .map(mn -> LIBS_DIR.resolve(mn + ".jar"))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
String cmd2 = String.format("jdeps -inverse -regex %s %s%n", name, paths); String cmd2 = String.format("jdeps --inverse -regex %s %s%n", name, paths);
try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd2)) { try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd2)) {
jdeps.verbose("-verbose:class").regex(name); jdeps.verbose("-verbose:class").regex(name);
paths.forEach(jdeps::addRoot); paths.forEach(jdeps::addRoot);

View File

@ -24,7 +24,7 @@
module m3 { module m3 {
requires public java.sql; requires public java.sql;
requires public m2; requires public m2;
requires java.logging; // TODO: --gen-module-info to do transitive reduction requires java.logging; // TODO: --generate-module-info to do transitive reduction
requires public m1; requires public m1;
exports p3; exports p3;
} }