• CMake 指南
    • 基本概念
    • 常用构建选项
      • CMake 通用
    • 各平台构建示例
      • Linux
      • macOS
      • iOS
      • Android
      • Windows
    • 常见问题
      • 如何添加 C/C++ 源码?
      • 如何添加图片,字体等资源文件?
        • 添加字体资源
      • 如何添加 Lua 源码?
      • 如何使用第三方代码库?
      • 如何编辑 iOS 工程的 Info.plist?
      • 常用的 CMake 命令
    • CMake 帮助

    CMake 指南

    CMake 是一个开源的跨平台构建工具,Cocos2d-x 是一个开源的跨平台游戏引擎,两者十分契合。

    Cocos2d-x 决定自 3.17 版本开始,支持 CMake 的全平台构建。支持的平台包括 Android (NDK)、iOS、macOS、Linux、Windows(VC++ compiler),同时支持通过 CMake 将引擎部分进行预编译,并在新的构建过程中重用预编译的引擎库。

    基本概念

    在使用 CMake 构建工程之前,最好能对软件构建中一些基本的概念有初步的了解,比如什么是编译,链接,打包。了解这些对后续使用 CMake 有很大的帮助。

    此处只解释一下:外部构建(Out-of-source Build),在从源码生成最终的二进制可执行文件的过程中,会生成大量的中间文件,中间文件和源码在同一个目录内时会使源码目录混乱不堪,使用外部构建,即将所有生成的中间文件都放在一个非源码目录中,这样无论构建多少次,源码目录始终干净如新。

    常用构建选项

    CMake 通用

    • -G,通过 CMake 生成特定 IDE 的项目配置文件。这个操作依赖 IDE,即无法在一个没安装 Xcode 的 macOS 上通过 CMake 生成对应的工程文件。

      • -GXcode 生成 Xcode 工程文件
      • -GVisual Studio 15 2017 生成 Visual Studio 2017 工程文件
    • CMAKE_BUILD_TYPE, 指定构建模式,比如 Debug 还是 Release,默认值 Debug。

      • -DCMAKE_BUILD_TYPE=Release 指定以 Release 模式生成工程。
    • -H -B-H 用来指定一个源码目录,指定的目录必须含有一个 CMakeLists.txt 文件,-B 用来指定 CMake 生成的中间文件的存放目录。

      • -H..\cocos2d-x -Bmsvc_build 指定要构建工程的工程路径是上一级目录的 cocos2d-x 子目录,指定 CMake 生成的文件存放在 msvc_build 目录。
    • —build 执行构建过程,同时指定曾使用 CMake 命令生成的构建文件所在目录。
    • cmake —build ./msvcbuild 在执行这个构建过程时,CMake 会自动选择对应的构建工具。<!—### Cocos2d-x 特有以下 Cocos2d-x 特有的选项和使用预编译库有关。1. GEN_COCOS_PREBUILT 控制构建过程是否生成预编译库,默认行为是不生成,开启选项将会增加一个构建目标:prebuilt,执行这个构建目标时,将会编译引擎部分的代码,并将生成的库文件,拷贝至存放预编译库的目录,默认将库拷贝至引擎目录的 prebuilt 子目录。 -DGEN_COCOS_PREBUILT=ON 将会增加一个构建目录:prebuilt,用于执行库的生成,拷贝。1. USE_COCOS_PREBUILT 控制生成的构建工程是否使用预编译库,默认行为是不使用,开启选项将会自动查找使用预编译库,关闭库相关的构建目标,默认在引擎目录的 prebuilt 子目录查找预编译库。 -DUSE_COCOS_PREBUILT=ON 将会自动使用预编译库,关于库相关的 target。1. _COCOS_PREBUILT_ROOT 指定预编译库存放的目录,是一个可选选项,对于在 Android 平台中使用预编译库是一个必选选项,因为正常情况下,Android Studio 在进行 CMake 构建过程时,无法获取到环境变量,导致找不到引擎根目录。 * -DCOCOS_PREBUILT_ROOT=/Users/laptop/cocos-prebuilt 设置存放预编译库的目录—>

    各平台构建示例

    Linux

    1. cd cocos2d-x
    2. mkdir linux-build && cd linux-build
    3. cmake .. -G"Unix Makefiles"
    4. make -j 4

    在执行 make -j 4 命令之前,可以执行 make help 查看所有的构建目标,使用 make <target> 构建一个特定的目标。

    macOS

    1. cd cocos2d-x
    2. mkdir mac-build && cd mac-build
    3. cmake .. -GXcode
    4. open Cocos2d-x.xcodeproj

    在 macOS 上使用 cmake .. -GXcode 将会默认生成 macOS 的工程。iOS 工程和 macOS 工程并不能同时生成到一个 Xcode 工程中。

    iOS

    1. cd cocos2d-x
    2. mkdir ios-build && cd ios-build
    3. cmake .. -GXcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphoneos
    4. open Cocos2d-x.xcodeproj

    参数-DCMAKE_OSX_SYSROOT=iphoneos是可选的,默认构建的是为运行在 iOS 设备的工程。如果想构建运行在模拟器的工程,请加参数 -DCMAKE_OSX_SYSROOT=iphonesimulator。 需要注意的是,只有在 MacOS 10.15 和 Xcode 11 之后的模拟器才能支持运行 Apple Metal 应用。

    Android

    在当前版本的工程中, 默认使用 CMake 构建, ndk-build 相关的支持已经移除. 如果需要在 Android Studio 中使用预编译库,需特别设置预编译库存放的目录,请参考关于预编译库的介绍,以及 build.gradle 中的注释。

    Windows

    1. cd cocos2d-x
    2. mkdir win32-build && cd win32-build
    3. cmake .. -G"Visual Studio 15 2017"
    4. cmake --build .

    以上命令使用 CMake 生成 Cocos2d-x 测试项目的 Visual Studio 2017 工程。生成后,可以在文件浏览器中找到 cocos2d-x/win32-build 目录,双击打开 Cocos2d-x.sln。设置 cpp-tests 为启动项目,即可正常编译运行。

    另一种方式,由于 Visual Studio 2017 已经直接支持 CMake 工程,可以直接使用。详细请参考 CMake 支持。

    常见问题

    如何添加 C/C++ 源码?

    一般我们会把源码放在 Classes/ 目录下. 但如果只做这一步, 我们会遇到类似的编译报错.

    1. __/**.cpp:__: undefined reference to `******'

    我们还需要在 CMakeLists.txt 中添加新增源码的路径

    1. @@ -52,10 +52,12 @@ endif()
    2. list(APPEND GAME_SOURCE
    3. Classes/AppDelegate.cpp
    4. Classes/HelloWorldScene.cpp
    5. + Classes/**/*.cpp
    6. )
    7. list(APPEND GAME_HEADER
    8. Classes/AppDelegate.h
    9. Classes/HelloWorldScene.h
    10. + Classes/**/*.h
    11. )

    然后更新 本地工程文件

    1. ~/Projects/MyCppGame/build$ cmake ..

    如何添加图片,字体等资源文件?

    在不同的平台上, 不同的构建系统 管理资源的方式会有差异. 好在 CMake 已经帮我们做了大部分工作. 我们需要做的就是把准备好的资源放到 Resources/ 目录下.

    但在实际操作中, 我们可能还是在 Windows 和 Linux 上遇到类似

    1. Error while loading: 'HelloWorld2.png'

    找不到资源的报错.

    即使我们已经更新了资源, 报错还是出现了. 这很让人感到困惑.

    如果在工程目录中执行下面命令

    1. ~/Projects/MyCppGame$ find . -name Resources

    会发现 有多个 Resources 目录

    1. ./Resources
    2. ./build/bin/MyCppGame/Resources

    这里的第二个目录是前者的一个副本, 如果出现变更不一致的情形就会存在同步问题.

    在 Mac, iOS 和 Android 平台上, 构建工具(gradle,Xcode)生成的目标是一个程序包. 程序包中除了可执行文件,还包括了所需要的其他资源文件. 资源文件会和可执行程序一起发布, 所以目标不再依赖原本的资源文件(Resources/)目录中的内容. 但是 在Windows和Linux上, 生成的目标对象 只有一个可执行文件, 并不包含资源文件. 比如在Windows上就只有一个MyCppGame.exe文件. 为了让可执行文件能够找到资源, 我们需要把整个 Resources/ 拷贝到 和它同一个目录中.

    当前我们并没有提供给开发者 拷贝资源文件的 接口, 而是通过CMake 提供的机制把这个过程作为一个钩子交给了 本地构建工具.

    Cocos2d-x 提供了类似与下面代码片段的过程

    1. add_custom_command(TARGET MyCppGame POST_BUILD
    2. COMMAND cmake -E copy_directory ./Resources ./build/bin/MyCppGame/Resources
    3. )

    这里的重点在 POST_BUILD. 只有触发了Build 才会执行 POST_BUILD. 如果源文件发生了变化, 在编译完成后就会触发 拷贝资源的动作. 这里有一个问题, 如果资源文件发生了变化,但是源码没有变化, 拷贝动作会被触发吗? 答案是:不会. 这就是运行时找不到新增资源的原因.

    了解了导致错误的原因, 解决这个问题就不会很难. 一个简单的解决办法就是修改 Classes/ 中的任意源码(比如添加空行,然后删除,保存), 从而触发 BuildPOST_BUILD. 或者通过其他方式手动同步两个Resource文件夹.

    在 Mac/iOS 平台还会有一个类似的问题. Xcode 工程需要把 Resources/ 中的文件标记为 "资源文件". 但这一步是在执行 cmake ../ -GXcode 时进行的. 后续 资源文件的变更不会同步到 Xcode 工程文件. 解决这个问题的方法也很简单, 需要重新执行 cmake 更新 Xcode 工程文件.

    1. ~/Projects/MyCppGame/build$ cmake ..

    也就是说, 在资源发生变更时需要重新执行 cmake ...

    添加字体资源

    添加字体资源和添加图片资源的操作是类似的. 和处理图片的过程相似, 就是把 字体 添加到 Resources/fonts 目录.

    iOS 上添加字体, 需要一个额外的步骤.

    proj.ios_mac/ios/Info.plist 中添加 UIAppFonts.

    1. @@ -29,7 +29,9 @@
    2. <key>LSRequiresIPhoneOS</key>
    3. <true/>
    4. <key>UIAppFonts</key>
    5. - <array/>
    6. + <array>
    7. + <string>fonts/Scissor Cuts.ttf</string>
    8. + </array>
    9. <key>UILaunchStoryboardName</key>

    然后更新工程文件

    1. ~/Projects/MyCppGame/build$ cmake ..

    如何添加 Lua 源码?

    可以参考 图片资源的更新方法.

    如何使用第三方代码库?

    有的时候我们需要复用已有的代码库 或者导入开源的 第三方代码. 我们可以使用 CMake 提供的指令 add_subdirectory 导入其他的 CMake 工程.

    如果这个代码库不包含可用的CMakeLists.txt, 我们需要先把这个工程改造为一个 CMake 工程.

    以开源项目nanomsg为例, 在下载好源码之后, 拷贝到工程目录中

    1. mkdir deps
    2. cp -r ~/Downloads/nanomsg-1.1.5 deps/

    在 CMakeLists.txt 中添加下面的内容

    1. @@ -129,6 +131,16 @@ target_include_directories(${APP_NAME}
    2. PRIVATE ${COCOS2DX_ROOT_PATH}/cocos/audio/include/
    3. )
    4. +set(NN_STATIC_LIB ON)
    5. +set(NN_ENABLE_DOC OFF)
    6. +set(NN_TESTS OFF)
    7. +set(NN_TOOLS OFF)
    8. +add_subdirectory(deps/nanomsg-1.1.5)
    9. +target_link_libraries(${APP_NAME} nanomsg)
    10. +
    11. +target_include_directories(${APP_NAME} PRIVATE deps/nanomsg-1.1.5/src)
    12. +
    13. +
    14. # mark app resources
    15. setup_cocos_app_config(${APP_NAME})

    这里的前4行的set的作用是设置nanomsg的编译选项.

    更详细的介绍可以参考 target_include_directoriestarget_link_libraries.

    之后我们就可以在代码中使用这个库了

    1. @@ -24,6 +24,10 @@
    2. #include "HelloWorldScene.h"
    3. +#include "nn.h"

    如何编辑 iOS 工程的 Info.plist?

    和修改字体的过程一样, 我们需要修改 proj.ios_mac/ios/Info.plist. 这个文件并没有被 Xcode 所直接使用, 它是项目中 CMakeFiles/MyCppTest.dir/Info.plist 的模板文件. 我们需要更新目标来更新Info.plist,

    在修改模板后, 需要执行 cmake .. 使之生效.

    需要注意的是, 通过 Xcode 进行的修改是不会保存到 proj.ios_mac/ios/Info.plist 中的, 如果构建目录被删除或者新建后 都需要重新编辑.

    Info.plist 的内容可以参考官方文档

    常用的 CMake 命令

    • target_include_directories 添加头文件搜索目录

    • target_compile_definitions 添加宏定义

    • target_compile_options 添加编译参数

    • target_link_libraries 链接库

    CMake 帮助

    • CMake 官网: cmake.org

    • CMake 文档: cmake.org/documentation

    • CMake FAQ: Wiki/CMake_FAQ