繁体   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