一  为什么需要动态库

  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

Unity3D跨平台动态库编译---记kcp基于CMake的各平台构建实践的更多相关文章

  1. Unity跨平台C/CPP动态库编译---可靠UDP网络库kcp基于CMake的各平台构建实践

    1.为什么需要动态库 a)提供原生代码(native code)的支持,也叫原生插件,但是我实践的是c/cpp跨平台动态库,这里不具体涉及安卓平台java库和ios平台的objectc库构建. b)某 ...

  2. C/C++ 跨平台交叉编译、静态库/动态库编译、MinGW、Cygwin、CodeBlocks使用原理及链接参数选项

    目录 . 引言 . 交叉编译 . Cygwin简介 . 静态库编译及使用 . 动态库编译及使用 . MinGW简介 . CodeBlocks简介 0. 引言 UNIX是一个注册商标,是要满足一大堆条件 ...

  3. linux动态库编译和使用详细剖析 - 后续

    引言 - 也许是修行 很久以前写过关于动态库科普文章, 废话反正是说了好多. 核心就是在 linux 上面玩了一下 dlopen : ) linux动态库编译和使用详细剖析 - https://www ...

  4. linux动态库编译和使用

    linux动态库编译和使用详细剖析 引言 重点讲述linux上使用gcc编译动态库的一些操作.并且对其深入的案例分析.最后介绍一下动态库插件技术, 让代码向后兼容.关于linux上使用gcc基础编译, ...

  5. 动态库与静态库的学习 博主写的很好 静态库 编译的时候 需要加上 static 动态库编译ok运行不成功就按照文章中的方法修改

    来源连接   http://www.cnblogs.com/skynet/p/3372855.html C++静态库与动态库 这次分享的宗旨是--让大家学会创建与使用静态库.动态库,知道静态库与动态库 ...

  6. linux动态库编译和使用详细剖析

    引言 重点讲述linux上使用gcc编译动态库的一些操作.并且对其深入的案例分析.最后介绍一下动态库插件技术, 让代码向后兼容.关于linux上使用gcc基础编译, 预编译,编译,生成机械码最后链接输 ...

  7. linux下动态库编译的依赖问题

    这里主要是想试验一下,对一个具有多层嵌套的动态库进行编译时,是否要把最底层的库也包含进来的问题,结论是:只要直接依赖的库名称,不需要最底层库名称. 一,目录结构ZZZ├── add│   ├── ad ...

  8. openssl动态库编译

    通常Linux系统自带OpenSSL,但是其so文件由于没有debug信息,因此无法跟踪内部函数,对于学习 不太方便,需要通过源码重新安装.         我的Linux系统是CentOS7,自带的 ...

  9. 安卓之Android.mk多文件以及动态库编译

    1.多文件编译 多文件编译共有两种方式: (1) 在Android.mk中一一添加 LOCAL_PATH:= $(call my-dir) #定义当前模块的相对路径 include $(CLEAR_V ...

随机推荐

  1. Mac下配置MAMP Pro+PHPStorm

    一.配置MAMP Pro Hosts 下载地址:http://xclient.info/s/mamp-pro.html 在Hosts页签下,如图所示位置选择你工程目录 二.配置PHPStorm 1.点 ...

  2. Java50道经典习题-程序46 字符串连接

    题目:编写一个两个字符串连接的程序 import java.util.Scanner; public class Prog46 { public static void main(String[] a ...

  3. 国内物联网平台(3):QQ物联智能硬件开放平台

    国内物联网平台(3)——QQ物联·智能硬件开放平台 马智 平台定位 将QQ帐号体系.好友关系链.QQ消息通道及音视频服务等核心能力提供给可穿戴设备.智能家居.智能车载.传统硬件等领域的合作伙伴,实现用 ...

  4. 动态横向(水平)合并GridView数据行DataRow的列

    前一段时间,Insus.NET有写过<动态合并GridView数据行DataRow的列>http://www.cnblogs.com/insus/p/3238348.html, 那是纵向( ...

  5. 167. Two Sum II - Input array is sorted两数之和

    1. 原始题目 给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数. 函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2. 说明 ...

  6. LAMP之PHP

    保持apache.mysql正在运行 [root@cairui php-]# lsof -i tcp: COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NA ...

  7. Python Flask-web表单

    Flask-WTF扩展可以把处理web表单的过程变成一种愉悦的体验. 一.跨站请求伪造保护 默认情况下,Flask-WTF能够保护所有表单免受跨站请求伪造的攻击.恶意网站把请求发送到被攻击者已登录的网 ...

  8. Mysql INNER JOIN

    1.MySQL INNER JOIN子句将一个表中的行与其他表中的行进行匹配,并允许从两个表中查询包含列的行记录. 2.INNER JOIN子句是SELECT语句的可选部分,它出现在FROM子句之后. ...

  9. Linq中DeferredLoadingEnabled,DataLoadOption的用法

    1.  基本的数据关系图 Student和Class之间是多对一关系,Student和Course之间是多对多关系. DataContext的DeferredLoadingEnabled属性指定是否需 ...

  10. C. The Fair Nut and String 递推分段形dp

    C. The Fair Nut and String 递推分段形dp 题意 给出一个字符串选择一个序列\({p_1,p_2...p_k}\)使得 对于任意一个\(p_i\) , \(s[p_i]==a ...