|
| 1 | +% The Rust Packaging Guide |
| 2 | + |
| 3 | +# Introduction |
| 4 | + |
| 5 | +Sharing is caring. Rust comes with a tool, `rustpkg`, which allows you to |
| 6 | +package up your Rust code and share it with other people. This guide will |
| 7 | +get you started on all of the concepts and commands you need to give the gift |
| 8 | +of Rust code to someone else. |
| 9 | + |
| 10 | +# Installing External Packages |
| 11 | + |
| 12 | +First, let's try to use an external package somehow. I've made a sample package |
| 13 | +called `hello` to demonstrate how to do so. Here's how `hello` is used: |
| 14 | + |
| 15 | +~~~~ |
| 16 | +extern mod hello; |
| 17 | +
|
| 18 | +fn main() { |
| 19 | + hello::world(); |
| 20 | +} |
| 21 | +~~~~ |
| 22 | + |
| 23 | +Easy! But if you try to compile this, you'll get an error: |
| 24 | + |
| 25 | +~~~~ {.notrust} |
| 26 | +$ rustc main.rs |
| 27 | +main.rs:1:0: 1:17 error: can't find crate for `hello` |
| 28 | +main.rs:1 extern mod hello; |
| 29 | + ^~~~~~~~~~~~~~~~~ |
| 30 | +~~~~ |
| 31 | + |
| 32 | +This makes sense, as we haven't gotten it from anywhere yet! Luckily for us, |
| 33 | +`rustpkg` has an easy way to fetch others' code: the `install` command. It's |
| 34 | +used like this: |
| 35 | + |
| 36 | +~~~ {.notrust} |
| 37 | +$ rustpkg install PKG_ID |
| 38 | +~~~ |
| 39 | + |
| 40 | +This will install a package named `PKG_ID` into your current Rust environment. |
| 41 | +I called it `PKG_ID` in this example because `rustpkg` calls this a 'package |
| 42 | +identifier.' When using it with an external package like this, it's often a |
| 43 | +URI fragment. You see, Rust has no central authority for packages. You can |
| 44 | +build your own `hello` library if you want, and that's fine. We'd both host |
| 45 | +them in different places and different projects would rely on whichever version |
| 46 | +they preferred. |
| 47 | + |
| 48 | +To install the `hello` library, simply run this in your terminal: |
| 49 | + |
| 50 | +~~~ {.notrust} |
| 51 | +$ rustpkg install github.com/steveklabnik/hello |
| 52 | +~~~ |
| 53 | + |
| 54 | +You should see a message that looks like this: |
| 55 | + |
| 56 | +~~~ {.notrust} |
| 57 | +note: Installed package github.com/steveklabnik/hello-0.1 to /some/path/.rust |
| 58 | +~~~ |
| 59 | + |
| 60 | +Now, compiling our example should work: |
| 61 | + |
| 62 | +~~~ {.notrust} |
| 63 | +$ rustc main.rs |
| 64 | +$ ./main |
| 65 | +Hello, world. |
| 66 | +~~~ |
| 67 | + |
| 68 | +Simple! That's all it takes. |
| 69 | + |
| 70 | +# Workspaces |
| 71 | + |
| 72 | +Before we can talk about how to make packages of your own, you have to |
| 73 | +understand the big concept with `rustpkg`: workspaces. A 'workspace' is simply |
| 74 | +a directory that has certain sub-directories that `rustpkg` expects. Different |
| 75 | +Rust projects will go into different workspaces. |
| 76 | + |
| 77 | +A workspace consists of any directory that has the following |
| 78 | +directories: |
| 79 | + |
| 80 | +* `src`: The directory where all the source code goes. |
| 81 | +* `build`: This directory contains all of the build output. |
| 82 | +* `lib`: The directory where any libraries distributed with the package go. |
| 83 | +* `bin`: This directory holds any binaries distributed with the package. |
| 84 | + |
| 85 | +There are also default file names you'll want to follow as well: |
| 86 | + |
| 87 | +* `main.rs`: A file that's going to become an executable. |
| 88 | +* `lib.rs`: A file that's going to become a library. |
| 89 | + |
| 90 | +# Building your own Package |
| 91 | + |
| 92 | +Now that you've got workspaces down, let's build your own copy of `hello`. Go |
| 93 | +to wherever you keep your personal projects, and let's make all of the |
| 94 | +directories we'll need. I'll refer to this personal project directory as |
| 95 | +`~/src` for the rest of this guide. |
| 96 | + |
| 97 | +## Creating our workspace |
| 98 | + |
| 99 | +~~~ {.notrust} |
| 100 | +$ cd ~/src |
| 101 | +$ mkdir -p hello/src/hello |
| 102 | +$ cd hello |
| 103 | +~~~ |
| 104 | + |
| 105 | +Easy enough! Let's do one or two more things that are nice to do: |
| 106 | + |
| 107 | +~~~ {.notrust} |
| 108 | +$ git init . |
| 109 | +$ cat > README.md |
| 110 | +# hello |
| 111 | +
|
| 112 | +A simple package for Rust. |
| 113 | +
|
| 114 | +## Installation |
| 115 | +
|
| 116 | +``` |
| 117 | +$ rustpkg install github.com/YOUR_USERNAME/hello |
| 118 | +``` |
| 119 | +^D |
| 120 | +$ cat > .gitignore |
| 121 | +.rust |
| 122 | +build |
| 123 | +^D |
| 124 | +$ git commit -am "Initial commit." |
| 125 | +~~~ |
| 126 | + |
| 127 | +If you're not familliar with the `cat >` idiom, it will make files with the |
| 128 | +text you type inside. Control-D (`^D`) ends the text for the file. |
| 129 | + |
| 130 | +Anyway, we've got a README and a `.gitignore`. Let's talk about that |
| 131 | +`.gitignore` for a minute: we are ignoring two directories, `build` and |
| 132 | +`.rust`. `build`, as we discussed earlier, is for build artifacts, and we don't |
| 133 | +want to check those into a repository. `.rust` is a directory that `rustpkg` |
| 134 | +uses to keep track of its own settings, as well as the source code of any other |
| 135 | +external packages that this workspace uses. This is where that `rustpkg |
| 136 | +install` puts all of its files. Those are also not to go into our repository, |
| 137 | +so we ignore it all as well. |
| 138 | + |
| 139 | +Next, let's add a source file: |
| 140 | + |
| 141 | +~~~ |
| 142 | +#[desc = "A hello world Rust package."]; |
| 143 | +#[license = "MIT"]; |
| 144 | +
|
| 145 | +pub fn world() { |
| 146 | + println!("Hello, world."); |
| 147 | +} |
| 148 | +~~~ |
| 149 | + |
| 150 | +Put this into `src/hello/lib.rs`. Let's talk about each of these attributes: |
| 151 | + |
| 152 | +## Crate attributes for packages |
| 153 | + |
| 154 | +`license` is equally simple: the license we want this code to have. I chose MIT |
| 155 | +here, but you should pick whatever license makes the most sense for you. |
| 156 | + |
| 157 | +`desc` is a description of the package and what it does. This should just be a |
| 158 | +sentence or two. |
| 159 | + |
| 160 | +## Building your package |
| 161 | + |
| 162 | +Building your package is simple: |
| 163 | + |
| 164 | +~~~ {.notrust} |
| 165 | +$ rustpkg build hello |
| 166 | +~~~ |
| 167 | + |
| 168 | +This will compile `src/hello/lib.rs` into a library. After this process |
| 169 | +completes, you'll want to check out `build`: |
| 170 | + |
| 171 | +~~~ {.notrust} |
| 172 | +$ ls build/x86_64-unknown-linux-gnu/hello/ |
| 173 | +libhello-ed8619dad9ce7d58-0.1.0.so |
| 174 | +~~~ |
| 175 | + |
| 176 | +This directory naming structure is called a 'build triple,' and is because I'm |
| 177 | +on 64 bit Linux. Yours may differ based on platform. |
| 178 | + |
| 179 | +You'll also notice that `src/hello/lib.rs` turned into |
| 180 | +`libhello-ed8619dad9ce7d58-0.1.0.so`. This is a simple combination of the |
| 181 | +library name, a hash of its content, and the version. |
| 182 | + |
| 183 | +Now that your library builds, you'll want to commit: |
| 184 | + |
| 185 | +~~~ {.notrust} |
| 186 | +$ git add src |
| 187 | +$ git commit -m "Adding source code." |
| 188 | +~~~ |
| 189 | + |
| 190 | +If you're using GitHub, after creating the project, do this: |
| 191 | + |
| 192 | +~~~ {.notrust} |
| 193 | +$ git remote add origin [email protected]:YOUR_USERNAME/hello.git |
| 194 | +$ git push origin -u master |
| 195 | +~~~ |
| 196 | + |
| 197 | +Now you can install and use it! Go anywhere else in your filesystem: |
| 198 | + |
| 199 | +~~~ {.notrust} |
| 200 | +$ cd ~/src/foo |
| 201 | +$ rustpkg install github.com/YOUR_USERNAME/hello |
| 202 | +WARNING: The Rust package manager is experimental and may be unstable |
| 203 | +note: Installed package github.com/YOUR_USERNAME/hello-0.1 to /home/yourusername/src/hello/.rust |
| 204 | +~~~ |
| 205 | + |
| 206 | +That's it! |
| 207 | + |
| 208 | +# Testing your Package |
| 209 | + |
| 210 | +Testing your package is simple as well. First, let's change `src/hello/lib.rs` to contain |
| 211 | +a function that can be sensibly tested: |
| 212 | + |
| 213 | +~~~ |
| 214 | +#[desc = "A Rust package for determining whether unsigned integers are even."]; |
| 215 | +#[license = "MIT"]; |
| 216 | +
|
| 217 | +pub fn is_even(i: uint) -> bool { |
| 218 | + i % 2 == 0 |
| 219 | +} |
| 220 | +~~~ |
| 221 | + |
| 222 | +Once you've edited `lib.rs`, you can create a second crate file, `src/hello/test.rs`, |
| 223 | +to put tests in: |
| 224 | + |
| 225 | +~~~ |
| 226 | +#[license = "MIT"]; |
| 227 | +extern mod hello; |
| 228 | +use hello::is_even; |
| 229 | +
|
| 230 | +#[test] |
| 231 | +fn test_is_even() { |
| 232 | + assert!(is_even(0)); |
| 233 | + assert!(!is_even(1)); |
| 234 | + assert!(is_even(2)); |
| 235 | +} |
| 236 | +~~~ |
| 237 | + |
| 238 | +Note that you have to import the crate you just created in `lib.rs` with the |
| 239 | +`extern mod hello` directive. That's because you're putting the tests in a different |
| 240 | +crate from the main library that you created. |
| 241 | + |
| 242 | +Now, you can use the `rustpkg test` command to build this test crate (and anything else |
| 243 | +it depends on) and run the tests, all in one step: |
| 244 | + |
| 245 | +~~~ {.notrust} |
| 246 | +$ rustpkg test hello |
| 247 | +WARNING: The Rust package manager is experimental and may be unstable |
| 248 | +note: Installed package hello-0.1 to /Users/tjc/.rust |
| 249 | +
|
| 250 | +running 1 test |
| 251 | +test test_is_even ... ok |
| 252 | +
|
| 253 | +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured |
| 254 | +~~~ |
| 255 | + |
| 256 | +# More resources |
| 257 | + |
| 258 | +There's a lot more going on with `rustpkg`, this is just to get you started. |
| 259 | +Check out [the rustpkg manual](rustpkg.html) for the full details on how to |
| 260 | +customize `rustpkg`. |
| 261 | + |
| 262 | +A tag was created on GitHub specifically for `rustpkg`-related issues. You can |
| 263 | +[see all the Issues for rustpkg |
| 264 | +here](https://github.com/mozilla/rust/issues?direction=desc&labels=A-pkg&sort=created&state=open), |
| 265 | +with bugs as well as new feature plans. `rustpkg` is still under development, |
| 266 | +and so may be a bit flaky at the moment. |
| 267 | + |
| 268 | +You may also want to check out [this blog |
| 269 | +post](http://tim.dreamwidth.org/1820526.html), which contains some of the early |
| 270 | +design decisions and justifications. |
0 commit comments