@@ -90,6 +90,9 @@ elseif(APPLE)
9090elseif (UNIX )
9191 set (RAC_PLATFORM_LINUX TRUE )
9292 set (RAC_PLATFORM_NAME "Linux" )
93+ elseif (WIN32 )
94+ set (RAC_PLATFORM_WINDOWS TRUE )
95+ set (RAC_PLATFORM_NAME "Windows" )
9396else ()
9497 set (RAC_PLATFORM_NAME "Unknown" )
9598endif ()
@@ -125,6 +128,57 @@ if(NOT DEFINED LIBARCHIVE_VERSION)
125128 set (LIBARCHIVE_VERSION "3.8.1" )
126129endif ()
127130
131+ # -----------------------------------------------------------------------------
132+ # Zlib: Bundle from source when system zlib is not available.
133+ # Windows (MSVC) and some cross-compilation targets don't ship zlib.
134+ # We try system first; if not found, build from source so libarchive gets it.
135+ # -----------------------------------------------------------------------------
136+ find_package (ZLIB QUIET )
137+ if (NOT ZLIB_FOUND)
138+ message (STATUS "System zlib not found — bundling from source..." )
139+ FetchContent_Declare (
140+ zlib_src
141+ GIT_REPOSITORY https://github.com/madler/zlib.git
142+ GIT_TAG v1.3.1
143+ GIT_SHALLOW TRUE
144+ )
145+ # Prevent zlib from installing or building examples
146+ set (ZLIB_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE )
147+ set (SKIP_INSTALL_ALL ON CACHE BOOL "" FORCE )
148+ set (SKIP_INSTALL_LIBRARIES ON CACHE BOOL "" FORCE )
149+ set (SKIP_INSTALL_HEADERS ON CACHE BOOL "" FORCE )
150+ set (SKIP_INSTALL_FILES ON CACHE BOOL "" FORCE )
151+ # Save and restore BUILD_SHARED_LIBS
152+ set (_SAVED_BSL_ZLIB ${BUILD_SHARED_LIBS} )
153+ set (BUILD_SHARED_LIBS OFF )
154+ FetchContent_MakeAvailable (zlib_src)
155+ set (BUILD_SHARED_LIBS ${_SAVED_BSL_ZLIB} )
156+
157+ # Set cache variables so libarchive's find_package(ZLIB) picks up our build.
158+ # For multi-config generators (Visual Studio), we point to the static lib
159+ # output. The actual path is resolved at build time via target_link_libraries.
160+ set (ZLIB_INCLUDE_DIR "${zlib_src_SOURCE_DIR} ;${zlib_src_BINARY_DIR} " CACHE PATH "" FORCE )
161+ set (ZLIB_INCLUDE_DIRS "${zlib_src_SOURCE_DIR} ;${zlib_src_BINARY_DIR} " CACHE PATH "" FORCE )
162+ # Use the CMake target name directly - this works because we link manually below
163+ set (ZLIB_LIBRARY zlibstatic CACHE STRING "" FORCE )
164+ set (ZLIB_LIBRARIES zlibstatic CACHE STRING "" FORCE )
165+ set (ZLIB_FOUND TRUE CACHE BOOL "" FORCE )
166+ # Create an imported ZLIB::ZLIB target that points to our zlibstatic
167+ if (NOT TARGET ZLIB::ZLIB)
168+ add_library (ZLIB::ZLIB ALIAS zlibstatic )
169+ endif ()
170+ # On MSVC, set zlibstatic output to a known location so the linker can find it
171+ if (MSVC AND TARGET zlibstatic)
172+ set_target_properties (zlibstatic PROPERTIES
173+ ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR} /lib"
174+ ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR} /lib"
175+ )
176+ endif ()
177+ message (STATUS "Bundled zlib ready (v1.3.1)" )
178+ else ()
179+ message (STATUS "Using system zlib: ${ZLIB_LIBRARIES} " )
180+ endif ()
181+
128182# -----------------------------------------------------------------------------
129183# BZip2: Bundle from source for cross-compilation targets
130184# Android NDK and Emscripten don't ship libbz2. macOS/iOS have it in the SDK.
@@ -156,6 +210,13 @@ if(NOT BZIP2_FOUND)
156210 set (BZIP2_INCLUDE_DIR "${bzip2_src_SOURCE_DIR} " CACHE PATH "" FORCE )
157211 set (BZIP2_LIBRARIES bz2_bundled CACHE STRING "" FORCE )
158212 set (BZIP2_FOUND TRUE CACHE BOOL "" FORCE )
213+ # On MSVC, set output to a known location so the linker can find it
214+ if (MSVC AND TARGET bz2_bundled)
215+ set_target_properties (bz2_bundled PROPERTIES
216+ ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR} /lib"
217+ ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR} /lib"
218+ )
219+ endif ()
159220 message (STATUS "Bundled BZip2 ready (v1.0.8)" )
160221else ()
161222 message (STATUS "Using system BZip2: ${BZIP2_LIBRARIES} " )
@@ -182,7 +243,7 @@ set(ENABLE_LIBXML2 OFF CACHE BOOL "" FORCE)
182243set (ENABLE_EXPAT OFF CACHE BOOL "" FORCE )
183244set (ENABLE_PCREPOSIX OFF CACHE BOOL "" FORCE )
184245set (ENABLE_PCRE2POSIX OFF CACHE BOOL "" FORCE )
185- set (ENABLE_LIBGCC OFF CACHE BOOL "" FORCE )
246+ set (ENABLE_LIBGCC ON CACHE BOOL "" FORCE )
186247set (ENABLE_CNG OFF CACHE BOOL "" FORCE )
187248set (ENABLE_TAR OFF CACHE BOOL "" FORCE ) # Don't build bsdtar binary
188249set (ENABLE_CPIO OFF CACHE BOOL "" FORCE ) # Don't build bsdcpio binary
@@ -203,6 +264,32 @@ if(TARGET bz2_bundled AND TARGET archive_static)
203264 target_link_libraries (archive_static bz2_bundled )
204265endif ()
205266
267+ # Link bundled zlib to libarchive if we built it from source
268+ if (TARGET zlibstatic AND TARGET archive_static)
269+ target_link_libraries (archive_static zlibstatic )
270+ target_include_directories (archive_static PRIVATE ${zlib_src_SOURCE_DIR} ${zlib_src_BINARY_DIR} )
271+ endif ()
272+
273+ # On MSVC multi-config generators, libarchive references "zlibstatic.lib" and
274+ # "bz2_bundled.lib" by bare filename. The linker can't find them because they
275+ # are built into <config>/ subdirectories. Fix: redirect their output to a
276+ # single known directory and add it to the global linker search path.
277+ if (MSVC )
278+ set (RAC_BUNDLED_LIB_DIR "${CMAKE_BINARY_DIR} /_bundled_libs" )
279+ foreach (_cfg Release Debug RelWithDebInfo MinSizeRel)
280+ string (TOUPPER "${_cfg} " _CFG)
281+ if (TARGET zlibstatic)
282+ set_target_properties (zlibstatic PROPERTIES
283+ ARCHIVE_OUTPUT_DIRECTORY_${_CFG} "${RAC_BUNDLED_LIB_DIR} " )
284+ endif ()
285+ if (TARGET bz2_bundled)
286+ set_target_properties (bz2_bundled PROPERTIES
287+ ARCHIVE_OUTPUT_DIRECTORY_${_CFG} "${RAC_BUNDLED_LIB_DIR} " )
288+ endif ()
289+ endforeach ()
290+ link_directories ("${RAC_BUNDLED_LIB_DIR} " )
291+ endif ()
292+
206293message (STATUS "libarchive ready (v${LIBARCHIVE_VERSION} )" )
207294
208295# =============================================================================
@@ -234,6 +321,17 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
234321 add_compile_options (-fvisibility=hidden )
235322 add_compile_options (-ffunction-sections -fdata-sections )
236323 endif ()
324+ elseif (MSVC )
325+ # /W3 = reasonable warning level, /utf-8 = source/execution charset
326+ # /Zc:__cplusplus = report correct __cplusplus value
327+ # /EHsc = standard C++ exception handling
328+ add_compile_options (/W3 /utf-8 /Zc:__cplusplus /EHsc )
329+ # Suppress common harmless warnings in third-party code
330+ add_compile_options (/wd4244 /wd4267 /wd4996 )
331+ add_compile_definitions (_CRT_SECURE_NO_WARNINGS NOMINMAX WIN32_LEAN_AND_MEAN )
332+ if (CMAKE_BUILD_TYPE STREQUAL "Release" )
333+ add_compile_options (/O2 /DNDEBUG )
334+ endif ()
237335endif ()
238336
239337# =============================================================================
@@ -351,8 +449,11 @@ set(RAC_FEATURES_SOURCES
351449 src/features/embeddings/embeddings_component.cpp
352450 # Voice Agent
353451 src/features/voice_agent/voice_agent.cpp
354- # Result memory management
355- src/features/result_free.cpp
452+ # Result memory management (weak symbol fallbacks)
453+ # On MSVC, each service .cpp already provides strong definitions,
454+ # so result_free.cpp (which uses __attribute__((weak)) on GCC/Clang)
455+ # must be excluded to avoid LNK2005 duplicate symbol errors.
456+ $<$<NOT :$<CXX_COMPILER_ID :MSVC >>:src /features /result_free .cpp >
356457)
357458
358459# Platform services (Apple Foundation Models + System TTS + CoreML Diffusion)
@@ -420,7 +521,20 @@ if(RAC_BUILD_SHARED)
420521endif ()
421522
422523# libarchive - native archive extraction
423- target_link_libraries (rac_commons PRIVATE archive_static )
524+ # PUBLIC on Windows because MSVC static libs don't propagate transitive deps
525+ if (WIN32 )
526+ target_link_libraries (rac_commons PUBLIC archive_static )
527+ # Tell libarchive headers we're using the static library (not DLL)
528+ target_compile_definitions (rac_commons PRIVATE LIBARCHIVE_STATIC )
529+ if (TARGET zlibstatic)
530+ target_link_libraries (rac_commons PUBLIC zlibstatic )
531+ endif ()
532+ if (TARGET bz2_bundled)
533+ target_link_libraries (rac_commons PUBLIC bz2_bundled )
534+ endif ()
535+ else ()
536+ target_link_libraries (rac_commons PRIVATE archive_static )
537+ endif ()
424538target_include_directories (rac_commons PRIVATE ${libarchive_SOURCE_DIR} /libarchive ${libarchive_BINARY_DIR} )
425539
426540# Platform-specific linking
@@ -440,6 +554,12 @@ if(RAC_PLATFORM_ANDROID)
440554 target_link_libraries (rac_commons PUBLIC log )
441555endif ()
442556
557+ if (RAC_PLATFORM_WINDOWS)
558+ target_compile_definitions (rac_commons PRIVATE RAC_PLATFORM_WINDOWS=1 )
559+ # ws2_32 = Winsock, shlwapi = path utilities
560+ target_link_libraries (rac_commons PUBLIC ws2_32 shlwapi )
561+ endif ()
562+
443563set_target_properties (rac_commons PROPERTIES
444564 CXX_STANDARD 20
445565 CXX_STANDARD_REQUIRED ON
@@ -587,6 +707,9 @@ message(STATUS " Services: LLM, STT, TTS, VAD interfaces")
587707if (APPLE AND RAC_BUILD_PLATFORM)
588708 message (STATUS " Platform: Apple Foundation Models, System TTS" )
589709endif ()
710+ if (RAC_PLATFORM_WINDOWS)
711+ message (STATUS " Platform: Windows (MSVC)" )
712+ endif ()
590713if (RAC_BUILD_BACKENDS)
591714 message (STATUS " Backends: LlamaCPP=${RAC_BACKEND_LLAMACPP} , ONNX=${RAC_BACKEND_ONNX} , WhisperCPP=${RAC_BACKEND_WHISPERCPP} , WhisperKitCoreML=${RAC_BACKEND_WHISPERKIT_COREML} " )
592715 if (RAC_BACKEND_RAG)
0 commit comments