【问题标题】:CMake: copy_directory custom command fails on macOSCMake:copy_directory 自定义命令在 macOS 上失败
【发布时间】:2019-02-20 02:00:19
【问题描述】:

我有一个跨平台(Windows、Mac、iOS)CMake 项目,需要将二进制资源(图像、音频、文本文件等)复制到最终应用程序。我之前只是将所有资源都添加到 add_executable 命令中,并且在我想将所有内容组织到子目录之前效果很好。

为了在保留文件夹结构的同时复制应用程序资产,我最终在 windows 目标中使用了以下自定义命令:

add_custom_command(
  TARGET ${APP_TARGET_NAME} PRE_LINK
  COMMAND ${CMAKE_COMMAND} -E copy_directory

  ${CMAKE_CURRENT_SOURCE_DIR}/${APP_ASSETS_DIR} 
  $<TARGET_FILE_DIR:${APP_TARGET_NAME}>/assets
)

效果很好。当我尝试在 macOS 上做同样的事情时,问题就来了。当我在 macOS 上使用相同的 $&lt;TARGET_FILE_DIR&gt; 技巧时,我得到了输出应用程序包的地址(这非常好),所以我在末尾添加了一个 /resources 并尝试在那里复制,但这失败了。

在 XCode 中我收到以下错误:

PhaseScriptExecution CMake\ PreLink\ Rules /Users/someuser/Documents/Build/Test/Test.build/Debug/Test_MAC.build/Script-2CF8724D08BC49E4A13B9E75.sh
cd /Users/someuser/Documents/GitHub/Test
/bin/sh -c /Users/someuser/Documents/Build/Test/Test.build/Debug/Test_MAC.build/Script-2CF8724D08BC49E4A13B9E75.sh

/Users/someuser/Documents/Build/Test/Debug/Test_MAC.app/Contents/MacOS/Test_MAC -E copy_directory /Users/someuser/Documents/GitHub/Test/assets /Users/someuser/Documents/Build/Test/Debug/Test_MAC.app/Contents/Resources
make: *** [Test_MAC_buildpart_0] Segmentation fault: 11
Command /bin/sh failed with exit code 2

这不是特别有用。我试过PRE_LINKPOST_BUILD 以及copy_directorycopy

为什么会失败?我无法在 iOS 上进行测试,但我想这两者会以类似的方式工作。

如何将我的资产复制到 macOS(也包括 iOS)上的捆绑包中?

【问题讨论】:

  • 该命令不应出现段错误,因此这可能意味着您正在使用的 CMake 版本中存在错误。你运行的是什么版本?使用cmake --version 查看此信息。
  • 在使用 CPack 构建 dmg 文件时,我经常遇到Segmentation fault: 11 消息。原来我忘记添加一些资源,底层工具崩溃了。
  • @JohnSzakmeister 终端版本3.13.2,桌面应用3.13.4
  • 我尝试将终端升级到 3.13.4,但遇到了同样的问题

标签: macos cmake


【解决方案1】:

在网上没有太多有用的关于使用 CMake 生成框架/包的文档。大多数智慧都隐藏在 CMakeLists.txt 文件中,而不是 CMake 教程中。

众所周知,这两种方法都有效,但要正确使用有点棘手。我在带有 CMake 的 Unix Makefiles 生成器的版本化框架项目中同时使用了它们。

首先您将资源添加到您的框架/捆绑包(我的与项目同名,因此我在以下几行中使用${PROJECT_NAME}或者将它们作为参数添加到add_library ,例如

add_library(${PROJECT_NAME} SHARED ${SOURCES} ${HEADERS} ${RESOURCES})

然后为框架/包设置目标属性:

  if(BUILD_MAC_FRAMEWORK)
    # Set the framework target properties just to make sure the relevant links inside the framework 
    # are created.  Because the default framework name differs from the project name we change the
    # output name property.
    set_target_properties(${PROJECT_NAME} PROPERTIES
      FRAMEWORK TRUE
      FRAMEWORK_VERSION ${MAC_FRAMEWORK_VERSION}
      #PUBLIC_HEADER "${PUBLIC_HEADERS}" # does not work recursively
      #PRIVATE_HEADER "${PRIVATE_HEADERS}" # does not work recursively
      RESOURCE "${CMAKE_BINARY_DIR}/version.plist" # does not work recursively
      MACOSX_FRAMEWORK_IDENTIFIER org.company.sampleFramework.framework
      MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${PROJECT_VERSION}
      MACOSX_FRAMEWORK_BUNDLE_VERSION ${PROJECT_VERSION}
      MACOSX_FRAMEWORK_INFO_PLIST "${CMAKE_BINARY_DIR}/Info.plist"
      OUTPUT_NAME ${MAC_FRAMEWORK_NAME}
    )
  endif()

稍后使用辅助函数设置资源文件相对于Resources 目录的框架路径

# determine which subdirectory this file (header, resource) should be installed into.
function(set_macosx_properties _removable_prefixes _install_prefix _source_files)
  foreach(_file ${_source_files})
    get_filename_component(_loc "${_file}" DIRECTORY)
    foreach(_prefix ${_removable_prefixes})
      string(REPLACE "${_prefix}" "" _loc "${_loc}")
    endforeach()
    set_source_files_properties(${_file} PROPERTIES MACOSX_PACKAGE_LOCATION ${_install_prefix}${_loc})
  endforeach()
endfunction()

set_macosx_properties("${CMAKE_SOURCE_DIR}/include;${CMAKE_BINARY_DIR}/include"  "Headers" "${HEADERS}")
set_macosx_properties("${CMAKE_SOURCE_DIR}/data;${CMAKE_BINARY_DIR}/data" "Resources" "${RESOURCES}")

辅助函数移除指定的前缀并用安装前缀替换它们。

确保两个命令(add_libraryset_macosx_properties)是从同一个目录/CMakeLists.txt 调用的!命令的不同位置不起作用。

您使用对add_custom_command 的调用如下。我不记得其他类型的目标是否不起作用,但我一直使用POST_BUILD自定义目标。

add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD 
  COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_FILE_DIR:${PROJECT_NAME}>/Documentation
  COMMAND ${CMAKE_COMMAND} -E create_symlink ./Versions/Current/Documentation $<TARGET_FILE_DIR:${PROJECT_NAME}>/../../Documentation
  COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/html $<TARGET_FILE_DIR:${PROJECT_NAME}>/Documentation/html)

add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD 
  COMMAND ${CMAKE_COMMAND} -E remove $<TARGET_FILE_DIR:${PROJECT_NAME}>/Documentation/html/${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.qch
  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/html/${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.qch $<TARGET_FILE_DIR:${PROJECT_NAME}>/Documentation)

最后,通过一条命令完成安装:

install(TARGETS ${PROJECT_NAME} FRAMEWORK DESTINATION . COMPONENT development)

【讨论】:

  • 嗯...这两种方法似乎都不起作用。我什至直接在我的资源数组上尝试了“set_macosx_properties”,但我无法将文件放在任何类型的子目录中。第二种方法不起作用,因为我遇到了与之前相同的错误。
  • 我用框架的设置/安装说明更新了答案。你能用Unix Makefiles生成器而不是XCode项目来检查吗?
猜你喜欢
  • 2018-12-16
  • 1970-01-01
  • 2019-04-18
  • 1970-01-01
  • 1970-01-01
  • 2021-10-25
  • 2013-07-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多