kornos/kernel/build.zig

261 lines
8.4 KiB
Zig

// imports
const std = @import("std");
const Builder = std.build.Builder;
// Alloc stuff
var GPAAlloc = std.heap.GeneralPurposeAllocator(.{}){};
var alloc = &GPAAlloc.allocator;
// Target enumeration stuff
const Target = struct {
parent: ?*const Target = null,
cpu_arch: ?std.Target.Cpu.Arch = null,
cpu_model: ?std.build.Target.CpuModel = null,
extra_features: []const std.Target.Cpu.Feature = &[_] std.Target.Cpu.Feature {},
forbidden_features: []const std.Target.Cpu.Feature = &[_] std.Target.Cpu.Feature {},
archdir: ?[]const u8 = null,
linkscript: ?[]const u8 = null,
name: []const u8,
};
const x86 = Target{
.archdir = "x86",
.name = "x86-generic",
};
const x86_64_nosse = std.Target.Cpu.Model {
.name = "x86_64-sse2+soft_float",
.llvm_name = null,
.features = std.Target.x86.featureSet(&[_] std.Target.x86.Feature {std.Target.x86.Feature.@"64bit"})
};
const x86_64 = Target {
.parent = &x86,
.cpu_arch = std.Target.Cpu.Arch.x86_64,
.extra_features = &[_] std.Target.Cpu.Feature {
std.Target.x86.all_features[@enumToInt(std.Target.x86.Feature.soft_float)],
},
.forbidden_features = &[_] std.Target.Cpu.Feature {
std.Target.x86.all_features[@enumToInt(std.Target.x86.Feature.sse)],
std.Target.x86.all_features[@enumToInt(std.Target.x86.Feature.sse2)],
},
.archdir = "x86_64",
.name = "x86_64-generic",
};
const intel386 = Target {
.parent = &x86,
.cpu_arch = std.Target.Cpu.Arch.i386,
.cpu_model = std.build.Target.CpuModel {.explicit = &std.builtin.Target.x86.cpu._i386},
.archdir = "i386",
.name = "i386-generic",
};
const x86_64_stivale2 = Target {
.parent = &x86_64,
// .archdir = "x86_64/stivale2",
.linkscript = "make/x86_64/linker.ld",
.name = "x86_64",
};
const i386_stivale2 = Target {
.parent = &intel386,
.linkscript = "make/i386/linker.ld",
.name = "i386",
};
const OutputTargets = &[_] Target {
x86_64_stivale2,
i386_stivale2,
};
const Targets = enum {
x86_64,
x86_64_stivale2,
i386,
i386_stivale2,
pub fn getTarget(self: Targets) Target {
return switch(self) {
.x86_64 => x86_64_stivale2,
.x86_64_stivale2 => x86_64_stivale2,
.i386 => i386_stivale2,
.i386_stivale2 => i386_stivale2,
};
}
pub fn default() Targets {
return Targets.x86_64_stivale2;
}
};
fn getCpuArch(t: Target) std.Target.Cpu.Arch {
return t.cpu_arch orelse getCpuArch(t.parent.?.*);
}
fn getCpuModel(t: Target) std.build.Target.CpuModel {
if(t.cpu_model) |m| {
return m;
} else if (t.parent) |p| {
return getCpuModel(t.parent.?.*);
} else {
return std.build.Target.CpuModel.baseline;
}
}
fn getExtraFeatures(t: Target) std.Target.Cpu.Feature.Set {
var parentset = std.Target.Cpu.Feature.Set.empty;
if(t.parent) |p| {
parentset = getExtraFeatures(p.*);
}
for (t.extra_features) |bl_ft| {
parentset.addFeature(bl_ft.index);
}
return parentset;
}
fn getForbiddenFeatures(t: Target) std.Target.Cpu.Feature.Set {
var parentset = std.Target.Cpu.Feature.Set.empty;
if(t.parent) |p| {
parentset = getForbiddenFeatures(p.*);
}
for (t.forbidden_features) |bl_ft| {
parentset.addFeature(bl_ft.index);
}
return parentset;
}
fn getLinkerScript(t: Target) []const u8 {
return t.linkscript orelse getLinkerScript(t.parent.?.*);
}
fn getTarget(t: Target) std.zig.CrossTarget {
return .{
.cpu_arch = getCpuArch(t),
.cpu_model = getCpuModel(t),
.cpu_features_add = getExtraFeatures(t),
.cpu_features_sub = getForbiddenFeatures(t),
.os_tag = std.Target.Os.Tag.freestanding,
};
}
// Directory traversal stuff
const Files = struct {
generic_c: [][]const u8,
archspecific_c: [][]const u8,
archspecific_s: [][]const u8,
nasm: [][]const u8,
};
fn strPrefix(str: []const u8, prefix: []const u8) bool {
if (str.len < prefix.len) return false;
return std.mem.eql(u8, str[0..prefix.len], prefix);
}
fn fileExtEql(name: []const u8, ext: []const u8) bool {
std.debug.assert(ext[0] == '.');
if(name.len <= ext.len) return false;
const file_ext = name[name.len - ext.len..];
return std.mem.eql(u8, file_ext, ext);
}
fn findSources(dir: []const u8, ext: []const u8, prefix: ?[]const u8) ![][] const u8 {
var files = std.ArrayList([]const u8).init(alloc);
var walker = try std.fs.walkPath(alloc, dir);
defer walker.deinit();
while (try walker.next()) |entry| {
if(entry.kind != std.fs.Dir.Entry.Kind.File) continue;
if(prefix != null and strPrefix(entry.path, prefix.?)) {
// std.debug.print("Ignoring {}\n", .{entry.path});
} else {
if(fileExtEql(entry.basename, ext)) {
// std.debug.print("Adding file {}\n", .{entry.path});
var p = std.ArrayList(u8).init(alloc);
try p.appendSlice(entry.path);
try files.append(p.toOwnedSlice());
} else {
// std.debug.print("wrong file extension: {}\n", .{entry.basename});
}
}
}
return files.toOwnedSlice();
}
fn findArch(t: Target, ext: []const u8) ![][] const u8 {
var arch_c = std.ArrayList([]const u8).init(alloc);
if (t.parent) |parent| {
const parentfiles = findArch(parent.*, ext) catch unreachable;
try arch_c.appendSlice( parentfiles );
}
if (t.archdir) |archdir| {
const dir = try std.fmt.allocPrint(alloc, "src/arch/{}", .{archdir});
const files = try findSources(dir, ext, null);
try arch_c.appendSlice(files);
}
return arch_c.items;
}
fn findFiles(t: Target) !Files {
const generic_c = try findSources("src", ".c", "src/arch/");
const arch_c = try findArch(t, ".c");
const arch_s = try findArch(t, ".s");
const nasm = try findArch(t, ".nasm");
return Files {
.generic_c = generic_c,
.archspecific_c = arch_c,
.archspecific_s = arch_s,
.nasm = nasm
};
}
pub fn build(b: *Builder) !void {
const target_option = b.option(Targets, "target", "The kernel target") orelse Targets.default();
const ktarget = target_option.getTarget();
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
// const mode = .ReleaseSmall;
const files = try findFiles(ktarget);
const cflags = [_][]const u8{"-Wall", "-Wextra", "-pedantic", "-std=gnu11", "-I../ext", "-Isrc", "-fPIE", "-mno-red-zone"};
const exename = try std.fmt.allocPrint(alloc, "kernel-{}", .{ktarget.name});
const exe = b.addExecutable(exename, "src/main.zig");
exe.addIncludeDir("src");
var cfiles = std.ArrayList([]const u8).init(alloc);
try cfiles.appendSlice(files.generic_c);
try cfiles.appendSlice(files.archspecific_c);
for (cfiles.items) |c_file| {
// std.debug.print("CC: {}\n", .{c_file});
exe.addCSourceFile(c_file, &cflags);
}
for(files.archspecific_s) |s_file| {
// std.debug.print("zig as: {}\n", .{s_file});
exe.addAssemblyFile(s_file);
}
for(files.nasm) |nasm_file| {
// std.debug.print("nasm: {}\n", .{nasm_file});
const output = try std.fmt.allocPrint(alloc, "zig-cache/nasm/{}.o", .{nasm_file});
const output_folder = std.fs.cwd().makePath(std.fs.path.dirname(output).?);
const assX = b.addSystemCommand(&[_][]const u8{"nasm", "-Isrc", "-felf64", nasm_file, "-o", output});
exe.step.dependOn(&assX.step);
exe.addObjectFile(output);
}
// const zigobj = b.addObject("zigkalloc", "src/allocator/calloc.zig");
// zigobj.setTarget(getTarget(ktarget));
// zigobj.strip = true;
// // zigobj.single_threaded = true;
// // zigobj.code_model = std.builtin.CodeModel.kernel;
// exe.addObject(zigobj);
exe.setTarget(getTarget(ktarget));
exe.setBuildMode(mode);
exe.code_model = std.builtin.CodeModel.kernel;
exe.setLinkerScriptPath(getLinkerScript(ktarget));
// exe.setOutputDir("bin");
if(mode != .Debug) {
exe.strip = true;
}
// exe.single_threaded = true;
exe.install();
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
// const run_step = b.step("run", "Run the app");
// run_step.dependOn(&run_cmd.step);
}