[英]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.