2010-04-13 31 views
7

Tôi có gói python với một số mã C cần thiết để xây dựng một phần mở rộng (với một số nhu cầu xây dựng không tầm thường). Tôi đã sử dụng SCons làm hệ thống xây dựng của mình bởi vì nó thực sự tốt và linh hoạt.Sử dụng SCons làm công cụ xây dựng cho các đường rãnh

Tôi đang tìm cách biên dịch các phần mở rộng trăn của mình với các SCON đã sẵn sàng để phân phối với các dấu rãnh. Tôi muốn rằng người dùng chỉ cần gõ setup.py install và nhận được phần mở rộng được biên dịch với SCons thay vì các công cụ xây dựng distutils mặc định.

Một ý tưởng mà bạn nghĩ đến là xác định lại lệnh build_ext trong các phần mềm gián đoạn, nhưng tôi không thể tìm thấy tài liệu mở rộng cho nó.

Bất kỳ đề xuất nào?

Trả lời

2

Các enscons package dường như được thiết kế để làm gì là câu hỏi. Ví dụ về việc sử dụng nó để tạo gói có phần mở rộng C là here.

Bạn có thể có một cấu trúc gói cơ bản như:

pkgroot/ 
    pyproject.toml 
    setup.py 
    SConstruct 
    README.md 
    pkgname/ 
     __init__.py 
     pkgname.py 
     cfile.c 

Trong file pyproject.toml có thể giống như thế:

[build-system] 
requires = ["enscons"] 

[tool.enscons] 
name = "pkgname" 
description = "My nice packahe" 
version = "0.0.1" 
author = "Me" 
author_email = "[email protected]" 
keywords = ["spam"] 
url = "https://github.com/me/pkgname" 
src_root = "" 
packages = ["pkgname"] 

nơi phần [tool.enscons] chứa nhiều điều quen thuộc với người setuptools/distutils setup chức năng. Sao chép từ here, các setup.py chức năng có thể chứa một cái gì đó như:

#!/usr/bin/env python 

# Call enscons to emulate setup.py, installing if necessary. 

import sys, subprocess, os.path 

sys.path[0:0] = ['setup-requires'] 

try: 
    import enscons.setup 
except ImportError: 
    requires = ["enscons"] 
    subprocess.check_call([sys.executable, "-m", "pip", "install", 
     "-t", "setup-requires"] + requires) 
    del sys.path_importer_cache['setup-requires'] # needed if setup-requires was absent 
    import enscons.setup 

enscons.setup.setup() 

Cuối cùng, các tập tin SConstruct có thể giống như thế:

# Build pkgname 

import sys, os 
import pytoml as toml 
import enscons, enscons.cpyext 

metadata = dict(toml.load(open('pyproject.toml')))['tool']['enscons'] 

# most specific binary, non-manylinux1 tag should be at the top of this list 
import wheel.pep425tags 
full_tag = next(tag for tag in wheel.pep425tags.get_supported() if not 'manylinux' in tag) 

env = Environment(tools=['default', 'packaging', enscons.generate, enscons.cpyext.generate], 
        PACKAGE_METADATA=metadata, 
        WHEEL_TAG=full_tag) 

ext_filename = os.path.join('pkgname', 'libcfile') 

extension = env.SharedLibrary(target=ext_filename, 
           source=['pkgname/cfile.c']) 

py_source = Glob('pkgname/*.py') 

platlib = env.Whl('platlib', py_source + extension, root='') 
whl = env.WhlFile(source=platlib) 

# Add automatic source files, plus any other needed files. 
sdist_source=list(set(FindSourceFiles() + 
    ['PKG-INFO', 'setup.py'] + 
    Glob('pkgname/*', exclude=['pkgname/*.os']))) 

sdist = env.SDist(source=sdist_source) 
env.Alias('sdist', sdist) 

install = env.Command("#DUMMY", whl, 
         ' '.join([sys.executable, '-m', 'pip', 'install', '--no-deps', '$SOURCE'])) 
env.Alias('install', install) 
env.AlwaysBuild(install) 

env.Default(whl, sdist) 

Sau này, bạn sẽ có thể chạy

sudo python setup.py install 

để biên dịch phần mở rộng C và tạo bánh xe và cài đặt gói python hoặc

python setup.py sdist 

để tạo phân phối nguồn.

Tôi nghĩ bạn về cơ bản có thể làm bất cứ điều gì bạn có thể với SCons trong tệp SConstruct.

+0

Thay vì đăng các liên kết dưới dạng câu trả lời, hãy thêm một số văn bản để giải thích cách câu trả lời này giúp OP trong việc khắc phục vấn đề hiện tại.Thanks –

