Compare commits
12 Commits
0c70b2a3f7
...
352bf8c286
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
352bf8c286 | ||
|
|
091c70815c | ||
|
|
111b65c708 | ||
|
|
a06f3076c7 | ||
|
|
7d9982112a | ||
|
|
31ae16784a | ||
|
|
b788d6685d | ||
|
|
63efd03382 | ||
|
|
bf0fc90272 | ||
|
|
6028db040d | ||
|
|
7ca469a62d | ||
|
|
b5fd53b5ec |
@ -9,6 +9,8 @@ main = do
|
|||||||
hello "Haskell"
|
hello "Haskell"
|
||||||
helloStruct T{a = True, b = 42}
|
helloStruct T{a = True, b = 42}
|
||||||
helloStruct T{a = False, b = maxBound}
|
helloStruct T{a = False, b = maxBound}
|
||||||
|
helloEnum E1
|
||||||
|
helloEnum E3
|
||||||
helloShape $ Circle 3.14
|
helloShape $ Circle 3.14
|
||||||
helloShape $ Rectangle 10.0 5.0
|
helloShape $ Rectangle 10.0 5.0
|
||||||
putStrLn $ "3 + 4 = " <> show (add 3 4)
|
putStrLn $ "3 + 4 = " <> show (add 3 4)
|
||||||
|
|||||||
13
flake.lock
generated
13
flake.lock
generated
@ -527,15 +527,16 @@
|
|||||||
"hs-bindgen-src": {
|
"hs-bindgen-src": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1774379170,
|
"lastModified": 1774599157,
|
||||||
"narHash": "sha256-lZV6IdCBf8uCt21qB5mfgLaP9CNgho/HsqjvkulDR2Q=",
|
"narHash": "sha256-jgV67xhWzxMwyiyy5RPtu+VQvGTt+FoMXCWJcZ7lczY=",
|
||||||
"owner": "well-typed",
|
"owner": "well-typed",
|
||||||
"repo": "hs-bindgen",
|
"repo": "hs-bindgen",
|
||||||
"rev": "4b6febb5cc6196835bd2890a3ab27a88dab1806b",
|
"rev": "3c4af10590d0d09e825a9735e9a03d7f60914e21",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "well-typed",
|
"owner": "well-typed",
|
||||||
|
"ref": "release-0.1-alpha2",
|
||||||
"repo": "hs-bindgen",
|
"repo": "hs-bindgen",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
@ -560,11 +561,11 @@
|
|||||||
"libclang-src": {
|
"libclang-src": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1774018529,
|
"lastModified": 1774600891,
|
||||||
"narHash": "sha256-Bo5wvityXKCmlnrobtI9WkA1maR7sfkDXo1VOZvrPLk=",
|
"narHash": "sha256-LTAyNMY4Vu0vPeEq2wXB0KWY4kGtqtHTRmADjLdkv78=",
|
||||||
"owner": "well-typed",
|
"owner": "well-typed",
|
||||||
"repo": "libclang",
|
"repo": "libclang",
|
||||||
"rev": "83387d72a8dfae9f75d27db6b32ea37afab06268",
|
"rev": "1054474fae403bfb52c7919680cac03d3d3d4237",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
nix-haskell.url = "github:reflex-frp/nix-haskell";
|
nix-haskell.url = "github:reflex-frp/nix-haskell";
|
||||||
nixpkgs.follows = "nix-haskell/nixpkgs";
|
nixpkgs.follows = "nix-haskell/nixpkgs";
|
||||||
hls-src = { url = "github:haskell/haskell-language-server/2.13.0.0"; flake = false; };
|
hls-src = { url = "github:haskell/haskell-language-server/2.13.0.0"; flake = false; };
|
||||||
hs-bindgen-src = { url = "github:well-typed/hs-bindgen"; flake = false; };
|
hs-bindgen-src = { url = "github:well-typed/hs-bindgen/release-0.1-alpha2"; flake = false; };
|
||||||
libclang-src = { url = "github:well-typed/libclang"; flake = false; };
|
libclang-src = { url = "github:well-typed/libclang"; flake = false; };
|
||||||
flake-utils.url = "github:numtide/flake-utils";
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
crane.url = "github:ipetkov/crane";
|
crane.url = "github:ipetkov/crane";
|
||||||
|
|||||||
11
garnet.cabal
11
garnet.cabal
@ -6,6 +6,13 @@ author: Patrick Aldis
|
|||||||
maintainer:
|
maintainer:
|
||||||
george.thomas@obsidian.systems
|
george.thomas@obsidian.systems
|
||||||
patrick.aldis@obsidian.systems
|
patrick.aldis@obsidian.systems
|
||||||
|
-- aha, nice, this does fix recompilation checking
|
||||||
|
extra-source-files:
|
||||||
|
rust/target/debug/garnet_rs.h
|
||||||
|
-- that could be problematic given file is gitignored? unfortunately this doesn't work
|
||||||
|
-- tbf, I haven't even looked up the docs, just saw the autocompletion
|
||||||
|
-- extra-tmp-files:
|
||||||
|
-- rust/target/debug/garnet_rs.h
|
||||||
|
|
||||||
common common
|
common common
|
||||||
default-language: GHC2024
|
default-language: GHC2024
|
||||||
@ -43,11 +50,13 @@ library
|
|||||||
GarnetRs.Wrapped
|
GarnetRs.Wrapped
|
||||||
hs-source-dirs: lib
|
hs-source-dirs: lib
|
||||||
include-dirs: rust/target/debug
|
include-dirs: rust/target/debug
|
||||||
|
-- HLS gives up entirely when the header is malformed if we do this
|
||||||
|
-- and anyway, I don't think it gives us dependency tracking like `extra-source-files` does
|
||||||
|
-- includes: garnet_rs.h
|
||||||
extra-bundled-libraries: Cgarnet_rs
|
extra-bundled-libraries: Cgarnet_rs
|
||||||
build-depends:
|
build-depends:
|
||||||
hs-bindgen,
|
hs-bindgen,
|
||||||
hs-bindgen-runtime,
|
hs-bindgen-runtime,
|
||||||
primitive,
|
|
||||||
template-haskell,
|
template-haskell,
|
||||||
|
|
||||||
executable garnet
|
executable garnet
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
{-# LANGUAGE CApiFFI #-}
|
{-# LANGUAGE CApiFFI #-}
|
||||||
{-# LANGUAGE DerivingVia #-}
|
{-# LANGUAGE DerivingVia #-}
|
||||||
{-# LANGUAGE FieldSelectors #-}
|
|
||||||
{-# LANGUAGE MagicHash #-}
|
{-# LANGUAGE MagicHash #-}
|
||||||
{-# LANGUAGE PatternSynonyms #-}
|
{-# LANGUAGE PatternSynonyms #-}
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
@ -30,7 +29,15 @@ import HsBindgen.TH
|
|||||||
import Language.Haskell.TH
|
import Language.Haskell.TH
|
||||||
import System.Process
|
import System.Process
|
||||||
|
|
||||||
|
import Control.Monad.IO.Class (MonadIO (liftIO))
|
||||||
|
import Language.Haskell.TH.Syntax (addDependentFile)
|
||||||
|
import System.Directory.Extra (getCurrentDirectory)
|
||||||
|
|
||||||
do
|
do
|
||||||
|
-- not sure this does anything - hs-bindgen should already be doing the tracking, and the issues are from elsewhere
|
||||||
|
-- dir <- liftIO getCurrentDirectory
|
||||||
|
-- liftIO $ print dir
|
||||||
|
-- addDependentFile $ dir <> "/rust/target/debug/garnet_rs.h"
|
||||||
systemDirs <- -- TODO bit of a hack
|
systemDirs <- -- TODO bit of a hack
|
||||||
map (Dir . T.unpack . T.strip)
|
map (Dir . T.unpack . T.strip)
|
||||||
. concatMap (takeWhile (maybe False ((== ' ') . fst) . T.uncons) . dropWhile T.null . T.lines)
|
. concatMap (takeWhile (maybe False ((== ' ') . fst) . T.uncons) . dropWhile T.null . T.lines)
|
||||||
|
|||||||
@ -1,11 +1,20 @@
|
|||||||
|
{-# LANGUAGE PatternSynonyms #-}
|
||||||
|
|
||||||
-- TODO automate this sort of high level wrapper boilerplate
|
-- TODO automate this sort of high level wrapper boilerplate
|
||||||
-- or look at upstream plans: https://github.com/well-typed/hs-bindgen/issues?q=state%3Aopen%20label%3A%22highlevel%22
|
-- or look at upstream plans: https://github.com/well-typed/hs-bindgen/issues?q=state%3Aopen%20label%3A%22highlevel%22
|
||||||
module GarnetRs.Wrapped (
|
module GarnetRs.Wrapped (
|
||||||
T (..),
|
T (..),
|
||||||
|
Raw.E (..),
|
||||||
|
-- TODO hmm, we don't really want to have to list all of these...
|
||||||
|
-- is there an option to make them not be patterns at all?
|
||||||
|
pattern Raw.E1,
|
||||||
|
pattern Raw.E2,
|
||||||
|
pattern Raw.E3,
|
||||||
Shape (..),
|
Shape (..),
|
||||||
BTree (..),
|
BTree (..),
|
||||||
hello,
|
hello,
|
||||||
helloStruct,
|
helloStruct,
|
||||||
|
helloEnum,
|
||||||
helloShape,
|
helloShape,
|
||||||
add,
|
add,
|
||||||
sumTree,
|
sumTree,
|
||||||
@ -38,7 +47,6 @@ data Shape
|
|||||||
convertShape :: Shape -> Raw.Shape
|
convertShape :: Shape -> Raw.Shape
|
||||||
convertShape = \case
|
convertShape = \case
|
||||||
Circle r -> Raw.Shape Raw.Circle $ Raw.set_shape_circle_circle $ Raw.Circle_Body r
|
Circle r -> Raw.Shape Raw.Circle $ Raw.set_shape_circle_circle $ Raw.Circle_Body r
|
||||||
-- hmm, unintuitive name
|
|
||||||
Rectangle w h -> Raw.Shape Raw.Rectangle $ Raw.set_shape_circle_rectangle $ Raw.Rectangle_Body w h
|
Rectangle w h -> Raw.Shape Raw.Rectangle $ Raw.set_shape_circle_rectangle $ Raw.Rectangle_Body w h
|
||||||
|
|
||||||
data BTree a
|
data BTree a
|
||||||
@ -63,6 +71,9 @@ hello = flip useAsCString $ Raw.hello . unsafeFromPtr
|
|||||||
helloStruct :: T -> IO ()
|
helloStruct :: T -> IO ()
|
||||||
helloStruct = flip with (Raw.hello_struct . unsafeFromPtr) . convertT
|
helloStruct = flip with (Raw.hello_struct . unsafeFromPtr) . convertT
|
||||||
|
|
||||||
|
helloEnum :: Raw.E -> IO ()
|
||||||
|
helloEnum = flip with (Raw.hello_enum . unsafeFromPtr)
|
||||||
|
|
||||||
helloShape :: Shape -> IO ()
|
helloShape :: Shape -> IO ()
|
||||||
helloShape = flip with (Raw.hello_shape . unsafeFromPtr) . convertShape
|
helloShape = flip with (Raw.hello_shape . unsafeFromPtr) . convertShape
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,22 @@ use std::env;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
// this doesn't make _much_ difference really, since this is our only Rust source file
|
||||||
|
// but it seems it's probably better than not having it
|
||||||
|
// what we really want is to tell Rust to only regenerate the header file if the Rust code actually compiles
|
||||||
|
// but we don't have that flexibility
|
||||||
|
// and it's an issue because cbindgen tries to be fault-tolerant in some ways that don't even seem to make sense
|
||||||
|
//
|
||||||
|
// e.g. mis-spell "Option" as "Option" and you get
|
||||||
|
// void print_optional(Optio<const int8_t*> x);
|
||||||
|
// instead of
|
||||||
|
// void print_optional(const int8_t *x);
|
||||||
|
// and that's only an issue because in HLS TH dependent-file watching gives up after an error
|
||||||
|
// i.e. once the containing splice has thrown an exception once, the containing file needs a manual edit to kick it
|
||||||
|
// P.S. strings to stdout?! what a terrible API
|
||||||
|
// don't get me started in the discoverability of actually then using the terminal for debugging:
|
||||||
|
// println!("cargo::warning={:?}", env::var("OUT_DIR"));
|
||||||
|
println!("cargo::rerun-if-changed=lib.rs");
|
||||||
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||||
let profile = env::var("PROFILE").unwrap();
|
let profile = env::var("PROFILE").unwrap();
|
||||||
cbindgen::Builder::new()
|
cbindgen::Builder::new()
|
||||||
|
|||||||
28
rust/lib.rs
28
rust/lib.rs
@ -11,7 +11,7 @@ fn say_hello(name: &str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn hello(c: *const c_char) -> () {
|
extern "C" fn hello(c: *const c_char) {
|
||||||
say_hello(unsafe { CStr::from_ptr(c) }.to_str().unwrap())
|
say_hello(unsafe { CStr::from_ptr(c) }.to_str().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,10 +23,23 @@ struct T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn hello_struct(t: &T) -> () {
|
extern "C" fn hello_struct(t: &T) {
|
||||||
say_hello(&format!("{:?}", t))
|
say_hello(&format!("{:?}", t))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum E {
|
||||||
|
E1,
|
||||||
|
E2,
|
||||||
|
E3,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "C" fn hello_enum(e: &E) {
|
||||||
|
say_hello(&format!("{:?}", e))
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Shape {
|
enum Shape {
|
||||||
@ -35,7 +48,7 @@ enum Shape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn hello_shape(s: &Shape) -> () {
|
extern "C" fn hello_shape(s: &Shape) {
|
||||||
say_hello(&format!("{:?}", s))
|
say_hello(&format!("{:?}", s))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +93,7 @@ enum BTreeC {
|
|||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn sum_tree(t: &BTreeC) -> i64 {
|
extern "C" fn sum_tree(t: &BTreeC) -> i64 {
|
||||||
(unsafe { std::mem::transmute::<_, &BTree<i64>>(t) }).sum()
|
(unsafe { std::mem::transmute::<&BTreeC, &BTree<i64>>(t) }).sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
@ -89,9 +102,8 @@ extern "C" fn sum_slice(v: *const i64, s: usize) -> i64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn print_optional(x: Option<&i8>) -> () {
|
extern "C" fn print_optional(x: Option<&i8>) {
|
||||||
match x {
|
if let Some(x) = x {
|
||||||
Some(x) => println!("{}", x / 2),
|
println!("{}", x / 2)
|
||||||
None => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user