|
| 1 | +% Rust Packaging Tutorial |
| 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 tutorial 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 | + |
| 33 | +This makes sense, as we haven't gotten it from anywhere yet! Luckily for us, |
| 34 | +`rustpkg` has an easy way to fetch others' code: the `install` command. It's |
| 35 | +used like this: |
| 36 | + |
| 37 | +~~~ {.notrust} |
| 38 | +$ rustpkg install fragment |
| 39 | +~~~ |
| 40 | + |
| 41 | +This will install a package named 'fragment' into your current Rust |
| 42 | +environment. I called it 'fragment' in this example because when using it with |
| 43 | +an external package like this, it's often a URI fragment. You see, Rust has no |
| 44 | +central authority for packages. You can build your own `hello` library if you |
| 45 | +want, and that's fine. We'd both host them in different places and different |
| 46 | +projects would rely on whichever version 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 folders that `rustpkg` expects. Different Rust |
| 75 | +projects will go into different workspaces. |
| 76 | + |
| 77 | +A workspace consists of any folder 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 tutorial. |
| 96 | + |
| 97 | +### Creating neccesary files |
| 98 | + |
| 99 | +~~~ {.notrust} |
| 100 | +$ cd ~/src |
| 101 | +$ mkdir -p hello/{src/hello,build,lib,bin} |
| 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 insie. 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 folder that `rustpkg` uses |
| 134 | +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 | +#[link(name = "hello", |
| 143 | + vers = "0.1.0", |
| 144 | + uuid = "0028fbe0-1f1f-11e3-8224-0800200c9a66", |
| 145 | + url = "https://github.com/YOUR_USERNAME/hello")]; |
| 146 | +
|
| 147 | +#[desc = "A hello world Rust package."]; |
| 148 | +#[license = "MIT"]; |
| 149 | +#[crate_type = "lib"]; |
| 150 | +
|
| 151 | +pub fn world() { |
| 152 | + println("Hello, world."); |
| 153 | +} |
| 154 | +~~~ |
| 155 | + |
| 156 | +Put this into `src/hello/lib.rs`. Let's talk about each of these attributes: |
| 157 | + |
| 158 | +### Crate attributes for packages |
| 159 | + |
| 160 | +`crate_type` is the simplest: we're building a library here, so we set it to |
| 161 | +`"lib"`. If we were making an executable of some kind, we'd set this to `"bin"` |
| 162 | +instead. |
| 163 | + |
| 164 | +`license` is equally simple: the license we want this code to have. I chose MIT |
| 165 | +here, but you should pick whatever license makes the most sense for you. |
| 166 | + |
| 167 | +`desc` is a description of the package and what it does. This should just be a |
| 168 | +sentence or two. |
| 169 | + |
| 170 | +`link` is the big complex attribute here. It's still not too complex: `name` is |
| 171 | +the name of the package, and `vers` is the version. If you're building a |
| 172 | +library, consider using [Semantic Versioning](http://semver.org/) as your |
| 173 | +versioning scheme. Future versions of `rustpkg` will assume SemVer. |
| 174 | + |
| 175 | +`uuid` is simply a unique identifier. You can generate a UUID by visiting [this |
| 176 | +page](http://www.famkruithof.net/uuid/uuidgen). Just copy whatever it puts out |
| 177 | +into the value for `uuid`. For more on UUIDs, see |
| 178 | +[RFC4122](http://www.ietf.org/rfc/rfc4122.txt). |
| 179 | + |
| 180 | +Finally, `url` is a URL where this package is located. Easy. |
| 181 | + |
| 182 | +### Building your package |
| 183 | + |
| 184 | +Building your package is simple: |
| 185 | + |
| 186 | +~~~ {.notrust} |
| 187 | +$ rustpkg build hello |
| 188 | +~~~ |
| 189 | + |
| 190 | +This will compile `src/hello/lib.rs` into a library. After this process |
| 191 | +completes, you'll want to check out `build`: |
| 192 | + |
| 193 | +~~~ {.notrust} |
| 194 | +$ ls build/x86_64-unknown-linux-gnu/hello/ |
| 195 | +libhello-ed8619dad9ce7d58-0.1.0.so |
| 196 | +~~~ |
| 197 | + |
| 198 | +This directory naming structure is called a 'build triple,' and is because I'm |
| 199 | +on 64 bit Linux. Yours may differ based on platform. |
| 200 | + |
| 201 | +You'll also notice that `src/hello/lib.rs` turned into |
| 202 | +`libhello-ed8619dad9ce7d58-0.1.0.so`. This is a simple combination of the |
| 203 | +library name, a hash of its content, and the version. |
| 204 | + |
| 205 | +Now that your library builds, you'll want to commit: |
| 206 | + |
| 207 | +~~~ {.notrust} |
| 208 | +$ git add src |
| 209 | +$ git commit -m "Adding source code." |
| 210 | +~~~ |
| 211 | + |
| 212 | +If you're using GitHub, after creating the project, do this: |
| 213 | + |
| 214 | +~~~ {.notrust} |
| 215 | +$ git remote add origin [email protected]:YOUR_USERNAME/hello.git |
| 216 | +$ git push origin -u master |
| 217 | +~~~ |
| 218 | + |
| 219 | +Now you can install and use it! Go anywhere else in your filesystem: |
| 220 | + |
| 221 | +~~~ {.notrust} |
| 222 | +$ cd ~/src/foo |
| 223 | +$ rustpkg install github/YOUR_USERNAME/hello |
| 224 | +WARNING: The Rust package manager is experimental and may be unstable |
| 225 | +note: Installed package github.com/YOUR_USERNAME/hello-0.1 to /home/yourusername/src/hello/.rust |
| 226 | +~~~ |
| 227 | + |
| 228 | +That's it! |
| 229 | + |
| 230 | +## More resources |
| 231 | + |
| 232 | +There's a lot more going on with `rustpkg`, this is just to get you started. |
| 233 | +Check out [the rustpkg manual](rustpkg.html) for the full details on how to |
| 234 | +customize `rustpkg`. |
| 235 | + |
| 236 | +A tag was created on GitHub specifically for `rustpkg`-related issues. You can |
| 237 | +[see all the Issues for rustpkg |
| 238 | +here](https://github.com/mozilla/rust/issues?direction=desc&labels=A-pkg&sort=created&state=open), |
| 239 | +with bugs as well as new feature plans. `rustpkg` is still under development, |
| 240 | +and so may be a bit flaky at the moment. |
| 241 | + |
| 242 | +You may also want to check out [this blog |
| 243 | +post](http://tim.dreamwidth.org/1820526.html), which contains some of the early |
| 244 | +design decisions and justifications. |
0 commit comments