Jam创建项目工程源码分析(1) 创建前准备
Unity是如何调用jam创建项目工程的
Unity中创建 项目工程的代码主要是jam.pl 这个perl脚本里面的
RunJamExe("--workspace","--config=$top/Projects/Jam/WorkSpaceGenerationConfigWin.jam", "--gen=vs2012","$top/Jamfile.jam","$top/Projects/JamGenerated");
它会携带对应的参数调用Jam.exe. 这里Jam.exe由Perl脚本根据当前系统选择。
BEGIN {
$top = File::Spec->rel2abs( dirname(__FILE__) );
}
my $jambuilds = "$top/External/Jamplus/builds";
print "jambuilds: $jambuilds\n";
my $jamExe = "$jambuilds/bin/macosx32/jam";
if ($^O eq "MSWin32")
{
$jamExe = "$jambuilds/bin/win32/jam.exe";
}
这里Jam.exe就是起到了中转的作用,Jam.exe检测到有--workspace参数,会将除了--workspace之外的参数传递给同目录下的workspace.bat,这个batch文件里面的内容很简单,就是调用..\scripts\JamToWorkspace.lua 这个lua文件。
但如果我们直接调用这个lua文件,它会出现错误提示,因为jam程序在调用 workspace.bat之前,设置了几个环境变量。
我们需要在调用JamToWorkspace.lua之前设置JAM_EXECUTABLE,OS,OSPLAT这几个环境变量,然后进入到Unity源代码目录。最后再执行JamToWorkspace.lua
这里我们可以在workspace.bat相同的目录下,创建一个新的invoke_workspace.bat。
set JAM_EXECUTABLE=C:\Unity4.7.1f1_source\External\Jamplus\builds\src\..\bin\win32\jam.exe
set OS=NT
set OSPLAT=X86
cd C:\Unity4.7.1f1_source
@"%~dp0lua\lua" "%~dp0..\scripts\JamToWorkspace.lua" --config=Projects/Jam/WorkSpaceGenerationConfigWin.jam --gen=vs2012 Jamfile.jam Projects/JamGenerated
~ 是扩展的意思,变量扩充(下面详细介绍),相当于把一个相对路径转换绝对路径
%0 代指批处理文件自身(绝对路径 "D:\test\bat\test.bat",注意有双引号)
%~d0 是指批处理所在的盘符,其中d代表drive。(扩充到盘符 D: )
%~p0 是指批处理所在的目录,其中p代表path。(扩充到路径 \test\bat\ )
%~dp0 是批处理所在的盘符加路径。(扩充到盘符和路径 :D:\test\bat\)
环境变量检测
打开JamToWorkspace.lua,首先我们可以看到lua代码尝试获取几个之前我们提到的环境变量。如果没有的话,它会直接退出程序。
OS = os.getenv("OS")
OSPLAT = os.getenv("OSPLAT")
JAM_EXECUTABLE = os.getenv("JAM_EXECUTABLE")
if not OS or not OSPLAT or not JAM_EXECUTABLE then
print('*** JamToWorkspace must be called directly from Jam.')
print('\nUsage: jam --workspace ...')
os.exit(-1)
end
require对应模块
然后在执行对应的代码之前,需要加载对应的模块,这里会先将当前lua文件所处的scripts目录添加到require会搜索的集合中。
scriptPath = os.path.simplify(os.path.make_absolute(((debug.getinfo(1, "S").source:match("@(.+)[\\/]") or '.') .. '\\'):gsub('\\', '/'):lower()))
--- scriptPath is where current lua lies
package.path = scriptPath .. "?.lua;" .. package.path
package.pathis a string containing search patterns separated by semicolons (;).
package.path控制require语句到哪里去找lua文件。它是以;分割的搜索pattern字符串
接着就会require一系列的lua文件。
jamPath = os.path.simplify(os.path.make_absolute(scriptPath .. '../'))
然后会设置jamPath的值为..\Jamplus\builds\bin,这个变量主要用于找到该目录下面的Jambase.jam文件。
解析命令行参数
JamToWorkspace.lua主要是通过ProcessCommandLine这个函数, 试图将命令行参数转化为Option这个类。
首先 我们可以通过打印arg这个变量来查看commandline的内容。
print("arg "..table.concat (arg, " "));
[[arg --ide=vs2012 --jamfile=Jamfile2.jam --outputpath=Projects/JamGenerated ]]
Option相关的类和函数位于getopt.lua文件。local options =...定义了如何解析commandline,这里需要解析的Option的name有gen,gui,compiler,postfix,config等等。
getopt.getOpt函数会返回未能解析的命令行nonOpts,以及解析后的命令行opts,还有错误信息errors。
getOpt这个函数会按照传入的options变量去解析commandline,它会将=符号左右两边分别转化为table的key和value,存储到返回值opts这个table变量里面。
local options = Options {
Option {{"config"}, "Filename of additional configuration file", "Req", 'CONFIG'},
Option {{"gen"}, "Set the name of IDE we want to export projects", "Req", 'GENERATOR'},
Option {{"ide"}, "Set the name of IDE we want to export projects", "Req", 'GENERATOR'},
Option {{"compiler"}, "Set the default compiler used to build with", "Req", 'COMPILER'},
Option {{"jamfile"}, "jamfile containing workspace info", "Req", "JAMFILE"},
Option {{"outputpath"}, "where to output the workspace", "Req", "OUTPUTPATH"},
}
-- arg is a global table where commandline is stored
nonOpts, opts, errors = getopt.getOpt (arg, options)
根据传入的commandline,这里会设置opts.gen为vs2012和opts.config为Projects/Jam/WorkSpaceGenerationConfigWin.jam。
如果我们往调用JamToWorkspace.lua的参数中添加--gui,那么这里opts.gui也会被设置为1,在lua运行结束后会在资源管理器中打开生成的目录。
应用命令行参数
ProcessCommandLine解析完命令行后, AfterProcessCommandline就会被调用,它会基于解析的参数,来设置一些变量。
opts.gen里面存储的是希望导出的项目对应的IDE类型,比如我们这里传入的命令行包含--gen=vs2012,说明我们想导出的是vs2012这个IDE的项目。
AfterProcessCommandline函数会根据opts.gen设置当前的ideExporter。 targetIDExporter = IDExporters[opts.gen]
targetIDExporter 对象是用于生成解决方案和项目工程的核心类,字段有:
Initialize, 初始化exporterShutdown, 销毁对象时的操作GetProjectExporter, 获取Project导出类(vcxproj文件)GetWorkspaceExporter, 获取解决方案导出类(sln文件)
除了找到idExporter, AfterProcessCommandline 还会将命令行参数中的 源文件sourceJamfile 和 输出路径outputPath 变为绝对路径。
-- Turn the source code root into an absolute path based on the current working directory.
absoluteSourceJamfilePath = os.path.simplify(os.path.make_absolute(opts.jamfile))
absoluteSourceRootPath, sourceJamfile = absoluteSourceJamfilePath:match('(.+/)(.*)')
-- Do the same with the destination.
absoluteOutputPath = os.path.simplify(os.path.add_slash(os.path.make_absolute(opts.outputpath)))
最后如果命令传入的参数里有指定Config文件,那么会尝试读取对应的Config lua文件,然后将里面的Config对象合并。
这个Config对象 可以配置 ValidPlatforms 或者是 ValidConfigs。
比如 Unity生成项目工程的时候,命令行中会包含 --config=$top/Projects/Jam/WorkSpaceGenerationConfigWin.jam, 但实际上这里指定的是lua文件,里面的语法都是lua语法。

浙公网安备 33010602011771号