import os import sys from xml.dom import minidom def os_is_win32(): return sys.platform == 'win32' def os_is_mac(): return sys.platform == 'darwin' IS_DEBUG = False def output_msg(msg): if IS_DEBUG: print(msg) class VCXProject(object): def __init__(self, proj_file_path): self.xmldoc = minidom.parse(proj_file_path) self.root_node = self.xmldoc.documentElement if os.path.isabs(proj_file_path): self.file_path = proj_file_path else: self.file_path = os.path.abspath(proj_file_path) def get_or_create_node(self, parent, node_name, create_new=True): children = parent.getElementsByTagName(node_name) if len(children) > 0: return children[0] else: if create_new: child = parent.createElement(node_name) return child else: return None def save(self, new_path=None): if new_path is None: savePath = self.file_path else: if os.path.isabs(new_path): savePath = new_path else: savePath = os.path.abspath(new_path) output_msg("Saving the vcxproj to %s" % savePath) if not os.path.isabs(savePath): savePath = os.path.abspath(savePath) file_obj = open(savePath, "w") self.xmldoc.writexml(file_obj, encoding="utf-8") file_obj.close() file_obj = open(savePath, "r") file_content = file_obj.read() file_obj.close() file_content = file_content.replace(""", "\"") file_content = file_content.replace("/>", " />") if os_is_mac(): file_content = file_content.replace("\n", "\r\n") file_content = file_content.replace("?><", "?>\r\n<") file_obj = open(savePath, "w") file_obj.write(file_content) file_obj.close() output_msg("Saving Finished") def remove_lib(self, lib_name): cfg_nodes = self.root_node.getElementsByTagName("ItemDefinitionGroup") for cfg_node in cfg_nodes: cond_attr = cfg_node.attributes["Condition"].value if cond_attr.lower().find("debug") >= 0: cur_mode = "Debug" else: cur_mode = "Release" # remove the linked lib config link_node = self.get_or_create_node(cfg_node, "Link") depends_node = self.get_or_create_node(link_node, "AdditionalDependencies") link_info = depends_node.firstChild.nodeValue cur_libs = link_info.split(";") link_modified = False if lib_name in cur_libs: output_msg("Remove linked library %s from \"%s\" configuration" % (lib_name, cur_mode)) cur_libs.remove(lib_name) link_modified = True if link_modified: link_info = ";".join(cur_libs) depends_node.firstChild.nodeValue = link_info def add_lib(self, lib_name): cfg_nodes = self.root_node.getElementsByTagName("ItemDefinitionGroup") for cfg_node in cfg_nodes: cond_attr = cfg_node.attributes["Condition"].value if cond_attr.lower().find("debug") >= 0: cur_mode = "Debug" else: cur_mode = "Release" # add the linked lib config link_node = self.get_or_create_node(cfg_node, "Link") depends_node = self.get_or_create_node(link_node, "AdditionalDependencies") link_info = depends_node.firstChild.nodeValue cur_libs = link_info.split(";") link_modified = False if lib_name not in cur_libs: output_msg("Add linked library %s for \"%s\" configuration" % (lib_name, cur_mode)) cur_libs.insert(0, lib_name) link_modified = True if link_modified: link_info = ";".join(cur_libs) depends_node.firstChild.nodeValue = link_info def get_event_command(self, event, config=None): cfg_nodes = self.root_node.getElementsByTagName("ItemDefinitionGroup") ret = "" for cfg_node in cfg_nodes: if config is not None: cond_attr = cfg_node.attributes["Condition"].value if cond_attr.lower().find("debug") >= 0: cur_mode = "Debug" else: cur_mode = "Release" if cur_mode.lower() != config.lower(): continue event_nodes = cfg_node.getElementsByTagName(event) if len(event_nodes) <= 0: continue event_node = event_nodes[0] cmd_nodes = event_node.getElementsByTagName("Command") if len(cmd_nodes) <= 0: continue cmd_node = cmd_nodes[0] ret = cmd_node.firstChild.nodeValue break return ret def set_event_command(self, event, command, config=None, create_new=True): cfg_nodes = self.root_node.getElementsByTagName("ItemDefinitionGroup") for cfg_node in cfg_nodes: if config is not None: if 'Condition' not in cfg_node.attributes.keys(): continue cond_attr = cfg_node.attributes["Condition"].value if cond_attr.lower().find("debug") >= 0: cur_mode = "Debug" else: cur_mode = "Release" if cur_mode.lower() != config.lower(): continue event_node = self.get_or_create_node(cfg_node, event, create_new) if event_node is None: continue cmd_node = self.get_or_create_node(event_node, "Command") if cmd_node.firstChild is None: impl = minidom.getDOMImplementation() dom = impl.createDocument(None, 'catalog', None) nodeValue = dom.createTextNode(command) cmd_node.appendChild(nodeValue) else: cmd_node.firstChild.nodeValue = command def get_node_if(self, parent, name): children = parent.getElementsByTagName(name) child = None if len(children) > 0: child = children[0] else: child = self.xmldoc.createElement(name) parent.appendChild(child) return child def set_item(self, event, eventItem, command): cfg_nodes = self.root_node.getElementsByTagName("ItemDefinitionGroup") for cfg_node in cfg_nodes: cond_attr = cfg_node.attributes["Condition"].value if cond_attr.lower().find("debug") >= 0: cur_mode = "Debug" else: cur_mode = "Release" output_msg("event: %s" % event) event_node = self.get_node_if(cfg_node, event) cmd_node = self.get_node_if(event_node, eventItem) text_node = self.xmldoc.createTextNode(command) cmd_node.appendChild(text_node) def set_include_dirs(self, paths): if "%(AdditionalIncludeDirectories)" not in paths: paths.append("%(AdditionalIncludeDirectories)") include_value = ";".join(paths) include_value = include_value.replace("/", "\\") cfg_nodes = self.root_node.getElementsByTagName("ItemDefinitionGroup") for cfg_node in cfg_nodes: compile_node = self.get_or_create_node(cfg_node, "ClCompile") include_node = self.get_or_create_node(compile_node, "AdditionalIncludeDirectories") include_node.firstChild.nodeValue = include_value def remove_proj_reference(self): itemgroups = self.root_node.getElementsByTagName("ItemGroup") for item in itemgroups: proj_refers = item.getElementsByTagName("ProjectReference") if len(proj_refers) > 0: self.root_node.removeChild(item) def remove_predefine_macro(self, macro, config=None): cfg_nodes = self.root_node.getElementsByTagName("ItemDefinitionGroup") for cfg_node in cfg_nodes: if config is not None: if 'Condition' not in cfg_node.attributes.keys(): continue cond_attr = cfg_node.attributes["Condition"].value if cond_attr.lower().find("debug") >= 0: cur_mode = "Debug" else: cur_mode = "Release" if (cur_mode.lower() != config.lower()): continue compile_node = self.get_or_create_node(cfg_node, "ClCompile") predefine_node = self.get_or_create_node(compile_node, "PreprocessorDefinitions") defined_values = predefine_node.firstChild.nodeValue defined_list = defined_values.split(";") if macro in defined_list: defined_list.remove(macro) new_value = ";".join(defined_list) predefine_node.firstChild.nodeValue = new_value