feat: add MinGW cross-compilation support for Windows builds on Linux (#2108)

This commit is contained in:
涵曦
2025-11-26 00:07:43 +08:00
committed by GitHub
parent 5608d39789
commit 234e134967
19 changed files with 3101 additions and 2 deletions

7
.gitignore vendored
View File

@@ -10,4 +10,9 @@
*.so *.so
*.dSYM *.dSYM
.DS_Store .DS_Store
.vscode .vscode
3rd/lua/lua.exe
3rd/lua/luac.exe
3rd/lua/lua54.dll
skynet.exe
*.dll

View File

@@ -0,0 +1 @@
#pragma once

View File

@@ -0,0 +1,5 @@
#include "compat.h"
#include "dlfcn.c"
#include "unistd.c"
#include "wepoll.c"

View File

@@ -0,0 +1,4 @@
#pragma once
#include "unistd.h"
#include "dlfcn.h"

20
3rd/compat-mingw/dlfcn.c Normal file
View File

@@ -0,0 +1,20 @@
#include "dlfcn.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
void *dlopen(const char *path, int flag) {
return LoadLibraryA(path);
}
const char *dlerror() {
DWORD err = GetLastError();
HLOCAL LocalAddress = NULL;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, err, 0, (PTSTR)&LocalAddress, 0, NULL);
return (LPSTR)LocalAddress;
}
void *dlsym(void *dl, const char *sym) {
return GetProcAddress(dl, sym);
}

7
3rd/compat-mingw/dlfcn.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
enum { RTLD_NOW, RTLD_GLOBAL };
void *dlopen(const char *path, int flag);
const char *dlerror();
void *dlsym(void *dl, const char *sym);

3
3rd/compat-mingw/netdb.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
#include <ws2tcpip.h>

View File

@@ -0,0 +1 @@
#pragma once

View File

@@ -0,0 +1 @@
#pragma once

View File

@@ -0,0 +1,3 @@
#pragma once
#include "wepoll.h"

View File

@@ -0,0 +1 @@
#pragma once

View File

@@ -0,0 +1,17 @@
#pragma once
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN
#undef FD_SETSIZE
#define FD_SETSIZE 1024
#include <winsock2.h>
#include <windows.h>
#include <conio.h>
#include <ws2ipdef.h>
#include <ws2tcpip.h>
#include "socket_poll.h"
#include "socket_epoll.h"

381
3rd/compat-mingw/unistd.c Normal file
View File

