lsteamclient: Generate struct definitions for all abis.

CW-Bug-Id: #22729
This commit is contained in:
Rémi Bernon 2023-09-23 23:51:24 +02:00 committed by Arkadiusz Hiler
parent cafc3fb8e7
commit 7c622566cf
5 changed files with 18180 additions and 10 deletions

View File

@ -297,3 +297,4 @@ SOURCES = \
struct_converters_157.cpp \
struct_converters_158.cpp \
unix_steam_client_manual.cpp \
unixlib_generated.cpp \

View File

@ -510,6 +510,31 @@ class Struct:
def fields(self):
return [f for f in self.padded_fields if type(f) is not Padding]
def write_definition(self, out, prefix):
version = all_versions[sdkver][self.name]
kind = 'union' if type(self) is Union else 'struct'
wrapped = len(prefix) > 0
out(f'#pragma pack( push, {self.align} )\n')
out(f'{kind} {prefix}{version}\n')
out(u'{\n')
for f in self.padded_fields:
if type(f) is Field:
out(f' {declspec(f._cursor, f.name, prefix, wrapped)};\n')
else:
out(f' uint8_t __pad_{f.offset}[{f.size}];\n')
out(u'};\n')
out(u'#pragma pack( pop )\n\n')
def write_checks(self, out, prefix):
version = all_versions[sdkver][self.name]
out(f'C_ASSERT( sizeof({prefix}{version}) >= {self.size} );\n')
for f in self.fields:
out(f'C_ASSERT( offsetof({prefix}{version}, {f.name}) == {f.offset} );\n')
out(f'C_ASSERT( sizeof({prefix}{version}().{f.name}) >= {f.size} );\n')
out(u'\n')
def needs_conversion(self, other):
if other.id in self._conv_cache:
return self._conv_cache[other.id]
@ -751,13 +776,13 @@ def callconv(cursor, prefix):
def declspec_func(decl, name, prefix):
ret = declspec(decl.get_result(), "", prefix)
params = [declspec(a, "", prefix) for a in decl.argument_types()]
ret = declspec(decl.get_result(), "", prefix, False)
params = [declspec(a, "", prefix, False) for a in decl.argument_types()]
params = ", ".join(params) if len(params) else "void"
return f'{ret} ({name})({params})'
def declspec(decl, name, prefix):
def declspec(decl, name, prefix, wrapped=False):
call = callconv(decl, prefix)
if type(decl) is Cursor:
decl = decl.type
@ -768,10 +793,16 @@ def declspec(decl, name, prefix):
return declspec_func(decl, name, prefix)
if decl.kind in (TypeKind.POINTER, TypeKind.LVALUEREFERENCE):
decl = decl.get_pointee()
return declspec(decl, f"*{call}{const}{name}", prefix)
spec = declspec(decl, f"*{call}{const}{name}", prefix, False)
if wrapped:
return f'{prefix.upper()}PTR({spec}, {name})'
return spec
if decl.kind == TypeKind.CONSTANTARRAY:
decl, count = decl.element_type, decl.element_count
return declspec(decl, f"({const}{name})[{count}]", prefix)
if wrapped:
spec = declspec(decl, const, prefix, False)
return f'{prefix.upper()}ARRAY({spec}, {count}, {name})'
return declspec(decl, f"({const}{name})[{count}]", prefix, False)
if len(name):
name = f' {name}'
@ -782,6 +813,13 @@ def declspec(decl, name, prefix):
return f'uint{decl.get_size() * 8}_t{name}'
type_name = decl.spelling.removeprefix("const ")
if prefix not in (None, "win") and decl.kind == TypeKind.RECORD \
and type_name in all_versions[sdkver] \
and type_name not in EXEMPT_STRUCTS:
if type_name in unique_structs:
return f'{const}{all_versions[sdkver][type_name]}{name}'
return f'{const}{prefix}{all_versions[sdkver][type_name]}{name}'
if prefix == "win" and param_needs_conversion(decl):
return f"{const}win{type_name}_{sdkver}{name}"
if type_name.startswith('ISteam'):
@ -793,6 +831,8 @@ def declspec(decl, name, prefix):
if type_name.startswith(('uint', 'unsigned')):
return f'{const}uint{decl.get_size() * 8}_t{name}'
if 'unnamed union' in decl.spelling:
return f'{const}struct {{ uint8_t _[{decl.get_size()}]; }}{name}'
return f'{decl.spelling}{name}'
@ -861,20 +901,20 @@ def handle_method_cpp(method, classname, cppname, out):
type_name = underlying_typename(param)
if param.type.kind != TypeKind.POINTER:
out(f' {declspec(param, f"lin_{name}", "u_")};\n')
out(f' {declspec(param, f"lin_{name}", None)};\n')
out(f' win_to_lin_struct_{type_name}_{sdkver}( &params->{name}, &lin_{name} );\n')
continue
pointee = param.type.get_pointee()
if pointee.kind == TypeKind.POINTER:
need_output[name] = param
out(f' {declspec(pointee, f"lin_{name}", "u_")};\n')
out(f' {declspec(pointee, f"lin_{name}", None)};\n')
continue
if not pointee.is_const_qualified():
need_output[name] = param
out(f' {declspec(pointee, f"lin_{name}", "u_")};\n')
out(f' {declspec(pointee, f"lin_{name}", None)};\n')
out(f' win_to_lin_struct_{type_name}_{sdkver}( params->{name}, &lin_{name} );\n')
for name, param in sorted(manual_convert.items()):
@ -1506,8 +1546,8 @@ for i, name in enumerate(all_structs.keys()):
if not versions or sdkver not in versions: continue
all_versions[sdkver][name] = versions[sdkver]
def struct_order(tuple):
name, structs = tuple
def struct_order(x):
name, structs = x if type(x) is tuple else (x, all_structs[x])
order = (struct.order for abis in structs.values()
for struct in abis.values())
return (min(order), name)
@ -1559,6 +1599,129 @@ with open('struct_converters.h', 'a') as file:
out(u'#endif /* __STRUCT_CONVERTERS_H */\n')
declared = {}
with open('steamclient_structs_generated.h', 'w') as file:
out = file.write
for name in sorted(unique_structs, key=struct_order):
if name in EXEMPT_STRUCTS: continue
for sdkver, abis in all_structs[name].items():
if name not in all_versions[sdkver]: continue
version = all_versions[sdkver][name]
if f'struct {version}' in declared: continue
declared[f'struct {version}'] = True
kind = 'union' if type(abis['w64']) is Union else 'struct'
out(f'typedef {kind} {version} {version};\n')
abis['w64'].write_definition(out, "")
for name, structs in all_structs.items():
if name in EXEMPT_STRUCTS: continue
if name in unique_structs: continue
for sdkver, abis in structs.items():
if name not in all_versions[sdkver]: continue
version = all_versions[sdkver][name]
if f'typedef {version}' in declared: continue
declared[f'typedef {version}'] = True
kind = 'union' if type(abis['w64']) is Union else 'struct'
if type(abis['w64']) is Class:
out(f'typedef {kind} u_{version} u_{version};\n')
out(f'typedef {kind} u_{version} u64_{version};\n')
out(f'typedef {kind} u_{version} u32_{version};\n')
out(f'typedef {kind} w_{version} w_{version};\n')
out(f'typedef {kind} w_{version} w64_{version};\n')
out(f'typedef {kind} w_{version} w32_{version};\n')
continue
if abis["w64"].needs_conversion(abis["u64"]):
out(f'typedef {kind} u64_{version} u64_{version};\n')
else:
out(f'typedef {kind} w64_{version} u64_{version};\n')
out(f'typedef {kind} w64_{version} w64_{version};\n')
if abis["w32"].needs_conversion(abis["u32"]):
out(f'typedef {kind} u32_{version} u32_{version};\n')
else:
out(f'typedef {kind} w32_{version} u32_{version};\n')
out(f'typedef {kind} w32_{version} w32_{version};\n')
for name, structs in all_structs.items():
if name in EXEMPT_STRUCTS: continue
if name in unique_structs: continue
for sdkver, abis in structs.items():
if name not in all_versions[sdkver]: continue
version = all_versions[sdkver][name]
if f'struct {version}' in declared: continue
declared[f'struct {version}'] = True
kind = 'union' if type(abis['w64']) is Union else 'struct'
if type(abis['w64']) is Class:
abis['w64'].write_definition(out, "w_")
abis['u64'].write_definition(out, "u_")
continue
abis['w64'].write_definition(out, "w64_")
if abis["w64"].needs_conversion(abis["u64"]):
abis['u64'].write_definition(out, "u64_")
abis['w32'].write_definition(out, "w32_")
if abis["w32"].needs_conversion(abis["u32"]):
abis['u32'].write_definition(out, "u32_")
out(u'#ifdef __i386__\n')
out(f'typedef w32_{version} w_{version};\n')
out(f'typedef u32_{version} u_{version};\n')
out(u'#endif\n')
out(u'#ifdef __x86_64__\n')
out(f'typedef w64_{version} w_{version};\n')
out(f'typedef u64_{version} u_{version};\n')
out(u'#endif\n')
out(u'\n')
with open('unixlib_generated.cpp', 'w') as file:
out = file.write
out(u'/* This file is auto-generated, do not edit. */\n\n')
out(u'#include "steamclient_structs.h"\n\n')
for name in sorted(unique_structs, key=struct_order):
for sdkver, abis in all_structs[name].items():
if name not in all_versions[sdkver]: continue
version = all_versions[sdkver][name]
if f'checks {version}' in declared: continue
declared[f'checks {version}'] = True
abis['w64'].write_checks(out, "")
for name, structs in all_structs.items():
if name in EXEMPT_STRUCTS: continue
if name in unique_structs: continue
for sdkver, abis in structs.items():
if name not in all_versions[sdkver]: continue
version = all_versions[sdkver][name]
if f'checks {version}' in declared: continue
declared[f'checks {version}'] = True
if type(abis['w64']) is Class:
continue
abis['w64'].write_checks(out, "w64_")
abis['u64'].write_checks(out, "u64_")
abis['w32'].write_checks(out, "w32_")
abis['u32'].write_checks(out, "u32_")
getapifile = open("cb_getapi_table.dat", "w")
cbsizefile = open("cb_getapi_sizes.dat", "w")

