简介:记录开发一个跨平台C++项目的历程

1. 背景

我司服务端项目大部分使用一个简单的模式:C++做底层负责网络/内存/多线程/日志等,内嵌一个Lua虚拟机,业务逻辑都用Lua写。这个模式既能提供高性能,又能让业务逻辑开发简单,安全。多年来运作良好。

过去几年,服务端的开发和运行环境均在Linux下。今年要开一个新项目,我心血来潮想要在Windows下开发,当然线上还是部署在Linux中。所以就需要让这个项目同时支持Linux和Windows。业务层面好说,因为用Lua开发,本身100%跨平台。所以只需要让C++代码能跨平台编译运行即可。

2. C++跨平台编译运行

我们的C++项目主要依赖STL/Lua/Socket库。

  1. STL本身就是跨平台的,只要有C++编译器即可。线程库用的c++11的std::thread。Easy!
  2. Lua源代码是用标准C89写,基本零依赖,几乎所有平台都可以编译,但我懒的自己编译了,所以直接用社区提供的LuaBinaries
  3. Socket库我们是自己开发的,所以简单封装了一个Socket类,底层根据不同平台调用不同的API,对外提供统一的抽象接口。

遇到的第一个问题是:如何"一键"在Win/Linux下编译

Linux平台下,我们一直用Makefile,所以轻车熟路的写了一个,搞定Linux下编译。

Windows平台下,就没那么简单了,绕了点弯路。由于我本身用了多年的cygwin,所以直接用cygwin下的gcc编译,还能直接用我为Linux平台写的Makefile。这一步也很简单,但问题出在Lua的C模块上,我们用了一些开源的Lua C模块,例如lua-cjson,这个东西虽然也可以在cygwin下编译,但运行时Lua虚拟机总是不能正确加载,折腾了好久最终放弃。因为考虑到以后可能还会用到其他开源的项目,而且其他项目成员也不一定都喜欢装一个cygwin,所以我还是决定弄成Windows原生的exe和dll。

安装了一个VS2019(这东西真大,十几个G),所有C++代码丢进去,配置下链接上面提到的LuaBinaries,运行完美。那开源的项目如何编译成原生dll呢?由于开源项目大多提供了Makefile或CMake的编译脚本,很少直接提供VS工程的,所以我决定用mingw。下面以编译lua-cjson为例记录下过程。

  1. 安装MingW,并将MingW的bin目录加入Path中

  2. 下载lua-cjson-2.1.0(https://www.kyne.com.au/\~mark/software/download/lua-cjson-2.1.0.tar.gz)

  3. 修改lua-cjson的Makefile,放开## Windows (MinGW)下面的注释

    ## Windows (MinGW)
    CC =                gcc # 增加此行
    TARGET =            cjson.dll
    PREFIX =            c:/LuaBinaries # 改成你的LuaBinaries目录
    CJSON_CFLAGS =      -DDISABLE_INVALID_NUMBERS
    CJSON_LDFLAGS =     -shared -L$(PREFIX) -llua53 # 这里根据你的Lua版本配置
    

    然后打开CMD,cd到lua-cjson-2.1.0目录,运行:

    mingw32-make
    
  4. 踩到过的坑:链接lua dll时gcc报错"lua53.dll 无法识别的格式"。卡了半天才发现原来mingw的32位和64位是两个独立的项目。我用google搜mingw的官网,找到了(https://sourceforge.net/projects/mingw/),这个是32位的。而我下载的LuaBinaries是64位,自然链接不到。64位的mingw是这个(https://sourceforge.net/projects/mingw-w64/),注意根据你的平台选择正确的版本!