簡體   English   中英

如何使用 CMake 正確檢查 crypt()?

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM