[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

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.20)
project(looking-glass-client C CXX) project(looking-glass-client C CXX)
get_filename_component(PROJECT_TOP "${PROJECT_SOURCE_DIR}/.." ABSOLUTE) get_filename_component(PROJECT_TOP "${PROJECT_SOURCE_DIR}/.." ABSOLUTE)
@@ -34,6 +34,14 @@ else()
"The Looking Glass client does not support ${CMAKE_SYSTEM_NAME}") "The Looking Glass client does not support ${CMAKE_SYSTEM_NAME}")
endif() endif()
if(LG_CLIENT_PLATFORM_WINDOWS AND MSVC AND
(NOT CMAKE_C_COMPILER_ID STREQUAL "Clang" OR
NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang"))
message(FATAL_ERROR
"The native Windows client currently requires clang-cl for both C and "
"C++; use the windows-clangcl configure preset")
endif()
set(OPTIMIZE_FOR_NATIVE_DEFAULT ON) set(OPTIMIZE_FOR_NATIVE_DEFAULT ON)
include(OptimizeForNative) # option(OPTIMIZE_FOR_NATIVE) include(OptimizeForNative) # option(OPTIMIZE_FOR_NATIVE)
include(UninstallTarget) include(UninstallTarget)
@@ -145,34 +153,67 @@ if(ENABLE_USB_AUDIO)
endif() endif()
add_feature_info(ENABLE_USB_AUDIO ENABLE_USB_AUDIO "USB audio support.") add_feature_info(ENABLE_USB_AUDIO ENABLE_USB_AUDIO "USB audio support.")
add_compile_options( if(MSVC)
"-Wall" foreach(LG_CLIENT_COMPILE_OPTION
"-Wextra" /W4
"-Wno-sign-compare" /WX
"-Wno-unused-parameter" /utf-8
"$<$<COMPILE_LANGUAGE:C>:-Wstrict-prototypes>" /fp:fast
"$<$<C_COMPILER_ID:GNU>:-Wimplicit-fallthrough=2>" /Gy
"-Werror" /Gw
"-Wfatal-errors" /wd4100
"-g" /clang:-Wno-sign-compare
"-ffast-math" /clang:-Wno-unused-parameter
"-fdata-sections" /clang:-Wfatal-errors)
"-ffunction-sections" add_compile_options(
"$<$<CONFIG:DEBUG>:-O0;-g3;-ggdb>" "$<$<COMPILE_LANGUAGE:C>:${LG_CLIENT_COMPILE_OPTION}>"
) "$<$<COMPILE_LANGUAGE:CXX>:${LG_CLIENT_COMPILE_OPTION}>")
endforeach()
if(ENABLE_BACKTRACE)
add_compile_options( add_compile_options(
"-fno-omit-frame-pointer" "$<$<COMPILE_LANGUAGE:C>:/clang:-Wstrict-prototypes>")
"-fno-optimize-sibling-calls" add_link_options(/OPT:REF /NXCOMPAT)
else()
add_compile_options(
"-Wall"
"-Wextra"
"-Wno-sign-compare"
"-Wno-unused-parameter"
"$<$<COMPILE_LANGUAGE:C>:-Wstrict-prototypes>"
"$<$<C_COMPILER_ID:GNU>:-Wimplicit-fallthrough=2>"
"-Werror"
"-Wfatal-errors"
"-g"
"-ffast-math"
"-fdata-sections"
"-ffunction-sections"
"$<$<CONFIG:DEBUG>:-O0;-g3;-ggdb>"
) )
if(LG_CLIENT_PLATFORM_WINDOWS)
add_link_options("-Wl,--gc-sections" "-Wl,--nxcompat")
else()
add_link_options("-Wl,--gc-sections" "-z" "noexecstack")
endif()
endif() endif()
set(EXE_FLAGS "-Wl,--gc-sections -z noexecstack") if(ENABLE_BACKTRACE)
set(CMAKE_C_STANDARD 11) if(MSVC)
add_compile_options(
"$<$<COMPILE_LANGUAGE:C>:/Oy->"
"$<$<COMPILE_LANGUAGE:CXX>:/Oy->"
"$<$<COMPILE_LANGUAGE:C>:/clang:-fno-optimize-sibling-calls>"
"$<$<COMPILE_LANGUAGE:CXX>:/clang:-fno-optimize-sibling-calls>")
else()
add_compile_options(
"-fno-omit-frame-pointer"
"-fno-optimize-sibling-calls")
endif()
endif()
if(LG_CLIENT_PLATFORM_WINDOWS) set(CMAKE_C_STANDARD 11)
set(EXE_FLAGS "-Wl,--gc-sections -Wl,--nxcompat") set(CMAKE_C_STANDARD_REQUIRED ON)
if(MINGW)
add_compile_options("-fdebug-prefix-map=${PROJECT_TOP}/=") add_compile_options("-fdebug-prefix-map=${PROJECT_TOP}/=")
add_compile_definitions(__USE_MINGW_ANSI_STDIO=0) add_compile_definitions(__USE_MINGW_ANSI_STDIO=0)
endif() endif()
@@ -186,13 +227,22 @@ if (ENABLE_EGL)
endif() endif()
if(ENABLE_ASAN) if(ENABLE_ASAN)
add_compile_options("-fno-omit-frame-pointer" "-fsanitize=address") if(MSVC)
set(EXE_FLAGS "${EXE_FLAGS} -fno-omit-frame-pointer -fsanitize=address") message(FATAL_ERROR
"AddressSanitizer is not supported by the clang-cl build")
else()
add_compile_options("-fno-omit-frame-pointer" "-fsanitize=address")
add_link_options("-fno-omit-frame-pointer" "-fsanitize=address")
endif()
endif() endif()
if(ENABLE_UBSAN) if(ENABLE_UBSAN)
if(MSVC)
message(FATAL_ERROR
"UndefinedBehaviorSanitizer is not supported by the clang-cl build")
endif()
add_compile_options("-fsanitize=undefined") add_compile_options("-fsanitize=undefined")
set(EXE_FLAGS "${EXE_FLAGS} -fsanitize=undefined") add_link_options("-fsanitize=undefined")
endif() endif()
add_definitions(-D ATOMIC_LOCKING) add_definitions(-D ATOMIC_LOCKING)
@@ -266,9 +316,13 @@ if(ENABLE_EGL)
list(APPEND SOURCES src/egl_dynprocs.c) list(APPEND SOURCES src/egl_dynprocs.c)
endif() endif()
if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") if(MSVC)
set_source_files_properties(src/overlay/graphs.c PROPERTIES set_source_files_properties(src/overlay/graphs.c PROPERTIES
COMPILE_FLAGS "-fno-fast-math" COMPILE_OPTIONS "/fp:precise"
)
elseif(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
set_source_files_properties(src/overlay/graphs.c PROPERTIES
COMPILE_OPTIONS "-fno-fast-math"
) )
endif() endif()
@@ -407,8 +461,6 @@ target_link_libraries(looking-glass-client
lg_gui lg_gui
) )
set_target_properties(looking-glass-client PROPERTIES LINK_FLAGS "${EXE_FLAGS}")
if(ENABLE_TESTS AND LG_CLIENT_PLATFORM_WINDOWS) if(ENABLE_TESTS AND LG_CLIENT_PLATFORM_WINDOWS)
add_library(client_test_version OBJECT add_library(client_test_version OBJECT
"${CMAKE_BINARY_DIR}/version.c" "${CMAKE_BINARY_DIR}/version.c"

42
client/CMakePresets.json Normal file
View File

@@ -0,0 +1,42 @@
{
"version": 3,
"cmakeMinimumRequired": {
"major": 3,
"minor": 21,
"patch": 0
},
"configurePresets": [
{
"name": "windows-clangcl",
"displayName": "Windows clang-cl",
"description": "Build the Windows client with the MSVC ABI",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/windows-clangcl",
"toolchainFile": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"cacheVariables": {
"CMAKE_C_COMPILER": "clang-cl",
"CMAKE_CXX_COMPILER": "clang-cl",
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
"CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreadedDLL",
"ENABLE_AUDIO": true,
"ENABLE_EGL": true,
"ENABLE_NETWORK": true,
"ENABLE_WASAPI": true,
"OPTIMIZE_FOR_NATIVE": "OFF",
"VCPKG_TARGET_TRIPLET": "x64-windows"
}
}
],
"buildPresets": [
{
"name": "windows-clangcl-release",
"displayName": "Windows clang-cl RelWithDebInfo",
"configurePreset": "windows-clangcl"
}
]
}

View File

@@ -11,11 +11,14 @@ add_library(audiodev_WASAPI STATIC
target_link_libraries(audiodev_WASAPI target_link_libraries(audiodev_WASAPI
avrt avrt
lg_common lg_common
m
ole32 ole32
uuid uuid
) )
if(MINGW)
target_link_libraries(audiodev_WASAPI m)
endif()
target_include_directories(audiodev_WASAPI target_include_directories(audiodev_WASAPI
PRIVATE PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}"

View File

@@ -42,6 +42,18 @@ find_package_handle_standard_args(ANGLE
ANGLE_GLESV2_LIBRARY ANGLE_GLESV2_LIBRARY
) )
if(ANGLE_FOUND AND MSVC)
foreach(_ANGLE_LIBRARY IN ITEMS
"${ANGLE_EGL_LIBRARY}"
"${ANGLE_GLESV2_LIBRARY}")
if(_ANGLE_LIBRARY MATCHES "\\.(a|dll\\.a)$")
message(FATAL_ERROR
"The clang-cl client requires MSVC-ABI ANGLE .lib files; found "
"${_ANGLE_LIBRARY}")
endif()
endforeach()
endif()
mark_as_advanced( mark_as_advanced(
ANGLE_EGL_INCLUDE_DIR ANGLE_EGL_INCLUDE_DIR
ANGLE_GLES_INCLUDE_DIR ANGLE_GLES_INCLUDE_DIR
@@ -68,3 +80,4 @@ endif()
unset(_ANGLE_HINTS) unset(_ANGLE_HINTS)
unset(_ANGLE_FIND_POLICY) unset(_ANGLE_FIND_POLICY)
unset(_ANGLE_LIBRARY)

View File

@@ -27,6 +27,13 @@ find_package_handle_standard_args(SampleRate
SampleRate_LIBRARY SampleRate_LIBRARY
) )
if(SampleRate_FOUND AND MSVC AND
SampleRate_LIBRARY MATCHES "\\.(a|dll\\.a)$")
message(FATAL_ERROR
"The clang-cl client requires an MSVC-ABI samplerate .lib; found "
"${SampleRate_LIBRARY}")
endif()
mark_as_advanced( mark_as_advanced(
SampleRate_INCLUDE_DIR SampleRate_INCLUDE_DIR
SampleRate_LIBRARY SampleRate_LIBRARY

View File

@@ -22,6 +22,7 @@
#define _H_LG_OVERLAY_UTILS_ #define _H_LG_OVERLAY_UTILS_
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h>
#include "common/types.h" #include "common/types.h"
@@ -41,7 +42,7 @@ void overlayTextURL(const char * url, const char * text);
void overlayTextMaybeURL(const char * text, bool wrapped); void overlayTextMaybeURL(const char * text, bool wrapped);
// create a texture from a SVG and scale it to fit the supplied width & height // create a texture from a SVG and scale it to fit the supplied width & height
bool overlayLoadSVG(const char * data, unsigned int size, OverlayImage * image, bool overlayLoadSVG(const char * data, size_t size, OverlayImage * image,
int width, int height); int width, int height);
void overlayFreeImage(OverlayImage * image); void overlayFreeImage(OverlayImage * image);

View File

@@ -1,26 +1,23 @@
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.10)
project(renderer_EGL LANGUAGES C CXX) project(renderer_EGL LANGUAGES C CXX)
find_program(AWK NAMES gawk mawk original-awk awk)
if(AWK MATCHES ".+-NOTFOUND")
message(FATAL_ERROR "FATAL: some known version of awk couldn't be found (${AWK}).")
else()
message(STATUS "Using awk: ${AWK}")
endif()
include(MakeObject) include(MakeObject)
function(build_shaders header_dir) function(build_shaders header_dir)
file(GLOB headers "${header_dir}/*.h") file(GLOB headers "${header_dir}/*.h")
set(EGL_SHADER_PROCESSED) set(EGL_SHADER_PROCESSED)
set(include_dir "${CMAKE_CURRENT_SOURCE_DIR}/${header_dir}")
foreach(shader ${ARGN}) foreach(shader ${ARGN})
set(out_f "${CMAKE_CURRENT_BINARY_DIR}/${shader}") set(out_f "${CMAKE_CURRENT_BINARY_DIR}/${shader}")
add_custom_command(OUTPUT "${out_f}" add_custom_command(
COMMAND "${AWK}" -f "${CMAKE_CURRENT_SOURCE_DIR}/glsl.include.awk" OUTPUT "${out_f}"
"${CMAKE_CURRENT_SOURCE_DIR}/${shader}" > "${out_f}" COMMAND "${CMAKE_COMMAND}"
"-DLG_MAKE_OBJECT_ACTION=PREPROCESS"
"-DLG_MAKE_OBJECT_INPUT=${CMAKE_CURRENT_SOURCE_DIR}/${shader}"
"-DLG_MAKE_OBJECT_OUTPUT=${out_f}"
"-DLG_MAKE_OBJECT_INCLUDE_DIR=${include_dir}"
-P "${LG_MAKE_OBJECT_SCRIPT}"
MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/${shader}" MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/${shader}"
DEPENDS ${headers} DEPENDS ${headers} "${LG_MAKE_OBJECT_SCRIPT}"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/shader"
COMMENT "Preprocessing shader ${shader}" COMMENT "Preprocessing shader ${shader}"
VERBATIM VERBATIM
) )

View File

@@ -18,7 +18,6 @@
* Temple Place, Suite 330, Boston, MA 02111-1307 USA * Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#define _GNU_SOURCE
#include "filter.h" #include "filter.h"
#include "effect.h" #include "effect.h"
#include "app.h" #include "app.h"
@@ -45,7 +44,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <strings.h>
#define GLSL_MAX_TEXTURES 16 #define GLSL_MAX_TEXTURES 16
#define GLSL_EXPR_STACK 128 #define GLSL_EXPR_STACK 128
@@ -633,11 +631,11 @@ static bool evaluateExpression(const GLSLContext * context,
if (!copy) if (!copy)
return false; return false;
double stack[GLSL_EXPR_STACK]; double stack[GLSL_EXPR_STACK];
unsigned int count = 0; unsigned int count = 0;
char * state; char * state = NULL;
for (char * token = strtok_r(copy, " \t\r\n", &state); token; for (char * token = lg_strtok_r(copy, " \t\r\n", &state); token;
token = strtok_r(NULL, " \t\r\n", &state)) token = lg_strtok_r(NULL, " \t\r\n", &state))
{ {
if (!strcmp(token, "!")) if (!strcmp(token, "!"))
{ {
@@ -1077,7 +1075,7 @@ static bool createFilter(const char * root, const char * relative,
if (!this->relative || !this->base.ops.name) if (!this->relative || !this->base.ops.name)
goto fail; goto fail;
char * extension = strrchr((char *)this->base.ops.name, '.'); char * extension = strrchr((char *)this->base.ops.name, '.');
if (extension && !strcasecmp(extension, ".glsl")) if (extension && !lg_strcasecmp(extension, ".glsl"))
*extension = '\0'; *extension = '\0';
app_registerImGuiText(this->base.ops.name); app_registerImGuiText(this->base.ops.name);
@@ -1118,7 +1116,7 @@ static void glslFree(EGL_Filter * filter)
static bool hasGLSLExtension(const char * name) static bool hasGLSLExtension(const char * name)
{ {
const char * extension = strrchr(name, '.'); const char * extension = strrchr(name, '.');
return extension && !strcasecmp(extension, ".glsl"); return extension && !lg_strcasecmp(extension, ".glsl");
} }
static bool scanDirectory(const char * root, const char * relative, static bool scanDirectory(const char * root, const char * relative,

View File

@@ -1,13 +0,0 @@
BEGIN { FS="\"" }
function process(line, second) {
if (line ~ /^#include[ \t]*".+"[ \t\r]*$/) {
while (getline < second) {
process($0, $2)
}
} else {
print line
}
}
{ process($0, $2) } END { print "\0"; }

View File

@@ -154,7 +154,7 @@ static void loadPresetList(struct EGL_PostProcess * this)
continue; continue;
DEBUG_INFO("Found preset: %s", entry); DEBUG_INFO("Found preset: %s", entry);
char * name = strdup(entry); char * name = lg_strdup(entry);
if (!name) if (!name)
{ {
DEBUG_ERROR("Failed to allocate memory"); DEBUG_ERROR("Failed to allocate memory");
@@ -260,7 +260,7 @@ static void reorderFilters(struct EGL_PostProcess * this)
return; return;
} }
char * orderStr = strdup(option_get_string("eglFilter", "order")); char * orderStr = lg_strdup(option_get_string("eglFilter", "order"));
if (!orderStr) if (!orderStr)
{ {
DEBUG_ERROR("Failed to allocate memory"); DEBUG_ERROR("Failed to allocate memory");
@@ -339,7 +339,8 @@ static void savePresetAs(struct EGL_PostProcess * this)
} }
} }
this->activePreset = stringlist_push(this->presets, strdup(this->presetEdit)); this->activePreset = stringlist_push(
this->presets, lg_strdup(this->presetEdit));
} }
static void deletePreset(struct EGL_PostProcess * this) static void deletePreset(struct EGL_PostProcess * this)
@@ -396,7 +397,7 @@ static bool presetsUI(struct EGL_PostProcess * this)
if (this->activePreset >= 0) if (this->activePreset >= 0)
savePreset(this, stringlist_at(this->presets, this->activePreset)); savePreset(this, stringlist_at(this->presets, this->activePreset));
else else
presetError(this, strdup("You must select a preset to save.")); presetError(this, lg_strdup("You must select a preset to save."));
} }
if (igIsItemHovered(ImGuiHoveredFlags_None) && this->activePreset >= 0) if (igIsItemHovered(ImGuiHoveredFlags_None) && this->activePreset >= 0)

View File

@@ -738,14 +738,14 @@ static bool optRendererParse(struct Option * opt, const char * str)
if (!str) if (!str)
return false; return false;
if (strcasecmp(str, "auto") == 0) if (lg_strcasecmp(str, "auto") == 0)
{ {
g_params.forceRenderer = false; g_params.forceRenderer = false;
return true; return true;
} }
for(unsigned int i = 0; i < LG_RENDERER_COUNT; ++i) for(unsigned int i = 0; i < LG_RENDERER_COUNT; ++i)
if (strcasecmp(str, LG_Renderers[i]->getName()) == 0) if (lg_strcasecmp(str, LG_Renderers[i]->getName()) == 0)
{ {
g_params.forceRenderer = true; g_params.forceRenderer = true;
g_params.forceRendererIndex = i; g_params.forceRendererIndex = i;
@@ -771,12 +771,12 @@ static StringList optRendererValues(struct Option * opt)
static char * optRendererToString(struct Option * opt) static char * optRendererToString(struct Option * opt)
{ {
if (!g_params.forceRenderer) if (!g_params.forceRenderer)
return strdup("auto"); return lg_strdup("auto");
if (g_params.forceRendererIndex >= LG_RENDERER_COUNT) if (g_params.forceRendererIndex >= LG_RENDERER_COUNT)
return NULL; return NULL;
return strdup(LG_Renderers[g_params.forceRendererIndex]->getName()); return lg_strdup(LG_Renderers[g_params.forceRendererIndex]->getName());
} }
static bool parsePair(const char * str, long long * first, long long * second) static bool parsePair(const char * str, long long * first, long long * second)
@@ -838,7 +838,7 @@ static StringList optPosValues(struct Option * opt)
static char * optPosToString(struct Option * opt) static char * optPosToString(struct Option * opt)
{ {
if (g_params.center) if (g_params.center)
return strdup("center"); return lg_strdup("center");
int len = snprintf(NULL, 0, "%dx%d", g_params.x, g_params.y); int len = snprintf(NULL, 0, "%dx%d", g_params.x, g_params.y);
char * str = malloc(len + 1); char * str = malloc(len + 1);
@@ -919,7 +919,7 @@ static bool optScancodeParse(struct Option * opt, const char * str)
if (!lg_keycode_to_name[i]) if (!lg_keycode_to_name[i])
continue; continue;
if (strcasecmp(lg_keycode_to_name[i], str) == 0) if (lg_strcasecmp(lg_keycode_to_name[i], str) == 0)
{ {
opt->value.x_int = i; opt->value.x_int = i;
return true; return true;
@@ -981,11 +981,11 @@ static bool optMicDefaultParse(struct Option * opt, const char * str)
if (!str) if (!str)
return false; return false;
if (strcasecmp(str, "prompt") == 0) if (lg_strcasecmp(str, "prompt") == 0)
g_params.micDefaultState = MIC_DEFAULT_PROMPT; g_params.micDefaultState = MIC_DEFAULT_PROMPT;
else if (strcasecmp(str, "allow") == 0) else if (lg_strcasecmp(str, "allow") == 0)
g_params.micDefaultState = MIC_DEFAULT_ALLOW; g_params.micDefaultState = MIC_DEFAULT_ALLOW;
else if (strcasecmp(str, "deny") == 0) else if (lg_strcasecmp(str, "deny") == 0)
g_params.micDefaultState = MIC_DEFAULT_DENY; g_params.micDefaultState = MIC_DEFAULT_DENY;
else else
return false; return false;
@@ -1010,11 +1010,11 @@ static char * optMicDefaultToString(struct Option * opt)
switch (g_params.micDefaultState) switch (g_params.micDefaultState)
{ {
case MIC_DEFAULT_PROMPT: case MIC_DEFAULT_PROMPT:
return strdup("prompt"); return lg_strdup("prompt");
case MIC_DEFAULT_ALLOW: case MIC_DEFAULT_ALLOW:
return strdup("allow"); return lg_strdup("allow");
case MIC_DEFAULT_DENY: case MIC_DEFAULT_DENY:
return strdup("deny"); return lg_strdup("deny");
} }
return NULL; return NULL;
@@ -1026,11 +1026,11 @@ static bool optAudioResamplerParse(
if (!str) if (!str)
return false; return false;
if (strcasecmp(str, "auto") == 0) if (lg_strcasecmp(str, "auto") == 0)
g_params.audioResampler = AUDIO_RESAMPLER_AUTO; g_params.audioResampler = AUDIO_RESAMPLER_AUTO;
else if (strcasecmp(str, "libsamplerate") == 0) else if (lg_strcasecmp(str, "libsamplerate") == 0)
g_params.audioResampler = AUDIO_RESAMPLER_LIBSAMPLERATE; g_params.audioResampler = AUDIO_RESAMPLER_LIBSAMPLERATE;
else if (strcasecmp(str, "backend") == 0) else if (lg_strcasecmp(str, "backend") == 0)
g_params.audioResampler = AUDIO_RESAMPLER_BACKEND; g_params.audioResampler = AUDIO_RESAMPLER_BACKEND;
else else
return false; return false;
@@ -1055,11 +1055,11 @@ static char * optAudioResamplerToString(struct Option * opt)
switch (g_params.audioResampler) switch (g_params.audioResampler)
{ {
case AUDIO_RESAMPLER_AUTO: case AUDIO_RESAMPLER_AUTO:
return strdup("auto"); return lg_strdup("auto");
case AUDIO_RESAMPLER_LIBSAMPLERATE: case AUDIO_RESAMPLER_LIBSAMPLERATE:
return strdup("libsamplerate"); return lg_strdup("libsamplerate");
case AUDIO_RESAMPLER_BACKEND: case AUDIO_RESAMPLER_BACKEND:
return strdup("backend"); return lg_strdup("backend");
} }
return NULL; return NULL;

View File

@@ -28,6 +28,7 @@
#include "common/debug.h" #include "common/debug.h"
#include "common/event.h" #include "common/event.h"
#include "common/locking.h" #include "common/locking.h"
#include "common/stringutils.h"
#include "common/thread.h" #include "common/thread.h"
#include "common/util.h" #include "common/util.h"
@@ -561,7 +562,7 @@ bool lgTransportFallback_start(const char * transportName,
atomic_init(&fallback->usable, false); atomic_init(&fallback->usable, false);
atomic_init(&fallback->videoAcceptingEvents, false); atomic_init(&fallback->videoAcceptingEvents, false);
fallback->transportName = strdup(transportName); fallback->transportName = lg_strdup(transportName);
if (!fallback->transportName) if (!fallback->transportName)
goto fail; goto fail;

View File

@@ -24,6 +24,7 @@
#include "common/debug.h" #include "common/debug.h"
#include "common/filesystem.h" #include "common/filesystem.h"
#include "common/locking.h" #include "common/locking.h"
#include "common/stringutils.h"
#include "cimgui.h" #include "cimgui.h"
@@ -33,7 +34,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#if defined(__GNUC__) #if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-function"
#endif #endif
@@ -43,7 +44,7 @@
#define STBTT_STATIC #define STBTT_STATIC
#define STB_TRUETYPE_IMPLEMENTATION #define STB_TRUETYPE_IMPLEMENTATION
#include "repos/gui/cimgui/imgui/imstb_truetype.h" #include "repos/gui/cimgui/imgui/imstb_truetype.h"
#if defined(__GNUC__) #if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
@@ -360,7 +361,7 @@ static FontPlatformFaceResult uiFontAddFace(void * opaque,
return FONT_PLATFORM_FACE_ERROR; return FONT_PLATFORM_FACE_ERROR;
} }
char * fileCopy = strdup(file); char * fileCopy = lg_strdup(file);
if (!fileCopy || if (!fileCopy ||
!uiFontGlyphReserve( !uiFontGlyphReserve(
&UIFontResolved, UIFontResolved.count + glyphCount)) &UIFontResolved, UIFontResolved.count + glyphCount))

View File

@@ -38,7 +38,7 @@ static OverlayImage l_image[LG_USER_STATUS_MAX] = { 0 };
static bool l_recordToggle; static bool l_recordToggle;
static double l_scale = 1.0; static double l_scale = 1.0;
static void status_loadImage(const char * data, unsigned int size, static void status_loadImage(const char * data, size_t size,
OverlayImage * image, int width, int height) OverlayImage * image, int width, int height)
{ {
overlayFreeImage(image); overlayFreeImage(image);

View File

@@ -95,7 +95,7 @@ void overlayTextMaybeURL(const char * text, bool wrapped)
igTextUnformatted(text, NULL); igTextUnformatted(text, NULL);
} }
bool overlayLoadSVG(const char * data, unsigned int size, OverlayImage * image, bool overlayLoadSVG(const char * data, size_t size, OverlayImage * image,
int width, int height) int width, int height)
{ {
image->tex = NULL; image->tex = NULL;

View File

@@ -11,7 +11,6 @@ add_executable(common-platform-tests
common_platform_test.c common_platform_test.c
) )
target_link_libraries(common-platform-tests target_link_libraries(common-platform-tests
${EXE_FLAGS}
lg_common lg_common
) )
target_compile_definitions(common-platform-tests PRIVATE target_compile_definitions(common-platform-tests PRIVATE
@@ -32,7 +31,6 @@ target_include_directories(event-source-tests PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_SOURCE_DIR}/../src"
) )
target_link_libraries(event-source-tests target_link_libraries(event-source-tests
${EXE_FLAGS}
lg_common lg_common
) )
add_test(NAME event-source-tests add_test(NAME event-source-tests
@@ -46,9 +44,6 @@ add_executable(windows-clipboard-files-tests
clipboard_files_windows_test.c clipboard_files_windows_test.c
../platform/Windows/clipboard_files.c ../platform/Windows/clipboard_files.c
) )
target_link_libraries(windows-clipboard-files-tests
${EXE_FLAGS}
)
add_test(NAME windows-clipboard-files-tests add_test(NAME windows-clipboard-files-tests
COMMAND windows-clipboard-files-tests COMMAND windows-clipboard-files-tests
) )
@@ -65,7 +60,6 @@ if(LG_CLIENT_PLATFORM_LINUX)
"${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_SOURCE_DIR}/../src"
) )
target_link_libraries(config-platform-tests target_link_libraries(config-platform-tests
${EXE_FLAGS}
lg_common lg_common
) )
add_test(NAME config-platform-tests add_test(NAME config-platform-tests
@@ -79,7 +73,6 @@ if(LG_CLIENT_PLATFORM_LINUX)
lgmp_platform_test.c lgmp_platform_test.c
) )
target_link_libraries(lgmp-platform-tests target_link_libraries(lgmp-platform-tests
${EXE_FLAGS}
lg_common lg_common
) )
add_test(NAME lgmp-platform-tests add_test(NAME lgmp-platform-tests
@@ -103,9 +96,6 @@ if(LG_CLIENT_PLATFORM_LINUX)
process_test.c process_test.c
../platform/Linux/process.c ../platform/Linux/process.c
) )
target_link_libraries(process-tests
${EXE_FLAGS}
)
add_test(NAME process-tests add_test(NAME process-tests
COMMAND process-tests COMMAND process-tests
) )
@@ -147,7 +137,6 @@ if(LG_CLIENT_PLATFORM_WINDOWS)
common_windows_test.c common_windows_test.c
) )
target_link_libraries(common-windows-tests target_link_libraries(common-windows-tests
${EXE_FLAGS}
lg_common lg_common
) )
add_test(NAME common-windows-tests add_test(NAME common-windows-tests
@@ -169,7 +158,6 @@ target_include_directories(sw-surface-tests PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_SOURCE_DIR}/../src"
) )
target_link_libraries(sw-surface-tests target_link_libraries(sw-surface-tests
${EXE_FLAGS}
lg_common lg_common
) )
add_test(NAME sw-surface-tests COMMAND sw-surface-tests) add_test(NAME sw-surface-tests COMMAND sw-surface-tests)
@@ -183,7 +171,6 @@ target_include_directories(font-tests PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_SOURCE_DIR}/../src"
) )
target_link_libraries(font-tests target_link_libraries(font-tests
${EXE_FLAGS}
lg_common lg_common
lg_gui lg_gui
) )
@@ -200,7 +187,6 @@ if(LG_CLIENT_PLATFORM_LINUX)
../src/kb_hid.c ../src/kb_hid.c
) )
target_link_libraries(lgmp-transport-tests target_link_libraries(lgmp-transport-tests
${EXE_FLAGS}
transport_LGMP transport_LGMP
lg_common lg_common
lgmp lgmp
@@ -222,7 +208,6 @@ if(LG_CLIENT_PLATFORM_LINUX)
../src/kb_hid.c ../src/kb_hid.c
) )
target_link_libraries(lgmp-frame-tests target_link_libraries(lgmp-frame-tests
${EXE_FLAGS}
transport_LGMP transport_LGMP
lg_common lg_common
lgmp lgmp
@@ -252,7 +237,6 @@ if(LG_CLIENT_PLATFORM_LINUX)
"${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_SOURCE_DIR}/../src"
) )
target_link_libraries(lgmp-input-tests target_link_libraries(lgmp-input-tests
${EXE_FLAGS}
lg_common lg_common
lgmp lgmp
) )
@@ -280,7 +264,6 @@ if(LG_CLIENT_PLATFORM_LINUX)
"${CMAKE_CURRENT_SOURCE_DIR}/../transports/LGMP" "${CMAKE_CURRENT_SOURCE_DIR}/../transports/LGMP"
) )
target_link_libraries(lgmp-clipboard-tests target_link_libraries(lgmp-clipboard-tests
${EXE_FLAGS}
lg_common lg_common
lgmp lgmp
) )
@@ -322,7 +305,6 @@ if(LG_CLIENT_PLATFORM_LINUX)
"${CMAKE_CURRENT_SOURCE_DIR}/../transports/LGMP" "${CMAKE_CURRENT_SOURCE_DIR}/../transports/LGMP"
) )
target_link_libraries(lgmp-audio-tests target_link_libraries(lgmp-audio-tests
${EXE_FLAGS}
transport_LGMP transport_LGMP
lg_common lg_common
lgmp lgmp
@@ -362,7 +344,6 @@ if(LG_CLIENT_PLATFORM_LINUX AND ENABLE_WAYLAND)
"${CMAKE_BINARY_DIR}/wayland" "${CMAKE_BINARY_DIR}/wayland"
) )
target_link_libraries(wayland-presentation-tests target_link_libraries(wayland-presentation-tests
${EXE_FLAGS}
lg_common lg_common
) )
set(WAYLAND_PRESENTATION_CASES set(WAYLAND_PRESENTATION_CASES
@@ -393,7 +374,6 @@ if(LG_CLIENT_PLATFORM_LINUX AND ENABLE_WAYLAND)
"${CMAKE_BINARY_DIR}/wayland" "${CMAKE_BINARY_DIR}/wayland"
) )
target_link_libraries(wayland-clipboard-tests target_link_libraries(wayland-clipboard-tests
${EXE_FLAGS}
lg_common lg_common
) )
set(WAYLAND_CLIPBOARD_CASES set(WAYLAND_CLIPBOARD_CASES
@@ -441,7 +421,6 @@ if(LG_CLIENT_PLATFORM_LINUX AND ENABLE_X11)
"${CMAKE_CURRENT_SOURCE_DIR}/../displayservers/X11" "${CMAKE_CURRENT_SOURCE_DIR}/../displayservers/X11"
) )
target_link_libraries(x11-clipboard-tests target_link_libraries(x11-clipboard-tests
${EXE_FLAGS}
lg_common lg_common
pthread pthread
) )
@@ -561,7 +540,6 @@ target_include_directories(mouse-tests PRIVATE
"${PROJECT_TOP}/repos/gui/cimgui/imgui" "${PROJECT_TOP}/repos/gui/cimgui/imgui"
) )
target_link_libraries(mouse-tests target_link_libraries(mouse-tests
${EXE_FLAGS}
lg_common lg_common
) )
set(MOUSE_CASES set(MOUSE_CASES
@@ -603,7 +581,6 @@ target_include_directories(input-tests PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_SOURCE_DIR}/../src"
) )
target_link_libraries(input-tests target_link_libraries(input-tests
${EXE_FLAGS}
lg_common lg_common
) )
set(INPUT_CASES set(INPUT_CASES
@@ -636,7 +613,6 @@ target_include_directories(keybind-tests PRIVATE
"${PROJECT_TOP}/repos/gui/cimgui/imgui" "${PROJECT_TOP}/repos/gui/cimgui/imgui"
) )
target_link_libraries(keybind-tests target_link_libraries(keybind-tests
${EXE_FLAGS}
lg_common lg_common
) )
set(KEYBIND_CASES set(KEYBIND_CASES
@@ -668,7 +644,6 @@ target_include_directories(app-keybind-tests PRIVATE
"${PROJECT_TOP}/repos/gui/cimgui/imgui" "${PROJECT_TOP}/repos/gui/cimgui/imgui"
) )
target_link_libraries(app-keybind-tests target_link_libraries(app-keybind-tests
${EXE_FLAGS}
lg_common lg_common
lg_gui lg_gui
) )
@@ -705,7 +680,6 @@ target_include_directories(clipboard-tests PRIVATE
"${PROJECT_TOP}/repos/gui/cimgui/imgui" "${PROJECT_TOP}/repos/gui/cimgui/imgui"
) )
target_link_libraries(clipboard-tests target_link_libraries(clipboard-tests
${EXE_FLAGS}
lg_common lg_common
) )
set(CLIPBOARD_CASES set(CLIPBOARD_CASES
@@ -746,7 +720,6 @@ if(LG_CLIENT_PLATFORM_LINUX)
"${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_SOURCE_DIR}/../src"
) )
target_link_libraries(clipboard-files-tests target_link_libraries(clipboard-files-tests
${EXE_FLAGS}
lg_common lg_common
PkgConfig::FUSE3 PkgConfig::FUSE3
) )
@@ -789,7 +762,6 @@ if(ENABLE_SPICE)
"${PROJECT_TOP}/repos/gui/cimgui/imgui" "${PROJECT_TOP}/repos/gui/cimgui/imgui"
) )
target_link_libraries(spice-clipboard-tests target_link_libraries(spice-clipboard-tests
${EXE_FLAGS}
lg_common lg_common
) )
foreach(name IN ITEMS outbound inbound) foreach(name IN ITEMS outbound inbound)
@@ -811,7 +783,6 @@ target_include_directories(transport-fallback-tests PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_SOURCE_DIR}/../src"
) )
target_link_libraries(transport-fallback-tests target_link_libraries(transport-fallback-tests
${EXE_FLAGS}
lg_common lg_common
) )
if(ENABLE_AUDIO) if(ENABLE_AUDIO)
@@ -861,7 +832,6 @@ if(ENABLE_SPICE)
"${PROJECT_TOP}/repos/PureSpice/include" "${PROJECT_TOP}/repos/PureSpice/include"
) )
target_link_libraries(spice-tests target_link_libraries(spice-tests
${EXE_FLAGS}
lg_common lg_common
) )
set(SPICE_CASES set(SPICE_CASES
@@ -897,7 +867,6 @@ if(ENABLE_SPICE)
"$<TARGET_PROPERTY:purespice,INCLUDE_DIRECTORIES>" "$<TARGET_PROPERTY:purespice,INCLUDE_DIRECTORIES>"
) )
target_link_libraries(purespice-connect-cancel-tests target_link_libraries(purespice-connect-cancel-tests
${EXE_FLAGS}
purespice purespice
pthread pthread
) )
@@ -923,7 +892,6 @@ target_include_directories(frame-scheduler-tests PRIVATE
"${PROJECT_TOP}/repos/gui/cimgui/imgui" "${PROJECT_TOP}/repos/gui/cimgui/imgui"
) )
target_link_libraries(frame-scheduler-tests target_link_libraries(frame-scheduler-tests
${EXE_FLAGS}
lg_common lg_common
) )
set(FRAME_SCHEDULER_CASES set(FRAME_SCHEDULER_CASES
@@ -950,17 +918,20 @@ add_executable(frame-timing-tests
target_compile_definitions(frame-timing-tests PRIVATE target_compile_definitions(frame-timing-tests PRIVATE
CIMGUI_DEFINE_ENUMS_AND_STRUCTS=1 CIMGUI_DEFINE_ENUMS_AND_STRUCTS=1
) )
target_compile_options(frame-timing-tests PRIVATE if(MSVC)
-O1 target_compile_options(frame-timing-tests PRIVATE /clang:-O1)
"$<$<C_COMPILER_ID:GNU>:-fwhole-program>" else()
) target_compile_options(frame-timing-tests PRIVATE
-O1
"$<$<C_COMPILER_ID:GNU>:-fwhole-program>"
)
endif()
target_include_directories(frame-timing-tests PRIVATE target_include_directories(frame-timing-tests PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_SOURCE_DIR}/../src"
"${PROJECT_TOP}/repos/gui/cimgui" "${PROJECT_TOP}/repos/gui/cimgui"
"${PROJECT_TOP}/repos/gui/cimgui/imgui" "${PROJECT_TOP}/repos/gui/cimgui/imgui"
) )
target_link_libraries(frame-timing-tests target_link_libraries(frame-timing-tests
${EXE_FLAGS}
lg_common lg_common
) )
set(FRAME_TIMING_CASES set(FRAME_TIMING_CASES
@@ -1005,7 +976,6 @@ target_include_directories(config-message-tests PRIVATE
"${PROJECT_TOP}/repos/gui/cimgui/imgui" "${PROJECT_TOP}/repos/gui/cimgui/imgui"
) )
target_link_libraries(config-message-tests target_link_libraries(config-message-tests
${EXE_FLAGS}
lg_common lg_common
) )
set(CONFIG_MESSAGE_CASES set(CONFIG_MESSAGE_CASES
@@ -1042,7 +1012,6 @@ if(ENABLE_AUDIO)
"${PROJECT_TOP}/repos/gui/cimgui/imgui" "${PROJECT_TOP}/repos/gui/cimgui/imgui"
) )
target_link_libraries(audio-tests target_link_libraries(audio-tests
${EXE_FLAGS}
lg_common lg_common
${SAMPLERATE_TARGET} ${SAMPLERATE_TARGET}
) )
@@ -1082,7 +1051,6 @@ target_include_directories(render-queue-tests PRIVATE
"${PROJECT_TOP}/repos/gui/cimgui/imgui" "${PROJECT_TOP}/repos/gui/cimgui/imgui"
) )
target_link_libraries(render-queue-tests target_link_libraries(render-queue-tests
${EXE_FLAGS}
lg_common lg_common
) )
set(RENDER_QUEUE_CASES set(RENDER_QUEUE_CASES
@@ -1112,7 +1080,6 @@ if(ENABLE_EGL)
"${CMAKE_CURRENT_SOURCE_DIR}/../renderers/EGL" "${CMAKE_CURRENT_SOURCE_DIR}/../renderers/EGL"
) )
target_link_libraries(desktop-rects-tests target_link_libraries(desktop-rects-tests
${EXE_FLAGS}
renderer_EGL renderer_EGL
) )
set(DESKTOP_RECTS_CASES set(DESKTOP_RECTS_CASES
@@ -1139,7 +1106,6 @@ if(ENABLE_EGL)
"${CMAKE_BINARY_DIR}/renderers/EGL/shader" "${CMAKE_BINARY_DIR}/renderers/EGL/shader"
) )
target_link_libraries(texture-dmabuf-tests target_link_libraries(texture-dmabuf-tests
${EXE_FLAGS}
lg_common lg_common
) )
set(TEXTURE_DMABUF_CASES set(TEXTURE_DMABUF_CASES
@@ -1167,7 +1133,6 @@ if(ENABLE_EGL)
"${CMAKE_CURRENT_SOURCE_DIR}/../renderers/EGL" "${CMAKE_CURRENT_SOURCE_DIR}/../renderers/EGL"
) )
target_link_libraries(postprocess-order-tests target_link_libraries(postprocess-order-tests
${EXE_FLAGS}
lg_common lg_common
lg_egl_provider lg_egl_provider
) )
@@ -1188,7 +1153,6 @@ if(ENABLE_EGL)
"${PROJECT_TOP}/common/include" "${PROJECT_TOP}/common/include"
) )
target_link_libraries(texture-upload-tests target_link_libraries(texture-upload-tests
${EXE_FLAGS}
LGProtocol::LGProtocol LGProtocol::LGProtocol
lg_egl_provider lg_egl_provider
) )

