Skynet 跨平台编译折腾了几次,这里主要记录下流水账。skynet 官方是只支持 linux,freebsd,macosx 三个平台的,一直都没支持 windows,这里说的跨平台编译主要也是 windows 平台。
很久以前在 android 上编译过,很简单,termux 里安装 gcc 基本就能编译成功,区别只是 arm 和 x86 的区别,因为基建都有人封装好,skynet 也没没有依赖硬件是 x86 还是 arm的,这类跨平台编译可以归纳为 linux 类跨平台编译。
macosx 很早就支持了的,支持的原因可能就是因为是 bsd 一个体系的,关键是支持 kqueue ,所以在 macosx 下编译就是顺手的事。
windows 就不同了,除了 posix 的差异,比如 pthread,关键还是 epoll 事件的支持。pthread 基建很全,无论是 mingw 还是 vs 环境,都有人封装好 pthread 库了,能直接使用。skynet 的另一个类似版本 hive 是支持 select 的,因此有人想到的方案是使用 select 模拟 epoll 来实现 windows 版本,就是这个 dpull/skynet-mingw 。在这个之前还见过有人侵入式修改的版本,可能就是因为需要侵入修改,就没人使用吧,找不到链接了。
后面又有了这个 vs 版本 cloudfreexiao/skynet/tree/windows ,这个版本的区别是能在 vs 里编译,epoll 不是用的 select 实现的,而是直接使用的 wepoll 这个库。因为vs 新版本支持了 clang 和 cmake,因此我就试试用 cmake 来编译 skynet ,这样就能很方便命令行编译和 vs 环境编译,只需要一份 cmake 配置即可,因此有了 skynet-cmake 。
按理说有了 skynet-cmake 之后,应该没必要再折腾了吧。但是上周又有人在我的 qq 群里聊到 windows 版本的问题,嫌弃 cmake ,学了 make 还得学 cmake 。因此我又折腾了一个版本,只使用 make,同样保持和 cmake 一样做到零侵入修改,只修改 makefile 和 platform.mk 引入 mingw.mk 即可,其实不引入也行,只是不引入得用 make -f mingw.mk ,引入只是为了直接使用 make mingw 来编译,当然引入了 3rd/compat-mingw ,由于是新增目录,不会有冲突,而且只在 mingw 生效。已经提了个 PR : cloudwu/skynet#2108 ,我是希望能合并进去的,这样应该不会再有人问为啥没有 skynet.exe 了吧。也想过侵入是修改 makefile 和 platform.mk ,而不是像现在这样独立一个 mingw.mk ,由于改动太大,windows 平台得编译 dll 的奇葩情况,独立一个 mingw.mk 是改动最小的方案了。
windows 平台编译主要需要注意的地方就是:
- lua 需要编译成 dll ,否则是无法加载动态库的,这也是为什么 lua 官方的 makefile 里 lua.exe 是动态链接 lua54.dll 的原因。
- pthread 需要静态链接进去,否则找不到 pthread.dll 。
- skynet 最好也是编译成 dll ,这样 c 服务或者 lua 库也是引用的 skynet.dll ,lua54.dll 也不要静态打包 到 skynet.dll ,防止出现 2 个lua 虚拟机的问题,导致 lua 的 c 库莫名其秒的不可用。
在 debian13 下只需要安装下面这些依赖就能轻松编译出 linux 版本和 windows 版本的 skynet 了。
# 安装所有必需的包
apt-get update && apt-get install -y --no-install-recommends \
# 编译工具链
build-essential \
make \
pkg-config \
\
# MinGW-w64 (支持32位和64位)
mingw-w64 \
mingw-w64-tools \
mingw-w64-i686-dev \
mingw-w64-x86-64-dev \
\
# 可选依赖
autoconf \
automake \
libtool \
\
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*还想偷懒就直接用这个 docker 吧 : https://github.com/hanxi/skynet-builder 。
最后,跟 dpull/skynet-mingw 一样,是有已知缺陷的,比如 console 服务不可用:
PS C:\work\skynet\skynet\skynet> .\skynet.exe .\examples\config
[:01000002] LAUNCH snlua bootstrap
[:01000003] LAUNCH snlua launcher
[:01000004] LAUNCH snlua cmaster
[:01000004] master listen socket 0.0.0.0:2013
[:01000005] LAUNCH snlua cslave
[:01000005] slave connect to master 127.0.0.1:2013
[:01000004] connect from 127.0.0.1:49225 4
[:01000006] LAUNCH harbor 1 16777221
[:01000004] Harbor 1 (fd=4) report 127.0.0.1:2526
[:01000005] Waiting for 0 harbors
[:01000005] Shakehand ready
[:01000007] LAUNCH snlua datacenterd
[:01000008] LAUNCH snlua service_mgr
[:01000009] LAUNCH snlua main
[:00000000] error: A message from [ :01000009 ] to [ :01000009 ] maybe in an endless loop (version = 87)
[:01000009] Server start
[:0100000a] LAUNCH snlua protoloader
[:0100000b] LAUNCH snlua console
[:0100000c] LAUNCH snlua debug_console 8000
[:0100000b] lua call [0 to :100000b : 0 msgsz = 56] error : ./lualib/skynet.lua:988: ./lualib/skynet.lua:452: ./lualib/skynet\socket.lua:365: assertion failed!
stack traceback:
[C]: in function 'assert'
./lualib/skynet\socket.lua:365: in function 'skynet.socket.readline'
./service/console.lua:16: in upvalue 'f'
./lualib/skynet.lua:375: in function <./lualib/skynet.lua:374>
stack traceback:
[C]: in function 'assert'
./lualib/skynet.lua:988: in function 'skynet.dispatch_message'
[:0100000c] Start debug console at 127.0.0.1:8000
[:0100000d] LAUNCH snlua simpledb
[:0100000e] LAUNCH snlua watchdog
[:0100000f] LAUNCH snlua gate
[:0100000f] Listen on 0.0.0.0:8888
[:01000009] Watchdog listen on 0.0.0.0:8888
[:01000009] KILL self
[:01000002] KILL self客户端运行效果:
PS C:\work\skynet\skynet\skynet> .\3rd\lua\lua.exe .\examples\client.lua
Request: 1
Request: 2
RESPONSE 1
msg Welcome to skynet, I will send heartbeat every 5 sec.
RESPONSE 2
hello
Request: 3
RESPONSE 3
result world
REQUEST heartbeat