neithanmo / csound-rs

This is a Rust bindings for Csound.
MIT License
13 stars 5 forks source link

distributing csound with an app built with csound-rs #1

Open sprucely opened 5 years ago

sprucely commented 5 years ago

I'm excited to see this project! I had just started toying with creating a rust wrapper for csound when I came across this. I was using libloading and some of the output from bindgen. I got as far as verifying that calls to "createCsound" and "destroyCsound" were working. Not sure it was necessary now, but I went the libloading route because I thought that would simplify the licensing issues with linking against lgpl code.

If I want to distribute csound with an application built using this crate, do you know if it would be possible to use it in an arbitrary folder by setting the environment variable "LD_LIBRARY_PATH" using std::env::set_var?

neithanmo commented 5 years ago

Hello sprucely, I have been working in this bindings for around 3 months, But it is a working in progress yet.. I din't know libloading, if I understood correctly, you want to distribute a rust application which uses this crate? O what you are trying to say is that libloading could be used to load the csound native library when this crate is compiled?.

For compiling this crate the libcsound.so have to be installed in the system, and the user only need to export the CSOUND_LIB_DIR with the current path to csound64, It have to be done either in linux or windows. libloading seems to me It can be used for loading symbols from a .so object inside of a rust module, but I don't know if it could be used inside of a build script to link in a platform agnostic way to the libcsound64 library..could llibloading be used for?

sprucely commented 5 years ago

Here's what I have so far using libloading. (Disclaimer: I just started learning rust)

#![recursion_limit = "1024"]

extern crate libloading as lib;
#[macro_use]
extern crate error_chain;

mod errors {
    error_chain!{}
}

use std::env;
pub use errors::*;

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct CSOUND_ {
    _unused: [u8; 0],
}
pub type CSOUND = CSOUND_;

pub struct CSoundWrapper {
    csound_ptr: *mut CSOUND,
    csound_lib: lib::Library
}

impl CSoundWrapper {
    pub fn new() -> Result<CSoundWrapper> {

        let csound_lib = lib::Library::new("lib/libcsound64.so")
            .chain_err(|| "unable to open csound library")?;
        let csound_ptr;

        env::set_var("OPCODE6DIR64", "lib/csound/plugins64-6.0");

        unsafe {
            let csound_create: lib::Symbol<unsafe extern fn() -> *mut CSOUND> = csound_lib.get(b"csoundCreate")
                .chain_err(|| "unexpected error creating csound instance")?;
            csound_ptr = csound_create();
        }    

        Ok(CSoundWrapper {
            csound_lib: csound_lib,
            csound_ptr: csound_ptr
        })
    }
}

impl Drop for CSoundWrapper{
    fn drop(&mut self) {
        unsafe {
            let csound_destroy: lib::Symbol<unsafe extern fn(*mut CSOUND)> = self.csound_lib.get(b"csoundDestroy").unwrap();
            csound_destroy(self.csound_ptr);
        }
    }
}

#[cfg(test)]
mod tests {

    #[test]
    fn it_works() {

        let _tmp = crate::CSoundWrapper::new();

    }
}

See how I use env::set_var for "OPCODE6DIR64" at runtime as opposed to buildtime? That tells csound where to find its plugins. If I choose to use your crate instead of my CSoundWrapper, I was wondering if I can do the same with environment variable "LD_LIBRARY_PATH" so that it will use the libcsound that is distributed with my godot addon. My goal is to create a custom AudioStream for godot game engine (see gdnative crate) to allow using csound to generate music/effects. It may be okay to require game developers to install csound on their development machine, but I don't want to require game users to install it just to be able to play a game.

I just learned that LD_LIBRARY_PATH is only applicable to posix platforms. Windows has its own conventions for searching for dlls and ways of overriding those conventions via manifest files. I think I can make it work. When I get some time I'll do some testing and let you know how it goes...

neithanmo commented 5 years ago

Ok, I got it.

Well, you can use this crate with yours, either windows or linux and even MacOS you can set env variables. The way libcsound64 is linked is defined in the build.rs script. The current script works in both linux and windows(but Users must install csound and export CSOUND_LIB_DIR var).

If you want this crate can use the csound which will be part of the godon engine, you can modify the build.rs script in order to link against a static version of csound(libcsound64.a), I guess this static version come with all opcodes integrated inside of it, if not, only export the OPCODE6DIR64 var .. I think it would be better than using libloading.

I was thinking about static linking a lot. Modifying the build script will let you to either using dinamic or static linking only by editing your Cargo.toml in your godot package.

Static linking is in my TODO list, but now, I prefer to fix some bugs in the current work and do improvements. But if you want to collaborate with that, would be grate!

more info about build scripts here

sprucely commented 5 years ago

Having an option in Cargo.toml to control static/dynamic linking might be helpful for some developers, but static linking is not something I would use because that would force me to license my code under csound's LGPL license. I much prefer releasing code under a more permissive license like MIT. Of course I probably shouldn't worry about licensing at this point, and just get something working.