View File

@@ -116,10 +116,10 @@ static void externalFrameInit(struct FakeExternalFrame * external)
struct EGLDynProcs g_egl_dynProcs; struct EGLDynProcs g_egl_dynProcs;
_Thread_local EGL_StateCache g_eglState; _Thread_local EGL_StateCache g_eglState;
const char b_shader_hdr_compose_vert[] = ""; const char b_shader_hdr_compose_vert[] = "";
const char b_shader_hdr_compose_vert_end[] = ""; const size_t b_shader_hdr_compose_vert_size = 1;
const char b_shader_downscale_linear_frag[] = ""; const char b_shader_downscale_linear_frag[] = "";
const char b_shader_downscale_linear_frag_end[] = ""; const size_t b_shader_downscale_linear_frag_size = 1;
static struct FakeSync * syncPtr(GLsync sync) static struct FakeSync * syncPtr(GLsync sync)
{ {

View File

@@ -5,9 +5,11 @@ add_library(transport_Test STATIC
test.c test.c
) )
target_compile_options(transport_Test PRIVATE if(MSVC)
-fno-fast-math target_compile_options(transport_Test PRIVATE /fp:precise)
) else()
target_compile_options(transport_Test PRIVATE -fno-fast-math)
endif()
target_link_libraries(transport_Test target_link_libraries(transport_Test
lg_common lg_common

View File

@@ -29,7 +29,6 @@
#include <stdatomic.h> #include <stdatomic.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#define TEST_BUFFER_COUNT 2 #define TEST_BUFFER_COUNT 2
#define TEST_PQ_LUT_SIZE 4096 #define TEST_PQ_LUT_SIZE 4096
@@ -610,7 +609,7 @@ static LG_TransportStatus test_nextFrame(LG_Transport * this, bool useDMA,
{ {
if (!this->holdLastFrame) if (!this->holdLastFrame)
return LG_TRANSPORT_END; return LG_TRANSPORT_END;
usleep(1000); nsleep(UINT64_C(1000000));
return LG_TRANSPORT_TIMEOUT; return LG_TRANSPORT_TIMEOUT;
} }
@@ -620,7 +619,8 @@ static LG_TransportStatus test_nextFrame(LG_Transport * this, bool useDMA,
if (now < this->nextFrameTime) if (now < this->nextFrameTime)
{ {
const uint64_t remaining = this->nextFrameTime - now; const uint64_t remaining = this->nextFrameTime - now;
usleep((remaining > 1000000 ? 1000000 : remaining) / 1000); nsleep(remaining > UINT64_C(1000000) ?
UINT64_C(1000000) : remaining);
return LG_TRANSPORT_TIMEOUT; return LG_TRANSPORT_TIMEOUT;
} }
} }
@@ -741,7 +741,7 @@ static LG_TransportStatus test_nextPointer(LG_Transport * this,
{ {
if (!this->connected) if (!this->connected)
return LG_TRANSPORT_DISCONNECTED; return LG_TRANSPORT_DISCONNECTED;
usleep(1000); nsleep(UINT64_C(1000000));
return LG_TRANSPORT_TIMEOUT; return LG_TRANSPORT_TIMEOUT;
} }

15
client/vcpkg.json Normal file
View File

@@ -0,0 +1,15 @@
{
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
"name": "looking-glass-client",
"version-string": "0",
"dependencies": [
{
"name": "angle",
"platform": "windows"
},
{
"name": "libsamplerate",
"platform": "windows"
}
]
}

View File

@@ -1,34 +1,156 @@
if(LG_MAKE_OBJECT_ACTION STREQUAL "EMBED")
if(NOT DEFINED LG_MAKE_OBJECT_INPUT OR
NOT DEFINED LG_MAKE_OBJECT_SOURCE OR
NOT DEFINED LG_MAKE_OBJECT_HEADER OR
NOT DEFINED LG_MAKE_OBJECT_SYMBOL)
message(FATAL_ERROR
"The embed action requires input, source, header, and symbol")
endif()
file(READ "${LG_MAKE_OBJECT_INPUT}" LG_MAKE_OBJECT_DATA HEX)
set(LG_MAKE_OBJECT_BYTES "")
string(LENGTH "${LG_MAKE_OBJECT_DATA}" LG_MAKE_OBJECT_LENGTH)
set(LG_MAKE_OBJECT_OFFSET 0)
while(LG_MAKE_OBJECT_OFFSET LESS LG_MAKE_OBJECT_LENGTH)
math(EXPR LG_MAKE_OBJECT_REMAINING
"${LG_MAKE_OBJECT_LENGTH} - ${LG_MAKE_OBJECT_OFFSET}")
if(LG_MAKE_OBJECT_REMAINING GREATER 32)
set(LG_MAKE_OBJECT_CHUNK_LENGTH 32)
else()
set(LG_MAKE_OBJECT_CHUNK_LENGTH "${LG_MAKE_OBJECT_REMAINING}")
endif()
string(SUBSTRING "${LG_MAKE_OBJECT_DATA}"
${LG_MAKE_OBJECT_OFFSET} ${LG_MAKE_OBJECT_CHUNK_LENGTH}
LG_MAKE_OBJECT_CHUNK)
string(REGEX REPLACE "([0-9a-fA-F][0-9a-fA-F])"
"(char)0x\\1, " LG_MAKE_OBJECT_CHUNK "${LG_MAKE_OBJECT_CHUNK}")
string(APPEND LG_MAKE_OBJECT_BYTES
" ${LG_MAKE_OBJECT_CHUNK}\n")
math(EXPR LG_MAKE_OBJECT_OFFSET
"${LG_MAKE_OBJECT_OFFSET} + ${LG_MAKE_OBJECT_CHUNK_LENGTH}")
endwhile()
get_filename_component(LG_MAKE_OBJECT_SOURCE_DIR
"${LG_MAKE_OBJECT_SOURCE}" DIRECTORY)
get_filename_component(LG_MAKE_OBJECT_HEADER_DIR
"${LG_MAKE_OBJECT_HEADER}" DIRECTORY)
file(MAKE_DIRECTORY
"${LG_MAKE_OBJECT_SOURCE_DIR}"
"${LG_MAKE_OBJECT_HEADER_DIR}")
file(WRITE "${LG_MAKE_OBJECT_SOURCE}"
"#include <stddef.h>\n\n"
"const char ${LG_MAKE_OBJECT_SYMBOL}[] =\n"
"{\n${LG_MAKE_OBJECT_BYTES} (char)0x00\n};\n\n"
"const size_t ${LG_MAKE_OBJECT_SYMBOL}_size =\n"
" sizeof(${LG_MAKE_OBJECT_SYMBOL});\n")
file(WRITE "${LG_MAKE_OBJECT_HEADER}"
"#include <stddef.h>\n\n"
"extern const char ${LG_MAKE_OBJECT_SYMBOL}[];\n"
"extern const size_t ${LG_MAKE_OBJECT_SYMBOL}_size;\n")
return()
endif()
function(_lg_expand_includes input include_dir output_var)
file(READ "${input}" content)
string(REGEX MATCH
"(^|\n)#include[ \t]*\"([^\"]+)\"[ \t\r]*(\n|$)" include_match
"${content}")
while(include_match)
set(include_prefix "${CMAKE_MATCH_1}")
set(include_name "${CMAKE_MATCH_2}")
set(include_line "${include_match}")
set(include_path "${include_dir}/${include_name}")
if(NOT EXISTS "${include_path}")
message(FATAL_ERROR
"Unable to resolve ${include_name} included by ${input}")
endif()
_lg_expand_includes("${include_path}" "${include_dir}" include_content)
if(NOT "${include_content}" MATCHES "\n$")
string(APPEND include_content "\n")
endif()
string(REPLACE "${include_line}"
"${include_prefix}${include_content}" content
"${content}")
string(REGEX MATCH
"(^|\n)#include[ \t]*\"([^\"]+)\"[ \t\r]*(\n|$)" include_match
"${content}")
endwhile()
set(${output_var} "${content}" PARENT_SCOPE)
endfunction()
if(LG_MAKE_OBJECT_ACTION STREQUAL "PREPROCESS")
if(NOT DEFINED LG_MAKE_OBJECT_INPUT OR
NOT DEFINED LG_MAKE_OBJECT_OUTPUT OR
NOT DEFINED LG_MAKE_OBJECT_INCLUDE_DIR)
message(FATAL_ERROR
"The preprocess action requires input, output, and include directory")
endif()
_lg_expand_includes(
"${LG_MAKE_OBJECT_INPUT}"
"${LG_MAKE_OBJECT_INCLUDE_DIR}"
LG_MAKE_OBJECT_DATA)
get_filename_component(LG_MAKE_OBJECT_OUTPUT_DIR
"${LG_MAKE_OBJECT_OUTPUT}" DIRECTORY)
file(MAKE_DIRECTORY "${LG_MAKE_OBJECT_OUTPUT_DIR}")
file(WRITE "${LG_MAKE_OBJECT_OUTPUT}" "${LG_MAKE_OBJECT_DATA}")
return()
endif()
if(LG_MAKE_OBJECT_ACTION STREQUAL "DEFINES")
if(NOT DEFINED LG_MAKE_OBJECT_INPUT OR
NOT DEFINED LG_MAKE_OBJECT_OUTPUT)
message(FATAL_ERROR "The defines action requires input and output")
endif()
file(STRINGS "${LG_MAKE_OBJECT_INPUT}" LG_MAKE_OBJECT_DEFINES
REGEX "^#define")
set(LG_MAKE_OBJECT_DATA "")
foreach(LG_MAKE_OBJECT_DEFINE IN LISTS LG_MAKE_OBJECT_DEFINES)
string(APPEND LG_MAKE_OBJECT_DATA "${LG_MAKE_OBJECT_DEFINE}\n")
endforeach()
get_filename_component(LG_MAKE_OBJECT_OUTPUT_DIR
"${LG_MAKE_OBJECT_OUTPUT}" DIRECTORY)
file(MAKE_DIRECTORY "${LG_MAKE_OBJECT_OUTPUT_DIR}")
file(WRITE "${LG_MAKE_OBJECT_OUTPUT}" "${LG_MAKE_OBJECT_DATA}")
return()
endif()
set(LG_MAKE_OBJECT_SCRIPT "${CMAKE_CURRENT_LIST_FILE}")
function(make_object out_var) function(make_object out_var)
set(result) set(result)
set(result_h) set(result_h)
foreach(in_f ${ARGN}) foreach(in_f ${ARGN})
file(RELATIVE_PATH out_f ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/${in_f}") file(RELATIVE_PATH out_f ${CMAKE_CURRENT_SOURCE_DIR}
set(out_h "${CMAKE_CURRENT_BINARY_DIR}/${out_f}.h") "${CMAKE_CURRENT_SOURCE_DIR}/${in_f}")
set(out_f "${out_f}.o") set(in_path "${CMAKE_CURRENT_SOURCE_DIR}/${in_f}")
set(out_h "${CMAKE_CURRENT_BINARY_DIR}/${out_f}.h")
set(out_c "${CMAKE_CURRENT_BINARY_DIR}/${out_f}.c")
string(REGEX REPLACE "[/.-]" "_" sym_in "${in_f}") string(REGEX REPLACE "[/.-]" "_" sym_in "${in_f}")
add_custom_command(OUTPUT ${out_f} add_custom_command(
COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/${in_f} ${out_f}.tmp OUTPUT "${out_c}" "${out_h}"
COMMAND dd if=/dev/zero bs=1 count=1 of=${out_f}.tmp oflag=append conv=notrunc status=none COMMAND "${CMAKE_COMMAND}"
COMMAND ${CMAKE_LINKER} -r -b binary -o ${out_f} ${out_f}.tmp "-DLG_MAKE_OBJECT_ACTION=EMBED"
COMMAND ${CMAKE_OBJCOPY} --rename-section .data=.rodata,CONTENTS,ALLOC,LOAD,READONLY,DATA ${out_f} ${out_f} "-DLG_MAKE_OBJECT_INPUT=${in_path}"
COMMAND ${CMAKE_OBJCOPY} --redefine-sym _binary_${sym_in}_o_tmp_start=b_${sym_in} ${out_f} ${out_f} "-DLG_MAKE_OBJECT_SOURCE=${out_c}"
COMMAND ${CMAKE_OBJCOPY} --redefine-sym _binary_${sym_in}_o_tmp_end=b_${sym_in}_end ${out_f} ${out_f} "-DLG_MAKE_OBJECT_HEADER=${out_h}"
COMMAND ${CMAKE_OBJCOPY} --redefine-sym _binary_${sym_in}_o_tmp_size=b_${sym_in}_size ${out_f} ${out_f} "-DLG_MAKE_OBJECT_SYMBOL=b_${sym_in}"
COMMAND ${CMAKE_OBJCOPY} --strip-symbol _binary_${sym_in}_size ${out_f} ${out_f} -P "${LG_MAKE_OBJECT_SCRIPT}"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${in_f}" DEPENDS "${in_path}" "${LG_MAKE_OBJECT_SCRIPT}"
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Embedding ${in_f}"
COMMENT "Creating object from ${in_f}"
VERBATIM VERBATIM
) )
file(WRITE ${out_h} "extern const char b_${sym_in}[];\n") get_filename_component(h_dir "${out_h}" DIRECTORY)
file(APPEND ${out_h} "extern const char b_${sym_in}_end[];\n") list(APPEND result_h "${h_dir}")
file(APPEND ${out_h} "#define b_${sym_in}_size (b_${sym_in}_end - b_${sym_in})\n") list(APPEND result "${out_c}")
get_filename_component(h_dir ${out_h} DIRECTORY)
list(APPEND result_h ${h_dir})
list(APPEND result ${out_f})
endforeach() endforeach()
list(REMOVE_DUPLICATES result_h) list(REMOVE_DUPLICATES result_h)
@@ -38,9 +160,15 @@ endfunction()
function(make_defines in_file out_file) function(make_defines in_file out_file)
file(RELATIVE_PATH rel_f ${CMAKE_CURRENT_SOURCE_DIR} "${in_file}") file(RELATIVE_PATH rel_f ${CMAKE_CURRENT_SOURCE_DIR} "${in_file}")
add_custom_command(OUTPUT ${out_file} add_custom_command(
COMMAND grep "^#define" "${in_file}" > "${out_file}" OUTPUT "${out_file}"
DEPENDS ${in_file} COMMAND "${CMAKE_COMMAND}"
COMMENT "Creating #defines from ${rel_f}" "-DLG_MAKE_OBJECT_ACTION=DEFINES"
"-DLG_MAKE_OBJECT_INPUT=${in_file}"
"-DLG_MAKE_OBJECT_OUTPUT=${out_file}"
-P "${LG_MAKE_OBJECT_SCRIPT}"
DEPENDS "${in_file}" "${LG_MAKE_OBJECT_SCRIPT}"
COMMENT "Extracting definitions from ${rel_f}"
VERBATIM
) )
endfunction() endfunction()

View File

@@ -77,7 +77,6 @@ function(lg_add_static_msquic)
set(LG_MSQUIC_BINARY_DIR "${CMAKE_BINARY_DIR}/MsQuic") set(LG_MSQUIC_BINARY_DIR "${CMAKE_BINARY_DIR}/MsQuic")
set(LG_MSQUIC_SYSTEM_LIBRARIES set(LG_MSQUIC_SYSTEM_LIBRARIES
ws2_32 ws2_32
schannel
ntdll ntdll
bcrypt bcrypt
ncrypt ncrypt
@@ -106,8 +105,41 @@ function(lg_add_static_msquic)
endif() endif()
if(MSVC) if(MSVC)
if(NOT CMAKE_GENERATOR MATCHES "^Ninja")
message(FATAL_ERROR
"The native Windows MsQuic build requires Ninja or Ninja "
"Multi-Config")
endif()
if(NOT EXISTS
"${LG_MSQUIC_SOURCE_DIR}/submodules/openssl/Configure")
message(FATAL_ERROR
"The MsQuic OpenSSL submodule is not initialized; run "
"git submodule update --init --recursive")
endif()
find_program(LG_MSQUIC_CL NAMES cl REQUIRED)
find_program(LG_MSQUIC_NMAKE NAMES nmake REQUIRED)
find_program(LG_MSQUIC_NASM NAMES nasm REQUIRED)
find_program(LG_MSQUIC_PERL NAMES perl REQUIRED)
list(APPEND LG_MSQUIC_CMAKE_ARGS list(APPEND LG_MSQUIC_CMAKE_ARGS
"-DQUIC_TLS_LIB=schannel") "-DQUIC_TLS_LIB=openssl"
"-DQUIC_USE_EXTERNAL_OPENSSL=OFF"
"-DQUIC_USE_SYSTEM_LIBCRYPTO=OFF"
"-DQUIC_OPENSSL_INCLUDE_DIR="
"-DQUIC_OPENSSL_LIB_DIR="
"-DQUIC_OPENSSL_ROOT_DIR="
"-DCMAKE_C_COMPILER=${LG_MSQUIC_CL}"
"-DCMAKE_CXX_COMPILER=${LG_MSQUIC_CL}")
if(NOT CMAKE_CONFIGURATION_TYPES)
list(APPEND LG_MSQUIC_CMAKE_ARGS
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
endif()
list(APPEND LG_MSQUIC_SYSTEM_LIBRARIES
gdi32
user32
wbemuuid
winmm)
set(LG_MSQUIC_RELEASE_LIBRARY set(LG_MSQUIC_RELEASE_LIBRARY
"${LG_MSQUIC_BINARY_DIR}/bin/Release/msquic.lib") "${LG_MSQUIC_BINARY_DIR}/bin/Release/msquic.lib")
endif() endif()

View File

@@ -2,18 +2,36 @@ set(OPTIMIZE_FOR_NATIVE AUTO CACHE STRING "Build with -march=native")
set_property(CACHE OPTIMIZE_FOR_NATIVE PROPERTY STRINGS AUTO ON OFF) set_property(CACHE OPTIMIZE_FOR_NATIVE PROPERTY STRINGS AUTO ON OFF)
set(OPTIMIZE_FOR_NATIVE_ARCH "none") set(OPTIMIZE_FOR_NATIVE_ARCH "none")
if(OPTIMIZE_FOR_NATIVE STREQUAL "ON" OR (OPTIMIZE_FOR_NATIVE STREQUAL "AUTO" AND OPTIMIZE_FOR_NATIVE_DEFAULT)) if(MSVC AND CMAKE_C_COMPILER_ID STREQUAL "Clang")
CHECK_C_COMPILER_FLAG("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE) set(OPTIMIZE_FOR_NATIVE_PREFIX "/clang:-march=")
elseif(MSVC)
set(OPTIMIZE_FOR_NATIVE_PREFIX "")
else()
set(OPTIMIZE_FOR_NATIVE_PREFIX "-march=")
endif()
if(NOT OPTIMIZE_FOR_NATIVE_PREFIX)
if(OPTIMIZE_FOR_NATIVE STREQUAL "ON" OR
NOT OPTIMIZE_FOR_NATIVE MATCHES "^(AUTO|OFF)$")
message(WARNING
"OPTIMIZE_FOR_NATIVE is not supported by ${CMAKE_C_COMPILER_ID}")
endif()
elseif(OPTIMIZE_FOR_NATIVE STREQUAL "ON" OR
(OPTIMIZE_FOR_NATIVE STREQUAL "AUTO" AND OPTIMIZE_FOR_NATIVE_DEFAULT))
CHECK_C_COMPILER_FLAG("${OPTIMIZE_FOR_NATIVE_PREFIX}native"
COMPILER_SUPPORTS_MARCH_NATIVE)
if(COMPILER_SUPPORTS_MARCH_NATIVE) if(COMPILER_SUPPORTS_MARCH_NATIVE)
set(OPTIMIZE_FOR_NATIVE_ARCH "native") set(OPTIMIZE_FOR_NATIVE_ARCH "native")
set(OPTIMIZE_FOR_NATIVE_ON ON) set(OPTIMIZE_FOR_NATIVE_ON ON)
endif() endif()
elseif(OPTIMIZE_FOR_NATIVE STREQUAL "AUTO" OR OPTIMIZE_FOR_NATIVE STREQUAL "OFF") elseif(OPTIMIZE_FOR_NATIVE STREQUAL "AUTO" OR OPTIMIZE_FOR_NATIVE STREQUAL "OFF")
CHECK_C_COMPILER_FLAG("-march=x86-64-v2" COMPILER_SUPPORTS_MARCH_X86_64_V2) CHECK_C_COMPILER_FLAG("${OPTIMIZE_FOR_NATIVE_PREFIX}x86-64-v2"
COMPILER_SUPPORTS_MARCH_X86_64_V2)
if(COMPILER_SUPPORTS_MARCH_X86_64_V2) if(COMPILER_SUPPORTS_MARCH_X86_64_V2)
set(OPTIMIZE_FOR_NATIVE_ARCH "x86-64-v2") set(OPTIMIZE_FOR_NATIVE_ARCH "x86-64-v2")
else() else()
CHECK_C_COMPILER_FLAG("-march=nehalem" COMPILER_SUPPORTS_MARCH_NEHALEM) CHECK_C_COMPILER_FLAG("${OPTIMIZE_FOR_NATIVE_PREFIX}nehalem"
COMPILER_SUPPORTS_MARCH_NEHALEM)
if(COMPILER_SUPPORTS_MARCH_NEHALEM) if(COMPILER_SUPPORTS_MARCH_NEHALEM)
set(OPTIMIZE_FOR_NATIVE_ARCH "nehalem") set(OPTIMIZE_FOR_NATIVE_ARCH "nehalem")
endif() endif()
@@ -24,7 +42,8 @@ else()
endif() endif()
if(NOT OPTIMIZE_FOR_NATIVE_ARCH STREQUAL "none") if(NOT OPTIMIZE_FOR_NATIVE_ARCH STREQUAL "none")
add_compile_options("-march=${OPTIMIZE_FOR_NATIVE_ARCH}") add_compile_options(
"${OPTIMIZE_FOR_NATIVE_PREFIX}${OPTIMIZE_FOR_NATIVE_ARCH}")
endif() endif()
add_feature_info(OPTIMIZE_FOR_NATIVE OPTIMIZE_FOR_NATIVE_ON "Optimized for ${OPTIMIZE_FOR_NATIVE_ARCH}") add_feature_info(OPTIMIZE_FOR_NATIVE OPTIMIZE_FOR_NATIVE_ON "Optimized for ${OPTIMIZE_FOR_NATIVE_ARCH}")

View File

@@ -7,7 +7,9 @@ include_directories(
${PROJECT_SOURCE_DIR}/include ${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") if (CMAKE_C_COMPILER_ID STREQUAL "Clang")
add_compile_options( add_compile_options(

View File

@@ -23,6 +23,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdarg.h>
// vsprintf but with buffer allocation // vsprintf but with buffer allocation
int valloc_sprintf(char ** str, const char * format, va_list ap) 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. // Find value in a list separated by delimiter.
bool str_containsValue(const char * list, char delimiter, const char * value); 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 // 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 // copy a potentially unterminated string into a null-terminated buffer
void str_copy(char * dst, size_t dstSize, const char * src, size_t srcSize); void str_copy(char * dst, size_t dstSize, const char * src, size_t srcSize);

View File

@@ -32,7 +32,6 @@
#include <emmintrin.h> #include <emmintrin.h>
#include <smmintrin.h> #include <smmintrin.h>
#include <immintrin.h> #include <immintrin.h>
#include <unistd.h>
static bool framebuffer_size_mul(size_t a, size_t b, size_t * result) 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; *waitTimeNs += nanotime() - waitStart;
return false; 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) static bool bool_parser(struct Option * opt, const char * str)
{ {
opt->value.x_bool = opt->value.x_bool =
strcasecmp(str, "1" ) == 0 || lg_strcasecmp(str, "1" ) == 0 ||
strcasecmp(str, "on" ) == 0 || lg_strcasecmp(str, "on" ) == 0 ||
strcasecmp(str, "yes" ) == 0 || lg_strcasecmp(str, "yes" ) == 0 ||
strcasecmp(str, "true") == 0; lg_strcasecmp(str, "true") == 0;
return true; return true;
} }
@@ -343,13 +343,14 @@ bool option_parse(int argc, char * argv[])
// emulate getopt for backwards compatability // emulate getopt for backwards compatability
if (argv[a][0] == '-') 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; state.doHelp = DOHELP_MODE_YES;
continue; continue;
} }
if (strcasecmp(argv[a], "--rst-help") == 0) if (lg_strcasecmp(argv[a], "--rst-help") == 0)
{ {
state.doHelp = DOHELP_MODE_RST; state.doHelp = DOHELP_MODE_RST;
continue; continue;
@@ -925,13 +926,14 @@ struct Option * option_get(const char * module, const char * name)
for(int i = 0; i < state.oCount; ++i) for(int i = 0; i < state.oCount; ++i)
{ {
struct Option * o = state.options[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; return o;
// check for usage of renamed options // check for usage of renamed options
if (o->old_module && o->old_name && if (o->old_module && o->old_name &&
(strcasecmp(o->old_module, module) == 0) && (lg_strcasecmp(o->old_module, module) == 0) &&
(strcasecmp(o->old_name , name) == 0)) (lg_strcasecmp(o->old_name , name) == 0))
{ {
// not fatal, but be noisy // not fatal, but be noisy
DEBUG_WARN( DEBUG_WARN(

View File

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

View File

@@ -19,6 +19,7 @@
*/ */
#include <stdbool.h> #include <stdbool.h>
#include <ctype.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
@@ -92,7 +93,48 @@ bool str_containsValue(const char * list, char delimiter, const char * value)
return false; 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) if (!s)
{ {
@@ -100,8 +142,8 @@ char * lg_strdup(const char *s)
return NULL; return NULL;
} }
const ssize_t len = strlen(s) + 1; const size_t len = strlen(s) + 1;
char * out = malloc(len); char * out = malloc(len);
if (!out) if (!out)
{ {
errno = ENOMEM; errno = ENOMEM;

View File

@@ -0,0 +1,44 @@
.. _build_client_windows:
Build the Windows client
########################
The Windows client uses ``clang-cl`` and the MSVC ABI. ANGLE continues to
provide EGL and OpenGL ES, while MsQuic and its bundled OpenSSL are linked
statically.
Requirements
------------
Install the following tools:
- Visual Studio 2022 Build Tools with the Desktop development with C++
workload, Clang tools for Windows, and a Windows SDK
- CMake 3.21 or newer
- Ninja
- Git
- Perl
- NASM
- vcpkg
Set ``VCPKG_ROOT`` to the vcpkg checkout. The client manifest installs native
MSVC-ABI builds of ANGLE and libsamplerate automatically.
Building
--------
Open an x64 Native Tools command prompt or Developer PowerShell, then run:
.. code:: powershell
git submodule update --init --recursive
cd client
cmake --preset windows-clangcl
cmake --build --preset windows-clangcl-release
The executable is written beneath ``client/build/windows-clangcl``. The
vcpkg toolchain copies the required ANGLE and libsamplerate runtime DLLs
beside it.
The native build deliberately does not consume MinGW ``.a`` or ``.dll.a``
libraries. All statically linked code must use the MSVC ABI.

View File

@@ -13,6 +13,7 @@ memory for frames, and a native Linux client for display and input.
quickstart quickstart
build build
build_client_windows
install install
usage usage

View File

@@ -1,3 +1,5 @@
ABI
ANGLE
Anime4K Anime4K
backend backend
backends backends
@@ -9,6 +11,7 @@ cadence
cgroups cgroups
checkboxes checkboxes
clang clang
clang-cl
cmake cmake
codec codec
compositor compositor
@@ -53,6 +56,7 @@ lexically
libdecor libdecor
libpipewire libpipewire
libpulse libpulse
libsamplerate
libvirt libvirt
linux linux
LookingGlass LookingGlass
@@ -65,9 +69,12 @@ mingw
mipmapping mipmapping
modprobe modprobe
mpv mpv
MsQuic
MSVC
msys msys
multisampling multisampling
namespace namespace
NASM
Navi Navi
NvFBC NvFBC
Nvidia Nvidia
@@ -123,6 +130,7 @@ upscaled
upscaler upscaler
upscales upscales
upscaling upscaling
vcpkg
viewport viewport
virt virt
VirtIO VirtIO

View File

@@ -12,15 +12,25 @@ add_library(lg_gui STATIC
cimplot/implot/implot_items.cpp cimplot/implot/implot_items.cpp
) )
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") if(MSVC)
target_compile_options(lg_gui PRIVATE /fp:precise)
set_source_files_properties(cimgui/cimgui.cpp PROPERTIES
COMPILE_OPTIONS "/clang:-Wno-error=unused-function"
)
set_source_files_properties(cimplot/cimplot.cpp PROPERTIES
COMPILE_OPTIONS
"/clang:-Wno-error=array-bounds;/clang:-Wno-error=unused-function"
)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options(lg_gui PRIVATE "-fno-fast-math") target_compile_options(lg_gui PRIVATE "-fno-fast-math")
set_source_files_properties(cimgui/cimgui.cpp PROPERTIES set_source_files_properties(cimgui/cimgui.cpp PROPERTIES
COMPILE_FLAGS "-Wno-error=unused-function" COMPILE_OPTIONS "-Wno-error=unused-function"
) )
set_source_files_properties(cimplot/cimplot.cpp PROPERTIES set_source_files_properties(cimplot/cimplot.cpp PROPERTIES
COMPILE_FLAGS COMPILE_OPTIONS
"-Wno-error=array-bounds -Wno-error=unused-function" "-Wno-error=array-bounds;-Wno-error=unused-function"
) )
endif() endif()