首页 > 解决方案 > 从 CMake execute_process 内部运行 awk

问题描述

我试图awk在 CMake中运行execute_process,但不知何故未能得到预期的结果。我我一定是违反了一些逃避规则,但我不确定我还需要在这里逃避什么。让我通过 MWE 来演示。

考虑以下内容version.h(为简洁起见省略了标题后卫):

#define LIB_MAJVER             1
#define LIB_MINVER             2
#define LIB_PATCH              3
#define LIB_BUILD              4

现在考虑以下简单的awk命令:

awk '$1 ~ /^#define/ && $2 ~ /^LIB_(MAJVER|MINVER|PATCH|BUILD)$/ { print "set(${PRJNAME}_" $2 " " $3 ")" }' version.h

输出应该是这样的(并且在从 shell 执行时):

set(${PRJNAME}_LIB_MAJVER 2)
set(${PRJNAME}_LIB_MINVER 9)
set(${PRJNAME}_LIB_PATCH 9)
set(${PRJNAME}_LIB_BUILD 1)

...这就是我include()在从版本标头生成它之后打算做的事情。

现在考虑以下内容CMakeLists.txt

cmake_minimum_required(VERSION 3.1)
set(PRJNAME foobar)

project (${PRJNAME})
find_program(AWK awk mawk gawk)

if(AWK MATCHES ".+-NOTFOUND")
    message(FATAL_ERROR "FATAL: awk (and mawk and gawk) could not be found (${AWK}).")
else()
    execute_process(
        COMMAND "${AWK}" '$1 ~ /^#define/ && $2 ~ /^LIB_(MAJVER|MINVER|PATCH|BUILD)$/\ { print "set(${PRJNAME}_" $2 " " $3 ")" }' "${CMAKE_SOURCE_DIR}/version.h"
        RESULT_VARIABLE AWK_EXITCODE
        OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/version.cmake"
        )
    message(STATUS "Exit code from awk: ${AWK_EXITCODE}")
    include(${CMAKE_CURRENT_BINARY_DIR}/version.cmake)
endif()

的输出execute_process是:

awk: cmd. line:1: '$1
awk: cmd. line:1: ^ invalid char ''' in expression

...这表明我试图执行的内容被逐字传递,而不是参数被去掉外引号。所以我什至懒得逃避命令$中的出现awk,我希望它必须被逃避。

现在解决此问题的一种方法是将其作为文件转储到 shell 脚本中(并在开发过程中验证它是否适用于我们使用的 CMake 版本)。另一个应该是使用/bin/sh -c,但这提出了我如何传递那个长命令字符串的问题......

但是,这似乎很麻烦且多余,因为应该有一种方法可以实现我想要的。

注意:我在 Linux 上使用 CMake 3.12.2。


我应该补充一点,我尝试用COMMAND以下内容替换字符串,以测试我能够用/bin/sh -c.

COMMAND /bin/sh -c [[[ "${AWK}" '$1 ~ /^#define/ && $2 ~ /^LIB_(MAJVER|MINVER|PATCH|BUILD)$/\ { print "set(${PRJNAME}_" $2 " " $3 ")" }' "${CMAKE_SOURCE_DIR}/version.h" ]]]

结果是这个错误:

CMake Error at CMakeLists.txt:11:
  Syntax Error in cmake code at column 180

  Argument not separated from preceding token by whitespace.


-- Configuring incomplete, errors occurred!

标签: awkcmake

解决方案


Tsyvarev的评论帮助我弄清楚发生了什么(在这里转载,因为实际的评论可能会消失):

与双引号 ( ") 不同,单引号 ( ') 在 CMake 中没有特殊含义。这就是为什么它在'...'论点中将单词分开。在双引号字符串中,双引号可以用\".

所以我重写COMMAND如下:

cmake_minimum_required(VERSION 3.1)
set(PRJNAME foobar)

project (${PRJNAME})
find_program(AWK awk mawk gawk)

if(AWK MATCHES ".+-NOTFOUND")
    message(FATAL_ERROR "FATAL: awk (and mawk and gawk) could not be found (${AWK}).")
else()
    execute_process(
        COMMAND /bin/sh -c "\"${AWK}\" '$1 ~ /^#define/ && $2 ~ /^LIB_(MAJVER|MINVER|PATCH|BUILD)$/\ { print \"set(\${PRJNAME}_\" $2 \" \" $3 \")\" }' \"${CMAKE_SOURCE_DIR}/version.h\""
        RESULT_VARIABLE AWK_EXITCODE
        OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/version.cmake"
        )
    message(STATUS "Exit code from awk: ${AWK_EXITCODE}")
    include(${CMAKE_CURRENT_BINARY_DIR}/version.cmake)
endif()

要点是我将整个awk命令传递给/bin/sh -c,用双引号引用,并且嵌入在外部双引号内的任何引号都需要转义,就像$字符一样。


推荐阅读