@@ -0,0 +1,381 @@
#include "unistd.h"
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <stdio.h>
#include <stdint.h>
#include <windows.h>
#include <conio.h>
#include <errno.h>
// WSA error to errno mapping function
static void set_errno_from_wsa_error(int wsa_error) {
switch (wsa_error) {
case WSAECONNRESET:
errno = ECONNRESET;
break;
case WSAECONNABORTED:
errno = ECONNABORTED;
break;
case WSAECONNREFUSED:
errno = ECONNREFUSED;
break;
case WSAENETDOWN:
errno = ENETDOWN;
break;
case WSAENETUNREACH:
errno = ENETUNREACH;
break;
case WSAEHOSTDOWN:
errno = EHOSTDOWN;
break;
case WSAEHOSTUNREACH:
errno = EHOSTUNREACH;
break;
case WSAETIMEDOUT:
errno = ETIMEDOUT;
break;
case WSAENOTCONN:
errno = ENOTCONN;
break;
case WSAEWOULDBLOCK:
errno = EAGAIN;
break;
case WSAEINTR:
errno = EINTR;
break;
case WSAEINVAL:
errno = EINVAL;
break;
case WSAEACCES:
errno = EACCES;
break;
case WSAEADDRINUSE:
errno = EADDRINUSE;
break;
case WSAEADDRNOTAVAIL:
errno = EADDRNOTAVAIL;
break;
default:
errno = EIO; // Generic I/O error for unknown cases
break;
}
}
// Windows Socket initialization
static int winsock_initialized = 0;
static int init_winsock(void) {
if (!winsock_initialized) {
WSADATA wsaData;
int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (result != 0) {
return -1;
}
winsock_initialized = 1;
}
return 0;
}
static void cleanup_winsock(void) {
if (winsock_initialized) {
WSACleanup();
winsock_initialized = 0;
}
}
// Auto-initialize Winsock when the library is loaded
__attribute__((constructor))
static void auto_init_winsock(void) {
init_winsock();
}
// Auto-cleanup Winsock when the library is unloaded
__attribute__((destructor))
static void auto_cleanup_winsock(void) {
cleanup_winsock();
}
static LONGLONG get_cpu_freq() {
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
return freq.QuadPart;
}
int kill(pid_t pid, int exit_code) {
return TerminateProcess((HANDLE)(uintptr_t)pid, exit_code);
}
#define NANOSEC 1000000000
#define MICROSEC 1000000
void usleep(size_t us) {
if (us > 1000) {
Sleep(us / 1000);
return;
}
LONGLONG delta = get_cpu_freq() / MICROSEC * us;
LARGE_INTEGER counter;
QueryPerformanceCounter(&counter);
LONGLONG start = counter.QuadPart;
for (;;) {
QueryPerformanceCounter(&counter);
if (counter.QuadPart - start >= delta)
return;
}
}
void sleep(size_t ms) {
Sleep(ms);
}
int clock_gettime(int what, struct timespec* ti) {
switch (what) {
case CLOCK_MONOTONIC:
static __int64 Freq = 0;
static __int64 Start = 0;
static __int64 StartTime = 0;
if (Freq == 0) {
StartTime = time(NULL);
QueryPerformanceFrequency((LARGE_INTEGER*)&Freq);
QueryPerformanceCounter((LARGE_INTEGER*)&Start);
}
__int64 Count = 0;
QueryPerformanceCounter((LARGE_INTEGER*)&Count);
// 乘以1000把秒化为毫秒
__int64 now = (__int64)((double)(Count - Start) / (double)Freq * 1000.0) + StartTime * 1000;
ti->tv_sec = now / 1000;
ti->tv_nsec = (now - now / 1000 * 1000) * 1000 * 1000;
return 0;
case CLOCK_REALTIME:
SYSTEMTIME st;
GetSystemTime(&st); // 获取 UTC 时间
// 将 SYSTEMTIME 转换为 UNIX 时间戳
FILETIME ft;
SystemTimeToFileTime(&st, &ft);
ULARGE_INTEGER u64;
u64.LowPart = ft.dwLowDateTime;
u64.HighPart = ft.dwHighDateTime;
ti->tv_sec = (uint32_t)((u64.QuadPart - 116444736000000000ULL) / 10000000); // 转换为秒
ti->tv_nsec = (uint32_t)((u64.QuadPart % 10000000) * 100); // 获取纳秒部分
return 0; // 响应成功
case CLOCK_THREAD_CPUTIME_ID:
// 获取当前线程的 CPU 时间
FILETIME creation_time, exit_time, kernel_time, user_time;
if (GetThreadTimes(GetCurrentThread(), &creation_time, &exit_time, &kernel_time, &user_time)) {
ULARGE_INTEGER u64;
u64.LowPart = user_time.dwLowDateTime;
u64.HighPart = user_time.dwHighDateTime;
ti->tv_sec = (uint32_t)((u64.QuadPart - 116444736000000000ULL) / 10000000); // 转换为秒
ti->tv_nsec = (uint32_t)((u64.QuadPart % 10000000) * 100); // 获取纳秒部分
return 0;
} else {
return -1; // 获取失败
}
}
return -1;
}
int flock(int fd, int flag) {
// Not implemented
return 3;
}
int fcntl(int fd, int cmd, long arg) {
if (cmd == F_GETFL)
return 0;
if (cmd == F_SETFL && arg == O_NONBLOCK) {
u_long ulOption = 1;
ioctlsocket(fd, FIONBIO, &ulOption);
}
return 1;
}
void sigfillset(int* flag) {
// Not implemented
}
int sigemptyset(int* set) {
/*Not implemented*/
return 0;
}
void sigaction(int flag, struct sigaction* action, void* param) {
// Not implemented
}
static void socket_keepalive(int fd) {
int keepalive = 1;
int ret = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepalive,
sizeof(keepalive));
assert(ret != SOCKET_ERROR);
}
int pipe(int fd[2]) {
int listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listen_fd == INVALID_SOCKET) {
return -1;
}
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
srand(time(NULL));
// use random port(range from 60000 to 60999) to simulate pipe()
int port;
for (;;) {
port = 60000 + rand() % 1000;
sin.sin_port = htons(port);
if (!bind(listen_fd, (struct sockaddr*)&sin, sizeof(sin)))
break;
}
if (listen(listen_fd, 5) == SOCKET_ERROR) {
closesocket(listen_fd);
return -1;
}
socket_keepalive(listen_fd);
int client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (client_fd == INVALID_SOCKET) {
closesocket(listen_fd);
return -1;
}
if (connect(client_fd, (struct sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR) {
closesocket(listen_fd);
closesocket(client_fd);
return -1;
}
struct sockaddr_in client_addr;
size_t name_len = sizeof(client_addr);
int client_sock = accept(listen_fd, (struct sockaddr*)&client_addr, &name_len);
if (client_sock == INVALID_SOCKET) {
closesocket(listen_fd);
closesocket(client_fd);
return -1;
}
closesocket(listen_fd); // Close listen socket as it's no longer needed
fd[0] = client_sock;
fd[1] = client_fd;
socket_keepalive(client_sock);
socket_keepalive(client_fd);
return 0;
}
int write(int fd, const void* ptr, unsigned int sz) {
WSABUF vecs[1];
vecs[0].buf = (char*)ptr;
vecs[0].len = sz;
DWORD bytesSent;
if (WSASend(fd, vecs, 1, &bytesSent, 0, NULL, NULL)) {
int wsa_error = WSAGetLastError();
set_errno_from_wsa_error(wsa_error);
return -1;
} else {
return bytesSent;
}
}
int read(int fd, void* buffer, unsigned int sz) {
WSABUF vecs[1];
vecs[0].buf = buffer;
vecs[0].len = sz;
DWORD bytesRecv = 0;
DWORD flags = 0;
if (WSARecv(fd, vecs, 1, &bytesRecv, &flags, NULL, NULL)) {
int wsa_error = WSAGetLastError();
if (wsa_error == WSAECONNRESET) {
return 0; // Connection closed by peer
}
// Map WSA error to errno for better error reporting
set_errno_from_wsa_error(wsa_error);
return -1;
} else {
return bytesRecv;
}
}
// Wrapper for recv function with better error handling
int compat_recv(SOCKET s, char *buf, int len, int flags) {
WSABUF vecs[1];
vecs[0].buf = buf;
vecs[0].len = len;
DWORD bytesRecv = 0;
DWORD wsaFlags = 0;
if (WSARecv(s, vecs, 1, &bytesRecv, &wsaFlags, NULL, NULL)) {
int wsa_error = WSAGetLastError();
// Handle non-blocking operations - these are not real errors
if (wsa_error == WSAEWOULDBLOCK || wsa_error == WSAEINTR) {
// For non-blocking sockets, this is normal - no data available right now
set_errno_from_wsa_error(wsa_error);
return -1; // Caller should check errno == EAGAIN
}
if (wsa_error == WSAECONNRESET) {
return 0; // Connection closed by peer
}
// Map WSA error to errno for better error reporting
set_errno_from_wsa_error(wsa_error);
return -1;
} else {
return bytesRecv;
}
}
int close(int fd) {
shutdown(fd, SD_BOTH);
return closesocket(fd);
}
int daemon(int a, int b) {
// Not implemented
return 0;
}
char* strsep(char** stringp, const char* delim) {
char* s;
const char* spanp;
int c, sc;
char* tok;
if ((s = *stringp) == NULL)
return (NULL);
for (tok = s;;) {
c = *s++;
spanp = delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = 0;
*stringp = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
}

117
3rd/compat-mingw/unistd.h Normal file
View File

@@ -0,0 +1,117 @@
#pragma once
#include <assert.h>
#include <stdio.h>
#include <time.h>
#include <process.h>
#include <io.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
// Define missing errno values for network errors
#ifndef ECONNRESET
#define ECONNRESET 104
#endif
#ifndef ECONNABORTED
#define ECONNABORTED 103
#endif
#ifndef ECONNREFUSED
#define ECONNREFUSED 111
#endif
#ifndef ENETDOWN
#define ENETDOWN 100
#endif
#ifndef ENETUNREACH
#define ENETUNREACH 101
#endif
#ifndef EHOSTDOWN
#define EHOSTDOWN 112
#endif
#ifndef EHOSTUNREACH
#define EHOSTUNREACH 113
#endif
#ifndef ETIMEDOUT
#define ETIMEDOUT 110
#endif
#ifndef ENOTCONN
#define ENOTCONN 107
#endif
#ifndef EADDRINUSE
#define EADDRINUSE 98
#endif
#ifndef EADDRNOTAVAIL
#define EADDRNOTAVAIL 99
#endif
// Include winsock2.h for gethostname and other network functions
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <ws2tcpip.h>
// Undefine Windows legacy keywords that conflict with variable names
#ifdef near
#undef near
#endif
#ifdef far
#undef far
#endif
// Socket compatibility macros
#define SHUT_RD SD_RECEIVE
#define SHUT_WR SD_SEND
#define SHUT_RDWR SD_BOTH
#define ssize_t size_t
#define random rand
#define srandom srand
#define snprintf _snprintf
#define localtime_r _localtime64_s
#define pid_t int
int kill(pid_t pid, int exit_code);
void usleep(size_t us);
void sleep(size_t ms);
int clock_gettime(int what, struct timespec *ti);
enum { LOCK_EX, LOCK_NB };
int flock(int fd, int flag);
struct sigaction {
void (*sa_handler)(int);
int sa_flags;
int sa_mask;
};
enum { SIGPIPE, SIGHUP, SA_RESTART };
void sigfillset(int *flag);
int sigemptyset(int* set);
void sigaction(int flag, struct sigaction *action, void* param);
int pipe(int fd[2]);
int daemon(int a, int b);
#define O_NONBLOCK 1
#define F_SETFL 0
#define F_GETFL 1
int fcntl(int fd, int cmd, long arg);
char *strsep(char **stringp, const char *delim);
int write(int fd, const void* ptr, unsigned int sz);
int read(int fd, void* buffer, unsigned int sz);
// Wrapper function for recv with better error handling
int compat_recv(SOCKET s, char *buf, int len, int flags);
// Macro to redirect recv calls to our wrapper
#define recv compat_recv
int close(int fd);
#define getpid _getpid
#define open _open
#define dup2 _dup2

2253
3rd/compat-mingw/wepoll.c Normal file

File diff suppressed because it is too large Load Diff

113
3rd/compat-mingw/wepoll.h Normal file
View File

@@ -0,0 +1,113 @@
/*
* wepoll - epoll for Windows
* https://github.com/piscisaureus/wepoll
*
* Copyright 2012-2020, Bert Belder <bertbelder@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef WEPOLL_H_
#define WEPOLL_H_
#ifndef WEPOLL_EXPORT
#define WEPOLL_EXPORT
#endif
#include <stdint.h>
enum EPOLL_EVENTS {
EPOLLIN = (int) (1U << 0),
EPOLLPRI = (int) (1U << 1),
EPOLLOUT = (int) (1U << 2),
EPOLLERR = (int) (1U << 3),
EPOLLHUP = (int) (1U << 4),
EPOLLRDNORM = (int) (1U << 6),
EPOLLRDBAND = (int) (1U << 7),
EPOLLWRNORM = (int) (1U << 8),
EPOLLWRBAND = (int) (1U << 9),
EPOLLMSG = (int) (1U << 10), /* Never reported. */
EPOLLRDHUP = (int) (1U << 13),
EPOLLONESHOT = (int) (1U << 31)
};
#define EPOLLIN (1U << 0)
#define EPOLLPRI (1U << 1)
#define EPOLLOUT (1U << 2)
#define EPOLLERR (1U << 3)
#define EPOLLHUP (1U << 4)
#define EPOLLRDNORM (1U << 6)
#define EPOLLRDBAND (1U << 7)
#define EPOLLWRNORM (1U << 8)
#define EPOLLWRBAND (1U << 9)
#define EPOLLMSG (1U << 10)
#define EPOLLRDHUP (1U << 13)
#define EPOLLONESHOT (1U << 31)
#define EPOLL_CTL_ADD 1
#define EPOLL_CTL_MOD 2
#define EPOLL_CTL_DEL 3
typedef void* HANDLE;
typedef uintptr_t SOCKET;
typedef union epoll_data {
void* ptr;
int fd;
uint32_t u32;
uint64_t u64;
SOCKET sock; /* Windows specific */
HANDLE hnd; /* Windows specific */
} epoll_data_t;
struct epoll_event {
uint32_t events; /* Epoll events and flags */
epoll_data_t data; /* User data variable */
};
#ifdef __cplusplus
extern "C" {
#endif
WEPOLL_EXPORT HANDLE epoll_create(int size);
WEPOLL_EXPORT HANDLE epoll_create1(int flags);
WEPOLL_EXPORT int epoll_close(HANDLE ephnd);
WEPOLL_EXPORT int epoll_ctl(HANDLE ephnd,
int op,
SOCKET sock,
struct epoll_event* event);
WEPOLL_EXPORT int epoll_wait(HANDLE ephnd,
struct epoll_event* events,
int maxevents,
int timeout);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* WEPOLL_H_ */

View File

@@ -121,6 +121,7 @@ $(LUA_CLIB_PATH)/lpeg.so : 3rd/lpeg/lpcap.c 3rd/lpeg/lpcode.c 3rd/lpeg/lpprint.c
clean : clean :
rm -f $(SKYNET_BUILD_PATH)/skynet $(CSERVICE_PATH)/*.so $(LUA_CLIB_PATH)/*.so && \ rm -f $(SKYNET_BUILD_PATH)/skynet $(CSERVICE_PATH)/*.so $(LUA_CLIB_PATH)/*.so && \
rm -rf $(SKYNET_BUILD_PATH)/*.dSYM $(CSERVICE_PATH)/*.dSYM $(LUA_CLIB_PATH)/*.dSYM rm -rf $(SKYNET_BUILD_PATH)/*.dSYM $(CSERVICE_PATH)/*.dSYM $(LUA_CLIB_PATH)/*.dSYM
$(MAKE) clean -f mingw.mk
cleanall: clean cleanall: clean
ifneq (,$(wildcard 3rd/jemalloc/Makefile)) ifneq (,$(wildcard 3rd/jemalloc/Makefile))
@@ -128,3 +129,4 @@ ifneq (,$(wildcard 3rd/jemalloc/Makefile))
endif endif
cd 3rd/lua && $(MAKE) clean cd 3rd/lua && $(MAKE) clean
rm -f $(LUA_STATICLIB) rm -f $(LUA_STATICLIB)
$(MAKE) cleanall -f mingw.mk

161
mingw.mk Normal file
View File

@@ -0,0 +1,161 @@
# Cross-compilation toolchain
CC = x86_64-w64-mingw32-gcc
AR = x86_64-w64-mingw32-ar
RANLIB = x86_64-w64-mingw32-ranlib
LUA_CLIB_PATH ?= luaclib
CSERVICE_PATH ?= cservice
SKYNET_BUILD_PATH ?= .
COMPAT_MINGW_DIR = 3rd/compat-mingw
LUA_DIR = 3rd/lua
LUA_CFLAGS = -g -O2 -Wall -I. -std=gnu99 -I../../skynet-src
LUA_STATICLIB := 3rd/lua/liblua.a
LUA_DLL ?= 3rd/lua/lua54.dll
SKYNET_DLL ?= $(SKYNET_BUILD_PATH)/skynet.dll
LUA_INC ?= $(LUA_DIR)
# Lua linking options
LUA_LIBS = -L$(LUA_DIR) -llua54
LUA_STATIC_LIBS = $(LUA_STATICLIB)
# Skynet linking and include options
SKYNET_LINK_LIBS = -L$(SKYNET_BUILD_PATH) -lskynet
SKYNET_INCLUDES = -Iskynet-src -I$(COMPAT_MINGW_DIR) -I$(LUA_INC)
SHARED_BUILD = $(CC) $(CFLAGS) $(SHARED)
# Compiler flags
CFLAGS = -g -O2 -Wall -std=gnu99 -I$(LUA_INC) $(MYCFLAGS)
CFLAGS += -I3rd/lua -Iskynet-src -I$(COMPAT_MINGW_DIR)
CFLAGS += -include $(COMPAT_MINGW_DIR)/compat.h
CFLAGS += -Wno-int-conversion -Wno-incompatible-pointer-types -Wno-pointer-sign -Wno-unused-function
LDFLAGS = -Wl,--export-all-symbols,--out-implib,libskynet.a
SHARED = -fPIC --shared -Wl,--export-all-symbols,--enable-auto-import,--allow-shlib-undefined,--unresolved-symbols=ignore-all
SKYNET_LIBS = -static-libgcc -Wl,-Bstatic -lpthread -Wl,-Bdynamic -lm -lws2_32 -lgdi32
SKYNET_DEFINES = -DNOUSE_JEMALLOC
COMPAT_LIB = $(COMPAT_MINGW_DIR)/libcompat.a
CSERVICE = snlua logger gate harbor
LUA_CLIB = skynet client bson md5 sproto lpeg
LUA_CLIB_SKYNET = \
lua-skynet.c lua-seri.c \
lua-socket.c \
lua-mongo.c \
lua-netpack.c \
lua-memory.c \
lua-multicast.c \
lua-cluster.c \
lua-crypt.c lsha1.c \
lua-sharedata.c \
lua-stm.c \
lua-debugchannel.c \
lua-datasheet.c \
lua-sharetable.c \
\
SKYNET_SRC = skynet_main.c skynet_handle.c skynet_module.c skynet_mq.c \
skynet_server.c skynet_start.c skynet_timer.c skynet_error.c \
skynet_harbor.c skynet_env.c skynet_monitor.c skynet_socket.c socket_server.c \
mem_info.c malloc_hook.c skynet_daemon.c skynet_log.c
$(LUA_STATICLIB):
@echo "Building Lua static library..."
cd $(LUA_DIR) && $(CC) $(LUA_CFLAGS) -DMAKE_LIB -c onelua.c -o onelua.o
cd $(LUA_DIR) && $(AR) rcs liblua.a onelua.o
$(LUA_DLL) : $(LUA_STATICLIB)
@echo "Building Lua DLL..."
cd $(LUA_DIR) && $(CC) -shared -o lua54.dll onelua.o -Wl,--export-all-symbols,--out-implib,liblua54.a $(SKYNET_LIBS)
@echo "Lua DLL and import library created successfully"
$(LUA_DIR)/lua.exe : $(LUA_DLL) $(LUA_STATICLIB)
@echo "Building Lua interpreter..."
cd $(LUA_DIR) && $(CC) $(LUA_CFLAGS) -c lua.c -o lua.o
cd $(LUA_DIR) && $(CC) $(LUA_CFLAGS) -o lua.exe lua.o -L. -llua54 $(SKYNET_LIBS)
cp $(LUA_DLL) $(SKYNET_BUILD_PATH)/
$(LUA_DIR)/luac.exe : $(LUA_DLL) $(LUA_STATICLIB)
@echo "Building Lua compiler..."
cd $(LUA_DIR) && $(CC) $(LUA_CFLAGS) -DMAKE_LUAC -c onelua.c -o luac.o
cd $(LUA_DIR) && $(CC) $(LUA_CFLAGS) -o luac.exe luac.o liblua.a $(SKYNET_LIBS)
$(COMPAT_LIB): $(COMPAT_MINGW_DIR)/compat.c
@echo "Building compatibility library..."
$(CC) $(CFLAGS) -c $(COMPAT_MINGW_DIR)/compat.c -o $(COMPAT_MINGW_DIR)/compat.o
cd $(COMPAT_MINGW_DIR) && $(AR) rcs libcompat.a compat.o
cd $(COMPAT_MINGW_DIR) && $(RANLIB) libcompat.a
# Build order: first build core libraries, then dependent modules
all : core_libs modules tools
.PHONY: core_libs modules tools
core_libs: $(LUA_STATICLIB) $(LUA_DLL) $(SKYNET_DLL)
modules: core_libs $(foreach v, $(CSERVICE), $(CSERVICE_PATH)/$(v).so) $(foreach v, $(LUA_CLIB), $(LUA_CLIB_PATH)/$(v).so)
tools: core_libs $(LUA_DIR)/lua.exe $(LUA_DIR)/luac.exe $(SKYNET_BUILD_PATH)/skynet.exe
SKYNET_LIB_SRC = $(filter-out skynet_main.c, $(SKYNET_SRC))
$(SKYNET_DLL) : $(foreach v, $(SKYNET_LIB_SRC), skynet-src/$(v)) $(COMPAT_LIB) $(LUA_DLL)
@echo "Building skynet.dll..."
$(CC) $(CFLAGS) -shared -o $@ $(foreach v, $(SKYNET_LIB_SRC), skynet-src/$(v)) $(COMPAT_LIB) $(LUA_LIBS) $(SKYNET_INCLUDES) $(SKYNET_LIBS) $(SKYNET_DEFINES) $(LDFLAGS)
$(SKYNET_BUILD_PATH)/skynet.exe : skynet-src/skynet_main.c $(SKYNET_DLL) $(COMPAT_LIB) $(LUA_DLL)
@echo "Building skynet.exe..."
$(CC) $(CFLAGS) -o $@ skynet-src/skynet_main.c $(COMPAT_LIB) $(SKYNET_LINK_LIBS) $(LUA_LIBS) $(SKYNET_INCLUDES) $(SKYNET_LIBS) $(SKYNET_DEFINES)
cp $(LUA_DLL) $(SKYNET_BUILD_PATH)/
$(LUA_CLIB_PATH) :
mkdir $(LUA_CLIB_PATH)
$(CSERVICE_PATH) :
mkdir $(CSERVICE_PATH)
define CSERVICE_TEMP
$$(CSERVICE_PATH)/$(1).so : service-src/service_$(1).c $$(LUA_DLL) $$(SKYNET_DLL) | $$(CSERVICE_PATH)
$$(CC) $$(CFLAGS) $$(SHARED) $$< -o $$@ $$(SKYNET_INCLUDES) $$(LUA_LIBS) $$(SKYNET_LINK_LIBS)
endef
$(foreach v, $(CSERVICE), $(eval $(call CSERVICE_TEMP,$(v))))
$(LUA_CLIB_PATH)/skynet.so : $(addprefix lualib-src/,$(LUA_CLIB_SKYNET)) $(SKYNET_DLL) $(LUA_DLL) | $(LUA_CLIB_PATH)
$(SHARED_BUILD) $(addprefix lualib-src/,$(LUA_CLIB_SKYNET)) -o $@ $(SKYNET_INCLUDES) -Iservice-src -Ilualib-src $(SKYNET_LINK_LIBS) $(LUA_LIBS) $(SKYNET_LIBS)
$(LUA_CLIB_PATH)/bson.so : lualib-src/lua-bson.c $(LUA_DLL) | $(LUA_CLIB_PATH)
$(SHARED_BUILD) $^ -o $@ $(SKYNET_INCLUDES) $(LUA_LIBS) $(SKYNET_LIBS)
$(LUA_CLIB_PATH)/md5.so : 3rd/lua-md5/md5.c 3rd/lua-md5/md5lib.c 3rd/lua-md5/compat-5.2.c $(LUA_DLL) | $(LUA_CLIB_PATH)
$(SHARED_BUILD) -I3rd/lua-md5 -Wno-attributes $^ -o $@ $(LUA_LIBS) $(SKYNET_LIBS)
$(LUA_CLIB_PATH)/client.so : lualib-src/lua-clientsocket.c lualib-src/lua-crypt.c lualib-src/lsha1.c $(COMPAT_LIB) $(LUA_DLL) | $(LUA_CLIB_PATH)
$(SHARED_BUILD) $^ -o $@ $(LUA_LIBS) $(SKYNET_LIBS)
$(LUA_CLIB_PATH)/sproto.so : lualib-src/sproto/sproto.c lualib-src/sproto/lsproto.c $(LUA_DLL) | $(LUA_CLIB_PATH)
$(SHARED_BUILD) -Ilualib-src/sproto $^ -o $@ $(LUA_LIBS) $(SKYNET_LIBS)
$(LUA_CLIB_PATH)/lpeg.so : 3rd/lpeg/lpcap.c 3rd/lpeg/lpcode.c 3rd/lpeg/lpprint.c 3rd/lpeg/lptree.c 3rd/lpeg/lpvm.c 3rd/lpeg/lpcset.c $(LUA_DLL) | $(LUA_CLIB_PATH)
$(SHARED_BUILD) -I3rd/lpeg $^ -o $@ $(LUA_LIBS) $(SKYNET_LIBS)
.PHONY: clean cleanall core_libs modules tools
clean :
rm -f $(SKYNET_BUILD_PATH)/*.exe $(SKYNET_BUILD_PATH)/*.dll $(SKYNET_BUILD_PATH)/*.a
rm -f $(COMPAT_LIB) $(COMPAT_MINGW_DIR)/*.o
rm -f $(CSERVICE_PATH)/*.so $(LUA_CLIB_PATH)/*.so
rm -f $(LUA_DIR)/*.a
cleanall: clean
rm -f $(LUA_STATICLIB)
rm -f $(LUA_DIR)/*.exe $(LUA_DIR)/*.dll $(LUA_DIR)/*.a $(LUA_DIR)/*.o

View File

@@ -1,5 +1,5 @@
PLAT ?= none PLAT ?= none
PLATS = linux freebsd macosx PLATS = linux freebsd macosx mingw
CC ?= gcc CC ?= gcc
@@ -25,6 +25,7 @@ EXPORT := -Wl,-E
linux : PLAT = linux linux : PLAT = linux
macosx : PLAT = macosx macosx : PLAT = macosx
freebsd : PLAT = freebsd freebsd : PLAT = freebsd
mingw : PLAT = mingw
macosx : SHARED := -fPIC -dynamiclib -Wl,-undefined,dynamic_lookup macosx : SHARED := -fPIC -dynamiclib -Wl,-undefined,dynamic_lookup
macosx : EXPORT := macosx : EXPORT :=
@@ -38,3 +39,6 @@ macosx : SKYNET_DEFINES :=-DNOUSE_JEMALLOC
linux macosx freebsd : linux macosx freebsd :
$(MAKE) all PLAT=$@ SKYNET_LIBS="$(SKYNET_LIBS)" SHARED="$(SHARED)" EXPORT="$(EXPORT)" MALLOC_STATICLIB="$(MALLOC_STATICLIB)" SKYNET_DEFINES="$(SKYNET_DEFINES)" $(MAKE) all PLAT=$@ SKYNET_LIBS="$(SKYNET_LIBS)" SHARED="$(SHARED)" EXPORT="$(EXPORT)" MALLOC_STATICLIB="$(MALLOC_STATICLIB)" SKYNET_DEFINES="$(SKYNET_DEFINES)"
mingw :
$(MAKE) -f mingw.mk all PLAT=$@