@@ -4,9 +4,11 @@ const Step = std.Build.Step;
44const Allocator = std .mem .Allocator ;
55
66pub const Style = union (enum ) {
7- /// The configure format supported by autotools. It uses `#undef foo` to
7+ /// A configure format supported by autotools that uses `#undef foo` to
88 /// mark lines that can be substituted with different values.
9- autoconf : std.Build.LazyPath ,
9+ autoconf_undef : std.Build.LazyPath ,
10+ /// A configure format supported by autotools that uses `@FOO@` output variables.
11+ autoconf_at : std.Build.LazyPath ,
1012 /// The configure format supported by CMake. It uses `@FOO@`, `${}` and
1113 /// `#cmakedefine` for template substitution.
1214 cmake : std.Build.LazyPath ,
@@ -17,7 +19,7 @@ pub const Style = union(enum) {
1719
1820 pub fn getPath (style : Style ) ? std.Build.LazyPath {
1921 switch (style ) {
20- .autoconf , .cmake = > | s | return s ,
22+ .autoconf_undef , .autoconf_at , .cmake = > | s | return s ,
2123 .blank , .nasm = > return null ,
2224 }
2325 }
@@ -191,15 +193,19 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
191193 const asm_generated_line = "; " ++ header_text ++ "\n " ;
192194
193195 switch (config_header .style ) {
194- .autoconf = > | file_source | {
196+ .autoconf_undef , .autoconf_at = > | file_source | {
195197 try output .appendSlice (c_generated_line );
196198 const src_path = file_source .getPath2 (b , step );
197199 const contents = std .fs .cwd ().readFileAlloc (arena , src_path , config_header .max_bytes ) catch | err | {
198200 return step .fail ("unable to read autoconf input file '{s}': {s}" , .{
199201 src_path , @errorName (err ),
200202 });
201203 };
202- try render_autoconf (step , contents , & output , config_header .values , src_path );
204+ switch (config_header .style ) {
205+ .autoconf_undef = > try render_autoconf_undef (step , contents , & output , config_header .values , src_path ),
206+ .autoconf_at = > try render_autoconf_at (step , contents , & output , config_header .values , src_path ),
207+ else = > unreachable ,
208+ }
203209 },
204210 .cmake = > | file_source | {
205211 try output .appendSlice (c_generated_line );
@@ -257,7 +263,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
257263 try man .writeManifest ();
258264}
259265
260- fn render_autoconf (
266+ fn render_autoconf_undef (
261267 step : * Step ,
262268 contents : []const u8 ,
263269 output : * std .ArrayList (u8 ),
@@ -304,6 +310,62 @@ fn render_autoconf(
304310 }
305311}
306312
313+ fn render_autoconf_at (
314+ step : * Step ,
315+ contents : []const u8 ,
316+ output : * std .ArrayList (u8 ),
317+ values : std .StringArrayHashMap (Value ),
318+ src_path : []const u8 ,
319+ ) ! void {
320+ const build = step .owner ;
321+ const allocator = build .allocator ;
322+
323+ const used = allocator .alloc (bool , values .count ()) catch @panic ("OOM" );
324+ for (used ) | * u | u .* = false ;
325+ defer allocator .free (used );
326+
327+ var any_errors = false ;
328+ var line_index : u32 = 0 ;
329+ var line_it = std .mem .splitScalar (u8 , contents , '\n ' );
330+ while (line_it .next ()) | line | : (line_index += 1 ) {
331+ const last_line = line_it .index == line_it .buffer .len ;
332+
333+ const old_len = output .items .len ;
334+ expand_variables_autoconf_at (output , line , values , used ) catch | err | switch (err ) {
335+ error .MissingValue = > {
336+ const name = output .items [old_len .. ];
337+ defer output .shrinkRetainingCapacity (old_len );
338+ try step .addError ("{s}:{d}: error: unspecified config header value: '{s}'" , .{
339+ src_path , line_index + 1 , name ,
340+ });
341+ any_errors = true ;
342+ continue ;
343+ },
344+ else = > {
345+ try step .addError ("{s}:{d}: unable to substitute variable: error: {s}" , .{
346+ src_path , line_index + 1 , @errorName (err ),
347+ });
348+ any_errors = true ;
349+ continue ;
350+ },
351+ };
352+ if (! last_line ) {
353+ try output .append ('\n ' );
354+ }
355+ }
356+
357+ for (values .unmanaged .entries .slice ().items (.key ), used ) | name , u | {
358+ if (! u ) {
359+ try step .addError ("{s}: error: config header value unused: '{s}'" , .{ src_path , name });
360+ any_errors = true ;
361+ }
362+ }
363+
364+ if (any_errors ) {
365+ return error .MakeFailed ;
366+ }
367+ }
368+
307369fn render_cmake (
308370 step : * Step ,
309371 contents : []const u8 ,
@@ -536,6 +598,59 @@ fn renderValueNasm(output: *std.ArrayList(u8), name: []const u8, value: Value) !
536598 }
537599}
538600
601+ fn expand_variables_autoconf_at (
602+ output : * std .ArrayList (u8 ),
603+ contents : []const u8 ,
604+ values : std .StringArrayHashMap (Value ),
605+ used : []bool ,
606+ ) ! void {
607+ const valid_varname_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_" ;
608+
609+ var curr : usize = 0 ;
610+ var source_offset : usize = 0 ;
611+ while (curr < contents .len ) : (curr += 1 ) {
612+ if (contents [curr ] != '@' ) continue ;
613+ if (std .mem .indexOfScalarPos (u8 , contents , curr + 1 , '@' )) | close_pos | {
614+ if (close_pos == curr + 1 ) {
615+ // closed immediately, preserve as a literal
616+ continue ;
617+ }
618+ const valid_varname_end = std .mem .indexOfNonePos (u8 , contents , curr + 1 , valid_varname_chars ) orelse 0 ;
619+ if (valid_varname_end != close_pos ) {
620+ // contains invalid characters, preserve as a literal
621+ continue ;
622+ }
623+
624+ const key = contents [curr + 1 .. close_pos ];
625+ const index = values .getIndex (key ) orelse {
626+ // Report the missing key to the caller.
627+ try output .appendSlice (key );
628+ return error .MissingValue ;
629+ };
630+ const value = values .unmanaged .entries .slice ().items (.value )[index ];
631+ used [index ] = true ;
632+ try output .appendSlice (contents [source_offset .. curr ]);
633+ switch (value ) {
634+ .undef , .defined = > {},
635+ .boolean = > | b | {
636+ try output .append (if (b ) '1' else '0' );
637+ },
638+ .int = > | i | {
639+ try output .writer ().print ("{d}" , .{i });
640+ },
641+ .ident , .string = > | s | {
642+ try output .appendSlice (s );
643+ },
644+ }
645+
646+ curr = close_pos ;
647+ source_offset = close_pos + 1 ;
648+ }
649+ }
650+
651+ try output .appendSlice (contents [source_offset .. ]);
652+ }
653+
539654fn expand_variables_cmake (
540655 allocator : Allocator ,
541656 contents : []const u8 ,
0 commit comments