66 /**
67 * The setup for the tool execution
68 */
69 public final class Context {
70 // package name to TypeDictionary
71 private final Map<String, TypeDictionary> tdMap;
72 // The folder path mapping to package name
73 private final Map<Path, String> pkgMap;
74 // The header file parsed
75 private final Map<Path, HeaderFile> headerMap;
76 // The args for parsing C
77 private final List<String> clangArgs;
78 // The set of source header files
79 private final Set<Path> sources;
80 // The list of library names
81 private final List<String> libraryNames;
82 // The list of library paths
83 private final List<String> libraryPaths;
84 // The list of library paths for link checks
85 private final List<String> linkCheckPaths;
86 // Symbol patterns to be excluded
87 private final List<Pattern> excludeSymbols;
88 // generate static forwarder class or not?
89 private boolean genStaticForwarder;
90
91 final PrintWriter out;
92 final PrintWriter err;
93
94 private Predicate<String> symChecker;
95 private Predicate<String> symFilter;
96
97 private final Parser parser;
98
99 private final static String defaultPkg = "jextract.dump";
100 final Logger logger = Logger.getLogger(getClass().getPackage().getName());
101
102 public Context(PrintWriter out, PrintWriter err) {
103 this.tdMap = new HashMap<>();
104 this.pkgMap = new HashMap<>();
105 this.headerMap = new HashMap<>();
106 this.clangArgs = new ArrayList<>();
107 this.sources = new TreeSet<>();
108 this.libraryNames = new ArrayList<>();
109 this.libraryPaths = new ArrayList<>();
110 this.linkCheckPaths = new ArrayList<>();
111 this.excludeSymbols = new ArrayList<>();
112 this.parser = new Parser(out, err, Main.INCLUDE_MACROS);
113 this.out = out;
114 this.err = err;
115 }
116
117 public Context() {
118 this(new PrintWriter(System.out, true), new PrintWriter(System.err, true));
119 }
120
121 TypeDictionary typeDictionaryFor(String pkg) {
122 return tdMap.computeIfAbsent(pkg, p->new TypeDictionary(this, p));
123 }
124
125 void addClangArg(String arg) {
126 clangArgs.add(arg);
127 }
128
129 public void addSource(Path path) {
130 sources.add(path);
131 }
132
133 void addLibraryName(String name) {
134 libraryNames.add(name);
135 }
136
137 void addLibraryPath(String path) {
138 libraryPaths.add(path);
139 }
140
141 void addLinkCheckPath(String path) {
142 linkCheckPaths.add(path);
143 }
144
145 void addExcludeSymbols(String pattern) {
146 excludeSymbols.add(Pattern.compile(pattern));
147 }
148
149 void setGenStaticForwarder(boolean flag) {
150 this.genStaticForwarder = flag;
151 }
152
153 // return the absolute path of the library of given name by searching
154 // in the given array of paths.
155 private static Optional<Path> findLibraryPath(Path[] paths, String libName) {
156 return Arrays.stream(paths).
157 map(p -> p.resolve(System.mapLibraryName(libName))).
158 filter(Files::isRegularFile).map(Path::toAbsolutePath).findFirst();
159 }
160
161 /*
162 * Load the specified shared libraries from the specified paths.
163 *
164 * @param lookup Lookup object of the caller.
201 }
202 return true;
203 } catch (NoSuchMethodException nsme) {
204 return false;
205 }
206 }).findFirst().isPresent());
207 };
208 } catch (UnsatisfiedLinkError ex) {
209 err.println(Main.format("warn.lib.not.found"));
210 symChecker = null;
211 }
212 } else {
213 symChecker = null;
214 }
215 }
216
217 private boolean isSymbolFound(String name) {
218 return symChecker == null? true : symChecker.test(name);
219 }
220
221 private void initSymFilter() {
222 if (!excludeSymbols.isEmpty()) {
223 Pattern[] pats = excludeSymbols.toArray(new Pattern[0]);
224 symFilter = name -> {
225 return Arrays.stream(pats).filter(pat -> pat.matcher(name).matches()).
226 findFirst().isPresent();
227 };
228 } else {
229 symFilter = null;
230 }
231 }
232
233 private boolean isSymbolExcluded(String name) {
234 return symFilter == null? false : symFilter.test(name);
235 }
236
237 /**
238 * Setup a package name for a given folder.
239 *
240 * @param folder The path to the folder, use null to set catch-all.
241 * @param pkg The package name
242 * @return True if the folder is setup successfully. False is a package
243 * has been assigned for the folder.
244 */
245 public boolean usePackageForFolder(Path folder, String pkg) {
246 if (folder != null) {
247 folder = folder.toAbsolutePath();
248 if (!Files.isDirectory(folder)) {
249 folder = folder.getParent();
250 }
251 }
252 String existing = pkgMap.putIfAbsent(folder, pkg);
253 final String finalFolder = (null == folder) ? "all folders not configured" : folder.toString();
254 if (null == existing) {
373 if (sources.contains(p) ||
374 (header.pkgName.equals(main.pkgName))) {
375 logger.config("Code gen for header " + p + " enabled in package " + header.pkgName);
376 header.useCodeFactory(fn.apply(header));
377 }
378 headerMap.put(p, header);
379 }
380 }
381 }
382
383 header.processTree(tree, main, isBuiltIn);
384 }
385
386 public void parse() {
387 parse(header -> genStaticForwarder?
388 new AsmCodeFactoryExt(this, header) : new AsmCodeFactory(this, header));
389 }
390
391 private boolean symbolFilter(Tree tree) {
392 String name = tree.name();
393 if (isSymbolExcluded(name)) {
394 return false;
395 }
396
397 // check for function symbols in libraries & warn missing symbols
398 if (tree instanceof FunctionTree && !isSymbolFound(name)) {
399 err.println(Main.format("warn.symbol.not.found", name));
400 //auto-exclude symbols not found
401 return false;
402 }
403
404 return true;
405 }
406
407 public void parse(Function<HeaderFile, AsmCodeFactory> fn) {
408 initSymChecker();
409 initSymFilter();
410
411 List<HeaderTree> headers = parser.parse(sources, clangArgs);
412 processHeaders(headers, fn);
413 }
414
415 private void processHeaders(List<HeaderTree> headers, Function<HeaderFile, AsmCodeFactory> fn) {
416 headers.stream().
417 map(new TreeFilter(this::symbolFilter)).
418 map(new TypedefHandler()).
419 map(new EmptyNameHandler()).
420 forEach(header -> {
421 HeaderFile hf = headerMap.computeIfAbsent(header.path(), p -> getHeaderFile(p, null));
422 hf.useCodeFactory(fn.apply(hf));
423 logger.info(() -> "Processing header file " + header.path());
424
425 header.declarations().stream()
426 .peek(decl -> logger.finest(
427 () -> "Cursor: " + decl.name() + "@" + decl.USR() + "?" + decl.isDeclaration()))
428 .forEach(decl -> processTree(decl, hf, fn));
429 });
|
66 /**
67 * The setup for the tool execution
68 */
69 public final class Context {
70 // package name to TypeDictionary
71 private final Map<String, TypeDictionary> tdMap;
72 // The folder path mapping to package name
73 private final Map<Path, String> pkgMap;
74 // The header file parsed
75 private final Map<Path, HeaderFile> headerMap;
76 // The args for parsing C
77 private final List<String> clangArgs;
78 // The set of source header files
79 private final Set<Path> sources;
80 // The list of library names
81 private final List<String> libraryNames;
82 // The list of library paths
83 private final List<String> libraryPaths;
84 // The list of library paths for link checks
85 private final List<String> linkCheckPaths;
86 // Symbol patterns to be included
87 private final List<Pattern> includeSymbols;
88 // Symbol patterns to be excluded
89 private final List<Pattern> excludeSymbols;
90 // generate static forwarder class or not?
91 private boolean genStaticForwarder;
92
93 final PrintWriter out;
94 final PrintWriter err;
95
96 private Predicate<String> symChecker;
97 private Predicate<String> includeSymFilter;
98 private Predicate<String> excludeSymFilter;
99
100 private final Parser parser;
101
102 private final static String defaultPkg = "jextract.dump";
103 final Logger logger = Logger.getLogger(getClass().getPackage().getName());
104
105 public Context(PrintWriter out, PrintWriter err) {
106 this.tdMap = new HashMap<>();
107 this.pkgMap = new HashMap<>();
108 this.headerMap = new HashMap<>();
109 this.clangArgs = new ArrayList<>();
110 this.sources = new TreeSet<>();
111 this.libraryNames = new ArrayList<>();
112 this.libraryPaths = new ArrayList<>();
113 this.linkCheckPaths = new ArrayList<>();
114 this.includeSymbols = new ArrayList<>();
115 this.excludeSymbols = new ArrayList<>();
116 this.parser = new Parser(out, err, Main.INCLUDE_MACROS);
117 this.out = out;
118 this.err = err;
119 }
120
121 public Context() {
122 this(new PrintWriter(System.out, true), new PrintWriter(System.err, true));
123 }
124
125 TypeDictionary typeDictionaryFor(String pkg) {
126 return tdMap.computeIfAbsent(pkg, p->new TypeDictionary(this, p));
127 }
128
129 void addClangArg(String arg) {
130 clangArgs.add(arg);
131 }
132
133 public void addSource(Path path) {
134 sources.add(path);
135 }
136
137 void addLibraryName(String name) {
138 libraryNames.add(name);
139 }
140
141 void addLibraryPath(String path) {
142 libraryPaths.add(path);
143 }
144
145 void addLinkCheckPath(String path) {
146 linkCheckPaths.add(path);
147 }
148
149 void addIncludeSymbols(String pattern) {
150 includeSymbols.add(Pattern.compile(pattern));
151 }
152
153 void addExcludeSymbols(String pattern) {
154 excludeSymbols.add(Pattern.compile(pattern));
155 }
156
157 void setGenStaticForwarder(boolean flag) {
158 this.genStaticForwarder = flag;
159 }
160
161 // return the absolute path of the library of given name by searching
162 // in the given array of paths.
163 private static Optional<Path> findLibraryPath(Path[] paths, String libName) {
164 return Arrays.stream(paths).
165 map(p -> p.resolve(System.mapLibraryName(libName))).
166 filter(Files::isRegularFile).map(Path::toAbsolutePath).findFirst();
167 }
168
169 /*
170 * Load the specified shared libraries from the specified paths.
171 *
172 * @param lookup Lookup object of the caller.
209 }
210 return true;
211 } catch (NoSuchMethodException nsme) {
212 return false;
213 }
214 }).findFirst().isPresent());
215 };
216 } catch (UnsatisfiedLinkError ex) {
217 err.println(Main.format("warn.lib.not.found"));
218 symChecker = null;
219 }
220 } else {
221 symChecker = null;
222 }
223 }
224
225 private boolean isSymbolFound(String name) {
226 return symChecker == null? true : symChecker.test(name);
227 }
228
229 private void initSymFilters() {
230 if (!includeSymbols.isEmpty()) {
231 Pattern[] pats = includeSymbols.toArray(new Pattern[0]);
232 includeSymFilter = name -> {
233 return Arrays.stream(pats).filter(pat -> pat.matcher(name).matches()).
234 findFirst().isPresent();
235 };
236 } else {
237 includeSymFilter = null;
238 }
239
240 if (!excludeSymbols.isEmpty()) {
241 Pattern[] pats = excludeSymbols.toArray(new Pattern[0]);
242 excludeSymFilter = name -> {
243 return Arrays.stream(pats).filter(pat -> pat.matcher(name).matches()).
244 findFirst().isPresent();
245 };
246 } else {
247 excludeSymFilter = null;
248 }
249 }
250
251 private boolean isSymbolIncluded(String name) {
252 return includeSymFilter == null? true : includeSymFilter.test(name);
253 }
254
255 private boolean isSymbolExcluded(String name) {
256 return excludeSymFilter == null? false : excludeSymFilter.test(name);
257 }
258
259 /**
260 * Setup a package name for a given folder.
261 *
262 * @param folder The path to the folder, use null to set catch-all.
263 * @param pkg The package name
264 * @return True if the folder is setup successfully. False is a package
265 * has been assigned for the folder.
266 */
267 public boolean usePackageForFolder(Path folder, String pkg) {
268 if (folder != null) {
269 folder = folder.toAbsolutePath();
270 if (!Files.isDirectory(folder)) {
271 folder = folder.getParent();
272 }
273 }
274 String existing = pkgMap.putIfAbsent(folder, pkg);
275 final String finalFolder = (null == folder) ? "all folders not configured" : folder.toString();
276 if (null == existing) {
395 if (sources.contains(p) ||
396 (header.pkgName.equals(main.pkgName))) {
397 logger.config("Code gen for header " + p + " enabled in package " + header.pkgName);
398 header.useCodeFactory(fn.apply(header));
399 }
400 headerMap.put(p, header);
401 }
402 }
403 }
404
405 header.processTree(tree, main, isBuiltIn);
406 }
407
408 public void parse() {
409 parse(header -> genStaticForwarder?
410 new AsmCodeFactoryExt(this, header) : new AsmCodeFactory(this, header));
411 }
412
413 private boolean symbolFilter(Tree tree) {
414 String name = tree.name();
415 if (!isSymbolIncluded(name) || isSymbolExcluded(name)) {
416 return false;
417 }
418
419 // check for function symbols in libraries & warn missing symbols
420 if (tree instanceof FunctionTree && !isSymbolFound(name)) {
421 err.println(Main.format("warn.symbol.not.found", name));
422 //auto-exclude symbols not found
423 return false;
424 }
425
426 return true;
427 }
428
429 public void parse(Function<HeaderFile, AsmCodeFactory> fn) {
430 initSymChecker();
431 initSymFilters();
432
433 List<HeaderTree> headers = parser.parse(sources, clangArgs);
434 processHeaders(headers, fn);
435 }
436
437 private void processHeaders(List<HeaderTree> headers, Function<HeaderFile, AsmCodeFactory> fn) {
438 headers.stream().
439 map(new TreeFilter(this::symbolFilter)).
440 map(new TypedefHandler()).
441 map(new EmptyNameHandler()).
442 forEach(header -> {
443 HeaderFile hf = headerMap.computeIfAbsent(header.path(), p -> getHeaderFile(p, null));
444 hf.useCodeFactory(fn.apply(hf));
445 logger.info(() -> "Processing header file " + header.path());
446
447 header.declarations().stream()
448 .peek(decl -> logger.finest(
449 () -> "Cursor: " + decl.name() + "@" + decl.USR() + "?" + decl.isDeclaration()))
450 .forEach(decl -> processTree(decl, hf, fn));
451 });
|