1
0
pl-build/pl_build/pl_build.py
Jonathan Hoffstadt 22d26cdafd
Some checks failed
Deploy Tools / build-package (push) Failing after 15s
initial commit
2024-09-05 12:20:53 -05:00

667 lines
26 KiB
Python

__version__ = "1.0.0"
###############################################################################
# Info #
###############################################################################
# very poorly written & dirty system, to be cleaned up later
###############################################################################
# Modules #
###############################################################################
from enum import Enum
from contextlib import contextmanager
###############################################################################
# Enums #
###############################################################################
class TargetType(Enum):
NONE = 0
STATIC_LIBRARY = 0
DYNAMIC_LIBRARY = 1
EXECUTABLE = 2
###############################################################################
# Classes #
###############################################################################
class CompilerSettings:
def __init__(self, name: str):
self.name = name
self.output_directory = None
self.output_binary = None
self.output_binary_extension = None
self.definitions = []
self.compiler_flags = []
self.linker_flags = []
self.include_directories = []
self.link_directories = []
self.source_files = []
self.static_link_libraries = []
self.dynamic_link_libraries = []
self.link_frameworks = []
self.target_type = TargetType.NONE
self.pre_build_step = None
self.post_build_step = None
# inherited from platform
self.platform_name = None
# inherited from config
self.config_name = None
# inherited from target
self.target_name = None
self.target_type = None
self.lock_file = None
self.reloadable = None
# inherited from project
self.project_name = None
self.reload_target_name = None
self.working_directory = None
self.registered_configurations = []
class CompilerProfile:
def __init__(self, compilers = None, platforms = None, configurations = None, targets = None):
self.compilers = compilers
self.platforms = platforms
self.configurations = configurations
self.targets = targets
self.output_directory = None
self.definitions = []
self.include_directories = []
self.link_directories = []
self.static_link_libraries = []
self.dynamic_link_libraries = []
self.link_frameworks = []
self.source_files = []
self.compiler_flags = []
self.linker_flags = []
self.output_binary_extension = None
def is_active(self):
if self.targets is not None:
found = False
for target in self.targets:
if target == _context.target_name:
found = True
break
if not found:
return False
if self.configurations is not None:
found = False
for config_name in self.configurations:
if config_name == _context.config_name:
found = True
break
if not found:
return False
if self.platforms is not None:
found = False
for platform_name in self.platforms:
if platform_name == _context.platform_name:
found = True
break
if not found:
return False
if self.compilers is not None:
found = False
for name in self.compilers:
if name == _context.working_settings.name:
found = True
break
if not found:
return False
return True
class BuildContext:
def __init__(self):
# persistent data
self.current_settings = []
# current project
self.project_name = None
self.reload_target_name = None
self.working_directory = None
self.registered_configurations = []
self.profiles = []
# current target
self.target_name = None
self.target_type = None
self.target_lock_file = None
self.target_reloadable = False
# current config
self.config_name = None
# current platform
self.platform_name = None
# working settings
self.working_settings = None
# project scope
self._project_output_directory = None
self._project_definitions = []
self._project_include_directories = []
self._project_link_directories = []
self._project_static_link_libraries = []
self._project_dynamic_link_libraries = []
self._project_link_frameworks = []
self._project_source_files = []
# target scope
self._target_output_binary = None
self._target_output_directory = None
self._target_definitions = []
self._target_include_directories = []
self._target_link_directories = []
self._target_static_link_libraries = []
self._target_dynamic_link_libraries = []
self._target_link_frameworks = []
self._target_source_files = []
# config scope
self._config_output_binary = None
self._config_output_directory = None
self._config_definitions = []
self._config_include_directories = []
self._config_link_directories = []
self._config_static_link_libraries = []
self._config_dynamic_link_libraries = []
self._config_link_frameworks = []
self._config_source_files = []
# platform scope
self._platform_output_binary = None
self._platform_output_directory = None
self._platform_definitions = []
self._platform_include_directories = []
self._platform_link_directories = []
self._platform_static_link_libraries = []
self._platform_dynamic_link_libraries = []
self._platform_link_frameworks = []
self._platform_source_files = []
###############################################################################
# Global Context #
###############################################################################
_context = BuildContext()
###############################################################################
# Project #
###############################################################################
@contextmanager
def project(name: str):
try:
# persistent data
_context.current_settings = []
# current project
_context.project_name = name
_context.reload_target_name = None
_context.working_directory = "./"
_context.registered_configurations = []
_context.profiles = []
# current target
_context.target_name = None
_context.target_type = None
_context.target_lock_file = None
_context.target_reloadable = False
# current config
_context.config_name = None
# current platform
_context.platform_name = None
# working settings
_context.working_settings = None
# project scope
_context._project_output_directory = None
_context._project_definitions = []
_context._project_include_directories = []
_context._project_link_directories = []
_context._project_static_link_libraries = []
_context._project_dynamic_link_libraries = []
_context._project_link_frameworks = []
_context._project_source_files = []
yield None
finally:
pass
def add_configuration(name: str):
_context.registered_configurations.append(name)
def set_working_directory(directory: str):
_context.working_directory = directory
def set_hot_reload_target(target_name: str):
_context.reload_target_name = target_name
###############################################################################
# Target #
###############################################################################
@contextmanager
def target(name: str, target_type: TargetType, reloadable: bool = False):
try:
_context.target_name = name
_context.target_type = target_type
_context.target_lock_file = "lock.tmp"
_context.target_reloadable = reloadable
yield None
finally:
_context.target_name = None
_context.target_type = None
_context.target_lock_file = None
_context.target_reloadable = False
_context._target_output_directory = None
_context._target_definitions = []
_context._target_include_directories = []
_context._target_link_directories = []
_context._target_static_link_libraries = []
_context._target_dynamic_link_libraries = []
_context._target_link_frameworks = []
_context._target_source_files = []
###############################################################################
# Configuration #
###############################################################################
@contextmanager
def configuration(name: str):
try:
_context.config_name = name
yield None
finally:
_context.config_name = None
_context._config_output_directory = None
_context._config_definitions = []
_context._config_include_directories = []
_context._config_link_directories = []
_context._config_static_link_libraries = []
_context._config_dynamic_link_libraries = []
_context._config_link_frameworks = []
_context._config_source_files = []
###############################################################################
# Platform #
###############################################################################
@contextmanager
def platform(name: str):
try:
_context.platform_name = name
yield None
finally:
_context.platform_name = None
_context._platform_output_directory = None
_context._platform_definitions = []
_context._platform_include_directories = []
_context._platform_link_directories = []
_context._platform_static_link_libraries = []
_context._platform_dynamic_link_libraries = []
_context._platform_link_frameworks = []
_context._platform_source_files = []
###############################################################################
# Compiler #
###############################################################################
@contextmanager
def compiler(name: str):
try:
compiler = CompilerSettings(name)
# inherited from platform
compiler.platform_name = _context.platform_name
# inherited from config
compiler.config_name = _context.config_name
# inherited from target
compiler.target_name = _context.target_name
compiler.target_type = _context.target_type
compiler.lock_file = _context.target_lock_file
compiler.reloadable = _context.target_reloadable
# inherited from project
compiler.project_name = _context.project_name
compiler.reload_target_name = _context.reload_target_name
compiler.working_directory = _context.working_directory
compiler.registered_configurations = _context.registered_configurations
# inherited
if _context._platform_output_directory is not None:
compiler.output_directory = _context._platform_output_directory
elif _context._config_output_directory is not None:
compiler.output_directory = _context._config_output_directory
elif _context._target_output_directory is not None:
compiler.output_directory = _context._target_output_directory
elif _context._project_output_directory is not None:
compiler.output_directory = _context._project_output_directory
if _context._platform_output_binary is not None:
compiler.output_binary = _context._platform_output_binary
elif _context._config_output_binary is not None:
compiler.output_binary = _context._config_output_binary
elif _context._target_output_binary is not None:
compiler.output_binary = _context._target_output_binary
compiler.link_directories = _context._project_link_directories + _context._target_link_directories + _context._config_link_directories + _context._platform_link_directories
compiler.definitions = _context._project_definitions + _context._target_definitions + _context._config_definitions + _context._platform_definitions
compiler.include_directories = _context._project_include_directories + _context._target_include_directories + _context._config_include_directories + _context._platform_include_directories
compiler.static_link_libraries = _context._project_static_link_libraries + _context._target_static_link_libraries + _context._config_static_link_libraries + _context._platform_static_link_libraries
compiler.dynamic_link_libraries = _context._project_dynamic_link_libraries + _context._target_dynamic_link_libraries + _context._config_dynamic_link_libraries + _context._platform_dynamic_link_libraries
compiler.link_frameworks = _context._project_link_frameworks + _context._target_link_frameworks + _context._config_link_frameworks + _context._platform_link_frameworks
compiler.source_files = _context._project_source_files + _context._target_source_files + _context._config_source_files + _context._platform_source_files
_context.working_settings = compiler
# check profiles
for profile in _context.profiles:
if profile.is_active():
_context.working_settings.definitions.extend(profile.definitions)
_context.working_settings.compiler_flags.extend(profile.compiler_flags)
_context.working_settings.include_directories.extend(profile.include_directories)
_context.working_settings.link_directories.extend(profile.link_directories)
_context.working_settings.static_link_libraries.extend(profile.static_link_libraries)
_context.working_settings.dynamic_link_libraries.extend(profile.dynamic_link_libraries)
_context.working_settings.link_frameworks.extend(profile.link_frameworks)
_context.working_settings.source_files.extend(profile.source_files)
_context.working_settings.linker_flags.extend(profile.linker_flags)
if _context.working_settings.output_directory is None:
_context.working_settings.output_directory = profile.output_directory
if _context.working_settings.output_binary_extension is None:
_context.working_settings.output_binary_extension = profile.output_binary_extension
yield _context.working_settings
finally:
_context.current_settings.append(_context.working_settings)
_context.working_settings = None
def add_source_files(*args):
if _context.working_settings is not None:
for arg in args:
_context.working_settings.source_files.append(arg)
elif _context.platform_name is not None:
for arg in args:
_context._platform_source_files.append(arg)
elif _context.config_name is not None:
for arg in args:
_context._config_source_files.append(arg)
elif _context.target_name is not None:
for arg in args:
_context._target_source_files.append(arg)
elif _context.project_name is not None:
for arg in args:
_context._project_source_files.append(arg)
else:
raise Exception("'add_source_files(...)' must be called within a scope")
def add_static_link_libraries(*args):
if _context.working_settings is not None:
for arg in args:
_context.working_settings.static_link_libraries.append(arg)
elif _context.platform_name is not None:
for arg in args:
_context._platform_static_link_libraries.append(arg)
elif _context.config_name is not None:
for arg in args:
_context._config_static_link_libraries.append(arg)
elif _context.target_name is not None:
for arg in args:
_context._target_static_link_libraries.append(arg)
elif _context.project_name is not None:
for arg in args:
_context._project_static_link_libraries.append(arg)
else:
raise Exception("'add_static_link_libraries(...)' must be called within a scope")
def add_dynamic_link_libraries(*args):
if _context.working_settings is not None:
for arg in args:
_context.working_settings.dynamic_link_libraries.append(arg)
elif _context.platform_name is not None:
for arg in args:
_context._platform_dynamic_link_libraries.append(arg)
elif _context.config_name is not None:
for arg in args:
_context._config_dynamic_link_libraries.append(arg)
elif _context.target_name is not None:
for arg in args:
_context._target_dynamic_link_libraries.append(arg)
elif _context.project_name is not None:
for arg in args:
_context._project_dynamic_link_libraries.append(arg)
else:
raise Exception("'add_dynamic_link_libraries(...)' must be called within a scope")
def add_link_frameworks(*args):
if _context.working_settings is not None:
for arg in args:
_context.working_settings.link_frameworks.append(arg)
elif _context.platform_name is not None:
for arg in args:
_context._platform_link_frameworks.append(arg)
elif _context.config_name is not None:
for arg in args:
_context._config_link_frameworks.append(arg)
elif _context.target_name is not None:
for arg in args:
_context._target_link_frameworks.append(arg)
elif _context.project_name is not None:
for arg in args:
_context._project_link_frameworks.append(arg)
else:
raise Exception("'add_link_frameworks(...)' must be called within a scope")
def add_definitions(*args):
if _context.working_settings is not None:
for arg in args:
_context.working_settings.definitions.append(arg)
elif _context.platform_name is not None:
for arg in args:
_context._platform_definitions.append(arg)
elif _context.config_name is not None:
for arg in args:
_context._config_definitions.append(arg)
elif _context.target_name is not None:
for arg in args:
_context._target_definitions.append(arg)
elif _context.project_name is not None:
for arg in args:
_context._project_definitions.append(arg)
else:
raise Exception("'add_definitions(...)' must be called within a scope")
def add_compiler_flags(*args):
for arg in args:
_context.working_settings.compiler_flags.append(arg)
def add_linker_flags(*args):
for arg in args:
_context.working_settings.linker_flags.append(arg)
def add_include_directories(*args):
if _context.working_settings is not None:
for arg in args:
_context.working_settings.include_directories.append(arg)
elif _context.platform_name is not None:
for arg in args:
_context._platform_include_directories.append(arg)
elif _context.config_name is not None:
for arg in args:
_context._config_include_directories.append(arg)
elif _context.target_name is not None:
for arg in args:
_context._target_include_directories.append(arg)
elif _context.project_name is not None:
for arg in args:
_context._project_include_directories.append(arg)
else:
raise Exception("'add_include_directories(...)' must be called within a scope")
def add_link_directories(*args):
if _context.working_settings is not None:
for arg in args:
_context.working_settings.link_directories.append(arg)
elif _context.platform_name is not None:
for arg in args:
_context._platform_link_directories.append(arg)
elif _context.config_name is not None:
for arg in args:
_context._config_link_directories.append(arg)
elif _context.target_name is not None:
for arg in args:
_context._target_link_directories.append(arg)
elif _context.project_name is not None:
for arg in args:
_context._project_link_directories.append(arg)
else:
raise Exception("'add_link_directories(...)' must be called within a scope")
def set_output_binary(binary: str):
if _context.working_settings is not None:
_context.working_settings.output_binary = binary
elif _context.platform_name is not None:
_context._platform_output_binary = binary
elif _context.config_name is not None:
_context._config_output_binary = binary
elif _context.target_name is not None:
_context._target_output_binary = binary
else:
raise Exception("'set_output_binary(...)' must be called within a correct scope")
def set_output_binary_extension(extension: str):
_context.working_settings.output_binary_extension = extension
def set_output_directory(directory: str):
if _context.working_settings is not None:
_context.working_settings.output_directory = directory
elif _context.platform_name is not None:
_context._platform_output_directory = directory
elif _context.config_name is not None:
_context._config_output_directory = directory
elif _context.target_name is not None:
_context._target_output_directory = directory
elif _context.project_name is not None:
_context._project_output_directory = directory
else:
raise Exception("'set_output_directory(...)' must be called within a scope")
def add_compiler_flags_profile(targets, configurations, platforms, compilers, *args):
profile = CompilerProfile(compilers, platforms, configurations, targets)
profile.compiler_flags = args
_context.profiles.append(profile)
def add_include_directories_profile(targets, configurations, platforms, compilers, *args):
profile = CompilerProfile(compilers, platforms, configurations, targets)
profile.include_directories = args
_context.profiles.append(profile)
def add_definitions_profile(targets, configurations, platforms, compilers, *args):
profile = CompilerProfile(compilers, platforms, configurations, targets)
profile.definitions = args
_context.profiles.append(profile)
def add_link_directories_profile(targets, configurations, platforms, compilers, *args):
profile = CompilerProfile(compilers, platforms, configurations, targets)
profile.link_directories = args
_context.profiles.append(profile)
def add_static_link_libraries_profile(targets, configurations, platforms, compilers, *args):
profile = CompilerProfile(compilers, platforms, configurations, targets)
profile.static_link_libraries = args
_context.profiles.append(profile)
def add_dynamic_link_libraries_profile(targets, configurations, platforms, compilers, *args):
profile = CompilerProfile(compilers, platforms, configurations, targets)
profile.dynamic_link_libraries = args
_context.profiles.append(profile)
def add_link_frameworks_profile(targets, configurations, platforms, compilers, *args):
profile = CompilerProfile(compilers, platforms, configurations, targets)
profile.link_frameworks = args
_context.profiles.append(profile)
def add_source_files_profile(targets, configurations, platforms, compilers, *args):
profile = CompilerProfile(compilers, platforms, configurations, targets)
profile.source_files = args
_context.profiles.append(profile)
def add_linker_flags_profile(targets, configurations, platforms, compilers, *args):
profile = CompilerProfile(compilers, platforms, configurations, targets)
profile.linker_flags = args
_context.profiles.append(profile)
def set_output_binary_extension_profile(targets, configurations, platforms, compilers, extension):
profile = CompilerProfile(compilers, platforms, configurations, targets)
profile.output_binary_extension = extension
_context.profiles.append(profile)
def set_output_directory_profile(targets, configurations, platforms, compilers, irectory):
profile = CompilerProfile(compilers, platforms, configurations, targets)
profile.output_directory = irectory
_context.profiles.append(profile)
def set_pre_target_build_step(code: str):
_context.working_settings.pre_build_step = code
def set_post_target_build_step(code: str):
_context.working_settings.post_build_step = code
###############################################################################
# Query #
###############################################################################
def get_platform() -> str:
return _context.platform_name
def get_target() -> str:
return _context.target_name
def get_target_type() -> str:
return _context.target_type
def get_configuration() -> str:
return _context.config_name
def get_compiler() -> str:
return _context.working_settings.name