SuperScriptMaterializer/scripts/mk_mtl_cfg.py

332 lines
13 KiB
Python
Raw Permalink Normal View History

import vs_props_writer, vs_vcxproj_modifier
import os, enum, sys, argparse
#region Constant Declarations
class BuildType(enum.Enum):
Standalone: str = "standalone"
Plugin: str = "plugin"
class VirtoolsVersion(enum.Enum):
V21 = '21'
V25 = '25'
V30 = '30'
V35 = '35'
V40 = '40'
V50 = '50'
VT_HEADER_PATH: dict[VirtoolsVersion, str] = {
VirtoolsVersion.V21: 'Include',
VirtoolsVersion.V25: 'Virtools_SDK\\Includes',
VirtoolsVersion.V30: 'Sdk\\Includes',
VirtoolsVersion.V35: 'Sdk\\Includes',
VirtoolsVersion.V40: 'Sdk\\Includes',
VirtoolsVersion.V50: 'Sdk\\Includes'
}
VT_LIB_PATH: dict[VirtoolsVersion, str] = {
VirtoolsVersion.V21: 'Lib',
VirtoolsVersion.V25: 'Virtools_SDK\\Lib',
VirtoolsVersion.V30: 'Sdk\\Lib',
VirtoolsVersion.V35: 'Sdk\\Lib\\Win32\\Release',
VirtoolsVersion.V40: 'Sdk\\Lib\\Win32\\Release',
VirtoolsVersion.V50: 'Sdk\\Lib\\Win32\\Release'
}
VT_STANDALONE_ATTACHED_LIBS: dict[VirtoolsVersion, str] = {
VirtoolsVersion.V21: "VxMath.lib;CK2.lib",
VirtoolsVersion.V25: "VxMath.lib;CK2.lib",
VirtoolsVersion.V30: "VxMath.lib;CK2.lib",
VirtoolsVersion.V35: "VxMath.lib;CK2.lib",
VirtoolsVersion.V40: "VxMath.lib;CK2.lib",
VirtoolsVersion.V50: "VxMath.lib;CK2.lib"
}
VT_PLUGIN_ATTACHED_LIBS: dict[VirtoolsVersion, str] = {
VirtoolsVersion.V21: "",
VirtoolsVersion.V25: "",
VirtoolsVersion.V30: "VxMath.lib;DllEditor.lib;CK2.lib;InterfaceControls.lib;CKControls.lib",
VirtoolsVersion.V35: "VxMath.lib;DllEditor.lib;CK2.lib;InterfaceControls.lib;CKControls.lib",
VirtoolsVersion.V40: "VxMath.lib;DllEditor.lib;CK2.lib;InterfaceControls.lib;CKControls.lib",
VirtoolsVersion.V50: "VxMath.lib;DllEditor.lib;CK2.lib;InterfaceControls.lib;CKControls.lib"
}
VT_PLUGIN_MACROS: dict[VirtoolsVersion, str] = {
VirtoolsVersion.V21: "_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE",
VirtoolsVersion.V25: "_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE",
VirtoolsVersion.V30: "_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE",
VirtoolsVersion.V35: "_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE",
VirtoolsVersion.V40: "_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE",
VirtoolsVersion.V50: "_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
}
VT_STANDALONE_MACROS: dict[VirtoolsVersion, str] = {
VirtoolsVersion.V21: "_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_DEBUG",
VirtoolsVersion.V25: "_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_DEBUG",
VirtoolsVersion.V30: "_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_DEBUG",
VirtoolsVersion.V35: "_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_DEBUG",
VirtoolsVersion.V40: "_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_DEBUG",
VirtoolsVersion.V50: "_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_DEBUG;VIRTOOLS_USER_SDK"
}
VT_PLUGIN_SUPPORTED_VER: set[VirtoolsVersion] = set((
VirtoolsVersion.V30,
VirtoolsVersion.V35,
VirtoolsVersion.V40,
VirtoolsVersion.V50,
))
VT_STANDALONE_SUPPORTED_VER: set[VirtoolsVersion] = set((
VirtoolsVersion.V21,
VirtoolsVersion.V25,
VirtoolsVersion.V30,
VirtoolsVersion.V35,
VirtoolsVersion.V40,
VirtoolsVersion.V50,
))
VT_EXECUTABLE_DEV: dict[VirtoolsVersion, str] = {
VirtoolsVersion.V25: "Dev.exe",
VirtoolsVersion.V30: "devr.exe",
VirtoolsVersion.V35: "devr.exe",
VirtoolsVersion.V40: "devr.exe",
VirtoolsVersion.V50: "devr.exe"
}
#endregion
#region Assist Functions
def get_project_root() -> str:
2024-05-29 10:45:38 +08:00
# build project root path and return
return os.path.dirname(os.path.dirname(__file__))
def check_project_root() -> None:
"""
Check whether this script is executed in correct folder.
If check failed, this function will exit script, otherwise, return directly.
"""
project_root: str = get_project_root()
# check whether have readme file
2024-05-29 10:45:38 +08:00
if not os.path.isfile(os.path.join(project_root, 'README.md')):
print('Fail to get project root folder. This script may be placed at wrong location.')
sys.exit(1)
2024-05-29 10:45:38 +08:00
def validate_combination(build_type: BuildType, vt_version: VirtoolsVersion) -> None:
"""
Check whether the given combination of build type and Virtools version is OK.
Some combination of build type and Virtools version is invalid.
For example, because Virtools 2.5 do not have UI register so plugin build type is not available in Virtools 2.1
2024-05-29 10:45:38 +08:00
If validation failed, this function will exit script, otherwise, return directly.
"""
2024-05-29 10:45:38 +08:00
# fetch result
is_okey: bool
match(build_type):
case BuildType.Standalone:
2024-05-29 10:45:38 +08:00
is_okey = vt_version in VT_STANDALONE_SUPPORTED_VER
case BuildType.Plugin:
2024-05-29 10:45:38 +08:00
is_okey = vt_version in VT_PLUGIN_SUPPORTED_VER
# output result
if not is_okey:
print(f'The combination of "{build_type.value}" and "{vt_version.value}" is not compatible currently.')
sys.exit(1)
def ensure_trailing_slash(given_path: str) -> str:
"""
Ensure given path is end with slash or backslash.
@param given_path The path for checking.
@return The path with trailing slash or backslash,
or the given path self if it already has.
"""
# make sure return value is end with slash or backslash
if given_path[-1] != '\\' or given_path[-1] != '/':
return given_path + '\\'
else:
return given_path
def get_header_path(vt_version: VirtoolsVersion, vt_root: str) -> str:
return os.path.join(vt_root, VT_HEADER_PATH[vt_version])
def get_lib_path(vt_version: VirtoolsVersion, vt_root: str) -> str:
return os.path.join(vt_root, VT_LIB_PATH[vt_version])
def get_attached_libs(build_type: BuildType, vt_version: VirtoolsVersion) -> str:
match(build_type):
case BuildType.Standalone:
return VT_STANDALONE_ATTACHED_LIBS[vt_version]
case BuildType.Plugin:
return VT_PLUGIN_ATTACHED_LIBS[vt_version]
def get_macros(build_type: BuildType, vt_version: VirtoolsVersion) -> str:
match(build_type):
case BuildType.Standalone:
return VT_STANDALONE_MACROS[vt_version]
case BuildType.Plugin:
return VT_PLUGIN_MACROS[vt_version]
def get_executable_dev(vt_version: VirtoolsVersion, vt_root: str) -> str:
"""
Return the path to executable Virtools Dev according to given Virtools version.
Usually it is `Dev.exe` or `devr.exe`.
@param vt_version The version of Virtools.
@param vt_root The path to Virtools root folder.
@return The path to executable Virtools Dev.
"""
return os.path.join(vt_root, VT_EXECUTABLE_DEV[vt_version])
def get_output_path(build_type: BuildType, vt_root: str) -> str:
2024-05-29 10:45:38 +08:00
"""
Get the output path for plugin.
For plugin build type, script will try output binary into `InterfacePlugins` folder in Virtools environment.
For standalone build type, script will try output binary in the root path of Virtools.
@param vt_version The version of Virtools.
@param vt_root The path to Virtools root folder.
@return The path where the compiled project binary will be placed.
"""
# fetch output path by build type
ret: str
match(build_type):
case BuildType.Standalone:
ret = vt_root
case BuildType.Plugin:
ret = os.path.join(vt_root, 'InterfacePlugins')
# make sure return value is end with slash or backslash
2024-05-29 10:45:38 +08:00
return ensure_trailing_slash(ret)
def get_binary_suffix(build_type: BuildType) -> str:
match(build_type):
case BuildType.Standalone:
return 'exe'
case BuildType.Plugin:
return 'dll'
def get_module_define(build_type: BuildType) -> str:
match(build_type):
case BuildType.Standalone:
return ''
case BuildType.Plugin:
return 'SuperScriptMaterializer.def'
#endregion
def main() -> None:
2024-05-29 10:45:38 +08:00
# ========== Check Environment ==========
check_project_root()
# ========== Accept User Input ==========
# build args parser
parser = argparse.ArgumentParser(description='Project Configuration Maker')
parser.add_argument(
'-b', '--build-type', required=True, action='store', dest='build_type', choices=tuple(item.value for item in BuildType),
help='The build type of project.'
)
parser.add_argument(
'-t', '--virtools-version', required=True, action='store', dest='virtools_version', choices=tuple(item.value for item in VirtoolsVersion),
help='The Virtools version you picked.'
)
parser.add_argument(
'-p', '--virtools-path', required=True, action='store', dest='virtools_path',
help='''
The path to the root folder of you picked Virtools version where you can find "Dev.exe".
If you select Virtools 2.1, this path should be the root folder of GitHub project "doyaGu/Virtools-SDK-2.1".
'''
)
parser.add_argument(
'-a', '--sqlite-amalgamation-path', required=True, action='store', dest='sqlite_amalgamation_path',
help='The path to downloaded sqlite amalgamation folder where you can find "sqlite3.h"'
)
parser.add_argument(
'-d', '--sqlite-dll-path', required=True, action='store', dest='sqlite_dll_path',
help='The path to downloaded sqlite dll folder where you can find "sqlite3.dll" and "sqlite3.lib" you just built a few minutes ago.'
)
# parse arguments
args = parser.parse_args()
# ========== Analyse Arguments ==========
# extract arguments
arg_virtools_version: VirtoolsVersion = VirtoolsVersion(args.virtools_version)
arg_build_type: BuildType = BuildType(args.build_type)
arg_virtools_path: str = args.virtools_path
arg_sqlite_amalgamation_path: str = args.sqlite_amalgamation_path
arg_sqlite_dll_path: str = args.sqlite_dll_path
# validate the combination
2024-05-29 10:45:38 +08:00
validate_combination(arg_build_type, arg_virtools_version)
2024-05-29 10:45:38 +08:00
# build macros values
# virtools version and build type macro
macro_virtools_ver: str = f'VIRTOOLS_{arg_virtools_version.value}'
macro_virtools_build_type: str = f'VIRTOOLS_{arg_build_type.value.upper()}'
# virtools header and lib
macro_virtools_header_path: str = get_header_path(arg_virtools_version, arg_virtools_path)
macro_virtools_lib_path: str = get_lib_path(arg_virtools_version, arg_virtools_path)
macro_virtools_attcahed_libs: str = get_attached_libs(arg_build_type, arg_virtools_version)
# sqlite header and lib
macro_sqlite_header_path: str = arg_sqlite_amalgamation_path
macro_sqlite_lib_path: str = arg_sqlite_dll_path
2024-05-29 10:45:38 +08:00
# output path macro
macro_virtools_output_path: str = get_output_path(arg_build_type, arg_virtools_path)
2024-05-29 10:45:38 +08:00
# virtools used macros
macro_virtools_macros: str = get_macros(arg_build_type, arg_virtools_version)
# misc
macro_virtools_binary_suffix: str = get_binary_suffix(arg_build_type)
macro_virtools_module_define: str = get_module_define(arg_build_type)
# ========== Create Property File ==========
props = vs_props_writer.VsPropsWriter()
# write subsystem
match(arg_build_type):
case BuildType.Standalone:
props.SetSubSystem(vs_props_writer.VsSubSystem.Console)
case BuildType.Plugin:
props.SetSubSystem(vs_props_writer.VsSubSystem.Windows)
# write macro and misc
# build type distinguish macro
props.AddMacro('VIRTOOLS_VER', macro_virtools_ver)
props.AddMacro('VIRTOOLS_BUILD_TYPE', macro_virtools_build_type)
# header and libs
props.AddMacro('VIRTOOLS_HEADER_PATH', macro_virtools_header_path)
props.AddMacro('VIRTOOLS_LIB_PATH', macro_virtools_lib_path)
props.AddMacro('VIRTOOLS_ATTACHED_LIBS', macro_virtools_attcahed_libs)
props.AddMacro('SQLITE_HEADER_PATH', macro_sqlite_header_path)
props.AddMacro('SQLITE_LIB_PATH', macro_sqlite_lib_path)
# output
props.AddMacro('VIRTOOLS_OUTPUT_PATH', macro_virtools_output_path)
# essential build macro
props.AddMacro('VIRTOOLS_MACROS', macro_virtools_macros)
# misc macro
props.AddMacro('VIRTOOLS_BINARY_SUFFIX', macro_virtools_binary_suffix)
props.AddMacro('VIRTOOLS_MODULE_DEFINE', macro_virtools_module_define)
# output
props.Generate(os.path.join(get_project_root(), 'Virtools.props'))
# ========== Modify ==========
vcxproj = vs_vcxproj_modifier.VsVcxprojModifier(
os.path.join(get_project_root(), 'SuperScriptMaterializer/SuperScriptMaterializer.vcxproj')
)
# write build type
match(arg_build_type):
case BuildType.Standalone:
vcxproj.SetBuildType(vcxproj.BUILDTYPE_EXE)
case BuildType.Plugin:
vcxproj.SetBuildType(vcxproj.BUILDTYPE_DLL)
# output
vcxproj.Modify()
# ========== Done ==========
print("Configuration OK!")
if __name__ == '__main__':
main()