Quellcode durchsuchen

Merge topic 'parse_arguments_argv_n'

cb299acc cmake_parse_arguments: Add option to read arguments from ARGC/ARGV#
Brad King vor 9 Jahren
Ursprung
Commit
c40cbccf7d

+ 11 - 0
Help/command/cmake_parse_arguments.rst

@@ -11,6 +11,17 @@ respective options.
   cmake_parse_arguments(<prefix> <options> <one_value_keywords>
                         <multi_value_keywords> args...)
 
+  cmake_parse_arguments(PARSE_ARGV N <prefix> <options> <one_value_keywords>
+                        <multi_value_keywords>)
+
+The first signature reads processes arguments passed in the ``args...``.
+This may be used in either a :command:`macro` or a :command:`function`.
+
+The ``PARSE_ARGV`` signature is only for use in a :command:`function`
+body.  In this case the arguments that are parsed come from the
+``ARGV#`` variables of the calling function.  The parsing starts with
+the Nth argument, where ``N`` is an unsigned integer.  This allows for
+the values to have special characters like ``;`` in them.
 
 The ``<options>`` argument contains all options for the respective macro,
 i.e.  keywords which can be used when calling the macro without any value

+ 6 - 0
Help/release/dev/parse_arguments_argv_n.rst

@@ -0,0 +1,6 @@
+parse_arguments_argv_n
+----------------------
+
+* The :command:`cmake_parse_arguments` command gained a new
+  mode to read arguments directly from ``ARGC`` and ``ARGV#``
+  variables inside a :command:`function` body.

+ 53 - 4
Source/cmParseArgumentsCommand.cxx

