CMake - MacOS - BundleUtilities将Python解释器添加到应用程序中,并且不会对其进行修复



我正在使用cmake version 3.16.1将Python添加到MacOS 10.15.1终端上的应用程序包中。当我尝试捆绑MacOS应用程序时,我收到来自捆绑实用程序的cmake错误:

  • 我的 cmake 生成的 myApp.app/发布文件夹中包含的 Python 解释器链接到外部库,也就是说,它没有被捆绑实用程序修复。

如果我遗漏了任何重要信息,请告诉我。

注意:这些摘自 CMakeList.txt它还为我们的跨平台应用程序构建了其他几个插件。我已经尽力缩小范围。

Python 是从/opt/local/Library/Frameworks/Python.framework/Versions/3.6/Pythonport实用程序安装的,python3.6 设置为默认版本。

$ python3 --version输出Python 3.6.9在我的终端上

我正在尝试使用CMakeLists.txt将Python3添加到我的MacOS应用程序包中。我已经将CMakeCache.txt中的一些变量复制到下面的评论中,以显示 cmake 找到了它们。

cmake_minimum_required(VERSION 3.12)
project(myApp)
#PYTHON_VERSION_NUMBER inherited from Makefile, e.g. "3.6"
#NOTE: Problem happens with and without "Interpreter" being specified
find_package(Python3 EXACT ${PYTHON_VERSION_NUMBER} REQUIRED COMPONENTS Development Interpreter)
#Python3 include directory is '/opt/local/Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m'
include_directories(AFTER SYSTEM ${Python3_INCLUDE_DIRS})
#$Python3_LIBRARY_DIRS is /opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib
link_directories(${Python3_LIBRARY_DIRS})
#Python3_LIBRARIES is '/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/libpython3.6m.dylib'
target_link_libraries(myApp ${Python3_LIBRARIES})

在这一点上,我能够构建几个源文件并将其链接到可执行文件中,其中一些需要Python,例如带有Python.h和cython编译源文件的C代码。 我可以将它们安装到应用程序中。

if(APPLE)
set(APPS "${CMAKE_INSTALL_PREFIX}/myApp.app")

