Skip to content

Commit d763203

Browse files
billatarmtgonzalezorlandoarm
authored andcommitted
build: support pkg-config
Support querying pkg-config for mbedtls directories. When building against mbedtls, use the following search criteria to locate the mbedtls dependency: 1. Env Variables 2. pkg-config 3. vendor directory This will allow binary packages from distributions to work without modification and not require a vendored mbedtls package. The problem with vendored packages is upsates, and since mbedtls is a critical cryptographic suite, it's important that the distributions can quickly update a single mbedtls package that everyone links to. Related to: - Mbed-TLS/mbedtls#8691 Signed-off-by: Bill Roberts <bill.roberts@arm.com>
1 parent d06b6eb commit d763203

File tree

3 files changed

+151
-92
lines changed

3 files changed

+151
-92
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

psa-crypto-sys/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ cc = "1.0.59"
1717
cmake = "0.1.44"
1818
regex = "1.9.1"
1919
walkdir = "2.3.1"
20+
pkg-config = "0.3.29"
2021

2122
[features]
2223
default = ["operations"]

psa-crypto-sys/build.rs

Lines changed: 143 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,73 @@ mod common {
6666
use std::io::{Error, ErrorKind, Result};
6767
use std::path::{Path, PathBuf};
6868

69+
#[cfg(any(feature = "prefix", feature = "operations"))]
70+
pub fn get_external_mbedtls() -> Option<Result<(String, String)>> {
71+
if env::var("MBEDTLS_LIB_DIR").is_err() ^ env::var("MBEDTLS_INCLUDE_DIR").is_err() {
72+
return Some(Err(Error::new(
73+
ErrorKind::Other,
74+
"both environment variables MBEDTLS_LIB_DIR and MBEDTLS_INCLUDE_DIR need to be set for operations feature",
75+
)));
76+
}
77+
78+
if let (Ok(lib_dir), Ok(include_dir)) =
79+
(env::var("MBEDTLS_LIB_DIR"), env::var("MBEDTLS_INCLUDE_DIR"))
80+
{
81+
println!("Found environment variables, using external MbedTLS");
82+
return Some(Ok((include_dir, lib_dir)));
83+
}
84+
85+
if let Ok(mbedtls_result) = pkg_config::Config::new()
86+
.range_version("3.5".."4.0")
87+
.probe("mbedtls")
88+
{
89+
let include_dirs: Vec<String> = mbedtls_result
90+
.include_paths
91+
.into_iter()
92+
.map(|x: PathBuf| -> String { x.into_os_string().into_string().unwrap() })
93+
.collect();
94+
let include_dir = include_dirs.join(" ");
95+
// The current build framework doesn't support multiple lib paths for -L unfortuantely, so
96+
// we just take the first element, which is enough for now :-(
97+
let lib_dir = <PathBuf as Clone>::clone(&mbedtls_result.link_paths[0])
98+
.into_os_string()
99+
.into_string()
100+
.unwrap();
101+
println!("Found pkg-config mbedtls, using external MbedTLS");
102+
return Some(Ok((include_dir, lib_dir)));
103+
}
104+
105+
// No env vars set and no discovered package through pkg-config
106+
None
107+
}
108+
109+
#[cfg(all(feature = "interface", not(feature = "operations")))]
110+
pub fn get_external_mbedtls_include_only() -> Result<String> {
111+
if let Ok(include_dir) = env::var("MBEDTLS_INCLUDE_DIR") {
112+
println!("Found environment variable, using external MbedTLS");
113+
return Ok(include_dir);
114+
}
115+
116+
if let Ok(mbedtls_result) = pkg_config::Config::new()
117+
.range_version("3.5".."4.0")
118+
.probe("mbedtls")
119+
{
120+
let include_dirs: Vec<String> = mbedtls_result
121+
.include_paths
122+
.into_iter()
123+
.map(|x: PathBuf| -> String { x.into_os_string().into_string().unwrap() })
124+
.collect();
125+
let include_dir = include_dirs.join(" ");
126+
127+
return Ok(include_dir);
128+
}
129+
130+
Err(Error::new(
131+
ErrorKind::Other,
132+
"interface feature necessitates MBEDTLS_INCLUDE_DIR environment variable",
133+
))
134+
}
135+
69136
pub fn configure_mbed_crypto() -> Result<()> {
70137
let mbedtls_dir = String::from("./vendor");
71138
let mbedtls_config = mbedtls_dir + "/scripts/config.py";
@@ -209,22 +276,17 @@ mod common {
209276
#[cfg(all(feature = "interface", not(feature = "operations")))]
210277
mod interface {
211278
use super::common;
212-
use std::env;
213-
use std::io::{Error, ErrorKind, Result};
279+
use std::io::Result;
214280

215281
// Build script when the interface feature is on and not the operations one
216282
pub fn script_interface() -> Result<()> {
217-
if let Ok(include_dir) = env::var("MBEDTLS_INCLUDE_DIR") {
218-
common::configure_mbed_crypto()?;
219-
common::generate_mbed_crypto_bindings(include_dir.clone(), false)?;
220-
let _ = common::compile_shim_library(include_dir, true, false)?;
221-
Ok(())
222-
} else {
223-
Err(Error::new(
224-
ErrorKind::Other,
225-
"interface feature necessitates MBEDTLS_INCLUDE_DIR environment variable",
226-
))
227-
}
283+
let include_dir = common::get_external_mbedtls_include_only()?;
284+
285+
// TODO: Does interface need the vendored mbedtls?
286+
common::configure_mbed_crypto()?;
287+
common::generate_mbed_crypto_bindings(include_dir.clone(), false)?;
288+
let _ = common::compile_shim_library(include_dir, true, false)?;
289+
Ok(())
228290
}
229291
}
230292

@@ -235,9 +297,9 @@ mod operations {
235297
use super::common::prefix;
236298
use cmake::Config;
237299
use std::env;
300+
use std::io::Result;
238301
#[cfg(feature = "prefix")]
239302
use std::io::Write;
240-
use std::io::{Error, ErrorKind, Result};
241303
use std::path::PathBuf;
242304
use walkdir::WalkDir;
243305

@@ -288,36 +350,31 @@ mod operations {
288350
let include;
289351
let external_mbedtls;
290352

291-
if env::var("MBEDTLS_LIB_DIR").is_err() ^ env::var("MBEDTLS_INCLUDE_DIR").is_err() {
292-
return Err(Error::new(
293-
ErrorKind::Other,
294-
"both environment variables MBEDTLS_LIB_DIR and MBEDTLS_INCLUDE_DIR need to be set for operations feature",
295-
));
296-
}
297-
if let (Ok(lib_dir), Ok(include_dir)) =
298-
(env::var("MBEDTLS_LIB_DIR"), env::var("MBEDTLS_INCLUDE_DIR"))
299-
{
300-
println!("Found environment varibales, using external MbedTLS");
301-
lib = lib_dir;
302-
include = include_dir;
303-
statically = cfg!(feature = "static") || env::var("MBEDCRYPTO_STATIC").is_ok();
304-
external_mbedtls = true;
305-
} else {
306-
println!("Did not find environment variables, building MbedTLS!");
307-
common::configure_mbed_crypto()?;
308-
let mut mbed_lib_dir = compile_mbed_crypto()?;
309-
let mut mbed_include_dir = mbed_lib_dir.clone();
310-
mbed_lib_dir.push("lib");
311-
if !mbed_lib_dir.as_path().exists() {
312-
_ = mbed_lib_dir.pop();
313-
mbed_lib_dir.push("lib64");
353+
match common::get_external_mbedtls() {
354+
Some(result) => {
355+
let (include_dir, lib_dir) = result.unwrap();
356+
lib = lib_dir;
357+
include = include_dir;
358+
statically = cfg!(feature = "static") || env::var("MBEDCRYPTO_STATIC").is_ok();
359+
external_mbedtls = true;
314360
}
315-
mbed_include_dir.push("include");
361+
None => {
362+
println!("Did not find external MBEDTLS, building MbedTLS!");
363+
common::configure_mbed_crypto()?;
364+
let mut mbed_lib_dir = compile_mbed_crypto()?;
365+
let mut mbed_include_dir = mbed_lib_dir.clone();
366+
mbed_lib_dir.push("lib");
367+
if !mbed_lib_dir.as_path().exists() {
368+
_ = mbed_lib_dir.pop();
369+
mbed_lib_dir.push("lib64");
370+
}
371+
mbed_include_dir.push("include");
316372

317-
lib = mbed_lib_dir.to_str().unwrap().to_owned();
318-
include = mbed_include_dir.to_str().unwrap().to_owned();
319-
statically = true;
320-
external_mbedtls = false;
373+
lib = mbed_lib_dir.to_str().unwrap().to_owned();
374+
include = mbed_include_dir.to_str().unwrap().to_owned();
375+
statically = true;
376+
external_mbedtls = false;
377+
}
321378
}
322379

323380
// Linking to PSA Crypto library is only needed for the operations.
@@ -332,58 +389,52 @@ mod operations {
332389
#[cfg(feature = "prefix")]
333390
// Build script when the operations feature is on
334391
pub fn script_operations() -> Result<()> {
335-
if env::var("MBEDTLS_LIB_DIR").is_err() ^ env::var("MBEDTLS_INCLUDE_DIR").is_err() {
336-
return Err(Error::new(
337-
ErrorKind::Other,
338-
"both environment variables MBEDTLS_LIB_DIR and MBEDTLS_INCLUDE_DIR need to be set for operations feature",
339-
));
340-
}
341-
342-
if let (Ok(lib_dir), Ok(include_dir)) =
343-
(env::var("MBEDTLS_LIB_DIR"), env::var("MBEDTLS_INCLUDE_DIR"))
344-
{
345-
println!("Building with external MBEDTLS");
346-
347-
// Request rustc to link the Mbed Crypto library
348-
let link_type = if cfg!(feature = "static") || env::var("MBEDCRYPTO_STATIC").is_ok() {
349-
"static"
350-
} else {
351-
"dylib"
352-
};
353-
println!("cargo:rustc-link-search=native={}", lib_dir);
354-
println!("cargo:rustc-link-lib={}=mbedcrypto", link_type);
355-
356-
common::generate_mbed_crypto_bindings(include_dir.clone(), true)?;
357-
let _ = common::compile_shim_library(include_dir, true, true)?;
358-
} else {
359-
println!("Did not find environment variables, building MbedTLS!");
360-
common::configure_mbed_crypto()?;
361-
let mut mbed_lib_dir = compile_mbed_crypto()?;
362-
let mut mbed_include_dir = mbed_lib_dir.clone();
363-
mbed_lib_dir.push("lib");
364-
if !mbed_lib_dir.as_path().exists() {
365-
_ = mbed_lib_dir.pop();
366-
mbed_lib_dir.push("lib64");
392+
match common::get_external_mbedtls() {
393+
Some(result) => {
394+
let (include_dir, lib_dir) = result.unwrap();
395+
// Request rustc to link the Mbed Crypto library
396+
let link_type = if cfg!(feature = "static") || env::var("MBEDCRYPTO_STATIC").is_ok()
397+
{
398+
"static"
399+
} else {
400+
"dylib"
401+
};
402+
println!("cargo:rustc-link-search=native={}", lib_dir);
403+
println!("cargo:rustc-link-lib={}=mbedcrypto", link_type);
404+
405+
common::generate_mbed_crypto_bindings(include_dir.clone(), true)?;
406+
let _ = common::compile_shim_library(include_dir, true, true)?;
367407
}
408+
None => {
409+
println!("Did not find environment variables, building MbedTLS!");
410+
common::configure_mbed_crypto()?;
411+
let mut mbed_lib_dir = compile_mbed_crypto()?;
412+
let mut mbed_include_dir = mbed_lib_dir.clone();
413+
mbed_lib_dir.push("lib");
414+
if !mbed_lib_dir.as_path().exists() {
415+
_ = mbed_lib_dir.pop();
416+
mbed_lib_dir.push("lib64");
417+
}
368418

369-
mbed_include_dir.push("include");
370-
let main_lib = mbed_lib_dir.join("libmbedcrypto.a");
371-
372-
let include = mbed_include_dir.to_str().unwrap().to_owned();
373-
common::generate_mbed_crypto_bindings(include.clone(), false)?;
374-
let shim_lib = common::compile_shim_library(include, false, false)?;
375-
376-
// Modify and copy the libraries into a new directory.
377-
let llib_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("llib");
378-
let main_lib_name = prefix() + "mbedcrypto";
379-
let shim_lib_name = prefix() + "shim";
380-
objcopy(vec![
381-
(main_lib, llib_path.join(format!("lib{}.a", main_lib_name))),
382-
(shim_lib, llib_path.join(format!("lib{}.a", shim_lib_name))),
383-
])?;
384-
println!("cargo:rustc-link-search=native={}", llib_path.display());
385-
println!("cargo:rustc-link-lib=static={}", main_lib_name);
386-
println!("cargo:rustc-link-lib=static={}", shim_lib_name);
419+
mbed_include_dir.push("include");
420+
let main_lib = mbed_lib_dir.join("libmbedcrypto.a");
421+
422+
let include = mbed_include_dir.to_str().unwrap().to_owned();
423+
common::generate_mbed_crypto_bindings(include.clone(), false)?;
424+
let shim_lib = common::compile_shim_library(include, false, false)?;
425+
426+
// Modify and copy the libraries into a new directory.
427+
let llib_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("llib");
428+
let main_lib_name = prefix() + "mbedcrypto";
429+
let shim_lib_name = prefix() + "shim";
430+
objcopy(vec![
431+
(main_lib, llib_path.join(format!("lib{}.a", main_lib_name))),
432+
(shim_lib, llib_path.join(format!("lib{}.a", shim_lib_name))),
433+
])?;
434+
println!("cargo:rustc-link-search=native={}", llib_path.display());
435+
println!("cargo:rustc-link-lib=static={}", main_lib_name);
436+
println!("cargo:rustc-link-lib=static={}", shim_lib_name);
437+
}
387438
}
388439

389440
Ok(())

0 commit comments

Comments
 (0)