在shell脚本中传递CMAKE_CXX_FLAGS

3

我遇到了一个关于bash和cmake以及引号的繁琐问题。 我需要使用不同的cmake标志多次编译程序。经过很多猜测,我在bash脚本中想出了以下结构:

cmake_params[1]=-DCMAKE_CXX_FLAGS=-O2\ -DNDEBUG
cmake_params[2]=-DCMAKE_CXX_FLAGS=-march=native\ -O2\ -DNDEBUG
# ....

#compile with:

for i in {1..n}
do
    # .. prepare ..
    mkdir build
    cd build
    cmake "${cmake_params[$i]}" ..
    make
done

请注意,我在cmake_params中转义了空格,并使用双引号调用了cmake。但是,最终,我需要能够将标志扩展到像这样糟糕的东西:
cmake_params[1]=-DCMAKE_CXX_COMPILER="clang++"\
  -DCMAKE_C_COMPILER="clang"\
  -DCMAKE_CXX_FLAGS=-march=native\ -O3\ -DNDEBUG\
  -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=true\
  -DCMAKE_POLICY_DEFAULT_CMP0069=NEW

但那样行不通。我尝试在CXX标志周围加上引号,省略编译器周围的引号以及省略实际cmake调用周围的引号,但都没有成功。错误消息各不相同,其中最突出的一个是:

The CMAKE_CXX_COMPILER:

clang++ -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_FLAGS=-march=native -O3 -DNDEBUG
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=true -DCMAKE_POLICY_DEFAULT_CMP0069=NEW

is not a full path and was not found in the PATH.

很明显,CMake错误解释了我的命令行。为了更加清晰,我想要将clang++作为CMAKE_CXX_COMPILER传递,并将-march=native -O3 -DNDEBUG作为CMAKE_CXX_FLAGS传递。

哪个bash脚本可以实现这一点,原因是什么?是否有关于引号和参数传递的资源?我尝试了一个又一个方法来找到可行的方案,但那甚至都不是瞎猜..


你有没有运气成功了? - Slava
2个回答

1

When you write (in bash):

cmake "${cmake_params[$i]}"

你正在请求它调用命令行实用程序cmake,将该实用程序传递给一个单一参数,该参数是cmake_params数组的指定元素的值。像任何其他命令行实用程序一样,cmake不会尝试重新解释接收到的参数;它假定您已经安排好了正确的参数传递方式。因此,当它接收到一个单一参数,其中包含以下内容时:
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_FLAGS=-march=native -O3 -DNDEBUG -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=true -DCMAKE_POLICY_DEFAULT_CMP0069=NEW

程序随后会将其内部变量CMAKE_C_COMPILER(等号前的id)的值设置为clang -DCMAKE_CXX_FLAGS=-march=native -O3 -DNDEBUG -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=true -DCMAKE_POLICY_DEFAULT_CMP0069=NEW

cmake接下来尝试通过在路径中搜索文件名clang -DCMAKE_CXX_FLAGS=-march=native -O3 -DNDEBUG -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=true -DCMAKE_POLICY_DEFAULT_CMP0069=NEW来查找编译器。显然,它没有找到该文件。

如果事情不是这样处理的话,在文件路径中有空格的地方使用文件名参数将变得非常困难。

如果这对您不重要,您可以采用非常简单的解决方案:像这样调用cmake

cmake ${cmake_params[$i]}

那告诉shell获取数组cmake_params的指定元素的值,然后(因为它没有引号)对该值执行单词拆分和路径名扩展,从而得到一系列参数,然后将这些参数逐个传递给cmake
在您提供的示例中,这应该可以正常工作。但它是脆弱甚至危险的。首先,因为将执行路径名扩展,所以值中的*可能会变成当前目录中所有文件的完整列表。其次,因为使用变量$IFS的值进行单词拆分,这个值可能已经被更改。最后,请注意,shell不解释扩展值内的引号(包括反斜杠)或参数扩展,因此无法标记某些空格使其免于单词拆分。这意味着您将无法使用带有空格的文件名或文件路径。
在现代bash版本中,您可以使用nameref实现更精确的解决方案。nameref是使用-n标志声明的变量,其名称为另一个变量的名称。您无法创建nameref数组,但nameref可以引用数组。
有了这个想法,我们可以重写您的初始想法:
# Each param set has its own array variable. There is no need to use
# integer suffixes; you could use more descriptive tags. Just make sure
# that there is no other variable whose name starts with the same prefix.
# Since we are creating arrays, we do *not* quote whitespace *unless*
# it is really part of a parameter value.
declare -a cmake_params_1=(-DCMAKE_CXX_FLAGS=-O2 -DNDEBUG)
declare -a cmake_params_2=(-DCMAKE_CXX_FLAGS=-march=native -O2 -DNDEBUG)
# ....

# Now we can loop through the various arrays of parameter lists: 

# ${!word*} expands to a list of existing variables whose names start with  word   
for name in "${!cmake_params_*}"; do
    # Create a nameref for the array whose name we got from the list
    declare -n array=$name
    # .. prepare ..
    mkdir build
    cd build
    # Here we can use "array" as though it were the variable named in the argument
    cmake "${array[@]}" ..
    make
done

抱歉回复晚了,感谢你对那个主题进行了一些解释!我尝试了两种方式,但仍然无法使其工作。当我使用第一个想法 cmake ${cmake_params[$i]} 时,CMAKE_CXX_FLAGS 没有正确设置。 我会收到错误 Parse error in command line argument: -DNDEBUG - 我认为这意味着 -DNDEBUG 直接传递给了 cmake,而不是作为 CMAKE_CXX_FLAGS 的一部分。使用引号将 CMAKE_CXX_FLAGS 包围起来,例如 -DCMAKE_CXX_FLAGS="-march=native -DNDEBUG -O3" 并没有帮助。如果我使用 nameref 的想法,则根据 ccmake 的输出,未传递标志... - Max Beikirch
这有点奇怪,因为当我在它们上面使用echo命令时,标志确实存在。我的bash似乎相当老,我的版本(4.2.26)不知道declare命令的-n标志。 - Max Beikirch

0

以下方法对我有效:

CMAKE_OPTS="-DBUILD_TESTING=OFF"
CMAKE_DEFAULTS="-GNinja \
                -DCMAKE_BUILD_TYPE=Release \
                \"-DCMAKE_CXX_FLAGS_RELEASE:STRING=-Wformat -Werror=format-security -DNDEBUG -Ofast -march=native -flto -mtune=native\" \
                -DCMAKE_PREFIX_PATH=${INSTALL_PREFIX} \
                -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} \
"

curl -L -o source.tar.gz ${SRC_URL}
tar -xzf source.tar.gz

rm -rf build_ && mkdir build_ && cd build_
eval "cmake ${CMAKE_DEFAULTS} ${CMAKE_OPTS} ${SRC_PATH}"
cmake --build . --target install

基本上,这个问题是将整个-DCMAKE_CXX_FLAGS_RELEASE\"\"包装起来,然后调用eval(不纯!我知道我知道...)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接