mirror of
https://github.com/Noratrieb/uwucc.git
synced 2026-01-14 16:45:07 +01:00
make stack work
This commit is contained in:
parent
e28469fcc0
commit
46e5662aab
15 changed files with 122 additions and 117 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
use nix
|
||||||
|
|
@ -131,8 +131,8 @@ pub struct Statement {
|
||||||
pub enum StatementKind {
|
pub enum StatementKind {
|
||||||
Alloca {
|
Alloca {
|
||||||
result: Register,
|
result: Register,
|
||||||
size: Operand,
|
size: u64,
|
||||||
align: Operand,
|
align: u64,
|
||||||
},
|
},
|
||||||
Store {
|
Store {
|
||||||
ptr: Operand,
|
ptr: Operand,
|
||||||
|
|
@ -234,6 +234,8 @@ impl Func<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BbIdx {
|
impl BbIdx {
|
||||||
|
pub const ZERO: Self = Self(0);
|
||||||
|
|
||||||
pub fn from_usize(n: usize) -> Self {
|
pub fn from_usize(n: usize) -> Self {
|
||||||
Self(n.try_into().unwrap())
|
Self(n.try_into().unwrap())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use super::{BbIdx, Branch, Func, Location, Operand};
|
||||||
use crate::ir::visit::Visitor;
|
use crate::ir::visit::Visitor;
|
||||||
|
|
||||||
pub fn traverse_postorder(func: &Func<'_>) -> Vec<BbIdx> {
|
pub fn traverse_postorder(func: &Func<'_>) -> Vec<BbIdx> {
|
||||||
// the final traversial, backwards.
|
// the final traversal, backwards.
|
||||||
// the starting bb has to be visited last.
|
// the starting bb has to be visited last.
|
||||||
let mut traversal = vec![BbIdx(0)];
|
let mut traversal = vec![BbIdx(0)];
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ impl<'a> Customizer<'a> for DefaultCustomizer<'a> {
|
||||||
self.0.set(Some(func));
|
self.0.set(Some(func));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_reg(&self, reg: Register, f: &mut fmt::Formatter<'_>, loc: Location) -> fmt::Result {
|
fn fmt_reg(&self, reg: Register, f: &mut fmt::Formatter<'_>, _loc: Location) -> fmt::Result {
|
||||||
match self.0.get().unwrap().regs[reg.0 as usize].name {
|
match self.0.get().unwrap().regs[reg.0 as usize].name {
|
||||||
None => write!(f, "%{}", reg.0),
|
None => write!(f, "%{}", reg.0),
|
||||||
Some(name) => write!(f, "%{name}"),
|
Some(name) => write!(f, "%{name}"),
|
||||||
|
|
@ -101,10 +101,8 @@ impl<W: Write> PrettyPrinter<W> {
|
||||||
} => {
|
} => {
|
||||||
writeln!(
|
writeln!(
|
||||||
self.out,
|
self.out,
|
||||||
" {} = alloca, size={}, align={}",
|
" {} = alloca, size={size}, align={align}",
|
||||||
print_reg(reg),
|
print_reg(reg),
|
||||||
print_op(size),
|
|
||||||
print_op(align)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
StatementKind::Store {
|
StatementKind::Store {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
use super::{visit::Visitor, Branch, Func, Register};
|
use super::{visit::Visitor, Branch, Func, Register, StatementKind};
|
||||||
use crate::ir::BbIdx;
|
use crate::ir::BbIdx;
|
||||||
|
|
||||||
pub fn validate(func: &Func<'_>) {
|
pub fn validate(func: &Func<'_>) {
|
||||||
|
|
@ -14,6 +14,16 @@ pub fn validate(func: &Func<'_>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i, bb) in func.bbs.iter().enumerate().skip(1) {
|
||||||
|
if bb
|
||||||
|
.statements
|
||||||
|
.iter()
|
||||||
|
.any(|stmt| matches!(stmt.kind, StatementKind::Alloca { .. }))
|
||||||
|
{
|
||||||
|
panic!("alloca is only allowed in first block, found in block {i}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut reg_names = FxHashSet::default();
|
let mut reg_names = FxHashSet::default();
|
||||||
for reg in &func.regs {
|
for reg in &func.regs {
|
||||||
if let Some(name) = reg.name {
|
if let Some(name) = reg.name {
|
||||||
|
|
|
||||||
|
|
@ -32,12 +32,10 @@ pub trait Visitor {
|
||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
StatementKind::Alloca {
|
StatementKind::Alloca {
|
||||||
result,
|
result,
|
||||||
size,
|
size: _,
|
||||||
align,
|
align: _,
|
||||||
} => {
|
} => {
|
||||||
self.visit_reg(result);
|
self.visit_reg(result);
|
||||||
self.visit_operand(size);
|
|
||||||
self.visit_operand(align);
|
|
||||||
}
|
}
|
||||||
StatementKind::Store {
|
StatementKind::Store {
|
||||||
ptr,
|
ptr,
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
|
||||||
for (var, def_span) in &decl.init_declarators {
|
for (var, def_span) in &decl.init_declarators {
|
||||||
let tyl = self.lcx.layout_of(ty);
|
let tyl = self.lcx.layout_of(ty);
|
||||||
let (name, name_span) = var.declarator.decl.name();
|
let (name, name_span) = var.declarator.decl.name();
|
||||||
let ptr_to = self.build.alloca(tyl.layout, Some(name), span);
|
let ptr_to = self.build.reserve_local(tyl.layout, name, span);
|
||||||
|
|
||||||
let variable_info = VariableInfo {
|
let variable_info = VariableInfo {
|
||||||
def_span: *def_span,
|
def_span: *def_span,
|
||||||
|
|
@ -478,7 +478,7 @@ fn lower_func<'cx>(
|
||||||
let span = param.declarator.1;
|
let span = param.declarator.1;
|
||||||
|
|
||||||
let alloca_name = Symbol::intern(&format!("{}.local", name));
|
let alloca_name = Symbol::intern(&format!("{}.local", name));
|
||||||
let ptr_to = cx.build.alloca(tyl.layout, Some(alloca_name), span);
|
let ptr_to = cx.build.reserve_local(tyl.layout, alloca_name, span);
|
||||||
|
|
||||||
let variable_info = VariableInfo {
|
let variable_info = VariableInfo {
|
||||||
def_span: span,
|
def_span: span,
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ use parser::{Span, Symbol};
|
||||||
use super::LoweringCx;
|
use super::LoweringCx;
|
||||||
use crate::{
|
use crate::{
|
||||||
ir::{
|
ir::{
|
||||||
self, BasicBlock, BbIdx, BinKind, Branch, ConstValue, Func, Layout, Operand, Register,
|
self, BasicBlock, BbIdx, BinKind, Branch, Func, Layout, Operand, Register, RegisterData,
|
||||||
RegisterData, Statement, StatementKind, TyLayout, UnaryKind,
|
Statement, StatementKind, TyLayout, UnaryKind,
|
||||||
},
|
},
|
||||||
ty::{Ty, TyKind},
|
ty::{Ty, TyKind},
|
||||||
};
|
};
|
||||||
|
|
@ -47,6 +47,15 @@ impl<'a, 'cx> FuncBuilder<'a, 'cx> {
|
||||||
reg
|
reg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reserve_local(&mut self, layout: &Layout, name: Symbol, span: Span) -> Register {
|
||||||
|
// Every local is a singleton.
|
||||||
|
let prev = self.current_bb;
|
||||||
|
self.current_bb = BbIdx(0);
|
||||||
|
let reg = self.alloca(layout, Some(name), span);
|
||||||
|
self.current_bb = prev;
|
||||||
|
reg
|
||||||
|
}
|
||||||
|
|
||||||
pub fn alloca(&mut self, layout: &Layout, name: Option<Symbol>, span: Span) -> Register {
|
pub fn alloca(&mut self, layout: &Layout, name: Option<Symbol>, span: Span) -> Register {
|
||||||
let void_ptr = self
|
let void_ptr = self
|
||||||
.lcx
|
.lcx
|
||||||
|
|
@ -56,8 +65,8 @@ impl<'a, 'cx> FuncBuilder<'a, 'cx> {
|
||||||
span,
|
span,
|
||||||
kind: StatementKind::Alloca {
|
kind: StatementKind::Alloca {
|
||||||
result: reg,
|
result: reg,
|
||||||
size: Operand::Const(ConstValue::u64(layout.size)),
|
size: layout.size,
|
||||||
align: Operand::Const(ConstValue::u64(layout.align)),
|
align: layout.align,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
self.cur_bb_mut().statements.push(stmt);
|
self.cur_bb_mut().statements.push(stmt);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
mod registers;
|
mod registers;
|
||||||
|
mod stack;
|
||||||
mod x86_64;
|
mod x86_64;
|
||||||
|
|
||||||
use std::process::Stdio;
|
use std::process::Stdio;
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ pub struct MachineReg(pub usize);
|
||||||
pub enum RegValue {
|
pub enum RegValue {
|
||||||
/// The SSA register contains an address on the stack.
|
/// The SSA register contains an address on the stack.
|
||||||
/// The offset is the offset from the start of the function.
|
/// The offset is the offset from the start of the function.
|
||||||
StackRelative { offset: u64 },
|
StackRelativePtr { offset: u64 },
|
||||||
/// The SSA register resides on the stack as it has been spilled.
|
/// The SSA register resides on the stack as it has been spilled.
|
||||||
/// This should be rather rare in practice.
|
/// This should be rather rare in practice.
|
||||||
Spilled { offset: u64 },
|
Spilled { offset: u64 },
|
||||||
|
|
@ -65,15 +65,13 @@ pub enum RegValue {
|
||||||
pub struct FunctionLayout {
|
pub struct FunctionLayout {
|
||||||
/// Where a register comes from at a particular usage of a register.
|
/// Where a register comes from at a particular usage of a register.
|
||||||
register_uses: FxHashMap<(Location, Register), RegValue>,
|
register_uses: FxHashMap<(Location, Register), RegValue>,
|
||||||
total_stack_space: u64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compute_layout(f: &Func) -> FunctionLayout {
|
pub fn compute_layout(_f: &Func) -> FunctionLayout {
|
||||||
let register_uses = FxHashMap::default();
|
let register_uses = FxHashMap::default();
|
||||||
|
|
||||||
FunctionLayout {
|
FunctionLayout {
|
||||||
register_uses,
|
register_uses,
|
||||||
total_stack_space: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,7 +100,7 @@ impl<'a> ir::pretty::Customizer<'a> for LayoutPrinter<'a> {
|
||||||
match layout {
|
match layout {
|
||||||
Some(RegValue::MachineReg(mach)) => write!(f, "reg-{}", mach.0)?,
|
Some(RegValue::MachineReg(mach)) => write!(f, "reg-{}", mach.0)?,
|
||||||
Some(RegValue::Spilled { offset }) => write!(f, "spill-{offset}")?,
|
Some(RegValue::Spilled { offset }) => write!(f, "spill-{offset}")?,
|
||||||
Some(RegValue::StackRelative { offset }) => {
|
Some(RegValue::StackRelativePtr { offset }) => {
|
||||||
write!(f, "i-forgot-what-this-meant-{offset}")?
|
write!(f, "i-forgot-what-this-meant-{offset}")?
|
||||||
}
|
}
|
||||||
None => write!(f, "<unknown>")?,
|
None => write!(f, "<unknown>")?,
|
||||||
|
|
|
||||||
43
codegen/src/stack.rs
Normal file
43
codegen/src/stack.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use analysis::ir::{BbIdx, Func, Register, StatementKind};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct StackLayout {
|
||||||
|
pub allocas: HashMap<Register, u64>,
|
||||||
|
pub total_size: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Based on the alloca's in the initial block, this calculcates stack pointer offsets for every allocation.
|
||||||
|
pub fn allocate_stack_space<'cx>(start_align: u64, func: &Func<'cx>) -> StackLayout {
|
||||||
|
assert_eq!(start_align, 8);
|
||||||
|
// REMEMBER: The stack grows down (on x86-64).
|
||||||
|
|
||||||
|
let mut temp_layout = HashMap::new();
|
||||||
|
let mut offset_backwards = 0;
|
||||||
|
|
||||||
|
for stmt in &func.bb(BbIdx::ZERO).statements {
|
||||||
|
if let StatementKind::Alloca {
|
||||||
|
result,
|
||||||
|
size,
|
||||||
|
align,
|
||||||
|
} = stmt.kind
|
||||||
|
{
|
||||||
|
if size != 8 || align != 8 {
|
||||||
|
todo!("non 8 integer {size} {align}")
|
||||||
|
}
|
||||||
|
offset_backwards += 8;
|
||||||
|
temp_layout.insert(result, offset_backwards);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let total_size = offset_backwards;
|
||||||
|
|
||||||
|
StackLayout {
|
||||||
|
allocas: temp_layout
|
||||||
|
.into_iter()
|
||||||
|
.map(|(reg, offset_back)| (reg, total_size - offset_back))
|
||||||
|
.collect(),
|
||||||
|
total_size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -40,7 +40,7 @@ use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
registers::{MachineReg, RegValue},
|
registers::{MachineReg, RegValue},
|
||||||
Result,
|
stack, Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
trait IcedErrExt {
|
trait IcedErrExt {
|
||||||
|
|
@ -61,9 +61,10 @@ struct AsmCtxt<'cx> {
|
||||||
a: CodeAssembler,
|
a: CodeAssembler,
|
||||||
reg_map: FxHashMap<Register, RegValue>,
|
reg_map: FxHashMap<Register, RegValue>,
|
||||||
reg_occupancy: Vec<Option<Register>>,
|
reg_occupancy: Vec<Option<Register>>,
|
||||||
current_stack_offset: u64,
|
|
||||||
bb_idx: BbIdx,
|
bb_idx: BbIdx,
|
||||||
|
|
||||||
|
stack_layout: stack::StackLayout,
|
||||||
|
|
||||||
// caches
|
// caches
|
||||||
last_register_uses: Vec<Option<Location>>,
|
last_register_uses: Vec<Option<Location>>,
|
||||||
}
|
}
|
||||||
|
|
@ -98,6 +99,9 @@ impl<'cx> AsmCtxt<'cx> {
|
||||||
// Prologue: Save rbp and save rsp in rbp.
|
// Prologue: Save rbp and save rsp in rbp.
|
||||||
self.a.push(x::rbp).sp(func.def_span)?;
|
self.a.push(x::rbp).sp(func.def_span)?;
|
||||||
self.a.mov(x::rbp, x::rsp).sp(func.def_span)?;
|
self.a.mov(x::rbp, x::rsp).sp(func.def_span)?;
|
||||||
|
self.a
|
||||||
|
.sub(x::rsp, self.stack_layout.total_size as i32)
|
||||||
|
.sp(func.def_span)?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let bb = &func.bbs[self.bb_idx.as_usize()];
|
let bb = &func.bbs[self.bb_idx.as_usize()];
|
||||||
|
|
@ -108,27 +112,15 @@ impl<'cx> AsmCtxt<'cx> {
|
||||||
} = *stmt;
|
} = *stmt;
|
||||||
|
|
||||||
match *kind {
|
match *kind {
|
||||||
StatementKind::Alloca {
|
StatementKind::Alloca { result, .. } => {
|
||||||
result: reg,
|
|
||||||
size,
|
|
||||||
align: _,
|
|
||||||
} => {
|
|
||||||
// For alloca, we allocate some space on the stack by subtracting from RSP.
|
|
||||||
// TODO: Align
|
|
||||||
match size {
|
|
||||||
Operand::Const(c) => {
|
|
||||||
let offset = c.as_i32();
|
|
||||||
self.a.sub(x::rsp, offset).sp(st_sp)?;
|
|
||||||
self.current_stack_offset += offset as u64;
|
|
||||||
}
|
|
||||||
Operand::Reg(_) => {
|
|
||||||
todo!("dynamic alloca is not supported. get a better computer")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.reg_map.insert(
|
self.reg_map.insert(
|
||||||
reg,
|
result,
|
||||||
RegValue::StackRelative {
|
RegValue::StackRelativePtr {
|
||||||
offset: self.current_stack_offset,
|
offset: *self
|
||||||
|
.stack_layout
|
||||||
|
.allocas
|
||||||
|
.get(&result)
|
||||||
|
.expect("no stack layout slot present for alloc register"),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -149,14 +141,15 @@ impl<'cx> AsmCtxt<'cx> {
|
||||||
Operand::Reg(reg) => {
|
Operand::Reg(reg) => {
|
||||||
let ptr_value = self.reg_map[®];
|
let ptr_value = self.reg_map[®];
|
||||||
match (ptr_value, value) {
|
match (ptr_value, value) {
|
||||||
(RegValue::StackRelative { offset }, Operand::Const(c)) => {
|
(RegValue::StackRelativePtr { offset }, Operand::Const(c)) => {
|
||||||
let offset_from_cur = self.current_stack_offset - offset;
|
|
||||||
|
|
||||||
self.a
|
self.a
|
||||||
.mov(x::qword_ptr(x::rsp + offset_from_cur), c.as_i32())
|
.mov(x::qword_ptr(x::rsp + offset), c.as_i32())
|
||||||
.sp(st_sp)?;
|
.sp(st_sp)?;
|
||||||
}
|
}
|
||||||
(RegValue::StackRelative { offset }, Operand::Reg(value)) => {
|
(
|
||||||
|
RegValue::StackRelativePtr { offset },
|
||||||
|
Operand::Reg(value),
|
||||||
|
) => {
|
||||||
todo!("stack relative ptr + reg value")
|
todo!("stack relative ptr + reg value")
|
||||||
}
|
}
|
||||||
(RegValue::Spilled { .. }, _) => todo!("spilled"),
|
(RegValue::Spilled { .. }, _) => todo!("spilled"),
|
||||||
|
|
@ -229,13 +222,16 @@ pub fn generate_func<'cx>(lcx: &'cx LoweringCx<'cx>, func: &Func<'cx>) -> Result
|
||||||
let fn_sp = func.def_span;
|
let fn_sp = func.def_span;
|
||||||
let a = CodeAssembler::new(64).sp(fn_sp)?;
|
let a = CodeAssembler::new(64).sp(fn_sp)?;
|
||||||
|
|
||||||
|
let stack_layout = stack::allocate_stack_space(8, func);
|
||||||
|
dbg!(&stack_layout);
|
||||||
|
|
||||||
let mut cx = AsmCtxt {
|
let mut cx = AsmCtxt {
|
||||||
lcx,
|
lcx,
|
||||||
a,
|
a,
|
||||||
reg_map: FxHashMap::default(),
|
reg_map: FxHashMap::default(),
|
||||||
reg_occupancy: vec![None; 8],
|
reg_occupancy: vec![None; 8],
|
||||||
current_stack_offset: 0,
|
|
||||||
bb_idx: BbIdx(0),
|
bb_idx: BbIdx(0),
|
||||||
|
stack_layout,
|
||||||
last_register_uses: ir::info::last_register_uses(func),
|
last_register_uses: ir::info::last_register_uses(func),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
26
flake.lock
generated
26
flake.lock
generated
|
|
@ -1,26 +0,0 @@
|
||||||
{
|
|
||||||
"nodes": {
|
|
||||||
"nixpkgs": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1685199731,
|
|
||||||
"narHash": "sha256-t8I2oEFetISWpY4NUydCNcDJLSBGGyMCeozzVborlZA=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "3580ac6c65ec97ebccb02c166af8d19045d4d291",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": "nixpkgs"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": "root",
|
|
||||||
"version": 7
|
|
||||||
}
|
|
||||||
40
flake.nix
40
flake.nix
|
|
@ -1,40 +0,0 @@
|
||||||
{
|
|
||||||
description = "the uwucc c compiler";
|
|
||||||
|
|
||||||
inputs = {
|
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs"; # also valid: "nixpkgs"
|
|
||||||
};
|
|
||||||
|
|
||||||
outputs = { self, nixpkgs }:
|
|
||||||
let
|
|
||||||
allSystems = [
|
|
||||||
"x86_64-linux" # 64-bit Intel/AMD Linux
|
|
||||||
"aarch64-linux" # 64-bit ARM Linux
|
|
||||||
"x86_64-darwin" # 64-bit Intel macOS
|
|
||||||
"aarch64-darwin" # 64-bit ARM macOS
|
|
||||||
];
|
|
||||||
|
|
||||||
# Helper to provide system-specific attributes
|
|
||||||
forAllSystems = f: nixpkgs.lib.genAttrs allSystems (system: f {
|
|
||||||
pkgs = import nixpkgs { inherit system; };
|
|
||||||
});
|
|
||||||
in
|
|
||||||
{
|
|
||||||
devShells = forAllSystems ({ pkgs }: {
|
|
||||||
default = pkgs.mkShell {
|
|
||||||
buildInputs = with pkgs; [
|
|
||||||
clang
|
|
||||||
llvmPackages_16.bintools
|
|
||||||
rustup
|
|
||||||
cargo-insta
|
|
||||||
gdb
|
|
||||||
];
|
|
||||||
|
|
||||||
shellHook = ''
|
|
||||||
export PATH=$PATH:''${CARGO_HOME:-~/.cargo}/bin
|
|
||||||
export PATH=$PATH:''${RUSTUP_HOME:-~/.rustup}/toolchains/$RUSTC_VERSION-x86_64-unknown-linux-gnu/bin/
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
15
shell.nix
Normal file
15
shell.nix
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{ pkgs ? import <nixpkgs> { } }: pkgs.mkShell
|
||||||
|
{
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
clang
|
||||||
|
llvmPackages_16.bintools
|
||||||
|
rustup
|
||||||
|
cargo-insta
|
||||||
|
gdb
|
||||||
|
];
|
||||||
|
|
||||||
|
shellHook = ''
|
||||||
|
export PATH=$PATH:''${CARGO_HOME:-~/.cargo}/bin
|
||||||
|
export PATH=$PATH:''${RUSTUP_HOME:-~/.rustup}/toolchains/$RUSTC_VERSION-x86_64-unknown-linux-gnu/bin/
|
||||||
|
'';
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue