CMakeMacroParseArguments: Difference between revisions

From KitwarePublic
Jump to navigationJump to search
(add obsolete mark)
(Add explicit preformat markup)
Line 123: Line 123:
Here is a somewhat more realistic usage of <tt>PARSE_ARGUMENTS</tt>.  Let us say that we are creating an application that accepts plugins with components, and we need a CMake macro that makes it easy to compile and link a plugin.  The plugin will have some code in it, and it will have to have some sort of factory built in that allows the introspection and creation of components in the plugin.  We also may want to embed some scripts in the plugin.  The plugin may depend on other libraries and plugins.  Finally, we may have some options to determine how the plugin may be compiled or used.  We will create a macro command that can be called as follows.
Here is a somewhat more realistic usage of <tt>PARSE_ARGUMENTS</tt>.  Let us say that we are creating an application that accepts plugins with components, and we need a CMake macro that makes it easy to compile and link a plugin.  The plugin will have some code in it, and it will have to have some sort of factory built in that allows the introspection and creation of components in the plugin.  We also may want to embed some scripts in the plugin.  The plugin may depend on other libraries and plugins.  Finally, we may have some options to determine how the plugin may be compiled or used.  We will create a macro command that can be called as follows.


<pre>
  ADD_PLUGIN(name [AUTO_INSTALL] [NO_MODULE] source1 source2 ...
  ADD_PLUGIN(name [AUTO_INSTALL] [NO_MODULE] source1 source2 ...
   EXPORTS object1 object2 ...
   EXPORTS object1 object2 ...
Line 129: Line 130:
   [DEPENDS plugin1 plugin2 ...]
   [DEPENDS plugin1 plugin2 ...]
   )
   )
</pre>


Although the argument usage is easy for a user to understand (especially one familiar with using other CMake commands), but it can be a hassle for a macro to parse.  Of course, <tt>PARSE_ARGUMENTS</tt> will do it for us.
Although the argument usage is easy for a user to understand (especially one familiar with using other CMake commands), but it can be a hassle for a macro to parse.  Of course, <tt>PARSE_ARGUMENTS</tt> will do it for us.

Revision as of 18:04, 20 April 2018

Back

CAUTION: The contents of this page may be obsolete
120px-Old finnish stop sign.svg.png

Definition

There is a general convention for CMake commands that take optional flags and/or variable arguments. Optional flags are all caps and are added to the arguments to turn on. Variable arguments have an all caps identifier to determine where each variable argument list starts.

If you are using CMake 2.8.3 or newer please use the CMakeParseArguments macro provided by the default CMake installation instead of the code below.

The PARSE_ARGUMENTS macro, defined below, can be used by other macros to parse arguments defined in this way. Note that this macro relies on the LIST_CONTAINS command.

MACRO(PARSE_ARGUMENTS prefix arg_names option_names)
  SET(DEFAULT_ARGS)
  FOREACH(arg_name ${arg_names})
    SET(${prefix}_${arg_name})
  ENDFOREACH(arg_name)
  FOREACH(option ${option_names})
    SET(${prefix}_${option} FALSE)
  ENDFOREACH(option)

  SET(current_arg_name DEFAULT_ARGS)
  SET(current_arg_list)
  FOREACH(arg ${ARGN})
    LIST_CONTAINS(is_arg_name ${arg} ${arg_names})
    IF (is_arg_name)
      SET(${prefix}_${current_arg_name} ${current_arg_list})
      SET(current_arg_name ${arg})
      SET(current_arg_list)
    ELSE (is_arg_name)
      LIST_CONTAINS(is_option ${arg} ${option_names})
      IF (is_option)
	SET(${prefix}_${arg} TRUE)
      ELSE (is_option)
	SET(current_arg_list ${current_arg_list} ${arg})
      ENDIF (is_option)
    ENDIF (is_arg_name)
  ENDFOREACH(arg)
  SET(${prefix}_${current_arg_name} ${current_arg_list})
