From 0c6e4559611cf17f5b328e891d0a11a9f2bc8ee9 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sat, 3 Jan 2026 01:03:00 -0600 Subject: [PATCH] scripts: test.py/bench.py: Allowed expressions in ifdefs/ifndefs This extends our ifdef/ifndef test attributes to support more complicated logic expressions. So far we haven't really needed this (ifdef/ifndef accepts an implicitly anded list, which has covered everything so far), but I realized there's a simple trick to make this work. For example, in test.toml: ifdef = 'A && !(B || C)' Generated ifdef: #if (defined(A) && !(defined(B) || defined(C))) This doesn't require complex parsing or anything, just a simple regex: s/[a-zA-Z_0-9]\+/defined(&)/g Is using #if defined(A) everywhere instead of #ifdef A more expensive for the compiler? Not sure. But it seems like we're heavily dominated by the single-threaded link time, so I'm not sure we care. --- scripts/bench.py | 40 ++++++++++++++++++++++++++++++---------- scripts/test.py | 40 ++++++++++++++++++++++++++++++---------- 2 files changed, 60 insertions(+), 20 deletions(-) diff --git a/scripts/bench.py b/scripts/bench.py index 7fc3aac2..bba5d3d9 100755 --- a/scripts/bench.py +++ b/scripts/bench.py @@ -402,9 +402,13 @@ def compile(bench_paths, **args): # write any ifdef prologues if case.ifdef or case.ifndef: for ifdef in case.ifdef: - f.writeln('#ifdef %s' % ifdef) + f.writeln('#if (%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifdef)) for ifndef in case.ifndef: - f.writeln('#ifndef %s' % ifndef) + f.writeln('#if !(%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifndef)) f.writeln() # create case define functions @@ -474,9 +478,13 @@ def compile(bench_paths, **args): # write any ifdef prologues if suite.ifdef or suite.ifndef: for ifdef in suite.ifdef: - f.writeln('#ifdef %s' % ifdef) + f.writeln('#if (%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifdef)) for ifndef in suite.ifndef: - f.writeln('#ifndef %s' % ifndef) + f.writeln('#if !(%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifndef)) f.writeln() # write any suite defines @@ -534,9 +542,13 @@ def compile(bench_paths, **args): 'BENCH_INTERNAL' if suite.internal else None])) or 0)) for ifdef in suite.ifdef: - f.writeln(4*' '+'#ifdef %s' % ifdef) + f.writeln(4*' '+'#if (%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifdef)) for ifndef in suite.ifndef: - f.writeln(4*' '+'#ifndef %s' % ifndef) + f.writeln(4*' '+'#if !(%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifndef)) # create suite defines if suite.defines: f.writeln(4*' '+'.defines = (const bench_define_t[]){') @@ -562,9 +574,13 @@ def compile(bench_paths, **args): else None])) or 0)) for ifdef in it.chain(suite.ifdef, case.ifdef): - f.writeln(12*' '+'#ifdef %s' % ifdef) + f.writeln(12*' '+'#if (%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifdef)) for ifndef in it.chain(suite.ifndef, case.ifndef): - f.writeln(12*' '+'#ifndef %s' % ifndef) + f.writeln(12*' '+'#if !(%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifndef)) # create case defines if case.defines: f.writeln(12*' '+'.defines' @@ -633,9 +649,13 @@ def compile(bench_paths, **args): # any ifdef prologues if suite.ifdef or suite.ifndef: for ifdef in suite.ifdef: - f.writeln('#ifdef %s' % ifdef) + f.writeln('#if (%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifdef)) for ifndef in suite.ifndef: - f.writeln('#ifndef %s' % ifndef) + f.writeln('#if !(%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifndef)) f.writeln() # any suite code diff --git a/scripts/test.py b/scripts/test.py index 51a9801b..34be6ea8 100755 --- a/scripts/test.py +++ b/scripts/test.py @@ -414,9 +414,13 @@ def compile(test_paths, **args): # write any ifdef prologues if case.ifdef or case.ifndef: for ifdef in case.ifdef: - f.writeln('#ifdef %s' % ifdef) + f.writeln('#if (%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifdef)) for ifndef in case.ifndef: - f.writeln('#ifndef %s' % ifndef) + f.writeln('#if !(%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifndef)) f.writeln() # create case define functions @@ -486,9 +490,13 @@ def compile(test_paths, **args): # write any ifdef prologues if suite.ifdef or suite.ifndef: for ifdef in suite.ifdef: - f.writeln('#ifdef %s' % ifdef) + f.writeln('#if (%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifdef)) for ifndef in suite.ifndef: - f.writeln('#ifndef %s' % ifndef) + f.writeln('#if !(%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifndef)) f.writeln() # write any suite defines @@ -548,9 +556,13 @@ def compile(test_paths, **args): 'TEST_FUZZ' if suite.fuzz else None])) or 0)) for ifdef in suite.ifdef: - f.writeln(4*' '+'#ifdef %s' % ifdef) + f.writeln(4*' '+'#if (%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifdef)) for ifndef in suite.ifndef: - f.writeln(4*' '+'#ifndef %s' % ifndef) + f.writeln(4*' '+'#if !(%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifndef)) # create suite defines if suite.defines: f.writeln(4*' '+'.defines = (const test_define_t[]){') @@ -580,9 +592,13 @@ def compile(test_paths, **args): else None])) or 0)) for ifdef in it.chain(suite.ifdef, case.ifdef): - f.writeln(12*' '+'#ifdef %s' % ifdef) + f.writeln(12*' '+'#if (%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifdef)) for ifndef in it.chain(suite.ifndef, case.ifndef): - f.writeln(12*' '+'#ifndef %s' % ifndef) + f.writeln(12*' '+'#if !(%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifndef)) # create case defines if case.defines: f.writeln(12*' '+'.defines' @@ -651,9 +667,13 @@ def compile(test_paths, **args): # any ifdef prologues if suite.ifdef or suite.ifndef: for ifdef in suite.ifdef: - f.writeln('#ifdef %s' % ifdef) + f.writeln('#if (%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifdef)) for ifndef in suite.ifndef: - f.writeln('#ifndef %s' % ifndef) + f.writeln('#if !(%s)' % re.sub( + '[a-zA-Z_0-9]+', 'defined(\g<0>)', + ifndef)) f.writeln() # any suite code