From 8fdd01c882a5639148770e222d37bf57c88c3d0e Mon Sep 17 00:00:00 2001 From: Rebecca Heineman Date: Sun, 5 Nov 2023 11:25:13 -0600 Subject: [PATCH] Synced with perforce --- makeprojects/__init__.py | 2 +- makeprojects/codewarrior.py | 592 ++--- makeprojects/defaults.py | 31 +- makeprojects/enums.py | 335 ++- makeprojects/glsl_support.py | 6 +- makeprojects/makefile.py | 161 +- makeprojects/visual_studio.py | 13 +- makeprojects/visual_studio_2010.py | 1181 ++++++---- makeprojects/visual_studio_utils.py | 78 + makeprojects/xcode.py | 3212 ++++++++++----------------- makeprojects/xcode_utils.py | 1014 +++++++++ unittests/test_enums.py | 30 +- 12 files changed, 3736 insertions(+), 2919 deletions(-) diff --git a/makeprojects/__init__.py b/makeprojects/__init__.py index 6235332..d05ca8c 100644 --- a/makeprojects/__init__.py +++ b/makeprojects/__init__.py @@ -78,7 +78,7 @@ ######################################## # Current version of the library as a numeric tuple -__numversion__ = (0, 14, 5) +__numversion__ = (0, 15, 0) # Current version of the library __version__ = ".".join([str(num) for num in __numversion__]) diff --git a/makeprojects/codewarrior.py b/makeprojects/codewarrior.py index b5c8e8f..0a67e00 100644 --- a/makeprojects/codewarrior.py +++ b/makeprojects/codewarrior.py @@ -62,7 +62,7 @@ source_file_filter from .build_objects import BuildObject, BuildError -_MCPFILE_MATCH = re_compile('(?is).*\\.mcp\\Z') +_MCPFILE_MATCH = re_compile("(?is).*\\.mcp\\Z") if not PY2: unicode = str @@ -74,29 +74,29 @@ CODEWARRIOR_ERRORS = ( None, - 'error opening file', - 'project not open', - 'IDE is already building', - 'invalid target name (for /t flag)', - 'error changing current target', - 'error removing objects', - 'build was cancelled', - 'build failed', - 'process aborted', - 'error importing project', - 'error executing debug script', - 'attempted use of /d together with /b and/or /r' + "error opening file", + "project not open", + "IDE is already building", + "invalid target name (for /t flag)", + "error changing current target", + "error removing objects", + "build was cancelled", + "build failed", + "process aborted", + "error importing project", + "error executing debug script", + "attempted use of /d together with /b and/or /r" ) _CW_SUPPORTED_LINKERS = ( - 'MW ARM Linker Panel', # ARM for Nintendo DSI - 'x86 Linker', # Windows - 'PPC Linker', # macOS PowerPC - '68K Linker', # macOS 68k - 'PPC EABI Linker' # PowerPC for Nintendo Wii + "MW ARM Linker Panel", # ARM for Nintendo DSI + "x86 Linker", # Windows + "PPC Linker", # macOS PowerPC + "68K Linker", # macOS 68k + "PPC EABI Linker" # PowerPC for Nintendo Wii ) -TAB = '\t' +TAB = "\t" ######################################## @@ -125,16 +125,16 @@ def parse_mcp_file(full_pathname): try: # Load in the .mcp file, it's a binary file - with open(full_pathname, 'rb') as filep: + with open(full_pathname, "rb") as filep: # Get the signature and the endian cool = filep.read(4) - if cool == b'cool': + if cool == b"cool": # Big endian - endian = '>' - elif cool == b'looc': + endian = ">" + elif cool == b"looc": # Little endian - endian = '<' + endian = "<" else: print( 'Codewarrior "cool" signature not found!', @@ -143,17 +143,17 @@ def parse_mcp_file(full_pathname): # Get the offset to the strings filep.seek(16) - index_offset = struct_unpack(endian + 'I', filep.read(4))[0] + index_offset = struct_unpack(endian + "I", filep.read(4))[0] filep.seek(index_offset) - string_offset = struct_unpack(endian + 'I', filep.read(4))[0] + string_offset = struct_unpack(endian + "I", filep.read(4))[0] # Read in the version filep.seek(28) cw_version = bytearray(filep.read(4)) - # Load the string 'CodeWarrior Project' + # Load the string "CodeWarrior Project" filep.seek(40) - if filep.read(19) != b'CodeWarrior Project': + if filep.read(19) != b"CodeWarrior Project": print( '"Codewarrior Project" signature not found!', file=sys.stderr) @@ -170,7 +170,7 @@ def parse_mcp_file(full_pathname): break # Only strings with a colon are parsed - parts = item.split(':') + parts = item.split(":") if len(parts) == 2: # Target:panel target = parts[0] @@ -322,12 +322,12 @@ def build(self): cmd = [ cw_path, self.file_name, - '/t', + "/t", self.configuration, - '/s', - '/c', - '/q', - '/b'] + "/s", + "/c", + "/q", + "/b"] else: # Create the folder for the error log error_file = os.path.join( @@ -351,7 +351,7 @@ def build(self): if error_code and error_code < len(CODEWARRIOR_ERRORS): msg = CODEWARRIOR_ERRORS[error_code] except OSError as error: - error_code = getattr(error, 'winerror', error.errno) + error_code = getattr(error, "winerror", error.errno) msg = str(error) print(msg, file=sys.stderr) @@ -426,7 +426,7 @@ def create_build_object(file_name, priority=50, # Was the file corrupted? if targetlist is None: - print(file_name + ' is corrupt') + print(file_name + " is corrupt") return [] # Test for linkers that are not available on Windows @@ -502,18 +502,18 @@ def create_clean_object(file_name, priority=50, # Was the file corrupted? if targetlist is None: - print(file_name + ' is corrupt') + print(file_name + " is corrupt") return [] # Test for linkers that are not available on Windows if get_windows_host_type(): if '68K Linker' in linkers: print( - ('"{}" requires a 68k linker ' - 'which Windows doesn\'t support.').format(file_name)) + ("\"{}\" requires a 68k linker " + "which Windows doesn't support.").format(file_name)) return [] - if 'PPC Linker' in linkers: + if "PPC Linker" in linkers: print( ('"{}" requires a PowerPC linker ' 'which Windows doesn\'t support.').format(file_name)) @@ -560,7 +560,7 @@ def test(ide, platform_type): # pylint: disable=unused-argument return platform_type in ( - PlatformTypes.win32,) + PlatformTypes.win32, ) class SETTING(object): @@ -730,10 +730,10 @@ def __init__(self, platform, path, root=None, recursive=False): recursive = True self.settings = [ - SearchPath(platform, path, root, 'SearchPath'), - SETTING('Recursive', truefalse(recursive)), - SETTING('FrameworkPath', 'false'), - SETTING('HostFlags', 'All') + SearchPath(platform, path, root, "SearchPath"), + SETTING("Recursive", truefalse(recursive)), + SETTING("FrameworkPath", "false"), + SETTING("HostFlags", "All") ] def generate(self, line_list, level=4): @@ -761,15 +761,15 @@ def __init__(self, projecttype, filename): filename: Name of the output file """ if projecttype == ProjectTypes.library: - x86type = 'Library' - extension = '.lib' + x86type = "Library" + extension = ".lib" else: - x86type = 'Application' - extension = '.exe' + x86type = "Application" + extension = ".exe" self.settings = [ - SETTING('MWProject_X86_type', x86type), - SETTING('MWProject_X86_outfile', filename + extension) + SETTING("MWProject_X86_type", x86type), + SETTING("MWProject_X86_outfile", filename + extension) ] def generate(self, line_list, level=4): @@ -793,30 +793,30 @@ def __init__(self): Initialize """ self.settings = [ - SETTING('MWFrontEnd_C_cplusplus', '0'), - SETTING('MWFrontEnd_C_templateparser', '0'), - SETTING('MWFrontEnd_C_instance_manager', '0'), - SETTING('MWFrontEnd_C_enableexceptions', '0'), - SETTING('MWFrontEnd_C_useRTTI', '0'), - SETTING('MWFrontEnd_C_booltruefalse', '1'), - SETTING('MWFrontEnd_C_wchar_type', '1'), - SETTING('MWFrontEnd_C_ecplusplus', '0'), - SETTING('MWFrontEnd_C_dontinline', '0'), - SETTING('MWFrontEnd_C_inlinelevel', '0'), - SETTING('MWFrontEnd_C_autoinline', '1'), - SETTING('MWFrontEnd_C_defer_codegen', '0'), - SETTING('MWFrontEnd_C_bottomupinline', '1'), - SETTING('MWFrontEnd_C_ansistrict', '0'), - SETTING('MWFrontEnd_C_onlystdkeywords', '0'), - SETTING('MWFrontEnd_C_trigraphs', '0'), - SETTING('MWFrontEnd_C_arm', '0'), - SETTING('MWFrontEnd_C_checkprotos', '1'), - SETTING('MWFrontEnd_C_c99', '1'), - SETTING('MWFrontEnd_C_gcc_extensions', '1'), - SETTING('MWFrontEnd_C_enumsalwaysint', '1'), - SETTING('MWFrontEnd_C_unsignedchars', '0'), - SETTING('MWFrontEnd_C_poolstrings', '1'), - SETTING('MWFrontEnd_C_dontreusestrings', '0') + SETTING("MWFrontEnd_C_cplusplus", "0"), + SETTING("MWFrontEnd_C_templateparser", "1"), + SETTING("MWFrontEnd_C_instance_manager", "1"), + SETTING("MWFrontEnd_C_enableexceptions", "0"), + SETTING("MWFrontEnd_C_useRTTI", "0"), + SETTING("MWFrontEnd_C_booltruefalse", "1"), + SETTING("MWFrontEnd_C_wchar_type", "1"), + SETTING("MWFrontEnd_C_ecplusplus", "0"), + SETTING("MWFrontEnd_C_dontinline", "0"), + SETTING("MWFrontEnd_C_inlinelevel", "0"), + SETTING("MWFrontEnd_C_autoinline", "1"), + SETTING("MWFrontEnd_C_defer_codegen", "0"), + SETTING("MWFrontEnd_C_bottomupinline", "1"), + SETTING("MWFrontEnd_C_ansistrict", "0"), + SETTING("MWFrontEnd_C_onlystdkeywords", "0"), + SETTING("MWFrontEnd_C_trigraphs", "0"), + SETTING("MWFrontEnd_C_arm", "0"), + SETTING("MWFrontEnd_C_checkprotos", "1"), + SETTING("MWFrontEnd_C_c99", "1"), + SETTING("MWFrontEnd_C_gcc_extensions", "1"), + SETTING("MWFrontEnd_C_enumsalwaysint", "1"), + SETTING("MWFrontEnd_C_unsignedchars", "0"), + SETTING("MWFrontEnd_C_poolstrings", "1"), + SETTING("MWFrontEnd_C_dontreusestrings", "0") ] def generate(self, line_list, level=4): @@ -841,18 +841,18 @@ def __init__(self, defines): """ definestring = [] for item in defines: - definestring.append('#define ' + item) + definestring.append("#define " + item) self.settings = [ - SETTING('C_CPP_Preprocessor_PrefixText', definestring), - SETTING('C_CPP_Preprocessor_MultiByteEncoding', 'encASCII_Unicode'), - SETTING('C_CPP_Preprocessor_PCHUsesPrefixText', 'false'), - SETTING('C_CPP_Preprocessor_EmitPragmas', 'true'), - SETTING('C_CPP_Preprocessor_KeepWhiteSpace', 'false'), - SETTING('C_CPP_Preprocessor_EmitFullPath', 'false'), - SETTING('C_CPP_Preprocessor_KeepComments', 'false'), - SETTING('C_CPP_Preprocessor_EmitFile', 'true'), - SETTING('C_CPP_Preprocessor_EmitLine', 'false') + SETTING("C_CPP_Preprocessor_PrefixText", definestring), + SETTING("C_CPP_Preprocessor_MultiByteEncoding", "encASCII_Unicode"), + SETTING("C_CPP_Preprocessor_PCHUsesPrefixText", "false"), + SETTING("C_CPP_Preprocessor_EmitPragmas", "true"), + SETTING("C_CPP_Preprocessor_KeepWhiteSpace", "false"), + SETTING("C_CPP_Preprocessor_EmitFullPath", "false"), + SETTING("C_CPP_Preprocessor_KeepComments", "false"), + SETTING("C_CPP_Preprocessor_EmitFile", "true"), + SETTING("C_CPP_Preprocessor_EmitLine", "false") ] def generate(self, line_list, level=4): @@ -876,30 +876,30 @@ def __init__(self): Initialize """ self.settings = [ - SETTING('MWWarning_C_warn_illpragma', '1'), - SETTING('MWWarning_C_warn_possunwant', '1'), - SETTING('MWWarning_C_pedantic', '1'), - SETTING('MWWarning_C_warn_illtokenpasting', '0'), - SETTING('MWWarning_C_warn_hidevirtual', '1'), - SETTING('MWWarning_C_warn_implicitconv', '1'), - SETTING('MWWarning_C_warn_impl_f2i_conv', '1'), - SETTING('MWWarning_C_warn_impl_s2u_conv', '1'), - SETTING('MWWarning_C_warn_impl_i2f_conv', '1'), - SETTING('MWWarning_C_warn_ptrintconv', '1'), - SETTING('MWWarning_C_warn_unusedvar', '1'), - SETTING('MWWarning_C_warn_unusedarg', '1'), - SETTING('MWWarning_C_warn_resultnotused', '0'), - SETTING('MWWarning_C_warn_missingreturn', '1'), - SETTING('MWWarning_C_warn_no_side_effect', '1'), - SETTING('MWWarning_C_warn_extracomma', '1'), - SETTING('MWWarning_C_warn_structclass', '1'), - SETTING('MWWarning_C_warn_emptydecl', '1'), - SETTING('MWWarning_C_warn_filenamecaps', '0'), - SETTING('MWWarning_C_warn_filenamecapssystem', '0'), - SETTING('MWWarning_C_warn_padding', '0'), - SETTING('MWWarning_C_warn_undefmacro', '0'), - SETTING('MWWarning_C_warn_notinlined', '0'), - SETTING('MWWarning_C_warningerrors', '0') + SETTING("MWWarning_C_warn_illpragma", "1"), + SETTING("MWWarning_C_warn_possunwant", "1"), + SETTING("MWWarning_C_pedantic", "1"), + SETTING("MWWarning_C_warn_illtokenpasting", "0"), + SETTING("MWWarning_C_warn_hidevirtual", "1"), + SETTING("MWWarning_C_warn_implicitconv", "1"), + SETTING("MWWarning_C_warn_impl_f2i_conv", "1"), + SETTING("MWWarning_C_warn_impl_s2u_conv", "1"), + SETTING("MWWarning_C_warn_impl_i2f_conv", "1"), + SETTING("MWWarning_C_warn_ptrintconv", "1"), + SETTING("MWWarning_C_warn_unusedvar", "1"), + SETTING("MWWarning_C_warn_unusedarg", "1"), + SETTING("MWWarning_C_warn_resultnotused", "0"), + SETTING("MWWarning_C_warn_missingreturn", "1"), + SETTING("MWWarning_C_warn_no_side_effect", "1"), + SETTING("MWWarning_C_warn_extracomma", "1"), + SETTING("MWWarning_C_warn_structclass", "1"), + SETTING("MWWarning_C_warn_emptydecl", "1"), + SETTING("MWWarning_C_warn_filenamecaps", "0"), + SETTING("MWWarning_C_warn_filenamecapssystem", "0"), + SETTING("MWWarning_C_warn_padding", "0"), + SETTING("MWWarning_C_warn_undefmacro", "0"), + SETTING("MWWarning_C_warn_notinlined", "0"), + SETTING("MWWarning_C_warningerrors", "0") ] def generate(self, line_list, level=4): @@ -922,32 +922,32 @@ def __init__(self, configuration): """ Initialize """ - if configuration == 'Debug': - disableopt = '1' - optimizeasm = '0' + if configuration == "Debug": + disableopt = "1" + optimizeasm = "0" else: - disableopt = '0' - optimizeasm = '1' + disableopt = "0" + optimizeasm = "1" self.settings = [ - SETTING('MWCodeGen_X86_processor', 'PentiumIV'), - SETTING('MWCodeGen_X86_use_extinst', '1'), - SETTING('MWCodeGen_X86_extinst_mmx', '0'), - SETTING('MWCodeGen_X86_extinst_3dnow', '0'), - SETTING('MWCodeGen_X86_extinst_cmov', '1'), - SETTING('MWCodeGen_X86_extinst_sse', '0'), - SETTING('MWCodeGen_X86_extinst_sse2', '0'), - SETTING('MWCodeGen_X86_use_mmx_3dnow_convention', '0'), - SETTING('MWCodeGen_X86_vectorize', '0'), - SETTING('MWCodeGen_X86_profile', '0'), - SETTING('MWCodeGen_X86_readonlystrings', '1'), - SETTING('MWCodeGen_X86_alignment', 'bytes8'), - SETTING('MWCodeGen_X86_intrinsics', '1'), - SETTING('MWCodeGen_X86_optimizeasm', optimizeasm), - SETTING('MWCodeGen_X86_disableopts', disableopt), - SETTING('MWCodeGen_X86_relaxieee', '1'), - SETTING('MWCodeGen_X86_exceptions', 'ZeroOverhead'), - SETTING('MWCodeGen_X86_name_mangling', 'MWWin32') + SETTING("MWCodeGen_X86_processor", "PentiumIV"), + SETTING("MWCodeGen_X86_use_extinst", "1"), + SETTING("MWCodeGen_X86_extinst_mmx", "0"), + SETTING("MWCodeGen_X86_extinst_3dnow", "0"), + SETTING("MWCodeGen_X86_extinst_cmov", "1"), + SETTING("MWCodeGen_X86_extinst_sse", "0"), + SETTING("MWCodeGen_X86_extinst_sse2", "0"), + SETTING("MWCodeGen_X86_use_mmx_3dnow_convention", "0"), + SETTING("MWCodeGen_X86_vectorize", "0"), + SETTING("MWCodeGen_X86_profile", "0"), + SETTING("MWCodeGen_X86_readonlystrings", "1"), + SETTING("MWCodeGen_X86_alignment", "bytes8"), + SETTING("MWCodeGen_X86_intrinsics", "1"), + SETTING("MWCodeGen_X86_optimizeasm", optimizeasm), + SETTING("MWCodeGen_X86_disableopts", disableopt), + SETTING("MWCodeGen_X86_relaxieee", "1"), + SETTING("MWCodeGen_X86_exceptions", "ZeroOverhead"), + SETTING("MWCodeGen_X86_name_mangling", "MWWin32") ] def generate(self, line_list, level=4): @@ -970,14 +970,14 @@ def __init__(self, configuration): """ Initialize """ - if configuration == 'Debug': - level = 'Level0' + if configuration == "Debug": + level = "Level0" else: - level = 'Level4' + level = "Level4" self.settings = [ - SETTING('GlobalOptimizer_X86__optimizationlevel', level), - SETTING('GlobalOptimizer_X86__optfor', 'Size') + SETTING("GlobalOptimizer_X86__optimizationlevel", level), + SETTING("GlobalOptimizer_X86__optfor", "Size") ] def generate(self, line_list, level=4): @@ -1001,24 +1001,24 @@ def __init__(self): Initialize """ self.settings = [ - SETTING('PDisasmX86_showHeaders', 'true'), - SETTING('PDisasmX86_showSectHeaders', 'true'), - SETTING('PDisasmX86_showSymTab', 'true'), - SETTING('PDisasmX86_showCode', 'true'), - SETTING('PDisasmX86_showData', 'true'), - SETTING('PDisasmX86_showDebug', 'false'), - SETTING('PDisasmX86_showExceptions', 'false'), - SETTING('PDisasmX86_showRelocation', 'true'), - SETTING('PDisasmX86_showRaw', 'false'), - SETTING('PDisasmX86_showAllRaw', 'false'), - SETTING('PDisasmX86_showSource', 'false'), - SETTING('PDisasmX86_showHex', 'true'), - SETTING('PDisasmX86_showComments', 'false'), - SETTING('PDisasmX86_resolveLocals', 'false'), - SETTING('PDisasmX86_resolveRelocs', 'true'), - SETTING('PDisasmX86_showSymDefs', 'true'), - SETTING('PDisasmX86_unmangle', 'false'), - SETTING('PDisasmX86_verbose', 'false') + SETTING("PDisasmX86_showHeaders", "true"), + SETTING("PDisasmX86_showSectHeaders", "true"), + SETTING("PDisasmX86_showSymTab", "true"), + SETTING("PDisasmX86_showCode", "true"), + SETTING("PDisasmX86_showData", "true"), + SETTING("PDisasmX86_showDebug", "false"), + SETTING("PDisasmX86_showExceptions", "false"), + SETTING("PDisasmX86_showRelocation", "true"), + SETTING("PDisasmX86_showRaw", "false"), + SETTING("PDisasmX86_showAllRaw", "false"), + SETTING("PDisasmX86_showSource", "false"), + SETTING("PDisasmX86_showHex", "true"), + SETTING("PDisasmX86_showComments", "false"), + SETTING("PDisasmX86_resolveLocals", "false"), + SETTING("PDisasmX86_resolveRelocs", "true"), + SETTING("PDisasmX86_showSymDefs", "true"), + SETTING("PDisasmX86_unmangle", "false"), + SETTING("PDisasmX86_verbose", "false") ] def generate(self, line_list, level=4): @@ -1042,26 +1042,26 @@ def __init__(self): Initialize """ self.settings = [ - SETTING('MWLinker_X86_runtime', 'Custom'), - SETTING('MWLinker_X86_linksym', '0'), - SETTING('MWLinker_X86_linkCV', '1'), - SETTING('MWLinker_X86_symfullpath', 'false'), - SETTING('MWLinker_X86_linkdebug', 'true'), - SETTING('MWLinker_X86_debuginline', 'true'), - SETTING('MWLinker_X86_subsystem', 'Unknown'), - SETTING('MWLinker_X86_entrypointusage', 'Default'), - SETTING('MWLinker_X86_entrypoint', ''), - SETTING('MWLinker_X86_codefolding', 'Any'), - SETTING('MWLinker_X86_usedefaultlibs', 'true'), - SETTING('MWLinker_X86_adddefaultlibs', 'false'), - SETTING('MWLinker_X86_mergedata', 'true'), - SETTING('MWLinker_X86_zero_init_bss', 'false'), - SETTING('MWLinker_X86_generatemap', '0'), - SETTING('MWLinker_X86_checksum', 'false'), - SETTING('MWLinker_X86_linkformem', 'false'), - SETTING('MWLinker_X86_nowarnings', 'false'), - SETTING('MWLinker_X86_verbose', 'false'), - SETTING('MWLinker_X86_commandfile', '') + SETTING("MWLinker_X86_runtime", "Custom"), + SETTING("MWLinker_X86_linksym", "0"), + SETTING("MWLinker_X86_linkCV", "1"), + SETTING("MWLinker_X86_symfullpath", "false"), + SETTING("MWLinker_X86_linkdebug", "true"), + SETTING("MWLinker_X86_debuginline", "true"), + SETTING("MWLinker_X86_subsystem", "Unknown"), + SETTING("MWLinker_X86_entrypointusage", "Default"), + SETTING("MWLinker_X86_entrypoint", ""), + SETTING("MWLinker_X86_codefolding", "Any"), + SETTING("MWLinker_X86_usedefaultlibs", "true"), + SETTING("MWLinker_X86_adddefaultlibs", "false"), + SETTING("MWLinker_X86_mergedata", "true"), + SETTING("MWLinker_X86_zero_init_bss", "false"), + SETTING("MWLinker_X86_generatemap", "0"), + SETTING("MWLinker_X86_checksum", "false"), + SETTING("MWLinker_X86_linkformem", "false"), + SETTING("MWLinker_X86_nowarnings", "false"), + SETTING("MWLinker_X86_verbose", "false"), + SETTING("MWLinker_X86_commandfile", "") ] def generate(self, line_list, level=4): @@ -1089,19 +1089,19 @@ def __init__(self, platform, configuration, filename): """ if platform.is_windows(): self.filename = convert_to_windows_slashes(filename) - self.format = 'Windows' + self.format = "Windows" else: self.filename = convert_to_linux_slashes(filename) - self.format = 'Unix' + self.format = "Unix" - self.flags = '' - if self.filename.endswith('.lib') or self.filename.endswith('.a'): - self.kind = 'Library' + self.flags = "" + if self.filename.endswith(".lib") or self.filename.endswith(".a"): + self.kind = "Library" else: - self.kind = 'Text' - if configuration != 'Release' and \ - self.filename.endswith(('.c', '.cpp')): - self.flags = 'Debug' + self.kind = "Text" + if configuration != "Release" and \ + self.filename.endswith((".c", ".cpp")): + self.flags = "Debug" def generate(self, line_list, level=4): """ @@ -1109,14 +1109,14 @@ def generate(self, line_list, level=4): """ tabs = TAB * level tabs2 = tabs + TAB - line_list.append(tabs + '') - line_list.append(tabs2 + 'Name') - line_list.append(tabs2 + '' + self.filename + '') - line_list.append(tabs2 + '' + \ - self.format + '') - line_list.append(tabs2 + '' + self.kind + '') - line_list.append(tabs2 + '' + self.flags + '') - line_list.append(tabs + '') + line_list.append(tabs + "") + line_list.append(tabs2 + "Name") + line_list.append(tabs2 + "" + self.filename + "") + line_list.append(tabs2 + "" + \ + self.format + "") + line_list.append(tabs2 + "" + self.kind + "") + line_list.append(tabs2 + "" + self.flags + "") + line_list.append(tabs + "") class FILEREF(object): @@ -1136,10 +1136,10 @@ def __init__(self, platform, configuration, filename): self.configuration = configuration if platform.is_windows(): self.filename = convert_to_windows_slashes(filename) - self.format = 'Windows' + self.format = "Windows" else: self.filename = convert_to_linux_slashes(filename) - self.format = 'Unix' + self.format = "Unix" def generate(self, line_list, level=4): """ @@ -1147,17 +1147,17 @@ def generate(self, line_list, level=4): """ tabs = TAB * level tabs2 = tabs + TAB - line_list.append(tabs + '') + line_list.append(tabs + "") if self.configuration is not None: line_list.append(tabs2 + - '' + + "" + str(self.configuration) + - '') - line_list.append(tabs2 + 'Name') - line_list.append(tabs2 + '' + self.filename + '') - line_list.append(tabs2 + '' + \ - self.format + '') - line_list.append(tabs + '') + "") + line_list.append(tabs2 + "Name") + line_list.append(tabs2 + "" + self.filename + "") + line_list.append(tabs2 + "" + \ + self.format + "") + line_list.append(tabs + "") class GROUP(object): @@ -1203,16 +1203,16 @@ def generate(self, line_list, level=2): Generate output """ if level == 1: - groupstring = 'GROUPLIST' + groupstring = "GROUPLIST" else: - groupstring = 'GROUP' + groupstring = "GROUP" tabs = TAB * level - entry = tabs + '<' + groupstring + '>' + entry = tabs + "<" + groupstring + ">" if self.name is not None: - entry = entry + '' + self.name + '' + entry = entry + "" + self.name + "" line_list.append(entry) - groups = sorted(self.groups, key=operator.attrgetter('name')) + groups = sorted(self.groups, key=operator.attrgetter("name")) for item in groups: item.generate(line_list, level + 1) @@ -1221,7 +1221,7 @@ def generate(self, line_list, level=2): key=lambda s: s.filename.lower()) for item in filerefs: item.generate(line_list, level + 1) - line_list.append(tabs + '') + line_list.append(tabs + "") class SUBTARGET(object): @@ -1244,12 +1244,12 @@ def generate(self, line_list, level=4): """ tabs = TAB * level tabs2 = tabs + TAB - line_list.append(tabs + '') + line_list.append(tabs + "") line_list.append(tabs2 + - '' + + "" + str(self.target.name) + - '') - line_list.append(tabs + '') + "") + line_list.append(tabs + "") class TARGET(object): @@ -1280,8 +1280,8 @@ def __init__(self, name, linker): self.linker = linker self.settinglist = [ SETTING( - 'Linker', linker), SETTING( - 'Targetname', name)] + "Linker", linker), SETTING( + "Targetname", name)] self.filelist = [] self.linkorder = [] self.subtargetlist = [] @@ -1307,30 +1307,30 @@ def generate(self, line_list, level=2): """ tabs = TAB * level tabs2 = tabs + TAB - line_list.append(tabs + '') - line_list.append(tabs2 + '' + str(self.name) + '') + line_list.append(tabs + "") + line_list.append(tabs2 + "" + str(self.name) + "") - line_list.append(tabs2 + '') + line_list.append(tabs2 + "") for item in self.settinglist: item.generate(line_list, level + 2) - line_list.append(tabs2 + '') + line_list.append(tabs2 + "") - line_list.append(tabs2 + '') + line_list.append(tabs2 + "") for item in self.filelist: item.generate(line_list, level + 2) - line_list.append(tabs2 + '') + line_list.append(tabs2 + "") - line_list.append(tabs2 + '') + line_list.append(tabs2 + "") for item in self.linkorder: item.generate(line_list, level + 2) - line_list.append(tabs2 + '') + line_list.append(tabs2 + "") - line_list.append(tabs2 + '') + line_list.append(tabs2 + "") for item in self.subtargetlist: item.generate(line_list, level + 2) - line_list.append(tabs2 + '') + line_list.append(tabs2 + "") - line_list.append(tabs + '') + line_list.append(tabs + "") class ORDEREDTARGET(object): @@ -1353,9 +1353,9 @@ def generate(self, line_list, level=2): """ tabs = TAB * level line_list.append(tabs + - '' + + "" + str(self.target.name) + - '') + "") class Project(object): @@ -1464,32 +1464,32 @@ def __init__(self, solution, projectname=None, target.settinglist.append( SearchPath( configuration.platform, - 'bin', - 'Project', - 'OutputDirectory')) + "bin", + "Project", + "OutputDirectory")) # User include folders temp_list = configuration.get_unique_chained_list( - '_source_include_list') + "_source_include_list") temp_list.extend(configuration.get_unique_chained_list( - 'include_folders_list')) + "include_folders_list")) if temp_list: - usersearchpaths = target.addsetting('UserSearchPaths') + usersearchpaths = target.addsetting("UserSearchPaths") for item in temp_list: entry = usersearchpaths.addsetting() entry.subsettings.append( SearchPathAndFlags( configuration.platform, item, - 'Project', + "Project", False)) # System include folders temp_list = configuration.get_unique_chained_list( "_library_folders_list") if temp_list: - systemsearchpaths = target.addsetting('SystemSearchPaths') + systemsearchpaths = target.addsetting("SystemSearchPaths") for item in temp_list: entry = systemsearchpaths.addsetting() entry.subsettings.append( @@ -1504,7 +1504,7 @@ def __init__(self, solution, projectname=None, # C/C++ Language target.settinglist.append(MWFrontEnd_C()) - definelist = configuration.get_chained_list('define_list') + definelist = configuration.get_chained_list("define_list") # C/C++ Preprocessor target.settinglist.append(C_CPP_Preprocessor(definelist)) # C/C++ Warnings @@ -1647,66 +1647,66 @@ def generate(self, line_list=None): # Write out the XML description template line_list.extend([ - '', - ''), - '', - (''), - '', - '', - '', - '', - (''), - '', - '', - '', - '', - (''), - '', - '', - (''), - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - ']>', - '' + "", + ""), + "", + (""), + "", + "", + "", + "", + (""), + "", + "", + "", + "", + (""), + "", + "", + (""), + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "]>", + "" ]) # Start the project diff --git a/makeprojects/defaults.py b/makeprojects/defaults.py index 0d211a8..3b1db10 100644 --- a/makeprojects/defaults.py +++ b/makeprojects/defaults.py @@ -247,6 +247,9 @@ def configuration_presets(configuration): libraries_list.extend( ["pixEvt.lib", "d3d11_x.lib", "combase.lib", "kernelx.lib", "uuid.lib", "%(XboxExtensionsDependencies)"]) + define_list.extend(["_XM_F16C_INTRINSICS_", + "WINAPI_FAMILY=WINAPI_FAMILY_TV_TITLE", + "__WRL_NO_DEFAULT_LIB__"]) # Nintendo DSI specific defines if platform is PlatformTypes.dsi: @@ -269,10 +272,16 @@ def configuration_presets(configuration): # Nintendo WiiU if platform is PlatformTypes.wiiu: - configuration.include_folders_list.append( - "$(CAFE_ROOT_DOS)\\system\\src\\tool\\gfx\\include") - configuration.include_folders_list.append( - "$(CAFE_ROOT_DOS)\\system\\include") + configuration.include_folders_list.extend(( + "$(CAFE_ROOT)\\system\\src\\tool\\gfx\\include", + "$(CAFE_ROOT)\\system\\include")) + libraries_list.append("nn_act.a") + if configuration.debug: + configuration.library_folders_list.append( + "$(CAFE_ROOT)\\system\\lib\\ghs\\cafe\\DEBUG") + else: + configuration.library_folders_list.append( + "$(CAFE_ROOT)\\system\\lib\\ghs\\cafe\\NDEBUG") # Nintendo Switch if platform.is_switch(): @@ -293,13 +302,17 @@ def configuration_presets(configuration): define_list.append("NN_ENABLE_ASSERT") define_list.append("NN_ENABLE_ABORT_MESSAGE") if configuration.optimization: + configuration.switch_build_type = "Develop" define_list.append("NN_SDK_BUILD_DEVELOP") else: + configuration.switch_build_type = "Debug" define_list.append("NN_SDK_BUILD_DEBUG") else: + configuration.switch_build_type = "Release" define_list.append("NN_SDK_BUILD_RELEASE") define_list.append("NN_DISABLE_ASSERT") define_list.append("NN_DISABLE_ABORT_MESSAGE") + define_list.append("ALLOW_OLD_MEM_FUNCS") # Linux platform if platform is PlatformTypes.linux: @@ -408,7 +421,9 @@ def get_project_type(build_rules_list, verbose=False, project_type=None): item = ProjectTypes.lookup(project_type) if not isinstance(item, ProjectTypes): print( - "Project Type \"{}\" is not supported, using \"tool\".".format(project_type)) + "Project Type \"{}\" is not supported, " + "using \"tool\".".format( + project_type)) project_type = ProjectTypes.tool else: project_type = item @@ -454,7 +469,8 @@ def get_platform(build_rules_list, verbose=False, platform=None): item = PlatformTypes.lookup(platform) if not isinstance(item, PlatformTypes): print( - "Platform Type \"{}\" is not supported, using a default.".format(platform)) + "Platform Type \"{}\" is not supported, " + "using a default.".format(platform)) platform = PlatformTypes.default() else: platform = item @@ -554,7 +570,8 @@ def get_ide(build_rules_list, verbose=False, ide=None, platform=None): ide = guess_ide(platform) if not ide: print( - "IDE Type \"{}\" is not supported, using a default.".format(ide)) + "IDE Type \"{}\" is not supported, " + "using a default.".format(ide)) ide = IDETypes.default() else: ide = item diff --git a/makeprojects/enums.py b/makeprojects/enums.py index 858664f..e9df123 100644 --- a/makeprojects/enums.py +++ b/makeprojects/enums.py @@ -175,10 +175,11 @@ class FileTypes(IntEnum): a65 = 21 ppc = 22 a68 = 23 - image = 24 - ico = 25 - icns = 26 - appxmanifest = 27 + s = 24 + image = 25 + ico = 26 + icns = 27 + appxmanifest = 28 @staticmethod def lookup(test_name): @@ -263,6 +264,7 @@ def __str__(self): "a65": FileTypes.a65, # 6502/65816 source code "ppc": FileTypes.ppc, # PowerPC source code "a68": FileTypes.a68, # 680x0 source code + "s": FileTypes.s, # Generic assembly code "ico": FileTypes.ico, # Windows icon file "icns": FileTypes.icns, # Mac OSX Icon file "png": FileTypes.image, # Art files @@ -304,6 +306,7 @@ def __str__(self): FileTypes.a65: "6502/65816 assembly file", FileTypes.ppc: "PowerPC assembly file", FileTypes.a68: "680x0 assembly file", + FileTypes.s: "Generic assembly file", FileTypes.image: "Image file", FileTypes.ico: "Windows Icon file", FileTypes.icns: "macOS Icon file", @@ -344,6 +347,39 @@ def source_file_filter(file_list, file_type_list): ######################################## +def source_file_detect(file_list, file_type_list): + """ + Detect if a file of a specific type exists + + Note: file_type_list can either be a single enums.FileTypes enum or an + iterable list of enums.FileTypes + + Args: + file_list: list of core.SourceFile entries. + file_type_list: enums.FileTypes to match. + Returns: + True if the FileTypes was found, False if not + """ + + # If a single item was passed, use a simple loop + if isinstance(file_type_list, FileTypes): + for item in file_list: + if item.type is file_type_list: + + # Matched! + return True + else: + # A list was passed, so test against the list + for item in file_list: + if item.type in file_type_list: + + # Matched! + return True + return False + +######################################## + + class ProjectTypes(IntEnum): """ Enumeration of supported project types @@ -611,7 +647,8 @@ def is_xcode(self): return self in ( IDETypes.xcode3, IDETypes.xcode4, IDETypes.xcode5, IDETypes.xcode6, IDETypes.xcode7, IDETypes.xcode8, IDETypes.xcode9, IDETypes.xcode10, - IDETypes.xcode11, IDETypes.xcode12, IDETypes.xcode13, IDETypes.xcode14) + IDETypes.xcode11, IDETypes.xcode12, IDETypes.xcode13, + IDETypes.xcode14) ######################################## @@ -897,9 +934,9 @@ class PlatformTypes(IntEnum): macosxintel64: Mac OSX Intel 64 bit only macosxarm64: Mac OSX ARM 64 bit only - macos9: Mac OS 9, all CPUs - macos968k: Mac OS 9 680x0 only - macos9ppc: Mac OS 9 PowerPC 32 bit only + macos: Mac OS 7-9, all CPUs + macos68k: Mac OS 7-9 680x0 only + macosppc: Mac OS 7-9 PowerPC 32 bit only maccarbon: Mac OS Carbon, all CPUs maccarbon68k: Mac OS Carbon 680x0 only (CFM) maccarbonppc: Mac OS Carbon PowerPC 32 bit only @@ -957,79 +994,87 @@ class PlatformTypes(IntEnum): # pylint: disable=too-many-public-methods - windows = 0 - windowsintel = 1 - windowsarm = 2 - win32 = 3 - win64 = 4 - winarm32 = 5 - winarm64 = 6 - winitanium = 7 - - macosx = 8 - macosxppc32 = 9 - macosxppc64 = 10 - macosxintel32 = 11 - macosxintel64 = 12 - macosxarm64 = 13 - - macos9 = 14 - macos968k = 15 - macos9ppc = 16 - maccarbon = 17 - maccarbon68k = 18 - maccarbonppc = 19 - - ios = 20 - ios32 = 21 - ios64 = 22 - iosemu = 23 - iosemu32 = 24 - iosemu64 = 25 - - xbox = 26 - xbox360 = 27 - xboxone = 28 - xboxgdk = 29 - xboxonex = 30 - - ps1 = 31 - ps2 = 32 - ps3 = 33 - ps4 = 34 - ps5 = 35 - psp = 36 - vita = 37 - - wii = 38 - wiiu = 39 - switch = 40 - switch32 = 41 - switch64 = 42 - - dsi = 43 - ds = 44 - - stadia = 45 - android = 46 - shield = 47 - amico = 48 - ouya = 49 - tegra = 50 - androidarm32 = 51 - androidarm64 = 52 - androidintel32 = 53 - androidintel64 = 54 - - linux = 55 - - msdos = 56 - msdos4gw = 57 - msdosx32 = 58 - - beos = 59 - - iigs = 60 + msdos = 0 + msdos4gw = 1 + msdosx32 = 2 + + beos = 3 + + iigs = 4 + + xbox = 5 + xbox360 = 6 + xboxone = 7 + xboxgdk = 8 + xboxonex = 9 + + ps1 = 10 + ps2 = 11 + ps3 = 12 + ps4 = 13 + ps5 = 14 + psp = 15 + vita = 16 + + wii = 17 + wiiu = 18 + switch = 19 + switch32 = 20 + switch64 = 21 + + dsi = 22 + ds = 23 + + windows = 24 + windowsintel = 25 + windowsarm = 26 + win32 = 27 + win64 = 28 + winarm32 = 29 + winarm64 = 30 + winitanium = 31 + + macosx = 32 + macosxppc32 = 33 + macosxppc64 = 34 + macosxintel32 = 35 + macosxintel64 = 36 + macosxarm64 = 37 + + ios = 38 + iosemu = 39 + ios32 = 40 + ios64 = 41 + iosemu32 = 42 + iosemu64 = 43 + + mac = 44 + mac68k = 45 + macppc = 46 + macclassic = 47 + maccarbon = 48 + + mac68knear = 49 + mac68knearfp = 50 + mac68kfar = 51 + mac68kfarfp = 52 + mac68kcarbon = 53 + + macppcclassic = 54 + macppccarbon = 55 + + stadia = 56 + android = 57 + shield = 58 + amico = 59 + ouya = 60 + tegra = 61 + androidarm32 = 62 + androidarm64 = 63 + androidintel32 = 64 + androidintel64 = 65 + + linux = 66 def get_short_code(self): """ @@ -1069,8 +1114,9 @@ def is_xbox(self): True if the platform is for Xbox, Xbox 360, or Xbox ONE. """ - return self in (PlatformTypes.xbox, PlatformTypes.xbox360, - PlatformTypes.xboxone, PlatformTypes.xboxgdk, PlatformTypes.xboxonex) + return self in ( + PlatformTypes.xbox, PlatformTypes.xbox360, PlatformTypes.xboxone, + PlatformTypes.xboxgdk, PlatformTypes.xboxonex) def is_xboxone(self): """ @@ -1080,7 +1126,8 @@ def is_xboxone(self): True if the platform is for Xbox ONE. """ - return self in (PlatformTypes.xboxone, PlatformTypes.xboxgdk, PlatformTypes.xboxonex) + return self in (PlatformTypes.xboxone, + PlatformTypes.xboxgdk, PlatformTypes.xboxonex) def is_microsoft(self): """ @@ -1136,6 +1183,27 @@ def is_macos(self): return self.is_macos_classic() or self.is_macos_carbon() + def is_macos_68k(self): + """ + Determine if the platform is MacOS 68K. + + Returns: + True if Apple MacOS 1.0 through 8.1 using the 68k processor + """ + return self in (PlatformTypes.mac68knear, PlatformTypes.mac68knearfp, + PlatformTypes.mac68kfar, PlatformTypes.mac68kfarfp, + PlatformTypes.mac68kcarbon, PlatformTypes.mac68k) + + def is_macos_ppc(self): + """ + Determine if the platform is MacOS PowerPC. + + Returns: + True if Apple MacOS 7.0 through 9.2.2 using the PowerPC processor + """ + return self in (PlatformTypes.macppcclassic, PlatformTypes.macppccarbon, + PlatformTypes.macppc) + def is_macos_carbon(self): """ Determine if the platform is MacOS Carbon. @@ -1143,8 +1211,8 @@ def is_macos_carbon(self): Returns: True if the platform is Apple MacOS Carbon API. """ - return self in (PlatformTypes.maccarbon, PlatformTypes.maccarbon68k, - PlatformTypes.maccarbonppc) + return self in (PlatformTypes.maccarbon, PlatformTypes.mac68kcarbon, + PlatformTypes.macppccarbon) def is_macos_classic(self): """ @@ -1153,8 +1221,11 @@ def is_macos_classic(self): Returns: True if the platform is Apple MacOS 1.0 through 9.2.2. """ - return self in (PlatformTypes.macos9, - PlatformTypes.macos968k, PlatformTypes.macos9ppc) + return self in (PlatformTypes.mac, PlatformTypes.macclassic, + PlatformTypes.mac68k, PlatformTypes.macppc, + PlatformTypes.mac68knear, PlatformTypes.mac68knearfp, + PlatformTypes.mac68kfar, PlatformTypes.mac68kfarfp, + PlatformTypes.macppcclassic) def is_msdos(self): """ @@ -1196,8 +1267,9 @@ def is_nintendo(self): Returns: True if it's a Nintendo platform """ - return self.is_switch() or self in (PlatformTypes.wii, PlatformTypes.wiiu, - PlatformTypes.ds, PlatformTypes.dsi) + return self.is_switch() or self in ( + PlatformTypes.wii, PlatformTypes.wiiu, PlatformTypes.ds, + PlatformTypes.dsi) def is_sony(self): """ @@ -1289,7 +1361,19 @@ def match(self, second): return self.is_macosx() == second.is_macosx() # Test macos 1.0 - 9.2.2 - if PlatformTypes.macos9 in (self, second): + if PlatformTypes.mac in (self, second): + return self.is_macos() == second.is_macos() + + # Test macos 68K + if PlatformTypes.mac68k in (self, second): + return self.is_macos_68k() == second.is_macos_68k() + + # Test macos PowerPC + if PlatformTypes.macppc in (self, second): + return self.is_macos_ppc() == second.is_macos_ppc() + + # Test macos classic + if PlatformTypes.macclassic in (self, second): return self.is_macos_classic() == second.is_macos_classic() # Test macos Carbon @@ -1390,7 +1474,10 @@ def lookup(platform_name): return item specials = { - "macos": PlatformTypes.macos9, + "macos": PlatformTypes.macosx, + "macos7": PlatformTypes.mac, + "macos8": PlatformTypes.mac, + "macos9": PlatformTypes.macppc, "carbon": PlatformTypes.maccarbon, "scarlett": PlatformTypes.xboxonex } @@ -1457,12 +1544,18 @@ def __str__(self): PlatformTypes.macosxintel32: "osxx86", PlatformTypes.macosxintel64: "osxx64", PlatformTypes.macosxarm64: "osxa64", - PlatformTypes.macos9: "mac", # Mac OS targets (Pre-OSX) - PlatformTypes.macos968k: "mac68k", - PlatformTypes.macos9ppc: "macppc", + PlatformTypes.mac: "mac", # Mac OS targets (Pre-OSX) + PlatformTypes.mac68k: "mac68k", + PlatformTypes.macppc: "macppc", + PlatformTypes.macclassic: "mac", PlatformTypes.maccarbon: "car", - PlatformTypes.maccarbon68k: "car68k", - PlatformTypes.maccarbonppc: "carppc", + PlatformTypes.mac68knear: "mac68k", + PlatformTypes.mac68knearfp: "mac68kfp", + PlatformTypes.mac68kfar: "mac68kfar", + PlatformTypes.mac68kfarfp: "mac68kfarfp", + PlatformTypes.mac68kcarbon: "car68k", + PlatformTypes.macppcclassic: "macppc", + PlatformTypes.macppccarbon: "carppc", PlatformTypes.ios: "ios", # iOS targets PlatformTypes.ios32: "iosa32", PlatformTypes.ios64: "iosa64", @@ -1573,12 +1666,18 @@ def __str__(self): PlatformTypes.macosxarm64: "Apple macOS ARM 64", # Mac OS targets (Pre-OSX) - PlatformTypes.macos9: "Apple MacOS 9 PPC and 68k", - PlatformTypes.macos968k: "Apple MacOS 9 68k", - PlatformTypes.macos9ppc: "Apple MacOS 9 PowerPC 32", + PlatformTypes.mac: "Apple MacOS PPC and 68k", + PlatformTypes.mac68k: "Apple MacOS 68k", + PlatformTypes.macppc: "Apple MacOS PowerPC", + PlatformTypes.macclassic: "Apple MacOS Classic", PlatformTypes.maccarbon: "Apple MacOS Carbon", - PlatformTypes.maccarbon68k: "Apple MacOS Carbon 68k", - PlatformTypes.maccarbonppc: "Apple MacOS Carbon PowerPC 32", + PlatformTypes.mac68knear: "Apple MacOS 68k", + PlatformTypes.mac68knearfp: "Apple MacOS 68k w/68881", + PlatformTypes.mac68kfar: "Apple MacOS 68k far", + PlatformTypes.mac68kfarfp: "Apple MacOS 68k far w/68881", + PlatformTypes.mac68kcarbon: "Apple MacOS CFM 68k", + PlatformTypes.macppcclassic: "Apple MacOS Classic PowerPC", + PlatformTypes.macppccarbon: "Apple MacOS Carbon PowerPC", # iOS targets PlatformTypes.ios: "Apple iOS", @@ -1660,12 +1759,32 @@ def __str__(self): PlatformTypes.macosxintel32, PlatformTypes.macosxintel64, PlatformTypes.macosxarm64), - PlatformTypes.macos9: ( - PlatformTypes.macos968k, - PlatformTypes.macos9ppc), + PlatformTypes.mac: ( + PlatformTypes.mac68knear, + PlatformTypes.mac68knearfp, + PlatformTypes.mac68kfar, + PlatformTypes.mac68kfarfp, + PlatformTypes.mac68kcarbon, + PlatformTypes.macppcclassic, + PlatformTypes.macppccarbon), + PlatformTypes.mac68k: ( + PlatformTypes.mac68knear, + PlatformTypes.mac68knearfp, + PlatformTypes.mac68kfar, + PlatformTypes.mac68kfarfp, + PlatformTypes.mac68kcarbon), + PlatformTypes.macppc: ( + PlatformTypes.macppcclassic, + PlatformTypes.macppccarbon), + PlatformTypes.macclassic: ( + PlatformTypes.mac68knear, + PlatformTypes.mac68knearfp, + PlatformTypes.mac68kfar, + PlatformTypes.mac68kfarfp, + PlatformTypes.macppcclassic), PlatformTypes.maccarbon: ( - PlatformTypes.maccarbon68k, - PlatformTypes.maccarbonppc), + PlatformTypes.mac68kcarbon, + PlatformTypes.macppccarbon), PlatformTypes.ios: ( PlatformTypes.ios32, PlatformTypes.ios64), @@ -1833,4 +1952,6 @@ def add_burgerlib(configuration): platform.get_platform_folder()) configuration.include_folders_list.append(lib_dir) + configuration.env_variable_list.append("BURGER_SDKS") + return 0 diff --git a/makeprojects/glsl_support.py b/makeprojects/glsl_support.py index 4e0e55c..ecbfb2e 100644 --- a/makeprojects/glsl_support.py +++ b/makeprojects/glsl_support.py @@ -25,7 +25,7 @@ # Boolean list for GLSL, Name, Default, switches GLSL_BOOLEANS = ( - ("CPP", (True, "/c", True)), + ("CPP", (True, "-c", True)), ) # String entries for GLSL, Name, default, switch, generates output, quote @@ -34,7 +34,7 @@ ("ObjectFileName", ( "%(RootDir)%(Directory)%(FileName).h", "", True, True)), ("VariableName", ( - "g_%(FileName)", "/l ", False, False)) + "g_%(FileName)", "-l ", False, False)) ) @@ -50,7 +50,7 @@ def make_glsl_command(command_dict, source_file): """ # Create the initial command line - cmd = ["stripcomments.exe", "\"%(FullPath)\""] + cmd = ["stripcomments", "\"%(FullPath)\""] lookup_booleans(cmd, GLSL_BOOLEANS, command_dict) outputs = lookup_strings(cmd, GLSL_STRINGS, command_dict) diff --git a/makeprojects/makefile.py b/makeprojects/makefile.py index 3edcc88..65f025f 100644 --- a/makeprojects/makefile.py +++ b/makeprojects/makefile.py @@ -44,6 +44,7 @@ get_output_template from .build_objects import BuildObject, BuildError from .config import _MAKEFILE_MATCH +from .watcom_util import get_custom_list, get_output_list # List of IDES this module supports SUPPORTED_IDES = (IDETypes.make,) @@ -297,6 +298,9 @@ def generate(solution): if error: return error + # Handle any post processing + makefile_lines = solution.post_process(makefile_lines) + # Save the file if it changed save_text_file_if_newer( os.path.join(solution.working_directory, solution.makefile_filename), @@ -320,6 +324,8 @@ class MakeProject(object): platforms: List of all platform types configuration_list: List of all configurations configuration_names: List of configuration names + custom_list: List of custom built files + output_list: List of custom output files """ def __init__(self, solution): @@ -335,12 +341,19 @@ def __init__(self, solution): self.configuration_list = [] self.configuration_names = [] + # Init the list of custom rules + custom_list = [] + # Process all the projects and configurations for project in solution.project_list: # Process the filenames - project.get_file_list((FileTypes.h, FileTypes.cpp, - FileTypes.c, FileTypes.x86)) + project.get_file_list( + [FileTypes.h, FileTypes.cpp, FileTypes.c, FileTypes.x86, + FileTypes.x64, FileTypes.glsl]) + + # Keep a copy of the filenames for now + codefiles = project.codefiles # Add to the master list self.configuration_list.extend(project.configuration_list) @@ -362,6 +375,15 @@ def __init__(self, solution): if configuration.platform not in self.platforms: self.platforms.append(configuration.platform) + # Get the rule list + rule_list = (configuration.custom_rules, + configuration.parent.custom_rules, + configuration.parent.parent.custom_rules) + get_custom_list(custom_list, rule_list, codefiles) + + self.custom_list = custom_list + self.output_list = get_output_list(custom_list) + ######################################## def write_header(self, line_list): @@ -377,13 +399,50 @@ def write_header(self, line_list): line_list.extend(( "#", "# Build " + self.solution.name + " with make", - "#", "# Generated with makeprojects.makefile", "#")) return 0 ######################################## + def write_output_list(self, line_list): + """ + Output the list of object files to create. + + Args: + line_list: List of lines of text generated. + Returns: + Zero + """ + + line_list.extend([ + "", + "#", + "# Custom output files", + "#", + "" + ]) + + # Get a list of custom files + output_list = self.output_list + if not output_list: + line_list.append("EXTRA_OBJS:=") + return 0 + + colon = "EXTRA_OBJS:= " + for item in output_list: + line_list.append( + colon + + convert_to_linux_slashes( + item) + " \\") + colon = "\t" + + # Remove the " &" from the last line + line_list[-1] = line_list[-1][:-2] + return 0 + + ######################################## + @staticmethod def write_default_goal(line_list): """ @@ -558,6 +617,7 @@ def _write_phony_binaries(self, line_list): "", ".PHONY: clean_" + target_name, "clean_" + target_name + ":", + "\t@-rm -f $(EXTRA_OBJS)", "\t@-rm -rf temp/" + bin_folder, "\t@-rm -f bin/" + bin_name, # Test if the directory is empty, if so, delete the @@ -882,14 +942,13 @@ def _setasmflags(self, line_list): for configuration in self.configuration_list: entries = ["AFlags" + configuration.make_name + ":="] - # Enable debug information - if configuration.debug: - entries.append("-g") - # Add defines define_list = configuration.get_chained_list("define_list") for item in define_list: - entries.append("-D" + item) + if item.find("=") == -1: + entries.append("--defsym " + item + "=1") + else: + entries.append("--defsym " + item) line_list.append(" ".join(entries)) return 0 @@ -986,6 +1045,18 @@ def write_rules(self, line_list): "@echo $(' closing + # Output tag with attributes and support "/>" closing for attribute in self.attributes: - line = '{0} {1}="{2}"'.format(line, + line = "{0} {1}=\"{2}\"".format(line, escape_xml_cdata(attribute[0]), escape_xml_attribute(attribute[1])) if not self.elements and not self.contents: - line_list.append(line + ' />') + line_list.append(line + " />") return line_list # Close the open tag - line = line + '>' + line = line + ">" if self.contents: # contents could be multi-line, deal with it. - lines = escape_xml_cdata(self.contents).split('\n') + lines = escape_xml_cdata(self.contents).split("\n") line = line + lines.pop(0) if lines: line_list.append(line) @@ -534,7 +536,7 @@ def generate(self, line_list=None, indent=0): if not self.elements: line_list.append( - '{0}'.format(line, escape_xml_cdata(self.name))) + "{0}".format(line, escape_xml_cdata(self.name))) return line_list line_list.append(line) @@ -542,7 +544,7 @@ def generate(self, line_list=None, indent=0): for element in self.elements: element.generate(line_list, indent=indent + 1) # Close the current element - line_list.append('{0}'.format(tabs, escape_xml_cdata(self.name))) + line_list.append("{0}".format(tabs, escape_xml_cdata(self.name))) return line_list ######################################## @@ -555,7 +557,7 @@ def __repr__(self): Human readable string or None if the solution is invalid """ - return '\n'.join(self.generate()) + return "\n".join(self.generate()) def __str__(self): """ @@ -588,12 +590,12 @@ def __init__(self, configuration): self.configuration = configuration VS2010XML.__init__( - self, 'ProjectConfiguration', { - 'Include': + self, "ProjectConfiguration", { + "Include": configuration.vs_configuration_name}) - self.add_tag('Configuration', configuration.name) - self.add_tag('Platform', configuration.vs_platform) + self.add_tag("Configuration", configuration.name) + self.add_tag("Platform", configuration.vs_platform) ######################################## @@ -614,8 +616,8 @@ def __init__(self, project): ## Parent project self.project = project - VS2010XML.__init__(self, 'ItemGroup', { - 'Label': 'ProjectConfigurations'}) + VS2010XML.__init__(self, "ItemGroup", { + "Label": "ProjectConfigurations"}) for configuration in project.configuration_list: self.add_element(VS2010ProjectConfiguration(configuration)) @@ -639,8 +641,8 @@ def __init__(self, project): ## Parent project self.project = project - VS2010XML.__init__(self, 'PropertyGroup', { - 'Label': 'NsightTegraProject'}) + VS2010XML.__init__(self, "PropertyGroup", { + "Label": "NsightTegraProject"}) self.add_tag("NsightTegraProjectRevisionNumber", "11") @@ -664,15 +666,15 @@ def __init__(self, project): ## Parent project self.project = project - VS2010XML.__init__(self, 'ImportGroup', {'Label': 'ExtensionTargets'}) + VS2010XML.__init__(self, "ImportGroup", {"Label": "ExtensionTargets"}) for props in project.vs_targets: props = convert_to_windows_slashes(props) self.add_element( VS2010XML( - 'Import', { - 'Project': props, - 'Condition': "exists('{}')".format(props)})) + "Import", { + "Project": props, + "Condition": "exists('{}')".format(props)})) ######################################## @@ -691,12 +693,35 @@ def __init__(self, project): project: Project record to extract defaults. """ + # pylint: disable=too-many-branches + ## Parent project self.project = project VS2010XML.__init__(self, "PropertyGroup", {"Label": "Globals"}) ide = project.ide + # Check for the special case of Xbox ONE + found_xbox = False + if ide >= IDETypes.vs2017: + for configuration in project.configuration_list: + if configuration.platform.is_xbox(): + found_xbox = True + break + + # Xbox ONE needs this entry + if found_xbox: + self.add_tag("ApplicationEnvironment", "title") + + # Name of the project + self.add_tag("ProjectName", project.name) + + # Set the language + if found_xbox: + self.add_tag("DefaultLanguage", "en-US") + + self.add_tag("ProjectGuid", "{{{}}}".format(project.vs_uuid)) + # Check for the special case of Android for VS2022 found_android = False if ide >= IDETypes.vs2022: @@ -705,11 +730,6 @@ def __init__(self, project): found_android = True break - self.add_tags(( - ("ProjectName", project.name), - ("ProjectGuid", "{{{}}}".format(project.vs_uuid)) - )) - if found_android: self.add_tags(( ("Keyword", "Android"), @@ -718,33 +738,50 @@ def __init__(self, project): ("ApplicationTypeRevision", "3.0") )) else: - # Was there an override? - platform_version = project.vs_platform_version - - # Create a default - if platform_version is None: - - # Visual Studio 2019 and higher allows using "Latest" - # SDK - if ide in (IDETypes.vs2019, IDETypes.vs2022): - platform_version = "10.0" - - # Visual Studio 2015-2017 require explicit SDK - elif ide in (IDETypes.vs2015, IDETypes.vs2017): - - # Special case if using the Xbox ONE toolset - # The Xbox ONE XDK requires 8.1, the GDK does not - for configuration in project.configuration_list: - if configuration.platform is PlatformTypes.xboxone: - platform_version = "8.1" - break - else: - # Set to the latest installed with 2017 - platform_version = "10.0.17763.0" - self.add_tag( - "WindowsTargetPlatformVersion", - platform_version) + # Test if WindowsTargetPlatformVersion is needed + for configuration in project.configuration_list: + if configuration.platform.is_switch(): + break + + else: + # Was there an override? + platform_version = project.vs_platform_version + + # Create a default + if platform_version is None: + + # Visual Studio 2019 and higher allows using "Latest" + # SDK + if ide in (IDETypes.vs2019, IDETypes.vs2022): + platform_version = "10.0" + + # Visual Studio 2015-2017 require explicit SDK + elif ide in (IDETypes.vs2015, IDETypes.vs2017): + + # Special case if using the Xbox ONE toolset + # The Xbox ONE XDK requires 8.1, the GDK does not + for configuration in project.configuration_list: + if configuration.platform is PlatformTypes.xboxone: + platform_version = "8.1" + break + else: + # Set to the latest installed with 2017 + platform_version = "10.0.17763.0" + + self.add_tag( + "WindowsTargetPlatformVersion", + platform_version) + + # The Xbox GDK requires to be declared as "C" + if ide >= IDETypes.vs2017: + for configuration in project.configuration_list: + if configuration.platform in ( + PlatformTypes.xboxgdk, PlatformTypes.xboxonex): + self.add_tag( + "GDKExtLibNames", + "Xbox.Services.API.C") + break ######################################## @@ -771,41 +808,41 @@ def __init__(self, configuration): vs_configuration_name = configuration.vs_configuration_name VS2010XML.__init__( - self, 'PropertyGroup', - {'Condition': "'$(Configuration)|$(Platform)'=='{}'".format( + self, "PropertyGroup", + {"Condition": "'$(Configuration)|$(Platform)'=='{}'".format( vs_configuration_name), - 'Label': 'Configuration'}) + "Label": "Configuration"}) platform = configuration.platform project_type = configuration.project_type # Set the configuration type if project_type in (ProjectTypes.app, ProjectTypes.tool): - configuration_type = 'Application' + configuration_type = "Application" elif project_type is ProjectTypes.sharedlibrary: - configuration_type = 'DynamicLibrary' + configuration_type = "DynamicLibrary" else: - configuration_type = 'StaticLibrary' + configuration_type = "StaticLibrary" # Which toolset to use? platform_toolset = configuration.get_chained_value( - 'vs_platform_toolset') + "vs_platform_toolset") if not platform_toolset: if platform.is_windows(): platformtoolsets = { - IDETypes.vs2010: 'v100', - IDETypes.vs2012: 'v110_xp', - IDETypes.vs2013: 'v120_xp', - IDETypes.vs2015: 'v140_xp', - IDETypes.vs2017: 'v141_xp', - IDETypes.vs2019: 'v142', - IDETypes.vs2022: 'v143' + IDETypes.vs2010: "v100", + IDETypes.vs2012: "v110_xp", + IDETypes.vs2013: "v120_xp", + IDETypes.vs2015: "v140_xp", + IDETypes.vs2017: "v141_xp", + IDETypes.vs2019: "v142", + IDETypes.vs2022: "v143" } platform_toolset = platformtoolsets.get( - configuration.ide, 'v141_xp') + configuration.ide, "v141_xp") # ARM targets must use the non-xp toolset - if platform_toolset.endswith('_xp'): + if platform_toolset.endswith("_xp"): if platform in (PlatformTypes.winarm32, PlatformTypes.winarm64): platform_toolset = platform_toolset[:-3] @@ -813,12 +850,12 @@ def __init__(self, configuration): # Xbox ONE uses this tool chain elif platform.is_xboxone(): platformtoolsets_one = { - IDETypes.vs2017: 'v141', - IDETypes.vs2019: 'v142', - IDETypes.vs2022: 'v143' + IDETypes.vs2017: "v141", + IDETypes.vs2019: "v142", + IDETypes.vs2022: "v143" } platform_toolset = platformtoolsets_one.get( - configuration.ide, 'v141') + configuration.ide, "v141") # The default is 5.0, but currently the Android plug in is # causing warnings with __ANDROID_API__. Fall back to 3.8 @@ -826,11 +863,11 @@ def __init__(self, configuration): platform_toolset = "Clang_3_8" self.add_tags(( - ('ConfigurationType', configuration_type), + ("ConfigurationType", configuration_type), # Enable debug libraries - ('UseDebugLibraries', truefalse( + ("UseDebugLibraries", truefalse( configuration.debug)), - ('PlatformToolset', platform_toolset) + ("PlatformToolset", platform_toolset) )) # Handle android minimum tool set @@ -839,9 +876,9 @@ def __init__(self, configuration): PlatformTypes.androidarm64): # 64 bit support was introduced in android 21 # Lollipop 5.0 - android_min_api = 'android-21' + android_min_api = "android-21" else: - android_min_api = 'android-9' + android_min_api = "android-9" self.add_tag("AndroidMinAPI", android_min_api) self.add_tag("AndroidTargetAPI", "android-24") @@ -864,6 +901,14 @@ def __init__(self, configuration): # Nintendo Switch SDK location if platform.is_switch(): self.add_tag("NintendoSdkRoot", "$(NINTENDO_SDK_ROOT)\\") + self.add_tag("NintendoSdkSpec", "NX") + item = getattr(configuration, "switch_build_type", "Debug") + self.add_tag("NintendoSdkBuildType", item) + + # If Visual Studio 2022 for Windows or Xbox, use the 64 bit tools + if configuration.ide >= IDETypes.vs2022: + if platform.is_xbox() or platform.is_windows(): + self.add_tag("PreferredToolArchitecture", "x64") ######################################## @@ -884,15 +929,15 @@ def __init__(self, project): ## Parent project self.project = project - VS2010XML.__init__(self, 'ImportGroup', {'Label': 'ExtensionSettings'}) + VS2010XML.__init__(self, "ImportGroup", {"Label": "ExtensionSettings"}) for props in project.vs_props: props = convert_to_windows_slashes(props) self.add_element( VS2010XML( - 'Import', { - 'Project': props, - 'Condition': "exists('{}')".format(props)})) + "Import", { + "Project": props, + "Condition": "exists('{}')".format(props)})) ######################################## @@ -912,7 +957,7 @@ def __init__(self, project): ## Parent project self.project = project - VS2010XML.__init__(self, 'PropertyGroup', {'Label': 'UserMacros'}) + VS2010XML.__init__(self, "PropertyGroup", {"Label": "UserMacros"}) ######################################## @@ -933,18 +978,32 @@ def __init__(self, project): ## Parent project self.project = project - VS2010XML.__init__(self, 'ImportGroup', {'Label': 'PropertySheets'}) + VS2010XML.__init__(self, "ImportGroup", {"Label": "PropertySheets"}) self.add_element( VS2010XML( - 'Import', - {'Project': - '$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props', - 'Condition': + "Import", + {"Project": + "$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props", + "Condition": "exists('$(UserRootDir)\\Microsoft.Cpp." "$(Platform).user.props')", - 'Label': - 'LocalAppDataPlatform'})) + "Label": + "LocalAppDataPlatform"})) + + # Switch requires projects settings from the Nintendo SDK + for configuration in project.configuration_list: + if configuration.platform.is_switch(): + self.add_element( + VS2010XML( + "Import", + {"Project": + "$(NINTENDO_SDK_ROOT)\\Build\\VcProjectUtility\\" + "ImportNintendoSdk.props", + "Condition": + "exists('$(NINTENDO_SDK_ROOT)\\Build\\" + "VcProjectUtility\\ImportNintendoSdk.props')"})) + break ######################################## @@ -969,8 +1028,8 @@ def __init__(self, configuration): vs_configuration_name = configuration.vs_configuration_name VS2010XML.__init__( - self, 'PropertyGroup', - {'Condition': "'$(Configuration)|$(Platform)'=='{}'".format( + self, "PropertyGroup", + {"Condition": "'$(Configuration)|$(Platform)'=='{}'".format( vs_configuration_name)}) platform = configuration.platform @@ -980,56 +1039,101 @@ def __init__(self, configuration): # Xbox 360 deployment file names if platform is PlatformTypes.xbox360: - remote_root = 'xe:\\$(ProjectName)' - image_xex_output = '$(OutDir)$(TargetName).xex' + remote_root = "xe:\\$(ProjectName)" + image_xex_output = "$(OutDir)$(TargetName).xex" suffix = configuration.get_suffix() - target_name = '$(ProjectName){}'.format(suffix) + target_name = "$(ProjectName){}".format(suffix) if platform.is_android(): - target_name = 'lib' + target_name + target_name = "lib" + target_name - int_dir = '$(ProjectDir)temp\\$(ProjectName){}\\'.format(suffix) + int_dir = "$(ProjectDir)temp\\$(ProjectName){}\\".format(suffix) if platform is PlatformTypes.win32: - run_code_analysis = 'false' + run_code_analysis = "false" # Enable incremental linking self.add_tags(( - ('LinkIncremental', truefalse( + ("LinkIncremental", truefalse( not configuration.optimization)), - ('TargetName', target_name), - ('IntDir', int_dir), - ('OutDir', '$(ProjectDir)bin\\'), - ('RemoteRoot', remote_root), - ('ImageXexOutput', image_xex_output), - ('RunCodeAnalysis', run_code_analysis), - ('CodeAnalysisRuleSet', 'AllRules.ruleset'), - - # This is needed for the Xbox 360 - ('OutputFile', '$(OutDir)$(TargetName)$(TargetExt)') + ("TargetName", target_name), + ("IntDir", int_dir), + ("OutDir", "$(ProjectDir)bin\\"), + ("RemoteRoot", remote_root), + ("ImageXexOutput", image_xex_output), + ("RunCodeAnalysis", run_code_analysis), + ("CodeAnalysisRuleSet", "AllRules.ruleset") )) + # This is needed for the Xbox 360 + self.add_tag("OutputFile", "$(OutDir)$(TargetName)$(TargetExt)") + # For the love of all that is holy, the Xbox ONE requires # these entries as is. if platform is PlatformTypes.xboxone: - self.add_tags( - (('ExecutablePath', - ('$(Console_SdkRoot)bin;$(VCInstallDir)bin\\x86_amd64;' - '$(VCInstallDir)bin;$(WindowsSDK_ExecutablePath_x86);' - '$(VSInstallDir)Common7\\Tools\\bin;' - '$(VSInstallDir)Common7\\tools;' - '$(VSInstallDir)Common7\\ide;' - '$(ProgramFiles)\\HTML Help Workshop;' - '$(MSBuildToolsPath32);$(FxCopDir);$(PATH);')), - ('IncludePath', '$(Console_SdkIncludeRoot)'), - ('ReferencePath', - '$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)'), - ('LibraryPath', '$(Console_SdkLibPath)'), - ('LibraryWPath', - '$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)'), - ('GenerateManifest', 'false') - )) + self.add_tag("ExecutablePath", ( + "$(DurangoXdkTools);" + "$(DurangoXdkInstallPath)bin;" + "$(FXCToolPath);" + "$(VCInstallDir)bin\\x86_amd64;" + "$(VCInstallDir)bin;$(WindowsSDK_ExecutablePath_x86);" + "$(VSInstallDir)Common7\\Tools\\bin;" + "$(VSInstallDir)Common7\\tools;" + "$(VSInstallDir)Common7\\ide;" + "$(ProgramFiles)\\HTML Help Workshop;" + "$(MSBuildToolsPath32);" + "$(FxCopDir);" + "$(PATH)")) + + self.add_tag("ReferencePath", ( + "$(Console_SdkLibPath);" + "$(Console_SdkWindowsMetadataPath)")) + + self.add_tag("LibraryPath", "$(Console_SdkLibPath)") + + self.add_tag("LibraryWPath", ( + "$(Console_SdkLibPath);" + "$(Console_SdkWindowsMetadataPath)")) + + self.add_tag("IncludePath", ( + "$(Console_SdkIncludeRoot)\\um;" + "$(Console_SdkIncludeRoot)\\shared;" + "$(Console_SdkIncludeRoot)\\winrt")) + + self.add_tag("NativeExecutablePath", ( + "$(DurangoXdkTools);" + "$(DurangoXdkInstallPath)bin;" + "$(FXCToolPath);" + "$(NativeExecutablePath)")) + + self.add_tag("SlashAI", ( + "$(Console_SdkWindowsMetadataPath);" + "$(VCInstallDir)vcpackages;" + "$(AdditionalUsingDirectories)")) + + self.add_tag("RemoveExtraDeployFiles", "true") + + self.add_tag("IsolateConfigurationsOnDeploy", "true") + + # The Xbox GDK has its own fun + elif platform.is_xboxone(): + self.add_tag("ExecutablePath", ( + "$(Console_SdkRoot)bin;" + "$(Console_SdkToolPath);" + "$(ExecutablePath)")) + + self.add_tag("IncludePath", "$(Console_SdkIncludeRoot)") + + self.add_tag("ReferencePath", ( + "$(Console_SdkLibPath);" + "$(Console_SdkWindowsMetadataPath)")) + + self.add_tag("LibraryPath", "$(Console_SdkLibPath)") + + self.add_tag("LibraryWPath", ( + "$(Console_SdkLibPath);" + "$(Console_SdkWindowsMetadataPath)")) # Visual Studio Android puts multi-processor compilation here if platform.is_android() and configuration.ide >= IDETypes.vs2022: @@ -1051,149 +1155,167 @@ def __init__(self, configuration): configuration: Configuration record to extract defaults. """ - # Too many branches - # Too many locals - # Too many statements - # pylint: disable=R0912,R0914,R0915 + # I don't care + # pylint: disable=too-many-branches + # pylint: disable=too-many-statements + # pylint: disable=too-many-locals ## Parent configuration self.configuration = configuration - VS2010XML.__init__(self, 'ClCompile') + VS2010XML.__init__(self, "ClCompile") platform = configuration.platform - # Prepend $(ProjectDir) to all source folders - include_folders = [] - for item in configuration.get_unique_chained_list( - '_source_include_list'): - include_folders.append('$(ProjectDir){}'.format(item)) - - include_folders.extend(configuration.get_unique_chained_list( - 'include_folders_list')) - - if include_folders: - include_folders = '{};%(AdditionalIncludeDirectories)'.format( - packed_paths(include_folders, slashes='\\')) - else: - include_folders = None + # Xbox ONE XDK is Windows RT + if platform is PlatformTypes.xboxone: + self.add_tag("CompileAsWinRT", "true") - # Handle defines - define_list = configuration.get_chained_list('define_list') - if define_list: - define_list = '{};%(PreprocessorDefinitions)'.format( - packed_paths(define_list)) + # Get the optimization setting + if configuration.debug: + item = "Disabled" + elif platform is PlatformTypes.stadia: + item = "Full" + elif platform.is_android() and configuration.ide >= IDETypes.vs2022: + item = "Full" else: - define_list = None + item = "MinSpace" + self.add_tag("Optimization", item) + # Get the required run time library if configuration.debug: - optimization = 'Disabled' if platform.is_xboxone(): - runtime_library = 'MultiThreadedDebugDLL' + item = "MultiThreadedDebugDLL" else: - runtime_library = 'MultiThreadedDebug' - omit_frame_pointers = 'false' - basic_runtime_checks = 'EnableFastChecks' - inline_function_expansion = 'OnlyExplicitInline' - intrinic_functions = None - buffer_security_check = None - inline_assembly_optimization = None + item = "MultiThreadedDebug" + elif platform.is_xboxone(): + item = "MultiThreadedDLL" else: - optimization = 'MinSpace' - if platform.is_xboxone(): - runtime_library = 'MultiThreadedDLL' - else: - runtime_library = 'MultiThreaded' - omit_frame_pointers = 'true' - basic_runtime_checks = None - inline_function_expansion = 'AnySuitable' - intrinic_functions = 'true' - buffer_security_check = 'false' - inline_assembly_optimization = 'true' + item = "MultiThreaded" + self.add_tag("RuntimeLibrary", item) - # Not supported on the Xbox 360 - if platform is PlatformTypes.xbox360: - omit_frame_pointers = None + # Xbox has AVX, so use it + if platform.is_xboxone(): + self.add_tag( + "EnableEnhancedInstructionSet", + "AdvancedVectorExtensions") - optimization_level = None - branchless = None - cpp_language_std = None - omit_frame_pointer = None - stack_protector = None - strict_aliasing = None - function_sections = None - cpp_language_standard = None + # Not supported on the Xbox 360 + if platform is not PlatformTypes.xbox360: - if platform in (PlatformTypes.ps3, PlatformTypes.ps4, - PlatformTypes.ps5): - if configuration.optimization: - optimization_level = 'Level2' - if platform is PlatformTypes.ps3: - branchless = 'Branchless2' + # Omit the frame pointers? + if configuration.debug: + item = "false" else: - optimization_level = 'Level0' + item = "true" + self.add_tag("OmitFramePointers", item) - if platform in (PlatformTypes.vita, PlatformTypes.ps3): - cpp_language_std = 'Cpp11' + # Add runtime checks on debug + if configuration.debug: + self.add_tag("BasicRuntimeChecks", "EnableFastChecks") - if platform.is_android(): - if not configuration.debug: - omit_frame_pointer = 'true' - optimization_level = 'O3' - stack_protector = 'false' - strict_aliasing = 'true' - function_sections = 'true' - cpp_language_standard = 'gnu++11' + # Don't do buffer checks on release builds + if not configuration.debug: + self.add_tag("BufferSecurityCheck", "false") - # Switch - if platform.is_switch(): - if configuration.optimization: - omit_frame_pointer = "true" - optimization_level = "O3" + # Inline functions + if configuration.debug: + item = "OnlyExplicitInline" + else: + item = "AnySuitable" + self.add_tag("InlineFunctionExpansion", item) + + # Intrinsic functions + if not configuration.debug: + self.add_tag("IntrinsicFunctions", "true") + + # Inline assembly interleaving and optimizations + if not configuration.debug and platform is not PlatformTypes.xbox360: + self.add_tag("InlineAssemblyOptimization", "true") + + # Always do a minimal rebuild + self.add_tag("MinimalRebuild", "false") - # Not used for Android Targets - warning_level = "Level4" - debug_information_format = "OldStyle" - exception_handling = "false" + # Always include debugging information + self.add_tag("GenerateDebugInformation", "true") + + # Prepend $(ProjectDir) to all source folders + temp_list = [] + for item in configuration.get_unique_chained_list( + "_source_include_list"): + temp_list.append("$(ProjectDir){}".format(item)) + + temp_list.extend(configuration.get_unique_chained_list( + "include_folders_list")) + + if temp_list: + temp_list = "{};%(AdditionalIncludeDirectories)".format( + packed_paths(temp_list, slashes="\\")) + self.add_tag("AdditionalIncludeDirectories", temp_list) + + # Handle preprocessor defines + temp_list = configuration.get_chained_list("define_list") + if temp_list: + temp_list = "{};%(PreprocessorDefinitions)".format( + packed_paths(temp_list)) + self.add_tag("PreprocessorDefinitions", temp_list) + + # Warning level for errors + if platform is PlatformTypes.stadia or ( + platform.is_android() and configuration.ide >= IDETypes.vs2022): + item = "EnableAllWarnings" + else: + item = "Level4" + self.add_tag("WarningLevel", item) + + # Type of debug information + item = "OldStyle" if platform.is_android() and configuration.ide >= IDETypes.vs2022: - debug_information_format = None - warning_level = "EnableAllWarnings" - exception_handling = "Disabled" - if not configuration.debug: - optimization = "Full" + item = None # Handle Stadia if platform is PlatformTypes.stadia: - debug_information_format = None - warning_level = "EnableAllWarnings" - exception_handling = "Disabled" + item = None + if configuration.debug: + item = "FullDebug" + self.add_tag("DebugInformationFormat", item) + + # Program database name + self.add_tag("ProgramDataBaseFileName", "$(OutDir)$(TargetName).pdb") + + # Exception handling + item = "false" + if (platform.is_android() and configuration.ide >= IDETypes.vs2022) \ + or platform is PlatformTypes.stadia: + item = "Disabled" + self.add_tag("ExceptionHandling", item) + + # Floating point model + self.add_tag("FloatingPointModel", "Fast") + + # Run time type info + self.add_tag("RuntimeTypeInfo", "false") + + # Enable string pooling + self.add_tag("StringPooling", "true") + + # Function level linking + self.add_tag("FunctionLevelLinking", "true") + + omit_frame_pointer = None + stack_protector = None + strict_aliasing = None + + if platform.is_android(): if not configuration.debug: - optimization = "Full" - else: - debug_information_format = "FullDebug" + omit_frame_pointer = "true" + stack_protector = "false" + strict_aliasing = "true" - self.add_tags(( - ('Optimization', optimization), - ('RuntimeLibrary', runtime_library), - ('OmitFramePointers', omit_frame_pointers), - ('BasicRuntimeChecks', basic_runtime_checks), - ('BufferSecurityCheck', buffer_security_check), - ('InlineFunctionExpansion', inline_function_expansion), - ('IntrinsicFunctions', intrinic_functions), - ('InlineAssemblyOptimization', inline_assembly_optimization), - ('MinimalRebuild', 'false'), - ('GenerateDebugInformation', 'true'), - ('AdditionalIncludeDirectories', include_folders), - ('PreprocessorDefinitions', define_list), - ('WarningLevel', warning_level), - ('DebugInformationFormat', debug_information_format), - ('ProgramDataBaseFileName', '$(OutDir)$(TargetName).pdb'), - ('ExceptionHandling', exception_handling), - ('FloatingPointModel', 'Fast'), - ('RuntimeTypeInfo', 'false'), - ('StringPooling', 'true'), - ('FunctionLevelLinking', 'true') - )) + # Switch + if platform.is_switch(): + if configuration.optimization: + omit_frame_pointer = "true" # Stadia multiprocessor compilation if platform is PlatformTypes.stadia: @@ -1208,6 +1330,12 @@ def __init__(self, configuration): self.add_tag("EnableFiberSafeOptimizations", "true") + # Xbox ONE has using directories to the tool chain + if platform.is_xboxone(): + self.add_tag("AdditionalUsingDirectories", "$(SlashAI)") + if platform is not PlatformTypes.xboxone: + self.add_tag("SupportJustMyCode", "false") + # Profiling on the xbox 360 if platform is PlatformTypes.xbox360: @@ -1230,11 +1358,29 @@ def __init__(self, configuration): if configuration.fastcall: self.add_tag("CallingConvention", "FastCall") - self.add_tags(( - ('OptimizationLevel', optimization_level), - ('Branchless', branchless), - ('CppLanguageStd', cpp_language_std) - )) + # Set the optimization level + item = None + if platform in (PlatformTypes.ps3, PlatformTypes.ps4, + PlatformTypes.ps5): + if configuration.optimization: + item = "Level2" + else: + item = "Level0" + if platform.is_android() and configuration.optimization: + item = "O3" + + if platform.is_switch() and configuration.optimization: + # Don't use O3, it generates bad code + item = "O2" + self.add_tag("OptimizationLevel", item) + + # PS3 Branchless mode + if platform is PlatformTypes.ps3 and configuration.optimization: + self.add_tag("Branchless", "Branchless2") + + # PS3 and Vita allow CPP 11 + if platform in (PlatformTypes.vita, PlatformTypes.ps3): + self.add_tag("CppLanguageStd", "Cpp11") if platform in (PlatformTypes.ps4, PlatformTypes.ps5): self.add_tag("DisableSpecificWarnings", packed_paths( @@ -1247,13 +1393,16 @@ def __init__(self, configuration): self.add_tag("SetMessageToSilent", "1795") self.add_tags(( - ('StackProtector', stack_protector), - ('OmitFramePointer', omit_frame_pointer), - ('StrictAliasing', strict_aliasing), - ('FunctionSections', function_sections), - ('CppLanguageStandard', cpp_language_standard) + ("StackProtector", stack_protector), + ("OmitFramePointer", omit_frame_pointer), + ("StrictAliasing", strict_aliasing) )) + # nVidia android has CPP11 + if platform.is_android(): + self.add_tag("FunctionSections", "true") + self.add_tag("CppLanguageStandard", "gnu++11") + # Disable these features when compiling Intel Android # to disable warnings from clang for intel complaining # about ARM specific commands @@ -1302,48 +1451,55 @@ def __init__(self, configuration): platform = configuration.platform project_type = configuration.project_type - # Start with a copy (To prevent damaging the original list) - library_folders = configuration.get_unique_chained_list( + # Get the additional folders for libaries + item = configuration.get_unique_chained_list( "library_folders_list") + if item: + item = "{};%(AdditionalLibraryDirectories)".format( + packed_paths(item, slashes="\\")) + self.add_tag("AdditionalLibraryDirectories", item) - if library_folders: - library_folders = "{};%(AdditionalLibraryDirectories)".format( - packed_paths(library_folders, slashes="\\")) - else: - library_folders = None - - additional_libraries = configuration.get_unique_chained_list( + # Are there any additional library binaries to add? + item = configuration.get_unique_chained_list( "libraries_list") - if additional_libraries: + if item: + + # Xbox ONE only has the paths, nothing more if platform.is_xboxone(): - additional_libraries = "{}".format( - packed_paths(additional_libraries)) + item = "{}".format(packed_paths(item)) else: + # Playstation needs them converted to -l commands if platform in (PlatformTypes.ps4, PlatformTypes.ps5): libs = [] - for item in additional_libraries: - if item.startswith("-l"): - libs.append(item) + for lib in item: + if lib.startswith("-l"): + libs.append(lib) else: - libs.append("-l" + item) - additional_libraries = libs + libs.append("-l" + lib) + item = libs - additional_libraries = "{};%(AdditionalDependencies)".format( - packed_paths(additional_libraries)) - else: - additional_libraries = None + item = "{};%(AdditionalDependencies)".format( + packed_paths(item)) - subsystem = None - targetmachine = None - data_stripping = None - duplicate_stripping = None + # Add the tag + self.add_tag("AdditionalDependencies", item) + + # Is there a subsystem needed? + if platform.is_xboxone(): + self.add_tag("SubSystem", "Console") if platform.is_windows(): if project_type is ProjectTypes.tool: - subsystem = "Console" + item = "Console" else: - subsystem = "Windows" + item = "Windows" + self.add_tag("SubSystem", item) + + targetmachine = None + data_stripping = None + duplicate_stripping = None + if platform.is_windows(): if platform is PlatformTypes.win32: targetmachine = "MachineX86" elif platform is PlatformTypes.winarm32: @@ -1358,25 +1514,31 @@ def __init__(self, configuration): data_stripping = "StripFuncsAndData" duplicate_stripping = "true" - if configuration.optimization: - enable_comdat_folding = "true" - optimize_references = "true" - else: - enable_comdat_folding = None - optimize_references = "false" - self.add_tags(( - ("AdditionalLibraryDirectories", library_folders), - ("AdditionalDependencies", additional_libraries), - ("SubSystem", subsystem), ("TargetMachine", targetmachine), ("DataStripping", data_stripping), - ("DuplicateStripping", duplicate_stripping), - ("OptimizeReferences", optimize_references), - ("GenerateDebugInformation", "true"), - ("EnableCOMDATFolding", enable_comdat_folding) + ("DuplicateStripping", duplicate_stripping) )) + # Optimize the references? + if configuration.optimization: + item = "true" + else: + item = "false" + self.add_tag("OptimizeReferences", item) + + # Always add debug info + self.add_tag("GenerateDebugInformation", "true") + + # Should common data/code be folded together? + if configuration.optimization: + self.add_tag("EnableCOMDATFolding", "true") + + # Switch may have meta data for the final build + item = getattr(configuration, "switch_meta_source", None) + if item: + self.add_tag("FinalizeMetaSource", item) + if configuration.get_chained_value("profile"): self.add_tag("Profile", "true") @@ -1402,7 +1564,7 @@ def __init__(self, configuration): ## Parent configuration self.configuration = configuration - VS2010XML.__init__(self, 'Deploy') + VS2010XML.__init__(self, "Deploy") platform = configuration.platform project_type = configuration.project_type @@ -1413,14 +1575,14 @@ def __init__(self, configuration): if not project_type.is_library(): if platform is PlatformTypes.xbox360: - deployment_type = 'EmulateDvd' - dvd_emulation = 'ZeroSeekTimes' - deployment_files = '$(RemoteRoot)=$(ImagePath)' + deployment_type = "EmulateDvd" + dvd_emulation = "ZeroSeekTimes" + deployment_files = "$(RemoteRoot)=$(ImagePath)" self.add_tags(( - ('DeploymentType', deployment_type), - ('DvdEmulationType', dvd_emulation), - ('DeploymentFiles', deployment_files) + ("DeploymentType", deployment_type), + ("DvdEmulationType", dvd_emulation), + ("DeploymentFiles", deployment_files) )) @@ -1446,13 +1608,13 @@ def __init__(self, configuration): ## Parent configuration self.configuration = configuration - VS2010XML.__init__(self, 'PostBuildEvent') + VS2010XML.__init__(self, "PostBuildEvent") vs_description, vs_cmd = create_deploy_script(configuration) self.add_tags(( - ('Message', vs_description), - ('Command', vs_cmd) + ("Message", vs_description), + ("Command", vs_cmd) )) @@ -1482,8 +1644,8 @@ def __init__(self, configuration): vs_configuration_name = configuration.vs_configuration_name VS2010XML.__init__( - self, 'ItemDefinitionGroup', - {'Condition': "'$(Configuration)|$(Platform)'=='{}'".format( + self, "ItemDefinitionGroup", + {"Condition": "'$(Configuration)|$(Platform)'=='{}'".format( vs_configuration_name)}) ## ClCompile exporter @@ -1529,161 +1691,205 @@ def __init__(self, project): ## Parent project self.project = project - VS2010XML.__init__(self, 'ItemGroup') + VS2010XML.__init__(self, "ItemGroup") - for item in source_file_filter(project.codefiles, FileTypes.h): - self.add_element( - VS2010XML( - 'ClInclude', { - 'Include': convert_to_windows_slashes( - item.relative_pathname)})) + # Add in C++ headers, C files, etc + self.addfiles(FileTypes.h, "ClInclude") + self.addfiles((FileTypes.cpp, FileTypes.c), "ClCompile") + self.addfiles((FileTypes.x86, FileTypes.x64), "MASM") - for item in source_file_filter(project.codefiles, FileTypes.cpp): - self.add_element( - VS2010XML( - 'ClCompile', { - 'Include': convert_to_windows_slashes( - item.relative_pathname)})) + # Resource files + self.addfiles(FileTypes.rc, "ResourceCompile") - for item in source_file_filter(project.codefiles, FileTypes.c): - self.add_element( - VS2010XML( - 'ClCompile', { - 'Include': convert_to_windows_slashes( - item.relative_pathname)})) + # WiiU assembly + if project.platform_code == "wiu": + self.addfiles(FileTypes.s, "ASM") - for item in source_file_filter(project.codefiles, FileTypes.rc): - self.add_element( - VS2010XML( - 'ResourceCompile', { - 'Include': convert_to_windows_slashes( - item.relative_pathname)})) + # PS3 assembly + if project.platform_code in ("ps3", "ps4", "ps5", "vit", "swi"): + self.addfiles(FileTypes.s, "ClCompile") for item in source_file_filter(project.codefiles, FileTypes.hlsl): name = convert_to_windows_slashes(item.relative_pathname) - element = VS2010XML('HLSL', {'Include': name}) + element = VS2010XML("HLSL", {"Include": name}) self.add_element(element) # Cross platform way in splitting the path (MacOS doesn't like # windows slashes) - basename = name.lower().rsplit('\\', 1)[1] + basename = name.lower().rsplit("\\", 1)[1] splitname = os.path.splitext(basename) - if splitname[0].startswith('vs41'): - profile = 'vs_4_1' - elif splitname[0].startswith('vs4'): - profile = 'vs_4_0' - elif splitname[0].startswith('vs3'): - profile = 'vs_3_0' - elif splitname[0].startswith('vs2'): - profile = 'vs_2_0' - elif splitname[0].startswith('vs1'): - profile = 'vs_1_1' - elif splitname[0].startswith('vs'): - profile = 'vs_2_0' - elif splitname[0].startswith('ps41'): - profile = 'ps_4_1' - elif splitname[0].startswith('ps4'): - profile = 'ps_4_0' - elif splitname[0].startswith('ps3'): - profile = 'ps_3_0' - elif splitname[0].startswith('ps2'): - profile = 'ps_2_0' - elif splitname[0].startswith('ps'): - profile = 'ps_2_0' - elif splitname[0].startswith('tx'): - profile = 'tx_1_0' - elif splitname[0].startswith('gs41'): - profile = 'gs_4_1' - elif splitname[0].startswith('gs'): - profile = 'gs_4_0' + if splitname[0].startswith("vs41"): + profile = "vs_4_1" + elif splitname[0].startswith("vs4"): + profile = "vs_4_0" + elif splitname[0].startswith("vs3"): + profile = "vs_3_0" + elif splitname[0].startswith("vs2"): + profile = "vs_2_0" + elif splitname[0].startswith("vs1"): + profile = "vs_1_1" + elif splitname[0].startswith("vs"): + profile = "vs_2_0" + elif splitname[0].startswith("ps41"): + profile = "ps_4_1" + elif splitname[0].startswith("ps4"): + profile = "ps_4_0" + elif splitname[0].startswith("ps3"): + profile = "ps_3_0" + elif splitname[0].startswith("ps2"): + profile = "ps_2_0" + elif splitname[0].startswith("ps"): + profile = "ps_2_0" + elif splitname[0].startswith("tx"): + profile = "tx_1_0" + elif splitname[0].startswith("gs41"): + profile = "gs_4_1" + elif splitname[0].startswith("gs"): + profile = "gs_4_0" else: - profile = 'fx_2_0' + profile = "fx_2_0" element.add_tags(( - ('VariableName', 'g_' + splitname[0]), - ('TargetProfile', profile), - ('HeaderFileName', - '%(RootDir)%(Directory)Generated\\%(FileName).h'))) + ("VariableName", "g_" + splitname[0]), + ("TargetProfile", profile), + ("HeaderFileName", + "%(RootDir)%(Directory)Generated\\%(FileName).h"))) for item in source_file_filter(project.codefiles, FileTypes.x360sl): name = convert_to_windows_slashes(item.relative_pathname) - element = VS2010XML('X360SL', {'Include': name}) + element = VS2010XML("X360SL", {"Include": name}) self.add_element(element) # Cross platform way in splitting the path (MacOS doesn't like # windows slashes) - basename = name.lower().rsplit('\\', 1)[1] + basename = name.lower().rsplit("\\", 1)[1] splitname = os.path.splitext(basename) - if splitname[0].startswith('vs3'): - profile = 'vs_3_0' - elif splitname[0].startswith('vs2'): - profile = 'vs_2_0' - elif splitname[0].startswith('vs1'): - profile = 'vs_1_1' - elif splitname[0].startswith('vs'): - profile = 'vs_2_0' - elif splitname[0].startswith('ps3'): - profile = 'ps_3_0' - elif splitname[0].startswith('ps2'): - profile = 'ps_2_0' - elif splitname[0].startswith('ps'): - profile = 'ps_2_0' - elif splitname[0].startswith('tx'): - profile = 'tx_1_0' + if splitname[0].startswith("vs3"): + profile = "vs_3_0" + elif splitname[0].startswith("vs2"): + profile = "vs_2_0" + elif splitname[0].startswith("vs1"): + profile = "vs_1_1" + elif splitname[0].startswith("vs"): + profile = "vs_2_0" + elif splitname[0].startswith("ps3"): + profile = "ps_3_0" + elif splitname[0].startswith("ps2"): + profile = "ps_2_0" + elif splitname[0].startswith("ps"): + profile = "ps_2_0" + elif splitname[0].startswith("tx"): + profile = "tx_1_0" else: - profile = 'fx_2_0' + profile = "fx_2_0" element.add_tags(( - ('VariableName', 'g_' + splitname[0]), - ('TargetProfile', profile), - ('HeaderFileName', - '%(RootDir)%(Directory)Generated\\%(FileName).h'))) + ("VariableName", "g_" + splitname[0]), + ("TargetProfile", profile), + ("HeaderFileName", + "%(RootDir)%(Directory)Generated\\%(FileName).h"))) for item in source_file_filter(project.codefiles, FileTypes.vitacg): name = convert_to_windows_slashes(item.relative_pathname) - element = VS2010XML('VitaCGCompile', {'Include': name}) + element = VS2010XML("VitaCGCompile", {"Include": name}) self.add_element(element) # Cross platform way in splitting the path # (MacOS doesn't like windows slashes) - basename = item.relative_pathname.lower().rsplit('\\', 1)[1] + basename = item.relative_pathname.lower().rsplit("\\", 1)[1] splitname = os.path.splitext(basename) - if splitname[0].startswith('vs'): - profile = 'sce_vp_psp2' + if splitname[0].startswith("vs"): + profile = "sce_vp_psp2" else: - profile = 'sce_fp_psp2' - element.add_element(VS2010XML('TargetProfile', contents=profile)) + profile = "sce_fp_psp2" + element.add_element(VS2010XML("TargetProfile", contents=profile)) element.add_element( VS2010XML( - 'HeaderFileName', - contents='%(RootDir)%(Directory)Generated\\%(FileName).h')) + "HeaderFileName", + contents="%(RootDir)%(Directory)Generated\\%(FileName).h")) for item in source_file_filter(project.codefiles, FileTypes.glsl): - element = VS2010XML('GLSL', {'Include': convert_to_windows_slashes( + element = VS2010XML("GLSL", {"Include": convert_to_windows_slashes( item.relative_pathname)}) self.add_element(element) element.add_tags( - (('ObjectFileName', - '%(RootDir)%(Directory)Generated\\%(FileName).h'),)) + (("ObjectFileName", + "%(RootDir)%(Directory)Generated\\%(FileName).h"),)) - for item in source_file_filter( - project.codefiles, FileTypes.appxmanifest): - self.add_element( - VS2010XML( - 'AppxManifest', { - 'Include': convert_to_windows_slashes( - item.relative_pathname)})) + # Appx manifest + self.addfiles(FileTypes.appxmanifest, "AppxManifest") + # Ico files if self.project.ide >= IDETypes.vs2015: - chunkname = 'Image' + chunkname = "Image" else: - chunkname = 'None' - for item in source_file_filter(project.codefiles, FileTypes.ico): - self.add_element( - VS2010XML( - chunkname, { - 'Include': convert_to_windows_slashes( - item.relative_pathname)})) + chunkname = "None" + self.addfiles(FileTypes.ico, chunkname) + self.addfiles(FileTypes.image, chunkname) + +######################################## + + def addfiles(self, file_types, xml_name): + """ + Scan codefiles for a specific file type + + Args: + file_types: FileTypes of interest + xml_name: Visual Studio XML name + """ + + for item in source_file_filter(self.project.codefiles, file_types): + + # Create the file object + new_xml = VS2010XML( + xml_name, { + "Include": convert_to_windows_slashes( + item.relative_pathname)}) + + # Add it to the chain + self.add_element(new_xml) + + # Check if needs to be marked as "Not part of build" + if xml_name == "MASM": + + # Required for Visual Studio 2015 and higher, but present in all + # versions + for configuration in self.project.configuration_list: + if configuration.platform.is_xboxone(): + break + else: + element = VS2010XML( + "UseSafeExceptionHandlers", contents="true") + new_xml.add_element(element) + element.add_attribute("Condition", "'$(Platform)'=='Win32'") + + # Determine which target is acceptable + acceptable = { + FileTypes.x86: ("Win32",), + FileTypes.x64: ("x64", + "Durango", + "Gaming.Xbox.XboxOne.x64", + "Gaming.Xbox.Scarlett.x64") + }.get(item.type, []) + + # For early out + processed = set() + + # Check if there are other platforms that this file + # cannot be built on + for configuration in self.project.configuration_list: + vs_platform = configuration.platform.get_vs_platform()[0] + if vs_platform in processed: + continue + + processed.add(vs_platform) + if vs_platform not in acceptable: + new_xml.add_element( + VS2010XML( + "ExcludedFromBuild", { + "Condition": + "'$(Platform)'=='" + vs_platform + "'"}, + "true")) ######################################## @@ -1709,17 +1915,14 @@ def __init__(self, project): ## Parent project self.project = project - # Which project type? + # Which toolset version to use ide = project.ide - if ide < IDETypes.vs2015: - version = '4.0' - else: - version = '14.0' + version = get_toolset_version(ide) VS2010XML.__init__( - self, 'Project', - {'DefaultTargets': 'Build', 'ToolsVersion': version, - 'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'}) + self, "Project", + {"DefaultTargets": "Build", "ToolsVersion": version, + "xmlns": "http://schemas.microsoft.com/developer/msbuild/2003"}) # Add all the sub chunks @@ -1740,16 +1943,16 @@ def __init__(self, project): self.add_element( VS2010XML( - 'Import', - {'Project': '$(VCTargetsPath)\\Microsoft.Cpp.Default.props'})) + "Import", + {"Project": "$(VCTargetsPath)\\Microsoft.Cpp.Default.props"})) for configuration in project.configuration_list: self.add_element(VS2010Configuration(configuration)) self.add_element( VS2010XML( - 'Import', - {'Project': '$(VCTargetsPath)\\Microsoft.Cpp.props'})) + "Import", + {"Project": "$(VCTargetsPath)\\Microsoft.Cpp.props"})) ## VS2010ExtensionSettings self.extensionsettings = VS2010ExtensionSettings(project) @@ -1775,8 +1978,8 @@ def __init__(self, project): self.add_element( VS2010XML( - 'Import', - {'Project': '$(VCTargetsPath)\\Microsoft.Cpp.targets'})) + "Import", + {"Project": "$(VCTargetsPath)\\Microsoft.Cpp.targets"})) ## VS2010ExtensionTargets self.extensiontargets = VS2010ExtensionTargets(project) @@ -1838,9 +2041,22 @@ def __init__(self, project): groups = [] self.write_filter_group(FileTypes.h, groups, "ClInclude") - self.write_filter_group(FileTypes.cpp, groups, "ClCompile") - self.write_filter_group(FileTypes.c, groups, "ClCompile") + self.write_filter_group((FileTypes.cpp, FileTypes.c), + groups, "ClCompile") + self.write_filter_group((FileTypes.x86, FileTypes.x64), + groups, "MASM") + + # Generic assembly is assumed to be PowerPC for PS3 + if project.platform_code in ("ps3", "ps4", "ps5", "vit", "swi"): + self.write_filter_group(FileTypes.s, groups, "ClCompile") + self.write_filter_group(FileTypes.rc, groups, "ResourceCompile") + self.write_filter_group(FileTypes.ppc, groups, "ASM") + + # Generic assembly is assumed to be PowerPC for WiiU + if project.platform_code == "wiu": + self.write_filter_group(FileTypes.s, groups, "ASM") + self.write_filter_group(FileTypes.hlsl, groups, "HLSL") self.write_filter_group(FileTypes.x360sl, groups, "X360SL") self.write_filter_group(FileTypes.vitacg, groups, "VitaCGCompile") @@ -1850,8 +2066,10 @@ def __init__(self, project): # Visual Studio 2015 and later have a "compiler" for ico files if ide >= IDETypes.vs2015: self.write_filter_group(FileTypes.ico, groups, "Image") + self.write_filter_group(FileTypes.image, groups, "Image") else: self.write_filter_group(FileTypes.ico, groups, "None") + self.write_filter_group(FileTypes.image, groups, "None") # Remove all duplicate in the groups groupset = set(groups) @@ -1972,19 +2190,19 @@ def generate(solution): # Iterate over the project files and create the filenames for project in solution.project_list: - project.vs_output_filename = '{}{}{}.vcxproj'.format( + project.vs_output_filename = "{}{}{}.vcxproj".format( project.name, solution.ide_code, project.platform_code) project.vs_uuid = get_uuid(project.vs_output_filename) for configuration in project.configuration_list: vs_platform = configuration.platform.get_vs_platform()[0] if solution.ide >= IDETypes.vs2022: - vs_platform = {'x86-Android-NVIDIA': 'x86', - 'x64-Android-NVIDIA': 'x64', - 'ARM-Android-NVIDIA': 'ARM', - 'AArch64-Android-NVIDIA': 'ARM64'}.get(vs_platform, vs_platform) + vs_platform = {"x86-Android-NVIDIA": "x86", + "x64-Android-NVIDIA": "x64", + "ARM-Android-NVIDIA": "ARM", + "AArch64-Android-NVIDIA": "ARM64"}.get(vs_platform, vs_platform) configuration.vs_platform = vs_platform - configuration.vs_configuration_name = '{}|{}'.format( + configuration.vs_configuration_name = "{}|{}".format( configuration.name, vs_platform) # Write to memory for file comparison @@ -1998,7 +2216,7 @@ def generate(solution): verbose = solution.verbose # Create the final filename for the Visual Studio Solution file - solution_filename = '{}{}{}.sln'.format( + solution_filename = "{}{}{}.sln".format( solution.name, solution.ide_code, solution.platform_code) save_text_file_if_newer( @@ -2015,13 +2233,24 @@ def generate(solution): project.get_file_list([FileTypes.h, FileTypes.cpp, FileTypes.c, + FileTypes.x86, + FileTypes.x64, + FileTypes.ppc, + FileTypes.s, FileTypes.rc, FileTypes.ico, FileTypes.hlsl, FileTypes.glsl, FileTypes.x360sl, FileTypes.vitacg, - FileTypes.appxmanifest]) + FileTypes.appxmanifest, + FileTypes.image]) + + # Handle WiiU extensions based on found files + wiiu_props(project) + + # Handle x86/x64 support + add_masm_support(project) # Create the project file template exporter = VS2010vcproj(project) @@ -2048,7 +2277,7 @@ def generate(solution): file_name = os.path.join( solution.working_directory, - project.vs_output_filename + '.filters') + project.vs_output_filename + ".filters") if len(filter_lines) >= 4: save_text_file_if_newer( file_name, diff --git a/makeprojects/visual_studio_utils.py b/makeprojects/visual_studio_utils.py index 97de5a7..ed5175f 100644 --- a/makeprojects/visual_studio_utils.py +++ b/makeprojects/visual_studio_utils.py @@ -16,6 +16,7 @@ from burger import is_string from .validators import VSStringProperty +from .enums import IDETypes, FileTypes, PlatformTypes, source_file_detect ######################################## @@ -38,6 +39,32 @@ def get_path_property(pathname): return VSStringProperty("RelativePath", pathname) return VSStringProperty("FileName", pathname) +######################################## + + +def get_toolset_version(ide): + """ + Get the toolset version for the Visual Studio version + + Each version of Visual Studio uses a toolset version specific + to that version. Return the version number for the vcxproj file. + + Args: + ide = IDETypes of the IDE being generated + + Returns: + String of the toolset version for the ide + """ + + if ide < IDETypes.vs2013: + version = "4.0" + elif ide < IDETypes.vs2015: + version = "12.0" + elif ide < IDETypes.vs2017: + version = "14.0" + else: + version = "15.0" + return version ######################################## @@ -59,3 +86,54 @@ def convert_file_name_vs2010(item): item = item.replace("%(FullPath)", "$(InputPath)") item = item.replace("%(Identity)", "$(InputPath)") return item + +######################################## + + +def wiiu_props(project): + """ + If the project is for WiiU, check if there are assembly files. + + If there are assembly files, add the Nintendo supplied props file for + assembly language support + + Args: + project: Project to check + """ + + # Check if WiiU is a configuration + for configuration in project.configuration_list: + if configuration.platform is PlatformTypes.wiiu: + + # Are there any assembly source files in the project? + if source_file_detect(project.codefiles, FileTypes.s): + project.vs_props.append( + "$(VCTargetsPath)\\BuildCustomizations\\cafe2_asm.props") + project.vs_targets.append( + "$(VCTargetsPath)\\BuildCustomizations\\cafe2_asm.targets") + break + +######################################## + + +def add_masm_support(project): + """ + If the project is has x86 or x64 files, add the props files + + Note: + Visual Studio 2003-2008 does not have rules for x64 files. + + Args: + project: Project to check + """ + # Are there any assembly source files in the project? + if source_file_detect(project.codefiles, (FileTypes.x86, FileTypes.x64)): + + # Add support for masm on VS 2003-2008 + project.vs_rules.append("masm.rules") + + # Add support for masm on VS 2010 and beyond + project.vs_props.append( + "$(VCTargetsPath)\\BuildCustomizations\\masm.props") + project.vs_targets.append( + "$(VCTargetsPath)\\BuildCustomizations\\masm.targets") diff --git a/makeprojects/xcode.py b/makeprojects/xcode.py index 3273409..724b9e6 100644 --- a/makeprojects/xcode.py +++ b/makeprojects/xcode.py @@ -25,15 +25,9 @@ @var makeprojects.xcode._XCODE_SUFFIXES List of filename suffixes for xcode versions -@var makeprojects.xcode.TABS -Default tab format for XCode - @var makeprojects.xcode._TEMP_EXE_NAME Build executable pathname -@var makeprojects.xcode._XCODESAFESET -Valid characters for XCode strings without quoting - @var makeprojects.xcode._PERFORCE_PATH Path of the perforce executable @@ -42,21 +36,6 @@ @var makeprojects.xcode.OBJECT_VERSIONS Version values - -@var makeprojects.xcode.OBJECT_ORDER -Order of XCode objects - -@var makeprojects.xcode.FLATTENED_OBJECTS -List of XCode objects that flatten their children - -@var makeprojects.xcode.FILE_REF_LAST_KNOWN -Dictionary for mapping FileTypes to XCode file types - -@var makeprojects.xcode.FILE_REF_DIR -Map of root directories - -@var makeprojects.xcode.XCBUILD_FLAGS -List of XCBuildConfiguration settings for compilation """ # pylint: disable=too-many-arguments @@ -68,21 +47,23 @@ from __future__ import absolute_import, print_function, unicode_literals -import hashlib import os import sys -import string + from re import compile as re_compile from operator import attrgetter, itemgetter from burger import create_folder_if_needed, save_text_file_if_newer, \ - convert_to_windows_slashes, convert_to_linux_slashes, PY2, \ + convert_to_linux_slashes, PY2, \ get_mac_host_type, where_is_xcode, run_command -from .enums import FileTypes, ProjectTypes, PlatformTypes, IDETypes +from .enums import FileTypes, ProjectTypes, PlatformTypes, IDETypes, \ + source_file_detect from .core import SourceFile, Configuration, Project from .config import _XCODEPROJECT_FILE from .build_objects import BuildError, BuildObject -from .xcode_utils import get_sdk_root +from .xcode_utils import get_sdk_root, calcuuid, JSONDict, JSONEntry, \ + JSONArray, JSONObjects, PBXBuildRuleGLSL, PBXFileReference, \ + PBXShellScriptBuildPhase, PBXBuildFile, PBXGroup # Notes for macOS: # Xcode 3 is the only one that builds PowerPC @@ -103,32 +84,19 @@ ("x12", 12), ("x13", 13) ) -# Default tab format for XCode -TABS = "\t" - # Build executable pathname _TEMP_EXE_NAME = "${CONFIGURATION_BUILD_DIR}/${EXECUTABLE_NAME}" -# Valid characters for XCode strings without quoting -_XCODESAFESET = frozenset(string.ascii_letters + string.digits + "_$./") - # Path of the perforce executable _PERFORCE_PATH = "/opt/local/bin/p4" # Supported IDE codes for the XCode exporter SUPPORTED_IDES = ( - IDETypes.xcode3, - IDETypes.xcode4, - IDETypes.xcode5, - IDETypes.xcode6, - IDETypes.xcode7, - IDETypes.xcode8, - IDETypes.xcode9, - IDETypes.xcode10, - IDETypes.xcode11, - IDETypes.xcode12, - IDETypes.xcode13, - IDETypes.xcode14) + IDETypes.xcode3, IDETypes.xcode4, IDETypes.xcode5, + IDETypes.xcode6, IDETypes.xcode7, IDETypes.xcode8, + IDETypes.xcode9, IDETypes.xcode10, IDETypes.xcode11, + IDETypes.xcode12, IDETypes.xcode13, IDETypes.xcode14 +) # Tuple of objectVersion, , compatibilityVersion, developmentRegion OBJECT_VERSIONS = { @@ -148,597 +116,12 @@ IDETypes.xcode14: ("56", "1400", "Xcode 14.0", None) } -# This is the order of XCode chunks that match the way -# that XCode outputs them. -OBJECT_ORDER = ( - "PBXAggregateTarget", - "PBXBuildFile", - "PBXBuildRule", - "PBXContainerItemProxy", - "PBXCopyFilesBuildPhase", - "PBXFileReference", - "PBXFrameworksBuildPhase", - "PBXGroup", - "PBXNativeTarget", - "PBXProject", - "PBXReferenceProxy", - "PBXResourcesBuildPhase", - "PBXShellScriptBuildPhase", - "PBXSourcesBuildPhase", - "PBXTargetDependency", - "XCBuildConfiguration", - "XCConfigurationList" -) - -# List of XCode objects that flatten their children -FLATTENED_OBJECTS = ( - "PBXBuildFile", - "PBXFileReference" -) - -# Dictionary for mapping FileTypes to XCode file types -FILE_REF_LAST_KNOWN = { - FileTypes.library: None, - FileTypes.exe: None, - FileTypes.frameworks: "wrapper.framework", - FileTypes.glsl: "sourcecode.glsl", - FileTypes.xml: "text.xml", - FileTypes.xcconfig: "text.xcconfig", - FileTypes.cpp: "sourcecode.cpp.objcpp", - FileTypes.c: "source.c.c", - FileTypes.h: "sourcecode.c.h" -} - -# Map of root directories -FILE_REF_DIR = { - FileTypes.library: "BUILT_PRODUCTS_DIR", - FileTypes.exe: "BUILT_PRODUCTS_DIR", - FileTypes.frameworks: "SDKROOT", - FileTypes.cpp: "SOURCE_ROOT", - FileTypes.c: "SOURCE_ROOT" -} - -# Name / type / default -XCBUILD_FLAGS = ( - # Locations of any sparse SDKs - ("ADDITIONAL_SDKS", "string", None), - - # Group permission of deployment - ("ALTERNATE_GROUP", "string", None), - - # File permissions of deployment - ("ALTERNATE_MODE", "string", None), - - # Owner permission of deployment - ("ALTERNATE_OWNER", "string", None), - - # Specific files to apply deployment permissions - ("ALTERNATE_PERMISSIONS_FILES", "string", None), - - # Always search user paths in C++ - ("ALWAYS_SEARCH_USER_PATHS", "boolean", None), - - # Copy Files Build Phase will plist and strings to encoding - ("APPLY_RULES_IN_COPY_FILES", "boolean", None), - - # Default CPUs - ("ARCHS", "stringarray", None), - - # List of build variants - ("BUILD_VARIANTS", "stringarray", None), - - # Name of executable that loads the bundle - ("BUNDLE_LOADER", "string", None), - - # Name of the code signing certificate - ("CODE_SIGN_IDENTITY", "string", None), - - # Path to property list containing rules for signing - ("CODE_SIGN_RESOURCE_RULES_PATH", "string", None), - - # Path for build products - ("CONFIGURATION_BUILD_DIR", "string", - "$(SYMROOT)/$(PRODUCT_NAME)"), - - # Path for temp files - ("CONFIGURATION_TEMP_DIR", "string", - "$(SYMROOT)/$(PRODUCT_NAME)"), - - # Does copying preserve classic mac resource forks? - ("COPYING_PRESERVES_HFS_DATA", "boolean", None), - - # Strip debug symbols? - ("COPY_PHASE_STRIP", "boolean", None), - - # Numeric project version - ("CURRENT_PROJECT_VERSION", "string", None), - - # Strip dead code? - ("DEAD_CODE_STRIPPING", "boolean", "YES"), - - # Type of debug symbols - ("DEBUG_INFORMATION_FORMAT", "string", "dwarf"), - - # Are there valid deployment location settings? - ("DEPLOYMENT_LOCATION", "boolean", None), - - # Process deployment files - ("DEPLOYMENT_POSTPROCESSING", "boolean", None), - - # Destination root folder for deployment - ("DSTROOT", "string", None), - - # Compatible version of the dynamic library - ("DYLIB_COMPATIBILITY_VERSION", "string", None), - - # Numeric version of the dynamic library - ("DYLIB_CURRENT_VERSION", "string", None), - - # Enable OpenMP - ("ENABLE_OPENMP_SUPPORT", "boolean", None), - - # Files and folders to ignore on search. - ("EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES", "string", None), - - # Extension for executables - ("EXECUTABLE_EXTENSION", "string", None), - - # Prefix for executables - ("EXECUTABLE_PREFIX", "string", None), - - # File with symbols to export - ("EXPORTED_SYMBOLS_FILE", "string", None), - - # Array of directories to search for Frameworks - ("FRAMEWORK_SEARCH_PATHS", "stringarray", None), - - # Version of the framework being generated - ("FRAMEWORK_VERSION", "string", None), - - # PowerPC only, enable altivec - ("GCC_ALTIVEC_EXTENSIONS", "boolean", None), - - # Enable vectorization on loops - ("GCC_AUTO_VECTORIZATION", "boolean", None), - - # Default "char" to unsigned if set to true - ("GCC_CHAR_IS_UNSIGNED_CHAR", "boolean", None), - - # It true, assume no exceptions on new() - ("GCC_CHECK_RETURN_VALUE_OF_OPERATOR_NEW", "boolean", None), - - # Use CodeWarrior inline assembly syntax - ("GCC_CW_ASM_SYNTAX", "boolean", "YES"), - - # Use the latest version of the Objective C++ dialect - ("GCC_C_LANGUAGE_STANDARD", "string", "gnu99"), - - # Sets the level of debugging symbols in the output - ("GCC_DEBUGGING_SYMBOLS", "string", None), - - # Set YES for no relocatable code - ("GCC_DYNAMIC_NO_PIC", "boolean", "NO"), - - # Enable the asm keyword - ("GCC_ENABLE_ASM_KEYWORD", "boolean", None), - - # Enable built in functions like memcpy(). - ("GCC_ENABLE_BUILTIN_FUNCTIONS", "boolean", None), - - # Disable CPP Exceptionsstaticlib - ("GCC_ENABLE_CPP_EXCEPTIONS", "boolean", "NO"), - - # Disable CPP RTTI - ("GCC_ENABLE_CPP_RTTI", "boolean", "NO"), - - # Build everything as Objective C++ - ("GCC_INPUT_FILETYPE", "string", None), - - # Program flow for profiling. - ("GCC_INSTRUMENT_PROGRAM_FLOW_ARCS", "boolean", None), - - # Link with static to dynamic libraries - ("GCC_LINK_WITH_DYNAMIC_LIBRARIES", "boolean", None), - - # Enable 64 bit registers for powerpc 64 bit - ("GCC_MODEL_PPC64", "boolean", "NO"), - ("GCC_MODEL_PPC64[arch=ppc64]", "boolean", "YES"), - - # Tune for specific cpu - ("GCC_MODEL_TUNING", "string", "G4"), - ("GCC_MODEL_TUNING[arch=ppc64]", "string", "G5"), - - # Don't share global variables - ("GCC_NO_COMMON_BLOCKS", "boolean", None), - - # Call C++ constuctors on objective-c code - ("GCC_OBJC_CALL_CXX_CDTORS", "boolean", None), - - # bool takes one byte, not 4 - ("GCC_ONE_BYTE_BOOL", "boolean", None), - - # Optimizations level - ("GCC_OPTIMIZATION_LEVEL", "string", "s"), - - # C++ dialects - ("GCC_PFE_FILE_C_DIALECTS", "string", None), - - # Use a precompiled header - ("GCC_PRECOMPILE_PREFIX_HEADER", "boolean", None), - - # Name of the precompiled header - ("GCC_PREFIX_HEADER", "string", None), - - # Defines - ("GCC_PREPROCESSOR_DEFINITIONS", "stringarray", None), - - # Disabled defines - ("GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS", "string", None), - - # Reuse constant strings - ("GCC_REUSE_STRINGS", "boolean", None), - - # Shorten enums - ("GCC_SHORT_ENUMS", "boolean", None), - - # Use strict aliasing - ("GCC_STRICT_ALIASING", "boolean", None), - - # Assume extern symbols are private - ("GCC_SYMBOLS_PRIVATE_EXTERN", "boolean", None), - - # Don't emit code to make the static constructors thread safe - ("GCC_THREADSAFE_STATICS", "boolean", "NO"), - - # Causes warnings about missing function prototypes to become errors - ("GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS", "boolean", None), - - # Non conformant code errors become warnings. - ("GCC_TREAT_NONCONFORMANT_CODE_ERRORS_AS_WARNINGS", "boolean", None), - - # Warnings are errors - ("GCC_TREAT_WARNINGS_AS_ERRORS", "boolean", None), - - # Enable unrolling loops - ("GCC_UNROLL_LOOPS", "boolean", None), - - # Allow native prcompiling support - ("GCC_USE_GCC3_PFE_SUPPORT", "boolean", None), - - # Default to using a register for all function calls - ("GCC_USE_INDIRECT_FUNCTION_CALLS", "boolean", None), - - # Default to long calls - ("GCC_USE_REGISTER_FUNCTION_CALLS", "boolean", None), - - # Allow searching default system include folders. - ("GCC_USE_STANDARD_INCLUDE_SEARCHING", "boolean", None), - - # Which compiler to use - ("GCC_VERSION", "string", "com.apple.compilers.llvm.clang.1_0"), - - # Note: com.apple.compilers.llvmgcc42 generates BAD CODE for ppc64 and 4.2 - # doesn't work at all for ppc64. Only gcc 4.0 is safe for ppc64 - # i386 compiler llvmgcc42 has issues with 64 bit code in xcode3 - ("GCC_VERSION[sdk=macosx10.4]", "string", "com.apple.compilers.llvmgcc42"), - ("GCC_VERSION[sdk=macosx10.5]", "string", "com.apple.compilers.llvmgcc42"), - ("GCC_VERSION[sdk=macosx10.5][arch=i386]", "string", "4.2"), - ("GCC_VERSION[sdk=macosx10.5][arch=ppc64]", "string", "4.0"), - - # Warn of 64 bit value become 32 bit automatically - ("GCC_WARN_64_TO_32_BIT_CONVERSION", "boolean", "YES"), - - # Warn about deprecated functions - ("GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS", "boolean", None), - - # Warn about invalid use of offsetof() - ("GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO", "boolean", None), - - # Warn about missing ending newline in source code. - ("GCC_WARN_ABOUT_MISSING_NEWLINE", "boolean", None), - - # Warn about missing function prototypes - ("GCC_WARN_ABOUT_MISSING_PROTOTYPES", "boolean", "YES"), - - # Warn if the sign of a pointer changed. - ("GCC_WARN_ABOUT_POINTER_SIGNEDNESS", "boolean", "YES"), - - # Warn if return type is missing a value. - ("GCC_WARN_ABOUT_RETURN_TYPE", "boolean", "YES"), - - # Objective-C Warn if required methods are missing in class implementation - ("GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL", "boolean", "YES"), - - # Warn if a switch statement is missing enumeration entries - ("GCC_WARN_CHECK_SWITCH_STATEMENTS", "boolean", "YES"), - - # Warn if Effective C++ violations are present. - ("GCC_WARN_EFFECTIVE_CPLUSPLUS_VIOLATIONS", "boolean", None), - - # Warn is macOS stype "APPL" 4 character constants exist. - ("GCC_WARN_FOUR_CHARACTER_CONSTANTS", "boolean", None), - - # Warn if virtual functions become hidden. - ("GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS", "boolean", "YES"), - - # Disable all warnings. - ("GCC_WARN_INHIBIT_ALL_WARNINGS", "boolean", None), - - # Warn if union initializers are not fully bracketed. - ("GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED", "boolean", "NO"), - - # Warn if parentheses are missing from nested statements. - ("GCC_WARN_MISSING_PARENTHESES", "boolean", "YES"), - - # Warn if a class didn't declare its destructor as virtual if derived. - ("GCC_WARN_NON_VIRTUAL_DESTRUCTOR", "boolean", "YES"), - - # Warn if non-C++ standard keywords are used - ("GCC_WARN_PEDANTIC", "boolean", None), - - # Warn if implict type conversions occur. - ("GCC_WARN_PROTOTYPE_CONVERSION", "boolean", "YES"), - - # Warn if a variable becomes shadowed. - ("GCC_WARN_SHADOW", "boolean", "YES"), - - # Warn if signed and unsigned values are compared. - ("GCC_WARN_SIGN_COMPARE", "boolean", None), - - # Validate printf() and scanf(). - ("GCC_WARN_TYPECHECK_CALLS_TO_PRINTF", "boolean", "YES"), - - # Warn if a variable is clobbered by setjmp() or not initialized. - ("GCC_WARN_UNINITIALIZED_AUTOS", "boolean", "YES"), - - # Warn if a pragma is used that"s not know by this compiler. - ("GCC_WARN_UNKNOWN_PRAGMAS", "boolean", None), - - # Warn if a static function is never used. - ("GCC_WARN_UNUSED_FUNCTION", "boolean", "YES"), - - # Warn if a label is declared but not used. - ("GCC_WARN_UNUSED_LABEL", "boolean", "YES"), - - # Warn if a function parameter isn"t used. - ("GCC_WARN_UNUSED_PARAMETER", "boolean", "YES"), - - # Warn if a value isn't used. - ("GCC_WARN_UNUSED_VALUE", "boolean", "YES"), - - # Warn if a variable isn't used. - ("GCC_WARN_UNUSED_VARIABLE", "boolean", "YES"), - - # Merge object files into a single file (static libraries) - ("GENERATE_MASTER_OBJECT_FILE", "boolean", None), - - # Force generating a package information file - ("GENERATE_PKGINFO_FILE", "boolean", None), - - # Insert profiling code - ("GENERATE_PROFILING_CODE", "boolean", "NO"), - - # List of search paths for headers - ("HEADER_SEARCH_PATHS", "stringarray", None), - - # Directories for recursive search - ("INCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES", "string", None), - - # Expand the build settings in the plist file - ("INFOPLIST_EXPAND_BUILD_SETTINGS", "boolean", None), - - # Name of the plist file - ("INFOPLIST_FILE", "string", None), - - # Preprocessor flags for the plist file - ("INFOPLIST_OTHER_PREPROCESSOR_FLAGS", "string", None), - - # Output file format for the plist - ("INFOPLIST_OUTPUT_FORMAT", "string", None), - - # Prefix header for plist - ("INFOPLIST_PREFIX_HEADER", "string", None), - - # Allow preprocessing of the plist file - ("INFOPLIST_PREPROCESS", "boolean", None), - - # Defines for the plist file - ("INFOPLIST_PREPROCESSOR_DEFINITIONS", "stringarray", None), - - # Initialization routine name - ("INIT_ROUTINE", "string", None), - - # BSD group to attach for the installed executable - ("INSTALL_GROUP", "string", None), - - # File mode flags for installed executable - ("INSTALL_MODE_FLAG", "string", None), - - # Owner account for installed executable - ("INSTALL_OWNER", "string", None), - - # Path for installed executable - ("INSTALL_PATH", "string", None), - - # Keep private externs private - ("KEEP_PRIVATE_EXTERNS", "boolean", None), - - # Change the interal name of the dynamic library - ("LD_DYLIB_INSTALL_NAME", "string", None), - - # Generate a map file for dynamic libraries - ("LD_GENERATE_MAP_FILE", "boolean", None), - - # Path for the map file - ("LD_MAP_FILE_PATH", "string", None), - - # Flags to pass to a library using OpenMP - ("LD_OPENMP_FLAGS", "string", None), - - # List of paths to search for a library - ("LD_RUNPATH_SEARCH_PATHS", "string", None), - - # List of directories to search for libraries - ("LIBRARY_SEARCH_PATHS", "stringarray", None), - - # Display mangled names in linker - ("LINKER_DISPLAYS_MANGLED_NAMES", "boolean", None), - - # Link the standard libraries - ("LINK_WITH_STANDARD_LIBRARIES", "boolean", None), - - # Type of Mach-O file - ("MACH_O_TYPE", "string", "mh_execute"), - - # Deployment minimum OS - ("MACOSX_DEPLOYMENT_TARGET", "string", ""), - - # Kernel module name - ("MODULE_NAME", "string", None), - - # Kernel driver start function name - ("MODULE_START", "string", None), - - # Kernel driver stop function name - ("MODULE_STOP", "string", None), - - # Version number of the kernel driver - ("MODULE_VERSION", "string", None), - - # Root folder for intermediate files - ("OBJROOT", "string", "temp"), - - # If YES, only build the active CPU for fast recompilation - ("ONLY_ACTIVE_ARCH", "boolean", "NO"), - - # Path to file for order of functions to link - ("ORDER_FILE", "string", None), - - # Extra flags to pass to the C compiler - ("OTHER_CFLAGS", "string", None), - - # Extra flags to pass to the code sign tool - ("OTHER_CODE_SIGN_FLAGS", "string", None), - - # Extra flags to pass to the C++ compiler - ("OTHER_CPLUSPLUSFLAGS", "string", None), - - # Extra flags to pass to the linker - ("OTHER_LDFLAGS", "stringarray", None), - - # Extra flags to pass to the unit test tool - ("OTHER_TEST_FLAGS", "string", None), - - # Output file format for the plist file - ("PLIST_FILE_OUTPUT_FORMAT", "string", None), - - # Prebind the functions together - ("PREBINDING", "boolean", "YES"), - - # Include headers included in precompiler header - ("PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR", "boolean", None), - - # Flags to pass for pre-linker - ("PRELINK_FLAGS", "string", None), - - # Libraries to use for pre-linking - ("PRELINK_LIBS", "string", None), - - # Don't deleate dead code initializers - ("PRESERVE_DEAD_CODE_INITS_AND_TERMS", "boolean", None), - - # Path to copy private headers for building - ("PRIVATE_HEADERS_FOLDER_PATH", "string", None), - - # Product name - ("PRODUCT_NAME", "string", "$(TARGET_NAME)"), - - # Path to copy public headers for building - ("PUBLIC_HEADERS_FOLDER_PATH", "string", None), - - # Paths to search for rez - ("REZ_SEARCH_PATHS", "string", None), - - # Scan source code for include files for dependency graph generation. - ("SCAN_ALL_SOURCE_FILES_FOR_INCLUDES", "boolean", None), - - # SDK to use to for this build - ("SDKROOT", "string", None), - - # Flags for the section reordering - ("SECTORDER_FLAGS", "string", None), - - # Strip symbols in a seperate pass - ("SEPARATE_STRIP", "boolean", None), - - # Edit symbols with nmedit - ("SEPARATE_SYMBOL_EDIT", "boolean", None), - - # Path for directory for precompiled header files - ("SHARED_PRECOMPS_DIR", "string", None), - - # Skip the install phase in deployment - ("SKIP_INSTALL", "boolean", None), - - # Type of libary for Standard C - ("STANDARD_C_PLUS_PLUS_LIBRARY_TYPE", "string", None), - - # Encoding for Strings file for localization - ("STRINGS_FILE_OUTPUT_ENCODING", "string", "UTF-8"), - - # Flags to pass to the symbol stripper - ("STRIPFLAGS", "string", None), - - # Set to YES to strip symbols from installed product - ("STRIP_INSTALLED_PRODUCT", "boolean", None), - - # Style of symbol stripping - ("STRIP_STYLE", "string", None), - - # Products are placed in this folder - ("SYMROOT", "string", "temp"), - - # Path to the executable that accepts unit test bundles - ("TEST_HOST", "string", None), - - # Path to unit test tool - ("TEST_RIG", "string", None), - - # Path to file with symbols to NOT export - ("UNEXPORTED_SYMBOLS_FILE", "string", None), - - # Paths to user headers - ("USER_HEADER_SEARCH_PATHS", "string", None), - - # List of allowable cpu architectures - ("VALID_ARCHS", "string", None), - - # Name of the executable that creates the version info. - ("VERSIONING_SYSTEM", "string", None), - - # User name of the invoker of the version tool - ("VERSION_INFO_BUILDER", "string", None), - - # Allow exporting the version information - ("VERSION_INFO_EXPORT_DECL", "string", None), - - # Name of the file for version information - ("VERSION_INFO_FILE", "string", None), - - # Version info prefix - ("VERSION_INFO_PREFIX", "string", None), - - # Version info suffix - ("VERSION_INFO_SUFFIX", "string", None), - - # List of additional warning flags to pass to the compiler. - ("WARNING_CFLAGS", "stringarray", None), - - # List of additional warning flags to pass to the linker. - ("WARNING_LDFLAGS", "stringarray", None), - - # Extension for product wrappers - ("WRAPPER_EXTENSION", "string", None) +# Supported input files +SUPPORTED_FILES = ( + FileTypes.icns, FileTypes.h, FileTypes.cpp, FileTypes.c, + FileTypes.m, FileTypes.mm, FileTypes.ppc, FileTypes.x64, + FileTypes.x86, FileTypes.frameworks, FileTypes.exe, + FileTypes.library, FileTypes.glsl ) ######################################## @@ -1057,1528 +440,1278 @@ def test(ide, platform_type): ######################################## -def calcuuid(input_str): +def add_XCBuildConfiguration(build_settings, configuration): """ - Given a string, create a 96 bit unique hash for XCode + Update the settings for a XCBuildConfiguration Args: - input_str: string to hash - Returns: - 96 bit hash string in upper case. + build_settings: List of build settings + configuration: Configuration to use """ - temphash = hashlib.md5(convert_to_windows_slashes( - input_str).encode("utf-8")).hexdigest() + # pylint: disable=protected-access + + ide = configuration.ide + solution = configuration.project.solution + + # Xcode 13 and higher (ARM), requires code signing + if ide >= IDETypes.xcode13: + build_settings.add_dict_entry( + "CODE_SIGN_IDENTITY", "-") + build_settings.add_dict_entry( + "CODE_SIGN_IDENTITY[sdk=macosx*]", "Apple Development") + build_settings.add_dict_entry( + "CODE_SIGN_STYLE", "Automatic") + build_settings.add_dict_entry( + "CONFIGURATION_BUILD_DIR", "$(SYMROOT)/$(PRODUCT_NAME)$(SUFFIX)") + build_settings.add_dict_entry( + "CONFIGURATION_TEMP_DIR", "$(SYMROOT)/$(PRODUCT_NAME)$(SUFFIX)") + build_settings.add_dict_entry( + "DEVELOPMENT_TEAM", "SK433TW842") + build_settings.add_dict_entry( + "PROVISIONING_PROFILE_SPECIFIER", "") + + # Set the default SDKROOT + build_settings.add_dict_entry("SDKROOT", solution._xc_sdkroot) + + # Only add for Xcode 3, since Xcode 4 and higher doesn't support PPC + if configuration.platform.is_macosx() and ide < IDETypes.xcode4: + build_settings.add_dict_entry( + "SDKROOT[arch=ppc64]", "macosx10.5") + build_settings.add_dict_entry( + "SDKROOT[arch=ppc]", "macosx10.5") + + if ide >= IDETypes.xcode13: + build_settings.add_dict_entry( + "SUFFIX", + solution.ide_code + + solution.platform_code + + configuration.short_code) - # Take the hash string and only use the top 96 bits - - return temphash[0:24].upper() ######################################## -def quote_string_if_needed(input_path): +class PBXContainerItemProxy(JSONDict): """ - Quote a string for XCode. - - XCode requires quotes for certain characters. If any illegal character - exist in the string, the string will be reencoded to a quoted string using - XCode JSON rules. + Each PBXContainerItemProxy entry - Args: - input_path: string to encapsulate. - Returns: - Original input string if XCode can accept it or properly quoted + Attributes: + native_target: PBXNativeTarget to build. """ - # If there are any illegal characters, break - for item in input_path: - if item not in _XCODESAFESET: - break - else: - # No illegal characters in the string - if not input_path: - return "\"\"" - return input_path + def __init__(self, native_target, project_uuid): + """ + Initialize a PBXContainerItemProxy record. + + Args: + native_target: Parent PBXNativeTarget + project_uuid: Parent uuid + """ + + # Sanity check + if not isinstance(native_target, PBXNativeTarget): + raise TypeError( + "parameter \"native_target\" must be of type PBXNativeTarget") + + uuid = calcuuid("PBXContainerItemProxy" + native_target.target_name) + JSONDict.__init__( + self, + name=uuid, + isa="PBXContainerItemProxy", + comment="PBXContainerItemProxy", + uuid=uuid) + self.add_item( + JSONEntry( + name="containerPortal", + value=project_uuid, + comment="Project object")) + self.add_item(JSONEntry(name="proxyType", value="1")) + self.add_item( + JSONEntry( + name="remoteGlobalIDString", + value=native_target.uuid)) + self.add_item( + JSONEntry( + name="remoteInfo", + value="\"{}\"".format( + native_target.target_name))) - # Quote the escaped string. - return "\"{}\"".format(input_path.replace("\"", "\\\"")) + # PBXNativeTarget to build. + self.native_target = native_target ######################################## -class JSONRoot(object): +class PBXFrameworksBuildPhase(JSONDict): """ - XCode JSON root object - - Every JSON entry for XCode derives from this object and has a minimum of a - name, comment, uuid and an enabled flag. + Each PBXFrameworksBuildPhase entry Attributes: - name: Object's name (Can also be the uuid) - comment: Optional object's comment field - uuid: Optional uuid - enabled: If True, output this object in generated output. - suffix: Optional suffix used in generated output. - value: Value + files: JSONArray of PBXBuildFile records """ - def __init__(self, name, comment=None, uuid=None, - suffix=";", enabled=True, value=None): + def __init__(self, file_reference): """ - Initialize the JSONRoot entry. - + Initialize PBXFrameworksBuildPhase Args: - name: Name of this object - comment: Optional comment - uuid: uuid hash of the object - suffix: string to append at the end of the generated line of output. - enabled: If False, don't output this object in the generated object. - value: Optional value + file_reference: PBXFileReference record """ - self.name = name - self.comment = comment - self.uuid = uuid - self.enabled = enabled - self.suffix = suffix - self.value = value - - def add_item(self, item): - """ - Append an item to the array. + # Sanity check + if not isinstance(file_reference, PBXFileReference): + raise TypeError( + "parameter \"file_reference\" must be of type PBXFileReference") - Args: - item: JSONRoot based object. - """ + uuid = calcuuid( + "PBXFrameworksBuildPhase" + + file_reference.relative_pathname) + + JSONDict.__init__( + self, + name=uuid, + isa="PBXFrameworksBuildPhase", + comment="Frameworks", + uuid=uuid) + + self.add_item(JSONEntry(name="buildActionMask", value="2147483647")) + + files = JSONArray(name="files") + self.add_item(files) - self.value.append(item) + self.add_item( + JSONEntry( + name="runOnlyForDeploymentPostprocessing", + value="0")) - def find_item(self, name): + # JSONArray of PBXBuildFile records + self.files = files + + def add_build_file(self, build_file): """ - Find a named item. + Add a framework to the files record Args: - name: Name of the item to locate - Returns: - Reference to item or None if not found. + build_file: PBXBuildFile record """ - for item in self.value: - if item.name == name: - return item - return None + # Sanity check + if not isinstance(build_file, PBXBuildFile): + raise TypeError( + "parameter \"build_file\" must be of type PBXBuildFile") + + self.files.add_item( + JSONEntry( + build_file.uuid, + comment=os.path.basename( + build_file.file_reference.relative_pathname) + + " in Frameworks", suffix=",")) + + @staticmethod + def get_phase_name(): + """ + Return the build phase name for XCode. + """ + return "Frameworks" + ######################################## -class JSONEntry(JSONRoot): +class PBXNativeTarget(JSONDict): """ - XCode JSON single line entry. + Each PBXNative entry - Each JSON entry for XCode consists of the name followed by an optional - comment, and an optional value and then a mandatory suffix. + Attributes: + parent: Objects record (Parent) + target_name: Name of the target + build_config_list: JSONEntry of configurations + build_phases: JSONArray of build phases + build_rules: JSONArray of build rules + dependencies: JSONArray of dependencies """ - def __init__(self, name, comment=None, value=None, - suffix=";", enabled=True): + def __init__(self, parent, name, productreference, + productname, producttype, build_rules): """ - Initialize the JSONEntry. + Init PBXNativeTarget Args: - name: Name of this object - comment: Optional comment - value: Optional value - suffix: string to append at the end of the generated line of output. - enabled: If False, don't output this object in the generated object. + parent: Parent object + name: Name of the Native target + productreference: Reference to the object being built + productname: Name of the project being built + producttype: Type of product being built """ - JSONRoot.__init__( + uuid = calcuuid("PBXNativeTarget" + name) + JSONDict.__init__( self, - name=name, - comment=comment, - suffix=suffix, - enabled=enabled, - value=value) - - def generate(self, line_list, indent=0): - """ - Generate the text lines for this XML element. + name=uuid, + isa="PBXNativeTarget", + comment=name, + uuid=uuid) - Args: - line_list: list object to have text lines appended to - indent: number of tabs to insert (For recursion) - """ + self.build_config_list = JSONEntry( + "buildConfigurationList", + comment=( + "Build configuration list " + "for PBXNativeTarget \"{}\"").format(name), + enabled=False) + self.add_item(self.build_config_list) - if not self.enabled: - return 0 + self.build_phases = JSONArray("buildPhases") + self.add_item(self.build_phases) - # Determine the indentation - tabs = TABS * indent + self.build_rules = JSONArray("buildRules") + self.add_item(self.build_rules) + for item in build_rules: + self.build_rules.add_array_entry( + item.name).comment = "PBXBuildRule" - # Set the value string - value = "" if self.value is None else " = " + \ - quote_string_if_needed(self.value) + self.dependencies = JSONArray("dependencies") + self.add_item(self.dependencies) - # Set the comment string - comment = "" if self.comment is None else " /* {} */".format( - self.comment) + self.add_item(JSONEntry("name", value=name)) + self.add_item(JSONEntry("productName", value=productname)) - line_list.append( - "{}{}{}{}{}".format( - tabs, - quote_string_if_needed(self.name), - value, - comment, - self.suffix)) - return 0 + self.add_item( + JSONEntry( + "productReference", + value=productreference.uuid, + comment=productreference.relative_pathname)) -######################################## + self.add_item( + JSONEntry( + "productType", + value=producttype)) + self.parent = parent + self.target_name = name -class JSONArray(JSONRoot): - """ - XCode JSON array. + def add_build_phase(self, build_phase): + """ + Append a Buildphase target - Each JSON entry for XCode consists of the name followed by an optional - comment, and an optional value and then a mandatory suffix. + Args: + build_phase: Build phase object + """ - Attributes: - disable_if_empty: True if output is disabled if the list is empty - """ + self.build_phases.add_item( + JSONEntry( + build_phase.uuid, + comment=build_phase.get_phase_name(), + suffix=",")) - def __init__(self, name, comment=None, value=None, suffix=";", - enabled=True, disable_if_empty=False): + def add_dependency(self, target_dependency): """ - Initialize the entry. + Append a dependency. Args: - name: Name of this object - comment: Optional comment - value: List of default values - suffix: Suffix, either ";" or "," - enabled: If False, don't output this object in the generated object. - disable_if_empty: If True, don't output if no items in the list. + target_dependency: Target to depend on. """ - if value is None: - value = [] - - JSONRoot.__init__( - self, - name=name, - comment=comment, - suffix=suffix, - enabled=enabled, - value=value) + self.dependencies.add_item( + JSONEntry( + target_dependency.uuid, + comment=target_dependency.isa, + suffix=",")) - self.disable_if_empty = disable_if_empty + def set_config_list(self, config_list_reference): + """ + Attach a configuration list. + """ + self.build_config_list.value = config_list_reference.uuid + self.build_config_list.enabled = True def generate(self, line_list, indent=0): """ - Generate the text lines for this XML element. - Args: - line_list: list object to have text lines appended to - indent: number of tabs to insert (For recursion) + Write this record to output """ - if not self.enabled: - return 0 - - # Disable if there are no values? - if self.disable_if_empty and not self.value: - return 0 - - # Determine the indentation - tabs = TABS * indent - indent = indent + 1 - - # Get the optional comment - comment = "" if self.comment is None else " /* {} */".format( - self.comment) - - # Generate the array opening - line_list.append("{}{}{} = (".format(tabs, self.name, comment)) - - # Generate the array - for item in self.value: - item.generate(line_list, indent=indent) - - # Generate the array closing - line_list.append("{}){}".format(tabs, self.suffix)) - return 0 - - -def make_jsonarray(input_array): - """ - Convert an iterable of strings into JSONArray entries. - - Args: - input_array: Iterable of strings. - Returns: - list of JSONEntry items. - """ - - result = [] - for item in input_array: - result.append(JSONEntry(item, suffix=",")) - return result + return JSONDict.generate(self, line_list, indent) ######################################## -class JSONDict(JSONRoot): +class PBXProject(JSONDict): """ - XCode JSON dictionary - - Each JSON entry for XCode consists of the name followed by an optional - comment, and an optional value and then a mandatory suffix. + Each PBXProject entry Attributes: - disable_if_empty: True if output is disabled if the list is empty - isa: "Is a" name + build_config_list: List of build configurations + main_group: JSONEntry of the main group + targets: JSONArray of the targets """ - def __init__(self, name, isa=None, comment=None, value=None, - suffix=";", uuid=None, enabled=True, disable_if_empty=False): + def __init__(self, uuid, solution): """ - Initialize the entry. + Init PBXProject Args: - name: Name of this object - isa: "Is a" type of dictionary object - comment: Optional comment - value: List of default values - suffix: Suffix, either ";" or "," - uuid: uuid hash of the object - enabled: If False, don't output this object in the generated object. - disable_if_empty: If True, don't output if no items in the list. + uuid: Unique UUID + solution: Parent solution """ - - if uuid is None: - uuid = "" - - if value is None: - value = [] - - JSONRoot.__init__( + JSONDict.__init__( self, - name=name, - comment=comment, - uuid=uuid, - suffix=suffix, - enabled=enabled, - value=value) - - self.disable_if_empty = disable_if_empty - self.isa = isa + name=uuid, + isa="PBXProject", + comment="Project object", + uuid=uuid) - if isa is not None: - self.add_item(JSONEntry("isa", value=isa)) + # Look up versioning information + object_versions = OBJECT_VERSIONS.get(solution.ide) - def generate(self, line_list, indent=0): - """ - Generate the text lines for this XML element. - Args: - line_list: list object to have text lines appended to - indent: number of tabs to insert (For recursion) - """ + # Attributes record + attributes = JSONDict("attributes") + self.add_item(attributes) - if not self.enabled: - return 0 + attributes.add_item( + JSONEntry( + "BuildIndependentTargetsInParallel", + value="YES")) - # Disable if there are no values? - if self.disable_if_empty and self.value is not None: - return 0 + upgrade = object_versions[1] + attributes.add_item( + JSONEntry( + "LastUpgradeCheck", + value=upgrade, enabled=upgrade is not None)) - # Determine the indentation - tabs = TABS * indent - indent = indent + 1 + self.build_config_list = JSONEntry( + "buildConfigurationList", + comment=( + "Build configuration list " + "for PBXProject \"{}\"" + ).format(solution.name), enabled=False) + self.add_item(self.build_config_list) - # Get the optional comment" - comment = "" if self.comment is None else " /* {} */".format( - self.comment) + self.add_item( + JSONEntry( + "compatibilityVersion", + value=object_versions[2])) - # Generate the dictionary opening - line_list.append("{}{}{} = {{".format(tabs, self.name, comment)) + self.add_item( + JSONEntry( + "developmentRegion", + value=object_versions[3], + enabled=object_versions[3] is not None)) - # Generate the dictionary - for item in self.value: - item.generate(line_list, indent=indent) + ide = solution.ide + if ide >= IDETypes.xcode12: + self.add_item( + JSONEntry("developmentRegion", value="en")) - # Generate the dictionary closing - line_list.append("{}}}{}".format(tabs, self.suffix)) - return 0 + self.add_item(JSONEntry("hasScannedForEncodings", value="1")) -######################################## + known_regions = JSONArray("knownRegions") + self.add_item(known_regions) + known_regions.add_array_entry("en") + self.main_group = JSONEntry("mainGroup", enabled=False) + self.add_item(self.main_group) -class JSONObjects(JSONDict): - """ - XCode JSON dictionary + self.add_item(JSONEntry("projectDirPath", value="")) + self.add_item(JSONEntry("projectRoot", value="")) - Each JSON entry for XCode consists of the name followed by an optional - comment, and an optional value and then a mandatory suffix. - """ + self.targets = JSONArray("targets") + self.add_item(self.targets) - def __init__(self, name, uuid=None, enabled=True): + def append_target(self, item): """ - Initialize the entry. - - Args: - name: Name of this object - uuid: uuid hash of the object - enabled: If False, don't output this object in the generated object. + Append a PBXNative target """ - JSONDict.__init__(self, name, uuid=uuid, enabled=enabled) + self.targets.add_item( + JSONEntry( + item.uuid, + comment=item.target_name, + suffix=",")) - def get_entries(self, isa): + def set_config_list(self, config_list_reference): """ - Return a list of items that match the isa name. - - Args: - isa: isa name string. - Returns: - List of entires found, can be an empty list. + Attach a configuration list. """ + self.build_config_list.value = config_list_reference.uuid + self.build_config_list.enabled = True - item_list = [] - for item in self.value: - if item.isa == isa: - item_list.append(item) - return item_list - - def generate(self, line_list, indent=0): + def set_root_group(self, rootgroup): """ - Generate the text lines for this XML element. - Args: - line_list: list object to have text lines appended to - indent: number of tabs to insert (For recursion) + Set the root group. """ + self.main_group.value = rootgroup.uuid + self.main_group.comment = rootgroup.group_name + self.main_group.enabled = True - if not self.enabled: - return 0 - - # Determine the indentation - tabs = TABS * indent - indent = indent + 1 - - # Set the optional comment - comment = "" if self.comment is None else " /* {} */".format( - self.comment) - # Generate the dictionary opening - line_list.append("{}{}{} = {{".format(tabs, self.name, comment)) +######################################## - # Output the objects in "isa" order for XCode - for object_group in OBJECT_ORDER: - item_list = [] - for item in self.value: - if item.isa == object_group: - item_list.append(item) - if item_list: - - # Sort by uuid - item_list = sorted(item_list, key=attrgetter("uuid")) - - # Using the name of the class, output the array of data items - line_list.append("") - line_list.append("/* Begin {} section */".format(object_group)) - for item in item_list: - - # Because Apple hates me. Flatten these records instead - # of putting the data on individual lines, because, just - # because. - - if object_group in FLATTENED_OBJECTS: - # Generate the lines - temp_list = [] - item.generate(temp_list, indent=0) - # Flatten it and strip the tabs - temp = " ".join(temp_list).replace(TABS, "") - - # Remove this space to match the output of XCode - temp = temp.replace(" isa", "isa") - - # Insert the flattened line - line_list.append(tabs + TABS + temp) - else: - - # Output the item as is - item.generate(line_list, indent=indent) - line_list.append("/* End {} section */".format(object_group)) - - line_list.append("{}}}{}".format(tabs, self.suffix)) - return 0 - -######################################## - - -class PBXBuildFile(JSONDict): - """ - Create a PBXBuildFile entry +class PBXSourcesBuildPhase(JSONDict): + """ + Each PBXSourcesBuildPhase entry Attributes: - file_reference: PBXFileReference of the file being compiled + files: JSONArray of files + owner: Owner object + buildfirstlist: List of files to build first + buildlist: List of file to build later """ - def __init__(self, file_reference, output_reference): + def __init__(self, owner): """ - Init the PBXBuildFile record. + Init PBXSourcesBuildPhase Args: - file_reference: File reference of object to build - output_reference: File reference of lib/exe being built. + owner: Parent object """ - - # Sanity check - if not isinstance(file_reference, PBXFileReference): - raise TypeError( - "parameter \"file_reference\" must be of type PBXFileReference") - - if not isinstance(output_reference, PBXFileReference): - raise TypeError( - "parameter \"output_reference\" must be of type PBXFileReference") - - # Make the uuid uuid = calcuuid( - "PBXBuildFile" + - file_reference.source_file.relative_pathname + - output_reference.source_file.relative_pathname) - - basename = os.path.basename( - file_reference.source_file.relative_pathname) - - ref_type = "Frameworks" \ - if file_reference.source_file.type is FileTypes.frameworks \ - else "Sources" - + "PBXSourcesBuildPhase" + + owner.relative_pathname) JSONDict.__init__( self, name=uuid, - isa="PBXBuildFile", - comment="{} in {}".format(basename, ref_type), + isa="PBXSourcesBuildPhase", + comment="Sources", uuid=uuid) - # Add the uuid of the file reference + self.add_item(JSONEntry("buildActionMask", value="2147483647")) + files = JSONArray("files") + self.files = files + self.add_item(files) self.add_item( JSONEntry( - name="fileRef", - value=file_reference.uuid, - comment=basename)) + "runOnlyForDeploymentPostprocessing", + value="0")) + self.owner = owner + self.buildfirstlist = [] + self.buildlist = [] + + def append_file(self, item): + """ + Append a file uuid and name to the end of the list + """ + + if item.file_reference.source_file.type == FileTypes.glsl: + self.buildfirstlist.append([item, os.path.basename( + item.file_reference.relative_pathname)]) + else: + self.buildlist.append([item, os.path.basename( + item.file_reference.relative_pathname)]) + + @staticmethod + def get_phase_name(): + """ + Return the build phase name for XCode. + """ + return "Sources" + + def generate(self, line_list, indent=0): + """ + Write this record to output + """ + + self.buildfirstlist = sorted( + self.buildfirstlist, key=itemgetter(1)) + self.buildlist = sorted( + self.buildlist, key=itemgetter(1)) + for item in self.buildfirstlist: + self.files.add_item( + JSONEntry( + item[0].uuid, + comment="{} in Sources".format( + item[1]), suffix=",")) + + for item in self.buildlist: + self.files.add_item( + JSONEntry( + item[0].uuid, + comment="{} in Sources".format( + item[1]), suffix=",")) + return JSONDict.generate(self, line_list, indent) - # PBXFileReference of the file being compiled - self.file_reference = file_reference ######################################## -class BuildGLSL(JSONDict): +class PBXTargetDependency(JSONDict): """ - Each PBXBuildRule entry for building GLSL files. + Each PBXTargetDependency entry """ - def __init__(self, configuration): + def __init__(self, proxy, nativetarget): """ - Initialize the PBXBuildRule for GLSL + Init PBXTargetDependency Args: - configuration: Configuration to test for IDE + proxy: target proxy + nativetarget: Native target """ - - uuid = calcuuid("PBXBuildRule" + "BuildGLSL") - + uuid = calcuuid( + "PBXTargetDependency" + + proxy.native_target.target_name + + nativetarget.target_name) JSONDict.__init__( self, name=uuid, - isa="PBXBuildRule", - comment="PBXBuildRule", + isa="PBXTargetDependency", + comment="PBXTargetDependency", uuid=uuid) self.add_item( JSONEntry( - name="compilerSpec", - value="com.apple.compilers.proxy.script")) - self.add_item(JSONEntry(name="filePatterns", value="*.glsl")) - self.add_item(JSONEntry(name="fileType", value="pattern.proxy")) - ide = configuration.ide - if ide >= IDETypes.xcode12: - self.add_item(JSONArray(name="inputFiles")) - - self.add_item(JSONEntry(name="isEditable", value="1")) - - output_files = JSONArray(name="outputFiles") - self.add_item(output_files) - output_files.add_item( - JSONEntry( - "${INPUT_FILE_DIR}/generated/${INPUT_FILE_BASE}.h", - suffix=",")) - - if ide >= IDETypes.xcode12: - self.add_item(JSONEntry(name="runOncePerArchitecture", value="0")) - + "target", + value=nativetarget.uuid, + comment=nativetarget.target_name)) self.add_item( JSONEntry( - name="script", - value="${BURGER_SDKS}/macosx/bin/stripcomments " - "${INPUT_FILE_PATH}" - " -c -l g_${INPUT_FILE_BASE} " - "${INPUT_FILE_DIR}/generated/${INPUT_FILE_BASE}.h\\n")) + "targetProxy", + value=proxy.uuid, + comment="PBXContainerItemProxy")) ######################################## -class PBXContainerItemProxy(JSONDict): +class XCBuildConfiguration(JSONDict): """ - Each PBXContainerItemProxy entry + Each XCBuildConfiguration entry Attributes: - native_target: PBXNativeTarget to build. + build_settings: JSONDict of build settings + configuration: Parent configuration """ - def __init__(self, native_target, project_uuid): + def __init__(self, configuration, configfilereference, owner, + installpath): """ - Initialize a PBXContainerItemProxy record. + Initialize a XCBuildConfiguration object. Args: - native_target: Parent PBXNativeTarget - project_uuid: Parent uuid + configuration: Configuration + configfilereference: Reference to a config file + owner: Owner object + installpath: Path to install the final product """ - # Sanity check - if not isinstance(native_target, PBXNativeTarget): + # pylint: disable=too-many-branches + # pylint: disable=too-many-statements + + if not isinstance(configuration, Configuration): raise TypeError( - "parameter \"native_target\" must be of type PBXNativeTarget") + "parameter \"configuration\" must be of type Configuration") - uuid = calcuuid("PBXContainerItemProxy" + native_target.target_name) + self.configuration = configuration + ide = configuration.ide + project = configuration.project + solution = project.solution + + uuid = calcuuid("XCBuildConfiguration" + + owner.pbxtype + owner.targetname + configuration.name) JSONDict.__init__( self, name=uuid, - isa="PBXContainerItemProxy", - comment="PBXContainerItemProxy", + isa="XCBuildConfiguration", + comment=configuration.name, uuid=uuid) - self.add_item( - JSONEntry( - name="containerPortal", - value=project_uuid, - comment="Project object")) - self.add_item(JSONEntry(name="proxyType", value="1")) - self.add_item( - JSONEntry( - name="remoteGlobalIDString", - value=native_target.uuid)) - self.add_item( - JSONEntry( - name="remoteInfo", - value="\"{}\"".format( - native_target.target_name))) - # PBXNativeTarget to build. - self.native_target = native_target + # Was there a configuration file? + if configfilereference is not None: + self.add_dict_entry( + "baseConfigurationReference", + configfilereference.uuid).comment = os.path.basename( + configfilereference.filename) + build_settings = JSONDict("buildSettings") + self.add_item(build_settings) + self.build_settings = build_settings -######################################## + if installpath: + build_settings.add_dict_entry( + "INSTALL_PATH", "\"$(HOME)/Applications\"") + if (ide < IDETypes.xcode4 and owner.pbxtype == "PBXProject") or \ + (ide >= IDETypes.xcode4 and owner.pbxtype != "PBXProject"): -class PBXFileReference(JSONDict): - """ - Each PBXFileReference entry. + add_XCBuildConfiguration(build_settings, configuration) - Get the filename path and XCode type + if owner.pbxtype == "PBXProject": - Attributes: - source_file: core.SourceFile record - """ + # Locations of any sparse SDKs + # build_settings.add_dict_entry("ADDITIONAL_SDKS") - def __init__(self, source_file, ide): - """ - Initialize the PBXFileReference object. + # Group permission of deployment + # build_settings.add_dict_entry("ALTERNATE_GROUP") - Args: - source_file: core.SourceFile record - ide: IDETypes of the ide being built for. - """ + # File permissions of deployment + # build_settings.add_dict_entry("ALTERNATE_MODE") - # Sanity check - if not isinstance(source_file, SourceFile): - raise TypeError( - "parameter \"source_file\" must be of type SourceFile") + # Owner permission of deployment + # build_settings.add_dict_entry("ALTERNATE_OWNER") - source_file.relative_pathname = convert_to_linux_slashes( - source_file.relative_pathname) + # Specific files to apply deployment permissions + # build_settings.add_dict_entry("ALTERNATE_PERMISSIONS_FILES") - uuid = calcuuid("PBXFileReference" + source_file.relative_pathname) - basename = os.path.basename(source_file.relative_pathname) + # Always search user paths in C++ (Hard code) + build_settings.add_dict_entry("ALWAYS_SEARCH_USER_PATHS", "NO") - JSONDict.__init__( - self, - name=uuid, - isa="PBXFileReference", - comment=basename, - uuid=uuid) + # Copy Files Build Phase will plist and strings to encoding + # build_settings.add_dict_entry("APPLY_RULES_IN_COPY_FILES") - # If not binary, assume UTF-8 encoding - if source_file.type not in (FileTypes.library, FileTypes.exe, - FileTypes.frameworks): - self.add_item(JSONEntry(name="fileEncoding", value="4")) - - # If an output file, determine the output type - if source_file.type in (FileTypes.library, FileTypes.exe): - value = "archive.ar" if source_file.type is FileTypes.library \ - else "wrapper.application" if basename.endswith(".app") else \ - "compiled.mach-o.executable" - self.add_item(JSONEntry(name="explicitFileType", value=value)) - self.add_item(JSONEntry(name="includeInIndex", value="0")) - - # lastKnownFileType - value = FILE_REF_LAST_KNOWN.get(source_file.type, "sourcecode.c.h") - if value: - - # XCode 3 doesn't support sourcecode.glsl - if ide < IDETypes.xcode5: - if value.endswith(".glsl"): - value = "sourcecode" - - self.add_item(JSONEntry(name="lastKnownFileType", value=value)) - - if source_file.type not in (FileTypes.library, FileTypes.exe): - self.add_item(JSONEntry(name="name", value=basename)) - - if source_file.type in (FileTypes.library, FileTypes.exe): - value = basename - elif source_file.type is FileTypes.frameworks: - value = "System/Library/Frameworks/" + basename - else: - value = source_file.relative_pathname - self.add_item( - JSONEntry(name="path", value=value)) + # Default CPUs + temp_array = JSONArray( + "ARCHS", disable_if_empty=True, fold_array=True) + build_settings.add_item(temp_array) + self.fixup_archs(temp_array) - self.add_item( - JSONEntry( - name="sourceTree", - value=FILE_REF_DIR.get(source_file.type, "SOURCE_ROOT"))) + # List of build variants + temp_array = JSONArray( + "BUILD_VARIANTS", disable_if_empty=True, fold_array=True) + build_settings.add_item(temp_array) - # core.SourceFile record - self.source_file = source_file + # Name of executable that loads the bundle + # build_settings.add_dict_entry("BUNDLE_LOADER") + # Xcode 14 has C++20, use it + if ide >= IDETypes.xcode14: + build_settings.add_dict_entry( + "CLANG_CXX_LANGUAGE_STANDARD", "gnu++20") -######################################## + # Name of the code signing certificate + # build_settings.add_dict_entry("CODE_SIGN_IDENTITY") + # Path to property list containing rules for signing + # build_settings.add_dict_entry("CODE_SIGN_RESOURCE_RULES_PATH") -class PBXFrameworksBuildPhase(JSONDict): - """ - Each PBXFrameworksBuildPhase entry + # Path for build products + if ide < IDETypes.xcode13: + build_settings.add_dict_entry( + "CONFIGURATION_BUILD_DIR", + "$(SYMROOT)/$(PRODUCT_NAME)$(SUFFIX)") - Attributes: - files: JSONArray of PBXBuildFile records - """ + # Path for temp files + build_settings.add_dict_entry( + "CONFIGURATION_TEMP_DIR", + "$(SYMROOT)/$(PRODUCT_NAME)$(SUFFIX)") - def __init__(self, file_reference): - """ - Initialize PBXFrameworksBuildPhase - Args: - file_reference: PBXFileReference record - """ + # Does copying preserve classic mac resource forks? + # build_settings.add_dict_entry("COPYING_PRESERVES_HFS_DATA") - # Sanity check - if not isinstance(file_reference, PBXFileReference): - raise TypeError( - "parameter \"file_reference\" must be of type PBXFileReference") + # Strip debug symbols? + # build_settings.add_dict_entry("COPY_PHASE_STRIP") - uuid = calcuuid( - "PBXFrameworksBuildPhase" + - file_reference.source_file.relative_pathname) + # Numeric project version + # build_settings.add_dict_entry("CURRENT_PROJECT_VERSION") - JSONDict.__init__( - self, - name=uuid, - isa="PBXFrameworksBuildPhase", - comment="Frameworks", - uuid=uuid) + # Strip dead code? + build_settings.add_dict_entry("DEAD_CODE_STRIPPING", "YES") - self.add_item(JSONEntry(name="buildActionMask", value="2147483647")) + # Type of debug symbols (Use dwarf) + build_settings.add_dict_entry("DEBUG_INFORMATION_FORMAT", "dwarf") - files = JSONArray(name="files") - self.add_item(files) + # Are there valid deployment location settings? + # build_settings.add_dict_entry("DEPLOYMENT_LOCATION") - self.add_item( - JSONEntry( - name="runOnlyForDeploymentPostprocessing", - value="0")) + # Process deployment files + # build_settings.add_dict_entry("DEPLOYMENT_POSTPROCESSING") - # JSONArray of PBXBuildFile records - self.files = files + # Destination root folder for deployment + # build_settings.add_dict_entry("DSTROOT") - def add_build_file(self, build_file): - """ - Add a framework to the files record + # Compatible version of the dynamic library + # build_settings.add_dict_entry("DYLIB_COMPATIBILITY_VERSION") - Args: - build_file: PBXBuildFile record - """ + # Numeric version of the dynamic library + # build_settings.add_dict_entry("DYLIB_CURRENT_VERSION") - # Sanity check - if not isinstance(build_file, PBXBuildFile): - raise TypeError( - "parameter \"build_file\" must be of type PBXBuildFile") + # Enable OpenMP + # build_settings.add_dict_entry("ENABLE_OPENMP_SUPPORT") - self.files.add_item( - JSONEntry( - build_file.uuid, - comment=os.path.basename( - build_file.file_reference.source_file.relative_pathname) + - " in Frameworks", suffix=",")) + # Files and folders to ignore on search. + # build_settings.add_dict_entry( + # "EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES") - @staticmethod - def get_phase_name(): - """ - Return the build phase name for XCode. - """ - return "Frameworks" + # Extension for executables + # build_settings.add_dict_entry("EXECUTABLE_EXTENSION") + # Prefix for executables + # build_settings.add_dict_entry("EXECUTABLE_PREFIX") -######################################## + # File with symbols to export + # build_settings.add_dict_entry("EXPORTED_SYMBOLS_FILE") + # Array of directories to search for Frameworks + # build_settings.add_dict_entry("FRAMEWORK_SEARCH_PATHS") -class PBXGroup(JSONDict): - """ - Each PBXGroup entry + # Version of the framework being generated + # build_settings.add_dict_entry("FRAMEWORK_VERSION") - Attributes: - children: Children list - group_name: Name of this group - path: Root path for this group - group_list: List of child groups - file_list: List of child files - """ + # PowerPC only, enable altivec + # build_settings.add_dict_entry("GCC_ALTIVEC_EXTENSIONS") - def __init__(self, group_name, path): - """ - Init the PBXGroup. - """ + # Enable vectorization on loops + # build_settings.add_dict_entry("GCC_AUTO_VECTORIZATION") - # Create uuid, and handle an empty path - uuid_path = path - if path is None: - uuid_path = "" - uuid = calcuuid("PBXGroup" + group_name + uuid_path) + # Default "char" to unsigned if set to true + # build_settings.add_dict_entry("GCC_CHAR_IS_UNSIGNED_CHAR") - JSONDict.__init__( - self, - name=uuid, - isa="PBXGroup", - comment=group_name, - uuid=uuid) + # It true, assume no exceptions on new() + # build_settings.add_dict_entry( + # "GCC_CHECK_RETURN_VALUE_OF_OPERATOR_NEW") - children = JSONArray("children") - self.add_item(children) + # Use CodeWarrior inline assembly syntax + build_settings.add_dict_entry("GCC_CW_ASM_SYNTAX", "YES") - self.add_item( - JSONEntry( - "name", - value=group_name, - enabled=path is None or group_name != path)) + # Use the latest version of the Objective C++ dialect + item = "gnu99" if ide < IDETypes.xcode10 else "gnu11" + build_settings.add_dict_entry("GCC_C_LANGUAGE_STANDARD", item) - self.add_item(JSONEntry("path", value=path, enabled=path is not None)) + # Sets the level of debugging symbols in the output + # build_settings.add_dict_entry("GCC_DEBUGGING_SYMBOLS") - value = "SOURCE_ROOT" if path is not None else "" - self.add_item(JSONEntry("sourceTree", value=value)) + # Set YES for no relocatable code (NO is default) + if configuration.project_type is not ProjectTypes.sharedlibrary: + if ide < IDETypes.xcode12: + build_settings.add_dict_entry("GCC_DYNAMIC_NO_PIC", "NO") + build_settings.add_dict_entry( + "GCC_DYNAMIC_NO_PIC[arch=i386]", "YES") + if ide < IDETypes.xcode4: + build_settings.add_dict_entry( + "GCC_DYNAMIC_NO_PIC[arch=ppc64]", "YES") + build_settings.add_dict_entry( + "GCC_DYNAMIC_NO_PIC[arch=ppc]", "YES") - self.children = children - self.group_name = group_name - self.path = path - self.group_list = [] - self.file_list = [] + # Enable the asm keyword + # build_settings.add_dict_entry("GCC_ENABLE_ASM_KEYWORD") - def is_empty(self): - """ - Return True if there are no entries in this group. + # Enable built in functions like memcpy(). + # build_settings.add_dict_entry("GCC_ENABLE_BUILTIN_FUNCTIONS") - Returns: - True if this PBXGroup has no entries. - """ - return not (self.group_list or self.file_list) + # Disable CPP Exceptionsstaticlib + build_settings.add_dict_entry("GCC_ENABLE_CPP_EXCEPTIONS", "NO") - def add_file(self, file_reference): - """ - Append a file uuid and name to the end of the list. + # Disable CPP RTTI + build_settings.add_dict_entry("GCC_ENABLE_CPP_RTTI", "NO") - Args: - file_reference: PBXFileReference item to attach to this group. - """ + # Build everything as Objective C++ + # build_settings.add_dict_entry("GCC_INPUT_FILETYPE") - # Sanity check - if not isinstance(file_reference, PBXFileReference): - raise TypeError( - "parameter \"file_reference\" must be of type PBXFileReference") + # Program flow for profiling. + # build_settings.add_dict_entry("GCC_INSTRUMENT_PROGRAM_FLOW_ARCS") - self.file_list.append( - (file_reference.uuid, os.path.basename( - file_reference.source_file.relative_pathname))) + # Link with static to dynamic libraries + # build_settings.add_dict_entry("GCC_LINK_WITH_DYNAMIC_LIBRARIES") - def add_group(self, group): - """ - Append a group to the end of the list. + # Enable 64 bit registers for powerpc 64 bit + if ide < IDETypes.xcode4: + build_settings.add_dict_entry( + "GCC_MODEL_PPC64", "NO") + build_settings.add_dict_entry( + "GCC_MODEL_PPC64[arch=ppc64]", "YES") - Args: - group: PBXGroup item to attach to this group. - """ + # Tune for specific cpu + if ide < IDETypes.xcode4: + build_settings.add_dict_entry( + "GCC_MODEL_TUNING", "G4") + build_settings.add_dict_entry( + "GCC_MODEL_TUNING[arch=ppc64]", "G5") - # Sanity check - if not isinstance(group, PBXGroup): - raise TypeError( - "parameter \"group\" must be of type PBXGroup") + # Don't share global variables + # build_settings.add_dict_entry("GCC_NO_COMMON_BLOCKS") - self.group_list.append((group.uuid, group.group_name)) + # Call C++ constuctors on objective-c code + # build_settings.add_dict_entry("GCC_OBJC_CALL_CXX_CDTORS") - def generate(self, line_list, indent=0): - """ - Write this record to output. + # bool takes one byte, not 4 + # build_settings.add_dict_entry("GCC_ONE_BYTE_BOOL") - Args: - line_list: Line list to append new lines. - indent: number of tabs to insert (For recursion) - """ + # Optimizations level + item = "s" if configuration.optimization else "0" + build_settings.add_dict_entry("GCC_OPTIMIZATION_LEVEL", item) - # Output groups first - for item in sorted(self.group_list, key=itemgetter(1)): - self.children.add_item( - JSONEntry( - item[0], - comment=item[1], - suffix=",")) + # C++ dialects + # build_settings.add_dict_entry("GCC_PFE_FILE_C_DIALECTS") - # Output files last - for item in sorted(self.file_list, key=itemgetter(1)): - self.children.add_item( - JSONEntry( - item[0], - comment=item[1], - suffix=",")) + # Use a precompiled header + # build_settings.add_dict_entry("GCC_PRECOMPILE_PREFIX_HEADER") - return JSONDict.generate(self, line_list, indent) + # Name of the precompiled header + # build_settings.add_dict_entry("GCC_PREFIX_HEADER") -######################################## + # Set defines + temp_array = JSONArray("GCC_PREPROCESSOR_DEFINITIONS", + disable_if_empty=True, fold_array=True) + build_settings.add_item(temp_array) + for item in configuration.get_chained_list("define_list"): + temp_array.add_array_entry(item) + # Disabled defines + # build_settings.add_dict_entry( + # "GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS") -class PBXNativeTarget(JSONDict): - """ - Each PBXNative entry + # Reuse constant strings + # build_settings.add_dict_entry("GCC_REUSE_STRINGS") - Attributes: - parent: Objects record (Parent) - target_name: Name of the target - build_config_list: JSONEntry of configurations - build_phases: JSONArray of build phases - build_rules: JSONArray of build rules - dependencies: JSONArray of dependencies - """ + # Shorten enums + # build_settings.add_dict_entry("GCC_SHORT_ENUMS") - def __init__(self, parent, name, productreference, - productname, producttype): - """ - Init PBXNativeTarget + # Use strict aliasing + # build_settings.add_dict_entry("GCC_STRICT_ALIASING") - Args: - parent: Parent object - name: Name of the Native target - productreference: Reference to the object being built - productname: Name of the project being built - producttype: Type of product being built - """ + # Assume extern symbols are private + # build_settings.add_dict_entry("GCC_SYMBOLS_PRIVATE_EXTERN") - uuid = calcuuid("PBXNativeTarget" + name) - JSONDict.__init__( - self, - name=uuid, - isa="PBXNativeTarget", - comment=name, - uuid=uuid) + # Don't emit code to make the static constructors thread safe + build_settings.add_dict_entry("GCC_THREADSAFE_STATICS", "NO") - self.build_config_list = JSONEntry( - "buildConfigurationList", - comment=( - "Build configuration list " - "for PBXNativeTarget \"{}\"").format(name), - enabled=False) - self.add_item(self.build_config_list) + # Causes warnings about missing function prototypes to become errors + # build_settings.add_dict_entry( + # "GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS") - self.build_phases = JSONArray("buildPhases") - self.add_item(self.build_phases) + # Non conformant code errors become warnings. + # build_settings.add_dict_entry( + # "GCC_TREAT_NONCONFORMANT_CODE_ERRORS_AS_WARNINGS") - self.build_rules = JSONArray("buildRules") - self.add_item(self.build_rules) + # Warnings are errors + # build_settings.add_dict_entry("GCC_TREAT_WARNINGS_AS_ERRORS") - self.dependencies = JSONArray("dependencies") - self.add_item(self.dependencies) + # Enable unrolling loops + # build_settings.add_dict_entry("GCC_UNROLL_LOOPS") - self.add_item(JSONEntry("name", value=name)) - self.add_item(JSONEntry("productName", value=productname)) + # Allow native prcompiling support + # build_settings.add_dict_entry("GCC_USE_GCC3_PFE_SUPPORT") - self.add_item( - JSONEntry( - "productReference", - value=productreference.uuid, - comment=productreference.source_file.relative_pathname)) + # Default to using a register for all function calls + # build_settings.add_dict_entry("GCC_USE_INDIRECT_FUNCTION_CALLS") - self.add_item( - JSONEntry( - "productType", - value=producttype)) + # Default to long calls + # build_settings.add_dict_entry("GCC_USE_REGISTER_FUNCTION_CALLS") - self.parent = parent - self.target_name = name + # Allow searching default system include folders. + # build_settings.add_dict_entry( + # "GCC_USE_STANDARD_INCLUDE_SEARCHING") - def add_build_phase(self, build_phase): - """ - Append a Buildphase target + # Which compiler to use + if ide < IDETypes.xcode4 and configuration.platform.is_macosx(): + build_settings.add_dict_entry("GCC_VERSION", "") - Args: - build_phase: Build phase object - """ + # Note: com.apple.compilers.llvmgcc42 generates BAD CODE for + # ppc64 and 4.2 doesn't work at all for ppc64. Only gcc 4.0 is + # safe for ppc64 i386 compiler llvmgcc42 has issues with 64 bit + # code in xcode3 + build_settings.add_dict_entry("GCC_VERSION[arch=ppc64]", "4.0") + build_settings.add_dict_entry("GCC_VERSION[arch=ppc]", "4.0") - self.build_phases.add_item( - JSONEntry( - build_phase.uuid, - comment=build_phase.get_phase_name(), - suffix=",")) + # Warn of 64 bit value become 32 bit automatically + build_settings.add_dict_entry( + "GCC_WARN_64_TO_32_BIT_CONVERSION", "YES") - def add_dependency(self, target_dependency): - """ - Append a dependency. + # Warn about deprecated functions + # build_settings.add_dict_entry( + # "GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS") - Args: - target_dependency: Target to depend on. - """ + # Warn about invalid use of offsetof() + # build_settings.add_dict_entry( + # "GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO") - self.dependencies.add_item( - JSONEntry( - target_dependency.uuid, - comment=target_dependency.isa, - suffix=",")) + # Warn about missing ending newline in source code. + # build_settings.add_dict_entry("GCC_WARN_ABOUT_MISSING_NEWLINE") - def set_config_list(self, config_list_reference): - """ - Attach a configuration list. - """ - self.build_config_list.value = config_list_reference.uuid - self.build_config_list.enabled = True + # Warn about missing function prototypes + build_settings.add_dict_entry( + "GCC_WARN_ABOUT_MISSING_PROTOTYPES", "YES") - def generate(self, line_list, indent=0): - """ - Write this record to output - """ + # Warn if the sign of a pointer changed. + build_settings.add_dict_entry( + "GCC_WARN_ABOUT_POINTER_SIGNEDNESS", "YES") - for item in self.parent.objects.get_entries("PBXBuildRule"): - self.build_rules.add_item( - JSONEntry( - item.name, - comment="PBXBuildRule", - suffix=",")) + # Warn if return type is missing a value. + build_settings.add_dict_entry("GCC_WARN_ABOUT_RETURN_TYPE", "YES") - return JSONDict.generate(self, line_list, indent) + # Objective-C Warn if required methods are missing in class + # implementation + build_settings.add_dict_entry( + "GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL", "YES") -######################################## + # Warn if a switch statement is missing enumeration entries + build_settings.add_dict_entry( + "GCC_WARN_CHECK_SWITCH_STATEMENTS", "YES") + # Warn if Effective C++ violations are present. + # build_settings.add_dict_entry( + # "GCC_WARN_EFFECTIVE_CPLUSPLUS_VIOLATIONS") -class PBXProject(JSONDict): - """ - Each PBXProject entry + # Warn is macOS stype "APPL" 4 character constants exist. + # build_settings.add_dict_entry("GCC_WARN_FOUR_CHARACTER_CONSTANTS") - Attributes: - build_config_list: List of build configurations - main_group: JSONEntry of the main group - targets: JSONArray of the targets - """ + # Warn if virtual functions become hidden. + build_settings.add_dict_entry( + "GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS", "YES") - def __init__(self, uuid, solution): - """ - Init PBXProject + # Disable all warnings. + # build_settings.add_dict_entry("GCC_WARN_INHIBIT_ALL_WARNINGS") - Args: - uuid: Unique UUID - solution: Parent solution - """ - JSONDict.__init__( - self, - name=uuid, - isa="PBXProject", - comment="Project object", - uuid=uuid) + # Warn if union initializers are not fully bracketed. + build_settings.add_dict_entry( + "GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED", "NO") - # Look up versioning information - object_versions = OBJECT_VERSIONS.get(solution.ide) + # Warn if parentheses are missing from nested statements. + build_settings.add_dict_entry( + "GCC_WARN_MISSING_PARENTHESES", "YES") - # Attributes record - attributes = JSONDict("attributes") - self.add_item(attributes) + # Warn if a class didn't declare its destructor as virtual if + # derived. + build_settings.add_dict_entry( + "GCC_WARN_NON_VIRTUAL_DESTRUCTOR", "YES") - attributes.add_item( - JSONEntry( - "BuildIndependentTargetsInParallel", - value="YES")) + # Warn if non-C++ standard keywords are used + # build_settings.add_dict_entry("GCC_WARN_PEDANTIC") - upgrade = object_versions[1] - attributes.add_item( - JSONEntry( - "LastUpgradeCheck", - value=upgrade, enabled=upgrade is not None)) + # Warn if implict type conversions occur. + if ide < IDETypes.xcode12: + build_settings.add_dict_entry( + "GCC_WARN_PROTOTYPE_CONVERSION", "YES") - self.build_config_list = JSONEntry( - "buildConfigurationList", - comment=( - "Build configuration list " - "for PBXProject \"{}{}{}\"" - ).format( - solution.name, - solution.ide_code, - solution.platform_code), - enabled=False) - self.add_item(self.build_config_list) + # Warn if a variable becomes shadowed. + build_settings.add_dict_entry("GCC_WARN_SHADOW", "YES") - self.add_item( - JSONEntry( - "compatibilityVersion", - value=object_versions[2])) + # Warn if signed and unsigned values are compared. + # build_settings.add_dict_entry("GCC_WARN_SIGN_COMPARE") - self.add_item( - JSONEntry( - "developmentRegion", - value=object_versions[3], - enabled=object_versions[3] is not None)) + # Validate printf() and scanf(). + build_settings.add_dict_entry( + "GCC_WARN_TYPECHECK_CALLS_TO_PRINTF", "YES") - ide = solution.ide - if ide >= IDETypes.xcode12: - self.add_item( - JSONEntry("developmentRegion", value="en")) + # Warn if a variable is clobbered by setjmp() or not initialized. + # Warn on autos is spurious for Debug builds + item = "YES" if configuration.optimization else "NO" + build_settings.add_dict_entry("GCC_WARN_UNINITIALIZED_AUTOS", item) - self.add_item(JSONEntry("hasScannedForEncodings", value="1")) + # Warn if a pragma is used that"s not know by this compiler. + # build_settings.add_dict_entry("GCC_WARN_UNKNOWN_PRAGMAS") - known_regions = JSONArray("knownRegions") - self.add_item(known_regions) - known_regions.add_item(JSONEntry("en", suffix=",")) + # Warn if a static function is never used. + build_settings.add_dict_entry("GCC_WARN_UNUSED_FUNCTION", "YES") - self.main_group = JSONEntry("mainGroup", enabled=False) - self.add_item(self.main_group) + # Warn if a label is declared but not used. + build_settings.add_dict_entry("GCC_WARN_UNUSED_LABEL", "YES") - self.add_item(JSONEntry("projectDirPath", value="")) - self.add_item(JSONEntry("projectRoot", value="")) + # Warn if a function parameter isn"t used. + build_settings.add_dict_entry("GCC_WARN_UNUSED_PARAMETER", "YES") - self.targets = JSONArray("targets") - self.add_item(self.targets) + # Warn if a value isn't used. + build_settings.add_dict_entry("GCC_WARN_UNUSED_VALUE", "YES") - def append_target(self, item): - """ - Append a PBXNative target - """ + # Warn if a variable isn't used. + build_settings.add_dict_entry("GCC_WARN_UNUSED_VARIABLE", "YES") - self.targets.add_item( - JSONEntry( - item.uuid, - comment=item.target_name, - suffix=",")) + # Merge object files into a single file (static libraries) + # build_settings.add_dict_entry("GENERATE_MASTER_OBJECT_FILE") - def set_config_list(self, config_list_reference): - """ - Attach a configuration list. - """ - self.build_config_list.value = config_list_reference.uuid - self.build_config_list.enabled = True + # Force generating a package information file + # build_settings.add_dict_entry("GENERATE_PKGINFO_FILE") - def set_root_group(self, rootgroup): - """ - Set the root group. - """ - self.main_group.value = rootgroup.uuid - self.main_group.comment = rootgroup.group_name - self.main_group.enabled = True + # Insert profiling code + item = "YES" if configuration.get_chained_value( + "profile") else "NO" + build_settings.add_dict_entry("GENERATE_PROFILING_CODE", item) -######################################## + # List of search paths for headers + temp_array = JSONArray("HEADER_SEARCH_PATHS", + disable_if_empty=True, fold_array=True) + build_settings.add_item(temp_array) + # Location of extra header paths + for item in configuration.get_chained_list( + "include_folders_list"): + temp_array.add_array_entry(item) + # Directories for recursive search + # build_settings.add_dict_entry( + # "INCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES") -class PBXShellScriptBuildPhase(JSONDict): - """ - Each PBXShellScriptBuildPhase entry + # Expand the build settings in the plist file + # build_settings.add_dict_entry("INFOPLIST_EXPAND_BUILD_SETTINGS") - Attributes: - files: JSONArray of files - """ + # Name of the plist file + # build_settings.add_dict_entry("INFOPLIST_FILE") - def __init__(self, input_data, output, command): - """ - Init PBXShellScriptBuildPhase + # Preprocessor flags for the plist file + # build_settings.add_dict_entry( + # "INFOPLIST_OTHER_PREPROCESSOR_FLAGS") - Args: - input_data: Input file references - output: List of file that will be built - command: Script to build - """ - uuid = calcuuid( - "PBXShellScriptBuildPhase" + - "".join(input_data) + - output + - command) - JSONDict.__init__( - self, - name=uuid, - isa="PBXShellScriptBuildPhase", - comment="ShellScript", - uuid=uuid) + # Output file format for the plist + # build_settings.add_dict_entry("INFOPLIST_OUTPUT_FORMAT") - self.add_item(JSONEntry("buildActionMask", value="2147483647")) - files = JSONArray("files") - self.add_item(files) - self.files = files + # Prefix header for plist + # build_settings.add_dict_entry("INFOPLIST_PREFIX_HEADER") - input_paths = JSONArray("inputPaths", disable_if_empty=True) - self.add_item(input_paths) - for item in input_data: - input_paths.add_item(JSONEntry(item, suffix=",")) + # Allow preprocessing of the plist file + # build_settings.add_dict_entry("INFOPLIST_PREPROCESS") - output_paths = JSONArray("outputPaths") - self.add_item(output_paths) - output_paths.add_item(JSONEntry(output, suffix=",")) + # Defines for the plist file + # build_settings.add_dict_entry( + # "INFOPLIST_PREPROCESSOR_DEFINITIONS") - self.add_item( - JSONEntry( - "runOnlyForDeploymentPostprocessing", - value="0")) - self.add_item(JSONEntry("shellPath", value="/bin/sh")) - self.add_item(JSONEntry("shellScript", value="{}\\n".format(command))) - self.add_item(JSONEntry("showEnvVarsInLog", value="0")) + # Initialization routine name + # build_settings.add_dict_entry("INIT_ROUTINE") - @staticmethod - def get_phase_name(): - """ - Return the build phase name for XCode. - """ - return "ShellScript" + # BSD group to attach for the installed executable + # build_settings.add_dict_entry("INSTALL_GROUP") -######################################## + # File mode flags for installed executable + # build_settings.add_dict_entry("INSTALL_MODE_FLAG") + # Owner account for installed executable + # build_settings.add_dict_entry("INSTALL_OWNER") -class PBXSourcesBuildPhase(JSONDict): - """ - Each PBXSourcesBuildPhase entry + # Keep private externs private + # build_settings.add_dict_entry("KEEP_PRIVATE_EXTERNS") - Attributes: - files: JSONArray of files - owner: Owner object - buildfirstlist: List of files to build first - buildlist: List of file to build later - """ + # Change the interal name of the dynamic library + # build_settings.add_dict_entry("LD_DYLIB_INSTALL_NAME") - def __init__(self, owner): - """ - Init PBXSourcesBuildPhase + # Generate a map file for dynamic libraries + # build_settings.add_dict_entry("LD_GENERATE_MAP_FILE") - Args: - owner: Parent object - """ - uuid = calcuuid( - "PBXSourcesBuildPhase" + - owner.source_file.relative_pathname) - JSONDict.__init__( - self, - name=uuid, - isa="PBXSourcesBuildPhase", - comment="Sources", - uuid=uuid) + # Path for the map file + # build_settings.add_dict_entry("LD_MAP_FILE_PATH") + + # Flags to pass to a library using OpenMP + # build_settings.add_dict_entry("LD_OPENMP_FLAGS") + + # List of paths to search for a library + # build_settings.add_dict_entry("LD_RUNPATH_SEARCH_PATHS") + + # List of directories to search for libraries + temp_array = JSONArray( + "LIBRARY_SEARCH_PATHS", disable_if_empty=True, fold_array=True) + build_settings.add_item(temp_array) + # Location of libraries + for item in configuration.get_chained_list( + "library_folders_list"): + temp_array.add_array_entry(item) + + # Display mangled names in linker + # build_settings.add_dict_entry("LINKER_DISPLAYS_MANGLED_NAMES") + + # Link the standard libraries + # build_settings.add_dict_entry("LINK_WITH_STANDARD_LIBRARIES") + + # Type of Mach-O file + if configuration.project_type is ProjectTypes.library: + item = "staticlib" + elif configuration.project_type is ProjectTypes.sharedlibrary: + item = "mh_dylib" + else: + item = "mh_execute" + build_settings.add_dict_entry("MACH_O_TYPE", item) + + # Deployment minimum OS + item = "10.5" if ide < IDETypes.xcode4 else "10.13" + build_settings.add_dict_entry("MACOSX_DEPLOYMENT_TARGET", item) + if ide < IDETypes.xcode4: + build_settings.add_dict_entry( + "MACOSX_DEPLOYMENT_TARGET[arch=ppc]", "10.4") + + # Kernel module name + # build_settings.add_dict_entry("MODULE_NAME") + + # Kernel driver start function name + # build_settings.add_dict_entry("MODULE_START") + + # Kernel driver stop function name + # build_settings.add_dict_entry("MODULE_STOP") + + # Version number of the kernel driver + # build_settings.add_dict_entry("MODULE_VERSION") + + # Root folder for intermediate files + build_settings.add_dict_entry("OBJROOT", "temp") + + # If YES, only build the active CPU for fast recompilation + build_settings.add_dict_entry("ONLY_ACTIVE_ARCH", "NO") + + # Path to file for order of functions to link + # build_settings.add_dict_entry("ORDER_FILE") + + # Extra flags to pass to the C compiler + # build_settings.add_dict_entry("OTHER_CFLAGS") + + # Extra flags to pass to the code sign tool + # build_settings.add_dict_entry("OTHER_CODE_SIGN_FLAGS") - self.add_item(JSONEntry("buildActionMask", value="2147483647")) - files = JSONArray("files") - self.files = files - self.add_item(files) - self.add_item( - JSONEntry( - "runOnlyForDeploymentPostprocessing", - value="0")) - self.owner = owner - self.buildfirstlist = [] - self.buildlist = [] + # Extra flags to pass to the C++ compiler + # build_settings.add_dict_entry("OTHER_CPLUSPLUSFLAGS") - def append_file(self, item): - """ - Append a file uuid and name to the end of the list - """ + # Extra flags to pass to the linker + temp_array = JSONArray( + "OTHER_LDFLAGS", disable_if_empty=True, fold_array=True) + build_settings.add_item(temp_array) + # Additional libraries + for item in configuration.get_chained_list( + "libraries_list"): + # Get rid of lib and .a + if item.startswith("lib"): + item = item[3:] + if item.endswith(".a"): + item = item[:-2] + temp_array.add_array_entry("-l" + item) - if item.file_reference.source_file.type == FileTypes.glsl: - self.buildfirstlist.append([item, os.path.basename( - item.file_reference.source_file.relative_pathname)]) - else: - self.buildlist.append([item, os.path.basename( - item.file_reference.source_file.relative_pathname)]) + # Extra flags to pass to the unit test tool + # build_settings.add_dict_entry("OTHER_TEST_FLAGS") - @staticmethod - def get_phase_name(): - """ - Return the build phase name for XCode. - """ - return "Sources" + # Output file format for the plist file + # build_settings.add_dict_entry("PLIST_FILE_OUTPUT_FORMAT") - def generate(self, line_list, indent=0): - """ - Write this record to output - """ + # Prebind the functions together + if ide < IDETypes.xcode12: + build_settings.add_dict_entry("PREBINDING", "YES") - self.buildfirstlist = sorted( - self.buildfirstlist, key=itemgetter(1)) - self.buildlist = sorted( - self.buildlist, key=itemgetter(1)) - for item in self.buildfirstlist: - self.files.add_item( - JSONEntry( - item[0].uuid, - comment="{} in Sources".format( - item[1]), suffix=",")) + # Include headers included in precompiler header + # build_settings.add_dict_entry( + # "PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR") - for item in self.buildlist: - self.files.add_item( - JSONEntry( - item[0].uuid, - comment="{} in Sources".format( - item[1]), suffix=",")) - return JSONDict.generate(self, line_list, indent) + # Flags to pass for pre-linker + # build_settings.add_dict_entry("PRELINK_FLAGS") + # Libraries to use for pre-linking + # build_settings.add_dict_entry("PRELINK_LIBS") -######################################## + # Don't deleate dead code initializers + # build_settings.add_dict_entry( + # "PRESERVE_DEAD_CODE_INITS_AND_TERMS") + # Path to copy private headers for building + # build_settings.add_dict_entry("PRIVATE_HEADERS_FOLDER_PATH") -class PBXTargetDependency(JSONDict): - """ - Each PBXTargetDependency entry - """ + # Product name + build_settings.add_dict_entry("PRODUCT_NAME", "$(TARGET_NAME)") - def __init__(self, proxy, nativetarget): - """ - Init PBXTargetDependency + # Path to copy public headers for building + # build_settings.add_dict_entry("PUBLIC_HEADERS_FOLDER_PATH") - Args: - proxy: target proxy - nativetarget: Native target - """ - uuid = calcuuid( - "PBXTargetDependency" + - proxy.native_target.target_name + - nativetarget.target_name) - JSONDict.__init__( - self, - name=uuid, - isa="PBXTargetDependency", - comment="PBXTargetDependency", - uuid=uuid) + # Paths to search for rez + # build_settings.add_dict_entry("REZ_SEARCH_PATHS") - self.add_item( - JSONEntry( - "target", - value=nativetarget.uuid, - comment=nativetarget.target_name)) - self.add_item( - JSONEntry( - "targetProxy", - value=proxy.uuid, - comment="PBXContainerItemProxy")) + # Scan source code for include files for dependency + # graph generation. + # build_settings.add_dict_entry( + # "SCAN_ALL_SOURCE_FILES_FOR_INCLUDES") -######################################## + # SDK to use to for this build + if ide >= IDETypes.xcode10: + build_settings.add_dict_entry("SDKROOT", solution._xc_sdkroot) + # Flags for the section reordering + # build_settings.add_dict_entry("SECTORDER_FLAGS") -class XCBuildConfiguration(JSONDict): - """ - Each XCBuildConfiguration entry + # Strip symbols in a seperate pass + # build_settings.add_dict_entry("SEPARATE_STRIP") - Attributes: - build_settings: JSONDict of build settings - configuration: Parent configuration - """ + # Edit symbols with nmedit + # build_settings.add_dict_entry("SEPARATE_SYMBOL_EDIT") - def __init__(self, configuration, configfilereference, owner, - installpath): - """ - Initialize a XCBuildConfiguration object. + # Path for directory for precompiled header files + # build_settings.add_dict_entry("SHARED_PRECOMPS_DIR") - Args: - configuration: Configuration - configfilereference: Reference to a config file - owner: Owner object - installpath: Path to install the final product - """ + # Skip the install phase in deployment + # build_settings.add_dict_entry("SKIP_INSTALL") - # pylint: disable=too-many-branches - # pylint: disable=too-many-statements + # Type of libary for Standard C + # build_settings.add_dict_entry("STANDARD_C_PLUS_PLUS_LIBRARY_TYPE") - if not isinstance(configuration, Configuration): - raise TypeError( - "parameter \"configuration\" must be of type Configuration") + # Encoding for Strings file for localization + build_settings.add_dict_entry( + "STRINGS_FILE_OUTPUT_ENCODING", "UTF-8") - self.configuration = configuration - ide = configuration.ide - solution = configuration.project.solution + # Flags to pass to the symbol stripper + # build_settings.add_dict_entry("STRIPFLAGS") - uuid = calcuuid("XCBuildConfiguration" + - owner.pbxtype + owner.targetname + configuration.name) - JSONDict.__init__( - self, - name=uuid, - isa="XCBuildConfiguration", - comment=configuration.name, - uuid=uuid) + # Set to YES to strip symbols from installed product + # build_settings.add_dict_entry("STRIP_INSTALLED_PRODUCT") - if configfilereference is not None: - self.add_item( - JSONEntry( - "baseConfigurationReference", - value=configfilereference.uuid, - comment=os.path.basename( - configfilereference.filename))) + # Style of symbol stripping + # build_settings.add_dict_entry("STRIP_STYLE") - build_settings = JSONDict("buildSettings") - self.add_item(build_settings) - self.build_settings = build_settings + # Suffix needed + if ide < IDETypes.xcode13: + build_settings.add_dict_entry( + "SUFFIX", + solution.ide_code + + solution.platform_code + + configuration.short_code) - if installpath: - build_settings.add_item(JSONEntry( - "INSTALL_PATH", - value="\"$(HOME)/Applications\"")) + # Products are placed in this folder + build_settings.add_dict_entry("SYMROOT", "temp") - if (ide < IDETypes.xcode4 and owner.pbxtype == "PBXProject") or \ - (ide >= IDETypes.xcode4 and owner.pbxtype != "PBXProject"): - build_settings.add_item( - JSONEntry("SDKROOT", value=solution._xc_sdkroot)) - if configuration.platform.is_macosx(): - build_settings.add_item( - JSONEntry("SDKROOT[arch=ppc64]", value="macosx10.5")) - build_settings.add_item( - JSONEntry("SDKROOT[arch=ppc]", value="macosx10.5")) + # Path to the executable that accepts unit test bundles + # build_settings.add_dict_entry("TEST_HOST") - if owner.pbxtype == "PBXProject": - # Insert the flags (and overrides) - for item in XCBUILD_FLAGS: - if item[1] in ("string", "boolean"): - build_settings.add_item( - JSONEntry( - item[0], - value=item[2], - enabled=item[2] is not None)) - elif item[1] == "stringarray": - temp_array = JSONArray(item[0], disable_if_empty=True) - build_settings.add_item(temp_array) - if item[2]: - for item2 in item[2]: - temp_array.add_item(JSONEntry(item2, suffix=",")) - - # Set ARCHS - self.fixup_archs() + # Path to unit test tool + # build_settings.add_dict_entry("TEST_RIG") - if configuration.platform.is_ios(): - platform_suffix = "ios" - else: - platform_suffix = "osx" + # Path to file with symbols to NOT export + # build_settings.add_dict_entry("UNEXPORTED_SYMBOLS_FILE") - # Set profiling - if configuration.get_chained_value("profile"): - item = build_settings.find_item("GENERATE_PROFILING_CODE") - item.value = "YES" + # Paths to user headers + # build_settings.add_dict_entry("USER_HEADER_SEARCH_PATHS") - # Set defines - item = build_settings.find_item("GCC_PREPROCESSOR_DEFINITIONS") - for define in configuration.get_chained_list("define_list"): - item.add_item(JSONEntry(define, suffix=",")) - - # Set optimization - item = build_settings.find_item("GCC_OPTIMIZATION_LEVEL") - if configuration.optimization: - item.value = "s" - else: - item.value = "0" + # List of allowable cpu architectures + # build_settings.add_dict_entry("VALID_ARCHS") - # Warn on autos is suprious for Debug builds - item = build_settings.find_item("GCC_WARN_UNINITIALIZED_AUTOS") - if configuration.optimization: - item.value = "YES" - else: - item.value = "NO" + # Name of the executable that creates the version info. + # build_settings.add_dict_entry("VERSIONING_SYSTEM") - # Set the unique output name - idecode = configuration.ide.get_short_code() - item = build_settings.find_item("PRODUCT_NAME") - item.value = ( - "$(TARGET_NAME){}{}{}" - ).format(idecode, platform_suffix, configuration.short_code) + # User name of the invoker of the version tool + # build_settings.add_dict_entry("VERSION_INFO_BUILDER") - # Set the output type - item = build_settings.find_item("MACH_O_TYPE") - if configuration.project_type is ProjectTypes.library: - item.value = "staticlib" - elif configuration.project_type is ProjectTypes.sharedlibrary: - item.value = "mh_dylib" - else: - item.value = "mh_execute" + # Allow exporting the version information + # build_settings.add_dict_entry("VERSION_INFO_EXPORT_DECL") - # Set the PIC type - item = build_settings.find_item("GCC_DYNAMIC_NO_PIC") - item.value = "NO" - if configuration.project_type is not ProjectTypes.sharedlibrary: - build_settings.add_item(JSONEntry( - "GCC_DYNAMIC_NO_PIC[arch=i386]", - value="YES", - enabled=True)) - build_settings.add_item(JSONEntry( - "GCC_DYNAMIC_NO_PIC[arch=ppc64]", - value="YES", - enabled=True)) - build_settings.add_item(JSONEntry( - "GCC_DYNAMIC_NO_PIC[arch=ppc]", - value="YES", - enabled=True)) + # Name of the file for version information + # build_settings.add_dict_entry("VERSION_INFO_FILE") - # Location of extra header paths - item = build_settings.find_item("HEADER_SEARCH_PATHS") - for define in configuration.get_chained_list( - "include_folders_list"): - item.add_item(JSONEntry(define, suffix=",")) + # Version info prefix + # build_settings.add_dict_entry("VERSION_INFO_PREFIX") - # Location of libraries - item = build_settings.find_item("LIBRARY_SEARCH_PATHS") - for define in configuration.get_chained_list( - "library_folders_list"): - item.add_item(JSONEntry(define, suffix=",")) + # Version info suffix + # build_settings.add_dict_entry("VERSION_INFO_SUFFIX") - # Additional libraries - item = build_settings.find_item("OTHER_LDFLAGS") - for define in configuration.get_chained_list( - "libraries_list"): - # Get rid of lib and .a - if define.startswith("lib"): - define = define[3:] - if define.endswith(".a"): - define = define[:-2] - item.add_item(JSONEntry("-l" + define, suffix=",")) + # List of additional warning flags to pass to the compiler. + # build_settings.add_dict_entry("WARNING_CFLAGS") + + # List of additional warning flags to pass to the linker. + # build_settings.add_dict_entry("WARNING_LDFLAGS") + + # Extension for product wrappers + # build_settings.add_dict_entry("WRAPPER_EXTENSION") + + else: + + # Is this a simulator target? + if configuration.platform.is_ios(): + if solution._xc_sdkroot == "iphoneos" and \ + configuration.platform in ( + PlatformTypes.iosemu32, PlatformTypes.iosemu64): + build_settings.add_dict_entry("SDKROOT", "iphonesimulator") # Make sure they are in sorted order build_settings.value = sorted( build_settings.value, key=attrgetter("name")) - self.add_item(JSONEntry("name", value=configuration.name)) + self.add_dict_entry("name", configuration.name) ######################################## - def fixup_archs(self): + def fixup_archs(self, archs): """ Based on the SDKROOT entry, set the default CPUs. """ + # pylint: disable=protected-access + # Start by getting the IDE and platform ide = self.configuration.ide sdkroot = self.configuration.project.solution._xc_sdkroot - # Start by getting SDKROOT - build_settings = self.build_settings - - # Start with no CPUs - cpus = [] - # Test for supported cpus for macosx if self.configuration.platform.is_macosx(): digits = sdkroot[6:].split(".") @@ -2588,32 +1721,34 @@ def fixup_archs(self): version = 6 if ide is IDETypes.xcode3: - cpus.append("ppc") + archs.add_array_entry("ppc") # macosx 10.3.9 is ppc 32 bit only if version >= 4: - cpus.append("ppc64") + archs.add_array_entry("ppc64") # Xcode 14 dropped x86 if ide < IDETypes.xcode14: - cpus.append("i386") + archs.add_array_entry("i386") # Everyone has x64 - cpus.append("x86_64") + archs.add_array_entry("x86_64") # Xcode 12 supports arm64 if ide >= IDETypes.xcode12: - cpus.append("arm64") - - elif self.configuration.platform in (PlatformTypes.iosemu32, PlatformTypes.iosemu64): - cpus.extend(("i386", "x86_64")) + archs.add_array_entry("arm64") - elif self.configuration.platform in (PlatformTypes.ios32, PlatformTypes.ios64): - # cpus.extend(("armv7", "armv7s", "arm64")) - cpus.extend(("armv6", "armv7", "i386", "x86_64")) + elif self.configuration.platform in ( + PlatformTypes.iosemu32, PlatformTypes.iosemu64): + archs.add_array_entry("i386") + archs.add_array_entry("x86_64") - item = build_settings.find_item("ARCHS") - item.value = make_jsonarray(cpus) + elif self.configuration.platform in ( + PlatformTypes.ios32, PlatformTypes.ios64): + archs.add_array_entry("armv6") + archs.add_array_entry("armv7") + archs.add_array_entry("i386") + archs.add_array_entry("x86_64") ######################################## @@ -2714,70 +1849,53 @@ def __init__(self, solution): # pylint: disable=too-many-locals # pylint: disable=too-many-branches - # Parent solution + # Set the parent, uuid, and solution self.solution = solution - uuid = calcuuid("PBXProjectRoot" + solution.xcode_folder_name) # Init the solution JSONDict.__init__(self, solution.name, uuid=uuid) # Initialize entries for master dictionary for the XCode project. - self.add_item(JSONEntry("archiveVersion", value="1")) - self.add_item(JSONDict("classes")) - self.add_item( - JSONEntry( - "objectVersion", - value=OBJECT_VERSIONS.get(solution.ide)[0])) - - # Main object list - objects = JSONObjects("objects") + objects = self.init_root_entries() self.objects = objects - self.add_item(objects) - - # UUID of the root object - rootobject = JSONEntry( - "rootObject", - value=uuid, - comment="Project object") - self.add_item(rootobject) idecode = solution.ide.get_short_code() - rootproject = PBXProject(uuid, solution) + rootproject = PBXProject(self.uuid, solution) objects.add_item(rootproject) - found_glsl = False - # Process all the projects and configurations for project in solution.project_list: - # Process the filenames - project.get_file_list([FileTypes.icns, - FileTypes.h, - FileTypes.cpp, - FileTypes.c, - FileTypes.frameworks, - FileTypes.exe, - FileTypes.library, - FileTypes.glsl]) - - framework_list = [] + # Find all the input files + project.get_file_list(SUPPORTED_FILES) + + # Determine if there are frameworks, if so, add them to + # the input file list + framework_set = set() for configuration in project.configuration_list: for item in configuration.frameworks_list: - if item not in framework_list: - framework_list.append(item) + if item not in framework_set: + framework_set.add(item) project.codefiles.append(SourceFile( item, "", FileTypes.frameworks)) - for item in project.codefiles: + # Make a list of build rules for files that need custom compilers + build_rules = [] - # If there were GLSL source files, add a custom build step - if not found_glsl and item.type is FileTypes.glsl: - objects.add_item(BuildGLSL(project.configuration_list[0])) - found_glsl = True + # Check if there are GLSL Files + if source_file_detect(project.codefiles, FileTypes.glsl): + glsl_build_rule = PBXBuildRuleGLSL(solution.ide) + objects.add_item(glsl_build_rule) + build_rules.append(glsl_build_rule) - objects.add_item(PBXFileReference(item, solution.ide)) + # Create all the file references + file_references = [] + for item in project.codefiles: + file_reference = PBXFileReference(item, solution.ide) + objects.add_item(file_reference) + file_references.append(file_reference) # What's the final output file? if project.project_type is ProjectTypes.library: @@ -2789,10 +1907,12 @@ def __init__(self, solution): "lib" + solution.name + idecode + libextension, "", FileTypes.library), solution.ide) objects.add_item(outputfilereference) + elif project.project_type is ProjectTypes.app: outputfilereference = PBXFileReference(SourceFile( solution.name + ".app", "", FileTypes.exe), solution.ide) objects.add_item(outputfilereference) + elif project.project_type is not ProjectTypes.empty: outputfilereference = PBXFileReference(SourceFile( solution.name, "", FileTypes.exe), solution.ide) @@ -2800,6 +1920,9 @@ def __init__(self, solution): else: outputfilereference = None + if outputfilereference: + file_references.append(outputfilereference) + # If a fat library, add references for dev and sim targets ioslibrary = False if project.platform is PlatformTypes.ios: @@ -2809,16 +1932,17 @@ def __init__(self, solution): if ioslibrary: devfilereference = PBXFileReference( SourceFile( - "lib" + solution.name + - idecode + "dev.a", "", + "lib" + solution.name + "dev.a", "", FileTypes.library), solution.ide) objects.add_item(devfilereference) + file_references.append(devfilereference) + simfilereference = PBXFileReference( SourceFile( - "lib" + solution.name + - idecode + "sim.a", "", + "lib" + solution.name + "sim.a", "", FileTypes.library), solution.ide) objects.add_item(simfilereference) + file_references.append(simfilereference) # Two targets for "fat" libraries buildphase1 = PBXSourcesBuildPhase( @@ -2834,9 +1958,11 @@ def __init__(self, solution): # Add source files to compile for the ARM and the Intel libs - for item in objects.get_entries("PBXFileReference"): - if item.source_file.type in (FileTypes.cpp, FileTypes.c, - FileTypes.glsl): + for item in file_references: + if item.source_file.type in (FileTypes.m, FileTypes.mm, + FileTypes.cpp, FileTypes.c, + FileTypes.glsl, FileTypes.ppc, FileTypes.x64, + FileTypes.x86): build_file = PBXBuildFile(item, devfilereference) objects.add_item(build_file) @@ -2865,9 +1991,11 @@ def __init__(self, solution): framephase1 = PBXFrameworksBuildPhase(outputfilereference) objects.add_item(framephase1) - for item in objects.get_entries("PBXFileReference"): - if item.source_file.type in (FileTypes.cpp, FileTypes.c, - FileTypes.glsl): + for item in file_references: + if item.source_file.type in (FileTypes.m, FileTypes.mm, + FileTypes.cpp, FileTypes.c, + FileTypes.glsl, FileTypes.ppc, FileTypes.x64, + FileTypes.x86): build_file = PBXBuildFile( item, outputfilereference) @@ -2880,115 +2008,14 @@ def __init__(self, solution): objects.add_item(build_file) framephase1.add_build_file(build_file) - # Create the root file group and the Products group - groupproducts = PBXGroup("Products", None) - - grouproot = PBXGroup(solution.name, None) - objects.add_item(grouproot) - - # No frameworks group unless one is warranted - - frameworksgroup = None + # Given the list of file references, create the + # directory tree for organizing the files + rootproject.set_root_group( + self.create_directory_tree(file_references)) - # Insert all the file references into group - for item in objects.get_entries("PBXFileReference"): - # Products go into a special group - if item.source_file.type is FileTypes.exe: - groupproducts.add_file(item) - elif item.source_file.type is FileTypes.library: - groupproducts.add_file(item) - elif item.source_file.type is FileTypes.frameworks: - - # Create the group if needed - - if frameworksgroup is None: - frameworksgroup = PBXGroup("Frameworks", None) - objects.add_item(frameworksgroup) - grouproot.add_group(frameworksgroup) - - frameworksgroup.add_file(item) - else: - # Isolate the path - index = item.source_file.relative_pathname.rfind("/") - if index == -1: - # Put in the root group - grouproot.add_file(item) - else: - # Separate the path and name - path = item.source_file.relative_pathname[0:index] - # - # See if a group already exists - # - found = False - for matchgroup in objects.get_entries("PBXGroup"): - if matchgroup.path is not None and \ - matchgroup.path == path: - # Add to a pre-existing group - matchgroup.add_file(item) - found = True - break - if found: - continue - - # Group not found. Iterate and create the group - # May need multiple levels - - # - # Hack to remove preceding ../ entries - # - - if path.startswith("../"): - index = 3 - elif path.startswith("../../"): - index = 6 - else: - index = 0 - - notdone = True - previousgroup = grouproot - while notdone: - endindex = path[index:].find("/") - if endindex == -1: - # Final level, create group and add reference - matchgroup = PBXGroup( - path[index:], path) - objects.add_item(matchgroup) - matchgroup.add_file(item) - previousgroup.add_group(matchgroup) - notdone = False - else: - # - # See if a group already exists - # - temppath = path[0:index + endindex] - found = False - for matchgroup in objects.get_entries( - "PBXGroup"): - if matchgroup.path is None: - continue - if matchgroup.path == temppath: - found = True - break - - if not found: - matchgroup = PBXGroup( - path[index:index + endindex], temppath) - objects.add_item(matchgroup) - previousgroup.add_group(matchgroup) - previousgroup = matchgroup - index = index + endindex + 1 - - # Any output? - if not groupproducts.is_empty(): - objects.add_item(groupproducts) - grouproot.add_group(groupproducts) # Create the config list for the root project - configlistref = XCConfigurationList( - "PBXProject", - solution.name + - solution.ide_code + - solution.platform_code) + "PBXProject", solution.name) objects.add_item(configlistref) for configuration in project.configuration_list: entry = self.addxcbuildconfigurationlist( @@ -2996,7 +2023,6 @@ def __init__(self, solution): configlistref.configuration_list.append(entry) rootproject.set_config_list(configlistref) - rootproject.set_root_group(grouproot) # # Create the PBXNativeTarget config chunks @@ -3032,7 +2058,8 @@ def __init__(self, solution): solution.name, outputfilereference, solution.name, - outputtype) + outputtype, + build_rules) objects.add_item(nativetarget1) nativetarget1.set_config_list(configlistref) rootproject.append_target(nativetarget1) @@ -3052,17 +2079,19 @@ def __init__(self, solution): configlistref.configuration_list.append( self.addxcbuildconfigurationlist( configuration, None, configlistref, False)) + nativetarget1 = PBXNativeTarget( self, solution.name, outputfilereference, solution.name, - outputtype) + outputtype, + []) objects.add_item(nativetarget1) nativetarget1.set_config_list(configlistref) rootproject.append_target(nativetarget1) - targetname = solution.name + idecode + "dev" + targetname = solution.name + "dev" configlistref = XCConfigurationList( "PBXNativeTarget", targetname) objects.add_item(configlistref) @@ -3078,7 +2107,8 @@ def __init__(self, solution): targetname, devfilereference, solution.name, - outputtype) + outputtype, + build_rules) objects.add_item(nativeprojectdev) nativeprojectdev.set_config_list(configlistref) rootproject.append_target(nativeprojectdev) @@ -3089,23 +2119,35 @@ def __init__(self, solution): nativeprojectdev, self.uuid) objects.add_item(devcontainer) - targetname = solution.name + idecode + "sim" + targetname = solution.name + "sim" configlistref = XCConfigurationList( "PBXNativeTarget", targetname) objects.add_item(configlistref) for configuration in project.configuration_list: + + # Hack to change ios native to ios emulation platforms + tempplatform = configuration.platform + configuration.platform = { + PlatformTypes.ios32: PlatformTypes.iosemu32, + PlatformTypes.ios64: PlatformTypes.iosemu64}.get( + tempplatform, tempplatform) + configlistref.configuration_list.append( self.addxcbuildconfigurationlist( configuration, None, configlistref, False)) + # Restore configuration + configuration.platform = tempplatform + nativeprojectsim = PBXNativeTarget( self, targetname, simfilereference, solution.name, - outputtype) + outputtype, + build_rules) objects.add_item(nativeprojectsim) nativeprojectsim.set_config_list(configlistref) rootproject.append_target(nativeprojectsim) @@ -3135,7 +2177,7 @@ def __init__(self, solution): # Copy the tool to the bin folder input_data = [_TEMP_EXE_NAME] output = ("${SRCROOT}/bin/" - "${EXECUTABLE_NAME}") + "${EXECUTABLE_NAME}${SUFFIX}") command = ( "if [ ! -d ${{SRCROOT}}/bin ];" @@ -3161,7 +2203,8 @@ def __init__(self, solution): "/Contents/MacOS/" "${EXECUTABLE_NAME}") - command = "if [ ! -d ${SRCROOT}/bin ]; then mkdir ${SRCROOT}/bin; fi\\n" \ + command = "if [ ! -d ${SRCROOT}/bin ]; then mkdir " \ + "${SRCROOT}/bin; fi\\n" \ "${CP} -r " + _TEMP_EXE_NAME + ".app/ " \ "${SRCROOT}/bin/${EXECUTABLE_NAME}" + ".app/\\n" \ "mv ${SRCROOT}/bin/${EXECUTABLE_NAME}" + ".app" \ @@ -3189,31 +2232,27 @@ def __init__(self, solution): input_data = [_TEMP_EXE_NAME] else: input_data = [ - "${BUILD_ROOT}/" + solution.name + idecode + - "dev/lib" + solution.name + idecode + "dev.a", - "${BUILD_ROOT}/" + solution.name + idecode + - "sim/lib" + - solution.name + idecode + "sim.a" + "${BUILD_ROOT}/" + solution.name + + "dev${SUFFIX}/lib" + solution.name + "dev.a", + "${BUILD_ROOT}/" + solution.name + + "sim${SUFFIX}/lib" + solution.name + "sim.a" ] if ioslibrary is True: - output = deploy_folder + "${FULL_PRODUCT_NAME}" - command = "export SUFFIX=${PRODUCT_NAME:${#PRODUCT_NAME}-6:6}\\n" + \ - _PERFORCE_PATH + " edit " + deploy_folder + "${FULL_PRODUCT_NAME}\\n" + \ - "lipo -output " + deploy_folder + \ - "${FULL_PRODUCT_NAME} -create ${BUILD_ROOT}/" + \ - solution.name + idecode + \ - "dev${SUFFIX}/lib" + solution.name + idecode + \ - "dev${SUFFIX}.a ${BUILD_ROOT}/" + \ - solution.name + idecode + \ - "sim${SUFFIX}/lib" + solution.name + \ - idecode + "sim${SUFFIX}.a\\n" + \ + output = deploy_folder + "lib${PRODUCT_NAME}${SUFFIX}.a" + command = _PERFORCE_PATH + " edit " + output + "\\n" + \ + "lipo -output " + output + \ + " -create ${BUILD_ROOT}/" + \ + solution.name + "dev${SUFFIX}/lib" + \ + solution.name + "dev.a ${BUILD_ROOT}/" + \ + solution.name + "sim${SUFFIX}/lib" + \ + solution.name + "sim.a\\n" + \ _PERFORCE_PATH + " revert -a " + \ - deploy_folder + "${FULL_PRODUCT_NAME}\\n" + output + "\\n" elif project.project_type is ProjectTypes.library: - output = ("{0}lib${{PRODUCT_NAME}}.a").format( + output = ("{0}lib${{PRODUCT_NAME}}${{SUFFIX}}.a").format( deploy_folder) command = ( "{0} edit {1}\\n" @@ -3263,9 +2302,170 @@ def addxcbuildconfigurationlist(self, configuration, configfilereference, self.objects.add_item(entry) return entry + ######################################## + + def init_root_entries(self): + """ + Init the root items for the XCProject + + Creates the entries archiveVersion, classes, objectVersion, + objects, and rootObject + + Returns: + objects, which is a JSONObjects object + """ + + # Always 1 + self.add_item(JSONEntry("archiveVersion", value="1")) + + # Always empty + self.add_item(JSONDict("classes")) + + # Set to the version of XCode being generated for + self.add_item( + JSONEntry( + "objectVersion", + value=OBJECT_VERSIONS.get(self.solution.ide)[0])) + + # Create the master object list + objects = JSONObjects("objects") + self.add_item(objects) + + # UUID of the root object + rootobject = JSONEntry( + "rootObject", + value=self.uuid, + comment="Project object") + self.add_item(rootobject) + + return objects + + ######################################## + + def create_directory_tree(self, file_references): + """ + Create the directory tree for all files in the project + + Args: + file_references: List of all file references to map + """ + + # pylint: disable=too-many-statements + # pylint: disable=too-many-branches + + # Main JSON object list + objects = self.objects + + # Create the root file group and the Products group + group_products = PBXGroup("Products", None) + + # No frameworks group unless one is warranted + framework_group = PBXGroup("Frameworks", None) + + # Origin of the directory tree (This will be returned) + group_root = PBXGroup(self.solution.name, None) + objects.add_item(group_root) + + # List of groups already made, to avoid making duplicates + groups_made = [] + + # pylint: disable=too-many-nested-blocks + + # Insert all the file references into the proper group + for item in file_references: + + # Products go into a special group + if item.source_file.type in (FileTypes.exe, FileTypes.library): + group_products.add_file(item) + continue + + # Frameworks go into the FrameWorks group + if item.source_file.type is FileTypes.frameworks: + framework_group.add_file(item) + continue + + # Add to the hierarchical groups + + # Isolate the path + index = item.relative_pathname.rfind("/") + if index == -1: + # Put in the root group + group_root.add_file(item) + continue + + # Separate the path and name + path = item.relative_pathname[0:index] + + # See if a group already exists + for match_group in groups_made: + + # Add to a pre-existing group if found + if match_group.path == path: + match_group.add_file(item) + break + else: + + # Group not found. Iterate and create the group + # May need multiple levels + + # Hack to remove preceding ../ entries + if path.startswith("../"): + index = 3 + elif path.startswith("../../"): + index = 6 + else: + index = 0 + + previous_group = group_root + while True: + + # At the final directory level? + endindex = path[index:].find("/") + if endindex == -1: + + # Final level, create group and add reference + match_group = PBXGroup(path[index:], path) + objects.add_item(match_group) + groups_made.append(match_group) + previous_group.add_group(match_group) + match_group.add_file(item) + break + + # See if a group already exists at this level + temppath = path[0:index + endindex] + for match_group in groups_made: + if match_group.path == temppath: + break + else: + + # Create an empty intermediate group + match_group = PBXGroup( + path[index:index + endindex], temppath) + objects.add_item(match_group) + groups_made.append(match_group) + previous_group.add_group(match_group) + + # Next level into the group + previous_group = match_group + index = index + endindex + 1 + + # Add in the Products group if needed + if not group_products.is_empty(): + objects.add_item(group_products) + group_root.add_group(group_products) + + # Add in the Frameworks group if needed + if not framework_group.is_empty(): + objects.add_item(framework_group) + group_root.add_group(framework_group) + + return group_root + + ######################################## + def generate(self, line_list, indent=0): """ - Generate an XCode project files + Generate an entire XCode project file Args: line_list: Line list to append new lines. @@ -3274,12 +2474,16 @@ def generate(self, line_list, indent=0): Non-zero on error. """ - # Write the XCode header + # Write the XCode header for charset line_list.append("// !$*UTF8*$!") + + # Open brace for beginning line_list.append("{") # Increase indentatiopn indent = indent + 1 + + # Dump everything in the project for item in self.value: item.generate(line_list, indent) @@ -3300,6 +2504,8 @@ def generate(solution): Numeric error code. """ + # pylint: disable=protected-access + # Failsafe if solution.ide not in SUPPORTED_IDES: return 10 diff --git a/makeprojects/xcode_utils.py b/makeprojects/xcode_utils.py index 2810cf6..6b33839 100644 --- a/makeprojects/xcode_utils.py +++ b/makeprojects/xcode_utils.py @@ -15,10 +15,149 @@ @package makeprojects.xcode_utils This module contains classes needed to generate project files intended for use by Apple's XCode IDE + +@var makeprojects.xcode_utils.TABS +Default tab format for XCode + +@var makeprojects.xcode_utils.OBJECT_ORDER +Order of XCode objects + +@var makeprojects.xcode.FILE_REF_DIR +Map of root directories + +@var makeprojects.xcode.FILE_REF_LAST_KNOWN +Dictionary for mapping FileTypes to XCode file types + +@var makeprojects.xcode_utils._XCODESAFESET +Valid characters for XCode strings without quoting """ +# pylint: disable=useless-object-inheritance +# pylint: disable=consider-using-f-string +# pylint: disable=too-many-lines + from __future__ import absolute_import, print_function, unicode_literals +import hashlib +import os +import string +from operator import attrgetter, itemgetter + +from burger import convert_to_windows_slashes, convert_to_linux_slashes + +from .core import SourceFile +from .enums import IDETypes, FileTypes + +# Default tab format for XCode +TABS = "\t" + +# This is the order of XCode chunks that match the way +# that XCode outputs them. +OBJECT_ORDER = ( + "PBXAggregateTarget", + "PBXBuildFile", + "PBXBuildRule", + "PBXContainerItemProxy", + "PBXCopyFilesBuildPhase", + "PBXFileReference", + "PBXFrameworksBuildPhase", + "PBXGroup", + "PBXNativeTarget", + "PBXProject", + "PBXReferenceProxy", + "PBXResourcesBuildPhase", + "PBXShellScriptBuildPhase", + "PBXSourcesBuildPhase", + "PBXTargetDependency", + "XCBuildConfiguration", + "XCConfigurationList" +) + +# Map of root directories +FILE_REF_DIR = { + FileTypes.library: "BUILT_PRODUCTS_DIR", + FileTypes.exe: "BUILT_PRODUCTS_DIR", + FileTypes.frameworks: "SDKROOT", + FileTypes.x86: "SOURCE_ROOT", + FileTypes.x64: "SOURCE_ROOT", + FileTypes.ppc: "SOURCE_ROOT", + FileTypes.cpp: "SOURCE_ROOT", + FileTypes.c: "SOURCE_ROOT", + FileTypes.m: "SOURCE_ROOT", + FileTypes.mm: "SOURCE_ROOT" +} + +# Dictionary for mapping FileTypes to XCode file types +FILE_REF_LAST_KNOWN = { + FileTypes.library: None, + FileTypes.exe: None, + FileTypes.frameworks: "wrapper.framework", + FileTypes.glsl: "sourcecode.glsl", + FileTypes.xml: "text.xml", + FileTypes.xcconfig: "text.xcconfig", + FileTypes.ppc: "sourcecode.asm.asm", + FileTypes.x86: "sourcecode.asm.asm", + FileTypes.x64: "sourcecode.asm.asm", + FileTypes.cpp: "sourcecode.cpp.objcpp", + FileTypes.c: "source.c.c", + FileTypes.h: "sourcecode.c.h", + FileTypes.m: "source.c.objc", + FileTypes.mm: "sourcecode.cpp.objcpp" +} + +# Valid characters for XCode strings without quoting +_XCODESAFESET = frozenset(string.ascii_letters + string.digits + "_$./") + +######################################## + + +def calcuuid(input_str): + """ + Given a string, create a 96 bit unique hash for XCode + + Args: + input_str: string to hash + Returns: + 96 bit hash string in upper case. + """ + + temphash = hashlib.md5(convert_to_windows_slashes( + input_str).encode("utf-8")).hexdigest() + + # Take the hash string and only use the top 96 bits + + return temphash[0:24].upper() + +######################################## + + +def quote_string_if_needed(input_path): + """ + Quote a string for XCode. + + XCode requires quotes for certain characters. If any illegal character + exist in the string, the string will be reencoded to a quoted string using + XCode JSON rules. + + Args: + input_path: string to encapsulate. + Returns: + Original input string if XCode can accept it or properly quoted + """ + + # If there are any illegal characters, break + for item in input_path: + if item not in _XCODESAFESET: + break + else: + # No illegal characters in the string + if not input_path: + return "\"\"" + return input_path + + # Quote the escaped string. + return "\"{}\"".format(input_path.replace("\"", "\\\"")) + ######################################## @@ -46,3 +185,878 @@ def get_sdk_root(solution): if solution.project_list[0].configuration_list[0].platform.is_ios(): return "iphoneos" return "macosx" + +######################################## + + +class JSONRoot(object): + """ + XCode JSON root object + + Every JSON entry for XCode derives from this object and has a minimum of a + name, comment, uuid and an enabled flag. + + Attributes: + name: Object's name (Can also be the uuid) + comment: Optional object's comment field + uuid: Optional uuid + enabled: If True, output this object in generated output. + suffix: Optional suffix used in generated output. + value: Value + """ + + # pylint: disable=too-many-arguments + + def __init__(self, name, comment=None, uuid=None, + suffix=";", enabled=True, value=None): + """ + Initialize the JSONRoot entry. + + Args: + name: Name of this object + comment: Optional comment + uuid: uuid hash of the object + suffix: string to append at the end of the generated line of output. + enabled: If False, don't output this object in the generated object. + value: Optional value + """ + + self.name = name + self.comment = comment + self.uuid = uuid + self.enabled = enabled + self.suffix = suffix + self.value = value + + def add_item(self, item): + """ + Append an item to the array. + + Args: + item: JSONRoot based object. + """ + + self.value.append(item) + + def find_item(self, name): + """ + Find a named item. + + Args: + name: Name of the item to locate + Returns: + Reference to item or None if not found. + """ + + for item in self.value: + if item.name == name: + return item + + return None + +######################################## + + +class JSONEntry(JSONRoot): + """ + XCode JSON single line entry. + + Each JSON entry for XCode consists of the name followed by an optional + comment, and an optional value and then a mandatory suffix. + """ + + # pylint: disable=too-many-arguments + + def __init__(self, name, comment=None, value=None, + suffix=";", enabled=True): + """ + Initialize the JSONEntry. + + Args: + name: Name of this object + comment: Optional comment + value: Optional value + suffix: string to append at the end of the generated line of output. + enabled: If False, don't output this object in the generated object. + """ + + JSONRoot.__init__( + self, + name=name, + comment=comment, + suffix=suffix, + enabled=enabled, + value=value) + + def generate(self, line_list, indent=0): + """ + Generate the text lines for this JSON element. + + Args: + line_list: list object to have text lines appended to + indent: number of tabs to insert (For recursion) + """ + + if not self.enabled: + return 0 + + # Determine the indentation + tabs = TABS * indent + + # Set the value string + value = "" if self.value is None else " = " + \ + quote_string_if_needed(self.value) + + # Set the comment string + comment = "" if self.comment is None else " /* {} */".format( + self.comment) + + # Generate the JSON line + line_list.append( + "{}{}{}{}{}".format( + tabs, + quote_string_if_needed(self.name), + value, + comment, + self.suffix)) + return 0 + +######################################## + + +class JSONArray(JSONRoot): + """ + XCode JSON array. + + Each JSON entry for XCode consists of the name followed by an optional + comment, and an optional value and then a mandatory suffix. + + Attributes: + disable_if_empty: True if output is disabled if the list is empty + """ + + # pylint: disable=too-many-arguments + + def __init__(self, name, comment=None, value=None, suffix=";", + enabled=True, disable_if_empty=False, fold_array=False): + """ + Initialize the entry. + + Args: + name: Name of this object + comment: Optional comment + value: List of default values + suffix: Suffix, either ";" or "," + enabled: If False, don't output this object in the generated object. + disable_if_empty: If True, don't output if no items in the list. + """ + + if value is None: + value = [] + + JSONRoot.__init__( + self, + name=name, + comment=comment, + suffix=suffix, + enabled=enabled, + value=value) + + self.disable_if_empty = disable_if_empty + self.fold_array = fold_array + + def add_array_entry(self, name): + """ + Create a new JSONEntry record and add to the array + + Take the string passed in and append it to the end of the array + + Args: + name: String to append to the array + Returns: + JSONEntry created that was added + """ + + new_entry = JSONEntry(name, suffix=",") + self.add_item(new_entry) + return new_entry + + def generate(self, line_list, indent=0): + """ + Generate the text lines for this JSON element. + + Args: + line_list: list object to have text lines appended to + indent: number of tabs to insert (For recursion) + """ + + if not self.enabled: + return 0 + + # Disable if there are no values? + if self.disable_if_empty and not self.value: + return 0 + + # Determine the indentation + tabs = TABS * indent + indent = indent + 1 + + # Get the optional comment + comment = "" if self.comment is None else " /* {} */".format( + self.comment) + + # If there is only one entry, and array folding is enabled, + # only output a single item, not an array + if self.fold_array and len(self.value) == 1: + line_list.append("{}{}{} = {}{}".format( + tabs, self.name, comment, + quote_string_if_needed(self.value[0].name), self.suffix)) + + else: + # Generate the array opening + line_list.append("{}{}{} = (".format(tabs, self.name, comment)) + + # Generate the array + for item in self.value: + item.generate(line_list, indent=indent) + + # Generate the array closing + line_list.append("{}){}".format(tabs, self.suffix)) + return 0 + +######################################## + + +class JSONDict(JSONRoot): + """ + XCode JSON dictionary + + Each JSON entry for XCode consists of the name followed by an optional + comment, and an optional value and then a mandatory suffix. + + Attributes: + disable_if_empty: True if output is disabled if the list is empty + isa: "Is a" name + """ + + # pylint: disable=too-many-arguments + + def __init__(self, name, isa=None, comment=None, value=None, + suffix=";", uuid=None, enabled=True, disable_if_empty=False, + flattened=False): + """ + Initialize the entry. + + Args: + name: Name of this object + isa: "Is a" type of dictionary object + comment: Optional comment + value: List of default values + suffix: Suffix, either ";" or "," + uuid: uuid hash of the object + enabled: If False, don't output this object in the generated object. + disable_if_empty: If True, don't output if no items in the list. + flattened: If True, flatten the child objects + """ + + if uuid is None: + uuid = "" + + if value is None: + value = [] + + JSONRoot.__init__( + self, + name=name, + comment=comment, + uuid=uuid, + suffix=suffix, + enabled=enabled, + value=value) + + self.disable_if_empty = disable_if_empty + self.isa = isa + self.flattened = flattened + + if isa is not None: + self.add_dict_entry("isa", isa) + + def add_dict_entry(self, name, value=None): + """ + Create a new JSONEntry record and add to the dictionary + + Take the string passed in and append it to dict + + Args: + name: String for the JSONEntry name + value: String to use as the value for the entry + Returns: + JSONEntry created that was added + """ + + new_entry = JSONEntry(name, value=value) + self.add_item(new_entry) + return new_entry + + def generate(self, line_list, indent=0): + """ + Generate the text lines for this JSON element. + Args: + line_list: list object to have text lines appended to + indent: number of tabs to insert (For recursion) + """ + + if not self.enabled: + return 0 + + # Disable if there are no values? + if self.disable_if_empty and self.value is not None: + return 0 + + # Determine the indentation + tabs = TABS * indent + indent = indent + 1 + + # Get the optional comment" + comment = "" if self.comment is None else " /* {} */".format( + self.comment) + + # Generate the dictionary opening + line_list.append("{}{}{} = {{".format(tabs, self.name, comment)) + + # Generate the dictionary + for item in self.value: + item.generate(line_list, indent=indent) + + # Generate the dictionary closing + line_list.append("{}}}{}".format(tabs, self.suffix)) + return 0 + +######################################## + + +class JSONObjects(JSONDict): + """ + XCode JSON dictionary + + Each JSON entry for XCode consists of the name followed by an optional + comment, and an optional value and then a mandatory suffix. + """ + + def __init__(self, name, uuid=None, enabled=True): + """ + Initialize the entry. + + Args: + name: Name of this object + uuid: uuid hash of the object + enabled: If False, don't output this object in the generated object. + """ + + JSONDict.__init__(self, name, uuid=uuid, enabled=enabled) + + def get_entries(self, isa): + """ + Return a list of items that match the isa name. + + Args: + isa: isa name string. + Returns: + List of entires found, can be an empty list. + """ + + item_list = [] + for item in self.value: + if item.isa == isa: + item_list.append(item) + return item_list + + def generate(self, line_list, indent=0): + """ + Generate the text lines for this JSON element. + + Args: + line_list: list object to have text lines appended to + indent: number of tabs to insert (For recursion) + """ + + if not self.enabled: + return 0 + + # Determine the indentation + tabs = TABS * indent + indent = indent + 1 + + # Set the optional comment + comment = "" if self.comment is None else " /* {} */".format( + self.comment) + + # Generate the dictionary opening + line_list.append("{}{}{} = {{".format(tabs, self.name, comment)) + + # Output the objects in "isa" order for XCode + for object_group in OBJECT_ORDER: + + # Find all entries by this name + item_list = [] + for item in self.value: + if item.isa == object_group: + item_list.append(item) + + # Any items in this group? + if item_list: + + # Sort by uuid + item_list = sorted(item_list, key=attrgetter("uuid")) + + # Using the name of the class, output the array of data items + line_list.append("") + line_list.append("/* Begin {} section */".format(object_group)) + for item in item_list: + + # Because Apple hates me. Check if a record needs to be + # flattened instead of putting the data on individual lines, + # because, just because. + + if getattr(item, "flattened", None): + # Generate the lines + temp_list = [] + item.generate(temp_list, indent=0) + # Flatten it and strip the tabs + temp = " ".join(temp_list).replace(TABS, "") + + # Remove this space to match the output of XCode + temp = temp.replace(" isa", "isa") + + # Insert the flattened line + line_list.append(tabs + TABS + temp) + else: + + # Output the item as is + item.generate(line_list, indent=indent) + line_list.append("/* End {} section */".format(object_group)) + + line_list.append("{}}}{}".format(tabs, self.suffix)) + return 0 + +######################################## + + +class PBXBuildRuleGLSL(JSONDict): + """ + Create a PBXBuildRule entry for building GLSL files. + + If *.glsl files are found, this rule will invoke stripcomments + to build the headers out of them. + + This object is referenced by PBXNativeTarget + """ + + def __init__(self, ide): + """ + Initialize the PBXBuildRule for GLSL + + Args: + ide: IDE used for build for + """ + + uuid = calcuuid("PBXBuildRule" + "BuildGLSL") + + # Init the parent as a PBXBuildRule + JSONDict.__init__( + self, + name=uuid, + isa="PBXBuildRule", + comment="PBXBuildRule", + uuid=uuid) + + # The rule is a bash/zsh script + self.add_dict_entry("compilerSpec", + "com.apple.compilers.proxy.script") + + # Apply to all *.glsl files + self.add_dict_entry("filePatterns", "*.glsl") + + # filePatterns is a wildcard + self.add_dict_entry("fileType", "pattern.proxy") + + # XCode 12 and higher needs the list of input files + if ide >= IDETypes.xcode12: + input_files = JSONArray("inputFiles") + self.add_item(input_files) + + # The source file is the only input + input_files.add_array_entry("${INPUT_FILE_PATH}") + + # This rule can be edited + self.add_dict_entry("isEditable", "1") + + # Create the list of output files + output_files = JSONArray("outputFiles") + self.add_item(output_files) + + # This is the file generated + output_files.add_array_entry( + "${INPUT_FILE_DIR}/generated/${INPUT_FILE_BASE}.h") + + # Only build once, don't build for each CPU type + if ide >= IDETypes.xcode12: + self.add_dict_entry("runOncePerArchitecture", "0") + + # The actual script to run stripcomments + self.add_dict_entry( + "script", + "${BURGER_SDKS}/macosx/bin/stripcomments " + "${INPUT_FILE_PATH}" + " -c -l g_${INPUT_FILE_BASE} " + "${INPUT_FILE_DIR}/generated/${INPUT_FILE_BASE}.h\\n") + +######################################## + + +class PBXFileReference(JSONDict): + """ + A PBXFileReference entry. + + For each and every file managed by an XCode project, a PBXFileReference + object will exist to reference it. Other sections of XCode will use the + UUID of this object to act upon the file referenced by this object. + + The UUID is used for both PBXGroup for file hierachical display and + PBXBuildFile if the file needs to be built with a compiler. + + Attributes: + source_file: core.SourceFile record + """ + + def __init__(self, source_file, ide): + """ + Initialize the PBXFileReference object. + + Args: + source_file: core.SourceFile record + ide: IDETypes of the ide being built for. + """ + + # pylint: disable=too-many-branches + + # Sanity check + if not isinstance(source_file, SourceFile): + raise TypeError( + "parameter \"source_file\" must be of type SourceFile") + + # XCode is hosted by MacOSX, so use linux slashes + relative_pathname = convert_to_linux_slashes( + source_file.relative_pathname) + + # Generate the UUID + uuid = calcuuid("PBXFileReference" + relative_pathname) + basename = os.path.basename(relative_pathname) + + JSONDict.__init__( + self, + name=uuid, + isa="PBXFileReference", + comment=basename, + uuid=uuid, + flattened=True) + + # core.SourceFile record + self.source_file = source_file + + # Save the MacOS version of the relative pathname + self.relative_pathname = relative_pathname + + # If not binary, assume UTF-8 encoding + if source_file.type not in (FileTypes.library, FileTypes.exe, + FileTypes.frameworks): + self.add_dict_entry("fileEncoding", "4") + + # If an output file, determine the output type and mark + # as "explicitFileType" + if source_file.type in (FileTypes.library, FileTypes.exe): + if source_file.type is FileTypes.library: + value = "archive.ar" + elif basename.endswith(".app"): + value = "wrapper.application" + else: + value = "compiled.mach-o.executable" + + self.add_dict_entry("explicitFileType", value) + + # Never add to the index + self.add_dict_entry("includeInIndex", "0") + + # lastKnownFileType + value = FILE_REF_LAST_KNOWN.get(source_file.type, "sourcecode.c.h") + + # Library and exe return None + if value: + + # XCode 3 and 4 doesn't support sourcecode.glsl + # Use sourcecode instead + if ide < IDETypes.xcode5: + if value.endswith(".glsl"): + value = "sourcecode" + + self.add_dict_entry("lastKnownFileType", value) + + # name record + if source_file.type not in (FileTypes.library, FileTypes.exe): + self.add_dict_entry("name", basename) + + if source_file.type is FileTypes.library: + value = basename + elif source_file.type is FileTypes.frameworks: + value = "System/Library/Frameworks/" + basename + else: + value = relative_pathname + self.add_dict_entry("path", value) + + self.add_dict_entry( + "sourceTree", + FILE_REF_DIR.get(source_file.type, "SOURCE_ROOT")) + +######################################## + + +class PBXGroup(JSONDict): + """ + Each PBXGroup entry + + Attributes: + children: Children list + group_name: Name of this group + path: Root path for this group + group_list: List of child groups + file_list: List of child files + """ + + def __init__(self, group_name, path): + """ + Init the PBXGroup. + """ + + # Create uuid, and handle an empty path + uuid_path = path + if path is None: + uuid_path = "" + uuid = calcuuid("PBXGroup" + group_name + uuid_path) + + JSONDict.__init__( + self, + name=uuid, + isa="PBXGroup", + comment=group_name, + uuid=uuid) + + self.group_name = group_name + self.path = path + self.group_list = [] + self.file_list = [] + + children = JSONArray("children") + self.add_item(children) + self.children = children + + self.add_dict_entry( + "name", group_name).enabled = path is None or group_name != path + + self.add_dict_entry("path", path).enabled = path is not None + + # Source tree root path + value = "SOURCE_ROOT" if path is not None else "" + self.add_dict_entry("sourceTree", value) + + def is_empty(self): + """ + Return True if there are no entries in this group. + + Returns: + True if this PBXGroup has no entries. + """ + + return not (self.group_list or self.file_list) + + def add_file(self, file_reference): + """ + Append a file uuid and name to the end of the list. + + Args: + file_reference: PBXFileReference item to attach to this group. + """ + + # Sanity check + if not isinstance(file_reference, PBXFileReference): + raise TypeError( + "parameter \"file_reference\" must be of type PBXFileReference") + + self.file_list.append( + (file_reference.uuid, os.path.basename( + file_reference.relative_pathname))) + + def add_group(self, group): + """ + Append a group to the end of the list. + + Args: + group: PBXGroup item to attach to this group. + """ + + # Sanity check + if not isinstance(group, PBXGroup): + raise TypeError( + "parameter \"group\" must be of type PBXGroup") + + self.group_list.append((group.uuid, group.group_name)) + + def generate(self, line_list, indent=0): + """ + Write this record to output. + + Args: + line_list: Line list to append new lines. + indent: number of tabs to insert (For recursion) + """ + + # Output groups first + for item in sorted(self.group_list, key=itemgetter(1)): + self.children.add_array_entry(item[0]).comment = item[1] + + # Output files last + for item in sorted(self.file_list, key=itemgetter(1)): + self.children.add_array_entry(item[0]).comment = item[1] + + return JSONDict.generate(self, line_list, indent) + + +######################################## + + +class PBXBuildFile(JSONDict): + """ + Create a PBXBuildFile entry + + Attributes: + file_reference: PBXFileReference of the file being compiled + """ + + def __init__(self, input_reference, output_reference): + """ + Init the PBXBuildFile record. + + Args: + input_reference: File reference of object to build + output_reference: File reference of lib/exe being built. + """ + + # Sanity check + if not isinstance(input_reference, PBXFileReference): + raise TypeError( + "parameter \"input_reference\"" + " must be of type PBXFileReference") + + if not isinstance(output_reference, PBXFileReference): + raise TypeError( + "parameter \"output_reference\"" + " must be of type PBXFileReference") + + # Make the uuid + uuid = calcuuid( + "PBXBuildFile" + + input_reference.relative_pathname + + output_reference.relative_pathname) + + basename = os.path.basename( + input_reference.relative_pathname) + + ref_type = "Frameworks" \ + if input_reference.source_file.type is FileTypes.frameworks \ + else "Sources" + + JSONDict.__init__( + self, + name=uuid, + isa="PBXBuildFile", + comment="{} in {}".format(basename, ref_type), + uuid=uuid, + flattened=True) + + # PBXFileReference of the file being compiled + self.file_reference = input_reference + + # Add the uuid of the file reference + self.add_dict_entry( + "fileRef", input_reference.uuid).comment = basename + +######################################## + + +class PBXShellScriptBuildPhase(JSONDict): + """ + Each PBXShellScriptBuildPhase entry + + Attributes: + files: JSONArray of files + """ + + def __init__(self, input_data, output, command): + """ + Init PBXShellScriptBuildPhase + + Args: + input_data: Input file references + output: String for the output file that will be built + command: Script to build + """ + + # Get the UUID + uuid = calcuuid( + "PBXShellScriptBuildPhase" + "".join(input_data) + + output + command) + + # Init the parent + JSONDict.__init__( + self, + name=uuid, + isa="PBXShellScriptBuildPhase", + comment="ShellScript", + uuid=uuid) + + self.add_dict_entry("buildActionMask", "2147483647") + + # Internal files, if any + files = JSONArray("files") + self.files = files + self.add_item(files) + + # Paths to input files + input_paths = JSONArray("inputPaths", disable_if_empty=True) + for item in input_data: + input_paths.add_array_entry(item) + self.add_item(input_paths) + + # Path to the output file + output_paths = JSONArray("outputPaths") + output_paths.add_array_entry(output) + self.add_item(output_paths) + + # Always run + self.add_dict_entry( + "runOnlyForDeploymentPostprocessing", "0") + + # Path to the shell + self.add_dict_entry("shellPath", "/bin/sh") + + # The actual script to run + self.add_dict_entry("shellScript", "{}\\n".format(command)) + + # Don't show the environment variables + self.add_dict_entry("showEnvVarsInLog", "0") + + @staticmethod + def get_phase_name(): + """ + Return the build phase name for XCode. + """ + return "ShellScript" diff --git a/unittests/test_enums.py b/unittests/test_enums.py index 86fbf42..94b41bb 100644 --- a/unittests/test_enums.py +++ b/unittests/test_enums.py @@ -89,6 +89,7 @@ def test_projecttypes_lookup(self): ######################################## + def test_idetypes_is_visual_studio(self): """ Test IDETypes.is_visual_studio(). @@ -107,6 +108,7 @@ def test_idetypes_is_visual_studio(self): ######################################## + def test_idetypes_is_xcode(self): """ Test IDETypes.is_xcode(). @@ -124,6 +126,7 @@ def test_idetypes_is_xcode(self): ######################################## + def test_idetypes_is_codewarrior(self): """ Test IDETypes.is_codewarrior(). @@ -139,6 +142,7 @@ def test_idetypes_is_codewarrior(self): ######################################## + def test_idetypes_lookup(self): """ Test IDETypes.lookup(). @@ -213,9 +217,14 @@ def test_platformtypes_is_macos(self): """ for item in PlatformTypes: - if item in (PlatformTypes.macos9, PlatformTypes.macos968k, - PlatformTypes.macos9ppc, PlatformTypes.maccarbon, - PlatformTypes.maccarbon68k, PlatformTypes.maccarbonppc): + if item in ( + PlatformTypes.mac, PlatformTypes.mac68k, + PlatformTypes.macppc, + PlatformTypes.macclassic, PlatformTypes.maccarbon, + PlatformTypes.mac68knear, PlatformTypes.mac68knearfp, + PlatformTypes.mac68kfar, PlatformTypes.mac68kfarfp, + PlatformTypes.mac68kcarbon, PlatformTypes.macppcclassic, + PlatformTypes.macppccarbon): self.assertTrue(item.is_macos()) else: self.assertFalse(item.is_macos()) @@ -228,8 +237,8 @@ def test_platformtypes_is_macos_carbon(self): """ for item in PlatformTypes: - if item in (PlatformTypes.maccarbon, PlatformTypes.maccarbon68k, - PlatformTypes.maccarbonppc): + if item in (PlatformTypes.maccarbon, PlatformTypes.mac68kcarbon, + PlatformTypes.macppccarbon): self.assertTrue(item.is_macos_carbon()) else: self.assertFalse(item.is_macos_carbon()) @@ -242,8 +251,11 @@ def test_platformtypes_is_macos_classic(self): """ for item in PlatformTypes: - if item in (PlatformTypes.macos9, PlatformTypes.macos968k, - PlatformTypes.macos9ppc): + if item in (PlatformTypes.mac, PlatformTypes.mac68k, + PlatformTypes.macppc, PlatformTypes.macclassic, + PlatformTypes.mac68knear, PlatformTypes.mac68knearfp, + PlatformTypes.mac68kfar, PlatformTypes.mac68kfarfp, + PlatformTypes.macppcclassic): self.assertTrue(item.is_macos_classic()) else: self.assertFalse(item.is_macos_classic()) @@ -251,6 +263,7 @@ def test_platformtypes_is_macos_classic(self): ######################################## + def test_platformtypes_lookup(self): """ Test PlatformTypes.lookup(). @@ -259,7 +272,8 @@ def test_platformtypes_lookup(self): ("windows", PlatformTypes.windows), ("win32", PlatformTypes.win32), ("w64", PlatformTypes.win64), - ("macos", PlatformTypes.macos9), + ("macos", PlatformTypes.macosx), + ("macos9", PlatformTypes.macppc), ("macosx", PlatformTypes.macosx), ("carbon", PlatformTypes.maccarbon), ("ouya", PlatformTypes.ouya),