Skip to content

Commit 5042622

Browse files
unamedkrclaude
andcommitted
MSVC compatibility: compile with Visual Studio 2019/2022 (fixes #10)
Platform-specific fixes for Windows/MSVC compilation: CMake: - Conditional -lm linking (MSVC CRT includes math) - _CRT_SECURE_NO_WARNINGS, _USE_MATH_DEFINES definitions - MSVC warning level /W3 with targeted suppressions Source: - stdatomic.h → MSVC _Interlocked* intrinsics - __thread → __declspec(thread) on MSVC - __attribute__((unused)) → __pragma(warning(suppress)) - clock_gettime/CLOCK_MONOTONIC → QueryPerformanceCounter - R_OK / access() → _access() with R_OK=4 define - pthread.h → Windows CRITICAL_SECTION/CONDITION_VARIABLE shim - unistd.h / dirent.h guarded behind #ifndef _WIN32 No functional changes on Unix/macOS. 34/34 tests pass, 0 warnings. Closes #10 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8cb5e1d commit 5042622

7 files changed

Lines changed: 87 additions & 3 deletions

File tree

CMakeLists.txt

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,20 @@ add_library(turboquant STATIC
2727
${TQ_ENGINE_SOURCES}
2828
)
2929
target_include_directories(turboquant PUBLIC include)
30-
target_link_libraries(turboquant PRIVATE m Threads::Threads)
30+
31+
# Platform-specific linking
32+
if(MSVC)
33+
# MSVC: no -lm needed, math is in CRT
34+
target_link_libraries(turboquant PRIVATE Threads::Threads)
35+
target_compile_definitions(turboquant PRIVATE
36+
_CRT_SECURE_NO_WARNINGS
37+
_USE_MATH_DEFINES
38+
)
39+
# Disable warnings that fire on valid C11
40+
target_compile_options(turboquant PRIVATE /W3 /wd4244 /wd4267 /wd4996)
41+
else()
42+
target_link_libraries(turboquant PRIVATE m Threads::Threads)
43+
endif()
3144

3245
# Apple Accelerate framework (cblas_sgemv via AMX coprocessor)
3346
if(APPLE)
@@ -47,7 +60,13 @@ add_library(turboquant_shared SHARED
4760
${TQ_ENGINE_SOURCES}
4861
)
4962
target_include_directories(turboquant_shared PUBLIC include)
50-
target_link_libraries(turboquant_shared PRIVATE m Threads::Threads)
63+
if(MSVC)
64+
target_link_libraries(turboquant_shared PRIVATE Threads::Threads)
65+
target_compile_definitions(turboquant_shared PRIVATE _CRT_SECURE_NO_WARNINGS _USE_MATH_DEFINES)
66+
target_compile_options(turboquant_shared PRIVATE /W3 /wd4244 /wd4267 /wd4996)
67+
else()
68+
target_link_libraries(turboquant_shared PRIVATE m Threads::Threads)
69+
endif()
5170

5271
# Accelerate for shared library too
5372
if(APPLE AND ACCELERATE_LIB)

src/engine/tq_gguf_quants.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,7 +1256,11 @@ static inline float dot_block_iq2_xxs(const uint8_t* blk, const float* x) {
12561256
/* Fused IQ2_XXS row dot: dot product of entire quantized row with input vector.
12571257
* Processes all 256-element super-blocks without any intermediate FP32 buffer.
12581258
* Reserved for future fused matmul optimization path. */
1259+
#ifdef _MSC_VER
1260+
__pragma(warning(suppress: 4505))
1261+
#else
12591262
__attribute__((unused))
1263+
#endif
12601264
static float fused_dot_iq2_xxs(const void* row, const float* x, int n) {
12611265
const int nb = n / 256;
12621266
const uint8_t* base = (const uint8_t*)row;

src/engine/tq_model.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
#ifdef _WIN32
2828
#include <windows.h>
2929
#include <io.h>
30+
#ifndef R_OK
31+
#define R_OK 4
32+
#endif
33+
#define access _access
3034
#else
3135
#include <sys/mman.h>
3236
#include <sys/stat.h>

src/engine/tq_ops.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,26 @@
1111
#include <stdlib.h>
1212
#include <string.h>
1313
#include <float.h>
14+
15+
#ifdef _WIN32
16+
#include <windows.h>
17+
/* pthread compat for MSVC (using Windows threads) */
18+
typedef HANDLE pthread_t;
19+
typedef CRITICAL_SECTION pthread_mutex_t;
20+
typedef CONDITION_VARIABLE pthread_cond_t;
21+
#define pthread_mutex_init(m, a) InitializeCriticalSection(m)
22+
#define pthread_mutex_lock(m) EnterCriticalSection(m)
23+
#define pthread_mutex_unlock(m) LeaveCriticalSection(m)
24+
#define pthread_mutex_destroy(m) DeleteCriticalSection(m)
25+
#define pthread_cond_init(c, a) InitializeConditionVariable(c)
26+
#define pthread_cond_wait(c, m) SleepConditionVariableCS(c, m, INFINITE)
27+
#define pthread_cond_broadcast(c) WakeAllConditionVariable(c)
28+
#define pthread_cond_destroy(c) ((void)0)
29+
/* __thread → __declspec(thread) */
30+
#define __thread __declspec(thread)
31+
#else
1432
#include <pthread.h>
33+
#endif
1534

1635
#ifdef __ARM_NEON
1736
#include <arm_neon.h>
@@ -29,7 +48,16 @@
2948
* Workers sleep between dispatches, wake via cond_broadcast.
3049
* Main thread does task[0], workers do task[1..n-1].
3150
* ============================================================ */
32-
#include <stdatomic.h>
51+
#if defined(_MSC_VER)
52+
/* MSVC: use interlocked intrinsics instead of C11 atomics */
53+
#include <intrin.h>
54+
typedef volatile long atomic_int;
55+
#define atomic_store(p, v) _InterlockedExchange((p), (v))
56+
#define atomic_load(p) _InterlockedCompareExchange((p), 0, 0)
57+
#define atomic_fetch_add(p, v) _InterlockedExchangeAdd((p), (v))
58+
#else
59+
#include <stdatomic.h>
60+
#endif
3361

3462
/* Forward declaration for 1-bit matmul (defined at end of file) */
3563
void tq_matmul_1bit(float* out, const float* x, const uint8_t* sign_data, const float* norms,

src/engine/tq_tokenizer.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
#include <string.h>
2020
#include <stddef.h>
2121

22+
#if defined(_MSC_VER) && !defined(__thread)
23+
#define __thread __declspec(thread)
24+
#endif
25+
2226
/* Global for qsort comparator (vocab index sorting) */
2327
static char** g_vocab_for_sort;
2428
static int cmp_vocab_idx(const void* a, const void* b) {

src/engine/tq_transformer.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,16 @@ static tq_profile_t g_profile = {0};
7070
int g_tq_profile_enabled = 0; /* set from quant --profile */
7171

7272
static inline double tq_now_ns(void) {
73+
#ifdef _WIN32
74+
LARGE_INTEGER freq, cnt;
75+
QueryPerformanceFrequency(&freq);
76+
QueryPerformanceCounter(&cnt);
77+
return (double)cnt.QuadPart / (double)freq.QuadPart * 1e9;
78+
#else
7379
struct timespec ts;
7480
clock_gettime(CLOCK_MONOTONIC, &ts);
7581
return (double)ts.tv_sec * 1e9 + (double)ts.tv_nsec;
82+
#endif
7683
}
7784

7885
/* Usage: double _tp; TQ_PROF_START(_tp); ... TQ_PROF_STOP(_tp, field); */

tools/quant.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,24 @@
3737
#include <time.h>
3838
#include <math.h>
3939

40+
/* MSVC: clock_gettime compatibility */
41+
#ifdef _WIN32
42+
#include <windows.h>
43+
#ifndef CLOCK_MONOTONIC
44+
#define CLOCK_MONOTONIC 1
45+
#endif
46+
struct timespec { long tv_sec; long tv_nsec; };
47+
static int clock_gettime(int id, struct timespec* ts) {
48+
(void)id;
49+
LARGE_INTEGER freq, cnt;
50+
QueryPerformanceFrequency(&freq);
51+
QueryPerformanceCounter(&cnt);
52+
ts->tv_sec = (long)(cnt.QuadPart / freq.QuadPart);
53+
ts->tv_nsec = (long)((cnt.QuadPart % freq.QuadPart) * 1000000000LL / freq.QuadPart);
54+
return 0;
55+
}
56+
#endif
57+
4058
/* Forward-pass profiling flag (defined in tq_transformer.c) */
4159
extern int g_tq_profile_enabled;
4260

0 commit comments

Comments
 (0)