CMake 秘籍(八)(3)

简介: CMake 秘籍(八)

CMake 秘籍(八)(2)https://developer.aliyun.com/article/1525075

根据系统环境配置预处理器定义

config.h文件是从src/config.h.in生成的,其中包含根据系统能力配置的预处理器标志:

/* Define if we have EBCDIC code */
#undef EBCDIC
/* Define unless no X support found */
#undef HAVE_X11
/* Define when terminfo support found */
#undef TERMINFO
/* Define when termcap.h contains ospeed */
#undef HAVE_OSPEED
/* ... */

src/config.h生成的示例可以像这个示例一样开始(定义可能因环境而异):

/* Define if we have EBCDIC code */
/* #undef EBCDIC */
/* Define unless no X support found */
#define HAVE_X11 1
/* Define when terminfo support found */
#define TERMINFO 1
/* Define when termcap.h contains ospeed */
/* #undef HAVE_OSPEED */
/* ... */

平台检查的一个很好的资源是这个页面:www.vtk.org/Wiki/CMake:How_To_Write_Platform_Checks

src/configure.ac中,我们可以检查需要执行哪些平台检查以设置相应的预处理器定义。

我们将使用#cmakedefinecmake.org/cmake/help/v3.5/command/configure_file.html?highlight=cmakedefine),并确保我们不会破坏现有的 Autotools 构建,我们将复制config.h.inconfig.h.cmake.in,并将所有#undef SOME_DEFINITION更改为#cmakedefine SOME_DEFINITION @SOME_DEFINITION@

generate_config_h函数中,我们首先定义一些变量:

set(TERMINFO 1)
set(UNIX 1)
# this is hardcoded to keep the discussion in the book chapter
# which describes the migration to CMake simpler
set(TIME_WITH_SYS_TIME 1)
set(RETSIGTYPE void)
set(SIGRETURN return)
find_package(X11)
set(HAVE_X11 ${X11_FOUND})

然后,我们执行一些类型大小检查:

check_type_size("int" VIM_SIZEOF_INT)
check_type_size("long" VIM_SIZEOF_LONG)
check_type_size("time_t" SIZEOF_TIME_T)
check_type_size("off_t" SIZEOF_OFF_T)

然后,我们遍历函数并检查系统是否能够解析它们:

foreach(
  _function IN ITEMS
  fchdir fchown fchmod fsync getcwd getpseudotty
  getpwent getpwnam getpwuid getrlimit gettimeofday getwd lstat
  memset mkdtemp nanosleep opendir putenv qsort readlink select setenv
  getpgid setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction
  sigprocmask sigvec strcasecmp strerror strftime stricmp strncasecmp
  strnicmp strpbrk strtol towlower towupper iswupper
  usleep utime utimes mblen ftruncate
  )
  string(TOUPPER "${_function}" _function_uppercase)
  check_function_exists(${_function} HAVE_${_function_uppercase})
endforeach()

我们验证特定的库是否包含特定的函数:

check_library_exists(tinfo tgetent "" HAVE_TGETENT)
if(NOT HAVE_TGETENT)
  message(FATAL_ERROR "Could not find the tgetent() function. You need to install a terminal library; for example ncurses.")
endif()

然后,我们遍历头文件并检查它们是否可用:

foreach(
  _header IN ITEMS
  setjmp.h dirent.h
  stdint.h stdlib.h string.h
  sys/select.h sys/utsname.h termcap.h fcntl.h
  sgtty.h sys/ioctl.h sys/time.h sys/types.h
  termio.h iconv.h inttypes.h langinfo.h math.h
  unistd.h stropts.h errno.h sys/resource.h
  sys/systeminfo.h locale.h sys/stream.h termios.h
  libc.h sys/statfs.h poll.h sys/poll.h pwd.h
  utime.h sys/param.h libintl.h libgen.h
  util/debug.h util/msg18n.h frame.h sys/acl.h
  sys/access.h sys/sysinfo.h wchar.h wctype.h
  )
  string(TOUPPER "${_header}" _header_uppercase)
  string(REPLACE "/" "_" _header_normalized "${_header_uppercase}")
  string(REPLACE "." "_" _header_normalized "${_header_normalized}")
  check_include_files(${_header} HAVE_${_header_normalized})
endforeach()

然后,我们将 CMake 选项从主CMakeLists.txt转换为预处理器定义:

string(TOUPPER "${FEATURES}" _features_upper)
set(FEAT_${_features_upper} 1)
set(FEAT_NETBEANS_INTG ${ENABLE_NETBEANS})
set(FEAT_JOB_CHANNEL ${ENABLE_CHANNEL})
set(FEAT_TERMINAL ${ENABLE_TERMINAL})

最后,我们检查是否能够编译特定的代码片段:

