[✔️]cocos creator 构建原生插件原理

简介: [✔️]cocos creator 构建原生插件原理

在构建的时候会执行cmake命令


3.6.3/resources/tools/cmake/bin/cmake.exe 
    -S"E:/proj/cocos/NewProject/native/engine/win64" 
    -B"E:/proj/cocos/NewProject/build/windows/proj" 
    -DRES_DIR="E:/proj/cocos/NewProject/build/windows" 
    -DAPP_NAME="NewProject" 


如果你对cmake比较熟悉,就会看明白命令行的选项都什么意思,可以参考这篇文章CMake命令行使用姿势


一切的起点


  • native\engine\win64\CMakeLists.txt


cmake_minimum_required(VERSION 3.8)
set(APP_NAME "NewProject" CACHE STRING "Project Name")
project(${APP_NAME} CXX)
set(CC_PROJECT_DIR ${CMAKE_CURRENT_LIST_DIR})
set(CC_UI_RESOURCES)
set(CC_PROJ_SOURCES)
set(CC_COMMON_SOURCES)
set(CC_ALL_SOURCES)
include(${CC_PROJECT_DIR}/../common/CMakeLists.txt) # 引入外部的CMake
set(EXECUTABLE_NAME ${APP_NAME})
# 重点关注的逻辑在这里
cc_windows_before_target(${EXECUTABLE_NAME})
add_executable(${EXECUTABLE_NAME}
    ${CC_ALL_SOURCES}
)
cc_windows_after_target(${EXECUTABLE_NAME})


  • native\engine\common\CMakeLists.txt


# .. 省略了很多set变量逻辑
if(NOT RES_DIR) # 对应外部设置的RES_DIR变量
    message(FATAL_ERROR "RES_DIR is not set!")
endif()
# 这个文件包含了大量的set,没有任何的逻辑
include(${RES_DIR}/proj/cfg.cmake)
# localCfg.cmake 是空逻辑
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/localCfg.cmake)
    include(${CMAKE_CURRENT_LIST_DIR}/localCfg.cmake)
endif()
# 这个变量定义在cfg.cmake,指向的是3.6.3/resources/resources/3d/engine/native
if(NOT COCOS_X_PATH)
    message(FATAL_ERROR "COCOS_X_PATH is not set!")
endif()
# engine相关的逻辑
include(${COCOS_X_PATH}/CMakeLists.txt)
# 入口源代码
list(APPEND CC_COMMON_SOURCES
    ${CMAKE_CURRENT_LIST_DIR}/Classes/Game.h
    ${CMAKE_CURRENT_LIST_DIR}/Classes/Game.cpp
)


从log可以看到,中间有执行:


node.exe plugin_parser.js


那剩下的问题就是cc_windows_before_target在哪里?在engine/common里面有加载engine相关的逻辑,我们看下engine大概处理了哪些


  • ${COCOS_X_PATH}/CMakeLists.txt


第一行就有


include(${CMAKE_CURRENT_LIST_DIR}/cmake/predefine.cmake)


在predefine.cmake中有


## predefined configurations for game applications
include(${CMAKE_CURRENT_LIST_DIR}/../../templates/cmake/common.cmake)
if(APPLE)
    include(${CMAKE_CURRENT_LIST_DIR}/../../templates/cmake/apple.cmake)
elseif(WINDOWS)
    include(${CMAKE_CURRENT_LIST_DIR}/../../templates/cmake/windows.cmake)
elseif(LINUX)
    include(${CMAKE_CURRENT_LIST_DIR}/../../templates/cmake/linux.cmake)
elseif(ANDROID)
    include(${CMAKE_CURRENT_LIST_DIR}/../../templates/cmake/android.cmake)
elseif(OHOS)
    include(${CMAKE_CURRENT_LIST_DIR}/../../templates/cmake/ohos.cmake)
elseif(QNX)
elseif(EMSCRIPTEN)
else()
    message(FATAL_ERROR "Unhandled platform specified cmake utils!")
endif()


所以逻辑就又分发到了templates里面,其实里面的逻辑也就刚好只有这2个marco,而这2个marco也就刚好就是我们要找的marco


macro(cc_windows_before_target target_name)
    if(${CMAKE_SIZEOF_VOID_P} STREQUAL "4")
        message(FATAL_ERROR "Win32 architecture is no more supported!!!")
    endif()
    list(APPEND CC_UI_RESOURCES
        ${CC_PROJECT_DIR}/game.rc
    )
    list(APPEND CC_PROJ_SOURCES
        ${CC_PROJECT_DIR}/main.cpp
        ${CC_PROJECT_DIR}/resource.h
        ${CC_UI_RESOURCES}
    )
    # 收集资源,实现逻辑在cmake/common.cmake
    cc_include_resources(${RES_DIR}/data CC_ASSET_FILES)
    list(APPEND CC_ALL_SOURCES ${CC_PROJ_SOURCES} ${CC_COMMON_SOURCES} ${CC_ASSET_FILES})
    # 很重要的一个函数,实现逻辑也在cmake/common.cmake
    cc_common_before_target(${target_name})
endmacro()
macro(cc_windows_after_target target_name)
    source_group(TREE ${RES_DIR}/data PREFIX "Resources" FILES ${CC_ASSET_FILES})
    source_group(TREE ${CC_PROJECT_DIR} PREFIX "Source Files" FILES ${CC_PROJ_SOURCES})
    source_group(TREE ${CC_PROJECT_DIR}/../common PREFIX "Source Files" FILES ${CC_COMMON_SOURCES})
    target_link_libraries(${target_name} ${ENGINE_NAME})
    target_include_directories(${target_name} PRIVATE
        ${CC_PROJECT_DIR}/../common/Classes
    )
    set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${target_name})
    cc_common_after_target(${target_name})
    if(EXISTS ${RES_DIR}/data/jsb-adapter)
        set(bin_dir ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR})
        add_custom_target(copy_resource ALL
            COMMAND ${CMAKE_COMMAND} -E echo "Copying resources to ${bin_dir}"
            COMMAND ${CMAKE_COMMAND} -E make_directory ${bin_dir}/Resources
            COMMAND robocopy "${RES_DIR}/data/" "${bin_dir}/Resources/" /MIR || (exit 0)
            COMMAND ${CMAKE_COMMAND} -E echo "Copying resources done!"
        )
        add_dependencies(${target_name} copy_resource)
        set_target_properties(copy_resource PROPERTIES FOLDER Utils)
    endif()
    if(MSVC)
        foreach(item ${WINDOWS_DLLS})
            get_filename_component(filename ${item} NAME)
            get_filename_component(abs ${item} ABSOLUTE)
            add_custom_command(TARGET ${target_name} POST_BUILD
                COMMAND ${CMAKE_COMMAND} -E copy_if_different ${abs} $<TARGET_FILE_DIR:${target_name}>/${filename}
            )
        endforeach()
        foreach(item ${V8_DLLS})
            get_filename_component(filename ${item} NAME)
            add_custom_command(TARGET ${target_name} POST_BUILD
                COMMAND ${CMAKE_COMMAND} -E copy_if_different ${V8_DIR}/$<IF:$<BOOL:$<CONFIG:RELEASE>>,Release,Debug>/${filename} $<TARGET_FILE_DIR:${target_name}>/${filename}
            )
        endforeach()
        target_link_options(${target_name} PRIVATE /SUBSYSTEM:WINDOWS)
    endif()
endmacro()


  • cmake/common.cmake


macro(cc_common_before_target target_name)
    set(CC_TARGET_NAME ${target_name})
    if(NOT CC_TARGET_NAME)
        message(FATAL_ERROR "CC_TARGET_NAME is not set!")
    endif()
    if(NOT SKIP_SCAN_PLUGINS AND USE_PLUGINS)
      # 里面有execute_process,调用nodejs脚本plugins_parser.js
      cc_gen_plugin_cmake_hook() 
    else()
        message(STATUS " Skip search plugins")
    endif()
    cc_load_hooks("Pre")
    if(USE_PLUGINS)
        # 加载ProjDir/Pre*.cmake、ProjDir/*Pre.cmake脚本
        cc_plugin_entry() 
    endif()
endmacro()


总结


总体来说,如果对cmake比较熟悉的话,还是非常容易看明白大概的实现思路,cmake的学习曲线本身也没有那么高。

目录
相关文章
|
4月前
|
XML 存储 JSON
CocosCreator 面试题(十五)Cocos Creator如何内置protobuf JS版本?
CocosCreator 面试题(十五)Cocos Creator如何内置protobuf JS版本?
|
10月前
|
前端开发 JavaScript 容器
前端封装库/工具库的组件库之Element
在现代前端开发中,UI 组件库是一个非常重要的组成部分。其中,Element 是一个备受欢迎的基于 Vue.js 的 UI 组件库。
175 0
|
10月前
|
前端开发 JavaScript 开发者
前端封装库/工具库的UI框架之Bootstrap
随着互联网时代的到来,对于Web应用的UI设计和开发变得越来越重要。而为了更高效地进行UI开发,前端封装库/工具库的出现成为了一个非常好的解决方案。其中一个颇受欢迎的UI框架就是Bootstrap。
123 0
|
11月前
|
移动开发 JavaScript 前端开发
|
存储 JSON API
Qt开发技术:Qt的动态静态插件框架介绍和Demo
Qt开发技术:Qt的动态静态插件框架介绍和Demo
Qt开发技术:Qt的动态静态插件框架介绍和Demo
|
编译器
Qt Creator plugin动手实践(5)分享一个简化版的插件框架,qt-creator-minimal
Qt Creator plugin动手实践(5)分享一个简化版的插件框架,qt-creator-minimal
357 0
Qt Creator plugin动手实践(5)分享一个简化版的插件框架,qt-creator-minimal
|
开发者
iOS8新特性扩展(Extension)应用之二——分享插件
iOS8新特性扩展(Extension)应用之二——分享插件
188 0
iOS8新特性扩展(Extension)应用之二——分享插件
iOS8新特性扩展(Extension)应用之四——自定义键盘控件
iOS8新特性扩展(Extension)应用之四——自定义键盘控件
417 0
iOS8新特性扩展(Extension)应用之四——自定义键盘控件
iOS8新特性扩展(Extension)应用之三——照片编辑插件
iOS8新特性扩展(Extension)应用之三——照片编辑插件
131 0
iOS8新特性扩展(Extension)应用之三——照片编辑插件