+0

@ ρяσѕρєяK Tôi đã thêm một ví dụ cụ thể hơn từ các liên kết. –

+0

Tôi nghĩ @joeforker là tác giả của enscons, vì vậy họ có thể thêm vào câu trả lời này. –

1

Xem trang: http://www.scons.org/wiki/PythonExtensions

Tôi đang sử dụng phiên bản sửa đổi một chút để xây dựng mở rộng pyrex-c cho python.

+0

Câu hỏi của tôi là nhiều hơn về cách làm điều đó (biên dịch phần mở rộng python với) trong kịch bản setup.py theo cách sạch nhất có thể. Bằng cách này, tôi có thể dễ dàng phân phối ứng dụng của mình. – pygabriel

+0

@pygabriel Để biên dịch các phần mở rộng C, bạn không cần SCons. Ở tất cả. – bialix

+2

@ bialix, Nó không phải là cần scons hay không, ví dụ tôi có một dự án đã sử dụng scons để xây dựng ... Làm thế nào tôi sẽ cắm nó trong distutils để viết chỉ "python setup.py install" hoặc phát triển và distutils chỉ cần gọi scons –

0

Tôi sử dụng scons để tạo tệp setup.py. Vì vậy, tôi đã tạo một mẫu có tên là setup.py.in và sử dụng các scon để mở rộng mẫu để tạo ra setup.py.

Dưới đây là một số liên kết đến các dự án của tôi mà thực hiện điều này:

setup.py.in template

The SConstruct

này tính một cuốn từ điển của chủ chốt, các cặp giá trị để thay thế vào mẫu setup.py.in để tạo setup.py.

Vì vậy, người dùng cuối cần thực hiện hai điều:

scons setup.py 
python setup.py install 

Cảnh báo: thứ sconstruct của tôi là một chút lộn xộn như tôi đã viết nó một lúc trước, nhưng nó phải chứng minh khái niệm này.

Nếu bạn học cách viết scons thích hợp các công cụ, sau đó điều này có thể được chuyển đổi thành một mục tiêu duy nhất, ví dụ:

scons --pymod 

Dưới đây là một công cụ scons sự tạo ra một wrapper Python với SWIG:

import SCons.Action 
from SCons.Script import EnsureSConsVersion 

SCons.Script.EnsureSConsVersion(0,96,92) 

SwigGenAction = SCons.Action.Action('$SWIGGENCOM', '$SWIGGENCOMSTR') 

def emitter(target, source, env): 
    """ 
    Add dependency from target to source 
    """ 

    env.Depends(target, source) 

    return target, source 


def generate(env): 
    """ 
    Add builders and construction variables for the SwigGen builder. 
    """ 

    if 'SWIGCOM' not in env: 
     raise SystemError("SCons build environment could not detect tool: swig") 

    bld = env.Builder(
     action = SwigGenAction, 
     emitter = emitter, 
     target_factory = env.fs.File) 

    env['BUILDERS']['SwigGen'] = bld 

    env['SWIGGENCOM'] = env['SWIGCOM'] 


def exists(env): 
    return env.Detect('swig') 

Bây giờ từ tập tin SConstruct của bạn, bạn có thể tạo mã wrapper:

foobar_cc = env.SwigGen("foobar_wrap.cc", "foobar.i") 

Nếu bạn sửa đổi foobar.i nó sẽ tái tạo foobar_wrap.cc. Một khi bạn có điều này, bạn có thể viết các công cụ khác để thực sự cài đặt python setup.py cho bạn, vì vậy khi --pymod được cung cấp, nó sẽ xây dựng mô đun python.

0

Giải pháp là để cung cấp cmdclass tùy biến bắt nguồn từ distutils.cmd.Commmand trong đó xây dựng các mô-đun cách bạn muốn nó:

import distutils.cmd 

class build_py_cmd(distutils.cmd.Command): 
    def initialize_options(self): 
     pass 

    def finalize_options(self): 
     pass 
    def run(self): 
     print("Calling SCons to build the module") 
     pbs.scons() 


setup(name = 'riak3k', 
     packages = ['riak3k'], 
     package_dir = {'': 'build/release'}, 
     cmdclass = {'build_py': build_py_cmd}, 
+0

Nhập 'pbs' là gì? –

+0

Có vẻ như mô-đun 'pbs' là từ https://pypi.python.org/pypi/pbs, để gọi các hàm OS như hàm python. Theo như tôi có thể nói, nó sẽ tương đương với 'subprocess.check_call (['scons'])'. –

Các vấn đề liên quan