Recently, when migrating the company's make system to cmake, we found that the function parameter of cmake is very strange. For example, if we pass a list as a parameter to a function, the form parameter in the function will become the following:
set(SRC)list(APPEND SRC a.cpp b.cpp)list(APPEND SRC c.cpp d.cpp)function(tst_arguments src_list)message("src_list = "${src_list})endfunction()message("SRC = "${SRC})<pre name="code" class="plain">tst_arguments(${SRC})==== output ====SRC = a.cppb.cppc.cppd.cppsrc_list = a.cpp
It is strange that $ {SRC} here is a complete 4 elements outside function, in function, only the first element is left (probably related to the fixed length of list ). If we want to pass the function to a list consisting of N source files, this obviously won't work.
A simple solution is to use argv and argc in combination. Their meanings are as follows: Main's argv and argc in C/C ++, representing the number of parameters and the number of parameters respectively, parse parameters using the following method:
function(tst_arguments src_list)message("ARGC = "${ARGC})message("ARGV = "${ARGV}) set(INDEX 0) while(INDEX LESS ${ARGC})message("ARG = "${ARGV${INDEX}})math(EXPR INDEX "${INDEX} + 1")endwhile()endfunction()<pre name="code" class="plain"><pre name="code" class="plain">tst_arguments(${SRC})
<pre name="code" class="plain">==== output ====ARGC = 4ARGV = a.cppb.cppc.cppd.cpp
Arg = A. cpparg = B. cpparg = C. cpparg = D. cpp
Of course, you can also use the foreach loop traversal parameter of cmake. This method is very effective when there is only one list parameter, but multiple parameters appear, as follows:
# Assume that the function link_lib links the source files in the src_list to a library and determines whether the library is a static library or a dynamic library based on the type. # function (link_lib src_list type) <PRE name = "code" class = "plain"> message ("argc =" $ {argc}) message ("argv =" $ {argv })
# The following operations are performed based on the actual conditions of the parameters to ensure that src_list and typeset (index 0) math (expr Max "$ {argc}-1") are obtained correctly ") while (index less $ {max}) # Do Something To linkmath (expr Index "$ {index} + 1") endwhile () endfunction ()
link_lib(${SRC} , so)<pre name="code" class="plain"><pre name="code" class="plain"><pre name="code" class="plain">==== output ====
Argc = 5
Argv = A. cppb. cppc. CPPD. cppso
Originally, Arg mixed the two parameters. Although we used while for special processing later, it was not universal for the cmake function and it was very troublesome to transplant it.
The final version of Solution uses cmake's cmake_parse_arguments to parse function parameters. It is a bit like parsing a map key-value pair. First, let's look at its function prototype:
Include (cmakeparsearguments) # <SPAN class = "highlighted"> cmake_parse_arguments </span> values (<prefix> <Options> <one_value_keywords> <multi_value_keywords> ARGs...) must contain this cmake file ...)
First, prefix is a prefix, which will be mentioned later when you reference the parameter. <option> is a list that contains some keyword you are interested in, then you can use it to check whether the keyword you need is set. <One_value_keywords> is a single-value parameter keyword list. <Multi_value_keywords> is a multi-value parameter keyword list (such as list). The following example shows how to use them. First, define the required functions, because the parameters are parsed by cmake_parse_arguments, you do not need to define the parameters in the function declaration:
function(tst_arguments) CMAKE_PARSE_ARGUMENTS( TEST "" "NAME;COMMAND;BASELINE" "ARGSLIST" ${ARGN} ) message("TEST_DEFAULT_ARGS is ${TEST_DEFAULT_ARGS} from ${ARGN}") message("TEST_NAME is ${TEST_NAME}") message("TEST_COMMAND is ${TEST_COMMAND}") message("TEST_ARGSLIST is ${TEST_ARGSLIST}") message("TEST_BASELINE is ${TEST_BASELINE}")endfunction(tst_arguments)
The prefix here is test. <one_value_keywords> we set the keyword (name; command; baseline) of the single-value parameter. This will indicate the relationship between keyword and value in subsequent function calls, <multi_value_keywords> we set the keyword ("argslist") of the multi-value parameter and call the function:
TEST_ARGUMENT( NAME testiso COMMAND "RunMe" ARGSLIST ${SRC} BASELINE "/home/sakaue/iWork")==== output ====TEST_DEFAULT_ARGS is from NAME;testiso;COMMAND;RunMe;ARGSLIST;a.cpp;b.cpp;c.cpp;d.cpp;BASELINE;/home/sakaue/iWorkTEST_NAME is testisoTEST_COMMAND is RunMeTEST_ARGSLIST is a.cpp;b.cpp;c.cpp;d.cppTEST_BASELINE is /home/sakaue/iWork
As you can see, the parameter transfer here is the same as Map <name, testiso _ $ {datafile} >,< command, "runme" >,< argslist, $ {SRC}>. In the function, the prefix + keyword is used to call the value, which is much more convenient than self-parsing parameters, it also does not mix the list parameter with other types of functions.