Crate system_deps

source ·
Expand description

system-deps lets you write system dependencies in Cargo.toml metadata, rather than programmatically in build.rs. This makes those dependencies declarative, so other tools can read them as well.

§Usage

In your Cargo.toml:

[build-dependencies]
system-deps = "2.0"

Then, to declare a dependency on testlib >= 1.2 add the following section:

[package.metadata.system-deps]
testlib = "1.2"

Finally, in your build.rs, add:

fn main() {
    system_deps::Config::new().probe().unwrap();
}

§Version format

Versions can be expressed in the following formats

  • “1.2” or “>= 1.2”: At least version 1.2
  • “>= 1.2, < 2.0”: At least version 1.2 but less than version 2.0

In the future more complicated version expressions might be supported.

Note that these versions are not interpreted according to the semver rules, but based on the rules defined by pkg-config.

§Feature-specific dependency

You can easily declare an optional system dependency by associating it with a feature:

[package.metadata.system-deps]
testdata = { version = "4.5", feature = "use-testdata" }

system-deps will check for testdata only if the use-testdata feature has been enabled.

§Optional dependency

Another option is to use the optional setting, which can also be used using features versions:

[package.metadata.system-deps]
test-data = { version = "4.5", optional = true }
testmore = { version = "2", v3 = { version = "3.0", optional = true }}

system-deps will automatically export for each dependency a feature system_deps_have_$DEP where $DEP is the toml key defining the dependency in snake_case. This can be used to check if an optional dependency has been found or not:

#[cfg(system_deps_have_testdata)]
println!("found test-data");

§Overriding library name

toml keys cannot contain dot characters so if your library name does, you can define it using the name field:

[package.metadata.system-deps]
glib = { name = "glib-2.0", version = "2.64" }

§Fallback library names

Some libraries may be available under different names on different platforms or distributions. To allow for this, you can define fallback names to search for if the main library name does not work.

[package.metadata.system-deps]
aravis = { fallback-names = ["aravis-0.8"] }

You may also specify different fallback names for different versions:

[package.metadata.system-deps.libfoo]
version = "0.1"
fallback-names = ["libfoo-0.1"]
v1 = { version = "1.0", fallback-names = ["libfoo1"] }
v2 = { version = "2.0", fallback-names = ["libfoo2"] }

§Feature versions

-sys crates willing to support various versions of their underlying system libraries can use features to control the version of the dependency required. system-deps will pick the highest version among enabled features. Such version features must use the pattern v1_0, v1_2, etc.

[features]
v1_2 = []
v1_4 = ["v1_2"]
v1_6 = ["v1_4"]

[package.metadata.system-deps.gstreamer_1_0]
name = "gstreamer-1.0"
version = "1.0"
v1_2 = { version = "1.2" }
v1_4 = { version = "1.4" }
v1_6 = { version = "1.6" }

The same mechanism can be used to require a different library name depending on the version:

[package.metadata.system-deps.gst_gl]
name = "gstreamer-gl-1.0"
version = "1.14"
v1_18 = { version = "1.18", name = "gstreamer-gl-egl-1.0" }

§Target specific dependencies

You can define target specific dependencies:

[package.metadata.system-deps.'cfg(target_os = "linux")']
testdata = "1"
[package.metadata.system-deps.'cfg(not(target_os = "macos"))']
testlib = "1"
[package.metadata.system-deps.'cfg(unix)']
testanotherlib = { version = "1", optional = true }

See the Rust documentation for the exact syntax. Currently, those keys are supported:

  • target_arch
  • target_endian
  • target_env
  • target_family
  • target_os
  • target_pointer_width
  • target_vendor
  • unix and windows

§Overriding build flags

By default system-deps automatically defines the required build flags for each dependency using the information fetched from pkg-config. These flags can be overridden using environment variables if needed:

With $NAME being the upper case name of the key defining the dependency in Cargo.toml. For example SYSTEM_DEPS_TESTLIB_SEARCH_NATIVE=/opt/lib could be used to override a dependency named testlib.

One can also define the environment variable SYSTEM_DEPS_$NAME_NO_PKG_CONFIG to fully disable pkg-config lookup for the given dependency. In this case at least SYSTEM_DEPS_$NAME_LIB or SYSTEM_DEPS_$NAME_LIB_FRAMEWORK should be defined as well.

§Internally build system libraries

-sys crates can provide support for building and statically link their underlying system library as part of their build process. Here is how to do this in your build.rs:

fn main() {
    system_deps::Config::new()
        .add_build_internal("testlib", |lib, version| {
            // Actually build the library here that fulfills the passed in version requirements
            system_deps::Library::from_internal_pkg_config("build/path-to-pc-file", lib, "1.2.4")
         })
        .probe()
        .unwrap();
}

This feature can be controlled using the SYSTEM_DEPS_$NAME_BUILD_INTERNAL environment variable which can have the following values:

  • auto: build the dependency only if the required version has not been found by pkg-config;
  • always: always build the dependency, ignoring any version which may be installed on the system;
  • never: (default) never build the dependency, system-deps will fail if the required version is not found on the system.

You can also use the SYSTEM_DEPS_BUILD_INTERNAL environment variable with the same values defining the behavior for all the dependencies which don’t have SYSTEM_DEPS_$NAME_BUILD_INTERNAL defined.

§Static linking

By default all libraries are dynamically linked, except when build internally as described above. Libraries can be statically linked by defining the environment variable SYSTEM_DEPS_$NAME_LINK=static. You can also use SYSTEM_DEPS_LINK=static to statically link all the libraries.

Structs§

  • Structure used to configure metadata before starting to probe for dependencies
  • All the system dependencies retrieved by Config::probe.
  • Internal library name and if a static library is available on the system
  • A system dependency

Enums§