Compile-Time Code Inclusion or Exclusion

Hello All,

Let’s say I want to generate code during compile-time. If a config field is set to true, include the function and if it’s set to false ignore the function and don’t include it.

I have this code here:

comptime {
    if (config.scheduler.suspendEnable) {
        pub fn wakeTask() bool {
            return true;
        }
        pub fn suspendTask() bool {
            return false;
        }
    }
}

and it gives me this error:

src/kernel/scheduler.zig:26:9: error: expected statement, found 'pub'
        pub fn wakeTask() bool {

How do I include or exclude functions during compile-time?

Zig compilation is lazy, functions only get included
if you export them explicitly or call them in an exported one,
recursively. For executables the main function is implicitly exported.

2 Likes

Thanks for the reply.

So what you’re saying is only the code that gets invoked in exported functions (code used in the “business code” so to speak) or explicitly tagged as @export/export gets included in the final build?

I’m following an RTOS book that explicitly includes or excludes code based on the configuration variables set through #define variables. I am going to have to take a different approach.

I’m following an RTOS book that explicitly includes or excludes code

If they are functions, you don’t need to do anything.

based on the configuration variables set through #define variables.
I am going to have to take a different approach.

Compile-time toggles can be passed through build options:

IIUC they are comptime values so you could use conditional
on the blocks and only one branch will be compiled.

If you can post an concrete example it’d be easier
to discuss approaches though.

2 Likes

Ahh, okay. The way I have my configuration options setup is the following.

Defining a data type with all the options related to the RTOS kernel services, setting it to the most default options. FCFS scheduler algorithm with no stack, timer, intertask comm., etc. in the types.zig file.

pub const RTOSConfig = struct {

    ...
    // Sub-Configuration Data Structures
    ...

    include_everything: bool   = false,
    scheduler: SchedulerConfig = SchedulerConfig {},
    task:      TaskConfig      = TaskConfig {},
    partition: PartitionConfig = PartitionConfig {},
    mailbox:   MailboxConfig   = MailboxConfig {},
    queue:     QueueConfig     = QueueConfig {},
    semaphore: SemaphoreConfig = SemaphoreConfig {},
    event:     EventConfig     = EventConfig {},
    pipe:      PipeConfig      = PipeConfig {},
    release:   ReleaseConfig   = ReleaseConfig {},
    system:    SystemConfig    = SystemConfig {},
}

Import the data structure into the config.zig file for user custom configuration.

const RTOSConfig = @import("types.zig").RTOSConfig;

pub const config = RTOSConfig {
    // User Custom Configuration
}

Then importing the configuration to kernel service files in order to enable features, initialize data structures, and exclude code. For example, the scheduler

pun const scheduler(comptimer T: SchedulerType) void {
    switch (T) {
        .RTC => {
            // Run to Completion Scheduling Algorithm
        },
        .RR, .TS, .PRIORITY {
            // Logic for the three scheduling algorithms that need timers, stacks, context, etc
            // Include/Exclude code depending on which scheduler has been chosen.
            // Initializing data structures etc.
        },
    }
}

*Left out details for brevity.

Ahh, okay. The way I have my configuration options setup
is the following.

I meant the reference C code to clarify what to be excluded here.

pub fn scheduler(comptime T: SchedulerType) void {
    switch (T) {
        .RR, .TS, .PRIORITY => {
            // Include/Exclude code depending on
            // which scheduler has been chosen.

Any branching determined by T is done at compile time.

BTW conventionally only Zig types are spelled in PascalCase,
T to be named scheduler_type or ty.

1 Like