[英]How do I correctly check for crypt() with CMake?
首先,请不要教我如何使用crypt()
——我知道它做什么和不做什么。 我有一个小 C 程序,它应该使用操作系统用来检查用户密码的crypt()
(假设它确实如此,我知道 OpenBSD 没有)。
但是,每个 libc 中的crypt()
都略有不同:有些需要unistd.h
,有些需要crypt.h
,有些不需要额外的库,有些需要-lcrypt
。 还有 libxcrypt ,它开始取代 glibc 长期不推荐使用的crypt()
。
长话短说:我是 CMake 的新手,虽然使用FindSomething.cmake
或 pkg-config 检查某些东西很容易,但检查要为 libc crypt()
调用的恶魔却不是,我觉得我正在这样做错误的。 它有效,但看起来太复杂了。
另外,如果其他方法找不到crypt()
,我想尝试使用 libxcrypt。 我怎样才能做到这一点而不重复一半的检查?
cmake_minimum_required(VERSION 3.10)
project(pwhash)
set(USE_LIBXCRYPT OFF CACHE BOOL "Use libxcrypt for crypt()")
find_package(PkgConfig REQUIRED)
add_executable(pwhash pwhash.c)
if(USE_LIBXCRYPT)
pkg_check_modules(LIBXCRYPT IMPORTED_TARGET REQUIRED libxcrypt)
target_link_libraries(pwhash PUBLIC PkgConfig::LIBXCRYPT)
target_compile_definitions(pwhash PUBLIC HAVE_CRYPT_H)
else()
include(CheckIncludeFile)
check_include_file(crypt.h HAVE_CRYPT_H)
if(HAVE_CRYPT_H)
list(APPEND CMAKE_REQUIRED_INCLUDES "crypt.h")
target_compile_definitions(pwhash PUBLIC HAVE_CRYPT_H)
endif()
include(CheckSymbolExists)
unset(HAVE_CRYPT CACHE)
check_symbol_exists(crypt "unistd.h" HAVE_CRYPT)
if(NOT HAVE_CRYPT)
unset(HAVE_CRYPT CACHE)
list(APPEND CMAKE_REQUIRED_LIBRARIES "crypt")
check_symbol_exists(crypt "unistd.h" HAVE_CRYPT)
if(HAVE_CRYPT)
target_link_libraries(pwhash PUBLIC crypt)
else()
error("No crypt() found")
endif()
endif()
endif()
但是,每个 libc 中的
crypt()
都略有不同:有些需要unistd.h
,有些需要crypt.h
,有些不需要额外的库,有些需要-lcrypt
。 还有 libxcrypt ,它开始取代 glibc 长期不推荐使用的crypt()
。
据我所知, crypt
函数在所有主要实现的unistd.h
声明。 这包括 macOS、FreeBSD、OpenBSD 和 Linux。 crypt 函数的扩展集,如crypt_r
、 crypt_rn
和crypt_ra
位于<crypt.h>
。 我很想知道哪些 libcs 在unistd.h
没有crypt
。
另外,如果其他方法找不到 crypt(),我想尝试使用 libxcrypt。 我怎样才能做到这一点而不重复一半的检查?
为此,我们将编写一个函数来封装每个方法。 每个函数都会尝试定义一个接口库pwhash_crypt
,它封装了crypt()
函数的使用要求。
我们将从样板开始:
cmake_minimum_required(VERSION 3.20)
project(pwhash LANGUAGES C)
首先,我们来看看find_libxcrypt
function(find_libxcrypt)
if (TARGET pwhash_crypt)
return()
endif ()
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBXCRYPT IMPORTED_TARGET libxcrypt)
if (TARGET PkgConfig::LIBXCRYPT)
add_library(pwhash_crypt INTERFACE)
target_link_libraries(pwhash_crypt INTERFACE PkgConfig::LIBXCRYPT)
target_compile_definitions(pwhash_crypt INTERFACE HAVE_CRYPT_H)
endif ()
endfunction()
这应该相当简单。 如果pwhash_crypt
目标不存在,那么它将尝试使用 pkg-config 来查找libxcrypt
并在存在时创建pwhash_crypt
。 库将它们的接口属性传播到链接到它们的目标,因此稍后当我们将pwhash
链接到pwhash_crypt
,它将定义HAVE_CRYPT_H
。
系统 crypt 实现find_sys_crypt
函数同样简单:
function(find_sys_crypt)
if (TARGET pwhash_crypt)
return()
endif ()
include(CheckIncludeFile)
include(CheckSymbolExists)
set(defs "")
set(CMAKE_REQUIRED_INCLUDES "")
set(CMAKE_REQUIRED_LIBRARIES "")
check_include_file("crypt.h" HAVE_CRYPT_H)
if (HAVE_CRYPT_H)
list(APPEND defs HAVE_CRYPT_H)
list(APPEND CMAKE_REQUIRED_INCLUDES "crypt.h")
endif ()
check_symbol_exists(crypt "unistd.h" HAVE_CRYPT)
if (NOT HAVE_CRYPT)
list(APPEND CMAKE_REQUIRED_LIBRARIES crypt)
check_symbol_exists(crypt "unistd.h" HAVE_CRYPT_WITH_LIB)
endif ()
if (HAVE_CRYPT OR HAVE_CRYPT_WITH_LIB)
add_library(pwhash_crypt INTERFACE)
target_link_libraries(pwhash_crypt INTERFACE ${CMAKE_REQUIRED_LIBRARIES})
target_compile_definitions(pwhash_crypt INTERFACE ${defs})
endif ()
endfunction()
这遵循与上一个函数和问题中的检查相同的结构。
然后你可以让用户选择是先还是第二次查找libxcrypt
,然后将结果链接到你的pwhash
可执行文件:
option(PREFER_LIBXCRYPT "Prefer libxcrypt for crypt()" OFF)
if (PREFER_LIBXCRYPT)
find_libxcrypt()
find_sys_crypt()
else ()
find_sys_crypt()
find_libxcrypt()
endif ()
if (NOT TARGET pwhash_crypt)
message(FATAL_ERROR "Could not find a suitable crypt() implementation")
endif ()
add_executable(pwhash pwhash.c)
target_link_libraries(pwhash PRIVATE pwhash_crypt)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.