您的位置:首页 > 移动开发 > Cocos引擎

[重新认识cocos2dx---工具篇] 一 setup.py

2015-11-02 18:07 351 查看
拿到引擎源码后运行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)


2. 命令行参数设置

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()


3. 主体部分 ---设置系统参数

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)


第一步来看设置cocos命令的路径

    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


小结:这一部分的结构很清晰,封装的函数恰到好处,类SetEnvVar 封装了大部分的操作

4. 结束部分

通知所有的顶层窗口,应用程序改变了系统参数

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: