[client] windows: add native clang-cl build

Build the Windows client against the MSVC ABI while retaining clang
language support. Use vcpkg for ANGLE and libsamplerate, and build
MsQuic with its bundled static OpenSSL.
This commit is contained in:
Geoffrey McRae
2026-10-02 18:52:45 +10:00
parent c456596bd7
commit 57f18d7e80
33 changed files with 583 additions and 205 deletions

View File

@@ -7,7 +7,9 @@ include_directories(
${PROJECT_SOURCE_DIR}/include
)
add_definitions(-D_GNU_SOURCE)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_compile_definitions(_GNU_SOURCE)
endif()
if (CMAKE_C_COMPILER_ID STREQUAL "Clang")
add_compile_options(

View File

@@ -23,6 +23,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdarg.h>
// vsprintf but with buffer allocation
int valloc_sprintf(char ** str, const char * format, va_list ap)
@@ -35,8 +36,14 @@ int alloc_sprintf(char ** str, const char * format, ...)
// Find value in a list separated by delimiter.
bool str_containsValue(const char * list, char delimiter, const char * value);
// Portable case-insensitive string comparison.
int lg_strcasecmp(const char * left, const char * right);
// Portable reentrant tokenization.
char * lg_strtok_r(char * str, const char * delimiters, char ** state);
// Local implementation of strdup
char * lg_strdup(const char *s);
char * lg_strdup(const char * s);
// copy a potentially unterminated string into a null-terminated buffer
void str_copy(char * dst, size_t dstSize, const char * src, size_t srcSize);

View File

@@ -32,7 +32,6 @@
#include <emmintrin.h>
#include <smmintrin.h>
#include <immintrin.h>
#include <unistd.h>
static bool framebuffer_size_mul(size_t a, size_t b, size_t * result)
{
@@ -65,7 +64,7 @@ bool framebuffer_wait_timed(const KVMFRFrameBuffer * frame, size_t size,
*waitTimeNs += nanotime() - waitStart;
return false;
}
usleep(1);
nsleep(1000);
}
}

View File

@@ -65,10 +65,10 @@ static bool int_parser(struct Option * opt, const char * str)
static bool bool_parser(struct Option * opt, const char * str)
{
opt->value.x_bool =
strcasecmp(str, "1" ) == 0 ||
strcasecmp(str, "on" ) == 0 ||
strcasecmp(str, "yes" ) == 0 ||
strcasecmp(str, "true") == 0;
lg_strcasecmp(str, "1" ) == 0 ||
lg_strcasecmp(str, "on" ) == 0 ||
lg_strcasecmp(str, "yes" ) == 0 ||
lg_strcasecmp(str, "true") == 0;
return true;
}
@@ -343,13 +343,14 @@ bool option_parse(int argc, char * argv[])
// emulate getopt for backwards compatability
if (argv[a][0] == '-')
{
if (strcasecmp(argv[a], "-h") == 0 || strcasecmp(argv[a], "--help") == 0)
if (lg_strcasecmp(argv[a], "-h") == 0 ||
lg_strcasecmp(argv[a], "--help") == 0)
{
state.doHelp = DOHELP_MODE_YES;
continue;
}
if (strcasecmp(argv[a], "--rst-help") == 0)
if (lg_strcasecmp(argv[a], "--rst-help") == 0)
{
state.doHelp = DOHELP_MODE_RST;
continue;
@@ -925,13 +926,14 @@ struct Option * option_get(const char * module, const char * name)
for(int i = 0; i < state.oCount; ++i)
{
struct Option * o = state.options[i];
if ((strcasecmp(o->module, module) == 0) && (strcasecmp(o->name, name) == 0))
if ((lg_strcasecmp(o->module, module) == 0) &&
(lg_strcasecmp(o->name, name) == 0))
return o;
// check for usage of renamed options
if (o->old_module && o->old_name &&
(strcasecmp(o->old_module, module) == 0) &&
(strcasecmp(o->old_name , name) == 0))
(lg_strcasecmp(o->old_module, module) == 0) &&
(lg_strcasecmp(o->old_name , name) == 0))
{
// not fatal, but be noisy
DEBUG_WARN(

View File

@@ -8,9 +8,9 @@ include_directories(
# allow use of functions for Windows 7 or later
add_compile_definitions(WINVER=0x0601 _WIN32_WINNT=0x0601)
add_compile_definitions(__USE_MINGW_ANSI_STDIO=0)
if(MINGW)
add_compile_definitions(__USE_MINGW_ANSI_STDIO=0)
if (MINGW)
# Build our own ntdll.dll import library
# This tricks MinGW into not linking stuff like memcpy from ntdll.dll instead of mscvrt.dll
if(NOT CMAKE_DLLTOOL)

View File

@@ -19,6 +19,7 @@
*/
#include <stdbool.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -92,7 +93,48 @@ bool str_containsValue(const char * list, char delimiter, const char * value)
return false;
}
char * lg_strdup(const char *s)
int lg_strcasecmp(const char * left, const char * right)
{
while (*left && *right)
{
const int leftChar = tolower((unsigned char)*left);
const int rightChar = tolower((unsigned char)*right);
if (leftChar != rightChar)
return leftChar - rightChar;
++left;
++right;
}
return (unsigned char)*left - (unsigned char)*right;
}
char * lg_strtok_r(char * str, const char * delimiters, char ** state)
{
char * token = str ? str : *state;
if (!token)
return NULL;
token += strspn(token, delimiters);
if (!*token)
{
*state = NULL;
return NULL;
}
char * end = token + strcspn(token, delimiters);
if (*end)
{
*end = '\0';
*state = end + 1;
}
else
*state = NULL;
return token;
}
char * lg_strdup(const char * s)
{
if (!s)
{
@@ -100,8 +142,8 @@ char * lg_strdup(const char *s)
return NULL;
}
const ssize_t len = strlen(s) + 1;
char * out = malloc(len);
const size_t len = strlen(s) + 1;
char * out = malloc(len);
if (!out)
{
errno = ENOMEM;