@@ -46,6 +46,10 @@ option(RAC_BUILD_SERVER "Build OpenAI-compatible HTTP server (runanywhere-server
4646# C++ CONFIGURATION
4747# =============================================================================
4848
49+ # C++20 is required because MSVC does not implement C++17 designated initializers
50+ # (e.g. `struct S s = {.field = value};`) — the codebase uses them in several
51+ # places (service vtable registration, config structs). All supported compilers
52+ # (GCC 10+, Clang 11+, MSVC 19.28+ / VS 2019 16.8+) support C++20.
4953set (CMAKE_CXX_STANDARD 20)
5054set (CMAKE_CXX_STANDARD_REQUIRED ON )
5155set (CMAKE_CXX_EXTENSIONS OFF )
@@ -90,6 +94,9 @@ elseif(APPLE)
9094elseif (UNIX )
9195 set (RAC_PLATFORM_LINUX TRUE )
9296 set (RAC_PLATFORM_NAME "Linux" )
97+ elseif (WIN32 )
98+ set (RAC_PLATFORM_WINDOWS TRUE )
99+ set (RAC_PLATFORM_NAME "Windows" )
93100else ()
94101 set (RAC_PLATFORM_NAME "Unknown" )
95102endif ()
@@ -125,6 +132,57 @@ if(NOT DEFINED LIBARCHIVE_VERSION)
125132 set (LIBARCHIVE_VERSION "3.8.1" )
126133endif ()
127134
135+ # -----------------------------------------------------------------------------
136+ # Zlib: Bundle from source when system zlib is not available.
137+ # Windows (MSVC) and some cross-compilation targets don't ship zlib.
138+ # We try system first; if not found, build from source so libarchive gets it.
139+ # -----------------------------------------------------------------------------
140+ find_package (ZLIB QUIET )
141+ if (NOT ZLIB_FOUND)
142+ message (STATUS "System zlib not found — bundling from source..." )
143+ FetchContent_Declare (
144+ zlib_src
145+ GIT_REPOSITORY https://github.com/madler/zlib.git
146+ GIT_TAG v1.3.1
147+ GIT_SHALLOW TRUE
148+ )
149+ # Prevent zlib from installing or building examples
150+ set (ZLIB_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE )
151+ set (SKIP_INSTALL_ALL ON CACHE BOOL "" FORCE )
152+ set (SKIP_INSTALL_LIBRARIES ON CACHE BOOL "" FORCE )
153+ set (SKIP_INSTALL_HEADERS ON CACHE BOOL "" FORCE )
154+ set (SKIP_INSTALL_FILES ON CACHE BOOL "" FORCE )
155+ # Save and restore BUILD_SHARED_LIBS
156+ set (_SAVED_BSL_ZLIB ${BUILD_SHARED_LIBS} )
157+ set (BUILD_SHARED_LIBS OFF )
158+ FetchContent_MakeAvailable (zlib_src)
159+ set (BUILD_SHARED_LIBS ${_SAVED_BSL_ZLIB} )
160+
161+ # Set cache variables so libarchive's find_package(ZLIB) picks up our build.
162+ # For multi-config generators (Visual Studio), we point to the static lib
163+ # output. The actual path is resolved at build time via target_link_libraries.
164+ set (ZLIB_INCLUDE_DIR "${zlib_src_SOURCE_DIR} ;${zlib_src_BINARY_DIR} " CACHE PATH "" FORCE )
165+ set (ZLIB_INCLUDE_DIRS "${zlib_src_SOURCE_DIR} ;${zlib_src_BINARY_DIR} " CACHE PATH "" FORCE )
166+ # Use the CMake target name directly - this works because we link manually below
167+ set (ZLIB_LIBRARY zlibstatic CACHE STRING "" FORCE )
168+ set (ZLIB_LIBRARIES zlibstatic CACHE STRING "" FORCE )
169+ set (ZLIB_FOUND TRUE CACHE BOOL "" FORCE )
170+ # Create an imported ZLIB::ZLIB target that points to our zlibstatic
171+ if (NOT TARGET ZLIB::ZLIB)
172+ add_library (ZLIB::ZLIB ALIAS zlibstatic )
173+ endif ()
174+ # On MSVC, set zlibstatic output to a known location so the linker can find it
175+ if (MSVC AND TARGET zlibstatic)
176+ set_target_properties (zlibstatic PROPERTIES
177+ ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR} /lib"
178+ ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR} /lib"
179+ )
180+ endif ()
181+ message (STATUS "Bundled zlib ready (v1.3.1)" )
182+ else ()
183+ message (STATUS "Using system zlib: ${ZLIB_LIBRARIES} " )
184+ endif ()
185+
128186# -----------------------------------------------------------------------------
129187# BZip2: Bundle from source for cross-compilation targets
130188# Android NDK and Emscripten don't ship libbz2. macOS/iOS have it in the SDK.
@@ -156,6 +214,13 @@ if(NOT BZIP2_FOUND)
156214 set (BZIP2_INCLUDE_DIR "${bzip2_src_SOURCE_DIR} " CACHE PATH "" FORCE )
157215 set (BZIP2_LIBRARIES bz2_bundled CACHE STRING "" FORCE )
158216 set (BZIP2_FOUND TRUE CACHE BOOL "" FORCE )
217+ # On MSVC, set output to a known location so the linker can find it
218+ if (MSVC AND TARGET bz2_bundled)
219+ set_target_properties (bz2_bundled PROPERTIES
220+ ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR} /lib"
221+ ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR} /lib"
222+ )
223+ endif ()
159224 message (STATUS "Bundled BZip2 ready (v1.0.8)" )
160225else ()
161226 message (STATUS "Using system BZip2: ${BZIP2_LIBRARIES} " )
@@ -182,7 +247,16 @@ set(ENABLE_LIBXML2 OFF CACHE BOOL "" FORCE)
182247set (ENABLE_EXPAT OFF CACHE BOOL "" FORCE )
183248set (ENABLE_PCREPOSIX OFF CACHE BOOL "" FORCE )
184249set (ENABLE_PCRE2POSIX OFF CACHE BOOL "" FORCE )
185- set (ENABLE_LIBGCC OFF CACHE BOOL "" FORCE )
250+ # libarchive's ENABLE_LIBGCC gates a `find_library(GCC_LIBRARY gcc)` / `-lgcc`
251+ # link. Needed on MSVC for the bundled runtime; a no-op on Apple/Clang (no
252+ # libgcc); on Linux+GCC keep it OFF so we don't add an explicit -lgcc to the
253+ # link line (it's pulled in implicitly and adding it can cause duplicate-symbol
254+ # warnings in static configurations).
255+ if (MSVC )
256+ set (ENABLE_LIBGCC ON CACHE BOOL "" FORCE )
257+ else ()
258+ set (ENABLE_LIBGCC OFF CACHE BOOL "" FORCE )
259+ endif ()
186260set (ENABLE_CNG OFF CACHE BOOL "" FORCE )
187261set (ENABLE_TAR OFF CACHE BOOL "" FORCE ) # Don't build bsdtar binary
188262set (ENABLE_CPIO OFF CACHE BOOL "" FORCE ) # Don't build bsdcpio binary
@@ -203,6 +277,32 @@ if(TARGET bz2_bundled AND TARGET archive_static)
203277 target_link_libraries (archive_static bz2_bundled )
204278endif ()
205279
280+ # Link bundled zlib to libarchive if we built it from source
281+ if (TARGET zlibstatic AND TARGET archive_static)
282+ target_link_libraries (archive_static zlibstatic )
283+ target_include_directories (archive_static PRIVATE ${zlib_src_SOURCE_DIR} ${zlib_src_BINARY_DIR} )
284+ endif ()
285+
286+ # On MSVC multi-config generators, libarchive references "zlibstatic.lib" and
287+ # "bz2_bundled.lib" by bare filename. The linker can't find them because they
288+ # are built into <config>/ subdirectories. Fix: redirect their output to a
289+ # single known directory and add it to the global linker search path.
290+ if (MSVC )
291+ set (RAC_BUNDLED_LIB_DIR "${CMAKE_BINARY_DIR} /_bundled_libs" )
292+ foreach (_cfg Release Debug RelWithDebInfo MinSizeRel)
293+ string (TOUPPER "${_cfg} " _CFG)
294+ if (TARGET zlibstatic)
295+ set_target_properties (zlibstatic PROPERTIES
296+ ARCHIVE_OUTPUT_DIRECTORY_${_CFG} "${RAC_BUNDLED_LIB_DIR} " )
297+ endif ()
298+ if (TARGET bz2_bundled)
299+ set_target_properties (bz2_bundled PROPERTIES
300+ ARCHIVE_OUTPUT_DIRECTORY_${_CFG} "${RAC_BUNDLED_LIB_DIR} " )
301+ endif ()
302+ endforeach ()
303+ link_directories ("${RAC_BUNDLED_LIB_DIR} " )
304+ endif ()
305+
206306message (STATUS "libarchive ready (v${LIBARCHIVE_VERSION} )" )
207307
208308# =============================================================================
@@ -234,6 +334,22 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
234334 add_compile_options (-fvisibility=hidden )
235335 add_compile_options (-ffunction-sections -fdata-sections )
236336 endif ()
337+ elseif (MSVC )
338+ # /W3 = reasonable warning level, /utf-8 = source/execution charset
339+ # /Zc:__cplusplus = report correct __cplusplus value
340+ # /EHsc = standard C++ exception handling
341+ add_compile_options (/W3 /utf-8 /Zc:__cplusplus /EHsc )
342+ # Suppress common harmless warnings in third-party code
343+ add_compile_options (/wd4244 /wd4267 /wd4996 )
344+ add_compile_definitions (_CRT_SECURE_NO_WARNINGS NOMINMAX WIN32_LEAN_AND_MEAN )
345+ # Use generator expressions instead of CMAKE_BUILD_TYPE so Release flags
346+ # apply correctly with multi-config generators (Visual Studio), where
347+ # CMAKE_BUILD_TYPE is empty at configure time and the config is selected
348+ # at build time via --config Release.
349+ add_compile_options (
350+ $<$<CONFIG :Release >:/O2 >
351+ $<$<CONFIG :Release >:/DNDEBUG >
352+ )
237353endif ()
238354
239355# =============================================================================
@@ -352,8 +468,11 @@ set(RAC_FEATURES_SOURCES
352468 src/features/embeddings/embeddings_component.cpp
353469 # Voice Agent
354470 src/features/voice_agent/voice_agent.cpp
355- # Result memory management
356- src/features/result_free.cpp
471+ # Result memory management (weak symbol fallbacks)
472+ # On MSVC, each service .cpp already provides strong definitions,
473+ # so result_free.cpp (which uses __attribute__((weak)) on GCC/Clang)
474+ # must be excluded to avoid LNK2005 duplicate symbol errors.
475+ $<$<NOT :$<CXX_COMPILER_ID :MSVC >>:src /features /result_free .cpp >
357476)
358477
359478# Platform services (Apple Foundation Models + System TTS + CoreML Diffusion)
@@ -421,7 +540,20 @@ if(RAC_BUILD_SHARED)
421540endif ()
422541
423542# libarchive - native archive extraction
424- target_link_libraries (rac_commons PRIVATE archive_static )
543+ # PUBLIC on Windows because MSVC static libs don't propagate transitive deps
544+ if (WIN32 )
545+ target_link_libraries (rac_commons PUBLIC archive_static )
546+ # Tell libarchive headers we're using the static library (not DLL)
547+ target_compile_definitions (rac_commons PRIVATE LIBARCHIVE_STATIC )
548+ if (TARGET zlibstatic)
549+ target_link_libraries (rac_commons PUBLIC zlibstatic )
550+ endif ()
551+ if (TARGET bz2_bundled)
552+ target_link_libraries (rac_commons PUBLIC bz2_bundled )
553+ endif ()
554+ else ()
555+ target_link_libraries (rac_commons PRIVATE archive_static )
556+ endif ()
425557target_include_directories (rac_commons PRIVATE ${libarchive_SOURCE_DIR} /libarchive ${libarchive_BINARY_DIR} )
426558
427559# Platform-specific linking
@@ -441,6 +573,12 @@ if(RAC_PLATFORM_ANDROID)
441573 target_link_libraries (rac_commons PUBLIC log )
442574endif ()
443575
576+ if (RAC_PLATFORM_WINDOWS)
577+ target_compile_definitions (rac_commons PRIVATE RAC_PLATFORM_WINDOWS=1 )
578+ # ws2_32 = Winsock, shlwapi = path utilities
579+ target_link_libraries (rac_commons PUBLIC ws2_32 shlwapi )
580+ endif ()
581+
444582set_target_properties (rac_commons PROPERTIES
445583 CXX_STANDARD 20
446584 CXX_STANDARD_REQUIRED ON
@@ -588,6 +726,9 @@ message(STATUS " Services: LLM, STT, TTS, VAD interfaces")
588726if (APPLE AND RAC_BUILD_PLATFORM)
589727 message (STATUS " Platform: Apple Foundation Models, System TTS" )
590728endif ()
729+ if (RAC_PLATFORM_WINDOWS)
730+ message (STATUS " Platform: Windows (MSVC)" )
731+ endif ()
591732if (RAC_BUILD_BACKENDS)
592733 message (STATUS " Backends: LlamaCPP=${RAC_BACKEND_LLAMACPP} , ONNX=${RAC_BACKEND_ONNX} , WhisperCPP=${RAC_BACKEND_WHISPERCPP} , WhisperKitCoreML=${RAC_BACKEND_WHISPERKIT_COREML} " )
593734 if (RAC_BACKEND_RAG)
0 commit comments