Skip to content

Add a means of finishing command line arguments processing

When invoking cmake in script mode, it often helps to be able to pass arbitrary arguments after the script name, so that the script could emulate some other command that doesn't have a cmake-compatible argument syntax. E.g. suppose that a cmake script was a wrapper for a compiler, then it might be invoked as

cmake -P myscript.cmake -Iinclude -Ddefine -Wall -o foo.o -c foo.c

Right now, cmake will run the list file (e.g. a script) as soon as it has read its name, and the list file will see all the command line arguments in CMAKE_ARGVn variables - whether they are allowed by cmake or not. So far so good. But as soon as the list file is done, cmake will resume processing the arguments - and will bail out with a fatal error, since those arguments are not proper cmake arguments.

I propose the following solutions, and will implement the desired one ASAP as I need this functionality myself:

  1. Support the rather common -- switch to mean: Ignore any further arguments. Those arguments are available to the script (in any mode), but the argument processing stops immediately. The above command line would then become:

     cmake -P myscript.cmake -- -Iinclude -Ddefine -Wall -o foo.o -c foo.c

    The script could then easily detect where it should start parsing arguments:

     set(arg_n 0)
     function(next_arg) ...
    
     next_arg()
     while(NOT arg STREQUAL "--")
       next_arg()
     endwhile()

    cmake::SetCacheArgs and cmake::SetArgs would be modified as follows:

     void cmake::SetArgs(const std::vector<std::string>& args)
     {
        ...
        for (unsigned int i = 1; i < args.size(); ++i) {
          std::string const& arg = args[i];
          if (arg == "--") break;
          ...
    
     bool cmake::SetCacheArgs(const std::vector<std::string>& args)
     {
       ...
       for (unsigned int i = 1; i < args.size(); ++i) {
         std::string const& arg = args[i];
         if (arg == "--") break;
         ...

    Does this introduce any backwards-compatibility concerns? The argument would be naturally ignored in the sub-argument parsing, i.e. if -foo takes an option, -foo -- would work as it used to, without assigning any meaning to --. The only way I see it being problematic would be if someone had a build script named --. Perhaps we could name this switch ---- to avoid any ambiguity.

  2. Allow the scripts to modify the CMAKE_ARGN and CMAKE_ARGVn, with a policy that enables the changes to be fed back to the command argument processor in older cmake versions. This makes it backwards-compatible. It'd be the most intrusive change, as it'd have to modify the SetArgs and SetCacheArgs flow. Obviously, only the changes to arguments past the argument that triggered the execution of a given list file would be taken into account. Setting ARGN to a value smaller or equal than the argument that triggered the execution of the list file will automatically finish processing the argument list. CMAKE_ARGP variable would be used to indicate the index of the argument that triggered the execution of the current list file. Its modification would be a developer warning, since it'd make no sense to move the "current argument" pointer.

  3. Expand the return() command to include optional argument FINISH, allowed in any mode at topmost scope, i.e. wherever a return() would finish processing the outermost list file. When present, no further command line arguments are processed. This has the problem that the arguments would still be processed by SetArgs and could have unintended side effects. A developer warning is issued if return(FINISH) is used in the wrong scope. cmReturnCommand would set a flag in the current state that would then interrupt SetCacheArgs.

If anyone has better ideas, I'd love to hear them and again: I'd like to implement it right away, so as not to waste anyone's time.

Edited by Ghost User
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information