-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Description
The custom build command is a very wonky mechanism. It is not cross-platform, it assumes that the user has certain softwares installed on his system and available in his PATH (usually make/gcc, sometimes curl), it does not support cross-compilation, etc. Basically it is like having a makefile without a configure script.
This is especially problematic on Windows. Because of this command, a lot of Rust libraries depend on the user having MinGW installed (even though rustc no longer requires this), and some libraries simply can't be compiled on Windows, like glfw-rs. I have the sensation that all the efforts spent on improving support for Windows are worthless because of this.
I propose to deprecate the build command. At first, print a warning when compiling a crate that uses it, and in a second time remove support for it entirely.
Replacements
This command should be replaced by two complementary mechanisms.
Binary dependencies
Add a pre-build string entry in Cargo.toml. This string must in the format $package/$bin where $package is the name of a dependency in the dependencies array, and $bin is the name of a binary found in this dependency. The binary will be compiled and then run by Cargo similarly to the current build command.
The binary would have access to the environment variables that the build currently has access to, plus an additional one named COMMAND_CARGO_MANIFEST_DIR which contains the directory of the Cargo manifest of the dependency (instead of the manifest of the package where the command is being run).
Example:
/Cargo.toml:
[package]
name = "whatever"
authors = []
pre-build = "my-compiler/compile"
[dependencies.my-compiler]
path = "my-compiler"/my-compiler/Cargo.toml:
[package]
name = "my-compiler"
authors = []
[[bin]]
name = "compile"Why is this better than a regular build command?
- Instead of having a makefile run
curlfor example, you can instead write a binary that uses a Rust http library, which is more cross-platform because it does not require the user to havecurlin his path. - In situations where you would need a very complex pre-build script (for example invoking cmake (which requires determining the list of generators and invoking the right one)), instead of writing a difficult-to-maintain makefile that you copy-paste in multiple projects, you could simply use a Rust library.
Add native
Add a native array in Cargo.toml that specifies a list of non-rust libraries that must be present for this project to compile.
[[native]]
name = "GL"
[[native]]
name = "X11"
[[native]]
name = "Xxf86vm"Cargo will process each entry in this order:
- Try to find a pre-compiled version of the library (if
Xis the library name, try to findlibX.*andX.*) in$package_root/native/$target. If it finds a match, copy the file in$(OUT_DIR).
For example if you are compiling forarm-linux-androideabiand require a library namedhello, Cargo will look fornative/arm-linux-androideabi/libhello.*andnative/arm-linux-androideabi/hello.*. - If we are not cross-compiling (ie. no
--targetoption has been passed) and if we didn't find anything in the previous step, try to invokepkg-config. If a result is found, pass the path of the library to rustc with the-Lflag. - If we didn't find anything in the previous steps, try to find a pre-compiled version of the library in
$(HOME)/.rust. There is no additional step because rustc already looks into$(HOME)/.rust. Cargo must still check if the library is present. - If nothing is found, print an error and stop. An additional flag
--ignore-missing-native-libscould be added to Cargo in order to bypass this error and print a warning instead.
This system could be improved in the future by adding more entries to native, for example allowing the user to choose whether to link statically or dynamically.