feat: base project
This commit is contained in:
240
build.zig
Normal file
240
build.zig
Normal file
@@ -0,0 +1,240 @@
|
||||
const std = @import("std");
|
||||
|
||||
// Choose your board
|
||||
const Board =
|
||||
// .pico;
|
||||
.pico_w;
|
||||
// .pico2;
|
||||
// .pico2_w;
|
||||
|
||||
// Choose whether Stdio goes to USB or UART
|
||||
const StdioUsb = true;
|
||||
const PicoStdlibDefine = if (StdioUsb) "LIB_PICO_STDIO_USB" else "LIB_PICO_STDIO_UART";
|
||||
|
||||
// Pico SDK path can be specified here for your convenience
|
||||
const PicoSDKPath: ?[]const u8 = null;
|
||||
|
||||
// arm-none-eabi toolchain path may be specified here as well
|
||||
const ARMNoneEabiPath: ?[]const u8 = null;
|
||||
|
||||
pub fn build(b: *std.Build) anyerror!void {
|
||||
|
||||
// ------------------
|
||||
const target = std.Target.Query{
|
||||
.abi = .eabi,
|
||||
.cpu_arch = .thumb,
|
||||
.cpu_model = .{ .explicit = cpu_model_by_board(Board) },
|
||||
.os_tag = .freestanding,
|
||||
};
|
||||
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const lib = b.addObject(.{
|
||||
.name = "zig-pico",
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = b.resolveTargetQuery(target),
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
// get and perform basic verification on the pico sdk path
|
||||
// if the sdk path contains the pico_sdk_init.cmake file then we know its correct
|
||||
const pico_sdk_path =
|
||||
if (PicoSDKPath) |sdk_path| sdk_path else std.process.getEnvVarOwned(b.allocator, "PICO_SDK_PATH") catch null orelse {
|
||||
std.log.err("The Pico SDK path must be set either through the PICO_SDK_PATH environment variable or at the top of build.zig.", .{});
|
||||
return;
|
||||
};
|
||||
|
||||
const pico_init_cmake_path = b.pathJoin(&.{ pico_sdk_path, "pico_sdk_init.cmake" });
|
||||
std.fs.cwd().access(pico_init_cmake_path, .{}) catch {
|
||||
std.log.err(
|
||||
\\Provided Pico SDK path does not contain the file pico_sdk_init.cmake
|
||||
\\Tried: {s}
|
||||
\\Are you sure you entered the path correctly?"
|
||||
, .{pico_init_cmake_path});
|
||||
return;
|
||||
};
|
||||
|
||||
// default arm-none-eabi includes
|
||||
lib.linkLibC();
|
||||
|
||||
// Standard libary headers may be in different locations on different platforms
|
||||
const arm_header_location = blk: {
|
||||
if (ARMNoneEabiPath) |path| {
|
||||
break :blk path;
|
||||
}
|
||||
|
||||
if (std.process.getEnvVarOwned(b.allocator, "ARM_NONE_EABI_PATH") catch null) |path| {
|
||||
break :blk path;
|
||||
}
|
||||
|
||||
const unix_path = "/usr/arm-none-eabi/include";
|
||||
if (std.fs.accessAbsolute(unix_path, .{})) |_| {
|
||||
break :blk unix_path;
|
||||
} else |err| err catch {};
|
||||
|
||||
break :blk error.StandardHeaderLocationNotSpecified;
|
||||
} catch |err| {
|
||||
err catch {};
|
||||
std.log.err(
|
||||
\\Could not determine ARM Toolchain include directory.
|
||||
\\Please set the ARM_NONE_EABI_PATH environment variable with the correct path
|
||||
\\or set the ARMNoneEabiPath variable at the top of build.zig
|
||||
, .{});
|
||||
return;
|
||||
};
|
||||
lib.addSystemIncludePath(.{ .cwd_relative = arm_header_location });
|
||||
|
||||
// Sort out the platform specifics
|
||||
const IsRP2040 = Board == .pico or Board == .pico_w;
|
||||
const Platform = comptime platform_by_board(Board);
|
||||
|
||||
// find the board header
|
||||
const board_header = blk: {
|
||||
const header_file = @tagName(Board) ++ ".h";
|
||||
const _board_header = b.pathJoin(&.{ pico_sdk_path, "src/boards/include/boards", header_file });
|
||||
|
||||
std.fs.cwd().access(_board_header, .{}) catch {
|
||||
std.log.err("Could not find the header file for board '{s}'\n", .{@tagName(Board)});
|
||||
return;
|
||||
};
|
||||
|
||||
break :blk header_file;
|
||||
};
|
||||
|
||||
// Autogenerate the header file like the pico sdk would
|
||||
const cmsys_exception_prefix = if (IsRP2040) "" else "//";
|
||||
const header_str = try std.fmt.allocPrint(b.allocator,
|
||||
\\#include "{s}/src/boards/include/boards/{s}"
|
||||
\\{s}#include "{s}/src/rp2_common/cmsis/include/cmsis/rename_exceptions.h"
|
||||
, .{ pico_sdk_path, board_header, cmsys_exception_prefix, pico_sdk_path });
|
||||
|
||||
// Write and include the generated header
|
||||
const config_autogen_step = b.addWriteFile("pico/config_autogen.h", header_str);
|
||||
lib.step.dependOn(&config_autogen_step.step);
|
||||
lib.addIncludePath(config_autogen_step.getDirectory());
|
||||
|
||||
// requires running cmake at least once
|
||||
lib.addSystemIncludePath(b.path("build/generated/pico_base"));
|
||||
|
||||
// PICO SDK includes
|
||||
// Find all folders called include in the Pico SDK
|
||||
{
|
||||
const pico_sdk_src = try std.fmt.allocPrint(b.allocator, "{s}/src", .{pico_sdk_path});
|
||||
var dir = try std.fs.cwd().openDir(pico_sdk_src, .{
|
||||
.iterate = true,
|
||||
.no_follow = true,
|
||||
});
|
||||
|
||||
const allowed_paths = [_][]const u8{ @tagName(Platform), "rp2_common", "common" };
|
||||
|
||||
var walker = try dir.walk(b.allocator);
|
||||
defer walker.deinit();
|
||||
while (try walker.next()) |entry| {
|
||||
if (std.mem.eql(u8, entry.basename, "include")) {
|
||||
for (allowed_paths) |path| {
|
||||
if (std.mem.indexOf(u8, entry.path, path)) |_| {
|
||||
const pico_sdk_include = try std.fmt.allocPrint(b.allocator, "{s}/src/{s}", .{ pico_sdk_path, entry.path });
|
||||
lib.addIncludePath(.{ .cwd_relative = pico_sdk_include });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Define the platform specific macros
|
||||
define_platform_specific_macros(lib, Platform);
|
||||
|
||||
// Define UART or USB constant for headers
|
||||
lib.root_module.addCMacro(PicoStdlibDefine, "1");
|
||||
|
||||
// required for pico_w wifi
|
||||
lib.root_module.addCMacro("PICO_CYW43_ARCH_THREADSAFE_BACKGROUND", "1");
|
||||
const cyw43_include = try std.fmt.allocPrint(b.allocator, "{s}/lib/cyw43-driver/src", .{pico_sdk_path});
|
||||
lib.addIncludePath(.{ .cwd_relative = cyw43_include });
|
||||
|
||||
// required by cyw43
|
||||
const lwip_include = try std.fmt.allocPrint(b.allocator, "{s}/lib/lwip/src/include", .{pico_sdk_path});
|
||||
lib.addIncludePath(.{ .cwd_relative = lwip_include });
|
||||
|
||||
// options headers
|
||||
lib.addIncludePath(b.path("config/"));
|
||||
|
||||
const compiled = lib.getEmittedBin();
|
||||
const install_step = b.addInstallFile(compiled, "mlem.o");
|
||||
install_step.step.dependOn(&lib.step);
|
||||
|
||||
// create build directory
|
||||
if (std.fs.cwd().makeDir("build")) |_| {} else |err| {
|
||||
if (err != error.PathAlreadyExists) return err;
|
||||
}
|
||||
|
||||
const uart_or_usb = if (StdioUsb) "-DSTDIO_USB=1" else "-DSTDIO_UART=1";
|
||||
const cmake_pico_sdk_path = b.fmt("-DPICO_SDK_PATH={s}", .{pico_sdk_path});
|
||||
const cmake_argv = [_][]const u8{ "cmake", "-B", "./build", "-S .", "-DPICO_BOARD=" ++ @tagName(Board), "-DPICO_PLATFORM=" ++ @tagName(Platform), cmake_pico_sdk_path, uart_or_usb };
|
||||
const cmake_step = b.addSystemCommand(&cmake_argv);
|
||||
cmake_step.step.dependOn(&install_step.step);
|
||||
|
||||
const make_argv = [_][]const u8{ "cmake", "--build", "./build", "--parallel" };
|
||||
const make_step = b.addSystemCommand(&make_argv);
|
||||
make_step.step.dependOn(&cmake_step.step);
|
||||
|
||||
const uf2_create_step = b.addInstallFile(b.path("build/mlem.uf2"), "firmware.uf2");
|
||||
uf2_create_step.step.dependOn(&make_step.step);
|
||||
|
||||
const uf2_step = b.step("uf2", "Create firmware.uf2");
|
||||
uf2_step.dependOn(&uf2_create_step.step);
|
||||
|
||||
const elf_create_step = b.addInstallFile(b.path("build/mlem.elf"), "firmware.elf");
|
||||
elf_create_step.step.dependOn(&make_step.step);
|
||||
|
||||
const elf_step = b.step("elf", "Create firmware.elf");
|
||||
elf_step.dependOn(&elf_create_step.step);
|
||||
|
||||
const copy_step = b.step("copy", "Copy firmware");
|
||||
copy_step.dependOn(uf2_step);
|
||||
copy_step.dependOn(elf_step);
|
||||
b.default_step = copy_step;
|
||||
|
||||
// b.default_step = uf2_step;
|
||||
}
|
||||
|
||||
// ------------------ Board support
|
||||
|
||||
pub fn cpu_model_by_board(board: @Type(.enum_literal)) *const std.Target.Cpu.Model {
|
||||
return switch (board) {
|
||||
.pico, .pico_w => &std.Target.arm.cpu.cortex_m0plus,
|
||||
.pico2, .pico2_w => &std.Target.arm.cpu.cortex_m33,
|
||||
else => @compileError("Unknown board type"),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn platform_by_board(board: @Type(.enum_literal)) @Type(.enum_literal) {
|
||||
return switch (board) {
|
||||
.pico, .pico_w => .rp2040,
|
||||
.pico2, .pico2_w => .rp2350,
|
||||
else => @compileError("Unknown platform"),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn define_platform_specific_macros(compile: *std.Build.Step.Compile, platform: @Type(.enum_literal)) void {
|
||||
switch (platform) {
|
||||
.rp2040 => {
|
||||
compile.root_module.addCMacro("PICO_RP2040", "1");
|
||||
compile.root_module.addCMacro("PICO_32BIT", "1");
|
||||
compile.root_module.addCMacro("PICO_ARM", "1");
|
||||
compile.root_module.addCMacro("PICO_CMSIS_DEVICE", "RP2040");
|
||||
compile.root_module.addCMacro("PICO_DEFAULT_FLASH_SIZE_BYTES", "\"2 * 1024 * 1024\"");
|
||||
},
|
||||
.rp2350 => {
|
||||
compile.root_module.addCMacro("PICO_RP2350", "1");
|
||||
compile.root_module.addCMacro("PICO_32BIT", "1");
|
||||
compile.root_module.addCMacro("PICO_ARM", "1");
|
||||
compile.root_module.addCMacro("PICO_PIO_VERSION", "1");
|
||||
compile.root_module.addCMacro("NUM_DOORBELLS", "1");
|
||||
compile.root_module.addCMacro("PICO_CMSIS_DEVICE", "RP2350");
|
||||
compile.root_module.addCMacro("PICO_DEFAULT_FLASH_SIZE_BYTES", "\"4 * 1024 * 1024\"");
|
||||
},
|
||||
else => @compileError("Unknown platform"),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user