(...

INSTALL(CODE "
include(BundleUtilities)
fixup_bundle("${APPS}" "" "")
" COMPONENT Runtime)
set(CPACK_BINARY_DRAGNDROP ON)
include(CPack)

在 fixup_bundle 的 cmake 输出期间,它会复制 Python:

-- fixup_bundle: preparing...
-- fixup_bundle: copying...
(...)
-- 2/66: copying '/opt/local/Library/Frameworks/Python.framework/Versions/3.6/Python'

。它修复了 Python 库:

-- 35/66: fixing up '/Users/username/Projects/myApp/build/release/myApp.app/Contents/Frameworks/Python.framework/Versions/3.6/Python'

cmakeBundleUtilitiesverify_app函数期间的错误输出。它显示Python解释器没有修复。

-- executable file 2: /Users/username/Projects/myApp/build/release/myApp.app/Contents/Frameworks/Python.framework/Versions/3.6/Resources/Python.app/Contents/MacOS/Python
-- verified='0'
-- info='external prerequisites found:
f='/Users/username/Projects/myApp/build/release/myApp.app/Contents/Frameworks/Python.framework/Versions/3.6/Resources/Python.app/Contents/MacOS/Python'
external_prereqs='/opt/local/Library/Frameworks/Python.framework/Versions/3.6/Python;/opt/local/lib/libiconv.2.dylib;/opt/local/lib/libintl.8.dylib'
-- 
CMake Error at /opt/local/share/cmake-3.16/Modules/BundleUtilities.cmake:1119 (message):
error: verify_app failed
Call Stack (most recent call first):
/opt/local/share/cmake-3.16/Modules/BundleUtilities.cmake:986 (verify_app)
cmake_install.cmake:155 (fixup_bundle)

查看 BundleUtilities 输出抱怨的特定文件,显示它链接到外部资源。

% otool -L build/release/myApp.app/Contents/Frameworks/Python.framework/Versions/3.6/Resources/Python.app/Contents/MacOS/Python
build/release/myApp.app/Contents/Frameworks/Python.framework/Versions/3.6/Resources/Python.app/Contents/MacOS/Python:
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1670.10.0)
/opt/local/Library/Frameworks/Python.framework/Versions/3.6/Python (compatibility version 3.6.0, current version 3.6.0)
/opt/local/lib/libintl.8.dylib (compatibility version 10.0.0, current version 10.5.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1281.0.0)

fixup_bundle复制了python框架,包括python库和解释器。只有图书馆修好了。然后,捆绑实用程序发现解释器链接到外部资源并正确生成错误。

这就引出了我的问题:

  • 为什么它没有被捆绑实用程序修复?
  • 我能做些什么来解决这个问题吗?
  • 也许我没有正确使用cmake?

错误中指定的文件是 Python 解释器。我不确定是否需要。一些 C 代码使用 Python.h 来调用 Python 解释器(也许是一个子问题 - 这个 Python 解释器二进制文件是必需的吗?

$ file /opt/local/Library/Frameworks/Python.framework/Versions/3.6/Resources/Python.app/Contents/MacOS/Python
/opt/local/Library/Frameworks/Python.framework/Versions/3.6/Resources/Python.app/Contents/MacOS/Python: Mach-O 64-bit executable x86_64
$ /opt/local/Library/Frameworks/Python.framework/Versions/3.6/Resources/Python.app/Contents/MacOS/Python
Python 3.6.9 (default, Oct 28 2019, 16:05:43) 
[GCC 4.2.1 Compatible Apple LLVM 11.0.0 (clang-1100.0.33.8)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>

这是一个库,捆绑实用程序会复制并修复该库以进行应用程序部署。

$ file /opt/local/Library/Frameworks/Python.framework/Versions/3.6/Python 
/opt/local/Library/Frameworks/Python.framework/Versions/3.6/Python: Mach-O 64-bit dynamically linked shared library x86_64

旁白:我将创建一个小项目,要么重现这一点,要么表明我们更大项目中的某些东西可能把事情搞砸了。如果它重现了这一点,则可能是对如何使用cmake的误解,或者更糟。

这个问题已经有一段时间了。

请注意,Python.app属于Resources,这有点不寻常。如果我们研究function(copy_resolved_framework_into_bundle ...),有一个盲目的资源复制:

execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_resources}" "${resolved_embedded_resources}")

这解释了Python可执行文件如何到达捆绑包,同时又不是依赖项!

然后function(verify_bundle_prerequisites ...)调用verify_app生成的捆绑包,并在复制后首次发现Python.app- 因此未修补。

起初,我正在考虑删除Python可执行文件,据报道可以解决问题。后来我认为拥有一个捆绑的Python解释器可能还不错。我们可以通过以下修改来处理它:

--- a/BundleUtilities.cmake 2019-12-28 02:10:43.000000000 +0100
+++ b/BundleUtilities.cmake 2019-12-28 09:39:26.000000000 +0100
@@ -982,6 +984,13 @@
message(STATUS "fixup_bundle: cleaning up...")
clear_bundle_keys(keys)
+    # Recursively discover and fix all subsequent executables.
+    get_bundle_all_executables("${bundle}" file_list)
+    list(REMOVE_ITEM file_list "${app}" ${CFG_IGNORE_ITEM})
+    list(LENGTH file_list nexecutables)
+    if (${nexecutables} GREATER 0)
+      list(GET file_list 0 f)
+      message(STATUS "fixup_bundle: fixing newly discovered executable ${f}...")
+      fixup_bundle("${f}" "" "${dirs}" IGNORE_ITEM ${CFG_IGNORE_ITEM} ${app})
+    endif()
+
message(STATUS "fixup_bundle: verifying...")
verify_app("${app}" IGNORE_ITEM "${CFG_IGNORE_ITEM}")
else()

有了这个模组,CPack 成功完成:

-- fixup_bundle: done
CPack: Create package
CPack: - package: ****.dmg generated.

最新更新