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.path is 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.genvs2012opts.configProjects/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, 初始化exporter
  • Shutdown, 销毁对象时的操作
  • 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语法。

posted @ 2026-02-25 20:34  dewxin  阅读(4)  评论(0)    收藏  举报