Error when compiling assembly with zig build

I’m getting these errors when I try to compile a riscv assembly file

path/main.s:1:1: error: clang exited with code 1
error: error(compilation): clang failed with stderr:
    path/main.s:32:2: error: instruction requires the following: 'Zbb' (Basic Bit-Manipulation) or 'Zbkb' (Bitmanip instructions for Cryptography)
        roriw a0, x0, 6
        ^
    path/main.s:84:2: error: instruction requires the following: 'Zcb' (Compressed basic bit manipulation instructions)
        c.lbu a5, (a4)
        ^
    path/main.s:85:2: error: instruction requires the following: 'Zcb' (Compressed basic bit manipulation instructions)
        c.sb a5, (a3)
        ^
    path/main.s:136:2: error: instruction requires the following: 'Zcb' (Compressed basic bit manipulation instructions)
        c.sb a0, (a3)
        ^

This is the build script I’m using

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.resolveTargetQuery(.{
        .cpu_arch = .riscv64,
        .os_tag = .linux,
        .cpu_features_add = std.Target.riscv.featureSet(&.{
            .c,
            .zcb,
            .zbb,
        }),
    });

    var mod = b.createModule(.{
        .target = target,
        .optimize = .ReleaseFast,
        .strip = true,
    });

    mod.addAssemblyFile(b.path("main.s"));

    const exe = b.addExecutable(.{ .name = "main", .root_module = mod, });

    b.installArtifact(exe);
}

Is adding cpu features in the target not enough? or is this supposed to work?

Have a look at src/Compilation.zig lines 6677-6726:

            // The Clang assembler does not accept the list of CPU features like the
            // compiler frontend does. Therefore we must hard-code the -m flags for
            // all CPU features here.
            switch (target.cpu.arch) {
                .riscv32, .riscv32be, .riscv64, .riscv64be => {
                    const RvArchFeat = struct { char: u8, feat: std.Target.riscv.Feature };
                    const letters = [_]RvArchFeat{
                        .{ .char = 'm', .feat = .m },
                        .{ .char = 'a', .feat = .a },
                        .{ .char = 'f', .feat = .f },
                        .{ .char = 'd', .feat = .d },
                        .{ .char = 'c', .feat = .c },
                    };
                    const prefix: []const u8 = if (target.cpu.arch == .riscv64) "rv64" else "rv32";
                    const prefix_len = 4;
                    assert(prefix.len == prefix_len);
                    var march_buf: [prefix_len + letters.len + 1]u8 = undefined;
                    var march_index: usize = prefix_len;
                    @memcpy(march_buf[0..prefix.len], prefix);

                    if (target.cpu.has(.riscv, .e)) {
                        march_buf[march_index] = 'e';
                    } else {
                        march_buf[march_index] = 'i';
                    }
                    march_index += 1;

                    for (letters) |letter| {
                        if (target.cpu.has(.riscv, letter.feat)) {
                            march_buf[march_index] = letter.char;
                            march_index += 1;
                        }
                    }

                    const march_arg = try std.fmt.allocPrint(arena, "-march={s}", .{
                        march_buf[0..march_index],
                    });
                    try argv.append(march_arg);

                    if (target.cpu.has(.riscv, .relax)) {
                        try argv.append("-mrelax");
                    } else {
                        try argv.append("-mno-relax");
                    }
                    if (target.cpu.has(.riscv, .save_restore)) {
                        try argv.append("-msave-restore");
                    } else {
                        try argv.append("-mno-save-restore");
                    }
                },

You can set ZIG_VERBOSE_CC=1 environment variable to obtain the zig clang command line being used to attempt to build the assembly.

If you can figure out what flags are needed to be passed to correctly communicate the target, you’re 95% of the way to fixing this problem in the compiler.