28ef43264a
Compiles for Windows x64 via mingw-w64 and still compiles clean on POSIX (darwin/linux) — all Windows code is behind #ifdef _WIN32, POSIX path unchanged. - el_platform_win.h (new): winsock2 + auto WSAStartup, el_closesocket(), dlsym->GetProcAddress, popen/_popen, mkdir/_mkdir, setenv/_putenv_s, timegm/_mkgmtime, localtime_r/gmtime_r. Threading unchanged — mingw winpthreads supplies <pthread.h> + -lpthread. - el_runtime.c: include block guarded; 10 socket-close sites -> el_closesocket(); setsockopt arg4 cast; tm_zone guarded; exec_bg fork/exec -> CreateProcess. Part of feat/windows-port. Core-el change, for Will's review. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
95 lines
4.3 KiB
C
95 lines
4.3 KiB
C
#ifndef EL_PLATFORM_WIN_H
|
|
#define EL_PLATFORM_WIN_H
|
|
/*
|
|
* el_platform_win.h — Windows OS-boundary shim for el_runtime.c.
|
|
*
|
|
* Branch: feat/windows-el-runtime. Included ONLY when _WIN32 is defined; the POSIX build is
|
|
* untouched. Goal: let el_runtime.c (a BSD-sockets / dlfcn / fork host) compile and link with
|
|
* mingw-w64 into a native neuron.exe, with no behavioural change to the Linux/macOS build.
|
|
*
|
|
* What it maps:
|
|
* - sockets : winsock2 (same call names: socket/bind/listen/accept/recv/send/setsockopt).
|
|
* Sockets close with closesocket() (see el_closesocket), and the stack must be
|
|
* started once with WSAStartup — done automatically via a load-time constructor.
|
|
* - dlsym : el_runtime.c uses dlsym(RTLD_DEFAULT, name) to resolve callback/tool symbols
|
|
* exported by the main module. Windows equivalent: GetProcAddress on the process
|
|
* module. Link the soul with -Wl,--export-all-symbols so the symbols are findable.
|
|
* - popen : mapped to _popen/_pclose.
|
|
* - threads : UNCHANGED. mingw-w64 ships winpthreads, so <pthread.h> + -lpthread just work.
|
|
*/
|
|
|
|
#ifndef WIN32_LEAN_AND_MEAN
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#endif
|
|
#include <winsock2.h>
|
|
#include <ws2tcpip.h>
|
|
#include <windows.h>
|
|
#include <io.h>
|
|
#include <process.h>
|
|
|
|
/* Portable headers mingw-w64 provides (verified present). */
|
|
#include <stdarg.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <strings.h> /* strcasecmp */
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include <time.h>
|
|
#include <sys/time.h> /* mingw-w64 provides gettimeofday here */
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#include <pthread.h>
|
|
|
|
/* ── socket close ─────────────────────────────────────────────────────────── */
|
|
/* Winsock closes sockets with closesocket(), not close() (close() is for file fds). The POSIX
|
|
build defines the same helper as close() so the call sites are identical across platforms. */
|
|
static inline int el_closesocket(int s) { return closesocket((SOCKET)s); }
|
|
|
|
/* ── winsock init (once, at load) ─────────────────────────────────────────── */
|
|
static void el__win_net_init(void) {
|
|
static int inited = 0;
|
|
if (!inited) { WSADATA w; WSAStartup(MAKEWORD(2, 2), &w); inited = 1; }
|
|
}
|
|
__attribute__((constructor)) static void el__win_ctor(void) { el__win_net_init(); }
|
|
|
|
/* ── dlsym → GetProcAddress ───────────────────────────────────────────────── */
|
|
#ifndef RTLD_DEFAULT
|
|
#define RTLD_DEFAULT ((void*)0)
|
|
#endif
|
|
static inline void* el_win_dlsym(void* handle, const char* name) {
|
|
(void)handle;
|
|
return (void*)(uintptr_t)GetProcAddress(GetModuleHandleA(NULL), name);
|
|
}
|
|
#define dlsym(h, n) el_win_dlsym((h), (n))
|
|
|
|
/* ── popen / pclose ───────────────────────────────────────────────────────── */
|
|
#define popen _popen
|
|
#define pclose _pclose
|
|
|
|
/* ── misc POSIX → Win32 shims ─────────────────────────────────────────────── */
|
|
#include <direct.h> /* _mkdir */
|
|
#define mkdir(path, mode) _mkdir(path) /* POSIX mkdir(path,mode) → _mkdir(path) */
|
|
#define timegm _mkgmtime /* UTC tm → time_t */
|
|
|
|
/* setenv/unsetenv: not in the Windows CRT; map to _putenv_s. */
|
|
static inline int setenv(const char* name, const char* value, int overwrite) {
|
|
(void)overwrite;
|
|
return _putenv_s(name, value ? value : "");
|
|
}
|
|
static inline int unsetenv(const char* name) { return _putenv_s(name, ""); }
|
|
|
|
/* localtime_r/gmtime_r: Windows offers localtime_s/gmtime_s with reversed arg order. */
|
|
static inline struct tm* localtime_r(const time_t* t, struct tm* out) {
|
|
return localtime_s(out, t) == 0 ? out : (struct tm*)0;
|
|
}
|
|
static inline struct tm* gmtime_r(const time_t* t, struct tm* out) {
|
|
return gmtime_s(out, t) == 0 ? out : (struct tm*)0;
|
|
}
|
|
|
|
#endif /* EL_PLATFORM_WIN_H */
|