curryrs icon indicating copy to clipboard operation
curryrs copied to clipboard

Let Haskell tell rustc which libs it needs.

Open mat8913 opened this issue 8 years ago • 9 comments

(Note: I don't expect this to be merged in its current state. There are a few problems which I am looking for suggestions on.)

Description

A custom Setup.hs is used on the Haskell side which figures out what libs are needed and outputs that as "cargo:" keys. A custom build.rs is used on the Rust side to pass those keys onto Cargo.

Use case

Suppose you have a Rust project and you would like to use some Haskell functions in it. You have the Haskell part of your project managed by Cabal and you want an easy way to link to it from Cargo. Here's what to do:

To the Cabal part:

  1. Change the build-type to "Custom"
  2. Add "curryrs" to your setup-depends
  3. Change your "Setup.hs" to this:
import Curryrs.Build
main = curryrsMain

To the Cargo part:

  1. Add "curryrs" to your build-dependencies
  2. In your build script, add a call to curryrs::build::link_package

Then just run "cargo build". It will build the Haskell package and link the required libs for you.

Currently, the shared lib versions are linked for all except for the package itself.

Problems

  • No Stack support
  • No support for choosing an rts
  • Haskell's "curryrs" now depends on "Cabal" (Would it be better to put Curryrs.Build in a separate package?)
  • "htest" now depends on "curryrs"

mat8913 avatar Jan 01 '17 08:01 mat8913

Hey thanks for taking the time to work on this! If I'm understanding this correctly what this is doing is automatically building the Haskell packages via cargo build rather than using a Makefile right? If so that's pretty cool!

So with your problems, I do want to maintain stack support since it's a good build tool and some people might only use that rather than cabal or vice versa. I'm not sure if there's a way to support custom Setup.hs files in stack so I'd look into that if possible.

If you look at the Rust code you might see the feature flags let you choose the runtime and that's what gets linked by curryrs so that when you tell the Haskell runtime to start it's using that. Did that functionality get removed somehow because that's how you should be able to choose the rts for programs when they run.

I'm not sure about a separate package. I kind of want to think this one over before making a decision.

htest already indirectly depended on curryrs to run so I think this is fine but I'll have to look it over just to be sure.

mgattozzi avatar Jan 01 '17 20:01 mgattozzi

Hey thanks for taking the time to work on this! If I'm understanding this correctly what this is doing is automatically building the Haskell packages via cargo build rather than using a Makefile right? If so that's pretty cool!

Yes, that is correct. However, I forgot to mention that this requires the Haskell "curryrs" to already be installed.

So with your problems, I do want to maintain stack support since it's a good build tool and some people might only use that rather than cabal or vice versa. I'm not sure if there's a way to support custom Setup.hs files in stack so I'd look into that if possible.

I've never used Stack before but it seems that Stack supports .cabal files. Is a Stack project required to have a valid .cabal file or is it just there for comparability with Cabal?

If you look at the Rust code you might see the feature flags let you choose the runtime and that's what gets linked by curryrs so that when you tell the Haskell runtime to start it's using that. Did that functionality get removed somehow because that's how you should be able to choose the rts for programs when they run.

I use Cabal's InstalledPackageIndex to find out how to link to everything. Unfortunately, Cabal doesn't know about the different flavors of rts. I'm going to try hardcoding the different flavors of rts since they seem to be the same across platforms.

mat8913 avatar Jan 02 '17 06:01 mat8913

Yes, that is correct. However, I forgot to mention that this requires the Haskell "curryrs" to already be installed. Ohhh I was wondering what that meant. You're saying it has to be installed locally for it to work? Is there some way to just get this into the package alone so as to not have people to install extra stuff as part of the setup process?

Stack uses cabal files under the hood to figure things out and how to compile everything. stack.yaml is used to specify other things needed that aren't in the LTS. If you haven't I'd recommend taking a look at it, but it's not required. This package just is meant to work for both. Stack uses cabal to do it's compilation it seems. It looks like in this article they mention that Setup.hs is used.

I use Cabal's InstalledPackageIndex to find out how to link to everything. Unfortunately, Cabal doesn't know about the different flavors of rts. I'm going to try hardcoding the different flavors of rts since they seem to be the same across platforms.

That should be fine. Not a big fan of hardcoding if avoidable but It's not always possible. I don't think the RTS will change much anytime soon and it's only like 4 versions so adding to them later if needed is fine.

mgattozzi avatar Jan 03 '17 20:01 mgattozzi

Ohhh I was wondering what that meant. You're saying it has to be installed locally for it to work? Is there some way to just get this into the package alone so as to not have people to install extra stuff as part of the setup process?

The only way I can think of is to copy src/Curryrs/Build.hs to htest/Curryrs/Build.hs and keep the two in sync.

Stack uses cabal files under the hood to figure things out and how to compile everything. stack.yaml is used to specify other things needed that aren't in the LTS. If you haven't I'd recommend taking a look at it, but it's not required. This package just is meant to work for both. Stack uses cabal to do it's compilation it seems. It looks like in this article they mention that Setup.hs is used.

I've had a bit of a play around with Stack. Unfortunately, Stack doesn't allow specifying a --work-dir above the current directory. This is needed to ensure all Haskell output goes into Cargo's target directory.

That should be fine. Not a big fan of hardcoding if avoidable but It's not always possible. I don't think the RTS will change much anytime soon and it's only like 4 versions so adding to them later if needed is fine.

Ok, my latest commit re-adds the ability to select an RTS. Also, on my system there seems to be a couple extra RTS flavors available so I updated the feature flags to make them selectable.

mat8913 avatar Jan 05 '17 15:01 mat8913

You could do a symlink for the build file. It'll just point to one file but it's treated as if it's in the same directory.

I've had a bit of a play around with Stack. Unfortunately, Stack doesn't allow specifying a --work-dir above the current directory. This is needed to ensure all Haskell output goes into Cargo's target directory.

Really? That seems like a bad idea on Stack's part but they might have a reason.

mgattozzi avatar Jan 05 '17 15:01 mgattozzi

You could do a symlink for the build file. It'll just point to one file but it's treated as if it's in the same directory.

Right, I forgot about symlinks. But would that still work on Windows?

Really? That seems like a bad idea on Stack's part but they might have a reason.

They have an open issue here: commercialhaskell/stack#1731

mat8913 avatar Jan 05 '17 23:01 mat8913

Looks like it's blocked by this causing windows to not work.

Symlink would work on one but not the other I would think and it would conflict. I wonder if Haskell has a macro like Rust's include!() that could solve the issue.

mgattozzi avatar Jan 06 '17 17:01 mgattozzi

Haskell has #include directives via CPP but the Setup.hs file gets copied to a different location before it gets compiled so it wont be as simple as

#include "../src/Curryrs/Build.hs"

mat8913 avatar Jan 07 '17 00:01 mat8913

Yeah and I'm not too much of a fan of #include. It's a bit too hand wavy and compiler magic.

mgattozzi avatar Jan 09 '17 18:01 mgattozzi