-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
RFC: Overhaul Cargo's build command support #403
Conversation
This RFC is targeted at overhauling the `build` command in Cargo manifests to be more robust and fully functional for building and linking native code. While largely targeted at Cargo, this RFC includes a few minor changes to the compiler itself, hence posting this RFC in this repository. The high level summary of this RFC is: 1. Instead of having the `build` command be some form of script, it will be a rust command instead 2. Establish a namespace of `foo-sys` packages which represent the native library `foo`. These packages will have Cargo-based dependencies between `*-sys` packages to express dependencies among C packages themselves. 3. Establish a set of standard environment variables for build commands which will instruct how `foo-sys` packages should be built in terms of dynamic or static linkage, as well as providing the ability to override where a package comes from via environment variables.
there's a number of |
and |
|
||
The responsibility of the build script is to ensure that all requested native | ||
libraries are available for the crate to compile. The conceptual output of the | ||
build script will be metadata metadata on stdout explaining how the compilation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"metadata metadata'
+1 Using Rust for building makes life easier when you need something very complex. The ability to wrap native dependencies as Cargo packages makes it possible to solve these problems isolated without having to redistribute the solution across the ecosystem manually. To overcome the problem with negation, perhaps some form of wildcard target triple can be used, and explicitly negate with an explicit dependency that gives an error message if it does not match the positive one. |
extra support code. | ||
|
||
This RFC does not propose a convention of what to name the build script files. | ||
Like `links`, it will be illegal to specify `build` without specifying `links`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume that one would just use links = []
when only using build
for code-generation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah actually now that I've thought about code generation I think I'll lift this requirement. I'll change the conditions for being run to "at least one of links
was not overridden or links
was empty to start out with", and there would just be no arguments to the script in this case.
Down the road, I'd prefer to use the build scripts less for their side effects, and more to marshal data directly--say parse files, splice the parsed AST with a generated one, and then invoke the compiler. The build script would be library dynamically loaded by cargo, and (dynamically) linked to cargo and the compiler. This approach seems a bit more elegant, and, if nixos is any guide, makes caching and implicit data parallelism for distributed builds more easier. Of course, without much rust->rust dynamic linking support this isn't feasible at the movement, and for integration with external tools, side effects will still be necessary. So I say definitely this is an improvement and +1 for now, but I hope the ideas mentioned above will be considered in some form for the long term. |
Can we separate the fetch/configure/build steps please? If Rust is going to be a systems language, Cargo won't always be the top of the build chain.
|
compile.rs will only ever be to invoke third party tools like automake / I suppose you could write a c compiler (eg clang) invoker in it, but it Can you elaborate on the fetch / build / configure thing? Why would you ever want the c compile step to be broken into distinct
|
@Jurily I agree with @shadowmint that the separation of the build steps seems orthogonal to the build cmd aspect of Cargo. I also do not plan to create a sub-project of cargo to reinvent autotools. I expect that, if necessary, those sorts of libraries will grow naturally in the ecosystem. I'll have to write a few shims for various packages to get Cargo itself working, but I don't plan on undertaking a huge endeavor right out of the gates. |
Should the output of the build script be cached? (the metadata and rustc_flag) In some situations it is desirable to cache it (for example if you generate Rust code, there's no reason why anything would change), but sometimes not (if you are pointing to a library in Eridius on #cargo suggested to add a flag to tell cargo whether or not it should be cached. In which case I think that this flag should be added to the output of the script. I like this idea. |
@tomaka how would control that at a fine level? If you had something like:
Then cargo will assume it has to cache all the build steps, which categorically wrong for building c libraries; in general the build tool (make, whatever) will already have the functionality built in to detect file system level changes and invoke the compiler if required. For a sys-foo package this won't be an issue because once the crate is compiled it won't be recompiled on each build anyway. For a normal package with code gen it won't be an issue because once the crate is compiled as a dependency it won't be compiled again. So... it's really only useful if the top level application is using a build step to generate code, and you don't want to run that build step on every compile. Any (Personally I'm not sure how useful this would actually be; I'm skeptical many top-level applications would use a build step, but I suppose it might make things slightly easier in some specific cases?) |
I was not thinking of a flag for the
As with other small improvements, I guess we'll see later if there's a need for this. |
Oh fair enough. I still don't see how useful that will be, given dependencies only get build once anyway, but if there's a need for it that seems fair enough. How would cargo cache the data between builds? |
That's the problem here. Let's say that the build script of If you run That's why in my opinion it is desirable to run all the build scripts every time you run The consequence of this, however, is that in the Case study: generated code, we need to make sure that the code is recompiled if |
mm... I don't have any strong feeling either way. I'm not exactly sure what use case is being served by making cargo rebuild every dependency every build on the off chance some system settings might have changed. CI on travis / cdash maybe? I guess that's plausible. I'd probably err on the side of waiting until it was actually an issue that is troubling people rather than trying to future proof against it, but that's just my $0.02. |
@tomaka no, that's why cargo needs to ask |
@o11c Why would cargo ever talk to pkg-config? On Thu, Oct 23, 2014 at 4:52 PM, o11c [email protected] wrote:
|
@tomaka I do think we'll need to cache it to forward metadata down to dependent packages. We should probably follow today's rebuilding heuristics in terms of when we run the build command which is to say that any package with a Which is to say I don't think the build scripts should unconditionally run on all |
Along with |
to the same C library, the C dependency should be refactored into a common | ||
Cargo-packaged dependency. | ||
|
||
It is illegal to define `link` without also defining `build`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/link/links/
Doing per-target-triple dependencies sounds maybe too precise. I could imagine there being per-target-triple dependencies, but I would think that more common would be per-OS dependencies. |
path = "winhttp" | ||
``` | ||
|
||
Here the top-level configuration key `platform` will be a table whose sub-keys |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This says "platform" but the example uses "target".
A search path for native libraries seems somewhat orthogonal to the rustc changes mentioned here, perhaps that's best left for another time. Issues like rust-lang/rust#16402 may also provide a solution there as well. I agree that the per-triple dependencies may be a little too precise, but I do also feel that we'll always need such a level of precision, we may just want to generalize it later to something more compatible. For example we may want to support something like |
Merged. Discussion. Tracking. |
This is an implementation of the rustc bits of [RFC 403][rfc]. This adds a new flag to the compiler, `-l`, as well as tweaking the `include!` macro (and related source-centric macros). The compiler's new `-l` flag is used to link libraries in from the command line. This flag stacks with `#[link]` directives already found in the program. The purpose of this flag, also stated in the RFC, is to ease linking against native libraries which have wildly different requirements across platforms and even within distributions of one platform. This flag accepts a string of the form `NAME[:KIND]` where `KIND` is optional or one of dylib, static, or framework. This is roughly equivalent to if the equivalent `#[link]` directive were just written in the program. The `include!` macro has been modified to recursively expand macros to allow usage of `concat!` as an argument, for example. The use case spelled out in RFC 403 was for `env!` to be used as well to include compile-time generated files. The macro also received a bit of tweaking to allow it to expand to either an expression or a series of items, depending on what context it's used in. [rfc]: rust-lang/rfcs#403
This reverts commit 2baf8d3.
This RFC is targeted at overhauling the
build
command in Cargo manifests to bemore robust and fully functional for building and linking native code. While
largely targeted at Cargo, this RFC includes a few minor changes to the compiler
itself, hence posting this RFC in this repository.
The high level summary of this RFC is:
build
command be some form of script, it will be arust command instead
foo-sys
packages which represent the nativelibrary
foo
. These packages will have Cargo-based dependencies between*-sys
packages to express dependencies among C packages themselves.will instruct how
foo-sys
packages should be built in terms of dynamic orstatic linkage, as well as providing the ability to override where a package
comes from via environment variables.
Rendered