<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 11.2 通過PyPI發布使用CMake/pybind11構建的C++/Python項目 **NOTE**:*此示例代碼可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-11/recipe-02 中找到。該示例在CMake 3.11版(或更高版本)中是有效的,并且已經在GNU/Linux、macOS和Windows上進行過測試。* 本示例中,我們將以第9章第5節的代碼的pybind11為例,為其添加相關的安裝目標和pip打包信息,并將項目上傳到PyPI。我們要實現一個可以使用pip安裝,并運行CMake從而獲取底層pybind11依賴項的項目。 ## 準備工作 要通過PyPI分發包的話,需要一個https://pypi.org 帳戶。當然,也可以先從本地路徑進行安裝練習。 **TIPS**:*建議使用Pipenv (https://docs.pipenv.org )或虛擬環境(https://virtualenv.pypa )安裝這個包和其他的Python包。* 我們基于第9章第5節的項目,它包含一個主`CMakeLists.txt`文件和一個`account/CMakeLists.txt`文件,配置帳戶示例目標時,使用如下的項目樹: ```shell . ├── account │ ├── account.cpp │ ├── account.hpp │ ├── CMakeLists.txt │ s└── test.py └── CMakeLists.txt ``` 示例中,`account.cpp`,` account.hpp`和`test.py`沒有任何變化。修改`account/CMakeLists.txt`,并為pip添加幾個文件,以便能夠構建安裝包。為此,需要根目錄中的另外三個文件:`README.rst`,`MANIFEST.in`和`setup.py`。 `README.rst`中包含關于項目的s文檔: ```txt Example project =============== Project description in here ... ``` `MANIFEST.in`列出了需要安裝的Python模塊: ```txt include README.rst CMakeLists.txt recursive-include account *.cpp *.hpp CMakeLists.txt ``` 最后,`setup.py`包含構建指令和安裝項目的說明: ```python import distutils.command.build as _build import os import sys from distutils import spawn from distutils.sysconfig import get_python_lib from setuptools import setup def extend_build(): class build(_build.build): def run(self): cwd = os.getcwd() if spawn.find_executable('cmake') is None: sys.stderr.write("CMake is required to build this package.\n") sys.exit(-1) _source_dir = os.path.split(__file__)[0] _build_dir = os.path.join(_source_dir, 'build_setup_py') _prefix = get_python_lib() try: cmake_configure_command = [ 'cmake', '-H{0}'.format(_source_dir), '-B{0}'.format(_build_dir), '-DCMAKE_INSTALL_PREFIX={0}'.format(_prefix), ] _generator = os.getenv('CMAKE_GENERATOR') if _generator is not None: cmake_configure_command.append('- G{0}'.format(_generator)) spawn.spawn(cmake_configure_command) spawn.spawn( ['cmake', '--build', _build_dir, '--target', 'install']) os.chdir(cwd) except spawn.DistutilsExecError: sys.stderr.write("Error while building with CMake\n") sys.exit(-1) _build.build.run(self) return build _here = os.path.abspath(os.path.dirname(__file__)) if sys.version_info[0] < 3: with open(os.path.join(_here, 'README.rst')) as f: long_description = f.read() else: with open(os.path.join(_here, 'README.rst'), encoding='utf-8') as f: long_description = f.read() _this_package = 'account' version = {} with open(os.path.join(_here, _this_package, 'version.py')) as f: exec(f.read(), version) setup( name=_this_package, version=version['__version__'], description='Description in here.', long_description=long_description, author='Bruce Wayne', author_email='bruce.wayne@example.com', url='http://example.com', license='MIT', packages=[_this_package], include_package_data=True, classifiers=[ 'Development Status :: 3 - Alpha', 'Intended Audience :: Science/Research', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.6' ], cmdclass={'build': extend_build()}) ``` `account`子目錄中放置一個`__init__.py`腳本: ```python from .version import __version__ from .account import Account __all__ = [ '__version__', 'Account', ] ``` 再放一個`version.py`腳本: ```python __version__ = '0.0.0' ``` 項目的文件結構如下: ```shell . ├── account │ ├── account.cpp │ ├── account.hpp │ ├── CMakeLists.txt │ ├── __init__.py │ ├── test.py │ └── version.py ├── CMakeLists.txt ├── MANIFEST.in ├── README.rst └── setup.py ``` ## 具體實施 本示例基于第9章第5節項目的基礎上。 首先,修改`account/CMakeLists.txt`,添加安裝目標: ```cmake install( TARGETS account LIBRARY DESTINATION account ) ``` 安裝目標時,`README.rst`, `MANIFEST.in`,`setup.py`、`__init__.py`和`version.py`將放置在對應的位置上,我們準備使用pybind11測試安裝過程: 1. 為此,在某處創建一個新目錄,我們將在那里測試安裝。 2. 在創建的目錄中,從本地路徑運行`pipenv install`。調整本地路徑,指向`setup.py`的目錄: ```shell $ pipenv install /path/to/cxx-example ``` 3. 在Pipenv環境中打開一個Python shell: ```shell $ pipenv run python ``` 4. Python shell中,可以測試我們的CMake包: ```shell >>> from account import Account >>> account1 = Account() >>> account1.deposit(100.0) >>> account1.deposit(100.0) >>> account1.withdraw(50.0) >>> print(account1.get_balance()) 150.0 ``` ## 工作原理 `${CMAKE_CURRENT_BINARY_DIR}`目錄包含編譯后的`account.cpython-36m-x86_64-linux-gnu.so`,這個動態庫就是使用pybind11構建Python模塊。但是請注意,它的名稱取決于操作系統(本例中是64位Linux)和Python環境(本例中是Python 3.6)。`setup.py`s腳本將運行CMake,并根據所選的Python環境(系統Python,Pipenv或虛擬環境)將Python模塊安裝到正確的路徑下。 不過,在安裝模塊時面臨兩個挑戰: * 名稱可變 * CMake外部設置路徑 可以使用下面的安裝目標來解決這個問題,將在setup.py中定義安裝目標位置: ```cmake install( TARGETS account LIBRARY DESTINATION account ) ``` 指示CMake將編譯好的Python模塊文件安裝到相對于安裝目標位置的`account`子目錄中(第10章中詳細討論了如何設置目標位置)。`setup.py`將通過設置`CMAKE_INSTALL_PREFIX`來設置安裝位置,并根據Python環境指向正確的路徑。 讓我們看看`setup.py`如何實現的。自下而上來看一下腳本: ```python setup( name=_this_package, version=version['__version__'], description='Description in here.', long_description=long_description, author='Bruce Wayne', author_email='bruce.wayne@example.com', url='http://example.com', license='MIT', packages=[_this_package], include_package_data=True, classifiers=[ 'Development Status :: 3 - Alpha', 'Intended Audience :: Science/Research', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.6' ], cmdclass={'build': extend_build()}) ``` 該腳本包含許多占位符,還包含一些自解釋的語句。這里我們將重點介紹最后一個指令`cmdclass`。這個指令中,通過自定義`extend_build`函數擴展默認的構建步驟。這個默認的構建步驟如下: ```python def extend_build(): class build(_build.build): def run(self): cwd = os.getcwd() if spawn.find_executable('cmake') is None: sys.stderr.write("CMake is required to build this package.\n") sys.exit(-1) _source_dir = os.path.split(__file__)[0] _build_dir = os.path.join(_source_dir, 'build_setup_py') _prefix = get_python_lib() try: cmake_configure_command = [ 'cmake', '-H{0}'.format(_source_dir), '-B{0}'.format(_build_dir), '-DCMAKE_INSTALL_PREFIX={0}'.format(_prefix), ] _generator = os.getenv('CMAKE_GENERATOR') if _generator is not None: cmake_configure_command.append('- G{0}'.format(_generator)) spawn.spawn(cmake_configure_command) spawn.spawn( ['cmake', '--build', _build_dir, '--target', 'install']) os.chdir(cwd) except spawn.DistutilsExecError: sys.stderr.write("Error while building with CMake\n") sys.exit(-1) _build.build.run(self) return build ``` 首先,檢查CMake是否可用。函數執行了兩個CMake命令: ```python cmake_configure_command = [ 'cmake', '-H{0}'.format(_source_dir), '-B{0}'.format(_build_dir), '-DCMAKE_INSTALL_PREFIX={0}'.format(_prefix), ] _generator = os.getenv('CMAKE_GENERATOR') if _generator is not None: cmake_configure_command.append('- G{0}'.format(_generator)) spawn.spawn(cmake_configure_command) spawn.spawn( ['cmake', '--build', _build_dir, '--target', 'install']) ``` 我們可以設置`CMAKE_GENERATOR`環境變量來修改生成器。安裝目錄如下方式設置: ```shell _prefix = get_python_lib() ``` 從安裝目錄的根目錄下,通過`distutils.sysconfig`導入`get_python_lib`函數。`cmake --build _build_dir --target install`命令以一種可移植的方式,構建和安裝我們的項目。使用`_build_dir`而不使用`build`的原因是,在測試本地安裝時,項目可能已經包含了一個`build`目錄,這將與新安裝過程發生沖突。對于已經上傳到PyPI的包,構建目錄的名稱并不會帶來什么影響。 ## 更多信息 現在我們已經測試了本地安裝,準備將包上傳到PyPI。在此之前,請確保`setup.py`中的元數據(例如:項目名稱、聯系方式和許可協議信息)是合理的,并且項目名稱沒有與PyPI已存在項目重名。在上傳到https://pypi.org 之前,先測試PyPI(https://test.pypi.org )上,進行上載和下載的嘗試。 上傳之前,我們需要在主目錄中創建一個名為`.pypirc`的文件,其中包含(替換成自己的`yourusername`和`yourpassword `): ``` [distutils]account index-servers= pypi pypitest [pypi] username = yourusername password = yourpassword [pypitest] repository = https://test.pypi.org/legacy/ username = yourusername password = yourpassword ``` 我們將分兩步進行。首先,我們在本地創建Release包: ```shell $ python setup.py sdist ``` 第二步中,使用Twine上傳生成的分布數據(我們將Twine安裝到本地的Pipenv中): ```shell $ pipenv run twine upload dist/* -r pypitest Uploading distributions to https://test.pypi.org/legacy/ Uploading yourpackage-0.0.0.tar.gz ``` 下一步,從測試實例到,將包安裝到一個隔離的環境中: ```python $ pipenv shell $ pip install --index-url https://test.pypi.org/simple/ yourpackage ``` 當一切正常,就將我們的包上傳到了PyPI: ```shell $ pipenv run twine upload dist/* -r pypi ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看