check_c_source_compiles(
  "
  #include <sys/types.h>
  #include <sys/stat.h>
  int
  main ()
  {
          struct stat st;
          int n;
          stat(\"/\", &st);
          n = (int)st.st_blksize;
    ;
    return 0;
  }
  "
  HAVE_ST_BLKSIZE
  )

然后使用定义的变量来配置src/config.h.cmake.inconfig.h,这完成了generate_config_h函数:

configure_file(
  ${CMAKE_CURRENT_LIST_DIR}/config.h.cmake.in
  ${CMAKE_CURRENT_BINARY_DIR}/auto/config.h
  @ONLY
  )

使用路径和编译器标志配置文件

我们生成pathdef.csrc/pathdef.c.in

#include "vim.h"
char_u *default_vim_dir = (char_u *)"@_default_vim_dir@";
char_u *default_vimruntime_dir = (char_u *)"@_default_vimruntime_dir@";
char_u *all_cflags = (char_u *)"@_all_cflags@";
char_u *all_lflags = (char_u *)"@_all_lflags@";
char_u *compiled_user = (char_u *)"@_compiled_user@";
char_u *compiled_sys = (char_u *)"@_compiled_sys@";

generate_pathdef_c函数配置src/pathdef.c.in,但我们省略了链接标志以简化:

function(generate_pathdef_c)
  set(_default_vim_dir ${CMAKE_INSTALL_PREFIX})
  set(_default_vimruntime_dir ${_default_vim_dir})
  set(_all_cflags "${CMAKE_C_COMPILER} ${CMAKE_C_FLAGS}")
  if(CMAKE_BUILD_TYPE STREQUAL "Release")
    set(_all_cflags "${_all_cflags} ${CMAKE_C_FLAGS_RELEASE}")
  else()
    set(_all_cflags "${_all_cflags} ${CMAKE_C_FLAGS_DEBUG}")
  endif()
  # it would require a bit more work and execute commands at build time
  # to get the link line into the binary
  set(_all_lflags "undefined")
  if(WIN32)
    set(_compiled_user $ENV{USERNAME})
  else()
    set(_compiled_user $ENV{USER})
  endif()
  cmake_host_system_information(RESULT _compiled_sys QUERY HOSTNAME)
  configure_file(
    ${CMAKE_CURRENT_LIST_DIR}/pathdef.c.in
    ${CMAKE_CURRENT_BINARY_DIR}/auto/pathdef.c
    @ONLY
    )
endfunction()

在配置时执行 shell 脚本

最后,我们使用以下函数生成osdef.h

function(generate_osdef_h)
  find_program(BASH_EXECUTABLE bash)
  execute_process(
    COMMAND
      ${BASH_EXECUTABLE} osdef.sh ${CMAKE_CURRENT_BINARY_DIR}
    WORKING_DIRECTORY
      ${CMAKE_CURRENT_LIST_DIR}
    )
endfunction()

为了在 ${CMAKE_CURRENT_BINARY_DIR}/src/auto 而不是 src/auto 中生成 osdef.h,我们不得不修改 osdef.sh 以接受 ${CMAKE_CURRENT_BINARY_DIR} 作为命令行参数。

osdef.sh内部,我们检查是否给出了这个参数:

if [ $# -eq 0 ]
  then
    # there are no arguments
    # assume the target directory is current directory
    target_directory=$PWD
  else
    # target directory is provided as argument
    target_directory=$1
fi

然后,我们生成 ${target_directory}/auto/osdef.h。为此,我们还需要调整osdef.sh内部的下述编译行:

$CC -I. -I$srcdir -I${target_directory} -E osdef0.c >osdef0.cc

CMake 秘籍(八)(4)https://developer.aliyun.com/article/1525077

相关文章
|
6月前
|
编译器 Shell 开发工具
CMake 秘籍(八)(5)
CMake 秘籍(八)
36 2
|
6月前
|
Linux iOS开发 C++
CMake 秘籍(六)(3)
CMake 秘籍(六)
48 1
|
6月前
|
Shell Linux C++
CMake 秘籍(六)(4)
CMake 秘籍(六)
49 1
|
6月前
|
编译器 Linux C++
CMake 秘籍(六)(5)
CMake 秘籍(六)
36 1
|
6月前
|
Linux C++ iOS开发
CMake 秘籍(三)(4)
CMake 秘籍(三)
40 1
|
6月前
|
Linux C++ iOS开发
CMake 秘籍(四)(1)
CMake 秘籍(四)
28 0
|
6月前
|
并行计算 关系型数据库 编译器
CMake 秘籍(七)(3)
CMake 秘籍(七)
88 0
|
6月前
|
并行计算 编译器 Linux
CMake 秘籍(二)(3)
CMake 秘籍(二)
33 0
|
6月前
|
编译器 Linux 开发工具
CMake 秘籍(四)(2)
CMake 秘籍(四)
28 0
|
6月前
|
XML 监控 Linux
CMake 秘籍(七)(4)
CMake 秘籍(七)
70 0