awk - 从 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!
解决方案
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
,用双引号引用,并且嵌入在外部双引号内的任何引号都需要转义,就像$
字符一样。
推荐阅读
- react-native - 有没有一种方法可以使用 PHP 为每个特定用户显示 MySQL 表值,以便在反应本机应用程序中查看他们的个人资料?
- flutter - 如何使用计数器方法增加颤动中淡入淡出动画的时间?
- c++ - vector.reserve(10000000) 的缺点是因为我想保留原始内存位置?
- sql - sql 两个where子句从一个表变成两个新行
- sql - 之前和之后的 SQL 子字符串
- angular - 在Angular 10中使用ng测试进行测试时如何克服业力中的NullInjector错误
- python - 如何在熊猫数据框中输入列表作为列值?
- php - PayPal Smart Button 服务器端实现 - 捕获交易的问题 - PHP
- vue.js - 从组件 VueJS 获取数据
- python - 在 Python 中将损坏的数据作为一行获取