简体   繁体   English

如何使用 CMake 正确检查 crypt()?

[英]How do I correctly check for crypt() with CMake?

First of all, please don't lecture me about using crypt() – I know what it does and what it does not.首先,请不要教我如何使用crypt() ——我知道它做什么和不做什么。 I have a little C program that is supposed to use the very crypt() that the OS is using to check user passwords (assuming it does, I know OpenBSD does not).我有一个小 C 程序,它应该使用操作系统用来检查用户密码的crypt() (假设它确实如此,我知道 OpenBSD 没有)。

However, crypt() is a little different in every libc: some require unistd.h , some require crypt.h , some require no extra libraries, some require -lcrypt .但是,每个 libc 中的crypt()都略有不同:有些需要unistd.h ,有些需要crypt.h ,有些不需要额外的库,有些需要-lcrypt And there's libxcrypt as well, which is starting to replace glibc's long deprecated crypt() .还有 libxcrypt ,它开始取代 glibc 长期不推荐使用的crypt()

Long story short: I'm new to CMake, and while checking for something with FindSomething.cmake or pkg-config is easy, checking for which demons to invoke for libc crypt() is not, and I feel like I'm doing it wrong.长话短说:我是 CMake 的新手,虽然使用FindSomething.cmake或 pkg-config 检查某些东西很容易,但检查要为 libc crypt()调用的恶魔却不是,我觉得我正在这样做错误的。 It works, but looks way too complicated.它有效,但看起来太复杂了。

Also, I'd like to try using libxcrypt if crypt() wasn't found with other methods.另外,如果其他方法找不到crypt() ,我想尝试使用 libxcrypt。 How can I do that without repeating half the checks?我怎样才能做到这一点而不重复一半的检查?

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()

However, crypt() is a little different in every libc: some require unistd.h , some require crypt.h , some require no extra libraries, some require -lcrypt .但是,每个 libc 中的crypt()都略有不同:有些需要unistd.h ,有些需要crypt.h ,有些不需要额外的库,有些需要-lcrypt And there's libxcrypt as well, which is starting to replace glibc's long deprecated crypt() .还有 libxcrypt ,它开始取代 glibc 长期不推荐使用的crypt()

As far as I know, the crypt function is declared in unistd.h on all major implementations.据我所知, crypt函数在所有主要实现的unistd.h声明。 That includes macOS, FreeBSD, OpenBSD, and Linux.这包括 macOS、FreeBSD、OpenBSD 和 Linux。 The extended set of crypt functions, like crypt_r , crypt_rn , and crypt_ra are in <crypt.h> . crypt 函数的扩展集,如crypt_rcrypt_rncrypt_ra位于<crypt.h> I'm curious to know which libcs do not have crypt in unistd.h .我很想知道哪些 libcs​​ 在unistd.h没有crypt

Also, I'd like to try using libxcrypt if crypt() wasn't found with other methods.另外,如果其他方法找不到 crypt(),我想尝试使用 libxcrypt。 How can I do that without repeating half the checks?我怎样才能做到这一点而不重复一半的检查?

For this, we'll write a function to encapsulate each method.为此,我们将编写一个函数来封装每个方法。 Each function will try to define an interface library pwhash_crypt that encapsulates the usage requirements for the crypt() function.每个函数都会尝试定义一个接口库pwhash_crypt ,它封装了crypt()函数的使用要求。

We'll start with the boilerplate:我们将从样板开始:

cmake_minimum_required(VERSION 3.20)
project(pwhash LANGUAGES C)

First, we'll look at find_libxcrypt首先,我们来看看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()

This should be fairly straightforward.这应该相当简单。 If the pwhash_crypt target does not exist, then it will try to use pkg-config to find libxcrypt and create pwhash_crypt if so.如果pwhash_crypt目标不存在,那么它将尝试使用 pkg-config 来查找libxcrypt并在存在时创建pwhash_crypt Libraries propagate their interface properties to the targets linking to them, so later when we link pwhash to pwhash_crypt , it will have HAVE_CRYPT_H defined.库将它们的接口属性传播到链接到它们的目标,因此稍后当我们将pwhash链接到pwhash_crypt ,它将定义HAVE_CRYPT_H

The function for the system crypt implementation find_sys_crypt is similarly straightforward:系统 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()

This follows the same structure as the previous function and the checks in your question.这遵循与上一个函数和问题中的检查相同的结构。

Then you can give users an option whether to look for libxcrypt first or second and then link the result to your pwhash executable:然后你可以让用户选择是先还是第二次查找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