Skip to content

Commit

Permalink
Expand the "link to system libraries" section
Browse files Browse the repository at this point in the history
  • Loading branch information
alexcrichton committed Nov 5, 2014
1 parent 85a96e4 commit c05442a
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/cargo/ops/cargo_rustc/links.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use std::collections::HashMap;
use core::PackageSet;
use util::{CargoResult, human};

// Returns a mapping of the root package plus its immediate dependencies to
// where the compiled libraries are all located.
// Validate that there are no duplicated native libraries among packages and
// that all packages with `links` also have a build script.
pub fn validate(deps: &PackageSet) -> CargoResult<()> {
let mut map = HashMap::new();

Expand Down
84 changes: 84 additions & 0 deletions src/doc/build-script.md
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,50 @@ performing this in a platform-agnostic fashion, and the purpose of a build
script is again to farm out as much of this as possible to make this as easy as
possible for consumers.

As an example to follow, let's take a look at one of [Cargo's own
dependencies][git2-rs], [libgit2][libgit2]. This library has a number of
constraints:

[git2-rs]: https://github.com/alexcrichton/git2-rs/tree/master/libgit2-sys
[libgit2]: https://github.com/libgit2/libgit2

* It has an optional dependency on OpenSSL on Unix to implement the https
transport.
* It has an optional dependency on libssh2 on all platforms to implement the ssh
transport.
* It is often not installed on all systems by default.
* It can be built from source using `cmake`.

To visualize what's going on here, let's take a look at the manifest for the
relevant Cargo package.

```toml
[package]
name = "libgit2-sys"
version = "0.0.1"
authors = ["..."]
links = "git2"
build = "build.rs"

[dependencies.libssh2-sys]
git = "https://github.com/alexcrichton/ssh2-rs"

[target.x86_64-unknown-linux-gnu.dependencies.openssl-sys]
git = "https://github.com/alexcrichton/openssl-sys"

# ...
```

As the above manifests show, we've got a `build` script specified, but it's
worth noting that this example has a `links` entry which indicates that the
crate (`libgit2-sys`) links to the `git2` native library.

Here we also see the unconditional dependency on `libssh2` via the
`libssh2-sys` crate, as well as a platform-specific dependency on `openssl-sys`
for unix (other variants elided for now). It may seem a little counterintuitive
to express *C dependencies* in the *Cargo manifest*, but this is actually using
one of Cargo's conventions in this space.

## `*-sys` Packages

To alleviate linking to system libraries, Cargo has a *convention* of package
Expand All @@ -428,3 +472,43 @@ convention of native-library-related packages:
* A common dependency allows centralizing logic on discovering `libfoo` itself
(or building it from source).
* These dependencies are easily overridable.

## Building libgit2

Now that we've got libgit2's dependencies sorted out, we need to actually write
the build script. We're not going to look at specific snippets of code here and
instead only take a look at the high-level details of the build script of
`libgit2-sys`. This is not recommending all packages follow this strategy, but
rather just outlining one specific strategy.

The first step of the build script should do is to query whether libgit2 is
already installed on the host system. To do this we'll leverage the preexisting
tool `pkg-config` (when its available). We'll also use a `build-dependencies`
section to refactor out all the `pkg-config` related code (or someone's already
done that!).

If `pkg-config` failed to find libgit2, or if `pkg-config` just wasn't
installed, the next step is to build libgit2 from bundled source code
(distributed as part of `libgit2-sys` itself). There are a few nuances when
doing so that we need to take into account, however:

* The build system of libgit2, `cmake`, needs to be able to find libgit2's
optional dependency of libssh2. We're sure we've already built it (it's a
Cargo dependency), we just need to communicate this information. To do this
we leverage the metadata format to communicate information between build
scripts. In this example the libssh2 package printed out `cargo:root=...` to
tell us where libssh2 is installed at, and we can then pass this along to
cmake with the `CMAKE_PREFIX_PATH` environment variable.

* We'll need to handle some `CFLAGS` values when compiling C code (and tell
`cmake` about this). Some flags we may want to pass are `-m64` for 64-bit
code, `-m32` for 32-bit code, or `-fPIC` for 64-bit code as well.

* Finally, we'll invoke `cmake` to place all output into the `OUT_DIR`
environment variable, and then we'll print the necessary metadata to instruct
rustc how to link to libgit2.

Most of the functionality of this build script is easily refactorable into
common dependencies, so our build script isn't quite as intimidating as this
descriptions! In reality it's expected that build scripts are quite succinct by
farming logic such as above to build dependencies.

5 comments on commit c05442a

@alexcrichton
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r=brson

@bors
Copy link
Contributor

@bors bors commented on c05442a Nov 5, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from brson
at alexcrichton@c05442a

@bors
Copy link
Contributor

@bors bors commented on c05442a Nov 5, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging alexcrichton/cargo/build-cmd = c05442a into auto-cargo

@bors
Copy link
Contributor

@bors bors commented on c05442a Nov 5, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alexcrichton/cargo/build-cmd = c05442a merged ok, testing candidate = 78c9d3fc

@bors
Copy link
Contributor

@bors bors commented on c05442a Nov 5, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.