拿到引擎源码后运行setup.py很必要,
该工具配置了引擎的环境变量的配置,并把他们添加到了path变量中
设置的变量包括:
COCOS_CONSOLE_ROOT
COCOS_TEMPLATES_ROOT
NDK_ROOT
ANDROID_SDK_ROOT
ANT_ROOT
重中之重------找到程序的入口:
if __name__ == '__main__':
1. 准备阶段-----判断版本
if not _check_python_version():
exit()
/**************************/
def _check_python_version():
major_ver = sys.version_info[0]
if major_ver > 2:
print ("The python version is %d.%d. But python 2.x is required. (Version 2.7 is well tested)\n"
"Download it here: https://www.python.org/" % (major_ver, sys.version_info[1]))
return False
return True
调用自定义的_check_python_version函数判断python的版本号,不是python 2.X的话退出,由于python 2.X 和python 3.X代码不兼容,判断版本号还是必须的
以Python 2.7.3为例,sys.version_info含有版本号信息如下,
>>> sys.version_info
sys.version_info(major=2, minor=7, micro=3, releaselevel='final', serial=0)
parser = OptionParser()
parser.add_option(
'-n', '--ndkroot', dest='ndk_root', help='directory of ndk root')
parser.add_option('-a', '--androidsdkroot',
dest='android_sdk_root', help='directory of android sdk root')
parser.add_option(
'-t', '--antroot', dest='ant_root', help='directory that contains ant/ant.bat')
opts, args = parser.parse_args()
env = SetEnvVar()
env.set_environment_variables(
opts.ndk_root, opts.android_sdk_root, opts.ant_root)
函数set_environment_variables()中的关键部分是一下五行
self.set_console_root()
self.set_templates_root()
ndk_ret = self.set_variable(NDK_ROOT, ndk_root)
sdk_ret = self.set_variable(ANDROID_SDK_ROOT, android_sdk_root)
ant_ret = self.set_variable(ANT_ROOT, ant_root)
def set_console_root(self):
print("->Check environment variable %s" % COCOS_CONSOLE_ROOT)
# 获取最新的路径
cocos_consle_root = os.path.join(
self.current_absolute_path, 'tools', 'cocos2d-console', 'bin')
# 获取已经设置的路径
old_dir = self._find_environment_variable(COCOS_CONSOLE_ROOT)
if old_dir is None:
# 首次设置时步骤
if self._isWindows():
self.set_windows_path(cocos_consle_root)
self._set_environment_variable(
COCOS_CONSOLE_ROOT, cocos_consle_root)
else:
if old_dir == cocos_consle_root:
# is same with before, nothing to do
return
# 更新最新的环境变量
if self._isWindows():
self.remove_dir_from_win_path(old_dir)
self.set_windows_path(cocos_consle_root)
self._force_update_env(COCOS_CONSOLE_ROOT, cocos_consle_root)
有几个重要的自定义函数
第一个 获取环境变量的值。函数中对注册表的操作是该工具的核心步骤,辅助os.environ是在该工具中常见的搭配
def _find_environment_variable(self, var):
'''
获取环境变量var的值,未找到返回None
'''
print(" ->Search for environment variable %s..." % var)
ret = None
try:
# os.environ 是一个字符串所对应环境的映像对象
# 当访问不存在的字段时python会抛异常
ret = os.environ[var]
except Exception:
if not self._isWindows():
file_list = self._get_unix_file_list()
if file_list is not None:
home = os.path.expanduser('~')
for name in file_list:
path = os.path.join(home, name)
ret = self._search_unix_variable(var, path)
if ret is not None:
break
else:
'''
_winreg 修改windows注册表
_winreg.OpenKeyEx() 读取,打开特定的key
_winreg.QueryValueEx()
_winreg.CloseKey()
'''
import _winreg
try:
env = None
# 打开一个键
env = _winreg.OpenKeyEx(_winreg.HKEY_CURRENT_USER,
'Environment',
0,
_winreg.KEY_READ)
#注册表中检索一个键的路径
ret = _winreg.QueryValueEx(env, var)[0]
_winreg.CloseKey(env)
except Exception:
if env:
_winreg.CloseKey(env)
ret = None
if ret is None:
print(" ->%s not found\n" % var)
else:
print(" ->%s is found : %s\n" % (var, ret))
return ret
第二个: 添加变量到Path变量中
def set_windows_path(self, add_dir):
'''
将add_dir加到Path变量中
'''
ret = False
import _winreg
try:
env = None
path = None
env = _winreg.OpenKeyEx(_winreg.HKEY_CURRENT_USER,
'Environment',
0,
_winreg.KEY_SET_VALUE | _winreg.KEY_READ)
path = _winreg.QueryValueEx(env, 'Path')[0]
# add variable if can't find it in PATH
# _winreg.SetValueEx() 设置一个值
# _winreg.FlushKey() 回写所有的键属性改变到注册表
path_lower = path.lower()
add_dir_lower = add_dir.lower()
if (path_lower.find(add_dir_lower) == -1):
path = add_dir + ';' + path
_winreg.SetValueEx(env, 'Path', 0, _winreg.REG_SZ, path)
_winreg.FlushKey(env)
_winreg.CloseKey(env)
ret = True
except Exception:
if not path:
path = add_dir
_winreg.SetValueEx(env, 'Path', 0, _winreg.REG_SZ, path)
_winreg.FlushKey(env)
ret = True
else:
_winreg.SetValueEx(env, 'Path', 0, _winreg.REG_SZ, path)
_winreg.FlushKey(env)
ret = False
if env:
_winreg.CloseKey(env)
if ret:
print(" ->Add directory \"%s\" into PATH succeed!\n" % add_dir)
else:
print(" ->Add directory \"%s\" into PATH failed!\n" % add_dir)
第三个: 根据不同的平台,分别添加环境变量
def _set_environment_variable(self, key, value):
'''
将key,value添加到环境变量中
'''
print(" -> Add %s environment variable..." % key)
ret = False
if self._isWindows():
ret = self._set_environment_variable_win32(key, value)
else:
ret = self._set_environment_variable_unix(key, value)
if ret:
print(" ->Added %s=%s\n" % (key, value))
else:
print(" ->Add failed\n")
return ret
# modify registry table to add an environment variable on windows
def _set_environment_variable_win32(self, key, value):
'''
在win32平台添加key,value的环境变量
'''
ret = False
import _winreg
try:
env = None
env = _winreg.OpenKeyEx(_winreg.HKEY_CURRENT_USER,
'Environment',
0,
_winreg.KEY_SET_VALUE | _winreg.KEY_READ)
_winreg.SetValueEx(env, key, 0, _winreg.REG_SZ, value)
_winreg.FlushKey(env)
_winreg.CloseKey(env)
ret = True
except Exception:
if env:
_winreg.CloseKey(env)
ret = False
return ret
第四个:删除Path中的变量,对字符串的操作还是值得注意的
def remove_dir_from_win_path(self, remove_dir):
'''
删除Path中的remove_dir
'''
import _winreg
try:
env = None
path = None
env = _winreg.OpenKeyEx(_winreg.HKEY_CURRENT_USER,
'Environment',
0,
_winreg.KEY_SET_VALUE | _winreg.KEY_READ)
path = _winreg.QueryValueEx(env, 'Path')[0]
path_lower = path.lower()
remove_dir = remove_dir.replace('/', '\\')
remove_dir_lower = remove_dir.lower()
start_pos = path_lower.find(remove_dir_lower)
if (start_pos >= 0):
length = len(remove_dir_lower)
need_remove = path[start_pos:(start_pos + length)]
path = path.replace(need_remove, '')
path = path.replace(';;', ';')
_winreg.SetValueEx(env, 'Path', 0, _winreg.REG_SZ, path)
_winreg.FlushKey(env)
_winreg.CloseKey(env)
print(' ->Remove directory \"%s\" from PATH!\n' % remove_dir)
except Exception:
print(' ->Remove directory \"%s\" from PATH failed!\n' %
remove_dir)
第五个: 更新环境变量
def _force_update_env(self, var_name, value):
ret = False
if self._isWindows():
print(" ->Force update environment variable %s" % var_name)
ret = self._set_environment_variable_win32(var_name, value)
if not ret:
print(" ->Failed!")
else:
print(" ->Succeed : %s=%s" % (var_name, value))
else:
ret = self._force_update_unix_env(var_name, value)
return ret
def _force_update_unix_env(self, var_name, value):
'''
有待分析
'''
import re
home = os.path.expanduser('~')
str_re = SetEnvVar.RE_FORMAT % var_name
patten = re.compile(str_re)
replace_str = 'export %s=%s\n' % (var_name, value)
file_list = SetEnvVar.MAC_CHECK_FILES
if self._isLinux():
file_list = SetEnvVar.LINUX_CHECK_FILES
print(" ->Update variable %s in files %s" %
(var_name, str(file_list)))
variable_updated = False
for file_name in file_list:
path = os.path.join(home, file_name)
if os.path.isfile(path):
lines = []
# read files
need_over_write = False
file_obj = open(path, 'r')
for line in file_obj:
str_temp = line.lstrip(' \t')
match = patten.match(str_temp)
if match is not None:
variable_updated = True
need_over_write = True
lines.append(replace_str)
else:
lines.append(line)
file_obj.close()
# rewrite file
if need_over_write:
file_obj = open(path, 'w')
file_obj.writelines(lines)
file_obj.close()
print(" ->File %s updated!" % path)
# nothing updated, should add variable
if not variable_updated:
print("\n ->No files updated, add variable %s instead!" %
var_name)
ret = self._set_environment_variable(var_name, value)
else:
ret = True
return ret
第二步来看设置新建工程时模板的路径
代码与第一步类同,略去
第三步来看设置android相关的路径,三者雷同
def set_variable(self, var_name, value):
'''
在环境变量中添加或是更新var_name, value
'''
print("->Check environment variable %s" % var_name)
find_value = self._find_environment_variable(var_name)
var_found = (find_value is not None)
action_none = 0
action_add = 1
action_update = 2
# 根据不同情况得出操作类型:不做,添加,更新
need_action = action_none
if var_found:
if value and self._check_valid(var_name, value):
# should update
need_action = action_update
else:
# do nothing
need_action = action_none
else:
if not value:
# find the command path in system
value = self._find_value_from_sys(var_name)
if not value:
value = self._get_input_value(var_name)
if value and self._check_valid(var_name, value):
# should add variable
need_action = action_add
else:
# do nothing
need_action = action_none
# 开始操作
if need_action == action_none:
# do nothing
return SetEnvVar.RESULT_DO_NOTHING
elif need_action == action_add:
# add variable
if self._set_environment_variable(var_name, value):
return SetEnvVar.RESULT_ADDED
else:
return SetEnvVar.RESULT_ADD_FAILED
elif need_action == action_update:
# update variable
if self._force_update_env(var_name, value):
# update succeed
return SetEnvVar.RESULT_UPDATED
else:
# update failed
return SetEnvVar.RESULT_UPDATE_FAILED
else:
return SetEnvVar.RESULT_DO_NOTHING
通知所有的顶层窗口,应用程序改变了系统参数
if env._isWindows():
import ctypes
HWND_BROADCAST = 0xFFFF
WM_SETTINGCHANGE = 0x1A
SMTO_ABORTIFHUNG = 0x0002
result = ctypes.c_long()
SendMessageTimeoutW = ctypes.windll.user32.SendMessageTimeoutW
SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
u'Environment', SMTO_ABORTIFHUNG, 5000, ctypes.byref(result))
总结: python的相关用法:(没办法了太长了,只能另开了)
[python 补充] optparser
os.path