Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: compiling using msys2 and mingw #1279

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 38 additions & 9 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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'

Expand Down
167 changes: 167 additions & 0 deletions src/winlog/convert_man_to_mc.py
Original file line number Diff line number Diff line change
@@ -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 <provider> 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(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)
2 changes: 1 addition & 1 deletion version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.4.29.20250106
0.4.29.20250108
71 changes: 40 additions & 31 deletions winscripts/gccsetup.ps1
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#!/usr/bin/env powershell

param([switch]$nomcexe)

#
# SPDX-FileCopyrightText: 2024 Duncan Greatwood
#
Expand Down Expand Up @@ -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) {
Expand All @@ -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")) {
Expand Down Expand Up @@ -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"
}