Skip to content

Instantly share code, notes, and snippets.

@z0w0
Last active October 19, 2020 14:45
Show Gist options
  • Save z0w0/4965917 to your computer and use it in GitHub Desktop.
Save z0w0/4965917 to your computer and use it in GitHub Desktop.
What's Rustpkg?

What's Rustpkg?

Rustpkg is a revamp of Cargo that brings awesome new features such as a build system described in build scripts. It's a purely functional package manager that has no central sources of any kind, but rather installs via URLs. It's similar to how Go's go get tool works, except Rustpkg requires a central metadata file (pkg.rs) in the repository, archive or folder in order to figure out how to build the package. This is a side effect of Rustpkg allowing multiple crates to be defined in a single package (i.e. a package is defined as a set of crates rather than a package being exactly the same as one crate). There's a plan to make it so the pkg.rs is not needed for single-crate packages, if you're not a fan of having to create a pkg.rs file and would rather it just find .rc files.

The metadata is written in Rust. This is both good and bad. One con is that Rust's syntax is going to be moderately unstable until v1.0 (as I was told), so compiling an old package might spring up weird compiling errors. On the other hand, you get to write the build process in Rust itself which is so incredibly meta and fun and you get to use an awesome language to build projects in that same awesome language.

Rustpkg also doubles as a powerful build system that gives you two ways to describe the build process of projects: declarative and imperative. The declarative syntax allows you to declare the build process using Rust's attribute syntax. A simplistic declarative package script (pkg.rs) would be something like the following (Servo doesn't actually use Rustpkg, it's just an example):

#[pkg(id = "org.mozilla.servo",
      vers = "0.5.6")];

#[pkg_dep(url = "git://github.com/mozilla-servo/rust-xlib")];

#[pkg_crate(file = "src/servo.rc")];
#[pkg_crate(file = "src/servo-gfx.rc")];

The imperative API is for when you need a more powerful build process, such as probing the system for important configuration, running shell scripts (or even autotools, which is a planned built-in feature that I want to add). A simple example using the imperative API is as follows (Rustpkg is automatically linked into package scripts):

#[pkg(id = "org.mozilla.servo",
      vers = "0.5.6")];

#[pkg_dep(url = "git://github.com/mozilla-servo/rust-xlib")];

#[pkg_do(build)]
fn build() {
   let platform = if os::is_toaster() { ~"platform=toaster" }
                  else { ~"platform=alien" };
   let crate = rustpkg::Crate(~"src/servo.rc").cfg(platform).flag(~"-g");

   rustpkg::build(~[crate]);
}

When a package's crates are installed, they are stored under a unique name (Rust's library crates work like this out of the box) in ~/.rustpkg/bin or ~/.rustpkg/lib. This allows packages to coexist in a purely functional manner. However, if you want to easily use a binary crate that has been installed from the ~/.rustpkg/bin path (after adding it to your $PATH) then rustpkg provides "preferring" functionality to symlink a generic name for the crate into the binary directory (which voids the purely functional label, which is why it's explicitly optional). For example, if you had a crate with the name servo and it's uniquely installed to ~/.rustpkg/bin/servo-<hash>-0.5.6 then rustpkg prefer servo would link it to ~/.rustpkg/bin/servo which you can then easily run as just servo if the binary directory is in your $PATH.

All crates are built and installed into ~/.rustpkg, but I'm planning on changing it so that crates are initially built into .rustpkg without unique hashing (only for binaries.. obviously library crates will still need the hashing kept intact). This allows you to easily run a built crate without installing it (I'll probably provide a rustpkg run <crate> command to compile and run a crate). Crates are then copied from .rustpkg to ~/.rustpkg. This patch will also remove uninstalling packages because it's not really needed for now.

Preferring is currently pretty dodgy, along with some of the other features. But that's to be expected due to this being the initial implementation and I plan to perfect it over time (including documentation). I still really want to add the following but they're not important for the initial pull request:

  • More features of the imperative API
  • Use the JIT for package scripts (JIT segfaults for me at the moment)
  • Use std::workcache for only compiling things that have changed
  • Add wrappers around autotools, $CC, etc. that also use workcache
  • Allow custom configuration to be declared for dependencies (#[pkg_dep(url = "git://github.com/brson/rust-sdl", target = "image mixer")];)

If you need any more help, either give me a ping on #rust or check out rustpkg --help.

@bstrie
Copy link

bstrie commented Feb 16, 2013

rustpkg prefer servo would link it to ~/.rustpkg/bin/servo which you can then easily run as just servo if the binary directory is in your $PATH.

Does rustpkg prefer automatically append the binary directory to your path if it's not already there? Should it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment