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 = "7.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.libfoo_1_0]
name = "libfoo-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.libfoo_gl]
name = "libfoo-gl-1.0"
version = "1.14"
v1_18 = { version = "1.18", name = "libfoo-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_archtarget_endiantarget_envtarget_familytarget_ostarget_pointer_widthtarget_vendorunixandwindows
§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:
SYSTEM_DEPS_$NAME_SEARCH_NATIVEto override thecargo:rustc-link-search=nativeflag;SYSTEM_DEPS_$NAME_SEARCH_FRAMEWORKto override thecargo:rustc-link-search=frameworkflag;SYSTEM_DEPS_$NAME_LIBto override thecargo:rustc-link-libflag;SYSTEM_DEPS_$NAME_LIB_FRAMEWORKto override thecargo:rustc-link-lib=frameworkflag;SYSTEM_DEPS_$NAME_INCLUDEto override thecargo:includeflag.
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 bypkg-config;always: always build the dependency, ignoring any version which may be installed on the system;never: (default) never build the dependency,system-depswill 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.
The libraries specified with this option can have any form readable by pkg-config, and they will inherit the main libraries’
binary paths if you are using them. If pkg-config can’t find some entry, it will print a warning but the compilation won’t fail.
§Using prebuilt binaries
Some system libraries may take too long to build or require a specific environment. system-deps allows to download and link against
prebuilt library binaries specified in the crate metadata. To do so, you need to enable the binary feature and configure the library metadata.
[package.metadata.system-deps.liba]
name = "liba"
version = "1.0"
url = "https://download/liba-1.0.tar.gz"
checksum = "..."
pkg_paths = [ "lib/pkgconfig" ]The snippet above will attempt to download the archive specified in the url field, extract it and add the relative paths from pkg_paths to the
PKG_CONFIG_PATH when looking for liba. This is done automatically and dependents of the library don’t need to make any changes.
It is recommended to have a feature in the crate’s Cargo.toml that enables the binary feature in system-deps, instead of hard-coding it.
[features]
binary = [ "system-deps/binary", "system-deps/gz" ]As oppossed to the other metadata in system-deps, the metadata section can be specified anywhere in the crate tree, with entries from top level crates having priority.
This allows for a crate to provide a default value for its binaries, and a dependent crate to add extra configuration.
# Crate graph: user_project -> libb -> liba
# libb/Cargo.toml
[package.metadata.system-deps.liba]
url = "https://download/custom-liba-1.0.tar.gz"
# user_project/Cargo.toml
[package.metadata.system-deps.liba]
url = "file:///tmp/liba"In this example, libb overwrites the binaries provided by liba (for compatibility reasons, to add flags needed by libb, to use a single package for both…).
However, the user project overwrites them again to point at a local file for development.
The binaries can be configured per target like other system-deps options:
[package.metadata.system-deps.liba.'cfg(target = "unix")']
url = "https://download/liba-unix-1.0.tar.gz"
[package.metadata.system-deps.liba.'cfg(target = "windows")']
url = "https://download/liba-windows-1.0.zip"By default, a binary archive adds its paths to PKG_CONFIG_PATH only for the library it is defined for. However, sometimes you may want to share a single url
for multiple libraries. While it is possible to repeat the url for every entry, a more concise approach is to use follows to copy the configuration from another library.
[package.metadata.system-deps.libb]
follows = "liba" # This name corresponds to the key of the metadata tableStructs§
- Config
- Structure used to configure
metadatabefore starting to probe for dependencies - Dependencies
- All the system dependencies retrieved by
Config::probe. - Internal
Lib - Internal library name and if a static library is available on the system
- Library
- A system dependency
Enums§
- Build
Internal Closure Error - Error used in return value of
Config::add_build_internalclosures - Error
- system-deps errors
- Source
- From where the library settings have been retrieved
Traits§
- Path
OrList - A trait that can represent both a reference to a Path like object or a list of paths.
Used in
Library::wrap_pkg_configandLibrary::from_internal_pkg_configto specify the list ofpkg-configpaths that should take priority.