diff --git a/README.md b/README.md index f592ce3..1213e95 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,37 @@ ## Pilot Light Build -Under construction. - -## Information + +### Background +The **pl-build** project is a child of the larger [Pilot Light](https://github.com/PilotLightTech/pilotlight) project. In this larger project, we do not have a "build system" per se. Instead we prefer to write batch/bash scripts that directly call the compiler. If the project was an end user product, this would be the end of it. However, this is not the case. It is meant to be easily be extended through adding additional extensions and being used as a "pilot light" to start new projects. With this comes a couple issues. Extensions are meant to be cross platform so users need the ability to easily add new binaries for all target platforms with minimal duplication. Users shouldn't need to be bash or batch scripting experts to build new targets for all platforms and shouldn't need to test the build scripts continuously on each platform. + + +### Requirements +* minimize duplicated information +* fine-grained control over compilation settings +* support unity builds +* support hot reloading +* generate scripts that can be used separately +* easily extended +* easy to add new platforms and compilers +* extremely light weight +* easy to customize and extended +* no preference on editor/IDE +* doesn't pretend different platforms don't exist +* entire build system can be understood in an hour + +Another way of putting it, is we want to focus on what matters to build binaries. Ultimately this is just compiler & linker settings. We don't want to think about the differences in bash/batch syntax. + +### Benefits Over Raw Scripts +Prior to this system, when we were writing scripts directly, we did what every developer does and began overengineering the build scripts to improve things like information duplication, configuration options, etc. However, this led to more compilicated scripts that were harder to debug and heavily deviated between platforms since batch/command are very different in features and syntax. It became hard for newcomers to work on and encouraged differences to creep in between the way individual build scripts worked. + +Using pl-build allows the clever/overengineered solutions to be accomplished at a higher level by the user in python. In the end, build scripts are output that are very straight forward and much easier to debug. It also makes it easier to implement new backends to target new compilers, platforms, scripting languages, etc. + +### Alternatives + +Keep in mind, **we don't want a build system**. We don't want to hide away details or abstract away control. We ultimately just need a tool to assist in generating the scripts for each platform. + +What about other CMake (and others)? They are bloated over complicated messes. They are also overkill for what we need (see Requirements section above). + + +## Documentation Under construction. diff --git a/pl_build/pl_build_linux.py b/pl_build/backend_linux.py similarity index 56% rename from pl_build/pl_build_linux.py rename to pl_build/backend_linux.py index 399a7b9..eeeaced 100644 --- a/pl_build/pl_build_linux.py +++ b/pl_build/backend_linux.py @@ -1,5 +1,4 @@ -import pl_build as pl -from pl_build import _context, __version__ +import pl_build.core as pl from pathlib import PurePath class plLinuxHelper: @@ -51,7 +50,26 @@ class plLinuxHelper: def delete_file(self, file): self.buffer += ' ' * self.indent + 'rm -f "' + file + '"\n' -def generate_build(name, platform, compiler, user_options): +def generate_build(name, user_options = None): + + platform = "Linux" + compiler = "gcc" + + data = pl.get_script_data() + + # retrieve settings supported by this platform/compiler & add + # default extensions if the user did not + platform_settings = [] + for settings in data.current_settings: + if settings.platform_name == platform and settings.name == compiler: + if settings.output_binary_extension is None: + if settings.target_type == pl.TargetType.EXECUTABLE: + settings.output_binary_extension = "" + elif settings.target_type == pl.TargetType.DYNAMIC_LIBRARY: + settings.output_binary_extension = ".so" + elif settings.target_type == pl.TargetType.STATIC_LIBRARY: + settings.output_binary_extension = ".a" + platform_settings.append(settings) helper = plLinuxHelper() @@ -64,10 +82,10 @@ def generate_build(name, platform, compiler, user_options): helper.add_line("#!/bin/bash") helper.add_spacing() helper.add_comment("Auto Generated by:") - helper.add_comment('"pl_build.py" version: ' + __version__) + helper.add_comment('"pl_build.py" version: ' + data.version) helper.add_spacing() - helper.add_comment("Project: " + _context.project_name) + helper.add_comment("Project: " + data.project_name) helper.add_spacing() helper.add_title("Development Setup") @@ -101,9 +119,9 @@ def generate_build(name, platform, compiler, user_options): helper.add_spacing() # set default config - if _context.registered_configurations: + if data.registered_configurations: helper.add_comment("default configuration") - helper.add_line("PL_CONFIG=" + _context.registered_configurations[0]) + helper.add_line("PL_CONFIG=" + data.registered_configurations[0]) helper.add_spacing() # check command line args for config @@ -123,20 +141,7 @@ def generate_build(name, platform, compiler, user_options): # helper.add_line(_context.pre_build_step) # helper.add_spacing() - # filter linux only settings - platform_settings = [] - for settings in _context.current_settings: - if settings.platform_name == platform: - if settings.output_binary_extension is None: - if settings.target_type == pl.TargetType.EXECUTABLE: - settings.output_binary_extension = "" - elif settings.target_type == pl.TargetType.DYNAMIC_LIBRARY: - settings.output_binary_extension = ".so" - elif settings.target_type == pl.TargetType.STATIC_LIBRARY: - settings.output_binary_extension = ".a" - platform_settings.append(settings) - - for register_config in _context.registered_configurations: + for register_config in data.registered_configurations: # filter this config only settings config_only_settings = [] @@ -148,7 +153,7 @@ def generate_build(name, platform, compiler, user_options): continue # find hot reload target - if _context.reload_target_name is not None: + if data.reload_target_name is not None: hot_reload = True helper.add_title("configuration | " + register_config) @@ -181,7 +186,7 @@ def generate_build(name, platform, compiler, user_options): helper.add_spacing() helper.add_comment("# let user know if hot reloading") - helper.add_line('if pidof -x "' + PurePath(_context.reload_target_name).stem + '" -o $$ >/dev/null;then') + helper.add_line('if pidof -x "' + PurePath(data.reload_target_name).stem + '" -o $$ >/dev/null;then') helper.set_indent(4) helper.add_line('PL_HOT_RELOAD_STATUS=1') helper.print_space() @@ -216,124 +221,122 @@ def generate_build(name, platform, compiler, user_options): helper.add_sub_title(settings.target_name + " | " + register_config) helper.add_spacing() - if settings.name == compiler: + if not settings.reloadable and hot_reload: + helper.add_comment('skip during hot reload') + helper.add_line('if [ $PL_HOT_RELOAD_STATUS -ne 1 ]; then') + helper.add_spacing() - if not settings.reloadable and hot_reload: - helper.add_comment('skip during hot reload') - helper.add_line('if [ $PL_HOT_RELOAD_STATUS -ne 1 ]; then') - helper.add_spacing() + if settings.pre_build_step is not None: + helper.add_line(settings.pre_build_step) + helper.add_spacing() - if settings.pre_build_step is not None: - helper.add_line(settings.pre_build_step) - helper.add_spacing() + helper.add_line("PL_RESULT=${BOLD}${GREEN}Successful.${NC}") + helper.add_raw('PL_DEFINES="') + for define in settings.definitions: + helper.add_raw('-D' + define + " ") + helper.add_raw('"\n') - helper.add_line("PL_RESULT=${BOLD}${GREEN}Successful.${NC}") - helper.add_raw('PL_DEFINES="') - for define in settings.definitions: - helper.add_raw('-D' + define + " ") + helper.add_raw('PL_INCLUDE_DIRECTORIES="') + for include in settings.include_directories: + helper.add_raw('-I' + include + ' ') + helper.add_raw('"\n') + + helper.add_raw('PL_LINK_DIRECTORIES="') + for link in settings.link_directories: + helper.add_raw('-L' + link + ' ') + helper.add_raw('"\n') + + helper.add_raw('PL_COMPILER_FLAGS="') + for flag in settings.compiler_flags: + helper.add_raw(flag + ' ') + helper.add_raw('"\n') + + helper.add_raw('PL_LINKER_FLAGS="') + for flag in settings.linker_flags: + helper.add_raw(flag + ' ') + helper.add_raw('"\n') + + helper.add_raw('PL_STATIC_LINK_LIBRARIES="') + for link in settings.static_link_libraries: + helper.add_raw('-l:' + link + '.a ') + helper.add_raw('"\n') + + helper.add_raw('PL_DYNAMIC_LINK_LIBRARIES="') + for link in settings.dynamic_link_libraries: + helper.add_raw('-l' + link + ' ') + helper.add_raw('"\n') + + if settings.target_type == pl.TargetType.STATIC_LIBRARY: + helper.add_comment('# run compiler only') + helper.print_space() + helper.print_line('${YELLOW}Step: ' + settings.target_name +'${NC}') + helper.print_line('${YELLOW}~~~~~~~~~~~~~~~~~~~${NC}') + helper.print_line('${CYAN}Compiling...${NC}') + helper.add_spacing() + + helper.add_comment('each file must be compiled separately') + for source in settings.source_files: + source_as_path = PurePath(source) + helper.add_line('gcc -c $PL_INCLUDE_DIRECTORIES $PL_DEFINES $PL_COMPILER_FLAGS ' + source + ' -o "./' + settings.output_directory + '/' + source_as_path.stem + '.o"') + helper.add_spacing() + helper.add_comment('combine object files into a static lib') + helper.add_line('ar rcs ./' + settings.output_directory + '/' + settings.output_binary + '.a ./' + settings.output_directory + '/*.o') + helper.add_line('rm ./' + settings.output_directory + '/*.o') + helper.add_spacing() + + elif settings.target_type == pl.TargetType.DYNAMIC_LIBRARY: + helper.add_raw('PL_SOURCES="') + for source in settings.source_files: + helper.add_raw(source + ' ') helper.add_raw('"\n') + helper.add_spacing() - helper.add_raw('PL_INCLUDE_DIRECTORIES="') - for include in settings.include_directories: - helper.add_raw('-I' + include + ' ') + helper.add_comment('run compiler (and linker)') + helper.print_space() + helper.print_line('${YELLOW}Step: ' + settings.target_name +'${NC}') + helper.print_line('${YELLOW}~~~~~~~~~~~~~~~~~~~${NC}') + helper.print_line('${CYAN}Compiling and Linking...${NC}') + helper.add_line('gcc -shared $PL_SOURCES $PL_INCLUDE_DIRECTORIES $PL_DEFINES $PL_COMPILER_FLAGS $PL_INCLUDE_DIRECTORIES $PL_LINK_DIRECTORIES $PL_LINKER_FLAGS $PL_STATIC_LINK_LIBRARIES $PL_DYNAMIC_LINK_LIBRARIES -o "./' + settings.output_directory + '/' + settings.output_binary + settings.output_binary_extension +'"') + helper.add_spacing() + + elif settings.target_type == pl.TargetType.EXECUTABLE: + helper.add_raw('PL_SOURCES="') + for source in settings.source_files: + helper.add_raw(source + ' ') helper.add_raw('"\n') + helper.add_spacing() - helper.add_raw('PL_LINK_DIRECTORIES="') - for link in settings.link_directories: - helper.add_raw('-L' + link + ' ') - helper.add_raw('"\n') + helper.add_comment('run compiler (and linker)') + helper.print_space() + helper.print_line('${YELLOW}Step: ' + settings.target_name +'${NC}') + helper.print_line('${YELLOW}~~~~~~~~~~~~~~~~~~~${NC}') + helper.print_line('${CYAN}Compiling and Linking...${NC}') + helper.add_line('gcc $PL_SOURCES $PL_INCLUDE_DIRECTORIES $PL_DEFINES $PL_COMPILER_FLAGS $PL_INCLUDE_DIRECTORIES $PL_LINK_DIRECTORIES $PL_LINKER_FLAGS $PL_STATIC_LINK_LIBRARIES $PL_DYNAMIC_LINK_LIBRARIES -o "./' + settings.output_directory + '/' + settings.output_binary + settings.output_binary_extension +'"') + helper.add_spacing() - helper.add_raw('PL_COMPILER_FLAGS="') - for flag in settings.compiler_flags: - helper.add_raw(flag + ' ') - helper.add_raw('"\n') + # check build status + helper.add_comment("check build status") + helper.add_line("if [ $? -ne 0 ]") + helper.add_line("then") + helper.add_line(" PL_RESULT=${BOLD}${RED}Failed.${NC}") + helper.add_line("fi") + helper.add_spacing() - helper.add_raw('PL_LINKER_FLAGS="') - for flag in settings.linker_flags: - helper.add_raw(flag + ' ') - helper.add_raw('"\n') + # print results + helper.add_comment("print results") + helper.print_line("${CYAN}Results: ${NC} ${PL_RESULT}") + helper.print_line("${CYAN}~~~~~~~~~~~~~~~~~~~~~~${NC}") + helper.add_spacing() - helper.add_raw('PL_STATIC_LINK_LIBRARIES="') - for link in settings.static_link_libraries: - helper.add_raw('-l:' + link + '.a ') - helper.add_raw('"\n') + if settings.post_build_step is not None: + helper.add_line(settings.post_build_step) + helper.add_spacing() - helper.add_raw('PL_DYNAMIC_LINK_LIBRARIES="') - for link in settings.dynamic_link_libraries: - helper.add_raw('-l' + link + ' ') - helper.add_raw('"\n') - - if settings.target_type == pl.TargetType.STATIC_LIBRARY: - helper.add_comment('# run compiler only') - helper.print_space() - helper.print_line('${YELLOW}Step: ' + settings.target_name +'${NC}') - helper.print_line('${YELLOW}~~~~~~~~~~~~~~~~~~~${NC}') - helper.print_line('${CYAN}Compiling...${NC}') - helper.add_spacing() - - helper.add_comment('each file must be compiled separately') - for source in settings.source_files: - source_as_path = PurePath(source) - helper.add_line('gcc -c $PL_INCLUDE_DIRECTORIES $PL_DEFINES $PL_COMPILER_FLAGS ' + source + ' -o "./' + settings.output_directory + '/' + source_as_path.stem + '.o"') - helper.add_spacing() - helper.add_comment('combine object files into a static lib') - helper.add_line('ar rcs ./' + settings.output_directory + '/' + settings.output_binary + '.a ./' + settings.output_directory + '/*.o') - helper.add_line('rm ./' + settings.output_directory + '/*.o') - helper.add_spacing() - - elif settings.target_type == pl.TargetType.DYNAMIC_LIBRARY: - helper.add_raw('PL_SOURCES="') - for source in settings.source_files: - helper.add_raw(source + ' ') - helper.add_raw('"\n') - helper.add_spacing() - - helper.add_comment('run compiler (and linker)') - helper.print_space() - helper.print_line('${YELLOW}Step: ' + settings.target_name +'${NC}') - helper.print_line('${YELLOW}~~~~~~~~~~~~~~~~~~~${NC}') - helper.print_line('${CYAN}Compiling and Linking...${NC}') - helper.add_line('gcc -shared $PL_SOURCES $PL_INCLUDE_DIRECTORIES $PL_DEFINES $PL_COMPILER_FLAGS $PL_INCLUDE_DIRECTORIES $PL_LINK_DIRECTORIES $PL_LINKER_FLAGS $PL_STATIC_LINK_LIBRARIES $PL_DYNAMIC_LINK_LIBRARIES -o "./' + settings.output_directory + '/' + settings.output_binary + settings.output_binary_extension +'"') - helper.add_spacing() - - elif settings.target_type == pl.TargetType.EXECUTABLE: - helper.add_raw('PL_SOURCES="') - for source in settings.source_files: - helper.add_raw(source + ' ') - helper.add_raw('"\n') - helper.add_spacing() - - helper.add_comment('run compiler (and linker)') - helper.print_space() - helper.print_line('${YELLOW}Step: ' + settings.target_name +'${NC}') - helper.print_line('${YELLOW}~~~~~~~~~~~~~~~~~~~${NC}') - helper.print_line('${CYAN}Compiling and Linking...${NC}') - helper.add_line('gcc $PL_SOURCES $PL_INCLUDE_DIRECTORIES $PL_DEFINES $PL_COMPILER_FLAGS $PL_INCLUDE_DIRECTORIES $PL_LINK_DIRECTORIES $PL_LINKER_FLAGS $PL_STATIC_LINK_LIBRARIES $PL_DYNAMIC_LINK_LIBRARIES -o "./' + settings.output_directory + '/' + settings.output_binary + settings.output_binary_extension +'"') - helper.add_spacing() - - # check build status - helper.add_comment("check build status") - helper.add_line("if [ $? -ne 0 ]") - helper.add_line("then") - helper.add_line(" PL_RESULT=${BOLD}${RED}Failed.${NC}") + if not settings.reloadable and hot_reload: + helper.add_comment("hot reload skip") helper.add_line("fi") helper.add_spacing() - # print results - helper.add_comment("print results") - helper.print_line("${CYAN}Results: ${NC} ${PL_RESULT}") - helper.print_line("${CYAN}~~~~~~~~~~~~~~~~~~~~~~${NC}") - helper.add_spacing() - - if settings.post_build_step is not None: - helper.add_line(settings.post_build_step) - helper.add_spacing() - - if not settings.reloadable and hot_reload: - helper.add_comment("hot reload skip") - helper.add_line("fi") - helper.add_spacing() - helper.add_comment("delete lock file(s)") for lock_file in lock_files: helper.delete_file(settings.output_directory + '/' + lock_file) @@ -352,4 +355,4 @@ def generate_build(name, platform, compiler, user_options): helper.add_comment('return CWD to previous CWD') helper.add_line('popd >/dev/null') - helper.write_file(_context.working_directory + "/" + name) \ No newline at end of file + helper.write_file(name) \ No newline at end of file diff --git a/pl_build/pl_build_macos.py b/pl_build/backend_macos.py similarity index 56% rename from pl_build/pl_build_macos.py rename to pl_build/backend_macos.py index 55b7c60..426f060 100644 --- a/pl_build/pl_build_macos.py +++ b/pl_build/backend_macos.py @@ -1,5 +1,4 @@ -import pl_build as pl -from pl_build import _context, __version__ +import pl_build.core as pl from pathlib import PurePath class plAppleHelper: @@ -51,10 +50,28 @@ class plAppleHelper: def delete_file(self, file): self.buffer += ' ' * self.indent + 'rm -f "' + file + '"\n' -def generate_build(name, platform, compiler, user_options): +def generate_build(name, user_options = None): + platform = "Darwin" + compiler = "clang" + + data = pl.get_script_data() helper = plAppleHelper() + # retrieve settings supported by this platform/compiler & add + # default extensions if the user did not + platform_settings = [] + for settings in data.current_settings: + if settings.platform_name == platform and settings.name == compiler: + if settings.output_binary_extension is None: + if settings.target_type == pl.TargetType.EXECUTABLE: + settings.output_binary_extension = "" + elif settings.target_type == pl.TargetType.DYNAMIC_LIBRARY: + settings.output_binary_extension = ".dylib" + elif settings.target_type == pl.TargetType.STATIC_LIBRARY: + settings.output_binary_extension = ".a" + platform_settings.append(settings) + hot_reload = False ############################################################################### @@ -63,10 +80,10 @@ def generate_build(name, platform, compiler, user_options): helper.add_spacing() helper.add_comment("Auto Generated by:") - helper.add_comment('"pl_build.py" version: ' + __version__) + helper.add_comment('"pl_build.py" version: ' + data.version) helper.add_spacing() - helper.add_comment("Project: " + _context.project_name) + helper.add_comment("Project: " + data.project_name) helper.add_spacing() helper.add_title("Development Setup") @@ -104,9 +121,9 @@ def generate_build(name, platform, compiler, user_options): helper.add_spacing() # set default config - if _context.registered_configurations: + if data.registered_configurations: helper.add_comment("default configuration") - helper.add_line("PL_CONFIG=" + _context.registered_configurations[0]) + helper.add_line("PL_CONFIG=" + data.registered_configurations[0]) helper.add_spacing() # check command line args for config @@ -126,20 +143,7 @@ def generate_build(name, platform, compiler, user_options): # helper.add_line(_context.pre_build_step) # helper.add_spacing() - # filter macos only settings - platform_settings = [] - for settings in _context.current_settings: - if settings.platform_name == platform: - if settings.output_binary_extension is None: - if settings.target_type == pl.TargetType.EXECUTABLE: - settings.output_binary_extension = "" - elif settings.target_type == pl.TargetType.DYNAMIC_LIBRARY: - settings.output_binary_extension = ".dylib" - elif settings.target_type == pl.TargetType.STATIC_LIBRARY: - settings.output_binary_extension = ".a" - platform_settings.append(settings) - - for register_config in _context.registered_configurations: + for register_config in data.registered_configurations: # filter this config only settings config_only_settings = [] @@ -151,7 +155,7 @@ def generate_build(name, platform, compiler, user_options): continue # check if hot reload - if _context.reload_target_name is not None: + if data.reload_target_name is not None: hot_reload = True helper.add_title("configuration | " + register_config) @@ -184,7 +188,7 @@ def generate_build(name, platform, compiler, user_options): helper.add_spacing() helper.add_comment("# let user know if hot reloading") - helper.add_line('running_count=$(ps aux | grep -v grep | grep -ci "' + PurePath(_context.reload_target_name).stem + '")') + helper.add_line('running_count=$(ps aux | grep -v grep | grep -ci "' + PurePath(data.reload_target_name).stem + '")') helper.add_line('if [ $running_count -gt 0 ]') helper.add_line('then') helper.set_indent(4) @@ -220,131 +224,129 @@ def generate_build(name, platform, compiler, user_options): helper.add_sub_title(settings.target_name + " | " + register_config) helper.add_spacing() - if settings.name == compiler: + if not settings.reloadable and hot_reload: + helper.add_comment('skip during hot reload') + helper.add_line('if [ $PL_HOT_RELOAD_STATUS -ne 1 ]; then') + helper.add_spacing() - if not settings.reloadable and hot_reload: - helper.add_comment('skip during hot reload') - helper.add_line('if [ $PL_HOT_RELOAD_STATUS -ne 1 ]; then') - helper.add_spacing() + if settings.pre_build_step is not None: + helper.add_line(settings.pre_build_step) + helper.add_spacing() - if settings.pre_build_step is not None: - helper.add_line(settings.pre_build_step) - helper.add_spacing() + helper.add_line("PL_RESULT=${BOLD}${GREEN}Successful.${NC}") + helper.add_raw('PL_DEFINES="') + for define in settings.definitions: + helper.add_raw('-D' + define + " ") + helper.add_raw('"\n') - helper.add_line("PL_RESULT=${BOLD}${GREEN}Successful.${NC}") - helper.add_raw('PL_DEFINES="') - for define in settings.definitions: - helper.add_raw('-D' + define + " ") - helper.add_raw('"\n') + helper.add_raw('PL_INCLUDE_DIRECTORIES="') + for include in settings.include_directories: + helper.add_raw('-I' + include + ' ') + helper.add_raw('"\n') - helper.add_raw('PL_INCLUDE_DIRECTORIES="') - for include in settings.include_directories: - helper.add_raw('-I' + include + ' ') - helper.add_raw('"\n') + helper.add_raw('PL_LINK_DIRECTORIES="') + for link in settings.link_directories: + helper.add_raw('-L' + link + ' ') + helper.add_raw('"\n') - helper.add_raw('PL_LINK_DIRECTORIES="') - for link in settings.link_directories: - helper.add_raw('-L' + link + ' ') - helper.add_raw('"\n') + helper.add_raw('PL_COMPILER_FLAGS="') + for flag in settings.compiler_flags: + helper.add_raw(flag + ' ') + helper.add_raw('"\n') - helper.add_raw('PL_COMPILER_FLAGS="') - for flag in settings.compiler_flags: - helper.add_raw(flag + ' ') - helper.add_raw('"\n') + helper.add_raw('PL_LINKER_FLAGS="') + for flag in settings.linker_flags: + helper.add_raw(flag + ' ') + helper.add_raw('"\n') - helper.add_raw('PL_LINKER_FLAGS="') - for flag in settings.linker_flags: - helper.add_raw(flag + ' ') - helper.add_raw('"\n') + helper.add_raw('PL_STATIC_LINK_LIBRARIES="') + for link in settings.static_link_libraries: + helper.add_raw('-l' + link + ' ') + helper.add_raw('"\n') - helper.add_raw('PL_STATIC_LINK_LIBRARIES="') - for link in settings.static_link_libraries: - helper.add_raw('-l' + link + ' ') - helper.add_raw('"\n') + helper.add_raw('PL_DYNAMIC_LINK_LIBRARIES="') + for link in settings.dynamic_link_libraries: + helper.add_raw('-l' + link + ' ') + helper.add_raw('"\n') - helper.add_raw('PL_DYNAMIC_LINK_LIBRARIES="') - for link in settings.dynamic_link_libraries: - helper.add_raw('-l' + link + ' ') - helper.add_raw('"\n') + helper.add_raw('PL_SOURCES="') + for source in settings.source_files: + helper.add_raw(source + ' ') + helper.add_raw('"\n') - helper.add_raw('PL_SOURCES="') + helper.add_raw('PL_LINK_FRAMEWORKS="') + for link in settings.link_frameworks: + helper.add_raw('-framework ' + link + ' ') + helper.add_raw('"\n') + + helper.add_spacing() + helper.add_comment('add flags for specific hardware') + helper.add_line('if [[ "$ARCH" == "arm64" ]]; then') + helper.add_line(' PL_COMPILER_FLAGS+="-arch arm64 "') + helper.add_line('else') + helper.add_line(' PL_COMPILER_FLAGS+="-arch x86_64 "') + helper.add_line('fi') + helper.add_spacing() + + if settings.target_type == pl.TargetType.STATIC_LIBRARY: + helper.add_comment('# run compiler only') + helper.print_space() + helper.print_line('${YELLOW}Step: ' + settings.target_name +'${NC}') + helper.print_line('${YELLOW}~~~~~~~~~~~~~~~~~~~${NC}') + helper.print_line('${CYAN}Compiling...${NC}') + helper.add_spacing() + + helper.add_comment('each file must be compiled separately') for source in settings.source_files: - helper.add_raw(source + ' ') - helper.add_raw('"\n') - - helper.add_raw('PL_LINK_FRAMEWORKS="') - for link in settings.link_frameworks: - helper.add_raw('-framework ' + link + ' ') - helper.add_raw('"\n') - + source_as_path = PurePath(source) + helper.add_line( 'clang -c $PL_INCLUDE_DIRECTORIES $PL_DEFINES $PL_COMPILER_FLAGS ' + source + ' -o "./' + settings.output_directory + '/' + source_as_path.stem + '.o"') helper.add_spacing() - helper.add_comment('add flags for specific hardware') - helper.add_line('if [[ "$ARCH" == "arm64" ]]; then') - helper.add_line(' PL_COMPILER_FLAGS+="-arch arm64 "') - helper.add_line('else') - helper.add_line(' PL_COMPILER_FLAGS+="-arch x86_64 "') - helper.add_line('fi') + helper.add_comment('combine object files into a static lib') + helper.add_line('ar rcs ./' + settings.output_directory + '/lib' + settings.output_binary + '.a ./' + settings.output_directory + '/*.o') + helper.add_line('rm ./' + settings.output_directory + '/*.o') helper.add_spacing() - if settings.target_type == pl.TargetType.STATIC_LIBRARY: - helper.add_comment('# run compiler only') - helper.print_space() - helper.print_line('${YELLOW}Step: ' + settings.target_name +'${NC}') - helper.print_line('${YELLOW}~~~~~~~~~~~~~~~~~~~${NC}') - helper.print_line('${CYAN}Compiling...${NC}') - helper.add_spacing() - - helper.add_comment('each file must be compiled separately') - for source in settings.source_files: - source_as_path = PurePath(source) - helper.add_line( 'clang -c $PL_INCLUDE_DIRECTORIES $PL_DEFINES $PL_COMPILER_FLAGS ' + source + ' -o "./' + settings.output_directory + '/' + source_as_path.stem + '.o"') - helper.add_spacing() - helper.add_comment('combine object files into a static lib') - helper.add_line('ar rcs ./' + settings.output_directory + '/lib' + settings.output_binary + '.a ./' + settings.output_directory + '/*.o') - helper.add_line('rm ./' + settings.output_directory + '/*.o') - helper.add_spacing() + elif settings.target_type == pl.TargetType.DYNAMIC_LIBRARY: + helper.add_comment('run compiler (and linker)') + helper.print_space() + helper.print_line('${YELLOW}Step: ' + settings.target_name +'${NC}') + helper.print_line('${YELLOW}~~~~~~~~~~~~~~~~~~~${NC}') + helper.print_line('${CYAN}Compiling and Linking...${NC}') + helper.add_line('clang -shared $PL_SOURCES $PL_INCLUDE_DIRECTORIES $PL_DEFINES $PL_COMPILER_FLAGS $PL_INCLUDE_DIRECTORIES $PL_LINK_DIRECTORIES $PL_LINKER_FLAGS $PL_STATIC_LINK_LIBRARIES $PL_DYNAMIC_LINK_LIBRARIES $PL_LINK_FRAMEWORKS -o "./' + settings.output_directory + '/' + settings.output_binary + settings.output_binary_extension +'"') + helper.add_spacing() - elif settings.target_type == pl.TargetType.DYNAMIC_LIBRARY: - helper.add_comment('run compiler (and linker)') - helper.print_space() - helper.print_line('${YELLOW}Step: ' + settings.target_name +'${NC}') - helper.print_line('${YELLOW}~~~~~~~~~~~~~~~~~~~${NC}') - helper.print_line('${CYAN}Compiling and Linking...${NC}') - helper.add_line('clang -shared $PL_SOURCES $PL_INCLUDE_DIRECTORIES $PL_DEFINES $PL_COMPILER_FLAGS $PL_INCLUDE_DIRECTORIES $PL_LINK_DIRECTORIES $PL_LINKER_FLAGS $PL_STATIC_LINK_LIBRARIES $PL_DYNAMIC_LINK_LIBRARIES $PL_LINK_FRAMEWORKS -o "./' + settings.output_directory + '/' + settings.output_binary + settings.output_binary_extension +'"') - helper.add_spacing() + elif settings.target_type == pl.TargetType.EXECUTABLE: + helper.add_comment('run compiler (and linker)') + helper.print_space() + helper.print_line('${YELLOW}Step: ' + settings.target_name +'${NC}') + helper.print_line('${YELLOW}~~~~~~~~~~~~~~~~~~~${NC}') + helper.print_line('${CYAN}Compiling and Linking...${NC}') + helper.add_line('clang $PL_SOURCES $PL_INCLUDE_DIRECTORIES $PL_DEFINES $PL_COMPILER_FLAGS $PL_INCLUDE_DIRECTORIES $PL_LINK_DIRECTORIES $PL_LINKER_FLAGS $PL_STATIC_LINK_LIBRARIES $PL_DYNAMIC_LINK_LIBRARIES -o "./' + settings.output_directory + '/' + settings.output_binary + settings.output_binary_extension +'"') + helper.add_spacing() - elif settings.target_type == pl.TargetType.EXECUTABLE: - helper.add_comment('run compiler (and linker)') - helper.print_space() - helper.print_line('${YELLOW}Step: ' + settings.target_name +'${NC}') - helper.print_line('${YELLOW}~~~~~~~~~~~~~~~~~~~${NC}') - helper.print_line('${CYAN}Compiling and Linking...${NC}') - helper.add_line('clang $PL_SOURCES $PL_INCLUDE_DIRECTORIES $PL_DEFINES $PL_COMPILER_FLAGS $PL_INCLUDE_DIRECTORIES $PL_LINK_DIRECTORIES $PL_LINKER_FLAGS $PL_STATIC_LINK_LIBRARIES $PL_DYNAMIC_LINK_LIBRARIES -o "./' + settings.output_directory + '/' + settings.output_binary + settings.output_binary_extension +'"') - helper.add_spacing() + # check build status + helper.add_comment("check build status") + helper.add_line("if [ $? -ne 0 ]") + helper.add_line("then") + helper.add_line(" PL_RESULT=${BOLD}${RED}Failed.${NC}") + helper.add_line("fi") + helper.add_spacing() - # check build status - helper.add_comment("check build status") - helper.add_line("if [ $? -ne 0 ]") - helper.add_line("then") - helper.add_line(" PL_RESULT=${BOLD}${RED}Failed.${NC}") + # print results + helper.add_comment("print results") + helper.print_line("${CYAN}Results: ${NC} ${PL_RESULT}") + helper.print_line("${CYAN}~~~~~~~~~~~~~~~~~~~~~~${NC}") + helper.add_spacing() + + if settings.post_build_step is not None: + helper.add_line(settings.post_build_step) + helper.add_spacing() + + if not settings.reloadable and hot_reload: + helper.add_comment("hot reload skip") helper.add_line("fi") helper.add_spacing() - # print results - helper.add_comment("print results") - helper.print_line("${CYAN}Results: ${NC} ${PL_RESULT}") - helper.print_line("${CYAN}~~~~~~~~~~~~~~~~~~~~~~${NC}") - helper.add_spacing() - - if settings.post_build_step is not None: - helper.add_line(settings.post_build_step) - helper.add_spacing() - - if not settings.reloadable and hot_reload: - helper.add_comment("hot reload skip") - helper.add_line("fi") - helper.add_spacing() - helper.add_comment("delete lock file(s)") for lock_file in lock_files: helper.delete_file(settings.output_directory + '/' + lock_file) @@ -363,4 +365,4 @@ def generate_build(name, platform, compiler, user_options): helper.add_comment('return CWD to previous CWD') helper.add_line('popd >/dev/null') - helper.write_file(_context.working_directory + "/" + name) \ No newline at end of file + helper.write_file(name) \ No newline at end of file diff --git a/pl_build/backend_win32.py b/pl_build/backend_win32.py new file mode 100644 index 0000000..00bf4b4 --- /dev/null +++ b/pl_build/backend_win32.py @@ -0,0 +1,454 @@ +import pl_build.core as pl + +class plWin32Helper: + + def __init__(self): + self.buffer = '\n' + self.indent = 0 + + def set_indent(self, indent): + self.indent = indent + + def write_file(self, file_path): + with open(file_path, "w") as file: + file.write(self.buffer) + + def add_line(self, line): + self.buffer += ' ' * self.indent + line + '\n' + + def add_raw(self, text): + self.buffer += text + + def add_label(self, label): + self.buffer += ':' + label + '\n' + + def add_spacing(self, count = 1): + self.buffer += '\n' * count + + def add_title(self, title): + line_length = 80 + padding = (line_length - 2 - len(title)) / 2 + self.buffer += ":: " + "#" * line_length + "\n" + self.buffer += ":: #" + " " * int(padding) + title + " " * int(padding + 0.5) + "#" + "\n" + self.buffer += (":: " + "#" * line_length) + "\n" + + def add_sub_title(self, title): + line_length = 80 + padding = (line_length - 2 - len(title)) / 2 + self.buffer += "::" + "~" * int(padding) + " " + title + " " + "~" * int(padding + 0.5) + "\n" + + def add_comment(self, comment): + self.buffer += ' ' * self.indent + ':: ' + comment + '\n' + + def print_line(self, text): + self.buffer += ' ' * self.indent + '@echo ' + text + '\n' + + def print_space(self): + self.buffer += '@echo.\n' + + def create_directory(self, directory): + self.buffer += ' ' * self.indent + '@if not exist "' + directory + '" @mkdir "' + directory + '"\n\n' + + def delete_file(self, file): + self.buffer += ' ' * self.indent + '@if exist "' + file + '"' + self.buffer += ' del "' + file + '"\n' + +def generate_build(name, user_options = None): + + platform = "Windows" + compiler = "msvc" + + data = pl.get_script_data() + + # retrieve settings supported by this platform/compiler & add + # default extensions if the user did not + platform_settings = [] + for settings in data.current_settings: + if settings.platform_name == platform and settings.name == compiler: + if settings.output_binary_extension is None: + if settings.target_type == pl.TargetType.EXECUTABLE: + settings.output_binary_extension = ".exe" + elif settings.target_type == pl.TargetType.DYNAMIC_LIBRARY: + settings.output_binary_extension = ".dll" + elif settings.target_type == pl.TargetType.STATIC_LIBRARY: + settings.output_binary_extension = ".lib" + platform_settings.append(settings) + + + helper = plWin32Helper() + + hot_reload = False + + ############################################################################### + # Intro # + ############################################################################### + + helper.add_comment("Project: " + data.project_name) + helper.add_comment("Auto Generated by:") + helper.add_comment('"pl_build.py" version: ' + data.version) + helper.add_spacing() + helper.add_comment("Project: " + data.project_name) + helper.add_spacing() + + helper.add_title("Development Setup") + helper.add_spacing() + + helper.add_comment('keep environment variables modifications local') + helper.add_line("@setlocal") + helper.add_spacing() + + helper.add_comment("make script directory CWD") + helper.add_line('@pushd %~dp0') + helper.add_line('@set dir=%~dp0') + helper.add_spacing() + + # try to setup dev environment + if isinstance(user_options, dict): + if "dev env setup" in user_options: + if user_options["dev env setup"] == True: + helper.add_comment("modify PATH to find vcvarsall.bat") + helper.add_line('@set PATH=C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Auxiliary\\Build;%PATH%') + helper.add_line('@set PATH=C:\\Program Files\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build;%PATH%') + helper.add_line('@set PATH=C:\\Program Files (x86)\\Microsoft Visual Studio\\2022\\Community\\VC\\Auxiliary\\Build;%PATH%') + helper.add_line('@set PATH=C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build;%PATH%') + helper.add_line('@set PATH=C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise/VC\\Auxiliary\\Build;%PATH%') + helper.add_spacing() + + helper.add_comment("setup environment for MSVC dev tools") + helper.add_line('@call vcvarsall.bat amd64 > nul') + helper.add_spacing() + + helper.add_comment("default compilation result") + helper.add_line('@set PL_RESULT=Successful.') + helper.add_spacing() + + # set default config + if data.registered_configurations: + helper.add_comment("default configuration") + helper.add_line("@set PL_CONFIG=" + data.registered_configurations[0]) + helper.add_spacing() + + # check command line args for config + helper.add_comment("check command line args for configuration") + helper.add_label("CheckConfiguration") + helper.add_line('@if "%~1"=="-c" (@set PL_CONFIG=%2) & @shift & @shift & @goto CheckConfiguration') + for register_config in data.registered_configurations: + helper.add_line('@if "%PL_CONFIG%" equ "' + register_config + '" ( goto ' + register_config + ' )') + helper.add_spacing() + + # if _context.pre_build_step is not None: + # helper.add_line(_context.pre_build_step) + # helper.add_spacing() + + + + for register_config in data.registered_configurations: + + # filter this config only settings + config_only_settings = [] + for settings in platform_settings: + if settings.config_name == register_config: + config_only_settings.append(settings) + + if len(config_only_settings) == 0: + continue + + # find hot reload target + if data.reload_target_name is not None: + hot_reload = True + + helper.add_title("configuration | " + register_config) + helper.add_spacing() + helper.add_label(register_config) + helper.add_spacing() + + output_dirs = set() + for settings in config_only_settings: + output_dirs.add(settings.output_directory) + + # create output directories + helper.add_comment("create output directories") + for dir in output_dirs: + helper.create_directory(dir) + + lock_files = set() + for settings in config_only_settings: + lock_files.add(settings.lock_file) + helper.add_comment("create lock file(s)") + for lock_file in lock_files: + helper.add_line('@echo LOCKING > "' + settings.output_directory + '/' + lock_file + '"') + + helper.add_spacing() + + if hot_reload: + + helper.add_comment("check if this is a hot reload") + helper.add_line("@set PL_HOT_RELOAD_STATUS=0") + + helper.add_spacing() + helper.add_comment("hack to see if " + data.reload_target_name + " exe is running") + helper.add_line("@echo off") + helper.add_line('2>nul (>>"' + data.reload_target_name + '.exe" echo off) && (@set PL_HOT_RELOAD_STATUS=0) || (@set PL_HOT_RELOAD_STATUS=1)') + + helper.add_spacing() + helper.add_comment("let user know if hot reloading") + helper.add_line("@if %PL_HOT_RELOAD_STATUS% equ 1 (") + helper.set_indent(4) + helper.print_line("-------- HOT RELOADING --------") + helper.set_indent(0) + helper.add_line(")") + helper.set_indent(0) + helper.add_spacing() + helper.add_comment("cleanup binaries if not hot reloading") + helper.add_line("@if %PL_HOT_RELOAD_STATUS% equ 0 (\n") + helper.set_indent(4) + + # delete old binaries & files + for settings in config_only_settings: + if settings.source_files: + helper.delete_file(settings.output_directory + '/' + settings.output_binary + settings.output_binary_extension) + if settings.target_type == pl.TargetType.DYNAMIC_LIBRARY: + helper.delete_file(settings.output_directory + '/' + settings.output_binary + '_*' + settings.output_binary_extension) + helper.delete_file(settings.output_directory + '/' + settings.output_binary + '_*.pdb') + elif settings.target_type == pl.TargetType.EXECUTABLE: + helper.delete_file(settings.output_directory + '/' + settings.output_binary + '_*.pdb') + + helper.set_indent(0) + if hot_reload: + helper.add_spacing() + helper.add_line(")") + helper.add_spacing() + + # other targets + for settings in config_only_settings: + helper.add_sub_title(settings.target_name + " | " + register_config) + helper.add_spacing() + + if not settings.reloadable and hot_reload: + helper.add_comment("skip during hot reload") + helper.add_line('@if %PL_HOT_RELOAD_STATUS% equ 1 goto ' + "Exit_" + settings.target_name) + helper.add_spacing() + + if settings.pre_build_step is not None: + helper.add_line(settings.pre_build_step) + helper.add_spacing() + + if settings.definitions: + helper.add_raw('@set PL_DEFINES=') + for define in settings.definitions: + helper.add_raw("-D" + define + " ") + helper.add_spacing() + + if settings.include_directories: + helper.add_raw('@set PL_INCLUDE_DIRECTORIES=') + for include in settings.include_directories: + helper.add_raw('-I"' + include + '" ') + helper.add_spacing() + + if settings.link_directories: + helper.add_raw('@set PL_LINK_DIRECTORIES=') + for link in settings.link_directories: + helper.add_raw('-LIBPATH:"' + link + '" ') + helper.add_spacing() + + if settings.compiler_flags: + helper.add_raw('@set PL_COMPILER_FLAGS=') + for flag in settings.compiler_flags: + helper.add_raw(flag + " ") + helper.add_spacing() + + settings.linker_flags.extend(["-incremental:no"]) + if settings.target_type == pl.TargetType.DYNAMIC_LIBRARY: + settings.linker_flags.extend(["-noimplib", "-noexp"]) + + if settings.linker_flags: + helper.add_raw('@set PL_LINKER_FLAGS=') + for flag in settings.linker_flags: + helper.add_raw(flag + " ") + helper.add_spacing() + + if settings.static_link_libraries: + helper.add_raw('@set PL_STATIC_LINK_LIBRARIES=') + for link in settings.static_link_libraries: + helper.add_raw(link + ".lib ") + helper.add_spacing() + + if settings.dynamic_link_libraries: + helper.add_raw('@set PL_DYNAMIC_LINK_LIBRARIES=') + for link in settings.dynamic_link_libraries: + helper.add_raw(link + ".lib ") + helper.add_spacing() + + if settings.target_type == pl.TargetType.STATIC_LIBRARY: + + helper.add_spacing() + helper.add_comment("run compiler only") + helper.print_space() + helper.print_line("Step: " + settings.target_name +"") + helper.print_line("~~~~~~~~~~~~~~~~~~~~~~") + helper.print_line("Compiling...") + + helper.add_spacing() + helper.add_comment('each file must be compiled separately') + for source in settings.source_files: + sub_buffer = "" + if settings.include_directories: + sub_buffer += " %PL_INCLUDE_DIRECTORIES%" + if settings.definitions: + sub_buffer += " %PL_DEFINES%" + if settings.compiler_flags: + sub_buffer += " %PL_COMPILER_FLAGS%" + helper.add_line('cl -c' + sub_buffer + " " + source + ' -Fo"' + settings.output_directory + '/"') + helper.add_spacing() + + helper.add_spacing() + helper.add_comment("check build status") + helper.add_line("@set PL_BUILD_STATUS=%ERRORLEVEL%") + + helper.add_spacing() + helper.add_comment("if failed, skip linking") + helper.add_raw("@if %PL_BUILD_STATUS% NEQ 0 (\n") + helper.add_raw(" @echo Compilation Failed with error code: %PL_BUILD_STATUS%\n") + helper.add_raw(" @set PL_RESULT=Failed.\n") + helper.add_raw(" goto " + 'Cleanup' + register_config) + helper.add_raw("\n)\n") + + helper.add_spacing() + helper.add_comment('link object files into a shared lib') + helper.add_raw("@echo Linking...\n") + helper.add_raw('lib -nologo -OUT:"' + settings.output_directory + '/' + settings.output_binary + settings.output_binary_extension + '" "' + settings.output_directory + '/*.obj"\n') + + elif settings.target_type == pl.TargetType.DYNAMIC_LIBRARY: + + helper.add_raw('@set PL_SOURCES=') + for source in settings.source_files: + helper.add_raw('"' + source + '" ') + helper.add_spacing() + + sub_buffer0 = "" + sub_buffer1 = "" + sub_buffer2 = "" + if settings.include_directories: + sub_buffer0 += " %PL_INCLUDE_DIRECTORIES%" + if settings.definitions: + sub_buffer0 += " %PL_DEFINES%" + if settings.compiler_flags: + sub_buffer0 += " %PL_COMPILER_FLAGS%" + if settings.linker_flags: + sub_buffer1 = " %PL_LINKER_FLAGS%" + if settings.link_directories: + sub_buffer2 += " %PL_LINK_DIRECTORIES%" + if settings.static_link_libraries: + sub_buffer2 += " %PL_STATIC_LINK_LIBRARIES%" + if settings.dynamic_link_libraries: + sub_buffer2 += " %PL_DYNAMIC_LINK_LIBRARIES%" + + helper.add_spacing() + helper.add_comment("run compiler (and linker)") + helper.print_space() + helper.add_raw('@echo Step: ' + settings.target_name +'\n') + helper.add_raw('@echo ~~~~~~~~~~~~~~~~~~~~~~\n') + helper.add_raw('@echo Compiling and Linking...\n') + helper.add_raw('cl' + sub_buffer0 + ' %PL_SOURCES% -Fe"' + settings.output_directory + '/' + settings.output_binary + settings.output_binary_extension + '" -Fo"' + settings.output_directory + '/" -LD -link' + sub_buffer1 + ' -PDB:"' + settings.output_directory + '/' + settings.output_binary + '_%random%.pdb"' + sub_buffer2 + "\n\n") + + helper.add_comment("check build status") + helper.add_raw("@set PL_BUILD_STATUS=%ERRORLEVEL%\n") + + helper.add_raw("\n:: failed\n") + helper.add_raw("@if %PL_BUILD_STATUS% NEQ 0 (\n") + helper.add_raw(" @echo Compilation Failed with error code: %PL_BUILD_STATUS%\n") + helper.add_raw(" @set PL_RESULT=Failed.\n") + helper.add_raw(" goto " + 'Cleanup' + register_config) + helper.add_raw("\n)\n") + + elif settings.target_type == pl.TargetType.EXECUTABLE: + + helper.add_raw('@set PL_SOURCES=') + for source in settings.source_files: + helper.add_raw('"' + source + '" ') + helper.add_spacing(2) + + sub_buffer0 = "" + sub_buffer1 = "" + sub_buffer2 = "" + if settings.include_directories: + sub_buffer0 += " %PL_INCLUDE_DIRECTORIES%" + if settings.definitions: + sub_buffer0 += " %PL_DEFINES%" + if settings.compiler_flags: + sub_buffer0 += " %PL_COMPILER_FLAGS%" + if settings.linker_flags: + sub_buffer1 = " %PL_LINKER_FLAGS%" + if settings.link_directories: + sub_buffer2 += " %PL_LINK_DIRECTORIES%" + if settings.static_link_libraries: + sub_buffer2 += " %PL_STATIC_LINK_LIBRARIES%" + if settings.dynamic_link_libraries: + sub_buffer2 += " %PL_DYNAMIC_LINK_LIBRARIES%" + + helper.add_comment("run compiler (and linker)") + helper.print_space() + helper.print_line('Step: ' + settings.target_name +'') + helper.print_line('~~~~~~~~~~~~~~~~~~~~~~') + helper.print_line('Compiling and Linking...') + + + if hot_reload: + helper.add_raw('\n:: skip actual compilation if hot reloading\n') + helper.add_raw('@if %PL_HOT_RELOAD_STATUS% equ 1 ( goto ' + 'Cleanup' + settings.target_name + ' )\n') + + helper.add_raw('\n:: call compiler\n') + helper.add_raw('cl' + sub_buffer0 + ' %PL_SOURCES% -Fe"' + settings.output_directory + '/' + settings.output_binary + settings.output_binary_extension + '" -Fo"' + settings.output_directory + '/" -link' + sub_buffer1 + ' -PDB:"' + settings.output_directory + '/' + settings.output_binary + '_%random%.pdb"' + sub_buffer2 + "\n\n") + + helper.add_comment("check build status") + helper.add_raw("@set PL_BUILD_STATUS=%ERRORLEVEL%\n") + helper.add_raw("\n:: failed\n") + helper.add_raw("@if %PL_BUILD_STATUS% NEQ 0 (\n") + helper.add_raw(" @echo Compilation Failed with error code: %PL_BUILD_STATUS%\n") + helper.add_raw(" @set PL_RESULT=Failed.\n") + helper.add_raw(" goto " + 'Cleanup' + register_config) + helper.add_raw("\n)\n") + + helper.add_spacing() + + helper.add_comment("print results") + helper.print_line("Result:  %PL_RESULT%") + helper.add_raw("@echo ~~~~~~~~~~~~~~~~~~~~~~\n") + helper.add_spacing() + + if settings.post_build_step is not None: + helper.add_line(settings.post_build_step) + helper.add_spacing() + + if not settings.reloadable: + helper.add_label("Exit_" + settings.target_name) + helper.add_spacing() + + helper.add_line(':Cleanup' + register_config) + helper.add_spacing() + helper.print_line('Cleaning...') + + helper.add_spacing() + helper.add_comment("delete obj files(s)") + for dir in output_dirs: + helper.add_line('@del "' + dir + '/*.obj" > nul 2> nul') + + helper.add_spacing() + helper.add_comment("delete lock file(s)") + for lock_file in lock_files: + helper.delete_file(settings.output_directory + '/' + lock_file) + + helper.add_spacing() + helper.add_comment('~' * 40) + helper.add_comment('end of ' + settings.config_name + ' configuration') + helper.add_line("goto ExitLabel") + helper.add_spacing() + + helper.add_label("ExitLabel") + helper.add_spacing() + # if _context.post_build_step is not None: + # helper.add_line(_context.post_build_step) + # helper.add_spacing() + helper.add_comment("return CWD to previous CWD") + helper.add_line('@popd') + helper.write_file(name) \ No newline at end of file diff --git a/pl_build/core.py b/pl_build/core.py new file mode 100644 index 0000000..2b87615 --- /dev/null +++ b/pl_build/core.py @@ -0,0 +1,800 @@ +# core.py + +# Index of this file: +# [SECTION] version +# [SECTION] imports +# [SECTION] enums +# [SECTION] public classes +# [SECTION] private classes +# [SECTION] global context +# [SECTION] context managers +# [SECTION] public api + +#----------------------------------------------------------------------------- +# [SECTION] version +#----------------------------------------------------------------------------- + +__version__ = "1.0.1" + +#----------------------------------------------------------------------------- +# [SECTION] imports +#----------------------------------------------------------------------------- + +from enum import Enum +from contextlib import contextmanager + +#----------------------------------------------------------------------------- +# [SECTION] enums +#----------------------------------------------------------------------------- + +class TargetType(Enum): + NONE = 0 + STATIC_LIBRARY = 0 + DYNAMIC_LIBRARY = 1 + EXECUTABLE = 2 + +#----------------------------------------------------------------------------- +# [SECTION] public 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 + +class ScriptData: + + def __init__(self): + self.version = __version__ + self.current_settings = [] + self.project_name = None + self.reload_target_name = None + self.registered_configurations = [] + +class BuildContext: + + def __init__(self): + + self._script_data = ScriptData() + + # current profiles + self._profiles = [] + + # current target information + self._target_name = None + self._target_type = None + self._target_lock_file = None + self._target_reloadable = False + + # current platform + self._platform_name = None + + # current 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_name = None + 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 = [] + +#----------------------------------------------------------------------------- +# [SECTION] private classes +#----------------------------------------------------------------------------- + +class _CompilerProfile: + + def __init__(self): + + self.compilers = None + self.platforms = None + self.configurations = None + self.targets = None + + 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 + +#----------------------------------------------------------------------------- +# [SECTION] global context +#----------------------------------------------------------------------------- + +_context = BuildContext() + +#----------------------------------------------------------------------------- +# [SECTION] context managers +#----------------------------------------------------------------------------- + +@contextmanager +def project(name: str): + try: + # persistent data + _context._script_data = ScriptData() + _context._script_data.project_name = name + + # current profiles + _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 + +@contextmanager +def target(name: str, target_type: TargetType = TargetType.EXECUTABLE, 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 = [] + +@contextmanager +def configuration(name: str): + try: + _context._config_name = name + + # register configurations if not already + exists = False + + for config in _context._script_data.registered_configurations: + + if config == name: + exists = True + break + + if not exists: + _context._script_data.registered_configurations.append(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 = [] + +@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 = [] + +@contextmanager +def compiler(name: str): + try: + compiler = CompilerSettings(name) + + # inherited from platform + compiler.platform_name = _context._platform_name + + # inherited from configuration + 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 various scopes + 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 + + # this is set here since profile.is_active() looks at it + _context._working_settings = compiler + + # inherited from matching 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._script_data.current_settings.append(_context._working_settings) + _context._working_settings = None + +#----------------------------------------------------------------------------- +# [SECTION] public api +#----------------------------------------------------------------------------- + +def set_hot_reload_target(target_name: str): + _context._script_data.reload_target_name = target_name + +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._script_data.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._script_data.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._script_data.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._script_data.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._script_data.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._script_data.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._script_data.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._script_data.project_name is not None: + _context._project_output_directory = directory + else: + raise Exception("'set_output_directory(...)' must be called within a scope") + +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 + +def add_compiler_flags_profile(*args, **kwargs): + + profile = _CompilerProfile() + + if "targets" in kwargs: + profile.targets = kwargs["targets"] + + if "configurations" in kwargs: + profile.configurations = kwargs["configurations"] + + if "compilers" in kwargs: + profile.compilers = kwargs["compilers"] + + if "platforms" in kwargs: + profile.platforms = kwargs["platforms"] + + profile.compiler_flags = args + _context._profiles.append(profile) + +def add_include_directories_profile(*args, **kwargs): + + profile = _CompilerProfile() + + if "targets" in kwargs: + profile.targets = kwargs["targets"] + + if "configurations" in kwargs: + profile.configurations = kwargs["configurations"] + + if "compilers" in kwargs: + profile.compilers = kwargs["compilers"] + + if "platforms" in kwargs: + profile.platforms = kwargs["platforms"] + + profile.include_directories = args + _context._profiles.append(profile) + +def add_definitions_profile(*args, **kwargs): + + profile = _CompilerProfile() + + if "targets" in kwargs: + profile.targets = kwargs["targets"] + + if "configurations" in kwargs: + profile.configurations = kwargs["configurations"] + + if "compilers" in kwargs: + profile.compilers = kwargs["compilers"] + + if "platforms" in kwargs: + profile.platforms = kwargs["platforms"] + + profile.definitions = args + _context._profiles.append(profile) + +def add_link_directories_profile(*args, **kwargs): + + profile = _CompilerProfile() + + if "targets" in kwargs: + profile.targets = kwargs["targets"] + + if "configurations" in kwargs: + profile.configurations = kwargs["configurations"] + + if "compilers" in kwargs: + profile.compilers = kwargs["compilers"] + + if "platforms" in kwargs: + profile.platforms = kwargs["platforms"] + + profile.link_directories = args + _context._profiles.append(profile) + +def add_static_link_libraries_profile(*args, **kwargs): + + profile = _CompilerProfile() + + if "targets" in kwargs: + profile.targets = kwargs["targets"] + + if "configurations" in kwargs: + profile.configurations = kwargs["configurations"] + + if "compilers" in kwargs: + profile.compilers = kwargs["compilers"] + + if "platforms" in kwargs: + profile.platforms = kwargs["platforms"] + + profile.static_link_libraries = args + _context._profiles.append(profile) + +def add_dynamic_link_libraries_profile(*args, **kwargs): + + profile = _CompilerProfile() + + if "targets" in kwargs: + profile.targets = kwargs["targets"] + + if "configurations" in kwargs: + profile.configurations = kwargs["configurations"] + + if "compilers" in kwargs: + profile.compilers = kwargs["compilers"] + + if "platforms" in kwargs: + profile.platforms = kwargs["platforms"] + + profile.dynamic_link_libraries = args + _context._profiles.append(profile) + +def add_link_frameworks_profile(*args, **kwargs): + + profile = _CompilerProfile() + + if "targets" in kwargs: + profile.targets = kwargs["targets"] + + if "configurations" in kwargs: + profile.configurations = kwargs["configurations"] + + if "compilers" in kwargs: + profile.compilers = kwargs["compilers"] + + if "platforms" in kwargs: + profile.platforms = kwargs["platforms"] + + profile.link_frameworks = args + _context._profiles.append(profile) + +def add_source_files_profile(*args, **kwargs): + + profile = _CompilerProfile() + + if "targets" in kwargs: + profile.targets = kwargs["targets"] + + if "configurations" in kwargs: + profile.configurations = kwargs["configurations"] + + if "compilers" in kwargs: + profile.compilers = kwargs["compilers"] + + if "platforms" in kwargs: + profile.platforms = kwargs["platforms"] + + profile.source_files = args + _context._profiles.append(profile) + +def add_linker_flags_profile(*args, **kwargs): + + profile = _CompilerProfile() + + if "targets" in kwargs: + profile.targets = kwargs["targets"] + + if "configurations" in kwargs: + profile.configurations = kwargs["configurations"] + + if "compilers" in kwargs: + profile.compilers = kwargs["compilers"] + + if "platforms" in kwargs: + profile.platforms = kwargs["platforms"] + + profile.linker_flags = args + _context._profiles.append(profile) + +def set_output_binary_extension_profile(extension: str, **kwargs): + + profile = _CompilerProfile() + + if "targets" in kwargs: + profile.targets = kwargs["targets"] + + if "configurations" in kwargs: + profile.configurations = kwargs["configurations"] + + if "compilers" in kwargs: + profile.compilers = kwargs["compilers"] + + if "platforms" in kwargs: + profile.platforms = kwargs["platforms"] + + profile.output_binary_extension = extension + _context._profiles.append(profile) + +def set_output_directory_profile(directory: str, **kwargs): + + profile = _CompilerProfile() + + if "targets" in kwargs: + profile.targets = kwargs["targets"] + + if "configurations" in kwargs: + profile.configurations = kwargs["configurations"] + + if "compilers" in kwargs: + profile.compilers = kwargs["compilers"] + + if "platforms" in kwargs: + profile.platforms = kwargs["platforms"] + + profile.output_directory = directory + _context._profiles.append(profile) + +def get_script_data() -> ScriptData: + return _context._script_data \ No newline at end of file diff --git a/pl_build/pl_build.py b/pl_build/pl_build.py deleted file mode 100644 index 2029f63..0000000 --- a/pl_build/pl_build.py +++ /dev/null @@ -1,666 +0,0 @@ -__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 diff --git a/pl_build/pl_build_win32.py b/pl_build/pl_build_win32.py deleted file mode 100644 index 65be0d9..0000000 --- a/pl_build/pl_build_win32.py +++ /dev/null @@ -1,449 +0,0 @@ -import pl_build as pl -from pl_build import _context, __version__ - -class plWin32Helper: - - def __init__(self): - self.buffer = '\n' - self.indent = 0 - - def set_indent(self, indent): - self.indent = indent - - def write_file(self, file_path): - with open(file_path, "w") as file: - file.write(self.buffer) - - def add_line(self, line): - self.buffer += ' ' * self.indent + line + '\n' - - def add_raw(self, text): - self.buffer += text - - def add_label(self, label): - self.buffer += ':' + label + '\n' - - def add_spacing(self, count = 1): - self.buffer += '\n' * count - - def add_title(self, title): - line_length = 80 - padding = (line_length - 2 - len(title)) / 2 - self.buffer += ":: " + "#" * line_length + "\n" - self.buffer += ":: #" + " " * int(padding) + title + " " * int(padding + 0.5) + "#" + "\n" - self.buffer += (":: " + "#" * line_length) + "\n" - - def add_sub_title(self, title): - line_length = 80 - padding = (line_length - 2 - len(title)) / 2 - self.buffer += "::" + "~" * int(padding) + " " + title + " " + "~" * int(padding + 0.5) + "\n" - - def add_comment(self, comment): - self.buffer += ' ' * self.indent + ':: ' + comment + '\n' - - def print_line(self, text): - self.buffer += ' ' * self.indent + '@echo ' + text + '\n' - - def print_space(self): - self.buffer += '@echo.\n' - - def create_directory(self, directory): - self.buffer += ' ' * self.indent + '@if not exist "' + directory + '" @mkdir "' + directory + '"\n\n' - - def delete_file(self, file): - self.buffer += ' ' * self.indent + '@if exist "' + file + '"' - self.buffer += ' del "' + file + '"\n' - -def generate_build(name, platform, compiler, user_options): - - helper = plWin32Helper() - - hot_reload = False - - ############################################################################### - # Intro # - ############################################################################### - - helper.add_comment("Project: " + _context.project_name) - helper.add_comment("Auto Generated by:") - helper.add_comment('"pl_build.py" version: ' + __version__) - helper.add_spacing() - helper.add_comment("Project: " + _context.project_name) - helper.add_spacing() - - helper.add_title("Development Setup") - helper.add_spacing() - - helper.add_comment('keep environment variables modifications local') - helper.add_line("@setlocal") - helper.add_spacing() - - helper.add_comment("make script directory CWD") - helper.add_line('@pushd %~dp0') - helper.add_line('@set dir=%~dp0') - helper.add_spacing() - - # try to setup dev environment - if isinstance(user_options, dict): - if "dev env setup" in user_options: - if user_options["dev env setup"] == True: - helper.add_comment("modify PATH to find vcvarsall.bat") - helper.add_line('@set PATH=C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Auxiliary\\Build;%PATH%') - helper.add_line('@set PATH=C:\\Program Files\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build;%PATH%') - helper.add_line('@set PATH=C:\\Program Files (x86)\\Microsoft Visual Studio\\2022\\Community\\VC\\Auxiliary\\Build;%PATH%') - helper.add_line('@set PATH=C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build;%PATH%') - helper.add_line('@set PATH=C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise/VC\\Auxiliary\\Build;%PATH%') - helper.add_spacing() - - helper.add_comment("setup environment for MSVC dev tools") - helper.add_line('@call vcvarsall.bat amd64 > nul') - helper.add_spacing() - - helper.add_comment("default compilation result") - helper.add_line('@set PL_RESULT=Successful.') - helper.add_spacing() - - # set default config - if _context.registered_configurations: - helper.add_comment("default configuration") - helper.add_line("@set PL_CONFIG=" + _context.registered_configurations[0]) - helper.add_spacing() - - # check command line args for config - helper.add_comment("check command line args for configuration") - helper.add_label("CheckConfiguration") - helper.add_line('@if "%~1"=="-c" (@set PL_CONFIG=%2) & @shift & @shift & @goto CheckConfiguration') - for register_config in _context.registered_configurations: - helper.add_line('@if "%PL_CONFIG%" equ "' + register_config + '" ( goto ' + register_config + ' )') - helper.add_spacing() - - # if _context.pre_build_step is not None: - # helper.add_line(_context.pre_build_step) - # helper.add_spacing() - - # filter win32 only settings & apply defaults - platform_settings = [] - for settings in _context.current_settings: - if settings.platform_name == platform: - if settings.output_binary_extension is None: - if settings.target_type == pl.TargetType.EXECUTABLE: - settings.output_binary_extension = ".exe" - elif settings.target_type == pl.TargetType.DYNAMIC_LIBRARY: - settings.output_binary_extension = ".dll" - elif settings.target_type == pl.TargetType.STATIC_LIBRARY: - settings.output_binary_extension = ".lib" - platform_settings.append(settings) - - for register_config in _context.registered_configurations: - - # filter this config only settings - config_only_settings = [] - for settings in platform_settings: - if settings.config_name == register_config: - config_only_settings.append(settings) - - if len(config_only_settings) == 0: - continue - - # find hot reload target - if _context.reload_target_name is not None: - hot_reload = True - - helper.add_title("configuration | " + register_config) - helper.add_spacing() - helper.add_label(register_config) - helper.add_spacing() - - output_dirs = set() - for settings in config_only_settings: - output_dirs.add(settings.output_directory) - - # create output directories - helper.add_comment("create output directories") - for dir in output_dirs: - helper.create_directory(dir) - - lock_files = set() - for settings in config_only_settings: - lock_files.add(settings.lock_file) - helper.add_comment("create lock file(s)") - for lock_file in lock_files: - helper.add_line('@echo LOCKING > "' + settings.output_directory + '/' + lock_file + '"') - - helper.add_spacing() - - if hot_reload: - - helper.add_comment("check if this is a hot reload") - helper.add_line("@set PL_HOT_RELOAD_STATUS=0") - - helper.add_spacing() - helper.add_comment("hack to see if " + _context.reload_target_name + " exe is running") - helper.add_line("@echo off") - helper.add_line('2>nul (>>"' + _context.reload_target_name + '.exe" echo off) && (@set PL_HOT_RELOAD_STATUS=0) || (@set PL_HOT_RELOAD_STATUS=1)') - - helper.add_spacing() - helper.add_comment("let user know if hot reloading") - helper.add_line("@if %PL_HOT_RELOAD_STATUS% equ 1 (") - helper.set_indent(4) - helper.print_line("-------- HOT RELOADING --------") - helper.set_indent(0) - helper.add_line(")") - helper.set_indent(0) - helper.add_spacing() - helper.add_comment("cleanup binaries if not hot reloading") - helper.add_line("@if %PL_HOT_RELOAD_STATUS% equ 0 (\n") - helper.set_indent(4) - - # delete old binaries & files - for settings in config_only_settings: - if settings.source_files: - if settings.name == compiler: - helper.delete_file(settings.output_directory + '/' + settings.output_binary + settings.output_binary_extension) - if settings.target_type == pl.TargetType.DYNAMIC_LIBRARY: - helper.delete_file(settings.output_directory + '/' + settings.output_binary + '_*' + settings.output_binary_extension) - helper.delete_file(settings.output_directory + '/' + settings.output_binary + '_*.pdb') - elif settings.target_type == pl.TargetType.EXECUTABLE: - helper.delete_file(settings.output_directory + '/' + settings.output_binary + '_*.pdb') - - helper.set_indent(0) - if hot_reload: - helper.add_spacing() - helper.add_line(")") - helper.add_spacing() - - # other targets - for settings in config_only_settings: - helper.add_sub_title(settings.target_name + " | " + register_config) - helper.add_spacing() - - if settings.name == compiler: - - if not settings.reloadable and hot_reload: - helper.add_comment("skip during hot reload") - helper.add_line('@if %PL_HOT_RELOAD_STATUS% equ 1 goto ' + "Exit_" + settings.target_name) - helper.add_spacing() - - if settings.pre_build_step is not None: - helper.add_line(settings.pre_build_step) - helper.add_spacing() - - if settings.definitions: - helper.add_raw('@set PL_DEFINES=') - for define in settings.definitions: - helper.add_raw("-D" + define + " ") - helper.add_spacing() - - if settings.include_directories: - helper.add_raw('@set PL_INCLUDE_DIRECTORIES=') - for include in settings.include_directories: - helper.add_raw('-I"' + include + '" ') - helper.add_spacing() - - if settings.link_directories: - helper.add_raw('@set PL_LINK_DIRECTORIES=') - for link in settings.link_directories: - helper.add_raw('-LIBPATH:"' + link + '" ') - helper.add_spacing() - - if settings.compiler_flags: - helper.add_raw('@set PL_COMPILER_FLAGS=') - for flag in settings.compiler_flags: - helper.add_raw(flag + " ") - helper.add_spacing() - - settings.linker_flags.extend(["-incremental:no"]) - if settings.target_type == pl.TargetType.DYNAMIC_LIBRARY: - settings.linker_flags.extend(["-noimplib", "-noexp"]) - - if settings.linker_flags: - helper.add_raw('@set PL_LINKER_FLAGS=') - for flag in settings.linker_flags: - helper.add_raw(flag + " ") - helper.add_spacing() - - if settings.static_link_libraries: - helper.add_raw('@set PL_STATIC_LINK_LIBRARIES=') - for link in settings.static_link_libraries: - helper.add_raw(link + ".lib ") - helper.add_spacing() - - if settings.dynamic_link_libraries: - helper.add_raw('@set PL_DYNAMIC_LINK_LIBRARIES=') - for link in settings.dynamic_link_libraries: - helper.add_raw(link + ".lib ") - helper.add_spacing() - - if settings.target_type == pl.TargetType.STATIC_LIBRARY: - - helper.add_spacing() - helper.add_comment("run compiler only") - helper.print_space() - helper.print_line("Step: " + settings.target_name +"") - helper.print_line("~~~~~~~~~~~~~~~~~~~~~~") - helper.print_line("Compiling...") - - helper.add_spacing() - helper.add_comment('each file must be compiled separately') - for source in settings.source_files: - sub_buffer = "" - if settings.include_directories: - sub_buffer += " %PL_INCLUDE_DIRECTORIES%" - if settings.definitions: - sub_buffer += " %PL_DEFINES%" - if settings.compiler_flags: - sub_buffer += " %PL_COMPILER_FLAGS%" - helper.add_line('cl -c' + sub_buffer + " " + source + ' -Fo"' + settings.output_directory + '/"') - helper.add_spacing() - - helper.add_spacing() - helper.add_comment("check build status") - helper.add_line("@set PL_BUILD_STATUS=%ERRORLEVEL%") - - helper.add_spacing() - helper.add_comment("if failed, skip linking") - helper.add_raw("@if %PL_BUILD_STATUS% NEQ 0 (\n") - helper.add_raw(" @echo Compilation Failed with error code: %PL_BUILD_STATUS%\n") - helper.add_raw(" @set PL_RESULT=Failed.\n") - helper.add_raw(" goto " + 'Cleanup' + register_config) - helper.add_raw("\n)\n") - - helper.add_spacing() - helper.add_comment('link object files into a shared lib') - helper.add_raw("@echo Linking...\n") - helper.add_raw('lib -nologo -OUT:"' + settings.output_directory + '/' + settings.output_binary + settings.output_binary_extension + '" "' + settings.output_directory + '/*.obj"\n') - - elif settings.target_type == pl.TargetType.DYNAMIC_LIBRARY: - - helper.add_raw('@set PL_SOURCES=') - for source in settings.source_files: - helper.add_raw('"' + source + '" ') - helper.add_spacing() - - sub_buffer0 = "" - sub_buffer1 = "" - sub_buffer2 = "" - if settings.include_directories: - sub_buffer0 += " %PL_INCLUDE_DIRECTORIES%" - if settings.definitions: - sub_buffer0 += " %PL_DEFINES%" - if settings.compiler_flags: - sub_buffer0 += " %PL_COMPILER_FLAGS%" - if settings.linker_flags: - sub_buffer1 = " %PL_LINKER_FLAGS%" - if settings.link_directories: - sub_buffer2 += " %PL_LINK_DIRECTORIES%" - if settings.static_link_libraries: - sub_buffer2 += " %PL_STATIC_LINK_LIBRARIES%" - if settings.dynamic_link_libraries: - sub_buffer2 += " %PL_DYNAMIC_LINK_LIBRARIES%" - - helper.add_spacing() - helper.add_comment("run compiler (and linker)") - helper.print_space() - helper.add_raw('@echo Step: ' + settings.target_name +'\n') - helper.add_raw('@echo ~~~~~~~~~~~~~~~~~~~~~~\n') - helper.add_raw('@echo Compiling and Linking...\n') - helper.add_raw('cl' + sub_buffer0 + ' %PL_SOURCES% -Fe"' + settings.output_directory + '/' + settings.output_binary + settings.output_binary_extension + '" -Fo"' + settings.output_directory + '/" -LD -link' + sub_buffer1 + ' -PDB:"' + settings.output_directory + '/' + settings.output_binary + '_%random%.pdb"' + sub_buffer2 + "\n\n") - - helper.add_comment("check build status") - helper.add_raw("@set PL_BUILD_STATUS=%ERRORLEVEL%\n") - - helper.add_raw("\n:: failed\n") - helper.add_raw("@if %PL_BUILD_STATUS% NEQ 0 (\n") - helper.add_raw(" @echo Compilation Failed with error code: %PL_BUILD_STATUS%\n") - helper.add_raw(" @set PL_RESULT=Failed.\n") - helper.add_raw(" goto " + 'Cleanup' + register_config) - helper.add_raw("\n)\n") - - elif settings.target_type == pl.TargetType.EXECUTABLE: - - helper.add_raw('@set PL_SOURCES=') - for source in settings.source_files: - helper.add_raw('"' + source + '" ') - helper.add_spacing(2) - - sub_buffer0 = "" - sub_buffer1 = "" - sub_buffer2 = "" - if settings.include_directories: - sub_buffer0 += " %PL_INCLUDE_DIRECTORIES%" - if settings.definitions: - sub_buffer0 += " %PL_DEFINES%" - if settings.compiler_flags: - sub_buffer0 += " %PL_COMPILER_FLAGS%" - if settings.linker_flags: - sub_buffer1 = " %PL_LINKER_FLAGS%" - if settings.link_directories: - sub_buffer2 += " %PL_LINK_DIRECTORIES%" - if settings.static_link_libraries: - sub_buffer2 += " %PL_STATIC_LINK_LIBRARIES%" - if settings.dynamic_link_libraries: - sub_buffer2 += " %PL_DYNAMIC_LINK_LIBRARIES%" - - helper.add_comment("run compiler (and linker)") - helper.print_space() - helper.print_line('Step: ' + settings.target_name +'') - helper.print_line('~~~~~~~~~~~~~~~~~~~~~~') - helper.print_line('Compiling and Linking...') - - - if hot_reload: - helper.add_raw('\n:: skip actual compilation if hot reloading\n') - helper.add_raw('@if %PL_HOT_RELOAD_STATUS% equ 1 ( goto ' + 'Cleanup' + settings.target_name + ' )\n') - - helper.add_raw('\n:: call compiler\n') - helper.add_raw('cl' + sub_buffer0 + ' %PL_SOURCES% -Fe"' + settings.output_directory + '/' + settings.output_binary + settings.output_binary_extension + '" -Fo"' + settings.output_directory + '/" -link' + sub_buffer1 + ' -PDB:"' + settings.output_directory + '/' + settings.output_binary + '_%random%.pdb"' + sub_buffer2 + "\n\n") - - helper.add_comment("check build status") - helper.add_raw("@set PL_BUILD_STATUS=%ERRORLEVEL%\n") - helper.add_raw("\n:: failed\n") - helper.add_raw("@if %PL_BUILD_STATUS% NEQ 0 (\n") - helper.add_raw(" @echo Compilation Failed with error code: %PL_BUILD_STATUS%\n") - helper.add_raw(" @set PL_RESULT=Failed.\n") - helper.add_raw(" goto " + 'Cleanup' + register_config) - helper.add_raw("\n)\n") - - helper.add_spacing() - - helper.add_comment("print results") - helper.print_line("Result:  %PL_RESULT%") - helper.add_raw("@echo ~~~~~~~~~~~~~~~~~~~~~~\n") - helper.add_spacing() - - if settings.post_build_step is not None: - helper.add_line(settings.post_build_step) - helper.add_spacing() - - if not settings.reloadable: - helper.add_label("Exit_" + settings.target_name) - helper.add_spacing() - - helper.add_line(':Cleanup' + register_config) - helper.add_spacing() - helper.print_line('Cleaning...') - - helper.add_spacing() - helper.add_comment("delete obj files(s)") - for dir in output_dirs: - helper.add_line('@del "' + dir + '/*.obj" > nul 2> nul') - - helper.add_spacing() - helper.add_comment("delete lock file(s)") - for lock_file in lock_files: - helper.delete_file(settings.output_directory + '/' + lock_file) - - helper.add_spacing() - helper.add_comment('~' * 40) - helper.add_comment('end of ' + settings.config_name + ' configuration') - helper.add_line("goto ExitLabel") - helper.add_spacing() - - helper.add_label("ExitLabel") - helper.add_spacing() - # if _context.post_build_step is not None: - # helper.add_line(_context.post_build_step) - # helper.add_spacing() - helper.add_comment("return CWD to previous CWD") - helper.add_line('@popd') - helper.write_file(_context.working_directory + "/" + name) \ No newline at end of file