Skip to content

Assist writing/using crates that should not have any code inlined into dependent crates #16159

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
huonw opened this issue Aug 1, 2014 · 5 comments
Labels
A-lints Area: Lints (warnings about flaws in source code) such as unused_mut.

Comments

@huonw
Copy link
Member

huonw commented Aug 1, 2014

AIUI, a license like the LGPL can be linked into a non-(L)GPL program only if it can be completely substituted for a replacement by the user (i.e. dynamically linked, with no inlined code/constants etc.). This means a LGPL Rust crate can only be used in non-(L)GPL programs if no code is inlined or otherwise codegened from it (e.g. generics).

We could have lint(s) that makes writing and using such libraries easier by warning/marking items that require codegen in the user crate (e.g. generics) and those that recommend copying data/code from one crate into another (e.g. non-#[inline(never)] statics, #[inline] functions). Note that the latter doesn't require inlining, and so doesn't necessarily have to be included in the first lint.

This could even include a #[no_inlining] extern crate some_lgpl_crate; attribute, that doesn't read crate metadata (making the compiler ignore #[inline] attributes and the AST metadata in that crate, and disallowing instantiating generic functions).

#![warn(items_requiring_crosscrate_inlining)]
#![warn(public_inlinable_items)]

static FOO: uint = 10; // warning: statics can be inlined by default, consider adding #[inline(never)]

pub fn foo<T>(...) { // warning: generic functions require inlining
   // ...
}

#[inline] // warning: inline attribute on public item
pub fn bar(...) {
    // ...
}
#[no_inlining]
extern crate foo;

fn main() {
    foo::bar::<int>() // error: instantiating generic function from crate `foo`, which is marked no_inlining

    // not inlined, just called as a non-#[inline] function would be
    foo::some_inlinable_function();
}
@AaronFriel
Copy link
Contributor

Please forgive me for any ignorance that follows from me, I have only recently started reading about Rust.

Would it be possible for the compiler to instantiate generics in a two-stage process, i.e.: suppose I have two Rust crates, lgpl and bsd. I would like bsd to utilize lgpl but not to incorporate any generics or inlined code, to make sure the libbsd binary is distributable under BSD license when dynamically linked with liblgpl.

Could the Rust compiler instantiate generics in a third, dynamically created crate, or dynamically modify liblgpl to instantiate the generics I export, producing a new liblgpl?

So the resulting hierarchy would be:

libbsd depends on liblgpl and liblgpl-generics
liblgpl-generics is the result of using metadata from my library and liblgpl to instantiate any generics, and depends on liblgpl.

Does that make sense?

@AaronFriel
Copy link
Contributor

Another thought that occurs to me is to utilize the very-late-binding approach that LLVM offers on some platforms to perform whole program optimization. If it was possible to realize generics as LLVM bitcode1 and compile to a static binary at installation time, you could work around library issues. The resulting binary would be generated on the end-user's machine. Rust would have to use something along the lines of LLVM's link time optimization model.

The benefit of this is that all installed libraries would be statically compiled, and I suspect link-time/whole program optimization is something that will concern Rust developers in the future anyhow. But is that an endeavor worth pursuing now? I am too ignorant to say.

1 - The immediate issue though is whether or not LLVM bitcode is an attractive target for generics to hit. My guess is that it would take substantial work to allow libraries to be compiled with generic metadata written in terms of LLVM bitcode, and it would take work on the linker side to then utilize that knowledge in linking libraries at installation time.

@brson
Copy link
Contributor

brson commented Aug 1, 2014

While this sounds like a useful thing to be able to determine, I've never heard that argument about LGPL being incompatible with inlining / monomorphization, a problem C++ would also have (though it sounds plausible). References?

@huonw
Copy link
Member Author

huonw commented Aug 2, 2014

I was just relaying concerns from here, I'm not sure of all the details myself.

Looking into the license itself, it seems there's some scope for allowing inlining/monomorphisation etc. in LGPL v3 (some research just now indicates this possibly wasn't the case for LGPL v2), although Rust's lack of 'headers' may leave us in limbo (maybe?).

@steveklabnik
Copy link
Member

I'm pulling a massive triage effort to get us ready for 1.0. As part of this, I'm moving stuff that's wishlist-like to the RFCs repo, as that's where major new things should get discussed/prioritized.

This issue has been moved to the RFCs repo: rust-lang/rfcs#662

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lints Area: Lints (warnings about flaws in source code) such as unused_mut.
Projects
None yet
Development

No branches or pull requests

4 participants