9
9
#![ deny( clippy:: perf) ]
10
10
#![ deny( clippy:: style) ]
11
11
12
+ use core:: fmt;
12
13
use proc_macro:: { token_stream, Delimiter , Group , TokenStream , TokenTree } ;
13
14
14
15
fn try_ident ( it : & mut token_stream:: IntoIter ) -> Option < String > {
@@ -119,93 +120,6 @@ fn get_byte_string(it: &mut token_stream::IntoIter, expected_name: &str) -> Stri
119
120
byte_string
120
121
}
121
122
122
- fn __build_modinfo_string_base (
123
- module : & str ,
124
- field : & str ,
125
- content : & str ,
126
- variable : & str ,
127
- builtin : bool ,
128
- ) -> String {
129
- let string = if builtin {
130
- // Built-in modules prefix their modinfo strings by `module.`.
131
- format ! (
132
- "{module}.{field}={content}" ,
133
- module = module,
134
- field = field,
135
- content = content
136
- )
137
- } else {
138
- // Loadable modules' modinfo strings go as-is.
139
- format ! ( "{field}={content}" , field = field, content = content)
140
- } ;
141
-
142
- format ! (
143
- "
144
- {cfg}
145
- #[link_section = \" .modinfo\" ]
146
- #[used]
147
- pub static {variable}: [u8; {length}] = *b\" {string}\\ 0\" ;
148
- " ,
149
- cfg = if builtin {
150
- "#[cfg(not(MODULE))]"
151
- } else {
152
- "#[cfg(MODULE)]"
153
- } ,
154
- variable = variable,
155
- length = string. len( ) + 1 ,
156
- string = string,
157
- )
158
- }
159
-
160
- fn __build_modinfo_string_variable ( module : & str , field : & str ) -> String {
161
- format ! ( "__{module}_{field}" , module = module, field = field)
162
- }
163
-
164
- fn build_modinfo_string_only_builtin ( module : & str , field : & str , content : & str ) -> String {
165
- __build_modinfo_string_base (
166
- module,
167
- field,
168
- content,
169
- & __build_modinfo_string_variable ( module, field) ,
170
- true ,
171
- )
172
- }
173
-
174
- fn build_modinfo_string_only_loadable ( module : & str , field : & str , content : & str ) -> String {
175
- __build_modinfo_string_base (
176
- module,
177
- field,
178
- content,
179
- & __build_modinfo_string_variable ( module, field) ,
180
- false ,
181
- )
182
- }
183
-
184
- fn build_modinfo_string ( module : & str , field : & str , content : & str ) -> String {
185
- build_modinfo_string_only_builtin ( module, field, content)
186
- + & build_modinfo_string_only_loadable ( module, field, content)
187
- }
188
-
189
- fn build_modinfo_string_optional ( module : & str , field : & str , content : Option < & str > ) -> String {
190
- if let Some ( content) = content {
191
- build_modinfo_string ( module, field, content)
192
- } else {
193
- "" . to_string ( )
194
- }
195
- }
196
-
197
- fn build_modinfo_string_param ( module : & str , field : & str , param : & str , content : & str ) -> String {
198
- let variable = format ! (
199
- "__{module}_{field}_{param}" ,
200
- module = module,
201
- field = field,
202
- param = param
203
- ) ;
204
- let content = format ! ( "{param}:{content}" , param = param, content = content) ;
205
- __build_modinfo_string_base ( module, field, & content, & variable, true )
206
- + & __build_modinfo_string_base ( module, field, & content, & variable, false )
207
- }
208
-
209
123
fn permissions_are_readonly ( perms : & str ) -> bool {
210
124
let ( radix, digits) = if let Some ( n) = perms. strip_prefix ( "0x" ) {
211
125
( 16 , n)
@@ -307,6 +221,118 @@ fn generated_array_ops_name(vals: &str, max_length: usize) -> String {
307
221
)
308
222
}
309
223
224
+ struct ModuleInfoStringBuilder < ' a > {
225
+ counter : usize ,
226
+ module : & ' a str ,
227
+ }
228
+
229
+ impl < ' a > ModuleInfoStringBuilder < ' a > {
230
+ fn new ( module_str : & ' a str ) -> ModuleInfoStringBuilder < ' a > {
231
+ ModuleInfoStringBuilder {
232
+ module : module_str,
233
+ counter : 0 ,
234
+ }
235
+ }
236
+
237
+ fn build_modinfo_string_base (
238
+ & self ,
239
+ field : & str ,
240
+ content : & str ,
241
+ variable : & str ,
242
+ builtin : bool ,
243
+ ) -> String {
244
+ let string = if builtin {
245
+ // Built-in modules prefix their modinfo strings by `module.`.
246
+ format ! (
247
+ "{module}.{field}={content}" ,
248
+ module = self . module,
249
+ field = field,
250
+ content = content
251
+ )
252
+ } else {
253
+ // Loadable modules' modinfo strings go as-is.
254
+ format ! ( "{field}={content}" , field = field, content = content)
255
+ } ;
256
+
257
+ format ! (
258
+ "
259
+ {cfg}
260
+ #[link_section = \" .modinfo\" ]
261
+ #[used]
262
+ pub static {variable}: [u8; {length}] = *b\" {string}\\ 0\" ;
263
+ " ,
264
+ cfg = if builtin {
265
+ "#[cfg(not(MODULE))]"
266
+ } else {
267
+ "#[cfg(MODULE)]"
268
+ } ,
269
+ variable = variable,
270
+ length = string. len( ) + 1 ,
271
+ string = string,
272
+ )
273
+ }
274
+
275
+ fn build_modinfo_string_variable ( & mut self , field : & str ) -> String {
276
+ self . counter += 1 ;
277
+ format ! (
278
+ "__{module}_{field}{counter}" ,
279
+ module = self . module,
280
+ field = field,
281
+ counter = self . counter,
282
+ )
283
+ }
284
+
285
+ fn build_modinfo_string_only_builtin ( & mut self , field : & str , content : & str ) -> String {
286
+ let str_var = self . build_modinfo_string_variable ( field) ;
287
+ self . build_modinfo_string_base ( field, content, & str_var, true )
288
+ }
289
+
290
+ fn build_modinfo_string_only_loadable ( & mut self , field : & str , content : & str ) -> String {
291
+ let str_var = self . build_modinfo_string_variable ( field) ;
292
+ self . build_modinfo_string_base ( field, content, & str_var, false )
293
+ }
294
+
295
+ fn build_modinfo_string ( & mut self , field : & str , content : & str ) -> String {
296
+ self . build_modinfo_string_only_builtin ( field, content)
297
+ + & self . build_modinfo_string_only_loadable ( field, content)
298
+ }
299
+
300
+ fn build_modinfo_string_optional ( & mut self , field : & str , content : Option < & str > ) -> String {
301
+ if let Some ( content) = content {
302
+ self . build_modinfo_string ( field, content)
303
+ } else {
304
+ "" . to_string ( )
305
+ }
306
+ }
307
+
308
+ fn build_modinfo_string_param ( & mut self , field : & str , param : & str , content : & str ) -> String {
309
+ let variable = format ! (
310
+ "__{module}_{field}_{param}" ,
311
+ module = self . module,
312
+ field = field,
313
+ param = param
314
+ ) ;
315
+ let content = format ! ( "{param}:{content}" , param = param, content = content) ;
316
+ self . build_modinfo_string_base ( field, & content, & variable, true )
317
+ + & self . build_modinfo_string_base ( field, & content, & variable, false )
318
+ }
319
+ }
320
+
321
+ #[ derive( Debug ) ]
322
+ enum Softdep {
323
+ Pre ( String ) ,
324
+ Post ( String ) ,
325
+ }
326
+
327
+ impl fmt:: Display for Softdep {
328
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
329
+ match self {
330
+ Softdep :: Pre ( ref module) => write ! ( f, "pre: {}" , module) ,
331
+ Softdep :: Post ( ref module) => write ! ( f, "post: {}" , module) ,
332
+ }
333
+ }
334
+ }
335
+
310
336
#[ derive( Debug , Default ) ]
311
337
struct ModuleInfo {
312
338
type_ : String ,
@@ -316,6 +342,7 @@ struct ModuleInfo {
316
342
description : Option < String > ,
317
343
alias : Option < String > ,
318
344
params : Option < Group > ,
345
+ softdeps : Option < Vec < Softdep > > ,
319
346
}
320
347
321
348
impl ModuleInfo {
@@ -331,6 +358,7 @@ impl ModuleInfo {
331
358
"alias" ,
332
359
"alias_rtnl_link" ,
333
360
"params" ,
361
+ "softdeps" ,
334
362
] ;
335
363
const REQUIRED_KEYS : & [ & str ] = & [ "type" , "name" , "license" ] ;
336
364
let mut seen_keys = Vec :: new ( ) ;
@@ -362,6 +390,9 @@ impl ModuleInfo {
362
390
info. alias = Some ( format ! ( "rtnl-link-{}" , expect_byte_string( it) ) )
363
391
}
364
392
"params" => info. params = Some ( expect_group ( it) ) ,
393
+ "softdeps" => {
394
+ info. softdeps = Some ( Self :: parse_softdeps ( expect_group ( it) ) ) ;
395
+ }
365
396
_ => panic ! (
366
397
"Unknown key \" {}\" . Valid keys are: {:?}." ,
367
398
key, EXPECTED_KEYS
@@ -397,6 +428,44 @@ impl ModuleInfo {
397
428
398
429
info
399
430
}
431
+
432
+ fn parse_softdeps ( group : Group ) -> Vec < Softdep > {
433
+ assert_eq ! ( group. delimiter( ) , Delimiter :: Brace ) ;
434
+
435
+ let mut it = group. stream ( ) . into_iter ( ) ;
436
+
437
+ let mut res = vec ! [ ] ;
438
+
439
+ while let Some ( order) = try_ident ( & mut it) {
440
+ res. push ( Self :: parse_softdep ( & mut it, & order) ) ;
441
+ }
442
+
443
+ expect_end ( & mut it) ;
444
+
445
+ res
446
+ }
447
+
448
+ fn parse_softdep ( it : & mut token_stream:: IntoIter , order : & str ) -> Softdep {
449
+ assert_eq ! ( expect_punct( it) , ':' ) ;
450
+ let module = expect_ident ( it) ;
451
+ let softdep = match & * order {
452
+ "pre" => Softdep :: Pre ( module) ,
453
+ "post" => Softdep :: Post ( module) ,
454
+ _ => panic ! ( "failed to parse invalid softdep '{}: {}" , order, module) ,
455
+ } ;
456
+ assert_eq ! ( expect_punct( it) , ',' ) ;
457
+ softdep
458
+ }
459
+
460
+ fn encode_softdeps < ' a > ( & self , str_builder : & mut ModuleInfoStringBuilder < ' a > ) -> String {
461
+ match self . softdeps {
462
+ Some ( ref softdeps) => softdeps. iter ( ) . fold ( String :: new ( ) , |mut acc, new| {
463
+ acc. push_str ( & str_builder. build_modinfo_string ( "softdep" , & format ! ( "{}" , new) ) ) ;
464
+ acc
465
+ } ) ,
466
+ None => String :: new ( ) ,
467
+ }
468
+ }
400
469
}
401
470
402
471
/// Declares a kernel module.
@@ -483,11 +552,14 @@ pub fn module(ts: TokenStream) -> TokenStream {
483
552
let mut it = ts. into_iter ( ) ;
484
553
485
554
let info = ModuleInfo :: parse ( & mut it) ;
555
+ let mut str_builder = ModuleInfoStringBuilder :: new ( & info. name ) ;
486
556
487
557
let name = info. name . clone ( ) ;
488
558
489
559
let mut array_types_to_generate = Vec :: new ( ) ;
490
560
let mut params_modinfo = String :: new ( ) ;
561
+ let softdeps = info. encode_softdeps ( & mut str_builder) ;
562
+
491
563
if let Some ( params) = info. params {
492
564
assert_eq ! ( params. delimiter( ) , Delimiter :: Brace ) ;
493
565
@@ -532,14 +604,12 @@ pub fn module(ts: TokenStream) -> TokenStream {
532
604
}
533
605
} ;
534
606
535
- params_modinfo. push_str ( & build_modinfo_string_param (
536
- & name,
607
+ params_modinfo. push_str ( & str_builder. build_modinfo_string_param (
537
608
"parmtype" ,
538
609
& param_name,
539
610
& param_kernel_type,
540
611
) ) ;
541
- params_modinfo. push_str ( & build_modinfo_string_param (
542
- & name,
612
+ params_modinfo. push_str ( & str_builder. build_modinfo_string_param (
543
613
"parm" ,
544
614
& param_name,
545
615
& param_description,
@@ -761,16 +831,18 @@ pub fn module(ts: TokenStream) -> TokenStream {
761
831
{params_modinfo}
762
832
763
833
{generated_array_types}
834
+ {softdeps}
764
835
" ,
765
836
type_ = info. type_,
766
837
name = info. name,
767
- author = & build_modinfo_string_optional( & name , "author" , info. author. as_deref( ) ) ,
768
- description = & build_modinfo_string_optional( & name , "description" , info. description. as_deref( ) ) ,
769
- license = & build_modinfo_string( & name , "license" , & info. license) ,
770
- alias = & build_modinfo_string_optional( & name , "alias" , info. alias. as_deref( ) ) ,
771
- file = & build_modinfo_string_only_builtin( & name , "file" , & file) ,
838
+ author = & str_builder . build_modinfo_string_optional( "author" , info. author. as_deref( ) ) ,
839
+ description = & str_builder . build_modinfo_string_optional( "description" , info. description. as_deref( ) ) ,
840
+ license = & str_builder . build_modinfo_string( "license" , & info. license) ,
841
+ alias = & str_builder . build_modinfo_string_optional( "alias" , info. alias. as_deref( ) ) ,
842
+ file = & str_builder . build_modinfo_string_only_builtin( "file" , & file) ,
772
843
params_modinfo = params_modinfo,
773
844
generated_array_types = generated_array_types,
845
+ softdeps = softdeps,
774
846
initcall_section = ".initcall6.init"
775
847
) . parse ( ) . expect ( "Error parsing formatted string into token stream." )
776
848
}
0 commit comments