From 84674fc4ea3226b4516d057ff570196d7d954a84 Mon Sep 17 00:00:00 2001 From: nblog <503407184@qq.com> Date: Thu, 5 Feb 2026 13:58:53 +0800 Subject: [PATCH] Enhance Windows compatibility and improve CMake configurations - Adjust MSVC compiler options and add definitions for better compatibility. - Modify CMakeLists to set appropriate output names for static libraries on Windows. - Update logging and network handling for improved signal management and data availability checks. - Introduce vcpkg.json for dependency management. --- CMakeLists.txt | 48 ++++++++++++++++------ examples/mcp/mcp_example_server.cc | 3 +- include/mcp/buffer.h | 6 +++ include/mcp/event/libevent_dispatcher.h | 2 +- include/mcp/filter/request_logger_filter.h | 1 + include/mcp/logging/log_message.h | 7 ++++ include/mcp/network/address.h | 4 ++ src/c_api/CMakeLists.txt | 13 +++--- src/config/file_config_source.cc | 1 + src/echo/echo_stdio_transport_advanced.cc | 1 + src/logging/CMakeLists.txt | 18 +++++--- src/network/connection_impl.cc | 5 +++ vcpkg.json | 6 +++ 13 files changed, 90 insertions(+), 25 deletions(-) create mode 100644 vcpkg.json diff --git a/CMakeLists.txt b/CMakeLists.txt index 923f52cc4..8c0ded52e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,8 +107,10 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") add_compile_options(-O3) endif() elseif(MSVC) - add_compile_options(/W4 /WX) -endif() + add_compile_options(/W3) + add_compile_definitions(NOMINMAX) + add_compile_definitions(WIN32_LEAN_AND_MEAN) + endif() # Memory sanitizer options for debugging option(ENABLE_ASAN "Enable AddressSanitizer for memory error detection" OFF) @@ -222,7 +224,10 @@ if(MCP_USE_LLHTTP) ) message(STATUS "Downloading llhttp... This may take a moment depending on your connection speed.") - FetchContent_MakeAvailable(llhttp) + FetchContent_GetProperties(llhttp) + if(NOT llhttp_POPULATED) + FetchContent_Populate(llhttp) + endif() message(STATUS "llhttp download complete.") # Build llhttp as a simple static library @@ -230,15 +235,15 @@ if(MCP_USE_LLHTTP) file(GLOB LLHTTP_SOURCES ${llhttp_SOURCE_DIR}/src/*.c) if(NOT TARGET llhttp) - add_library(llhttp STATIC ${LLHTTP_SOURCES}) - target_include_directories(llhttp PUBLIC ${llhttp_SOURCE_DIR}/include) + add_library(llhttp STATIC ${LLHTTP_SOURCES}) + target_include_directories(llhttp PUBLIC ${llhttp_SOURCE_DIR}/include) - # Enable position-independent code for shared library linking - set_target_properties(llhttp PROPERTIES POSITION_INDEPENDENT_CODE ON) + # Enable position-independent code for shared library linking + set_target_properties(llhttp PROPERTIES POSITION_INDEPENDENT_CODE ON) - # Disable warnings for third-party code - if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") - target_compile_options(llhttp PRIVATE -w) + # Disable warnings for third-party code + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + target_compile_options(llhttp PRIVATE -w) endif() endif() @@ -512,8 +517,12 @@ set(MCP_SDK_SOURCES ${MCP_CORE_SOURCES} ${MCP_CLIENT_SERVER_SOURCES} ${MCP_EVENT if(BUILD_STATIC_LIBS) add_library(gopher-mcp-static STATIC ${MCP_SDK_SOURCES} ${MCP_HTTP_SOURCES}) + if(WIN32) + set_target_properties(gopher-mcp-static PROPERTIES OUTPUT_NAME gopher-mcp-static) + else() + set_target_properties(gopher-mcp-static PROPERTIES OUTPUT_NAME gopher-mcp) + endif() set_target_properties(gopher-mcp-static PROPERTIES - OUTPUT_NAME gopher-mcp POSITION_INDEPENDENT_CODE ON VERSION ${GOPHER_MCP_VERSION} SOVERSION ${GOPHER_MCP_VERSION_MAJOR} @@ -654,8 +663,12 @@ endif() # Create Gopher MCP Echo Advanced libraries if(BUILD_STATIC_LIBS) add_library(gopher-mcp-echo-advanced-static STATIC ${MCP_ECHO_ADVANCED_SOURCES}) + if(WIN32) + set_target_properties(gopher-mcp-echo-advanced-static PROPERTIES OUTPUT_NAME gopher-mcp-echo-advanced-static) + else() + set_target_properties(gopher-mcp-echo-advanced-static PROPERTIES OUTPUT_NAME gopher-mcp-echo-advanced) + endif() set_target_properties(gopher-mcp-echo-advanced-static PROPERTIES - OUTPUT_NAME gopher-mcp-echo-advanced POSITION_INDEPENDENT_CODE ON ) endif() @@ -666,6 +679,7 @@ if(BUILD_SHARED_LIBS) VERSION ${GOPHER_MCP_VERSION} SOVERSION ${GOPHER_MCP_VERSION_MAJOR} POSITION_INDEPENDENT_CODE ON + WINDOWS_EXPORT_ALL_SYMBOLS ON ) else() add_library(gopher-mcp-echo-advanced ALIAS gopher-mcp-echo-advanced-static) @@ -704,8 +718,12 @@ endforeach() # Create Gopher MCP Event libraries if(BUILD_STATIC_LIBS) add_library(gopher-mcp-event-static STATIC ${MCP_EVENT_SOURCES}) + if(WIN32) + set_target_properties(gopher-mcp-event-static PROPERTIES OUTPUT_NAME gopher-mcp-event-static) + else() + set_target_properties(gopher-mcp-event-static PROPERTIES OUTPUT_NAME gopher-mcp-event) + endif() set_target_properties(gopher-mcp-event-static PROPERTIES - OUTPUT_NAME gopher-mcp-event POSITION_INDEPENDENT_CODE ON ) endif() @@ -716,6 +734,7 @@ if(BUILD_SHARED_LIBS) VERSION ${GOPHER_MCP_VERSION} SOVERSION ${GOPHER_MCP_VERSION_MAJOR} POSITION_INDEPENDENT_CODE ON + WINDOWS_EXPORT_ALL_SYMBOLS ON ) else() add_library(gopher-mcp-event ALIAS gopher-mcp-event-static) @@ -754,6 +773,9 @@ foreach(lib_target ${EVENT_REAL_TARGETS}) target_link_directories(${lib_target} PUBLIC ${LIBEVENT_LIBRARY_DIRS}) endif() target_link_libraries(${lib_target} PUBLIC ${LIBEVENT_LIBRARIES}) + if(WIN32) + target_link_libraries(${lib_target} PUBLIC ws2_32) + endif() endif() endif() endforeach() diff --git a/examples/mcp/mcp_example_server.cc b/examples/mcp/mcp_example_server.cc index 7e82a2c39..5aa1c3d3f 100644 --- a/examples/mcp/mcp_example_server.cc +++ b/examples/mcp/mcp_example_server.cc @@ -181,6 +181,8 @@ void setupLogging(bool verbose) { #ifdef _WIN32 // Windows Console Control Handler BOOL WINAPI ConsoleCtrlHandler(DWORD ctrlType) { + static std::atomic signal_count(0); + switch (ctrlType) { case CTRL_C_EVENT: case CTRL_BREAK_EVENT: @@ -196,7 +198,6 @@ BOOL WINAPI ConsoleCtrlHandler(DWORD ctrlType) { g_shutdown_cv.notify_all(); // For safety, if we receive multiple signals, force exit - static std::atomic signal_count(0); signal_count++; if (signal_count > 1) { std::cerr << "\n[INFO] Force shutdown after multiple signals..." diff --git a/include/mcp/buffer.h b/include/mcp/buffer.h index fd1e50f5b..eeac249dc 100644 --- a/include/mcp/buffer.h +++ b/include/mcp/buffer.h @@ -12,6 +12,12 @@ #include "mcp/core/compat.h" +// msvc does not define ssize_t by default +#if defined(_MSC_VER) +#include +typedef SSIZE_T ssize_t; +#endif + namespace mcp { // Forward declarations diff --git a/include/mcp/event/libevent_dispatcher.h b/include/mcp/event/libevent_dispatcher.h index 8a275b7b5..eab5d1799 100644 --- a/include/mcp/event/libevent_dispatcher.h +++ b/include/mcp/event/libevent_dispatcher.h @@ -16,7 +16,7 @@ namespace mcp { namespace event { // Rename to avoid conflict with struct event -using libevent_event = struct event; +using libevent_event = struct ::event; // Use libevent's socket type for callback signature compatibility. // On Windows, libevent uses intptr_t (SOCKET), on POSIX it uses int. diff --git a/include/mcp/filter/request_logger_filter.h b/include/mcp/filter/request_logger_filter.h index e55e8643c..6c4965f5e 100644 --- a/include/mcp/filter/request_logger_filter.h +++ b/include/mcp/filter/request_logger_filter.h @@ -14,6 +14,7 @@ #include #include #include +#include #include "mcp/core/compat.h" #include "mcp/json/json_serialization.h" diff --git a/include/mcp/logging/log_message.h b/include/mcp/logging/log_message.h index 93e37b8a3..31dac2eef 100644 --- a/include/mcp/logging/log_message.h +++ b/include/mcp/logging/log_message.h @@ -4,7 +4,14 @@ #include #include #include + +#if defined(_WIN32) +#include +using pid_t = int; +inline pid_t getpid() { return _getpid(); } +#else #include +#endif #include "mcp/logging/log_level.h" diff --git a/include/mcp/network/address.h b/include/mcp/network/address.h index d77454415..c0be3744f 100644 --- a/include/mcp/network/address.h +++ b/include/mcp/network/address.h @@ -17,6 +17,10 @@ #define _SOCKLEN_T_DEFINED typedef int socklen_t; #endif +#ifndef _MODE_T_DEFINED +#define _MODE_T_DEFINED +typedef int mode_t; +#endif #else #include #include diff --git a/src/c_api/CMakeLists.txt b/src/c_api/CMakeLists.txt index 5dce2d0d6..80f59fed2 100644 --- a/src/c_api/CMakeLists.txt +++ b/src/c_api/CMakeLists.txt @@ -182,11 +182,14 @@ option(BUILD_C_API_STATIC "Build static C API library" ON) if(BUILD_C_API_STATIC) add_library(gopher_mcp_c_static STATIC ${MCP_C_API_SOURCES}) - - set_target_properties(gopher_mcp_c_static PROPERTIES - OUTPUT_NAME gopher_mcp_c - POSITION_INDEPENDENT_CODE ON - ) + if(WIN32) + set_target_properties(gopher_mcp_c_static PROPERTIES OUTPUT_NAME gopher_mcp_c_static-static) + else() + set_target_properties(gopher_mcp_c_static PROPERTIES OUTPUT_NAME gopher_mcp_c_static) + endif() + set_target_properties(gopher_mcp_c_static PROPERTIES + POSITION_INDEPENDENT_CODE ON + ) target_include_directories(gopher_mcp_c_static PUBLIC diff --git a/src/config/file_config_source.cc b/src/config/file_config_source.cc index 4748394cd..48d1162f5 100644 --- a/src/config/file_config_source.cc +++ b/src/config/file_config_source.cc @@ -49,6 +49,7 @@ // Platform-specific includes #ifdef _WIN32 #include +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif namespace mcp { diff --git a/src/echo/echo_stdio_transport_advanced.cc b/src/echo/echo_stdio_transport_advanced.cc index 173fedb30..e46608c12 100644 --- a/src/echo/echo_stdio_transport_advanced.cc +++ b/src/echo/echo_stdio_transport_advanced.cc @@ -12,6 +12,7 @@ #ifdef _WIN32 #include #include +typedef SSIZE_T ssize_t; #define read(fd, buf, len) _read(fd, buf, static_cast(len)) #define write(fd, buf, len) _write(fd, buf, static_cast(len)) #ifndef STDIN_FILENO diff --git a/src/logging/CMakeLists.txt b/src/logging/CMakeLists.txt index 6acc250ff..4eb67baf8 100644 --- a/src/logging/CMakeLists.txt +++ b/src/logging/CMakeLists.txt @@ -13,10 +13,14 @@ set(MCP_LOGGING_SOURCES # Create static library add_library(gopher-mcp-logging-static STATIC ${MCP_LOGGING_SOURCES}) -set_target_properties(gopher-mcp-logging-static PROPERTIES - OUTPUT_NAME gopher-mcp-logging - POSITION_INDEPENDENT_CODE ON -) + if(WIN32) + set_target_properties(gopher-mcp-logging-static PROPERTIES OUTPUT_NAME gopher-mcp-logging-static) + else() + set_target_properties(gopher-mcp-logging-static PROPERTIES OUTPUT_NAME gopher-mcp-logging) + endif() + set_target_properties(gopher-mcp-logging-static PROPERTIES + POSITION_INDEPENDENT_CODE ON + ) target_include_directories(gopher-mcp-logging-static PUBLIC $ @@ -38,7 +42,7 @@ target_compile_definitions(gopher-mcp-logging-static PUBLIC # Create shared library if(BUILD_SHARED_LIBS) add_library(gopher-mcp-logging SHARED ${MCP_LOGGING_SOURCES}) - + target_include_directories(gopher-mcp-logging PUBLIC $ $ @@ -54,6 +58,10 @@ if(BUILD_SHARED_LIBS) target_compile_definitions(gopher-mcp-logging PUBLIC $<$:MCP_DEBUG_LOGGING> ) + + set_target_properties(gopher-mcp-logging PROPERTIES + WINDOWS_EXPORT_ALL_SYMBOLS ON + ) else() add_library(gopher-mcp-logging ALIAS gopher-mcp-logging-static) endif() diff --git a/src/network/connection_impl.cc b/src/network/connection_impl.cc index 87128a5a9..a0863fe0b 100644 --- a/src/network/connection_impl.cc +++ b/src/network/connection_impl.cc @@ -1423,8 +1423,13 @@ void ConnectionImpl::doWrite() { enableFileEvents(static_cast(event::FileReadyType::Read)); // Debug: Check if socket has pending data if (socket_) { +#ifdef _WIN32 + unsigned long bytes_available = 0; + if (ioctlsocket(socket_->ioHandle().fd(), FIONREAD, &bytes_available) == 0) { +#else int bytes_available = 0; if (ioctl(socket_->ioHandle().fd(), FIONREAD, &bytes_available) == 0) { +#endif GOPHER_LOG_TRACE("doWrite(): socket has {} bytes pending", bytes_available); } diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 000000000..c54e99ccc --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,6 @@ +{ + "dependencies": [ + "libevent", + "openssl" + ] +}