1
1
use std:: {
2
2
borrow:: Cow ,
3
- fmt,
3
+ collections:: { HashMap , HashSet } ,
4
+ fmt:: { self , Write } ,
4
5
fs:: File ,
5
6
io:: BufReader ,
6
7
path:: { Path , PathBuf } ,
7
8
} ;
8
9
9
10
use clang:: {
10
11
Clang ,
12
+ diagnostic:: Diagnostic ,
11
13
diagnostic:: Severity ,
12
14
Entity ,
13
15
EntityKind ,
16
+ EntityVisitResult ,
14
17
Index ,
15
18
TranslationUnit ,
16
19
Type ,
20
+ Unsaved ,
17
21
} ;
18
22
use dunce:: canonicalize;
23
+ use maplit:: hashmap;
24
+ use once_cell:: sync:: Lazy ;
19
25
20
26
use crate :: {
21
27
AbstractRefWrapper ,
22
28
Class ,
29
+ CompiledInterpolation ,
23
30
Const ,
24
31
Element ,
25
32
EntityExt ,
@@ -31,9 +38,11 @@ use crate::{
31
38
GeneratorEnv ,
32
39
get_definition_text,
33
40
line_reader,
41
+ opencv_module_from_path,
34
42
return_type_wrapper:: ReturnTypeWrapper ,
35
43
settings,
36
44
smart_ptr:: SmartPtr ,
45
+ StrExt ,
37
46
type_ref:: Kind as TypeRefKind ,
38
47
Typedef ,
39
48
vector:: Vector ,
@@ -59,6 +68,114 @@ pub trait GeneratorVisitor<'tu> {
59
68
fn visit_typedef ( & mut self , typedef : Typedef ) { }
60
69
fn visit_class ( & mut self , class : Class ) { }
61
70
fn visit_dependent_type ( & mut self , typ : Self :: D ) { }
71
+
72
+ fn visit_ephemeral_header ( & mut self , contents : & str ) { }
73
+ }
74
+
75
+ struct EphemeralGenerator < ' m > {
76
+ module : & ' m str ,
77
+ used_in_smart_ptr : HashSet < String > ,
78
+ descendants : HashMap < String , HashSet < String > > ,
79
+ }
80
+
81
+ impl < ' m > EphemeralGenerator < ' m > {
82
+ pub fn new ( module : & ' m str ) -> Self {
83
+ Self {
84
+ module,
85
+ used_in_smart_ptr : HashSet :: with_capacity ( 32 ) ,
86
+ descendants : HashMap :: with_capacity ( 16 ) ,
87
+ }
88
+ }
89
+
90
+ fn add_used_in_smart_ptr ( & mut self , func : Entity ) {
91
+ for arg in func. get_arguments ( ) . into_iter ( ) . flatten ( ) {
92
+ if let Some ( arg_type) = arg. get_type ( ) {
93
+ if arg_type. get_declaration ( ) . map_or ( false , |ent| ent. cpp_fullname ( ) . starts_with ( "cv::Ptr" ) ) {
94
+ let inner_type_ent = arg_type. get_template_argument_types ( ) . into_iter ( )
95
+ . flatten ( )
96
+ . flatten ( )
97
+ . next ( )
98
+ . and_then ( |t| t. get_declaration ( ) ) ;
99
+ if let Some ( inner_type_ent) = inner_type_ent {
100
+ self . used_in_smart_ptr . insert ( inner_type_ent. cpp_fullname ( ) . into_owned ( ) ) ;
101
+ }
102
+ }
103
+ }
104
+ }
105
+ }
106
+
107
+ pub fn make_generated_header ( & self ) -> String {
108
+ static TPL : Lazy < CompiledInterpolation > = Lazy :: new (
109
+ || include_str ! ( "../tpl/ephemeral/ephemeral.tpl.hpp" ) . compile_interpolation ( )
110
+ ) ;
111
+
112
+ let mut includes = String :: with_capacity ( 128 ) ;
113
+ let mut resolve_types = String :: with_capacity ( 1024 ) ;
114
+ let mut generate_types: Vec < Cow < _ > > = Vec :: with_capacity ( 32 ) ;
115
+
116
+ let mut resolve_types_idx = 0usize ;
117
+ let global_tweaks = settings:: GENERATOR_MODULE_TWEAKS . get ( "*" ) ;
118
+ let module_tweaks = settings:: GENERATOR_MODULE_TWEAKS . get ( self . module ) ;
119
+ for tweak in global_tweaks. iter ( ) . chain ( module_tweaks. iter ( ) ) {
120
+ for & include in & tweak. includes {
121
+ writeln ! ( & mut includes, "#include <opencv2/{}>" , include) . expect ( "Can't fail" ) ;
122
+ }
123
+ for & res_type in & tweak. resolve_types {
124
+ writeln ! ( & mut resolve_types, "typedef {} ephem{};" , res_type, resolve_types_idx) . expect ( "Can't fail" ) ;
125
+ resolve_types_idx += 1 ;
126
+ }
127
+ for & gen_type in & tweak. generate_types {
128
+ generate_types. push ( gen_type. into ( ) ) ;
129
+ }
130
+ }
131
+ for used_cppfull in & self . used_in_smart_ptr {
132
+ for desc_cppfull in self . descendants . get ( used_cppfull) . into_iter ( ) . flatten ( ) {
133
+ if !self . used_in_smart_ptr . contains ( desc_cppfull) {
134
+ generate_types. push ( format ! ( "cv::Ptr<{}>" , desc_cppfull) . into ( ) ) ;
135
+ }
136
+ }
137
+ }
138
+
139
+ TPL . interpolate ( & hashmap ! {
140
+ "includes" => includes,
141
+ "resolve_types" => resolve_types,
142
+ "generate_types" => generate_types. join( ",\n " ) ,
143
+ } )
144
+ }
145
+ }
146
+
147
+ impl EntityWalkerVisitor < ' _ > for & mut EphemeralGenerator < ' _ > {
148
+ fn wants_file ( & mut self , path : & Path ) -> bool {
149
+ opencv_module_from_path ( path) . map_or ( false , |m| m == self . module )
150
+ }
151
+
152
+ fn visit_entity ( & mut self , entity : Entity < ' _ > ) -> bool {
153
+ match entity. get_kind ( ) {
154
+ EntityKind :: ClassDecl | EntityKind :: StructDecl => {
155
+ entity. visit_children ( |c, _| {
156
+ match c. get_kind ( ) {
157
+ EntityKind :: BaseSpecifier => {
158
+ let c_decl = c. get_definition ( ) . expect ( "Can't get base class definition" ) ;
159
+ self . descendants . entry ( c_decl. cpp_fullname ( ) . into_owned ( ) )
160
+ . or_insert_with ( || HashSet :: with_capacity ( 4 ) )
161
+ . insert ( entity. cpp_fullname ( ) . into_owned ( ) ) ;
162
+ }
163
+ EntityKind :: Constructor | EntityKind :: Method | EntityKind :: FunctionTemplate
164
+ | EntityKind :: ConversionFunction => {
165
+ self . add_used_in_smart_ptr ( c)
166
+ }
167
+ _ => { }
168
+ }
169
+ EntityVisitResult :: Continue
170
+ } ) ;
171
+ }
172
+ EntityKind :: FunctionDecl => {
173
+ self . add_used_in_smart_ptr ( entity) ;
174
+ }
175
+ _ => { }
176
+ }
177
+ true
178
+ }
62
179
}
63
180
64
181
#[ derive( Debug ) ]
@@ -349,6 +466,26 @@ impl Generator {
349
466
}
350
467
}
351
468
469
+ fn make_ephemeral_header ( & self , contents : & str ) -> Unsaved {
470
+ Unsaved :: new ( self . src_cpp_dir . join ( "ocvrs_ephemeral.hpp" ) , contents)
471
+ }
472
+
473
+ fn handle_diags ( diags : & [ Diagnostic ] , panic_on_error : bool ) {
474
+ if !diags. is_empty ( ) {
475
+ let mut has_error = false ;
476
+ eprintln ! ( "=== WARNING: {} diagnostic messages" , diags. len( ) ) ;
477
+ for diag in diags {
478
+ if !has_error && matches ! ( diag. get_severity( ) , Severity :: Error | Severity :: Fatal ) {
479
+ has_error = true ;
480
+ }
481
+ eprintln ! ( "=== {}" , diag) ;
482
+ }
483
+ if has_error && panic_on_error {
484
+ panic ! ( "=== Errors during header parsing" ) ;
485
+ }
486
+ }
487
+ }
488
+
352
489
pub fn build_clang_command_line_args ( & self ) -> Vec < Cow < ' static , str > > {
353
490
let mut args = self . clang_include_dirs . iter ( )
354
491
. map ( |d| format ! ( "-isystem{}" , d. to_str( ) . expect( "Incorrect system include path" ) ) . into ( ) )
@@ -357,42 +494,39 @@ impl Generator {
357
494
)
358
495
. collect :: < Vec < _ > > ( ) ;
359
496
args. push ( "-DOCVRS_PARSING_HEADERS" . into ( ) ) ;
360
- args. push ( "-includeocvrs_resolve_types .hpp" . into ( ) ) ;
497
+ args. push ( "-includeocvrs_ephemeral .hpp" . into ( ) ) ;
361
498
// need to have c++14 here because VS headers contain features that require it
362
499
args. push ( "-std=c++14" . into ( ) ) ;
363
500
args
364
501
}
365
502
366
- pub fn process_module ( & self , module : & str , panic_on_error : bool , entity_processor : impl FnOnce ( Entity ) ) {
503
+ pub fn process_module ( & self , module : & str , panic_on_error : bool , entity_processor : impl FnOnce ( TranslationUnit ) ) {
367
504
let index = Index :: new ( & self . clang , true , false ) ;
368
505
let mut module_file = self . src_cpp_dir . join ( format ! ( "{}.hpp" , module) ) ;
369
506
if !module_file. exists ( ) {
370
507
module_file = self . opencv_include_dir . join ( format ! ( "opencv2/{}.hpp" , module) ) ;
371
508
}
372
509
let root_tu: TranslationUnit = index. parser ( module_file)
510
+ . unsaved ( & [ self . make_ephemeral_header ( "" ) ] )
373
511
. arguments ( & self . build_clang_command_line_args ( ) )
374
512
. detailed_preprocessing_record ( true )
375
513
. skip_function_bodies ( true )
376
514
. parse ( ) . expect ( "Cannot parse" ) ;
377
- let diags = root_tu. get_diagnostics ( ) ;
378
- if !diags. is_empty ( ) {
379
- let mut has_error = false ;
380
- eprintln ! ( "=== WARNING: {} diagnostic messages" , diags. len( ) ) ;
381
- for diag in diags {
382
- if !has_error && matches ! ( diag. get_severity( ) , Severity :: Error | Severity :: Fatal ) {
383
- has_error = true ;
384
- }
385
- eprintln ! ( "=== {}" , diag) ;
386
- }
387
- if has_error && panic_on_error {
388
- panic ! ( "=== Errors during header parsing" ) ;
389
- }
390
- }
391
- entity_processor ( root_tu. get_entity ( ) ) ;
515
+ Self :: handle_diags ( & root_tu. get_diagnostics ( ) , panic_on_error) ;
516
+ entity_processor ( root_tu) ;
392
517
}
393
518
394
- pub fn process_opencv_module ( & self , module : & str , visitor : impl for < ' gtu > GeneratorVisitor < ' gtu > ) {
395
- self . process_module ( module, true , |root_entity| {
519
+ pub fn process_opencv_module ( & self , module : & str , mut visitor : impl for < ' gtu > GeneratorVisitor < ' gtu > ) {
520
+ self . process_module ( module, true , |mut root_tu| {
521
+ let mut root_entity = root_tu. get_entity ( ) ;
522
+ let walker = EntityWalker :: new ( root_entity) ;
523
+ let mut ephem_gen = EphemeralGenerator :: new ( module) ;
524
+ walker. walk_opencv_entities ( & mut ephem_gen) ;
525
+ let hdr = ephem_gen. make_generated_header ( ) ;
526
+ visitor. visit_ephemeral_header ( & hdr) ;
527
+ root_tu = root_tu. reparse ( & [ self . make_ephemeral_header ( & hdr) ] ) . expect ( "Can't reparse file" ) ;
528
+ Self :: handle_diags ( & root_tu. get_diagnostics ( ) , true ) ;
529
+ root_entity = root_tu. get_entity ( ) ;
396
530
let gen_env = GeneratorEnv :: new ( root_entity, module) ;
397
531
let opencv_walker = OpenCVWalker :: new (
398
532
& self . opencv_include_dir ,
@@ -405,6 +539,10 @@ impl Generator {
405
539
}
406
540
}
407
541
542
+ pub fn is_ephemeral_header ( path : & Path ) -> bool {
543
+ path. ends_with ( "ocvrs_ephemeral.hpp" )
544
+ }
545
+
408
546
#[ allow( unused) ]
409
547
pub fn dbg_clang_type ( type_ref : Type ) {
410
548
struct TypeWrapper < ' tu > ( Type < ' tu > ) ;
0 commit comments