From e356afe66dcd6ec9656c1b01a2e846fab1261f1f Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Wed, 8 Jan 2025 19:33:30 +0100 Subject: [PATCH] feat: compiling using msys2 and mingw Yes, it's not as pretty as msvc, but it's open source tooling :/. I think this satisfies the immediate need, and if there are further changes I think they might be patchable. --- src/meson.build | 47 +++++++-- src/winlog/convert_man_to_mc.py | 167 ++++++++++++++++++++++++++++++++ version.txt | 2 +- winscripts/gccsetup.ps1 | 71 ++++++++------ 4 files changed, 246 insertions(+), 41 deletions(-) create mode 100644 src/winlog/convert_man_to_mc.py diff --git a/src/meson.build b/src/meson.build index f35c32152..827e52340 100644 --- a/src/meson.build +++ b/src/meson.build @@ -124,19 +124,49 @@ if host_machine.system() == 'windows' # pistachelog.dll # mc.exe and rc.exe being utilities provided by Windows - mc_prog = find_program('mc.exe') if compiler.get_id() == 'gcc' rc_prog = find_program('windres.exe') else rc_prog = find_program('rc.exe') endif - gen_src_log_rc_ct = custom_target( - 'gen-log-rc', - input: ['winlog'/'pist_winlog.man'], - output: ['pist_winlog.rc', 'pist_winlog.h'], - command: [mc_prog, '-um', '-h', '@OUTDIR@', '-r', '@OUTDIR@', '@INPUT@'] - ) + mc_prog = find_program('mc', required: false) + if mc_prog.found() + # Use 'mc' if available + gen_src_log_rc_ct = custom_target( + 'gen-log-rc', + input: ['winlog'/'pist_winlog.man'], + output: ['pist_winlog.rc', 'pist_winlog.h'], + command: [mc_prog, '-um', '-h', '@OUTDIR@', '-r', '@OUTDIR@', '@INPUT@'] + ) + else + # mc.exe is not available, use the Python script to convert .man to .mc + python_prog = find_program('python3', required: true) + convert_man_to_mc_script = files('winlog' / 'convert_man_to_mc.py') + + # Generate .mc file in the build directory + gen_mc_file = custom_target( + 'gen-mc-file', + input: ['winlog' / 'pist_winlog.man'], + output: 'pist_winlog.mc', + command: [python_prog, convert_man_to_mc_script, '@INPUT@', '@OUTPUT@'], + build_by_default: true + ) + + # Use windmc.exe to generate .rc and .h files from the .mc file + mc_prog = find_program('windmc.exe') + gen_src_log_rc_ct = custom_target( + 'gen-log-rc', + input: [gen_mc_file], # pist_winlog.mc + output: ['pist_winlog.rc', 'pist_winlog.h'], + command: [ + mc_prog, + '-h', '@OUTDIR@', + '-r', '@OUTDIR@', + '@INPUT@' + ] + ) + endif if compiler.get_id() == 'gcc' gen_src_log_res_ct = custom_target('gen-log-res', @@ -187,14 +217,13 @@ if host_machine.system() == 'windows' # Add script to install logging manifest when "meson install..." is run install_headers( - 'winlog'/'pist_winlog.man', 'winlog'/'installmanatinstall.ps1', + 'winlog'/'pist_winlog.man', 'winlog'/'installmanatinstall.ps1', install_dir : 'src'/'winlog') meson.add_install_script('winlog'/'installmanatinstall.ps1') pistache_extra_src += gen_src_log_rc_ct[1] # for pist_winlog.h endif - if host_machine.system() == 'windows' if compiler.get_id() == 'msvc' diff --git a/src/winlog/convert_man_to_mc.py b/src/winlog/convert_man_to_mc.py new file mode 100644 index 000000000..2bf7c7427 --- /dev/null +++ b/src/winlog/convert_man_to_mc.py @@ -0,0 +1,167 @@ +# SPDX-FileCopyrightText: 2025 Kreijstal +# +# SPDX-License-Identifier: Apache-2.0 + +import xml.etree.ElementTree as ET +import argparse +import sys +import os + +# Define the namespaces +namespaces = { + 'ns': 'http://schemas.microsoft.com/win/2004/08/events', + 'win': 'http://manifests.microsoft.com/win/2004/08/windows/events', + 'xs': 'http://www.w3.org/2001/XMLSchema' +} + +def main(input_file, output_file): + # Check if the input file has a .man extension + if not input_file.endswith('.man'): + print("Error: Input file must have a .man extension.") + sys.exit(1) + + # Parse the .man file + try: + tree = ET.parse(input_file) + except ET.ParseError as e: + print(f"Error: Failed to parse the XML file: {e}") + sys.exit(1) + except FileNotFoundError: + print(f"Error: File '{input_file}' not found.") + sys.exit(1) + + root = tree.getroot() + + # Extract provider information + provider = root.find('.//ns:provider', namespaces) + if provider is None: + print("Error: Could not find the element in the XML.") + sys.exit(1) + + provider_name = provider.get('name') + provider_guid = provider.get('guid') + provider_symbol = provider.get('symbol') + + # Convert provider name to a valid function name (e.g., "Pistache-Provider" -> "Pistache_Provider") + provider_func_name = provider_name.replace('-', '_') + + # Extract events + events = provider.find('ns:events', namespaces).findall('ns:event', namespaces) + + # Extract localization strings + strings = {} + string_table = root.find('.//ns:stringTable', namespaces).findall('ns:string', namespaces) + for string in string_table: + strings[string.get('id')] = string.get('value') + + # Start building the .mc content + mc_content = 'MessageIdTypedef=DWORD\n\n' + + # Provider Information + mc_content += f';// Provider Information\n' + mc_content += f';// Name: {provider_name}\n' + mc_content += f';// GUID: {provider_guid}\n' + mc_content += f';// Symbol: {provider_symbol}\n\n' + + # Events + mc_content += ';// Events\n' + for event in events: + message_id = event.get('value') + symbolic_name = event.get('symbol') + message = event.get('message') + if message.startswith('$(string.Event.'): + message_id_str = message.lstrip('$(string.Event.').rstrip(')') + message_text = strings.get(f'Event.{message_id_str}', '') + else: + message_text = message + mc_content += f'MessageId={message_id}\n' + mc_content += f'SymbolicName={symbolic_name}\n' + mc_content += 'Language=English\n' + mc_content += f'{message_text}\n.\n\n' + # Add comments for channel, level, task, and template + channel = event.get('channel') + level = event.get('level') + task = event.get('task') + template = event.get('template') + mc_content += f';// Channel: {channel}\n' + mc_content += f';// Level: {level}\n' + mc_content += f';// Task: {task}\n' + mc_content += f';// Template: {template}\n\n' + + # Generate Event Descriptors + mc_content += ';// Event Descriptors\n' + for event in events: + message_id = event.get('value') + symbolic_name = event.get('symbol') + mc_content += f';static const EVENT_DESCRIPTOR EventDesc_{symbolic_name} = {{ {message_id}, 1, 0, 0, 0, 0, 0 }};\n' + mc_content += '\n' + + # Generate Provider Handle and GUID + mc_content += ';// Provider Handle and GUID\n' + mc_content += f';static REGHANDLE {provider_func_name}Handle = 0;\n' + + # Format the GUID correctly + guid_parts = provider_guid.strip('{}').split('-') + guid_hex = [ + f'0x{guid_parts[0]}', # Data1 + f'0x{guid_parts[1]}', # Data2 + f'0x{guid_parts[2]}', # Data3 + f'0x{guid_parts[3][0:2]}', # Data4[0] + f'0x{guid_parts[3][2:4]}', # Data4[1] + f'0x{guid_parts[4][0:2]}', # Data4[2] + f'0x{guid_parts[4][2:4]}', # Data4[3] + f'0x{guid_parts[4][4:6]}', # Data4[4] + f'0x{guid_parts[4][6:8]}', # Data4[5] + f'0x{guid_parts[4][8:10]}', # Data4[6] + f'0x{guid_parts[4][10:12]}' # Data4[7] + ] + mc_content += f';static const GUID {provider_symbol} =\n' + mc_content += f';{{ {guid_hex[0]}, {guid_hex[1]}, {guid_hex[2]}, {{ {guid_hex[3]}, {guid_hex[4]}, {guid_hex[5]}, {guid_hex[6]}, {guid_hex[7]}, {guid_hex[8]}, {guid_hex[9]}, {guid_hex[10]} }} }};\n\n' + + # Generate Provider Registration Code + mc_content += ';// Provider Registration and Unregistration\n' + mc_content += f';static inline ULONG EventRegister{provider_func_name}() {{\n' + mc_content += f'; return EventRegister(&{provider_symbol}, nullptr, nullptr, &{provider_func_name}Handle);\n' + mc_content += ';}\n\n' + mc_content += f';static inline ULONG EventUnregister{provider_func_name}() {{\n' + mc_content += f'; return EventUnregister({provider_func_name}Handle);\n' + mc_content += ';}\n\n' + + # Generate Event Writing Functions + mc_content += ';// Event Writing Functions\n' + mc_content += ';#define GENERATE_EVENT_WRITE_FUNCTION(event_name, event_descriptor) \\\n' + mc_content += '; static inline ULONG event_name(PCWSTR message) { \\\n' + mc_content += '; EVENT_DATA_DESCRIPTOR descriptor; \\\n' + mc_content += '; EventDataDescCreate(&descriptor, message, (ULONG)((wcslen(message) + 1) * sizeof(WCHAR))); \\\n' + mc_content += f'; return EventWrite({provider_func_name}Handle, &event_descriptor, 1, &descriptor); \\\n' + mc_content += '; }\n\n' + + # Generate AssumeEnabled Macros + mc_content += ';// AssumeEnabled Macros\n' + mc_content += ';#define GENERATE_ASSUME_ENABLED_MACRO(event_name) \\\n' + mc_content += '; static inline ULONG event_name##_AssumeEnabled(PCWSTR message) { \\\n' + mc_content += '; return event_name(message); \\\n' + mc_content += '; }\n\n' + + # Generate Functions for Each Event + for event in events: + symbolic_name = event.get('symbol') + mc_content += f';GENERATE_EVENT_WRITE_FUNCTION(EventWrite{symbolic_name}, EventDesc_{symbolic_name})\n' + mc_content += f';GENERATE_ASSUME_ENABLED_MACRO(EventWrite{symbolic_name})\n\n' + + # Write to .mc file + try: + with open(output_file, 'w', encoding='utf-8') as mc_file: + mc_file.write(mc_content) + print(f"Successfully wrote to {output_file}") + except IOError as e: + print(f"Error: Failed to write to {output_file}: {e}") + sys.exit(1) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Convert a .man file to a .mc file.") + parser.add_argument("input_file", help="Path to the input .man file") + parser.add_argument("output_file", help="Path to the output .mc file") + args = parser.parse_args() + + main(args.input_file, args.output_file) diff --git a/version.txt b/version.txt index 9b1f66005..8464c8a1b 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.4.29.20250106 +0.4.29.20250108 diff --git a/winscripts/gccsetup.ps1 b/winscripts/gccsetup.ps1 index 8906000db..e24f7c17f 100644 --- a/winscripts/gccsetup.ps1 +++ b/winscripts/gccsetup.ps1 @@ -1,5 +1,7 @@ #!/usr/bin/env powershell +param([switch]$nomcexe) + # # SPDX-FileCopyrightText: 2024 Duncan Greatwood # @@ -74,27 +76,11 @@ if (($env:force_msys_gcc) -or ` $env:CXX="g++" $env:CC="gcc" -if (! (Get-Command mc.exe -errorAction SilentlyContinue)) { - if (Test-Path -Path "$env:ProgramFiles\Windows Kits") { - $win_sdk_found=1 - cd "$env:ProgramFiles\Windows Kits" - $mc_exes_found=Get-ChildItem -Path "mc.exe" -Recurse |` - Sort-Object -Descending -Property LastWriteTime - foreach ($mc_exe_found in $mc_exes_found) { - if ($mc_exe_found -like "*\x64\mc*") { - $mc_exe = $mc_exe_found - break - } - if ((! ($mc_exe)) -and ($mc_exe_found -like "*\x86\mc*")) { - $mc_exe = $mc_exe_found - } - } - } - - if (! ($mc_exe)) { - if (Test-Path -Path "${env:ProgramFiles(x86)}\Windows Kits") { +if (!($nomcexe)) { + if (! (Get-Command mc.exe -errorAction SilentlyContinue)) { + if (Test-Path -Path "$env:ProgramFiles\Windows Kits") { $win_sdk_found=1 - cd "${env:ProgramFiles(x86)}\Windows Kits" + cd "$env:ProgramFiles\Windows Kits" $mc_exes_found=Get-ChildItem -Path "mc.exe" -Recurse |` Sort-Object -Descending -Property LastWriteTime foreach ($mc_exe_found in $mc_exes_found) { @@ -107,20 +93,38 @@ if (! (Get-Command mc.exe -errorAction SilentlyContinue)) { } } } + + if (! ($mc_exe)) { + if (Test-Path -Path "${env:ProgramFiles(x86)}\Windows Kits") { + $win_sdk_found=1 + cd "${env:ProgramFiles(x86)}\Windows Kits" + $mc_exes_found=Get-ChildItem -Path "mc.exe" -Recurse |` + Sort-Object -Descending -Property LastWriteTime + foreach ($mc_exe_found in $mc_exes_found) { + if ($mc_exe_found -like "*\x64\mc*") { + $mc_exe = $mc_exe_found + break + } + if ((! ($mc_exe)) -and ($mc_exe_found -like "*\x86\mc*")) { + $mc_exe = $mc_exe_found + } + } + } + } } -} -cd "$savedpwd" + cd "$savedpwd" -if (! ($win_sdk_found)) { - throw "Unable to find Windows Kits (SDKs) folder" -} -if (! ($mc_exe)) { - throw "Unable to find mc.exe in Windows Kits (SDKs)" -} + if (! ($win_sdk_found)) { + throw "Unable to find Windows Kits (SDKs) folder" + } + if (! ($mc_exe)) { + throw "Unable to find mc.exe in Windows Kits (SDKs)" + } -$mc_exe_dir = Split-Path -Path $mc_exe -$env:PATH="$env:PATH;$mc_exe_dir" + $mc_exe_dir = Split-Path -Path $mc_exe + $env:PATH="$env:PATH;$mc_exe_dir" +} if (! (Get-Command ninja -errorAction SilentlyContinue)) { if (($env:VCPKG_DIR) -And (Test-Path -Path "$env:VCPKG_DIR\installed")) { @@ -209,4 +213,9 @@ cd "$savedpwd" pstPressKeyIfRaisedAndErrThenExit -Write-Host "SUCCESS: gcc.exe, mc.exe and ninja.exe set up" +if ($nomcexe) { + Write-Host "SUCCESS: gcc.exe and ninja.exe set up (mc.exe skipped)" +} +else { + Write-Host "SUCCESS: gcc.exe, mc.exe and ninja.exe set up" +}