Skip to content

Commit

Permalink
Adds support for non pkg-config tpm2-tss installs.
Browse files Browse the repository at this point in the history
- Adds support for specifying path to the tpm2-tss libraries and
  header files using the environment variable ```TPM2_TSS_PATH```.
  The specified path is expected to have the following layout:
  | -> <Specified path>
  |    | -> include
  |       | -> tss2
  |           | -> tss2_esys.h
  |
  |    | -> lib
  |        | -> tss2_esys.lib (or .so)

Signed-off-by: Jesper Brynolf <[email protected]>
  • Loading branch information
Superhepper committed Dec 10, 2023
1 parent afaf9e7 commit 5c31929
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 39 deletions.
2 changes: 1 addition & 1 deletion tss-esapi-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ documentation = "https://docs.rs/crate/tss-esapi-sys"
links = "tss2-esys"

[build-dependencies]
bindgen = { version = "0.66.1", optional = true }
bindgen = { version = "0.69.1", optional = true }
pkg-config = "0.3.18"
target-lexicon = "0.12.0"
cfg-if = "1.0.0"
Expand Down
148 changes: 110 additions & 38 deletions tss-esapi-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ fn main() {
cfg_if::cfg_if! {
if #[cfg(feature = "generate-bindings")] {
let installation = tpm2_tss::Installation::probe(true);
let out_dir = std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap());
installation.generate_bindings(&out_dir.join("tss_esapi_bindings.rs"));
} else {
let installation = tpm2_tss::Installation::probe(false);
target::ensure_supported();
let _ = tpm2_tss::Installation::probe(false);
}
}
}
Expand Down Expand Up @@ -56,7 +59,7 @@ pub mod tpm2_tss {
/// The installed tpm2-tss libraries that are of
/// interest.
pub struct Installation {
tss2_sys: Library,
_tss2_sys: Library,
tss2_esys: Library,
tss2_tctildr: Library,
tss2_mu: Library,
Expand All @@ -65,17 +68,20 @@ pub mod tpm2_tss {

impl Installation {
/// Probes the system for an installation.
pub fn probe(with_headers: bool) -> Self {
pub fn probe(with_header_files: bool) -> Self {
let install_path = Installation::installation_path_from_env_var();
Installation {
tss2_sys: Library::probe_required("tss2-sys", install_path.as_ref()),
tss2_esys: Library::probe_required("tss2-esys", install_path.as_ref()),
tss2_tctildr: Library::probe_required("tss2-tctildr", install_path.as_ref()),
tss2_mu: Library::probe_required("tss2-mu", install_path.as_ref()),
tss2_tcti_tbs: Library::probe_optional("tss2-tcti-tbs", install_path.as_ref()),
_tss2_sys: Library::probe_required("tss2-sys", install_path.as_ref(), with_header_files, false),
tss2_esys: Library::probe_required("tss2-esys", install_path.as_ref(), with_header_files, true),
tss2_tctildr: Library::probe_required("tss2-tctildr", install_path.as_ref(), with_header_files, false),
tss2_mu: Library::probe_required("tss2-mu", install_path.as_ref(), with_header_files, false),
tss2_tcti_tbs: Library::probe_optional("tss2-tcti-tbs", install_path.as_ref(), with_header_files),
}
}

cfg_if::cfg_if! {
if #[cfg(feature = "generate-bindings")] {

/// Generates bindings for the Installation.
pub fn generate_bindings(&self, esapi_out: &Path) {
self.bindgen_builder()
Expand All @@ -92,13 +98,27 @@ pub mod tpm2_tss {
.clang_arg(self.tss2_esys.include_dir_arg())
.clang_arg(self.tss2_tctildr.include_dir_arg())
.clang_arg(self.tss2_mu.include_dir_arg())
.rustfmt_bindings(true)
.formatter(bindgen::Formatter::Rustfmt)
.header(self.tss2_esys.header_file_arg())
.header(self.tss2_tctildr.header_file_arg())
.header(self.tss2_mu.header_file_arg())
//See this issue: https://github.com/parallaxsecond/rust-cryptoki/issues/12
.blocklist_type("max_align_t")
.generate_comments(false)
.blocklist_type("max_align_t")
// Needed for windows
.blocklist_type("IMAGE_TLS_DIRECTORY")
.blocklist_type("PIMAGE_TLS_DIRECTORY")
.blocklist_type("IMAGE_TLS_DIRECTORY64")
.blocklist_type("PIMAGE_TLS_DIRECTORY64")
.blocklist_type("_IMAGE_TLS_DIRECTORY64")
.blocklist_type("MONITORINFOEX")
.blocklist_type("MONITORINFOEXA")
.blocklist_type("MONITORINFOEXW")
.blocklist_type("tagMONITORINFOEXA")
.blocklist_type("tagMONITORINFOEXW")
.blocklist_type("LPMONITORINFOEX")
.blocklist_type("LPMONITORINFOEXA")
.blocklist_type("LPMONITORINFOEXW")
.derive_default(true);
if let Some(tss2_tcti_tbs) = &self.tss2_tcti_tbs {
builder = builder
Expand All @@ -107,7 +127,8 @@ pub mod tpm2_tss {
}
builder
}

}
}
/// Retrieves the installation path from the environment variable and validates it.
fn installation_path_from_env_var() -> Option<(PathBuf, String)> {
std::env::var(PATH_ENV_VAR_NAME).map_or_else(|e| {
Expand Down Expand Up @@ -165,7 +186,7 @@ pub mod tpm2_tss {

/// Struct holding the information for a library.
struct Library {
header_file: PathBuf,
header_file: Option<PathBuf>,
version: String,
name: String,
}
Expand All @@ -174,41 +195,53 @@ pub mod tpm2_tss {
/// Probes the different options for a required library.
///
/// # Arguments
/// lib_name - The name of the library.
/// install_path - Optional path and version of installation.
/// `lib_name` - The name of the library.
/// `install_path` - Optional path and version of installation.
/// `with_header_files` - Flag indicating if header files are required.
///
/// # Returns
/// The detected installed library.
/// # Panics
/// - If the library is not found.
pub fn probe_required(lib_name: &str, install_path: Option<&(PathBuf, String)>) -> Self {
Self::probe_optional(lib_name, install_path)
.unwrap_or_else(|| panic!("Failed to find {} library.", lib_name))
pub fn probe_required(lib_name: &str, install_path: Option<&(PathBuf, String)>, with_header_files: bool, report_version: bool) -> Self {
Self::probe_optional(lib_name, install_path, with_header_files)
.map_or_else(
|| panic!("Failed to find {} library.", lib_name),
|lib| {
if report_version {
println!("cargo:version={}", lib.version);
}
lib
})
}

/// Probes the different options for an optional library.
///
/// # Arguments
/// lib_name - The name of the library.
/// install_path - Optional path and version of installation.
/// `lib_name` - The name of the library.
/// `install_path` - Optional path and version of installation.
/// `with_header_files` - Flag indicating if header files are required.
///
/// # Returns
/// The detected installed library or None if no library was found.
pub fn probe_optional(lib_name: &str, install_path: Option<&(PathBuf, String)>) -> Option<Self> {
pub fn probe_optional(lib_name: &str, install_path: Option<&(PathBuf, String)>, with_header_files: bool) -> Option<Self> {
install_path
.map(|(path, version)| {
Self::probe_install_path(lib_name, &path, &version)
Self::probe_install_path(lib_name, path, version, with_header_files)
})
.or_else(|| Self::probe_pkg_config_optional(lib_name))
.or_else(|| Self::probe_pkg_config_optional(lib_name, with_header_files))
}

/// The include dir `clang_arg` bindgen builder argument.
///
/// # Panics
/// - If the library was probe without requiring header files.
/// - If the library specifies a header file does not have a parent directory.
/// - If the library specifies a header file path that contain invalid utf-8 characters.
pub fn include_dir_arg(&self) -> String {
self.header_file
.as_ref()
.unwrap_or_else(|| panic!("No header file present for `{}`.", self.name))
.parent()
.unwrap_or_else(|| panic!("Inconsistent `{}` header file path.", self.name))
.as_os_str()
Expand All @@ -224,24 +257,34 @@ pub mod tpm2_tss {
/// - If the library specifies a header file path that contain invalid utf-8 characters.
pub fn header_file_arg(&self) -> &str {
self.header_file
.as_os_str()
.to_str()
.unwrap_or_else(|| panic!("Error converting OsString to &str when processing `{}` include dir.", self.name))
.as_ref()
.map_or_else(
|| {
panic!("No header file present for `{}`.", self.name);
},
|v| {
v.as_os_str()
.to_str()
.unwrap_or_else(|| panic!("Error converting OsString to &str when processing `{}` include dir.", self.name))
})
}

/// Probe the system for an optional library using pkg-config.
fn probe_pkg_config_optional(lib_name: &str) -> Option<Self> {
///
/// # Args
/// `lib_name` - The name of the library.
/// `with_header_files` - Flag indicating if header files are required.
fn probe_pkg_config_optional(lib_name: &str, with_header_files: bool) -> Option<Self> {
pkg_config::Config::new()
.atleast_version(MINIMUM_VERSION)
.probe(lib_name)
.ok()
.map(|pkg_config| {
let header_file = pkg_config.include_paths[0]
.join("tss2")
.join(lib_name.replace("-", "_") + ".h");
if !header_file.is_file() {
panic!("Header file `{}` does not exist.", header_file.to_string_lossy());
if !with_header_files {
return Self {header_file: None, version: pkg_config.version, name: lib_name.to_string()}
}
//let file_name = PathBuf::from(lib_name.replace("-", "_"));
let header_file = Self::header_file(lib_name, &pkg_config.include_paths[0], with_header_files);
Self {header_file, version: pkg_config.version, name: lib_name.to_string()}
})
}
Expand All @@ -259,17 +302,46 @@ pub mod tpm2_tss {
/// # Panics
/// - If no `.lib` file for the library was found.
/// - If no `.h` file for the library was found.
fn probe_install_path(lib_name: &str, path: &Path, version: &str) -> Self {
let file_name = PathBuf::from(lib_name.replace("-", "_"));
let lib_file = path.join("lib").join(file_name.with_extension("lib"));
fn probe_install_path(lib_name: &str, path: &Path, version: &str, with_header_files: bool) -> Self {
let lib_path = path.join("lib");
Self::ensure_lib_file_exist(lib_name, &lib_path);

let include_path = path.join("include/tss2");
let header_file = Self::header_file(lib_name, &include_path, with_header_files);

Self {header_file, version: version.to_string(), name: lib_name.to_string()}
}

fn ensure_lib_file_exist(lib_name: &str, lib_path: &Path) {
let lib_file = lib_path.join(PathBuf::from(lib_name).with_extension("lib"));
if !lib_file.is_file() {
panic!("Lib file `{}`, does not exist.", lib_file.to_string_lossy());
panic!("Lib name: {}\n Lib file `{}`, does not exist.", lib_name, lib_file.to_string_lossy());
}
}

/// Creates a PathBuf object for the header file.
///
/// # Args
/// `lib_name` - Name of the library.
/// `include_path` - The include path to the header file.
/// `with_header_files` - Flag indicating if header files are required.
///
/// # Returns
/// An optional PathBuf object.
///
/// # Panics
/// - If `with_header_files` but the combination of `file_name` and `include_path`
/// does not point to an existing file.
fn header_file(lib_name: &str, include_path: &Path, with_header_files: bool) -> Option<PathBuf> {
if !with_header_files {
return None;
}
let header_file = path.join("include").join(file_name.with_extension("h"));
if !header_file.is_file() {
let file_name = PathBuf::from(lib_name.replace('-', "_"));
let header_file = include_path.join(file_name.with_extension("h"));
if with_header_files && !header_file.is_file() {
panic!("Header file `{}`, does not exist.", header_file.to_string_lossy());
}
Self {header_file, version: version.to_string(), name: lib_name.to_string()}
Some(header_file)
}
}
}

0 comments on commit 5c31929

Please sign in to comment.