diff --git a/tss-esapi-sys/Cargo.toml b/tss-esapi-sys/Cargo.toml index bc4b263a..d0281817 100644 --- a/tss-esapi-sys/Cargo.toml +++ b/tss-esapi-sys/Cargo.toml @@ -15,7 +15,7 @@ rust-version = "1.85.0" [build-dependencies] bindgen = { version = "0.72.1", optional = true } -pkg-config = "0.3.32" +pkg-config = "0.3.33" target-lexicon = "0.13.5" cfg-if = "1.0.4" semver = "1.0.27" diff --git a/tss-esapi-sys/README.md b/tss-esapi-sys/README.md index 8bdda2d1..35847f22 100644 --- a/tss-esapi-sys/README.md +++ b/tss-esapi-sys/README.md @@ -21,6 +21,7 @@ are discoverable in this way on your system. Our build script looks for `tss2-sys`, `tss2-esys`, `tss2-tctildr` and `tss2-mu`. A minimum version of `4.1.3` is required for all of them. On windows `tss2-tcti-tbs` is also required. + Having installed the open-source implementation libraries at `/usr/local/lib` (by default), it might happen that `pkg-config` can not find them. Run the following command if that is the case: @@ -39,7 +40,7 @@ NOTE: Only a limited set of bindings are committed and their target triplet is included in the name of the file - if the triplet you require is not available, feel free to raise a Pull Request to add it or to use build-time generation of bindings. All the committed bindings **MUST** be generated from -the library version found under the `vendor` submodule. +the previously mentioned minimum version. ## Bundling TPM-TSS @@ -55,6 +56,9 @@ the `TPM2_TSS_SOURCE_VERSION` environment variable. having to worry about the `tpm2-tss` library dependencies. But it is still necessary to make the shared libraries available to the executable that uses the library. +* The dependencies of `tpm2-tss` need to be installed and discoverable via + `pkg-config` on all platforms except Windows, on Windows this is handled + differently. See the [Windows section](#windows). * On Windows it might be necessary to manually create the `VERSION` file when a local source is being used. @@ -87,6 +91,10 @@ Compiling for windows requires a bit of setup to work with the bundled feature. and windows sdk 10.0 (Other versions of Visual Studio may work but are untested at this point). +NOTE: On Windows it is also necessary to ensure the runtime dependencies of `tpm2-tss` +(e.g. the OpenSSL DLLs) are discoverable. See the Windows DLL +[search order](https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order). + ### MacOS Compiling on MacOS requires the bundling feature. This requires dependencies @@ -105,7 +113,19 @@ brew install libftdi ### OpenSUSE / SUSE ``` -sudo zypper in autoconf autoconf-archive automake libjson-c-devel libtool libtpms-devel gawk make +sudo zypper in \ + autoconf \ + autoconf-archive \ + automake \ + gcc-c++ \ + libusb-devel \ + libjson-c-devel \ + libuuid-devel \ + libopenssl-3-devel \ + libtool \ + libtpms-devel \ + gawk \ + make ``` ## Cross compiling diff --git a/tss-esapi-sys/build.rs b/tss-esapi-sys/build.rs index 63125854..7673deb3 100644 --- a/tss-esapi-sys/build.rs +++ b/tss-esapi-sys/build.rs @@ -84,6 +84,60 @@ pub mod tpm2_tss { const MINIMUM_VERSION: &str = "4.1.3"; const INSTALLATION_PATH_ENV_VAR_NAME: &str = "TPM2_TSS_PATH"; + /// A tpm2-tss dependency + pub struct Dependency<'a> { + #[allow(unused)] + lib_name: &'a str, + #[allow(unused)] + lib_version: &'a str, + #[allow(unused)] + win_path_str: &'a str, + } + + impl<'a> Dependency<'a> { + pub const fn new(lib_name: &'a str, lib_version: &'a str, win_path_str: &'a str) -> Self { + Self { + lib_name, + lib_version, + win_path_str, + } + } + + pub fn probe(&self) { + cfg_if::cfg_if! { + if #[cfg(windows)] { + // TODO: Find some better way to check dependency. + let win_path = Path::new(self.win_path_str); + if !win_path.exists() { + panic!("Bundled build requires `{}` to be installed at `{}`.", self.lib_name, self.win_path_str); + } + let lib_dir: PathBuf = win_path.join("lib"); + // for linking + println!("cargo:rustc-link-search=all={}", lib_dir.display()); + println!("cargo:rustc-link-lib={}", self.lib_name); + } else { + // The cargo meta data will be printed automatically. + let _ = pkg_config::Config::new() + .cargo_metadata(true) // This is on by default but making it explicit here. + .atleast_version(self.lib_version) + .probe(self.lib_name) + .unwrap_or_else(|e| panic!("Bundled build requires `{}` >= {} to be discoverable via pkg-config ({}).", self.lib_name, self.lib_version, e)); + } + } + } + } + + /// All the dependencies of tpm2-tss. + /// + /// This is not used in all configurations therefore + /// the `allow(unused)`. + #[allow(unused)] + const DEPENDENCIES: [Dependency<'static>; 1] = [Dependency::new( + "libcrypto", + "1.1.0", + "C:\\OpenSSL-v11-Win64", + )]; + /// The installed tpm2-tss libraries that are of /// interest. pub struct Installation { @@ -104,6 +158,9 @@ pub mod tpm2_tss { pub fn bundled(out_path: &Path) -> Self { let version = Self::version(); let source_path = Self::source(out_path, &version); + for dep in DEPENDENCIES.iter() { + dep.probe(); + } Self::compile(&source_path); Self { _tss2_sys: Library::bundled_required("tss2-sys", &source_path, &version, false), @@ -373,11 +430,32 @@ pub mod tpm2_tss { } else { let install_path = Self::compile_with_autotools(source_path); + + // On some systems the files are installed to the lib64 dir + let tpm2_tss_pkg_config_path = if install_path.join("lib64").is_dir() { + install_path.join("lib64").join("pkgconfig") + } else if install_path.join("lib").is_dir() { + install_path.join("lib").join("pkgconfig") + } else { + panic!("Unable to find location to search for the bundled pkgconfig files.") + }; + + // Add the tpm2-tss libraries pkgconfig path first among the paths. + let pkg_config_paths = match std::env::var_os("PKG_CONFIG_PATH") { + Some(existing_paths) => { + let mut paths = vec![tpm2_tss_pkg_config_path]; + paths.append(&mut std::env::split_paths(&existing_paths).collect::>()); + std::env::join_paths(paths) + .expect("Should be possible to join all the pkg config paths into a PATH string.") + }, + None => { + std::env::join_paths(vec![tpm2_tss_pkg_config_path]) + .expect("Should be possible to convert tpm2-tss pkgconfig path to a PATH str.") + }, + }; + // SAFETY: The build script is not multi threaded so this is safe to do. - unsafe {std::env::set_var( - "PKG_CONFIG_PATH", - format!("{}", install_path.join("lib").join("pkgconfig").display()), - )}; + unsafe {std::env::set_var("PKG_CONFIG_PATH", pkg_config_paths)}; } } } @@ -645,7 +723,7 @@ pub mod tpm2_tss { cfg_if::cfg_if! { if #[cfg(windows)] { let include_path = _source_path.join("include").join("tss2"); - println!("cargo:rustc-link-lib=dylib={lib_name}"); + println!("cargo:rustc-link-lib={lib_name}"); Some(Self { header_file: Self::header_file(lib_name, &include_path, true), version: lib_version.to_string(), @@ -715,8 +793,15 @@ pub mod tpm2_tss { with_header_files: bool, lib_version: &str, ) -> Option { + // Make PKG config report as much as possible to cargo + // so there is no chance of ending up with `undefined references`. pkg_config::Config::new() .atleast_version(lib_version) + .cargo_metadata(true) + .env_metadata(true) + .print_system_libs(true) + .print_system_cflags(true) + .statik(true) .probe(lib_name) .ok() .map(|pkg_config| {