From 57eb6fb4660daf2e8768559d77163350df078505 Mon Sep 17 00:00:00 2001 From: Micah Snyder Date: Wed, 6 Dec 2023 16:17:13 -0500 Subject: [PATCH] CMake: Rust bindgen w/ C libs outside std include path In order to generate Rust bindings for C code, Rust's bindgen module needs to know where to find all headers included by the API. If they're all inside the project or inside the standard include path (e.g. /usr/include and /usr/local/include) that's fine. But for third- party C library headers from outside the standard include path, that's a problem. We didn't really notice this problem when generating on Unix systems until we switched to use OpenSSL 3.1 and tested on systems that have the OpenSSL 1.1.1 dev package installed. The ability to find headers outside the project path is also needed to generate bindings on Windows, if desired. This commit solves the problem by passing include directories for the ClamAV::libclamav CMake build target to the Rust build via the CARGO_INCLUDE_DIRECTORIES environment variable. Then, in the `libclamav_rust/build.rs` script, where we run bindgen, we split that `;` separated string into invididual paths and add each to the bindgen builder. --- cmake/FindRust.cmake | 14 +++++++------- libclamav_rust/CMakeLists.txt | 1 + libclamav_rust/build.rs | 10 ++++++++++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/cmake/FindRust.cmake b/cmake/FindRust.cmake index 4a90c41d3c..542f79be4d 100644 --- a/cmake/FindRust.cmake +++ b/cmake/FindRust.cmake @@ -236,7 +236,7 @@ function(add_rust_executable) # Build the executable. add_custom_command( OUTPUT "${OUTPUT}" - COMMAND ${CMAKE_COMMAND} -E env "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} + COMMAND ${CMAKE_COMMAND} -E env "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "CARGO_INCLUDE_DIRECTORIES=${ARGS_INCLUDE_DIRECTORIES}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} WORKING_DIRECTORY "${ARGS_SOURCE_DIRECTORY}" DEPENDS ${EXE_SOURCES} COMMENT "Building ${ARGS_TARGET} in ${ARGS_BINARY_DIRECTORY} with:\n\t ${cargo_EXECUTABLE} ${MY_CARGO_ARGS_STRING}") @@ -265,7 +265,7 @@ endfunction() function(add_rust_library) set(options) - set(oneValueArgs TARGET SOURCE_DIRECTORY BINARY_DIRECTORY PRECOMPILE_TESTS) + set(oneValueArgs TARGET SOURCE_DIRECTORY BINARY_DIRECTORY PRECOMPILE_TESTS INCLUDE_DIRECTORIES) cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(WIN32) @@ -287,8 +287,8 @@ function(add_rust_library) if("${CMAKE_OSX_ARCHITECTURES}" MATCHES "^(arm64;x86_64|x86_64;arm64)$") add_custom_command( OUTPUT "${OUTPUT}" - COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=x86_64-apple-darwin - COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=aarch64-apple-darwin + COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "CARGO_INCLUDE_DIRECTORIES=${ARGS_INCLUDE_DIRECTORIES}" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=x86_64-apple-darwin + COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "CARGO_INCLUDE_DIRECTORIES=${ARGS_INCLUDE_DIRECTORIES}" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=aarch64-apple-darwin COMMAND ${CMAKE_COMMAND} -E make_directory "${ARGS_BINARY_DIRECTORY}/${RUST_COMPILER_TARGET}/${CARGO_BUILD_TYPE}" COMMAND lipo -create ${ARGS_BINARY_DIRECTORY}/x86_64-apple-darwin/${CARGO_BUILD_TYPE}/lib${ARGS_TARGET}.a ${ARGS_BINARY_DIRECTORY}/aarch64-apple-darwin/${CARGO_BUILD_TYPE}/lib${ARGS_TARGET}.a -output "${OUTPUT}" WORKING_DIRECTORY "${ARGS_SOURCE_DIRECTORY}" @@ -297,14 +297,14 @@ function(add_rust_library) elseif("${CMAKE_OSX_ARCHITECTURES}" MATCHES "^(arm64)$") add_custom_command( OUTPUT "${OUTPUT}" - COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=aarch64-apple-darwin + COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "CARGO_INCLUDE_DIRECTORIES=${ARGS_INCLUDE_DIRECTORIES}" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=aarch64-apple-darwin WORKING_DIRECTORY "${ARGS_SOURCE_DIRECTORY}" DEPENDS ${LIB_SOURCES} COMMENT "Building ${ARGS_TARGET} in ${ARGS_BINARY_DIRECTORY} with: ${cargo_EXECUTABLE} ${MY_CARGO_ARGS_STRING}") elseif("${CMAKE_OSX_ARCHITECTURES}" MATCHES "^(x86_64)$") add_custom_command( OUTPUT "${OUTPUT}" - COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=x86_64-apple-darwin + COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "CARGO_INCLUDE_DIRECTORIES=${ARGS_INCLUDE_DIRECTORIES}" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=x86_64-apple-darwin COMMAND ${CMAKE_COMMAND} -E make_directory "${ARGS_BINARY_DIRECTORY}/${RUST_COMPILER_TARGET}/${CARGO_BUILD_TYPE}" WORKING_DIRECTORY "${ARGS_SOURCE_DIRECTORY}" DEPENDS ${LIB_SOURCES} @@ -312,7 +312,7 @@ function(add_rust_library) else() add_custom_command( OUTPUT "${OUTPUT}" - COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} + COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "CARGO_INCLUDE_DIRECTORIES=${ARGS_INCLUDE_DIRECTORIES}" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} WORKING_DIRECTORY "${ARGS_SOURCE_DIRECTORY}" DEPENDS ${LIB_SOURCES} COMMENT "Building ${ARGS_TARGET} in ${ARGS_BINARY_DIRECTORY} with: ${cargo_EXECUTABLE} ${MY_CARGO_ARGS_STRING}") diff --git a/libclamav_rust/CMakeLists.txt b/libclamav_rust/CMakeLists.txt index 7df3ffee91..dc8a139123 100644 --- a/libclamav_rust/CMakeLists.txt +++ b/libclamav_rust/CMakeLists.txt @@ -8,6 +8,7 @@ add_rust_library(TARGET clamav_rust SOURCE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" BINARY_DIRECTORY "${CMAKE_BINARY_DIR}" + INCLUDE_DIRECTORIES "$,PREPEND,-I>" # Tests cannot be pre-compiled here, because there are circular dependencies # between libclamav_rust and libclamav to include calls like `cli_getdsig()` # as well as the logging functions. diff --git a/libclamav_rust/build.rs b/libclamav_rust/build.rs index 88d9e6deb3..da7e5d5171 100644 --- a/libclamav_rust/build.rs +++ b/libclamav_rust/build.rs @@ -133,6 +133,7 @@ fn main() -> Result<(), &'static str> { fn execute_bindgen() -> Result<(), &'static str> { let build_dir = PathBuf::from(env::var("CARGO_TARGET_DIR").unwrap_or_else(|_| ".".into())); let build_include_path = format!("-I{}", build_dir.join(".").to_str().unwrap()); + let has_include_directories = env::var("CARGO_INCLUDE_DIRECTORIES").ok(); // Configure and generate bindings. let mut builder = builder() @@ -147,6 +148,15 @@ fn execute_bindgen() -> Result<(), &'static str> { // Enable bindgen to find generated headers in the build directory, too. .clang_arg(build_include_path); + // If include directories were specified, add them to the builder. + if let Some(include_directories) = has_include_directories { + for include_directory in include_directories.split(';') { + eprintln!("Including {include_directory}"); + // Enable bindgen to find dependencies headers. + builder = builder.clang_arg(include_directory); + } + } + for &include_path in BINDGEN_INCLUDE_PATHS { builder = builder.clang_arg(include_path); }