【问题标题】:CMake install pybind11 bindings using Homebrew formulaCMake 使用 Homebrew 公式安装 pybind11 绑定
【发布时间】:2021-06-04 09:47:42
【问题描述】:

我想为 CMake 项目提供 Homebrew 公式,该项目构建和安装 C++ 库及其使用 pybind11 编写的 Python 绑定。理想情况下,该公式应该通过运行一个普通的来工作

cmake --build . --target install

此安装流程在本地运行良好,但使用 Homebrew 公式会在 Python 绑定的安装目录中引入问题:虽然头文件和库安装在由 #{prefix} 标识的 Cellar 的正确目录中,但绑定需要位于 Python 可见的 site-packages 目录中。我正在使用

在 CMake 中获取这样的目录
install(TARGETS pyariadne DESTINATION ${Python_SITEARCH})

但 Homebrew 似乎无法写入该目录,返回一个 Operation not permitted。 通过以下方式识别安装目录

execute_process(COMMAND python3 -m site --user-site OUTPUT_VARIABLE INSTALL_DIR)

也不起作用,因为 Homebrew 在 /tmp 中标识了一个临时用户站点,因此随后删除了安装在那里的任何库。

我应该如何安装 Homebrew 中的所有内容,而不需要更改目录权限?我想避免为 pypi 打包并使用 pip 单独安装绑定。

EDIT(输出示例,涉及目录):

[109/110] Install the project...
-- Install configuration: "Release"
-- Installing: 

/usr/local/Cellar/python@3.9/3.9.2_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/pyariadne.so
CMake Error at cmake_install.cmake:49 (file):
  file INSTALL cannot copy file
  "/tmp/ariadne-20210305-1763-ggejxl/ariadne-2.1-rc2/build/pyariadne.so" to
  
"/usr/local/Cellar/python@3.9/3.9.2_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/pyariadne.so":
  Operation not permitted.

目录/usr/local/Cellar/python@3.9/3.9.2_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages 链接到/usr/local/lib/python3.9/site-packages。前者有用户lgeretti:staff,后者有用户lgeretti:admin。

这个问题不仅发生在我的机器上,而且我还在 macos:latest GitHub Actions 机器上验证它,其中唯一需要的步骤是 brew install 包。

【问题讨论】:

  • 你确定你使用的是 Homebrew 安装的 Python 而不是系统默认的 Python 吗? Homebrew 目录应该是用户可写的。
  • 我很积极。我在原始帖子中添加了一个输出示例。
  • 您是否运行brew doctor 并确认没有安装问题?
  • brew医生很好。在 OP 的底部,我添加了所涉及的目录和每个用户:组,但我不希望出现一些用户权限问题。

标签: python macos cmake homebrew pybind11


【解决方案1】:

在 Homebrew 讨论中从 this post 找到解决方案,该解决方案依赖于 libexec 目录和 pth 文件创建:

  1. 在 CMake 中使用 libexec 作为安装目标,使其以使用 Homebrew 而不是本地安装为条件:
  if (HOMEBREW)
      install(TARGETS pyariadne DESTINATION libexec)
  else()
      find_package(Python)
      install(TARGETS pyariadne DESTINATION ${Python_SITEARCH})
  endif()
  1. 在公式中设置以下内容,以创建 .pth 文件:
  def install
    mkdir "build" do
      system "cmake -G \"Ninja\" .. -DCMAKE_BUILD_TYPE=Release -DHOMEBREW=1 -DCMAKE_INSTALL_PREFIX=#{prefix}"
      system "cmake", "--build", ".", "--target", "install", "--parallel"
    end

    python_version = Language::Python.major_minor_version Formula["python@3.9"].bin/"python3"
    (lib/"python#{python_version}/site-packages/homebrew-ariadne.pth").write <<~EOS
      import site; site.addsitedir('#{libexec}')
    EOS
  end

【讨论】:

  • 很高兴您找到了解决方案!但这不是在 CMake 中做事的最佳方式。请参阅我的答案以获得更强大的内容。
【解决方案2】:

这是 Luca 良好解决方案的一个更好的 CMake 实现。应该通过缓存变量直接引入包定制点,而不是打包器特定的标志。这是标准GNUInstallDirs 模块采用的方法。见下文:

find_package(Python)

set(MyProj_INSTALL_PYTHONDIR "${Python_SITEARCH}"
    CACHE STRING "Install destination for Python targets")
install(TARGETS pyariadne DESTINATION "${MyProj_INSTALL_PYTHONDIR}")

MyProj_INSTALL_PYTHONDIR 的 默认 值为 Python_SITEARCH,但它可以在包脚本中被覆盖:

def install
  mkdir "build" do
    system "cmake -G \"Ninja\" .. -DCMAKE_BUILD_TYPE=Release " \
           "-DMyProj_INSTALL_PYTHONDIR=libexec -DCMAKE_INSTALL_PREFIX=#{prefix}"
    system "cmake", "--build", ".", "--target", "install", "--parallel"
  end

  python_version = Language::Python.major_minor_version Formula["python@3.9"].bin/"python3"
  (lib/"python#{python_version}/site-packages/homebrew-ariadne.pth").write <<~EOS
    import site; site.addsitedir('#{libexec}')
  EOS
end

这种方式明显更好,因为 CMake 构建不再需要了解有关 Homebrew 的任何信息。

【讨论】:

  • 谢谢,这确实比我使用的条件标志更干净。
猜你喜欢
  • 2011-04-28
  • 2018-10-08
  • 1970-01-01
  • 1970-01-01
  • 2021-01-14
  • 2022-08-19
  • 2018-07-18
相关资源
最近更新 更多