【问题标题】:Run Makefile on pip install在 pip install 上运行 Makefile
【发布时间】:2017-07-27 10:09:32
【问题描述】:

我有一些协议缓冲区定义需要构建到 Python 源代码中,作为pip install 进程的一部分。我在setup.py 中对setuptools.command.install 命令进行了子类化,但我认为它试图在安装包后运行Makefile,因此无法识别源。

我找不到有关 pip 安装过程中发生的情况的信息。任何人都可以解释一下吗?

setup.py:

import subprocess
import sys

from setuptools import setup
from setuptools.command.install import install

class Install(install):
    """Customized setuptools install command - builds protos on install."""
    def run(self):
        protoc_command = ["make", "python"]
        if subprocess.call(protoc_command) != 0:
            sys.exit(-1)
        install.run(self)


setup(
    name='myprotos',
    version='0.0.1',
    description='Protocol Buffers.',
    install_requires=[],
    cmdclass={
        'install': Install,
    }
)

$ pip install -vvv .的输出:

Processing /path/to/myprotos
  Running setup.py (path:/private/var/folders/3t/4qwkfyr903d0b7db7by2kj6r0000gn/T/pip-jpgCby-build/setup.py) egg_info for package from file:///path/to/myprotos
    Running command python setup.py egg_info
    running egg_info
    creating pip-egg-info/myprotos.egg-info
    writing pip-egg-info/myprotos.egg-info/PKG-INFO
    writing top-level names to pip-egg-info/myprotos.egg-info/top_level.txt
    writing dependency_links to pip-egg-info/myprotos.egg-info/dependency_links.txt
    writing manifest file 'pip-egg-info/myprotos.egg-info/SOURCES.txt'
    reading manifest file 'pip-egg-info/myprotos.egg-info/SOURCES.txt'
    writing manifest file 'pip-egg-info/myprotos.egg-info/SOURCES.txt'
  Source in /private/var/folders/3t/4qwkfyr903d0b7db7by2kj6r0000gn/T/pip-jpgCby-build has version 0.0.1, which satisfies requirement myprotos==0.0.1 from file:///path/to/myprotos
Building wheels for collected packages: myprotos
  Running setup.py bdist_wheel for myprotos: started
  Destination directory: /var/folders/3t/4qwkfyr903d0b7db7by2kj6r0000gn/T/tmpD7dfGKpip-wheel-
  Running command /usr/local/opt/python/bin/python2.7 -u -c "import setuptools, tokenize;__file__='/private/var/folders/3t/4qwkfyr903d0b7db7by2kj6r0000gn/T/pip-jpgCby-build/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" bdist_wheel -d /var/folders/3t/4qwkfyr903d0b7db7by2kj6r0000gn/T/tmpD7dfGKpip-wheel- --python-tag cp27
  running bdist_wheel
  running build
  installing to build/bdist.macosx-10.12-x86_64/wheel
  running install

  # THIS IS MY MAKEFILE RUNNING
  Grabbing github.com/google/protobuf...
  Building Python protos...
  # MAKEFILE COMPLETE

  running install_egg_info
  running egg_info
  creating myprotos.egg-info
  writing myprotos.egg-info/PKG-INFO
  writing top-level names to myprotos.egg-info/top_level.txt
  writing dependency_links to myprotos.egg-info/dependency_links.txt
  writing manifest file 'myprotos.egg-info/SOURCES.txt'
  reading manifest file 'myprotos.egg-info/SOURCES.txt'
  writing manifest file 'myprotos.egg-info/SOURCES.txt'
  Copying myprotos.egg-info to build/bdist.macosx-10.12-x86_64/wheel/myprotos-0.0.1-py2.7.egg-info
  running install_scripts
  creating build/bdist.macosx-10.12-x86_64/wheel/myprotos-0.0.1.dist-info/WHEEL
  Running setup.py bdist_wheel for myprotos: finished with status 'done'
  Stored in directory: /Users/jds/Library/Caches/pip/wheels/92/0b/37/b5a50146994bc0b6774407139f01d648ba3a9b4853d2719c51
  Removing source in /private/var/folders/3t/4qwkfyr903d0b7db7by2kj6r0000gn/T/pip-jpgCby-build
Successfully built myprotos
Installing collected packages: myprotos
  Found existing installation: myprotos 0.0.1
    Uninstalling myprotos-0.0.1:
      Removing file or directory /usr/local/lib/python2.7/site-packages/myprotos-0.0.1.dist-info/DESCRIPTION.rst
      Removing file or directory /usr/local/lib/python2.7/site-packages/myprotos-0.0.1.dist-info/INSTALLER
      Removing file or directory /usr/local/lib/python2.7/site-packages/myprotos-0.0.1.dist-info/METADATA
      Removing file or directory /usr/local/lib/python2.7/site-packages/myprotos-0.0.1.dist-info/RECORD
      Removing file or directory /usr/local/lib/python2.7/site-packages/myprotos-0.0.1.dist-info/WHEEL
      Removing file or directory /usr/local/lib/python2.7/site-packages/myprotos-0.0.1.dist-info/metadata.json
      Removing file or directory /usr/local/lib/python2.7/site-packages/myprotos-0.0.1.dist-info/top_level.txt
      Successfully uninstalled myprotos-0.0.1

Successfully installed myprotos-0.0.1
Cleaning up...

我的 Makefile 是否应该在生成源文件的过程中尽早运行?例如,在egg_info 运行之前文件是否需要存在?

如果我手动运行 Makefile 然后安装包,那么它就可以工作。


更新

这是我的项目的结构:

myprotos
├── Makefile
├── README.md
├── document.proto
├── myprotos         # Generated by Makefile
│   ├── __init__.py  # Generated by Makefile
│   └── proto_pb2.py # Generated by Makefile
└── setup.py 

这是 Makefile 的一部分,它从 Potocol 缓冲区定义生成 Python 源代码:

python: protoc deps
    # the protoc and deps command above just downloads
    # the `protoc` binary to a local bin directory 
    @echo "Building Python protos..."
    @mkdir -p "${PYTHON_OUT}"
    @touch "${PYTHON_OUT}"/__init__.py
    @printf "__all__ = ['proto_pb2']" > "${PYTHON_OUT}"/__init__.py
    @PATH="${LOCAL_BINARY_PATH}:$$PATH" protoc \
        --proto_path="${BASE}" \
        --proto_path="${GOPATH}/src/github.com/google/protobuf/src" \
        --python_out="${PYTHON_OUT}/" \
        ${PROTOS}

【问题讨论】:

  • 你应该运行它on build,而不是安装时
  • @NilsWerner 我已经更新了setup.py 以子类化构建命令,但我在导入包时仍然遇到问题。制造的轮子中似乎没有任何来源。
  • 您的MANIFEST.in 是什么样的?此外,您的 Makefile 生成的源文件应该放在 sdist?
  • @NilsWerner 我没有MANIFEST.in 文件。但是,如果我运行make,然后运行pip install .,则该软件包已安装并可使用。似乎即使在build 中,Python 源代码也没有足够早地生成。
  • 是的,这是意料之中的。您需要将所有非 py 源文件添加到 MANIFEST.in 并用您的 Makefile 究竟做了什么以及它使用和生成哪些文件来修改您的问题。因为如果它生成源文件,它需要进入sdist命令,如果它编译现有的源文件它需要进入build部分。

标签: python makefile pip


【解决方案1】:

好的,这里需要更改三件事:

  1. Makefiledocument.proto 添加到新文件MANIFEST.in

     Makefile
     document.proto
    

    如果您这样做,python setup.py sdist 创建的.zip 文件(也上传到 PyPI)将包含这些文件。

  2. 您需要在python setup.py build 期间运行您的make 命令,而不是在install 期间。由于您正在生成 Python 代码,因此您需要在此处更改 build_py 命令:

     import sys
     import subprocess
    
     from setuptools import setup
     from setuptools.command.build_py import build_py
    
     class Build(build_py):
         """Customized setuptools build command - builds protos on build."""
         def run(self):
             protoc_command = ["make", "python"]
             if subprocess.call(protoc_command) != 0:
                 sys.exit(-1)
             build_py.run(self)
    
    
     setup(
         name='buildtest',
         version='1.0',
         description='Python Distribution Utilities',
         packages=['buildtest'],
         cmdclass={
             'build_py': Build,
         }
     )
    

    如果您的Makefile 生成机器代码,即来自 C 或任何其他编译语言,您应该更改 build_ext 命令:

     import sys
     import subprocess
    
     from setuptools import setup
     from setuptools.command.build_ext import build_ext
    
     class Build(build_ext):
         """Customized setuptools build command - builds protos on build."""
         def run(self):
             protoc_command = ["make", "python"]
             if subprocess.call(protoc_command) != 0:
                 sys.exit(-1)
             build_ext.run(self)
    
    
     setup(
         name='buildtest',
         version='1.0',
         description='Python Distribution Utilities',
         packages=['buildtest'],
         has_ext_modules=lambda: True,
         cmdclass={
             'build_ext': Build,
         }
     )
    
  3. 最后,您需要通过在setup() 中定义属性packages 来告诉setuptoolsinstall 上安装生成的包:

     setup(
         ...
         packages=['myprotos']
     )
    

决定运行build_pybuild_ext的原因在于两者运行时的情况:

  • build_py 在创建必须是跨平台的源分发时也会运行。已编译的扩展通常不是跨平台的,因此您无法在此步骤中编译它们。
  • build_ext 仅在您创建特定于平台的二进制发行版时运行。在这里编译成特定平台的机器码就可以了。

【讨论】:

  • build 在最近的setuptools.command 中似乎不存在。 build_py 似乎有效。
  • @Nils:它可以工作,但是在 pip install 之后没有复制包文件的方式只有分发文件
猜你喜欢
  • 1970-01-01
  • 2013-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-09
  • 1970-01-01
相关资源
最近更新 更多