Skip to content

Commit

Permalink
demonstrate and test C-repr structs in FFI example
Browse files Browse the repository at this point in the history
  • Loading branch information
simvux committed Oct 1, 2024
1 parent 6167176 commit ffe88b8
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 19 deletions.
3 changes: 3 additions & 0 deletions examples/ffi/config.lm
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ val version = "1.0"
val authors = []

val dependencies = []

val linker_args = ["-flto"]
val linker_libs = ["src/main.c"]
28 changes: 28 additions & 0 deletions examples/ffi/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include "types.h"

struct Outer returns() {
struct Outer outer;
outer.a = 1;

struct Inner inner;
inner.a = 2;
inner.b = 3;
inner.c = 4;
inner.d = 5;
outer.b = inner;

outer.c = 6;

return outer;
}

unsigned int takes(struct Outer outer) {
if (outer.a != 1) return 10;
if (outer.b.a != 2) return 20;
if (outer.b.b != 3) return 30;
if (outer.b.c != 4) return 40;
if (outer.b.d != 5) return 50;
if (outer.c != 6) return 60;

return 100;
}
33 changes: 28 additions & 5 deletions examples/ffi/src/main.lm
Original file line number Diff line number Diff line change
@@ -1,8 +1,31 @@
use std:io

@[extern "exit", platform ["linux-gnu", "linux-musl"]]
fn my_libc_exit_call as i64 -> ()
fn libc_exit as i32 -> ()

fn main =
let exit_code = 5
in my_libc_exit_call exit_code
let outer = returns in
let n = takes outer in
if n == 100 then
libc_exit 0
else
libc_exit n

@[repr "C"]
type Inner {
a u32
b u8
c u64
d u16
}

@[repr "C"]
type Outer {
a u16
b Inner
c u8
}

@[extern "takes"]
fn takes as Outer -> i32

@[extern "returns"]
fn returns as Outer
16 changes: 16 additions & 0 deletions examples/ffi/src/types.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
struct Inner {
unsigned int a;
unsigned char b;
unsigned long long c;
unsigned short d;
};

struct Outer {
unsigned short a;
struct Inner b;
unsigned char c;
};


struct Outer returns();
unsigned int takes(struct Outer outer);
16 changes: 11 additions & 5 deletions lumina-compiler/src/ast/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ pub struct ProjectConfig {
pub epanic: bool,
pub prelude: String,
pub dependencies: Vec<Dependency>,
pub linker_args: Vec<String>,
pub linker_libs: Vec<String>,
}

#[derive(Debug)]
Expand Down Expand Up @@ -61,15 +63,19 @@ impl ProjectConfig {
self.epanic = bool(val.value)?;
Ok(())
}
"authors" => {
let authors = self.parse_str_list(val.value)?;
self.authors.extend(authors);
Ok(())
}
"authors" => self
.parse_str_list(val.value)
.map(|authors| self.authors.extend(authors)),
"prelude" => {
self.prelude = name(val.value)?;
Ok(())
}
"linker_args" => self
.parse_str_list(val.value)
.map(|args| self.linker_args.extend(args)),
"linker_libs" => self
.parse_str_list(val.value)
.map(|args| self.linker_libs.extend(args)),
_ => Err(Error::InvalidVal(val.span)),
}
}
Expand Down
14 changes: 12 additions & 2 deletions lumina-compiler/src/backend/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pub mod cranelift;

use super::{target::LinuxPlatform, target::Platform, Target};
use super::{ast, target::LinuxPlatform, target::Platform, Target};
use std::ffi::OsStr;
use std::fs::File;
use std::io::Write;
Expand All @@ -10,12 +10,14 @@ use std::process::ExitCode;
use tracing::info;

pub fn link_native_binary(
config: ast::ProjectConfig,
target: Target,
project_name: String,
output: &Path,
projectpath: PathBuf,
luminapath: PathBuf,
object: Vec<u8>,
) -> Result<(), ExitCode> {
let project_name = config.name.clone();
let workdir = create_workdir(&luminapath, &project_name);

let objectfile = {
Expand Down Expand Up @@ -45,12 +47,20 @@ pub fn link_native_binary(
Command::new(bindir.join("ld.lld"))
};

for arg in config.linker_args {
linker.arg(arg);
}

linker.arg("-o").arg(output).arg(&objectfile);

iter_objects(&sublinuxdir, &["o", "a"], |path| {
linker.arg(path);
});

for lib in config.linker_libs {
linker.arg(projectpath.join(lib));
}

linker.arg(linuxdir.join("syscall.o"));

linker
Expand Down
8 changes: 7 additions & 1 deletion lumina-compiler/src/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,12 @@ pub fn run<'a, 's>(
info: ProjectInfo,
target: Target,
ast: AST<'s>,
) -> (HIR<'s>, MMap<key::Func, TEnv<'s>>, ImplIndex) {
) -> (
ast::ProjectConfig,
HIR<'s>,
MMap<key::Func, TEnv<'s>>,
ImplIndex,
) {
let mut tenvs = ast.entities.fheaders.secondary();

let mut funcs = ast.entities.fheaders.secondary();
Expand Down Expand Up @@ -197,6 +202,7 @@ pub fn run<'a, 's>(
.map(|_, assoc| assoc.values().map(|a| a.name.tr(a.span)).collect());

(
ast.config,
HIR {
fnames: ast.entities.field_names,
val_initializers: ast.entities.vals,
Expand Down
13 changes: 7 additions & 6 deletions lumina/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ pub fn build_project(
settings: cli::BuildFlags,
) -> Result<FilePathBuf, ExitCode> {
let mut project_path = env.current_directory.clone();
let lumina_dir = env.lumina_directory.clone();

if let Some(path) = settings.project {
if path.is_absolute() {
project_path = path;
Expand All @@ -35,7 +37,7 @@ pub fn build_project(

let ast = match compiler::ast::parse(
project_path.clone(),
env.lumina_directory.clone(),
lumina_dir.clone(),
settings.epanic,
target.clone(),
) {
Expand All @@ -54,8 +56,7 @@ pub fn build_project(
Ok(pinfo) => pinfo,
};

let project_name = ast.config.name.clone();
let (hir, tenvs, mut iquery) = compiler::hir::run(pinfo, target, ast);
let (pconfig, hir, tenvs, mut iquery) = compiler::hir::run(pinfo, target, ast);

let (mir, has_failed) = compiler::mir::run(pinfo, target, hir, tenvs, &mut iquery);
if has_failed {
Expand All @@ -71,13 +72,13 @@ pub fn build_project(
Some(name) => {
let mut path = std::path::PathBuf::from(name);
while path.is_dir() {
path.push(&project_name);
path.push(&pconfig.name);
}
path
}
None if run => {
let mut path = std::env::temp_dir();
path.push(&project_name);
path.push(&pconfig.name);
path.set_extension(target.executable_extension());
path
}
Expand All @@ -87,7 +88,7 @@ pub fn build_project(
}
};

link_native_binary(target, project_name, &output, env.lumina_directory, object)?;
link_native_binary(pconfig, target, &output, project_path, lumina_dir, object)?;

Ok(output)
}
Expand Down
6 changes: 6 additions & 0 deletions lumina/tests/examples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,9 @@ fn example_using_ext_library() {
fn example_modules() {
run("examples/modules", "HelloWorld\nHelloWorld\n");
}

#[cfg(unix)]
#[test]
fn example_ffi() {
run("examples/ffi", "");
}

0 comments on commit ffe88b8

Please sign in to comment.