View File

@ -0,0 +1,58 @@
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <windef.h>
#include <winbase.h>
#ifdef __cplusplus
#include <array>
extern "C"
{
#endif /* __cplusplus */
#ifdef __cplusplus
#define U64_ARRAY( type, count, name ) std::array<type, count> name
#define U32_ARRAY( type, count, name ) std::array<type, count> name
#define W64_ARRAY( type, count, name ) std::array<type, count> name
#define W32_ARRAY( type, count, name ) std::array<type, count> name
#else
#define U64_ARRAY( type, count, name ) type name[count]
#define U32_ARRAY( type, count, name ) type name[count]
#define W64_ARRAY( type, count, name ) type name[count]
#define W32_ARRAY( type, count, name ) type name[count]
#endif
#define W_CDECL __cdecl
#define W_STDCALL __stdcall
#define U_CDECL __attribute__((sysv_abi))
#define U_STDCALL __attribute__((sysv_abi))
#ifdef __i386__
#define U64_PTR( decl, name ) uint64_t name
#define U32_PTR( decl, name ) decl
#define W64_PTR( decl, name ) uint64_t name
#define W32_PTR( decl, name ) decl
#define U_PTR U32_PTR
#define W_PTR W32_PTR
#endif
#ifdef __x86_64__
#define U64_PTR( decl, name ) decl
#define U32_PTR( decl, name ) uint32_t name
#define W64_PTR( decl, name ) decl
#define W32_PTR( decl, name ) uint32_t name
#define U_PTR U64_PTR
#define W_PTR W64_PTR
#endif
typedef struct { uint8_t _[8]; } CSteamID;
typedef struct { uint8_t _[8]; } CGameID;
typedef struct { uint8_t _[20]; } SteamIPAddress_t;
#include "steamclient_structs_generated.h"
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff