对于MEGAchat的开发和编译,我们主要使用CMake作为跨平台的项目配置工具。我们还使用 VCPKG 来管理在大多数平台(Windows、MacOS 和 Linux)中构建MEGAchat所需的依赖项。
有关每个操作系统所需构建工具的详细信息,请查看 MEGA SDK 存储库中的“构建工具”一章。
WebRTC for Android 中有关 WebRTC Android 编译的更多信息
MEGAchat需要一些依赖项才能工作。其中大多数是在配置阶段使用 VCPKG 自动下载和构建的。
对于Linux,系统中需要一些额外的库,以便VCPKG可以构建依赖项。对于基于 Debian 的发行版,您可以使用以下命令安装必要的库:
sudo apt install python3-pkg-resources libglib2.0-dev libgtk-3-dev libasound2-dev libpulse-dev
对于不同的 Linux 发行版,包名称可能有所不同,但它应该使用提供相同库的包成功构建。
您可以查看存储库根目录下的 vcpkg.json 文件中的完整依赖项集。
MEGAchat还需要 MEGA SDK 库。本文档后面有关于如何将其与MEGAchat一起使用的说明。 MEGA SDK 项目由MEGAchat CMake 自动加载,因此您只需将其克隆到预期路径即可。
系统中只应安装一种额外的可选依赖项:Qt Framework。只需要构建 Qt 示例应用程序,但测试、CLI 示例或库本身不是必需的。
首先,准备一个您选择的用于MEGAchat的目录。在本文档的示例中, mega
目录将用作工作空间目录。
mkdir mega
cd mega
准备好目录后,克隆MEGAchat存储库以获取MEGAchat源代码。
git clone https://github.com/meganz/MEGAchat
由于MEGAchat需要 MEGA SDK 才能工作,因此将 MEGA SDK 克隆到预期路径中。
git clone https://github.com/meganz/sdk MEGAchat/third-party/mega
最后,克隆MEGAchat文件夹旁边的 VCPKG 存储库。如果您已经在使用 VCPKG 并且拥有存储库的本地克隆,则可以跳过此步骤并使用系统上现有的 VCPKG。
git clone https://github.com/microsoft/vcpkg
以下说明用于从命令行界面 (CLI) 配置项目,但如果配置了相同的 CMake 参数,则 cmake-gui 或任何与 CMake 兼容的编辑器或 IDE 都应该适合。
MEGAchat的配置与任何其他常规 CMake 项目一样。唯一始终需要的参数是 VCPKG 目录,用于管理第三方依赖项。 MEGA SDK 依赖项是作为MEGAchat构建的一部分构建的。
要配置MEGAchat ,请从工作区( mega
目录)运行 CMake:
cmake -DVCPKG_ROOT=vcpkg -DCMAKE_BUILD_TYPE=Debug -S MEGAchat -B build_dir
注 1 :多重配置生成器(例如 Visual Studio)可能不需要-DCMAKE_BUILD_TYPE=<Debug|Release>
。
注2如果您的系统上安装了Qt Framework,但CMake无法检测到它,您可以添加-DCMAKE_PREFIX_PATH=</path/to/qt/install/dir>
以便CMake可以找到它。如果未安装 Qt 并且您不想安装它,可以通过设置-DENABLE_CHATLIB_QTAPP=OFF
来禁用 Qt 示例应用程序。库、CLI 示例和测试仍将构建。
在上面的 cmake 命令中,为了简单起见,使用了相对路径。如果您想更改 VCPKG、 MEGAchat或构建目录的位置,只需为其中任何一个提供有效的相对或绝对路径即可。
在项目配置过程中,VCPKG 将为平台构建和配置必要的库。第一次运行可能需要一段时间,但是一旦构建了库,VCPKG 就会从二进制缓存中检索它们。
MEGAchat可以配置不同的选项,其中一些可以在 chatlib_options.cmake 文件中找到。管理示例和测试的选项位于 CMakeLists.txt 中。
配置MEGAchat后,只需构建完整的项目:
cmake --build build_dir
您可以像CHATlib
或megaclc
一样指定--target=<target>
,或者只保留命令以构建所有目标。此外,可以添加-j <N>
或--parallel <N>
来管理并发并加快构建速度。
构建完成后,二进制文件将在 CMake 配置命令中指定的build_dir
中可用。
为了抽象代码复杂性, MEGAchat提供了一个中间层,可以快速创建新应用程序。
该文档位于src/ MEGAchat api.h
MEGAchat线程模型类似于 javascript 线程模型 - 一切都在主 (GUI) 线程中运行,绝不允许阻塞,外部事件(网络、计时器等、webrtc 事件等)会在主线程上触发回调。为此, MEGAchat必须能够与应用程序的事件循环交互 - 对于 GUI 应用程序来说,这通常是 GUI 框架的事件/消息循环,对于控制台应用程序来说,这通常是自定义消息循环。由于此消息循环是特定于平台的,因此应用程序开发人员有责任实现它与MEGAchat之间的接口。这听起来可能比实际情况更复杂 - 界面由两部分组成。其中一部分是megaPostMessageToGui(void*)
函数的实现,它将一个不透明的void*
指针发送到应用程序的消息循环。该函数通常由主线程以外的线程调用,但也可以由 GUI 线程本身调用。另一部分是应用程序消息循环中的代码,它识别这种类型的消息,并通过使用同一指针调用megaProcessMessage(void*)
将它们传递回MEGAchat - 这次是在主 (GUI) 线程的上下文中。所有这些都在/src/base/gcm.h
和/src/base/gcm.hpp
中实现。这些文件包含详细的文档。在 Windows 上实现此功能的一个示例是: megaPostMessageToGui(void*)
将使用用户消息类型执行PostMessage()
,并将void*
作为消息的 lParam 或 wParam,并且在事件处理switch
语句中,将有该消息类型的条目,通过转换消息的 lParam 或 wParam 来获取void*
指针,并将其传递给megaProcessMessage(void*)
。
MEGAchat依赖于 libuv,在其自己的专用线程中运行,以监视多个套接字的原始 I/O 事件,并实现计时器。它还依赖于 libuv 的高级 I/O 功能,例如 DNS 解析和 SSL 套接字。 libuv 之上的一个薄层,称为“服务”( /src/base/?services*.*
) 是在 libuv 和 GCM 之上实现的,以便为计时器提供简单的、类似 javascript 的异步 C++11 API ( src/base/timer.h
)、DNS 解析 ( /src/base/services-dns.hpp
)、http 客户端 ( /src/base/services-http.hpp
)。该层最初设计为具有纯 C 接口( cservices*.cpp/h
文件)的较低级别组件,以便服务可以由使用不同编译器构建的多个 DLL 和高级仅标头 C ++11 层是前端并包含公共 API - 这些是 .hpp 文件。
MEGAchat (libcurl) 中的所有网络库都使用 libuv 进行网络操作和计时器(C 库直接使用 libuv,C++ 代码使用 C++11 层,即timers.hpp
)。强烈建议 SDK 用户也这样做,尽管可以在套接字上阻塞专用工作线程,并通过 GCM 将事件发布到 GUI 线程。
使用模式如下:为某个事件(套接字 I/O 事件、计时器等)注册回调,并在事件发生时由libuv 线程调用该回调。如果事件可能在调用回调的库之外传播,尤其是传播到 GUI,那么在某些时候,必须使用 GCM 机制将事件处理编组到 GUI 线程。但是,如果事件是内部的并且从不传播到库外部,则可以直接在 libuv 线程的上下文中处理它(前提是它永远不会阻止它)。这节省了将其编组到 GUI 线程的性能成本,并且如果事件发生频率很高(例如仅需要将数据附加到缓冲区的传入数据块事件),则建议这样做。当传输完成时,每次传输都可以在 GUI 线程上编组一次完成事件,从而结合了两种方法的优点。
MEGAchat拥有先进的日志记录工具,支持带颜色的文件和控制台日志记录、日志文件轮换、多个日志通道,每个通道都有单独的日志级别。日志级别是在运行时(启动时)配置的,而不是在编译时配置的(即不是通过禁用日志宏)。这允许发布构建的应用程序为任何通道启用完整的调试日志记录。日志通道在 src/base/loggerChannelConfig.h 中定义和默认配置。该文件包含详细的文档。为了方便起见,每个通道的专用日志记录宏通常在使用它的代码中定义 - 有关示例,请参阅 karereCommon.h 中的 XXX_LOG_DEBUG/WARN/ERROR 宏。如果需要,SDK 用户可以自由创建额外的日志通道。 GUI 日志通道已定义。日志通道配置可以在运行时由 KRLOG 环境变量覆盖。其格式如下:
KRLOG=<chan name>=<log level>,<chan name2>=<log level2>...
日志级别为“关闭”、“错误”、“警告”、“信息”、“详细”、“调试”、“调试”。
有一个特殊的频道名称——“全部”。设置该通道的日志级别将设置所有通道的日志级别。例如,这可以轻松地使除一个(或几个)之外的所有通道静音,方法是:
KRLOG=all=warn,mychannel=debug,myotherchannel=info
同一个通道可以多次配置,只有最后一次设置才有效,这使得上述技巧成为可能。
MEGAchat要求应用程序在编译时定义函数karere::getAppDir()
,以便在进入main()
之前知道在哪里创建日志文件并尽早开始记录。如果MEGAchat构建为静态库,则这不是问题。在动态库的情况下,该函数必须是弱符号,以便MEGAchat本身可以在没有函数实现的情况下进行编译,并且在应用程序启动时加载MEGAchat共享库时要链接的实现。弱符号实际上不能跨编译器移植,这可能是一个问题。然而,它们受到 gcc 和 clang 的支持。如果不支持弱符号,则 karer e 必须构建为静态库。
base/promise.h
中的 Promise 库和/src/test-promise.cpp
中的示例用法/src/base/timers.hpp
中的setTimeout()
和setInterval()
定时器函数marshallCall()
函数将 lambda 调用从工作线程编组到 GUI 线程。使用示例可以在/src/webrtcAdapter.h
和许多不同的地方看到。在 GUI 线程中运行的高级代码中不应直接需要此机制。/src/chatClient.h;.cpp
中的整体客户端结构megaPostMessageToGui()
、如何启动“服务”以及如何实例化MEGAchat客户端。还展示了如何实现getAppDir()
方法,这是MEGAchat库所需的弱符号,以便在输入main()
之前创建日志文件并尽早开始记录。src/rtcModile/IRtcModule.h
中的视频模块公共接口及相关头文件megaPostMessageToGui()
,但它可以具有任何名称,前提是签名为extern "C" void(void*)
。该函数是MEGAchat所依赖的消息传递机制(称为 Gui Call Marshaller,或 GCM)的核心。您必须将此函数的指针传递给services_init()
。