summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2018-03-12 13:10:57 (GMT)
committerBrad King <brad.king@kitware.com>2018-03-14 15:10:25 (GMT)
commitce0b9832163624291db04d38984c6aa7ea8ca7d7 (patch)
tree9e1bf0f74675e752b6582f2f239b953c1271521c
parentb340cacde869102b2b548b2e7ebc7341334f1d58 (diff)
downloadCMake-ce0b9832163624291db04d38984c6aa7ea8ca7d7.zip
CMake-ce0b9832163624291db04d38984c6aa7ea8ca7d7.tar.gz
CMake-ce0b9832163624291db04d38984c6aa7ea8ca7d7.tar.bz2
target_compile_options: Add syntax to specify shell strings
Options specified via `COMPILE_OPTIONS` and `INTERFACE_COMPILE_OPTIONS` are deduplicated, but individual options can legitimately be duplicated when grouped with other options, e.g. -D A -D B After deduplication that becomes `-D A B`. Therefore we need a way to treat groups of options as units during deduplication. A simple approach is to specify each group as one option, e.g. "-D A" "-D B" However, that conflicts with options that legitimately have spaces. To break this ambiguity, add a `SHELL:` prefix syntax to specify that an option should be parsed like shell command line arguments after deduplication, e.g. "SHELL:-D A" "SHELL:-D B" These will survive deduplication intact, and then be parsed to produce `-D A -D B` on the final command line. Fixes: #15826
-rw-r--r--Help/command/COMPILE_OPTIONS_SHELL.txt9
-rw-r--r--Help/command/add_compile_options.rst2
-rw-r--r--Help/command/target_compile_options.rst2
-rw-r--r--Help/release/dev/compile-options-shell.rst6
-rw-r--r--Source/cmGeneratorTarget.cxx22
-rw-r--r--Tests/CompileOptions/CMakeLists.txt12
-rw-r--r--Tests/CompileOptions/main.cpp25
7 files changed, 73 insertions, 5 deletions
diff --git a/Help/command/COMPILE_OPTIONS_SHELL.txt b/Help/command/COMPILE_OPTIONS_SHELL.txt
new file mode 100644
index 0000000..a1316c8
--- /dev/null
+++ b/Help/command/COMPILE_OPTIONS_SHELL.txt
@@ -0,0 +1,9 @@
+The final set of compile options used for a target is constructed by
+accumulating options from the current target and the usage requirements of
+it dependencies. The set of options is de-duplicated to avoid repetition.
+While beneficial for individual options, the de-duplication step can break
+up option groups. For example, ``-D A -D B`` becomes ``-D A B``. One may
+specify a group of options using shell-like quoting along with a ``SHELL:``
+prefix. The ``SHELL:`` prefix is dropped and the rest of the option string
+is parsed using the :command:`separate_arguments` ``UNIX_COMMAND`` mode.
+For example, ``"SHELL:-D A" "SHELL:-D B"`` becomes ``-D A -D B``.
diff --git a/Help/command/add_compile_options.rst b/Help/command/add_compile_options.rst
index 3fe2a33..44924e6 100644
--- a/Help/command/add_compile_options.rst
+++ b/Help/command/add_compile_options.rst
@@ -21,3 +21,5 @@ Arguments to ``add_compile_options`` may use "generator expressions" with
the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
manual for available expressions. See the :manual:`cmake-buildsystem(7)`
manual for more on defining buildsystem properties.
+
+.. include:: COMPILE_OPTIONS_SHELL.txt
diff --git a/Help/command/target_compile_options.rst b/Help/command/target_compile_options.rst
index 3e7dc47..b7b4dc1 100644
--- a/Help/command/target_compile_options.rst
+++ b/Help/command/target_compile_options.rst
@@ -38,3 +38,5 @@ Arguments to ``target_compile_options`` may use "generator expressions"
with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
manual for available expressions. See the :manual:`cmake-buildsystem(7)`
manual for more on defining buildsystem properties.
+
+.. include:: COMPILE_OPTIONS_SHELL.txt
diff --git a/Help/release/dev/compile-options-shell.rst b/Help/release/dev/compile-options-shell.rst
new file mode 100644
index 0000000..3f83e0c
--- /dev/null
+++ b/Help/release/dev/compile-options-shell.rst
@@ -0,0 +1,6 @@
+compile-options-shell
+---------------------
+
+* :command:`target_compile_options` and :command:`add_compile_options`
+ commands gained a ``SHELL:`` prefix to specify a group of related
+ options using shell-like quoting.
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 8cdba93..c3872c1 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -2622,13 +2622,20 @@ std::vector<std::string> cmGeneratorTarget::GetIncludeDirectories(
return includes;
}
+enum class OptionsParse
+{
+ None,
+ Shell
+};
+
static void processCompileOptionsInternal(
cmGeneratorTarget const* tgt,
const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
std::vector<std::string>& options,
std::unordered_set<std::string>& uniqueOptions,
cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
- bool debugOptions, const char* logName, std::string const& language)
+ bool debugOptions, const char* logName, std::string const& language,
+ OptionsParse parse)
{
for (cmGeneratorTarget::TargetPropertyEntry* entry : entries) {
std::vector<std::string> entryOptions;
@@ -2639,7 +2646,12 @@ static void processCompileOptionsInternal(
std::string usedOptions;
for (std::string const& opt : entryOptions) {
if (uniqueOptions.insert(opt).second) {
- options.push_back(opt);
+ if (parse == OptionsParse::Shell &&
+ cmHasLiteralPrefix(opt, "SHELL:")) {
+ cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, options);
+ } else {
+ options.push_back(opt);
+ }
if (debugOptions) {
usedOptions += " * " + opt + "\n";
}
@@ -2664,7 +2676,7 @@ static void processCompileOptions(
{
processCompileOptionsInternal(tgt, entries, options, uniqueOptions,
dagChecker, config, debugOptions, "options",
- language);
+ language, OptionsParse::Shell);
}
void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result,
@@ -2718,7 +2730,7 @@ static void processCompileFeatures(
{
processCompileOptionsInternal(tgt, entries, options, uniqueOptions,
dagChecker, config, debugOptions, "features",
- std::string());
+ std::string(), OptionsParse::None);
}
void cmGeneratorTarget::GetCompileFeatures(std::vector<std::string>& result,
@@ -2768,7 +2780,7 @@ static void processCompileDefinitions(
{
processCompileOptionsInternal(tgt, entries, options, uniqueOptions,
dagChecker, config, debugOptions,
- "definitions", language);
+ "definitions", language, OptionsParse::None);
}
void cmGeneratorTarget::GetCompileDefinitions(
diff --git a/Tests/CompileOptions/CMakeLists.txt b/Tests/CompileOptions/CMakeLists.txt
index 692e0de..c9f1710 100644
--- a/Tests/CompileOptions/CMakeLists.txt
+++ b/Tests/CompileOptions/CMakeLists.txt
@@ -18,9 +18,21 @@ set_property(TARGET CompileOptions PROPERTY COMPILE_OPTIONS
"-DTEST_DEFINE"
"-DNEEDS_ESCAPE=\"E$CAPE\""
"$<$<CXX_COMPILER_ID:GNU>:-DTEST_DEFINE_GNU>"
+ "SHELL:" # produces no options
${c_tests}
${cxx_tests}
)
+if(BORLAND OR WATCOM)
+ # these compilers do not support separate -D flags
+ target_compile_definitions(CompileOptions PRIVATE NO_DEF_TESTS)
+else()
+ set_property(TARGET CompileOptions APPEND PROPERTY COMPILE_OPTIONS
+ "SHELL:-D DEF_A"
+ "$<1:SHELL:-D DEF_B>"
+ "SHELL:-D 'DEF_C' -D \"DEF_D\""
+ [[SHELL:-D "DEF_STR=\"string with spaces\""]]
+ )
+endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|Borland|Embarcadero")
set_property(TARGET CompileOptions APPEND PROPERTY COMPILE_OPTIONS
diff --git a/Tests/CompileOptions/main.cpp b/Tests/CompileOptions/main.cpp
index 63a0480..4779b88 100644
--- a/Tests/CompileOptions/main.cpp
+++ b/Tests/CompileOptions/main.cpp
@@ -12,6 +12,28 @@
#endif
#endif
+#ifndef NO_DEF_TESTS
+#ifndef DEF_A
+#error Expected definition DEF_A
+#endif
+
+#ifndef DEF_B
+#error Expected definition DEF_B
+#endif
+
+#ifndef DEF_C
+#error Expected definition DEF_C
+#endif
+
+#ifndef DEF_D
+#error Expected definition DEF_D
+#endif
+
+#ifndef DEF_STR
+#error Expected definition DEF_STR
+#endif
+#endif
+
#include <string.h>
int main()
@@ -20,6 +42,9 @@ int main()
#ifdef TEST_OCTOTHORPE
&& strcmp(TEST_OCTOTHORPE, "#") == 0
#endif
+#ifndef NO_DEF_TESTS
+ && strcmp(DEF_STR, "string with spaces") == 0
+#endif
&&
strcmp(EXPECTED_C_COMPILER_VERSION, TEST_C_COMPILER_VERSION) == 0 &&
strcmp(EXPECTED_CXX_COMPILER_VERSION, TEST_CXX_COMPILER_VERSION) ==