@@ -20,6 +20,8 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
 {
   // cmake_parse_arguments(prefix options single multi <ARGN>)
   //                         1       2      3      4
+  // or
+  // cmake_parse_arguments(PARSE_ARGV N prefix options single multi)
   if (args.size() < 4) {
     this->SetError("must be called with at least 4 arguments.");
     return false;
@@ -27,6 +29,27 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
 
   std::vector<std::string>::const_iterator argIter = args.begin(),
                                            argEnd = args.end();
+  bool parseFromArgV = false;
+  unsigned long argvStart = 0;
+  if (*argIter == "PARSE_ARGV") {
+    if (args.size() != 6) {
+      this->Makefile->IssueMessage(
+        cmake::FATAL_ERROR,
+        "PARSE_ARGV must be called with exactly 6 arguments.");
+      cmSystemTools::SetFatalErrorOccured();
+      return true;
+    }
+    parseFromArgV = true;
+    argIter++; // move past PARSE_ARGV
+    if (!cmSystemTools::StringToULong(argIter->c_str(), &argvStart)) {
+      this->Makefile->IssueMessage(cmake::FATAL_ERROR, "PARSE_ARGV index '" +
+                                     *argIter +
+                                     "' is not an unsigned integer");
+      cmSystemTools::SetFatalErrorOccured();
+      return true;
+    }
+    argIter++; // move past N
+  }
   // the first argument is the prefix
   const std::string prefix = (*argIter++) + "_";
 
@@ -90,11 +113,37 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
   } insideValues = NONE;
   std::string currentArgName;
 
-  // Flatten ;-lists in the arguments into a single list as was done
-  // by the original function(CMAKE_PARSE_ARGUMENTS).
   list.clear();
-  for (; argIter != argEnd; ++argIter) {
-    cmSystemTools::ExpandListArgument(*argIter, list);
+  if (!parseFromArgV) {
+    // Flatten ;-lists in the arguments into a single list as was done
+    // by the original function(CMAKE_PARSE_ARGUMENTS).
+    for (; argIter != argEnd; ++argIter) {
+      cmSystemTools::ExpandListArgument(*argIter, list);
+    }
+  } else {
+    // in the PARSE_ARGV move read the arguments from ARGC and ARGV#
+    std::string argc = this->Makefile->GetSafeDefinition("ARGC");
+    unsigned long count;
+    if (!cmSystemTools::StringToULong(argc.c_str(), &count)) {
+      this->Makefile->IssueMessage(cmake::FATAL_ERROR,
+                                   "PARSE_ARGV called with ARGC='" + argc +
+                                     "' that is not an unsigned integer");
+      cmSystemTools::SetFatalErrorOccured();
+      return true;
+    }
+    for (unsigned long i = argvStart; i < count; ++i) {
+      std::ostringstream argName;
+      argName << "ARGV" << i;
+      const char* arg = this->Makefile->GetDefinition(argName.str());
+      if (!arg) {
+        this->Makefile->IssueMessage(cmake::FATAL_ERROR,
+                                     "PARSE_ARGV called with " +
+                                       argName.str() + " not set");
+        cmSystemTools::SetFatalErrorOccured();
+        return true;
+      }
+      list.push_back(arg);
+    }
   }
 
   // iterate over the arguments list and fill in the values where applicable

+ 30 - 0
Tests/RunCMake/cmake_parse_arguments/ArgvN.cmake

@@ -0,0 +1,30 @@
+include(${CMAKE_CURRENT_LIST_DIR}/test_utils.cmake)
+
+function(test1)
+  cmake_parse_arguments(PARSE_ARGV 0
+    pref "OPT1;OPT2" "SINGLE1;SINGLE2" "MULTI1;MULTI2")
+
+  TEST(pref_OPT1 TRUE)
+  TEST(pref_OPT2 FALSE)
+  TEST(pref_SINGLE1 "foo;bar")
+  TEST(pref_SINGLE2 UNDEFINED)
+  TEST(pref_MULTI1 bar foo bar)
+  TEST(pref_MULTI2 UNDEFINED)
+  TEST(pref_UNPARSED_ARGUMENTS UNDEFINED)
+endfunction()
+test1(OPT1 SINGLE1 "foo;bar" MULTI1 bar foo bar)
+
+function(test2 arg1)
+  cmake_parse_arguments(PARSE_ARGV 1
+    pref "OPT1;OPT2" "SINGLE1;SINGLE2" "MULTI1;MULTI2")
+
+  TEST(arg1 "first named")
+  TEST(pref_OPT1 TRUE)
+  TEST(pref_OPT2 FALSE)
+  TEST(pref_SINGLE1 "foo;bar")
+  TEST(pref_SINGLE2 UNDEFINED)
+  TEST(pref_MULTI1 bar foo bar)
+  TEST(pref_MULTI2 UNDEFINED)
+  TEST(pref_UNPARSED_ARGUMENTS UNDEFINED)
+endfunction()
+test2("first named" OPT1 SINGLE1 "foo;bar" MULTI1 bar foo bar)

+ 1 - 0
Tests/RunCMake/cmake_parse_arguments/BadArgvN1-result.txt

@@ -0,0 +1 @@
+1

+ 5 - 0
Tests/RunCMake/cmake_parse_arguments/BadArgvN1-stderr.txt

@@ -0,0 +1,5 @@
+^CMake Error at BadArgvN1.cmake:[0-9]+ \(cmake_parse_arguments\):
+  PARSE_ARGV must be called with exactly 6 arguments.
+Call Stack \(most recent call first\):
+  BadArgvN1.cmake:[0-9]+ \(test1\)
+  CMakeLists.txt:[0-9]+ \(include\)$

+ 4 - 0
Tests/RunCMake/cmake_parse_arguments/BadArgvN1.cmake

@@ -0,0 +1,4 @@
+function(test1)
+  cmake_parse_arguments(PARSE_ARGV 0 pref "" "" "" extra)
+endfunction()
+test1()

+ 1 - 0
Tests/RunCMake/cmake_parse_arguments/BadArgvN2-result.txt

@@ -0,0 +1 @@
+1

+ 5 - 0
Tests/RunCMake/cmake_parse_arguments/BadArgvN2-stderr.txt

@@ -0,0 +1,5 @@
+^CMake Error at BadArgvN2.cmake:[0-9]+ \(cmake_parse_arguments\):
+  PARSE_ARGV index 'pref' is not an unsigned integer
+Call Stack \(most recent call first\):
+  BadArgvN2.cmake:[0-9]+ \(test2\)
+  CMakeLists.txt:[0-9]+ \(include\)$

+ 4 - 0
Tests/RunCMake/cmake_parse_arguments/BadArgvN2.cmake

@@ -0,0 +1,4 @@
+function(test2)
+  cmake_parse_arguments(PARSE_ARGV pref "" "" "" extra)
+endfunction()
+test2()

+ 1 - 0
Tests/RunCMake/cmake_parse_arguments/BadArgvN3-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
Tests/RunCMake/cmake_parse_arguments/BadArgvN3-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Error at BadArgvN3.cmake:[0-9]+ \(cmake_parse_arguments\):
+  PARSE_ARGV called with ARGC='' that is not an unsigned integer
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)$

+ 1 - 0
Tests/RunCMake/cmake_parse_arguments/BadArgvN3.cmake

@@ -0,0 +1 @@
+cmake_parse_arguments(PARSE_ARGV 0 pref "" "" "")

+ 1 - 0
Tests/RunCMake/cmake_parse_arguments/BadArgvN4-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
Tests/RunCMake/cmake_parse_arguments/BadArgvN4-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Error at BadArgvN4.cmake:[0-9]+ \(cmake_parse_arguments\):
+  PARSE_ARGV called with ARGV0 not set
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)$

+ 3 - 0
Tests/RunCMake/cmake_parse_arguments/BadArgvN4.cmake

@@ -0,0 +1,3 @@
+set(ARGC 1)
+cmake_parse_arguments(PARSE_ARGV 0 pref "" "" "")
+unset(ARGC)

+ 5 - 0
Tests/RunCMake/cmake_parse_arguments/RunCMakeTest.cmake

@@ -5,3 +5,8 @@ run_cmake(Initialization)
 run_cmake(Mix)
 run_cmake(CornerCases)
 run_cmake(Errors)
+run_cmake(ArgvN)
+run_cmake(BadArgvN1)
+run_cmake(BadArgvN2)
+run_cmake(BadArgvN3)
+run_cmake(BadArgvN4)