ENDMACRO(PARSE_ARGUMENTS)

If you are using CMake version greater than 2.4.7 you may use the following version which use LIST builtin command FIND which may be more efficient:

MACRO(PARSE_ARGUMENTS prefix arg_names option_names)
  SET(DEFAULT_ARGS)
  FOREACH(arg_name ${arg_names})    
    SET(${prefix}_${arg_name})
  ENDFOREACH(arg_name)
  FOREACH(option ${option_names})
    SET(${prefix}_${option} FALSE)
  ENDFOREACH(option)

  SET(current_arg_name DEFAULT_ARGS)
  SET(current_arg_list)
  FOREACH(arg ${ARGN})            
    SET(larg_names ${arg_names})    
    LIST(FIND larg_names "${arg}" is_arg_name)                   
    IF (is_arg_name GREATER -1)
      SET(${prefix}_${current_arg_name} ${current_arg_list})
      SET(current_arg_name ${arg})
      SET(current_arg_list)
    ELSE (is_arg_name GREATER -1)
      SET(loption_names ${option_names})    
      LIST(FIND loption_names "${arg}" is_option)            
      IF (is_option GREATER -1)
	     SET(${prefix}_${arg} TRUE)
      ELSE (is_option GREATER -1)
	     SET(current_arg_list ${current_arg_list} ${arg})
      ENDIF (is_option GREATER -1)
    ENDIF (is_arg_name GREATER -1)
  ENDFOREACH(arg)
  SET(${prefix}_${current_arg_name} ${current_arg_list})
ENDMACRO(PARSE_ARGUMENTS)

Usage

The PARSE_ARGUMENTS macro will take the arguments of another macro and define several variables. The first argument to PARSE_ARGUMENTS is a prefix to put on all variables it creates. The second argument is a list of names, and the third argument is a list of options. Both of these lists should be quoted. The rest of PARSE_ARGUMENTS are arguments from another macro to be parsed.

PARSE_ARGUMENTS(prefix arg_names options arg1 arg2...)

For each item in options, PARSE_ARGUMENTS will create a variable with that name, prefixed with prefix_. So, for example, if prefix is MY_MACRO and options is OPTION1;OPTION2, then PARSE_ARGUMENTS will create the variables MY_MACRO_OPTION1 and MY_MACRO_OPTION2. These variables will be set to true if the option exists in the command line or false otherwise.

For each item in arg_names, PARSE_ARGUMENTS will create a variable with that name, prefixed with prefix_. Each variable will be filled with the arguments that occur after the given arg_name is encountered up to the next arg_name or the end of the arguments. All options are removed from these lists. PARSE_ARGUMENTS also creates a prefix_DEFAULT_ARGS variable containing the list of all arguments up to the first arg_name encountered.

Here is a simple, albeit impractical, example of using PARSE_ARGUMENTS that demonstrates its behavior.

SET(arguments
  hello OPTION3 world
  LIST3 foo bar
  OPTION2
  LIST1 fuz baz
  )
PARSE_ARGUMENTS(ARG "LIST1;LIST2;LIST3" "OPTION1;OPTION2;OPTION3" ${arguments})

PARSE_ARGUMENTS creates 7 variables and sets them as follows:

  • ARG_DEFAULT_ARGS: hello;world
  • ARG_LIST1: fuz;baz
  • ARG_LIST2:
  • ARG_LIST3: foo;bar
  • ARG_OPTION1: FALSE
  • ARG_OPTION2: TRUE
  • ARG_OPTION3: TRUE

If you don't have any options, use an empty string in its place.

PARSE_ARGUMENTS(ARG "LIST1;LIST2;LIST3" "" ${arguments})

Likewise if you have no lists.

PARSE_ARGUMENTS(ARG "" "OPTION1;OPTION2;OPTION3" ${arguments})

Example

