import os import sys import re import xml.etree.ElementTree as ET ENVIRONMENT = {} # マクロを展開 def ExpandMacros(text): splitList = re.split( "(\$\([a-zA-Z0-9_]+?\))", text) expand_str = "" for s in splitList: match = re.match("\$\(([a-zA-Z0-9_]+?)\)", s) if match: if match.group(1) in ENVIRONMENT: expand_str += ExpandMacros(ENVIRONMENT[match.group(1)]) # 再帰 else: #システム周りの細かいところまで必要ないのでちゃんと実装しない expand_str += s else: expand_str += s return expand_str # 属性にあるConditionををチェックする def ValidElement(element): # Condition探す if "Condition" in element.attrib: # == で分割して param = element.attrib["Condition"].strip(' "').split("==") if 2 != len(param): #システム周りの細かいところまで必要ないので実装しない #raise BaseException("condition[%s]が想定外" % str(element.attrib)) return False # マクロ展開 str1 = ExpandMacros( param[0].strip(" '") ) str2 = ExpandMacros( param[1].strip(" '") ) # したのが同じじゃなかったら無効 if str1 != str2: return False return True # ;区切りで配列にする。その際マクロも展開する def ConvertText(prev_list, parent_str, text): if not text: return [] params = [] for param in text.split(";"): param = param.strip(' "') if not param: continue if param == "%(" + parent_str + ")": params += prev_list else: # マクロ展開 param = ExpandMacros(param) # 連結されてるかも datas = param.split(";") for data in datas: if data: params.append(data) return params def GenerateCompileOption(sln_name, vcxproj_name, preprocess_vcxproj_name): with open(preprocess_vcxproj_name, "r", encoding="utf-8") as f: root = ET.fromstring(f.read()) ENVIRONMENT.update( os.environ.items() ) ENVIRONMENT["Configuration"] = "Debug" ENVIRONMENT["Platform"] = "x64" ENVIRONMENT["SolutionDir"] = os.path.dirname(os.path.abspath(sln_name)) ENVIRONMENT["ProjectDir"] = os.path.dirname(os.path.abspath(vcxproj_name)) ENVIRONMENT["IncludePath"] = "$(VC_IncludePath);$(WindowsSDK_IncludePath)" ENVIRONMENT["VC_IncludePath"] = "" # システムはいらないので空白にしてしまう。 ENVIRONMENT["WindowsSDK_IncludePath"] = "" # システムはいらないので空白にしてしまう。 includes = [] definitions = [] forceIncludeFiles = [] for ItemDefinitionGroup in root.iter('{http://schemas.microsoft.com/developer/msbuild/2003}ItemDefinitionGroup'): if not ValidElement( ItemDefinitionGroup ): continue for AdditionalIncludeDirectories in ItemDefinitionGroup.iter('{http://schemas.microsoft.com/developer/msbuild/2003}AdditionalIncludeDirectories'): includes = ConvertText(includes, "AdditionalIncludeDirectories", AdditionalIncludeDirectories.text) # 追加ではなく代入 for PreprocessorDefinitions in ItemDefinitionGroup.iter('{http://schemas.microsoft.com/developer/msbuild/2003}PreprocessorDefinitions'): definitions = ConvertText(definitions, "PreprocessorDefinitions", PreprocessorDefinitions.text) # 追加ではなく代入 for ForcedIncludeFiles in ItemDefinitionGroup.iter('{http://schemas.microsoft.com/developer/msbuild/2003}ForcedIncludeFiles'): forceIncludeFiles = ConvertText(forceIncludeFiles, "ForcedIncludeFiles", ForcedIncludeFiles.text) # 追加ではなく代入 for PropertyGroup in root.iter('{http://schemas.microsoft.com/developer/msbuild/2003}PropertyGroup'): if not ValidElement( PropertyGroup ): continue for IncludePath in PropertyGroup.iter('{http://schemas.microsoft.com/developer/msbuild/2003}IncludePath'): includePaths = ConvertText([], "IncludePath", IncludePath.text) # 追加ではなく代入 text = "" includes = includePaths + includes # システムインクルードパスをくっつける for include in includes: text += "-I" + include + "\n" for definition in definitions: text += "-D" + definition + "\n" for forceIncludeFile in forceIncludeFiles: text += "-include" + forceIncludeFile + "\n" return text def GenerateHeaders(vcxproj_name): with open(vcxproj_name, "r", encoding="utf-8") as f: root = ET.fromstring(f.read()) headers = [] for ItemGroup in root.iter('{http://schemas.microsoft.com/developer/msbuild/2003}ItemGroup'): for ClInclude in ItemGroup.iter('{http://schemas.microsoft.com/developer/msbuild/2003}ClInclude'): for FileType in ClInclude.iter('{http://schemas.microsoft.com/developer/msbuild/2003}FileType'): if FileType.text == "CppCode": continue headers.append( ClInclude.get("Include") ) return headers def GenerateSources(vcxproj_name): with open(vcxproj_name, "r", encoding="utf-8") as f: root = ET.fromstring(f.read()) headers = [] for ItemGroup in root.iter('{http://schemas.microsoft.com/developer/msbuild/2003}ItemGroup'): for ClCompile in ItemGroup.iter('{http://schemas.microsoft.com/developer/msbuild/2003}ClCompile'): for FileType in ClCompile.iter('{http://schemas.microsoft.com/developer/msbuild/2003}FileType'): if FileType.text != "CppCode": continue headers.append( ClCompile.get("Include") ) return headers def GenerateVcxprojsFromSln(sln_name): vcxprojs = [] # XMLじゃない。 with open(sln_name, "r", encoding="utf-8") as f: lines = f.readlines() for line in lines: match = re.match( "[ \t]*Project[ \t]*\(", line ) if not match: continue statement = line.split("=") if len(statement) < 2: continue param = statement[1].split(",") if len(param) < 3: continue param = [x.strip(' "') for x in param] # 邪魔なの取り除く name = param[0] path = param[1] hash = param[2] # 特定拡張子のみオッケー(フィルタとかも普通に入ってくる) if not re.match( "^.*\.vcxproj$", path ): continue print(path) vcxprojs.append(path) return vcxprojs def Main(sln_name, vcxproj_name, preprocess_vcxproj_name, outputFileName): text = GenerateCompileOption(sln_name, vcxproj_name, preprocess_vcxproj_name) with open(outputFileName, "w", encoding="utf_8_sig") as f: f.write(text) if __name__ == '__main__': Main(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])