Unity跨平台C/CPP动态库编译---可靠UDP网络库kcp基于CMake的各平台构建实践
一 为什么需要动态库
1)提供原生代码(native code)的支持,也叫原生插件,但是我实践的是c/cpp跨平台动态库,这里不具体涉及安卓平台java库和ios平台的objectc库构建。
2)某些开源库是c/cpp编写,没有对应c#版本
3)或者有c#版本实现,但是效率或者gc达不到期望效果,特别是GC,一般的开源库c#版本的作者,对gc优化得大多不好
4)追求效率,比如A*寻路等开销比较大的算法,想做下优化
5)某些模块,如网络模块,需要Unity客户端和后端跑一份相同的逻辑代码,而不想维护两份语言的实现
二 示例demo选择
前阵子由于项目需要,编译了一下kcp库,这里拿kcp编译到Unity的各平台动态库来做一次总结,kcp的github地址:https://github.com/skywind3000/kcp。
有关这个库的其它信息这里不做介绍,它本质就是一个可靠UDP的网络库,我们项目是用在了一款多人实时射击类游戏中。
三 编译工具选择
这里使用的是CMake,官网地址为:https://cmake.org/。有关CMake的使用资料自行网络获取,我这里只说一点,这是一个跨平台的构建工具,针对不同的平台,只需要一份描述文件,很方便,不需要每个平台去写makefile。
四 示例demo选择
其中:
1)cmke目录:包含CMake在安卓、iOS平台进行构建时需要要到的两个文件:android.toolchain.cmake、iOS.cmake
2)Plugins目录:各平台构建的输出目录,构建完成后可以直接放置到Unity项目Assdets目录下使用
3)CMakeLists.txt文件:主要要由我们自己编写的一个文件,cmake根据CMakeLists生成各个平台编译的中间文件以及makefile文件
4)目标库源代码:kcp.h、kcp.c
5)make_xxx:各平台执行构建脚本文件,这些文件基本是固定的,不需要做什么修改
五 项目简要说明
1、kcp项目需要做的调整
kcp.c不需要动,kcp.h修改部分如下:
#ifdef DLL_EXPORTS
#define KCPDLL _declspec(dllexport)
#else
#define KCPDLL
#endif #ifdef __cplusplus
extern "C" {
#endif //---------------------------------------------------------------------
// interface
//--------------------------------------------------------------------- // create a new kcp control object, 'conv' must equal in two endpoint
// from the same connection. 'user' will be passed to the output callback
// output callback can be setup like this: 'kcp->output = my_udp_output'
KCPDLL ikcpcb* ikcp_create(IUINT32 conv, void *user);
//其它导出接口省略 #ifdef __cplusplus
}
#endif
2、CMakeLists文件编写
cmake_minimum_required(VERSION 2.8) if ( WIN32 AND NOT CYGWIN AND NOT ( CMAKE_SYSTEM_NAME STREQUAL "WindowsStore" ) )
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT" CACHE STRING "")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd" CACHE STRING "")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT" CACHE STRING "")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd" CACHE STRING "")
endif () project(kcp) if ( IOS )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode")
endif () find_path(KCP_PROJECT_DIR NAMES SConstruct
PATHS
${CMAKE_SOURCE_DIR}
NO_DEFAULT_PATH
) MARK_AS_ADVANCED(KCP_PROJECT_DIR) set ( KCP_CORE
kcp.c
) macro(source_group_by_dir proj_dir source_files)
if(MSVC OR APPLE)
get_filename_component(sgbd_cur_dir ${proj_dir} ABSOLUTE)
foreach(sgbd_file ${${source_files}})
get_filename_component(sgbd_abs_file ${sgbd_file} ABSOLUTE)
file(RELATIVE_PATH sgbd_fpath ${sgbd_cur_dir} ${sgbd_abs_file})
string(REGEX REPLACE "\(.*\)/.*" \\ sgbd_group_name ${sgbd_fpath})
string(COMPARE EQUAL ${sgbd_fpath} ${sgbd_group_name} sgbd_nogroup)
string(REPLACE "/" "\\" sgbd_group_name ${sgbd_group_name})
if(sgbd_nogroup)
set(sgbd_group_name "\\")
endif(sgbd_nogroup)
source_group(${sgbd_group_name} FILES ${sgbd_file})
endforeach(sgbd_file)
endif(MSVC OR APPLE)
endmacro(source_group_by_dir) source_group_by_dir(${CMAKE_CURRENT_SOURCE_DIR} KCP_CORE) if (APPLE)
if (IOS)
set(CMAKE_OSX_ARCHITECTURES "$(ARCHS_STANDARD)")
add_library(kcp STATIC
${KCP_CORE}
)
else ()
set(CMAKE_OSX_ARCHITECTURES "$(ARCHS_STANDARD_32_64_BIT)")
add_library(kcp MODULE
${KCP_CORE}
)
set_target_properties ( kcp PROPERTIES BUNDLE TRUE )
#set_target_properties ( kcp PROPERTIES FRAMEWORK TRUE )
#set_target_properties ( kcp PROPERTIES MACOSX_RPATH TRUE )
endif ()
else ( )
add_library(kcp SHARED
${KCP_CORE}
)
endif ( ) if ( WIN32 AND NOT CYGWIN )
target_compile_definitions (kcp PRIVATE DLL_EXPORTS)
endif ( )
1)第10行:指定项目名称为kcp
2)第26行:指定要编译的c/cpp文件
3)第70行:指定预定义宏DLL_EXPORTS,这个宏只有在window平台编译dll动态库才需要,其它平台不需要
4)其它没什么好说的,在构建你自己的项目时,只需要注意的带有“kcp”字样的地方替换为你自己对应的项目名称即可。
3、各平台构建脚本
1)window32位系统:make_win32.bat
mkdir build32 & pushd build32
cmake -G "Visual Studio 14 2015" ..
popd
cmake --build build32 --config Release
md Plugins\x86
copy /Y build32\Release\kcp.dll Plugins\x86\kcp.dll
rmdir /S /Q build32
pause
2)windows64位系统:make_win64.bat
mkdir build64 & pushd build64
cmake -G "Visual Studio 14 2015 Win64" ..
popd
cmake --build build64 --config Release
md Plugins\x86_64
copy /Y build64\Release\kcp.dll Plugins\x86_64\kcp.dll
rmdir /S /Q build64
pause
3)linux32位系统:make_linux32.sh
mkdir -p build_linux32 && cd build_linux32
cmake -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 -DCMAKE_SHARED_LINKER_FLAGS=-m32 ../
cd ..
cmake --build build_linux32 --config Release
cp build_linux32/kcp.so Plugins/x86/kcp.so
rm -rf build_linux32
4)linux64位系统:make_linux64.sh
mkdir -p build_linux64 && cd build_linux64
cmake ../
cd ..
cmake --build build_linux64 --config Release
cp build_linux64/kcp.so Plugins/x86_64/kcp.so
rm -rf build_linux64
5)Mac系统:make_osx.sh
mkdir -p build_osx && cd build_osx
cmake -GXcode ../
cd ..
cmake --build build_osx --config Release
mkdir -p Plugins/kcp.bundle/Contents/MacOS/
cp build_osx/Release/kcp.bundle/Contents/MacOS/kcp Plugins/kcp.bundle/Contents/MacOS/kcp
rm -rf build_osx
6)android系统:make_android.sh
if [ -z "$ANDROID_NDK" ]; then
export ANDROID_NDK=~/android-ndk-r10e
fi mkdir -p build_v7a && cd build_v7a
cmake -DANDROID_ABI=armeabi-v7a -DCMAKE_TOOLCHAIN_FILE=../cmake/android.toolchain.cmake -DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-clang3. -DANDROID_NATIVE_API_LEVEL=android- ../
cd ..
cmake --build build_v7a --config Release
mkdir -p Plugins/Android/libs/armeabi-v7a/
cp build_v7a/libkcp.so Plugins/Android/libs/armeabi-v7a/libkcp.so
rm -rf build_v7a mkdir -p build_x86 && cd build_x86
cmake -DANDROID_ABI=x86 -DCMAKE_TOOLCHAIN_FILE=../cmake/android.toolchain.cmake -DANDROID_TOOLCHAIN_NAME=x86-clang3. -DANDROID_NATIVE_API_LEVEL=android- ../
cd ..
cmake --build build_x86 --config Release
mkdir -p Plugins/Android/libs/x86/
cp build_x86/libkcp.so Plugins/Android/libs/x86/libkcp.so
rm -rf build_x86
7)iOS系统:make_ios.sh
mkdir -p build_ios && cd build_ios
cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/iOS.cmake -GXcode ../
cd ..
cmake --build build_ios --config Release
mkdir -p Plugins/iOS/
exist_armv7=`lipo -info build_ios/Release-iphoneos/libkcp.a | grep armv7 | wc -l`
exist_arm64=`lipo -info build_ios/Release-iphoneos/libkcp.a | grep arm64 | wc -l`
if [ $[exist_armv7] -eq ]; then
echo "** ERROR **: No support for armv7, maybe XCode version is to high, use manual_build_ios instead!"
elif [ $[exist_arm64] -eq ]; then
echo "** ERROR ** : No support for arm64, maybe XCode version is to high, use manual_build_ios instead!"
else
cp build_ios/Release-iphoneos/libkcp.a Plugins/iOS/libkcp.a
rm -rf build_io
fi
8)Windows Phone系统:make_uwp.bat
mkdir build_uwp & pushd build_uwp
cmake -G "Visual Studio 14 2015" -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0 ..
popd
cmake --build build_uwp --config Release
md Plugins\WSA\x86
copy /Y build_uwp\Release\kcp.dll Plugins\WSA\x86\kcp.dll
rmdir /S /Q build_uwp mkdir build_uwp64 & pushd build_uwp64
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0 ..
popd
cmake --build build_uwp64 --config Release
md Plugins\WSA\x64
copy /Y build_uwp64\Release\kcp.dll Plugins\WSA\x64\kcp.dll
rmdir /S /Q build_uwp64 mkdir build_uwp_arm & pushd build_uwp_arm
cmake -G "Visual Studio 14 2015 ARM" -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0 ..
popd
cmake --build build_uwp_arm --config Release
md Plugins\WSA\ARM
copy /Y build_uwp_arm\Release\kcp.dll Plugins\WSA\ARM\kcp.dll
rmdir /S /Q build_uwp_arm pause
9)这些脚本都很简单明了,像需要的VS版本、安卓的NDK版本等等,一看便知。要移植到你自己的构建项目也很简单,基本只需要修改项目名称即可。
六 各平台构建环境简要说明
1)以下各平台,均需要安装CMake,安装教程,包括各平台环境变量等的配置自行谷歌,很多相关帖子。
2)window系统和windows phone系统:在window系统中执行对应的.bat脚本即可,windows phone的编译需要相关SDK。本帖使用VS2015,windows phone暂时不需要,所以没有构建测试过。
3)linux系统:在linux系统中执行对应的.sh脚本即可
4)mac系统:在mac系统中执行对应的.sh脚本即可
5)iOS系统:在mack系统中执行对应的.sh脚本即可。需要xcode版本8.1,版本太高会有问题,可以进行手动构建,参考博文:iOS代码封装成.a文件(封装SDK)。真机上的.a动态库需要同时支持armv7,ram64架构,查看你编译出来的.a是否是正确架构可使用lipo -info kcp.a
6)android系统:安卓系统可以在各个平台编译,我这里是在linux系统中编译的,执行对应的.sh脚本即可,andorid SDK版本为:android-ndk-r10e。关于SDK安装以及环境变量配置自行谷歌。
7)可能根据各位自己的情况,编译过程会遇到各种小问题,但是这些问题几乎都是出在环境上,如环境变量、SDK版本、xcode版本等,我这里已经对环境信息给了足够的说明,如果你实践当中问题解决不了,可以参考我这里列举的环境。
8).sh文件在window下编辑可能会存在文件结束符问题,使用doc2unix命令转换就好,遇到权限问题使用chmod命令就好,其它可能遇到的细节问题自己耐心多多摸索,问题都不大。
七 Unity项目动态库配置简要说明
1、输出目录结构
由于我们公司全部在window下开发,所以没有编译linux下的动态库,如果你们需要,将在x86、x86_64目录下存在libkcp.so文件。同样,window phone平台也没实测。
2、window平台
x86、x86_64下的.dll文件:
3、Mac平台
kcp.bundle,配置时选择osx系统,任意cpu
4、linux平台
x86、x86_64下的.so文件,相应配置
5、andorid平台
Android子目录下的.so文件,选择Android Platform,cpu架构做对应勾选,很简单,不再截图
6、iOS平台
选择iOS Platform
八 动态库项目使用
编写对应kcp.cs文件,声明外部函数,脚本如下:
namespace KCP
{
using System;
using System.Runtime.InteropServices; public class kcp
{
#if UNITY_IPHONE && !UNITY_EDITOR
const string KcpDLL = "__Internal";
#else
const string KcpDLL = "kcp";
#endif [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
public static extern uint ikcp_check(IntPtr kcp, uint current);、
//其它接口省略
}
}
1)函数调用约定指明为cdecl
2)所有接口以静态外部函数导出
3)DllIport在iOS上和其它平台导出使用的参数不一样
4)在构建你自己的动态库时依葫芦画瓢就好,没啥太多要说的
九 kcp_build完整构建工程
github地址:https://github.com/smilehao/kcp_bulild
Unity跨平台C/CPP动态库编译---可靠UDP网络库kcp基于CMake的各平台构建实践的更多相关文章
- Unity3D跨平台动态库编译---记kcp基于CMake的各平台构建实践
一 为什么需要动态库 1)提供原生代码(native code)的支持,也叫原生插件,但是我实践的是c/cpp跨平台动态库,这里不具体涉及安卓平台java库和ios平台的objectc库构建. 2)某 ...
- libevent网络库
1.概述 libevent是一个C语言编写的.轻量级开源高性能事件通知库.作为底层网络库,已经被广泛应用(如:memcached.Vomit.Nylon.Netchat等).主要有以下几个亮点: 事件 ...
- 专注于HTTP的高性能高易用性网络库:Fslib.network库
博客列表页:http://blog.fishlee.net/tag/fslib-network/ 原创FSLib.Network库(目前专注于HTTP的高性能高易用性网络库) FSLib.Networ ...
- C/C++ 跨平台交叉编译、静态库/动态库编译、MinGW、Cygwin、CodeBlocks使用原理及链接参数选项
目录 . 引言 . 交叉编译 . Cygwin简介 . 静态库编译及使用 . 动态库编译及使用 . MinGW简介 . CodeBlocks简介 0. 引言 UNIX是一个注册商标,是要满足一大堆条件 ...
- [转]Linux下g++编译与使用静态库(.a)和动态库(.os) (+修正与解释)
在windows环境下,我们通常在IDE如VS的工程中开发C++项目,对于生成和使用静态库(*.lib)与动态库(*.dll)可能都已经比较熟悉,但是,在linux环境下,则是另一套模式,对应的静态库 ...
- android开发 NDK 编译和使用静态库、动态库 (转)
在eclipse工程目录下建立一个jni的文件夹 在jni文件夹中建立Android.mk和Application.mk文件 Android.mk文件: Android提供的一种makefile文件, ...
- linux下动态库编译的依赖问题
这里主要是想试验一下,对一个具有多层嵌套的动态库进行编译时,是否要把最底层的库也包含进来的问题,结论是:只要直接依赖的库名称,不需要最底层库名称. 一,目录结构ZZZ├── add│ ├── ad ...
- Linux下编译、使用静态库和动态库 自己测过的
每个程序实质上都会链接到一个或者多个的库.比如使用C函数的程序会链接到C运行时库,GUI程序会链接到窗口库等等.无论哪种情况,你都会要决定是链接到静态库(static libary)还是动态库(dyn ...
- 动态库与静态库的学习 博主写的很好 静态库 编译的时候 需要加上 static 动态库编译ok运行不成功就按照文章中的方法修改
来源连接 http://www.cnblogs.com/skynet/p/3372855.html C++静态库与动态库 这次分享的宗旨是--让大家学会创建与使用静态库.动态库,知道静态库与动态库 ...
随机推荐
- 坑中速记整理! 使用 kotlin 写第一个 ReactNative Android 模块
Kotlin 和 Swift, 两大新宠! 借 ReactNative 熟悉下 kotlin 的用法,不料掉坑里面了.昨晚花了大半夜,趁这会儿思路清晰,把涉及到的一些关键信息,迅速整理下. 最佳的使用 ...
- 组件 layui 常用控件下拉框的应用
下拉框的显示样式: 针对下拉框的绑定等操作时,在最后务必调用一次 form.render(); 1.基本定义: <div class="layui-form-item"> ...
- MyBatis开发中解决返回字段不全的问题
场景重现: mybatis 在查询的时候,可以返回Map,但是一旦这个字段为空(null)的时候,map里就没有了.我用的是mysql数据库,除了在查询语句上做ifnull判断给它默认值外,有没的别的 ...
- 从零开始搭建框架SSM+Redis+Mysql(一)之摘要
从零开始搭建框架SSM+Redis+Mysql(一)之摘要 本文章为本人实际的操作后的回忆笔记,如果有步骤错漏,希望来信307793969@qq.com或者评论指出. 本文章只体现过程,仅体现操作流程 ...
- 初学python之,IDLE安装
首先新手上路,写的第一篇博客,希望大家不要吐槽. 1.首先在python官网下载最新python版本 https://www.python.org/(注意根据自己的操作系统来选版本) 安装很简单傻瓜式 ...
- CountDownLatch、CyclicBarrier和 Semaphore比较
1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同: CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行: ...
- NIO FileChannel
NIO提供了比传统的文件访问更好的访问方法,NIO有两个优化的方法:一个是 FIleChannel.transferTo FileChannel.transferFrom,另一个是FileChanne ...
- Azure 基础:使用 powershell 创建虚拟机
在进行与 azure 相关的自动化过程中,创建虚拟主机是避不开的操作.由于系统本身的复杂性,很难用一两条简单的命令完成虚拟主机的创建.所以专门写一篇文章来记录使用 PowerShell 在 azure ...
- javascript的一些算法的实用小技巧
一.交换两个数字的值 我们交换两个数字的值想到的方法一般就是用一个新的变变量,让他把一个数存起来,然后在交换两个数字的值,看下面这种. var a = 1, b = 2; //交换两个数字的值 var ...
- 【hihoCoder】#1039 : 字符消除 by C solution
#1039 : 字符消除 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi最近在玩一个字符消除游戏.给定一个只包含大写字母"ABC"的字符串s,消 ...