@@ -13,14 +13,16 @@ pub const Style = union(enum) {
13
13
/// The configure format supported by CMake. It uses `@FOO@`, `${}` and
14
14
/// `#cmakedefine` for template substitution.
15
15
cmake : std.Build.LazyPath ,
16
+ /// Start with input file and replace occurrences of names with their values.
17
+ custom : std.Build.LazyPath ,
16
18
/// Instead of starting with an input file, start with nothing.
17
19
blank ,
18
20
/// Start with nothing, like blank, and output a nasm .asm file.
19
21
nasm ,
20
22
21
23
pub fn getPath (style : Style ) ? std.Build.LazyPath {
22
24
switch (style ) {
23
- .autoconf_undef , .autoconf_at , .cmake = > | s | return s ,
25
+ .autoconf_undef , .autoconf_at , .cmake , .custom = > | s | return s ,
24
26
.blank , .nasm = > return null ,
25
27
}
26
28
}
@@ -237,6 +239,16 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
237
239
try bw .writeAll (asm_generated_line );
238
240
try render_nasm (bw , config_header .values );
239
241
},
242
+ .custom = > | file_source | {
243
+ try bw .writeAll (asm_generated_line );
244
+ const src_path = file_source .getPath2 (b , step );
245
+ const contents = std .fs .cwd ().readFileAlloc (src_path , arena , .limited (config_header .max_bytes )) catch | err | {
246
+ return step .fail ("unable to read custom input file '{s}': {s}" , .{
247
+ src_path , @errorName (err ),
248
+ });
249
+ };
250
+ try render_custom (step , contents , bw , config_header .values );
251
+ },
240
252
}
241
253
242
254
const output = aw .written ();
@@ -545,6 +557,51 @@ fn render_nasm(bw: *Writer, defines: std.StringArrayHashMap(Value)) !void {
545
557
for (defines .keys (), defines .values ()) | name , value | try renderValueNasm (bw , name , value );
546
558
}
547
559
560
+ fn render_custom (
561
+ step : * Step ,
562
+ contents : []const u8 ,
563
+ bw : * Writer ,
564
+ dict : std .StringArrayHashMap (Value ),
565
+ ) ! void {
566
+ const build = step .owner ;
567
+ const allocator = build .allocator ;
568
+
569
+ var contents_copy = try allocator .dupe (u8 , contents );
570
+ defer allocator .free (contents_copy );
571
+
572
+ var any_errors = false ;
573
+ const values = dict .values ();
574
+ for (dict .keys (), 0.. ) | name , x | {
575
+ if (std .mem .indexOf (u8 , contents , name ) == null ) {
576
+ try step .addError ("error: config header value unused: '{s}'" , .{name });
577
+ any_errors = true ;
578
+ continue ;
579
+ }
580
+
581
+ const value = values [x ];
582
+ const value_str : []const u8 = switch (value ) {
583
+ .undef = > continue ,
584
+ .defined = > try allocator .dupe (u8 , "" ),
585
+ .boolean = > | b | try allocator .dupe (u8 , if (b ) "1" else "0" ),
586
+ .int = > | i | try std .fmt .allocPrint (allocator , "{d}" , .{i }),
587
+ .ident = > | ident | try std .fmt .allocPrint (allocator , "{s}" , .{ident }),
588
+ // TODO: use C-specific escaping instead of zig string literals
589
+ .string = > | string | try std .fmt .allocPrint (allocator , "\" {f}\" " , .{std .zig .fmtString (string )}),
590
+ };
591
+ defer allocator .free (value_str );
592
+
593
+ const replaced = try std .mem .replaceOwned (u8 , allocator , contents_copy , name , value_str );
594
+ defer allocator .free (replaced );
595
+
596
+ allocator .free (contents_copy );
597
+ contents_copy = try allocator .dupe (u8 , replaced );
598
+ }
599
+
600
+ try bw .writeAll (contents_copy );
601
+
602
+ if (any_errors ) return error .MakeFailed ;
603
+ }
604
+
548
605
fn renderValueC (bw : * Writer , name : []const u8 , value : Value ) ! void {
549
606
switch (value ) {
550
607
.undef = > try bw .print ("/* #undef {s} */\n " , .{name }),
0 commit comments