Here is a somewhat more realistic usage of PARSE_ARGUMENTS. Let us say that we are creating an application that accepts plugins with components, and we need a CMake macro that makes it easy to compile and link a plugin. The plugin will have some code in it, and it will have to have some sort of factory built in that allows the introspection and creation of components in the plugin. We also may want to embed some scripts in the plugin. The plugin may depend on other libraries and plugins. Finally, we may have some options to determine how the plugin may be compiled or used. We will create a macro command that can be called as follows.

 ADD_PLUGIN(name [AUTO_INSTALL] [NO_MODULE] source1 source2 ...
   EXPORTS object1 object2 ...
   [AUTOLOAD_SCRIPTS script1 script2 ...]
   [LINK_LIBRARIES lib1 lib2 ...]
   [DEPENDS plugin1 plugin2 ...]
   )

Although the argument usage is easy for a user to understand (especially one familiar with using other CMake commands), but it can be a hassle for a macro to parse. Of course, PARSE_ARGUMENTS will do it for us.

Here is a vacuous implementation of ADD_PLUGIN. It uses PARSE_ARGUMENTS to parse the argument specification above, and then simply prints out each argument list and option. Note that this example uses the CAR and CDR macros.

MACRO(ADD_PLUGIN)
  PARSE_ARGUMENTS(PLUGIN
    "EXPORTS;AUTOLOAD_SCRIPTS;LINK_LIBRARIES;DEPENDS"
    "AUTO_INSTALL;NO_MODULE"
    ${ARGN}
    )
  CAR(PLUGIN_NAME ${PLUGIN_DEFAULT_ARGS})
  CDR(PLUGIN_SOURCES ${PLUGIN_DEFAULT_ARGS})

  MESSAGE("*** Arguments for ${PLUGIN_NAME}")
  MESSAGE("Sources: ${PLUGIN_SOURCES}")
  MESSAGE("Exports: ${PLUGIN_EXPORTS}")
  MESSAGE("Autoload scripts: ${PLUGIN_AUTOLOAD_SCRIPTS}")
  MESSAGE("Link libraries: ${PLUGIN_LINK_LIBRARIES}")
  MESSAGE("Depends: ${PLUGIN_DEPENDS}")
  IF (PLUGIN_AUTO_INSTALL)
    MESSAGE("Auto install")
  ENDIF (PLUGIN_AUTO_INSTALL)
  IF (PLUGIN_NO_MODULE)
    MESSAGE("No module")
  ENDIF (PLUGIN_NO_MODULE)
ENDMACRO(ADD_PLUGIN)

Here are some examples of using this macro so you can see how PARSE_ARGUMENTS breaks up the arguments.

Input Output
ADD_PLUGIN(MyAppCore NO_MODULE
  CoreSource1.cxx CoreSource2.cxx
  EXPORTS RequiredObject1 RequredObject2
  AUTOLOAD_SCRIPTS startup.py initialize.py
  )
*** Arguments for MyAppCore
Sources: CoreSource1.cxx;CoreSource2.cxx
Exports: RequiredObject1;RequredObject2
Autoload scripts: startup.py;initialize.py
Link libraries: 
Depends: 
No module
ADD_PLUGIN(MyAppDefaultComponents
  Component1.cxx Component2.cxx
  EXPORTS Component1 Component2
  DEPENDS MyAppCore
  AUTO_INSTALL
  )
*** Arguments for MyAppDefaultComponents
Sources: Component1.cxx;Component2.cxx
Exports: Component1;Component2
Autoload scripts: 
Link libraries: 
Depends: MyAppCore
Auto install
ADD_PLUGIN(PartialDiffEqu
  Solver.cxx
  DEPENDS MyAppCore MyAppDefaultComponents
  LINK_LIBRARIES NumericalAnalysisPackage
  EXPORTS SolverObject
  )
*** Arguments for PartialDiffEqu
Sources: Solver.cxx
Exports: SolverObject
Autoload scripts: 
Link libraries: NumericalAnalysisPackage
Depends: MyAppCore;MyAppDefaultComponents



Back



CMake: [Welcome | Site Map]