Thu, 07 Jun 2012 20:30:57 -0700
7170079: Adjustments to build-infra makefiles
Reviewed-by: ohair, ohrstrom, ihse, jonas
Contributed-by: jonas <jonas.oreland@oracle.com>, erikj <erik.joelsson@oracle.com>, ihse <magnus.ihse.bursie@oracle.com>, tgranat <torbjorn.granat@oracle.com>, ykantser <yekaterina.kantserova@oracle.com>
jjg@1230 | 1 | /* |
jjg@1230 | 2 | * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. |
jjg@1230 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
jjg@1230 | 4 | * |
jjg@1230 | 5 | * This code is free software; you can redistribute it and/or modify it |
jjg@1230 | 6 | * under the terms of the GNU General Public License version 2 only, as |
jjg@1230 | 7 | * published by the Free Software Foundation. |
jjg@1230 | 8 | * |
jjg@1230 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
jjg@1230 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
jjg@1230 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
jjg@1230 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
jjg@1230 | 13 | * accompanied this code). |
jjg@1230 | 14 | * |
jjg@1230 | 15 | * You should have received a copy of the GNU General Public License version |
jjg@1230 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
jjg@1230 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
jjg@1230 | 18 | * |
jjg@1230 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
jjg@1230 | 20 | * or visit www.oracle.com if you need additional information or have any |
jjg@1230 | 21 | * questions. |
jjg@1230 | 22 | */ |
jjg@1230 | 23 | |
jjg@1230 | 24 | /* |
jjg@1230 | 25 | * @test |
jjg@1230 | 26 | * @bug 7150368 |
jjg@1230 | 27 | * @summary javac should include basic ability to generate native headers |
jjg@1230 | 28 | */ |
jjg@1230 | 29 | |
jjg@1230 | 30 | import java.io.File; |
jjg@1230 | 31 | import java.io.FileWriter; |
jjg@1230 | 32 | import java.io.IOException; |
jjg@1230 | 33 | import java.lang.annotation.Annotation; |
jjg@1230 | 34 | import java.lang.annotation.Retention; |
jjg@1230 | 35 | import java.lang.annotation.RetentionPolicy; |
jjg@1230 | 36 | import java.lang.reflect.InvocationTargetException; |
jjg@1230 | 37 | import java.lang.reflect.Method; |
jjg@1230 | 38 | import java.util.ArrayList; |
jjg@1230 | 39 | import java.util.Arrays; |
jjg@1230 | 40 | import java.util.HashSet; |
jjg@1230 | 41 | import java.util.List; |
jjg@1230 | 42 | import java.util.Set; |
jjg@1230 | 43 | |
jjg@1230 | 44 | import javax.tools.StandardJavaFileManager; |
jjg@1230 | 45 | import javax.tools.StandardLocation; |
jjg@1230 | 46 | |
jjg@1230 | 47 | import com.sun.source.util.JavacTask; |
jjg@1230 | 48 | import com.sun.tools.javac.api.JavacTool; |
jjg@1230 | 49 | |
jjg@1230 | 50 | public class NativeHeaderTest { |
jjg@1230 | 51 | public static void main(String... args) throws Exception { |
jjg@1230 | 52 | new NativeHeaderTest().run(); |
jjg@1230 | 53 | } |
jjg@1230 | 54 | |
jjg@1230 | 55 | /** How to invoke javac. */ |
jjg@1230 | 56 | enum RunKind { |
jjg@1230 | 57 | /** Use the command line entry point. */ |
jjg@1230 | 58 | CMD, |
jjg@1230 | 59 | /** Use the JavaCompiler API. */ |
jjg@1230 | 60 | API |
jjg@1230 | 61 | }; |
jjg@1230 | 62 | |
jjg@1230 | 63 | /** Which classes for which to generate headers. */ |
jjg@1230 | 64 | enum GenKind { |
jjg@1230 | 65 | /** Just classes with native methods or the marker annotation. */ |
jjg@1230 | 66 | SIMPLE, |
jjg@1230 | 67 | /** All appropriate classes within the top level class. */ |
jjg@1230 | 68 | FULL |
jjg@1230 | 69 | }; |
jjg@1230 | 70 | |
jjg@1230 | 71 | // ---------- Test cases, invoked reflectively via run. ---------- |
jjg@1230 | 72 | |
jjg@1230 | 73 | @Test |
jjg@1230 | 74 | void simpleTest(RunKind rk, GenKind gk) throws Exception { |
jjg@1230 | 75 | List<File> files = new ArrayList<File>(); |
jjg@1230 | 76 | files.add(createFile("p/C.java", |
jjg@1230 | 77 | "class C { native void m(); }")); |
jjg@1230 | 78 | |
jjg@1230 | 79 | Set<String> expect = createSet("C.h"); |
jjg@1230 | 80 | |
jjg@1230 | 81 | test(rk, gk, files, expect); |
jjg@1230 | 82 | } |
jjg@1230 | 83 | |
jjg@1230 | 84 | @Test |
jjg@1230 | 85 | void nestedClassTest(RunKind rk, GenKind gk) throws Exception { |
jjg@1230 | 86 | List<File> files = new ArrayList<File>(); |
jjg@1230 | 87 | files.add(createFile("p/C.java", |
jjg@1230 | 88 | "class C { static class Inner { native void m(); } }")); |
jjg@1230 | 89 | |
jjg@1230 | 90 | Set<String> expect = createSet("C_Inner.h"); |
jjg@1230 | 91 | if (gk == GenKind.FULL) expect.add("C.h"); |
jjg@1230 | 92 | |
jjg@1230 | 93 | test(rk, gk, files, expect); |
jjg@1230 | 94 | } |
jjg@1230 | 95 | |
jjg@1230 | 96 | @Test |
jjg@1230 | 97 | void localClassTest(RunKind rk, GenKind gk) throws Exception { |
jjg@1230 | 98 | List<File> files = new ArrayList<File>(); |
jjg@1230 | 99 | files.add(createFile("p/C.java", |
jjg@1230 | 100 | "class C { native void m(); void m2() { class Local { } } }")); |
jjg@1230 | 101 | |
jjg@1230 | 102 | Set<String> expect = createSet("C.h"); |
jjg@1230 | 103 | |
jjg@1230 | 104 | test(rk, gk, files, expect); |
jjg@1230 | 105 | } |
jjg@1230 | 106 | |
jjg@1230 | 107 | @Test |
jjg@1230 | 108 | void syntheticClassTest(RunKind rk, GenKind gk) throws Exception { |
jjg@1230 | 109 | List<File> files = new ArrayList<File>(); |
jjg@1230 | 110 | files.add(createFile("p/C.java", |
jjg@1230 | 111 | "class C {\n" |
jjg@1230 | 112 | + " private C() { }\n" |
jjg@1230 | 113 | + " class Inner extends C { native void m(); }\n" |
jjg@1230 | 114 | + "}")); |
jjg@1230 | 115 | |
jjg@1230 | 116 | Set<String> expect = createSet("C_Inner.h"); |
jjg@1230 | 117 | if (gk == GenKind.FULL) expect.add("C.h"); |
jjg@1230 | 118 | |
jjg@1230 | 119 | test(rk, gk, files, expect); |
jjg@1230 | 120 | |
jjg@1230 | 121 | // double check the synthetic class was generated |
jjg@1230 | 122 | checkEqual("generatedClasses", |
jjg@1230 | 123 | createSet("C.class", "C$1.class", "C$Inner.class"), |
jjg@1230 | 124 | createSet(classesDir.list())); |
jjg@1230 | 125 | } |
jjg@1230 | 126 | |
jjg@1230 | 127 | @Test |
jjg@1230 | 128 | void annoTest(RunKind rk, GenKind gk) throws Exception { |
jjg@1230 | 129 | List<File> files = new ArrayList<File>(); |
jjg@1230 | 130 | files.add(createFile("p/C.java", |
jjg@1230 | 131 | "@javax.tools.annotation.GenerateNativeHeader class C { }")); |
jjg@1230 | 132 | |
jjg@1230 | 133 | Set<String> expect = createSet("C.h"); |
jjg@1230 | 134 | |
jjg@1230 | 135 | test(rk, gk, files, expect); |
jjg@1230 | 136 | } |
jjg@1230 | 137 | |
jjg@1230 | 138 | @Test |
jjg@1230 | 139 | void annoNestedClassTest(RunKind rk, GenKind gk) throws Exception { |
jjg@1230 | 140 | List<File> files = new ArrayList<File>(); |
jjg@1230 | 141 | files.add(createFile("p/C.java", |
jjg@1230 | 142 | "class C { @javax.tools.annotation.GenerateNativeHeader class Inner { } }")); |
jjg@1230 | 143 | |
jjg@1230 | 144 | Set<String> expect = createSet("C_Inner.h"); |
jjg@1230 | 145 | if (gk == GenKind.FULL) expect.add("C.h"); |
jjg@1230 | 146 | |
jjg@1230 | 147 | test(rk, gk, files, expect); |
jjg@1230 | 148 | } |
jjg@1230 | 149 | |
jjg@1230 | 150 | /** |
jjg@1230 | 151 | * The worker method for each test case. |
jjg@1230 | 152 | * Compile the files and verify that exactly the expected set of header files |
jjg@1230 | 153 | * is generated. |
jjg@1230 | 154 | */ |
jjg@1230 | 155 | void test(RunKind rk, GenKind gk, List<File> files, Set<String> expect) throws Exception { |
jjg@1230 | 156 | List<String> args = new ArrayList<String>(); |
jjg@1230 | 157 | if (gk == GenKind.FULL) |
jjg@1230 | 158 | args.add("-XDjavah:full"); |
jjg@1230 | 159 | |
jjg@1230 | 160 | switch (rk) { |
jjg@1230 | 161 | case CMD: |
jjg@1230 | 162 | args.add("-d"); |
jjg@1230 | 163 | args.add(classesDir.getPath()); |
jjg@1230 | 164 | args.add("-h"); |
jjg@1230 | 165 | args.add(headersDir.getPath()); |
jjg@1230 | 166 | for (File f: files) |
jjg@1230 | 167 | args.add(f.getPath()); |
jjg@1230 | 168 | int rc = com.sun.tools.javac.Main.compile(args.toArray(new String[args.size()])); |
jjg@1230 | 169 | if (rc != 0) |
jjg@1230 | 170 | throw new Exception("compilation failed, rc=" + rc); |
jjg@1230 | 171 | break; |
jjg@1230 | 172 | |
jjg@1230 | 173 | case API: |
jjg@1230 | 174 | fm.setLocation(StandardLocation.SOURCE_PATH, Arrays.asList(srcDir)); |
jjg@1230 | 175 | fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(classesDir)); |
jjg@1230 | 176 | fm.setLocation(StandardLocation.NATIVE_HEADER_OUTPUT, Arrays.asList(headersDir)); |
jjg@1230 | 177 | JavacTask task = javac.getTask(null, fm, null, args, null, |
jjg@1230 | 178 | fm.getJavaFileObjectsFromFiles(files)); |
jjg@1230 | 179 | if (!task.call()) |
jjg@1230 | 180 | throw new Exception("compilation failed"); |
jjg@1230 | 181 | break; |
jjg@1230 | 182 | } |
jjg@1230 | 183 | |
jjg@1230 | 184 | Set<String> found = createSet(headersDir.list()); |
jjg@1230 | 185 | checkEqual("header files", expect, found); |
jjg@1230 | 186 | } |
jjg@1230 | 187 | |
jjg@1230 | 188 | /** Marker annotation for test cases. */ |
jjg@1230 | 189 | @Retention(RetentionPolicy.RUNTIME) |
jjg@1230 | 190 | @interface Test { } |
jjg@1230 | 191 | |
jjg@1230 | 192 | /** Combo test to run all test cases in all modes. */ |
jjg@1230 | 193 | void run() throws Exception { |
jjg@1230 | 194 | javac = JavacTool.create(); |
jjg@1230 | 195 | fm = javac.getStandardFileManager(null, null, null); |
jjg@1230 | 196 | |
jjg@1230 | 197 | for (RunKind rk: RunKind.values()) { |
jjg@1230 | 198 | for (GenKind gk: GenKind.values()) { |
jjg@1230 | 199 | for (Method m: getClass().getDeclaredMethods()) { |
jjg@1230 | 200 | Annotation a = m.getAnnotation(Test.class); |
jjg@1230 | 201 | if (a != null) { |
jjg@1230 | 202 | init(rk, gk, m.getName()); |
jjg@1230 | 203 | try { |
jjg@1230 | 204 | m.invoke(this, new Object[] { rk, gk }); |
jjg@1230 | 205 | } catch (InvocationTargetException e) { |
jjg@1230 | 206 | Throwable cause = e.getCause(); |
jjg@1230 | 207 | throw (cause instanceof Exception) ? ((Exception) cause) : e; |
jjg@1230 | 208 | } |
jjg@1230 | 209 | System.err.println(); |
jjg@1230 | 210 | } |
jjg@1230 | 211 | } |
jjg@1230 | 212 | } |
jjg@1230 | 213 | } |
jjg@1230 | 214 | System.err.println(testCount + " tests" + ((errorCount == 0) ? "" : ", " + errorCount + " errors")); |
jjg@1230 | 215 | if (errorCount > 0) |
jjg@1230 | 216 | throw new Exception(errorCount + " errors found"); |
jjg@1230 | 217 | } |
jjg@1230 | 218 | |
jjg@1230 | 219 | /** |
jjg@1230 | 220 | * Init directories for a test case. |
jjg@1230 | 221 | */ |
jjg@1230 | 222 | void init(RunKind rk, GenKind gk, String name) throws IOException { |
jjg@1230 | 223 | System.err.println("Test " + rk + " " + gk + " " + name); |
jjg@1230 | 224 | testCount++; |
jjg@1230 | 225 | |
jjg@1230 | 226 | testDir = new File(rk.toString().toLowerCase() + "_" + gk.toString().toLowerCase() + "-" + name); |
jjg@1230 | 227 | srcDir = new File(testDir, "src"); |
jjg@1230 | 228 | srcDir.mkdirs(); |
jjg@1230 | 229 | classesDir = new File(testDir, "classes"); |
jjg@1230 | 230 | classesDir.mkdirs(); |
jjg@1230 | 231 | headersDir = new File(testDir, "headers"); |
jjg@1230 | 232 | headersDir.mkdirs(); |
jjg@1230 | 233 | } |
jjg@1230 | 234 | |
jjg@1230 | 235 | /** Create a source file with given body text. */ |
jjg@1230 | 236 | File createFile(String path, final String body) throws IOException { |
jjg@1230 | 237 | File f = new File(srcDir, path); |
jjg@1230 | 238 | f.getParentFile().mkdirs(); |
jjg@1230 | 239 | try (FileWriter out = new FileWriter(f)) { |
jjg@1230 | 240 | out.write(body); |
jjg@1230 | 241 | } |
jjg@1230 | 242 | return f; |
jjg@1230 | 243 | } |
jjg@1230 | 244 | |
jjg@1230 | 245 | /** Convenience method to create a set of items. */ |
jjg@1230 | 246 | <T> Set<T> createSet(T... items) { |
jjg@1230 | 247 | return new HashSet<T>(Arrays.asList(items)); |
jjg@1230 | 248 | } |
jjg@1230 | 249 | |
jjg@1230 | 250 | /** Convenience method to check two values are equal, and report an error if not. */ |
jjg@1230 | 251 | <T> void checkEqual(String label, T expect, T found) { |
jjg@1230 | 252 | if ((found == null) ? (expect == null) : found.equals(expect)) |
jjg@1230 | 253 | return; |
jjg@1230 | 254 | System.err.println("Error: mismatch"); |
jjg@1230 | 255 | System.err.println(" expected: " + expect); |
jjg@1230 | 256 | System.err.println(" found: " + found); |
jjg@1230 | 257 | errorCount++; |
jjg@1230 | 258 | } |
jjg@1230 | 259 | |
jjg@1230 | 260 | // Shared across API test cases |
jjg@1230 | 261 | JavacTool javac; |
jjg@1230 | 262 | StandardJavaFileManager fm; |
jjg@1230 | 263 | |
jjg@1230 | 264 | // Directories set up by init |
jjg@1230 | 265 | File testDir; |
jjg@1230 | 266 | File srcDir; |
jjg@1230 | 267 | File classesDir; |
jjg@1230 | 268 | File headersDir; |
jjg@1230 | 269 | |
jjg@1230 | 270 | // Statistics |
jjg@1230 | 271 | int testCount; |
jjg@1230 | 272 | int errorCount; |
jjg@1230 | 273 | } |
jjg@1230 | 274 |