简体   繁体   English

CMake 使用 Homebrew 公式安装 pybind11 绑定

[英]CMake install pybind11 bindings using Homebrew formula

I would like to supply a Homebrew formula for a CMake project that builds and installs a C++ library along with its Python bindings written using pybind11.我想为 CMake 项目提供 Homebrew 公式,该项目构建和安装 C++ 库及其使用 pybind1 编写的 Python 绑定The formula should ideally work by running a plain理想情况下,该公式应该通过运行一个普通的

cmake --build . --target install

This installation flow works fine locally, but using a Homebrew formula introduces a problem in the installation directory for the Python bindings: while headers and libraries are installed in the proper directory in the Cellar identified by #{prefix}, the bindings need to be in a site-packages directory visible to Python.此安装流程在本地运行良好,但使用 Homebrew 公式会在 Python 绑定的安装目录中引入问题:虽然头文件和库安装在由 #{prefix} 标识的 Cellar 的正确目录中,但绑定需要位于Python 可见的站点包目录。 I am getting such directory within CMake using我正在使用 CMake 中的此类目录

install(TARGETS pyariadne DESTINATION ${Python_SITEARCH})

but the directory seem not to be writable by Homebrew, returning an Operation not permitted .但 Homebrew 似乎无法写入该目录,返回Operation not permitted Identifying the install directory by the following通过以下方式识别安装目录

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

does not work either since Homebrew identifies a temporary user site in /tmp and consequently any library installed there is subsequently removed.也不起作用,因为 Homebrew 在 /tmp 中标识了一个临时用户站点,因此随后删除了安装在那里的任何库。

How am I supposed to install everything from Homebrew, without resorting to changes of permissions to directories?我应该如何安装 Homebrew 中的所有内容,而无需更改目录权限? I'd like to avoid packaging for pypi and using pip to install the bindings separately.我想避免为 pypi 打包并使用 pip 单独安装绑定。

EDIT (example of the output, involved directories):编辑(output 的示例,涉及目录):

[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.

Directory /usr/local/Cellar/python@3.9/3.9.2_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages links to /usr/local/lib/python3.9/site-packages .目录/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 The former has user lgeretti:staff, the latter has user lgeretti:admin.前者有用户lgeretti:staff,后者有用户lgeretti:admin。

This issue not only happens on my machine, but I also verify it on a macos:latest GitHub Actions machine where the only required step is to brew install the package.这个问题不仅发生在我的机器上,而且我还在 macos 上验证它:最新的 GitHub Actions 机器,其中唯一需要的步骤是 brew 安装 package。

Found the solution from this post on Homebrew discussions, which relies on the libexec directory and pth file creation:这篇关于 Homebrew 讨论的帖子中找到了解决方案,该解决方案依赖于 libexec 目录和 pth 文件创建:

  1. Use libexec as installation target in CMake, made it conditional on using Homebrew rather than local installation:在 CMake 中使用 libexec 作为安装目标,使其以使用 Homebrew 而不是本地安装为条件:
  if (HOMEBREW)
      install(TARGETS pyariadne DESTINATION libexec)
  else()
      find_package(Python)
      install(TARGETS pyariadne DESTINATION ${Python_SITEARCH})
  endif()
  1. Set up the following in the formula, to create the.pth file:在公式中设置以下内容,以创建 .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

This is a better CMake implementation of Luca's good solution.这是 Luca 的好解决方案的一个更好的 CMake实现 One should introduce package customization points directly via a cache variable, rather than a packager-specific flag.应该通过缓存变量直接引入 package 自定义点,而不是通过特定于打包程序的标志。 This is the approach taken by the standard GNUInstallDirs module.这是标准GNUInstallDirs模块采用的方法。 See below:见下文:

find_package(Python)

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

The default value of MyProj_INSTALL_PYTHONDIR is Python_SITEARCH , but it can be overridden in a package script: Python_SITEARCH默认值为MyProj_INSTALL_PYTHONDIR ,但可以在 package 脚本中覆盖它:

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

This way is significantly better because the CMake build no longer needs to know anything about Homebrew.这种方式明显更好,因为 CMake 构建不再需要了解有关 Homebrew 的任何信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM