Skip to content

Commit

Permalink
Try standard system path when pkg-config fails (#444)
Browse files Browse the repository at this point in the history
Currently Rust-Themis requires pkg-config to successfully find Themis.
If it doesn't (for whatever reason) then the crate won't compile.
However, the library might be correctly installed in the system under
standard paths. This allows us to easily link against it dynamically.
Let's support this use case to allow non-packaged installations.

If pkg-config successfully locates core Themis library then we just go
with it. Otherwise we effectively try to run

    cc -shared src/dummy.c -lthemis

and see if that compiles. If it does then apparently Themis is installed
and we can use it by emitting appropriate instructions to Cargo.

Note that we support only dynamic linkage in this case. Static linkage
will not work because we will have to figure out transitive dependencies
like Soter and OpenSSL, which is the reason for preferring pkg-config.

* Wrap pkg_config::Library type

We're going to rely not only on pkg-config for locating Themis, but we
cannot construct pkg_config::Library instances (it has private fields).
Use a custom type with the same API instead.

* Don't panic immediately on pkg-config failure

We're going to provide an alternative code path for when pkg-config
fails, so instead of panicking with an error message just output it
to stderr and panic later. This enables us to insert some actions in
between and prevent the panic.

* Add changelog entry
  • Loading branch information
ilammy authored Apr 1, 2019
1 parent 5f5c7e9 commit 55c9ec0
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 12 deletions.
7 changes: 7 additions & 0 deletions src/wrappers/themis/rust/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@

The version currently in development.

## Internal improvements

- `libthemis-sys` is now able to use core Themis library installed in
standard system paths, without _pkg-config_ assistance. ([#444])

[#444]: https://github.com/cossacklabs/themis/pull/444

Version 0.11.0 — 2019-03-28
===========================

Expand Down
70 changes: 58 additions & 12 deletions src/wrappers/themis/rust/libthemis-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
use std::env;
use std::path::{Path, PathBuf};

use pkg_config::Library;

fn main() {
let themis = get_themis();

Expand All @@ -38,6 +36,11 @@ fn main() {
.expect("writing bindings!");
}

struct Library {
include_paths: Vec<PathBuf>,
link_paths: Vec<PathBuf>,
}

/// Embarks on an incredible adventure and returns with a suitable Themis (or dies trying).
fn get_themis() -> Library {
#[cfg(feature = "vendored")]
Expand All @@ -50,15 +53,20 @@ fn get_themis() -> Library {
pkg_config.statik(true);

match pkg_config.probe("libthemis") {
Ok(library) => return library,
Err(error) => panic!(format!(
"
Ok(library) => {
return Library {
include_paths: library.include_paths,
link_paths: library.link_paths,
};
}
Err(error) => {
eprintln!(
"
`libthemis-sys` could not find Themis installation in your system.
Please make sure you have appropriate development package installed.
On Linux it's called `libthemis-dev`, not just `libthemis`.
On macOS Homebrew formula is called `themis` or `themis-openssl`.
On macOS Homebrew formula is called `libthemis`.
Please refer to the documentation for installation instructions:
Expand All @@ -68,11 +76,30 @@ This crate uses `pkg-config` to locate the library. If you use
non-standard installation of Themis then you can help pkg-config
to locate your library by setting the PKG_CONFIG_PATH environment
variable to the path where `libthemis.pc` file is located.
{}
",
error
)),
"
);
eprintln!("{}", error);

if let Some(library) = try_system_themis() {
eprintln!(
"\
`libthemis-sys` tried using standard system paths and it seems that Themis
is available on your system. (However, pkg-config failed to find it.)
We will link against the system library.
"
);
return library;
} else {
eprintln!(
"\
`libthemis-sys` also tried to use standard system paths, but without success.
It seems that Themis is really not installed in your system.
"
);
}

panic!("Themis Core not installed");
}
}
}

Expand Down Expand Up @@ -111,3 +138,22 @@ impl CCBuildEx for cc::Build {
self
}
}

fn try_system_themis() -> Option<Library> {
let mut build = cc::Build::new();
build.file("src/dummy.c");
build.flag("-lthemis");

match build.try_compile("dummy") {
Ok(_) => {
println!("cargo:rustc-link-lib=dylib=themis");

// Use only system paths for header and library lookup.
Some(Library {
include_paths: vec![],
link_paths: vec![],
})
}
Err(_) => None,
}
}
22 changes: 22 additions & 0 deletions src/wrappers/themis/rust/libthemis-sys/src/dummy.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2019 (c) rust-themis developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Dummy file used to verify that the compiler sees native Themis library.

#include <themis/themis.h>

void libthemis_sys_unused(void)
{
themis_gen_ec_key_pair(NULL, NULL, NULL, NULL);
}

0 comments on commit 55c9ec0

Please sign in to comment.