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

拿到引擎源码后运行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

 


你可能感兴趣的:(cocos2dx,源码分析,python)