使用 setuptools 安装可执行文件以及库

问题描述 投票:0回答:1

我有一个 C++ 代码,通过

setuptools.Extension
生成 python 扩展。 在 setup.py 文件 中,我定义了一个 build_ext,并依赖 CMake 来构建扩展:

class BuildCMakeExtension(build_ext.build_ext):
  """Our custom build_ext command.

  Uses CMake to build extensions instead of a bare compiler (e.g. gcc, clang).
  """

  def run(self):
    self._check_build_environment()
    for ext in self.extensions:
      self.build_extension(ext)

  def _check_build_environment(self):
    ...

  def build_extension(self, ext):
    extension_dir = os.path.abspath(
        os.path.dirname(self.get_ext_fullpath(ext.name)))
    build_cfg = 'Debug' if self.debug else 'Release'
    cmake_args = [
        ...
    ]
    if platform.system() != 'Windows':
      cmake_args.extend([
          f'-DPython3_LIBRARY={sysconfig.get_paths()["stdlib"]}',
          f'-DPython3_INCLUDE_DIR={sysconfig.get_paths()["include"]}',
      ])
    if platform.system() == 'Darwin' and os.environ.get('ARCHFLAGS'):
      osx_archs = []
      if '-arch x86_64' in os.environ['ARCHFLAGS']:
        osx_archs.append('x86_64')
      if '-arch arm64' in os.environ['ARCHFLAGS']:
        osx_archs.append('arm64')
      cmake_args.append(f'-DCMAKE_OSX_ARCHITECTURES={";".join(osx_archs)}')
    os.makedirs(self.build_temp, exist_ok=True)
    subprocess.check_call(
        ['cmake', ext.source_dir] + cmake_args, cwd=self.build_temp)
    subprocess.check_call(
        ['cmake', '--build', '.', f'-j{os.cpu_count()}', '--config', build_cfg],
        cwd=self.build_temp)

    # Force output to <extension_dir>/. Amends CMake multigenerator output paths
    # on Windows and avoids Debug/ and Release/ subdirs, which is CMake default.
    ct_dir = os.path.join(extension_dir, 'cytosim')  # pylint:disable=unreachable
    for cfg in ('Release', 'Debug'):
      cfg_dir = os.path.join(extension_dir, cfg)
      if os.path.isdir(cfg_dir):
        for f in os.listdir(cfg_dir):
          shutil.move(os.path.join(cfg_dir, f), ct_dir)

在项目的CMakeLists中,我通过

pybind11_add_module(cytosim  ${PYCY_SOURCES})
set_target_properties(cytosim PROPERTIES OUTPUT_NAME "${PY_LIBRARY_NAME}")

添加模块

这在某种程度上运作良好(不知道如何),一旦构建完成,我很高兴在正确的位置找到我的 cytosim.xxxxx.so 文件

site_packages/cytosim

但是,编译还会通过

add_executable(${SIM_TARGET} "${PROJECT_SOURCE_DIR}/../src/sim/sim.cc")
创建可执行文件;但它不包含在 site_packages 中。

我该怎么做才能到达那里?

cmake setuptools cpython pybind11 conda-build
1个回答
0
投票

我没有找到一个干净的解决方案,但我确实找到了一个基于以下内容的工作解决方案:在setuptools中分发二进制实用程序

我们无法将可执行文件列为脚本,因为脚本需要是文本。我们不能将可执行文件作为包数据,因为我们想要新编译的可执行文件(而不是可能为不同平台编译的陈旧可执行文件......)。

解决方案确实是分发一个脚本,该脚本只是已编译的可执行文件的包装器,并在构建期间将已编译的可执行文件移动到扩展目录。

就我而言,我将其移至构建扩展功能中:

def build_extension(self, ext):
    extension_dir = os.path.abspath(
        os.path.dirname(self.get_ext_fullpath(ext.name)))
    ...
    parent = pathlib.Path(extension_dir).parent.absolute()
    for p in os.listdir(parent):
        pp = os.path.join(parent, p)
        if os.path.isdir(pp) and  p.startswith("temp."):
                       for f in os.listdir(pp):
                ff = os.path.join(pp, f)
                if os.access(ff, os.X_OK):
                    if f=="foo":
                        pybin = os.path.join(extension_dir, "foowrapper")
                        if not os.path.isdir(pybin):
                            os.mkdir(pybin)
                        shutil.move(ff, os.path.join(pybin, "wrapped_foo"))

这里我将可执行文件“foo”移动到文件夹“foowrapper”,并将其重命名为“wrapped_foo”;而“foo”将是一个包装脚本,它调用“wrapped_foo”:

#!python
import foowrapper as fw
import os,sys
import subprocess

""" A wrapper for foo """ 

path = os.path.dirname(fw.__file__)
exe = os.path.join(path, "wrapped_foo") 
subprocess.call([exe] + sys.argv[1:])
© www.soinside.com 2019 - 2024. All rights reserved.