4. 增加新类型
如果MPC并不支持某个特定的生成工具,你可能会考虑为其增加一个新的项目类型。例如,我们可以为MPC添加对Boost Jam、Eclipse、Xcode以及其他很多类型生成工具的支持。要达到这样的要求,我们需要有关于MPC输入文件以及面向对象Perl的知识。
4.1 输入文件语法
在这一节中,我们将为大家介绍在项目生成是使用的输入文件语法:
4.1.1 模板文件(mpd)
模板文件由大量MPC放入到每个生成的项目文件中去的信息构成,这些文件通过不同的模板指令来根据mpc文件的内容来提供相应的文本和数据的布局。
模板指令由<%%>结构来进行声明,该结构用来提供if语句、foo循环以及变量访问功能,需要注意的是,所有没有被<%%>包围的文本,包括空白都会原封不动的传递到生成的项目文件中去。
if语句可以只占用一行,也可以占用多行。例如,下面这行:
<%if(exename)%>BIN = <%exename%><%else%>LIB = <%sharedname%><%endif%>
同下面几行是一样的:
<%if(exename)%>
BIN = <%exename%>
<%else%>
LIB = <%sharedname%>
<%endif%>
foreach语句同样可以占用一行或者多行,如同关键字小节中描述的,foreach语句在空格分隔的列表环境中计算变量。foreach循环可以采用多种书写方式,第一种方式是对循环变量进行命名并列出每个变量值,这也是比较推荐的做法:
FILES=<%foreach(fvar, idl_files source_files header_files)%> <%fvar%><%endfor%>
第二种方式是让foreach来决定变量名称,在这种方式中,每个值都可以用传递给foreach的第一个变量的变量名称去除掉结尾的“s”字符来访问:
FILES=<%foreach(idl_files source_files header_files)%> <%idl_file%><%endfor%>
需要注意的是,<%idl_file%>变量会循环迭代idl_files、source_files和header_files列表中的每一个值。如果foreach的第一个变量并不以“s”字符结尾,则使用同第一个变量名相同的名称来表示。如:
<%foreach(filelist)%> <% filelist%><%endfor%>
表8中列出了可以在模板文件中使用的关键字。
表8. 模板文件关键字
| 关键字 | 描述 |
| if | 用来决定某个变量是否被定义。非操作(!)可以用来反转结果。该结构只检查在mpc文件或mpt文件中出现的值定义,缺省值(即使是由项目创建器实现的)并不会被if语句考虑。 |
| else | 同if语句一起使用,只有当if语句不为真的时候,else语句才会被执行。 |
| endif | 同if语句一起使用,用来结束if或者if/else块。 |
| noextension | 将变量值解释为文件名,并从变量中移除扩展名以及表示扩展名的点号。 |
| dirname | 将变量值解释为文件名,并从变量中移除basename。 |
| basename | 将变量值解释为文件名,并从变量中移除目录信息。 |
| basenoextension | 作用类似basename,不过同时从变量中移除扩展名以及表示扩展名的点号。 |
| foreach | 在空格分隔的列表环境中计算变量。 |
| forfirst | 同foreach一起使用,传递给forfirst的文字值会被放置到foreach中第一个迭代中去。 |
| fornotfirst | 同foreach一起使用,传递给fornotfirst的文字值会被放置到foreach中除第一个之外的每一个迭代中去。 |
| forlast | 同foreach一起使用,传递给forlast的文字值会被放置到foreach中最后一个迭代中去。 |
| fornotlast | 同foreach一起使用,传递给fornotlast的文字值会被放置到foreach中除最后一个之外的每一个迭代中去。 |
| endfor | 同foreach一起使用,用来结束foreach块。 |
| comment | 传递给comment的任何值都将被忽略(注释),可以使用任何除去换行和语句结束符之外的任何字符。 |
| flag_overrides | 直接覆盖在mpc文件中的项目范围内的设置,使用两个由逗号分隔的变量,第一个变量对应一个文件名,第二个可以是任何变量。 |
| marker | 同mpc语法中的verbatim关键字,可以用来在模板中指定占位符。如,<%marker(local)%>。 |
| uc | 返回变量值的大写字母形式。 |
| lc | 返回变量值的小写字母形式。 |
| ucw | 返回变量值中每个单词首字母大写的形式,单词使用空格或者下划线来进行分隔。 |
| normalize | 将连字号、斜杠、美元符号、括号以及点号转换为下划线。 |
| reverse | 反转数组参数值的顺序。 |
| sort | 对数组参数值进行排序。 |
| uniq | 返回数组参数值的唯一集合。 |
| multiple | 如果数组参数包含多个值,则返回真。 |
| starts_with | 如果参数值(第一个参数)以给出的正则表达式(第二个参数)开始,则返回真。 |
| ends_with | 如果参数值(第一个参数)以给出的正则表达式(第二个参数)结尾,则返回真。 |
| contains | 如果参数值(第一个参数)匹配给出的正则表达式(第二个参数),则返回真。 |
表9中列出了在部分模板文件中可以作为参数的一些特殊名称。在表7中列出的变量也可以使用(除了<%temporary%>)。
表9. 可在模板文件中使用的特殊值
| 值 | 描述 |
| custom_types | 包含自定义生成类型的列表。更多信息参见自定义类型。 |
| cwd | 完整的当前工作目录。 |
| forcount | 仅可与foreach一起使用,表示从1开始计数的foreach元素索引。 |
| project_name | 包含了当前正在被处理的项目名称。 |
| project_file | 包含了当前正在被处理的项目的输出文件名。 |
| ciao | 在GNUACE项目创建器模块中实现,指定项目使用了CIAO。 |
| cppdir | 在BMake项目创建器模块中实现,返回由分号分隔的Source_Files列表值。 |
| rcdir | 在BMake项目创建器模块中实现,返回由分号分隔的Resource_Files列表值。 |
| make_file_name | 在VC6和EM3项目创建器模块中实现,返回对应到该特定项目类型的由项目名称与make文件扩展组合在一起的文件名。 |
| tao | 在GNUACE项目创建器模块中实现,指定项目使用了TAO。 |
| guid | 在VC7项目创建器模块中实现,返回一个在VC7项目文件中使用的基于项目的guid值。 |
| vcversion | 在VC7项目创建器模块中实现,返回被创建项目类型的版本号:vc7返回7.00,vc71返回7.10,vc8返回8.00。 |
| vpath | 在GNUACE项目创建器模块中实现,返回源文件相对于在GNU Make中的VPATH设置的路径值。 |
4.1.1.1 自定义类型
为了支持多个自定义生成类型,我们使用了一个特殊的关键词。custom_types关键词用来访问一系列的用户自定义类型。在foreach循环中,可以使用custom_type关键词来访问每一个自定义类型。
通过对custom_type关键词使用->操作符,我们可以访问一些常用的信息:输入文件、输入文件扩展名、命令、命令输出选项、命令标志以及输出文件目录,这些信息可以通过对应该类型的字段名来进行访问。同该自定义类型相关的输入文件可以使用custom_type->input_files来进行访问,每一个输入文件都会对应以系列的输出文件,这些输出文件可以在foreach循环中通过custom_type->input_file->output_files来访问。表10中列出了自定义类型字段。
表10. 自定义类型字段
| 值 | 描述 |
| command | 自定义类型中使用的命令。 |
| commandflags | 不包括输出选项的命令行选项。 |
| dependent | 告诉命令哪些生成的文件需要有依赖。 |
| gendir | 针对特定文件类型的输出目录,该字段直接通过custom_type来访问则没有任何意义,应该始终在flag_overrides上下文中使用。 |
| input_files | 与自定义类型关联的输入文件。 |
| inputexts | 与自定义类型关联的输入文件扩展名。 |
| libpath | 命令相关的库路径设置。 |
| output_option | 可选的命令输出选项。 |
| pch_postrule | 用来决定命令是否需要支持预编译头。 |
| postcommand | 该命令允许用户在主命令处理完成自定义的输入文件之后,运行指定的命令。 |
例如,在下面的例子中,为生成自定义的输入文件创建了一个通用的makefile规则,显示了自定义类型的基本用法以及可以访问的一些字段,使用custom_types关键词的一个主要局限(可以在下面的例子中看到)就是不能为foreach指定别的变量名。
<%if(custom_types)%>
<%foreach(custom_types)%>
<%foreach(custom_type->input_files)%>
<%foreach(custom_type->input_file->output_files)%>
<%custom_type->input_file_output_file%>: <%custom_type->input_file%>
<%custom_type->command%> <%custom_type->commandflags%> $@
<%endfor%>
<%endfor%>
<%endfor%>
<%endif%>
4.1.1.2 群组文件
mpc文件语法中支持文件群组:可以在一个mpc文件中将一系列文件作为群组并在mpd文件中作为一个整体来进行访问。
文件(例如:Source_Files、Header_Files)可以按照组件小节中介绍的第二种方式来群组到一起。在mpd文件中,不同的组件可以通过在前面加上grouped_前缀来进行访问(如:grouped_source_files、grouped_header_files等)。
表11. 群组文件字段名
| 字段名 | 描述 |
| files | 组中的输入文件。 |
| component_name | 群组文件的组名。 |
下面是一个如何针对每一个组创建make宏的例子,展示了群组的基本用法和如何对字段进行访问。使用文件群组功能的主要局限(可以在下面的例子中看到)就是不能为foreach指定别的变量名。下面的例子中只使用了源文件,但是所有在mpc和mpd小节中列出的组件均可以使用。
<%if(grouped_source_files)%>
<%comment(Get back each set of grouped files)%>
<%foreach(grouped_source_files)%>
<%comment(This will provide the name of the group)%>
<%grouped_source_file%> = \
<%comment(Get all the source files in a single group)%>
<%foreach(grouped_source_file->files)%>
<%grouped_source_file->file)%><%fornotlast(“ \\”)%>
<%endfor%>
<%endfor%>
ifndef <%grouped_source_files->component_name%>
<%grouped_source_files->component_name%> = \
<%foreach(grouped_source_files)%>
<%grouped_source_file%><%fornotlast(“ \\”)%>
<%endfor%>
endif
<%endif%>
4.1.2 模板输入文件(mpt)
模板输入文件对于所有项目来说都通用的编译工具相关的特定信息。例如:编译器开关、中间文件目录、编译器宏等。每一个项目类型均可以为动态库、静态库、动态可执行文件和静态可执行文件提供相应的模板输入文件。但是,所有这些都不被MPC所实际需要。
模板输入文件相对于其他的MPC文件类型来说格式更加自由。它的语法类型mpc文件的语法,区别在于没有项目定义,并且只能使用一个关键词:conditional_include。该关键词用来包含其他可以在MPC包含文件搜索路径中找到的mpt文件,如果在conditional_include关键词后用双引号引起的名称没有找到,则忽略该名称,并且不会有任何的警告提示。mpt后缀会被自动添加到提供的名称后。
模板输入文件包含一系列的变量赋值操作。该变量赋值操作可以是下面两种方式中的任何一种:
variable_name = value1 “value 2”
variable_name += another_value
这些变量可以在对于的mpd文件中进行使用。
在一个mpt文件中,变量赋值操作可以组合到一起并进行命名,并在mpd文件中作为范围变量来进行使用。下面的例子显示了变量赋值组合使用的方式:
// mpt file
configurations = Release Debug
common_defines = WIN32 _CONSOLE
Release {
compiler_flags = /W3 /GX /O2 /MD /GR
defines = NDEBUG
}
Debug {
compiler_flags = /W3 /Gm /GX /Zi /Od /MDd /GR /Gy
defines = _DEBUG
}
conditional_include “vcfullmacros”
下面mpd文件片段使用了上面的mpt文件所提供的信息:
<%foreach(configurations)%>
Name = <%configuration%>
<%compile_flags%><%foreach(defines common_defines)%> /D <%define%>=1<%endfor%>
<%endfor%>
下面的内容则显示了上面例子的输出结果:
Name = Release
/W3 /GX /O2 /MD /GR /D NDEBUG=1 /D WIN32=1 /D _CONSOLE=1
Name = Debug
/W3 /Gm /GX /Zi /Od /MDd /GR /Gy /D _DEBUG=1 /D WIN32=1 /D _CONSOLE=1
如果一个foreach变量对应一个变量组名,则该变量组在该foreach范围类可用。
[ 本帖最后由 earthdog 于 2008-4-22 16:50 编辑 ]
