{"id":13494317,"url":"https://github.com/tbenthompson/cppimport","last_synced_at":"2025-05-14T17:09:34.088Z","repository":{"id":41207549,"uuid":"58673385","full_name":"tbenthompson/cppimport","owner":"tbenthompson","description":"Import C++ files directly from Python!","archived":false,"fork":false,"pushed_at":"2024-05-31T15:42:39.000Z","size":180,"stargazers_count":1214,"open_issues_count":11,"forks_count":70,"subscribers_count":40,"default_branch":"main","last_synced_at":"2025-05-10T11:37:15.258Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tbenthompson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-05-12T20:11:40.000Z","updated_at":"2025-04-12T08:34:00.000Z","dependencies_parsed_at":"2024-06-18T14:15:12.015Z","dependency_job_id":null,"html_url":"https://github.com/tbenthompson/cppimport","commit_stats":{"total_commits":180,"total_committers":18,"mean_commits":10.0,"dds":"0.12222222222222223","last_synced_commit":"0849d17ab737dfea3c6bab28f58f3b5c2fa7102e"},"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tbenthompson%2Fcppimport","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tbenthompson%2Fcppimport/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tbenthompson%2Fcppimport/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tbenthompson%2Fcppimport/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tbenthompson","download_url":"https://codeload.github.com/tbenthompson/cppimport/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254190395,"owners_count":22029632,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T19:01:23.862Z","updated_at":"2025-05-14T17:09:34.063Z","avatar_url":"https://github.com/tbenthompson.png","language":"Python","readme":"# cppimport - Import C++ directly from Python! \n\n\u003cp align=center\u003e\n    \u003ca target=\"_blank\" href=\"https://www.python.org/downloads/\" title=\"Python version\"\u003e\u003cimg src=\"https://img.shields.io/badge/python-%3E=_3.7-green.svg\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://pypi.org/project/cppimport/\" title=\"PyPI version\"\u003e\u003cimg src=\"https://img.shields.io/pypi/v/cppimport?logo=pypi\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://pypi.org/project/cppimport/\" title=\"PyPI\"\u003e\u003cimg src=\"https://img.shields.io/pypi/dm/cppimport\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"LICENSE\" title=\"License: MIT\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-blue.svg\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://github.com/tbenthompson/cppimport/actions\" title=\"Test Status\"\u003e\u003cimg src=\"https://github.com/tbenthompson/cppimport/actions/workflows/test.yml/badge.svg\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://codecov.io/gh/tbenthompson/cppimport\" title=\"Code coverage\"\u003e\u003cimg src=\"https://codecov.io/gh/tbenthompson/cppimport/branch/main/graph/badge.svg?token=GWpX62xMt5\"/\u003e\u003c/a\u003e\n\u003c/a\u003e\n\n\u003c/p\u003e\n\n## Contributing and architecture\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for details on the internals of `cppimport` and how to get involved in development.\n\n## Installation\n\nInstall with `pip install cppimport`.\n\n## A quick example\n\nSave the C++ code below as `somecode.cpp`.\n```c++\n// cppimport\n#include \u003cpybind11/pybind11.h\u003e\n\nnamespace py = pybind11;\n\nint square(int x) {\n    return x * x;\n}\n\nPYBIND11_MODULE(somecode, m) {\n    m.def(\"square\", \u0026square);\n}\n/*\n\u003c%\nsetup_pybind11(cfg)\n%\u003e\n*/\n```\n\nThen open a Python interpreter and import the C++ extension:\n```python\n\u003e\u003e\u003e import cppimport.import_hook\n\u003e\u003e\u003e import somecode #This will pause for a moment to compile the module\n\u003e\u003e\u003e somecode.square(9)\n81\n```\n\nHurray, you've called some C++ code from Python using a combination of `cppimport` and [`pybind11`](https://github.com/pybind/pybind11).  \n\nI'm a big fan of the workflow that this enables, where you can edit both C++ files and Python and recompilation happens transparently! It's also handy for quickly whipping together an optimized version of a slow Python function.\n\n## An explanation \n\nOkay, now that I've hopefully convinced you on how exciting this is, let's get into the details of how to do this yourself. First, the comment at top is essential to opt in to cppimport. Don't forget this! (See below for an explanation of why this is necessary.)\n```c++\n// cppimport\n```\n\nThe bulk of the file is a generic, simple [pybind11](https://github.com/pybind/pybind11) extension. We include the `pybind11` headers, then define a simple function that squares `x`, then export that function as part of a Python extension called `somecode`.\n\nFinally at the end of the file, there's a section I'll call the \"configuration block\":\n```\n\u003c%\nsetup_pybind11(cfg)\n%\u003e\n```\nThis region surrounded by `\u003c%` and `%\u003e` is a [Mako](https://www.makotemplates.org/) code block. The region is evaluated as Python code during the build process and provides configuration info like compiler and linker flags to the cppimport build system. \n\nNote that because of the Mako pre-processing, the comments around the configuration block may be omitted.  Putting the configuration block at the end of the file, while optional, ensures that line numbers remain correct in compilation error messages.\n\n## Building for production\nIn production deployments you usually don't want to include a c/c++ compiler, all the sources and compile at runtime. Therefore, a simple cli utility for pre-compiling all source files is provided. This utility may, for example, be used in CI/CD pipelines. \n\nUsage is as simple as\n\n```commandline\npython -m cppimport build\n```\n\nThis will build all `*.c` and `*.cpp` files in the current directory (and it's subdirectories) if they are eligible to be imported (i.e. contain the `// cppimport` comment in the first line).\n\nAlternatively, you may specifiy one or more root directories or source files to be built:\n\n```commandline\npython -m cppimport build ./my/directory/ ./my/single/file.cpp\n```\n_Note: When specifying a path to a file, the header check (`// cppimport`) is skipped for that file._\n\n### Fine-tuning for production\nTo further improve startup performance for production builds, you can opt-in to skip the checksum and compiled binary existence checks during importing by either setting the environment variable `CPPIMPORT_RELEASE_MODE` to `true` or setting the configuration from within Python:\n```python\ncppimport.settings['release_mode'] = True\n```\n**Warning:** Make sure to have all binaries pre-compiled when in release mode, as importing any missing ones will cause exceptions. \n\n## Frequently asked questions\n\n### What's actually going on?\n\nSometimes Python just isn't fast enough. Or you have existing code in a C or C++ library. So, you write a Python *extension module*, a library of compiled code. I recommend [pybind11](https://github.com/pybind/pybind11) for C++ to Python bindings or [cffi](https://cffi.readthedocs.io/en/latest/) for C to Python bindings. I've done this a lot over the years. But, I discovered that my productivity is slower when my development process goes from *Edit -\u003e Test* in just Python to *Edit -\u003e Compile -\u003e Test* in Python plus C++. So, `cppimport` combines the process of compiling and importing an extension in Python so that you can just run `import foobar` and not have to worry about multiple steps. Internally, `cppimport` looks for a file `foobar.cpp`. Assuming one is found, it's run through the Mako templating system to gather compiler options, then it's compiled and loaded as an extension module.\n\n### Does cppimport recompile every time a module is imported? \nNo! Compilation should only happen the first time the module is imported. The C++ source is compared with a checksum on each import to determine if any relevant file has changed. Additional dependencies (e.g. header files!) can be tracked by adding to the Mako header:\n```python\ncfg['dependencies'] = ['file1.h', 'file2.h']\n```\nThe checksum is computed by simply appending the contents of the extension C++ file together with the files in `cfg['sources']` and `cfg['dependencies']`. \n\n### How can I set compiler or linker args?\n\nStandard distutils configuration options are valid:\n\n```python\ncfg['extra_link_args'] = ['...']\ncfg['extra_compile_args'] = ['...']\ncfg['libraries'] = ['...']\ncfg['include_dirs'] = ['...']\n```\n\nFor example, to use C++11, add:\n```python\ncfg['extra_compile_args'] = ['-std=c++11']\n```\n\n### How can I split my extension across multiple source files?\n\nIn the configuration block: \n```python\ncfg['sources'] = ['extra_source1.cpp', 'extra_source2.cpp']\n```\n\n### cppimport isn't doing what I want, can I get more verbose output?\n`cppimport` uses the standard Python logging tools. Please add logging handlers to either the root logger or the `\"cppimport\"` logger. For example, to output all debug level log messages:\n\n```python\nroot_logger = logging.getLogger()\nroot_logger.setLevel(logging.DEBUG)\n\nhandler = logging.StreamHandler(sys.stdout)\nhandler.setLevel(logging.DEBUG)\nformatter = logging.Formatter(\"%(asctime)s - %(name)s - %(levelname)s - %(message)s\")\nhandler.setFormatter(formatter)\nroot_logger.addHandler(handler)\n```\n\n### How can I force a rebuild even when the checksum matches?\n\nSet:\n```python\ncppimport.settings['force_rebuild'] = True\n```\n\nAnd if this is a common occurence, I would love to hear your use case and why the combination of the checksum, `cfg['dependencies']` and `cfg['sources']` is insufficient!\n\nNote that `force_rebuild` does not work when importing the module concurrently.\n\n### Can I import my model concurrently?\n\nIt's (mostly) safe to use `cppimport` to import a module concurrently using multiple threads, processes or even machines!\nThere's an exception if your filesystem does not support file locking - see the next section. \n\nBefore building a module, `cppimport` obtains a lockfile preventing other processors from building it at the same time - this prevents clashes that can lead to failure.\nOther processes will wait maximum 10 mins until the first process has built the module and load it. If your module does not build within 10 mins then it will timeout.\nYou can increase the timeout time in the settings:\n\n```python\ncppimport.settings['lock_timeout'] = 10*60 # 10 mins\n```\n\nYou should not use `force_rebuild` when importing concurrently.\n\n### Acquiring the lock hangs or times out unexpectedly - what's going on?\nCertain platforms (e.g. those running \na Data Virtualization Service, DVS) do not support file locking. If you're on Linux with access to `flock`, you can test whether\nlocking is supported (credit to [this page](https://help.univention.com/t/howto-verify-the-mounted-filesystem-supports-file-locking/10149)):\n\n```bash\ntouch testfile\nflock ./testfile true \u0026\u0026 echo ok || echo nok\n```\n\nIf locking is not supported, you can disable the file lock in\nthe cppimport global settings: \n\n```python\ncppimport.settings['use_filelock'] = False \n```\n\nThis setting must be changed before you import any\ncode. By setting `use_filelock=False`, you become responsible \nfor ensuring that only a single process\n(re)builds the package at a time. For example: if you're\nusing [mpi4py](https://mpi4py.readthedocs.io/en/stable/)\nto run independent, communicating processes, here's how \nto protect the build:\n\n```python\nfrom mpi4py import MPI\nimport cppimport, cppimport.import_hook\ncppimport.settings[\"use_filelock\"] = False\n\npid = MPI.COMM_WORLD.Get_rank()\n\nif pid == 0:\n    import somecode      # Process 0 compiles extension if needed \nMPI.COMM_WORLD.Barrier() # Remaining processes wait \nimport somecode          # All processes use compiled extension \n```\n\n### How can I get information about filepaths in the configuration block?\nThe module name is available as the `fullname` variable and the C++ module file is available as `filepath`.\nFor example,\n```\n\u003c%\nmodule_dir = os.path.dirname(filepath)\n%\u003e\n```\n\n### How can I make compilation faster? \n\nIn single file extensions, this is a fundamental issue with C++. Heavily templated code is often quite slow to compile. \n\nIf your extension has multiple source files using the `cfg['sources']` capability, then you might be hoping for some kind of incremental compilation. For the uninitiated, incremental compilation involves only recompiling those source files that have changed. Unfortunately this isn't possible because cppimport is built on top of the setuptools and distutils and these standard library components do not support incremental compilation. \n\nI recommend following the suggestions on [this SO answer](http://stackoverflow.com/questions/11013851/speeding-up-build-process-with-distutils). That is:\n\n1. Use `ccache` to reduce the cost of rebuilds\n2. Enable parallel compilation. This can be done with `cfg['parallel'] = True` in the C++ file's configuration header.\n\nAs a further thought, if your extension has many source files and you're hoping to do incremental compiles, that probably indicates that you've outgrown `cppimport` and should consider using a more complete build system like CMake.\n\n### Why does the import hook need \"cppimport\" on the first line of the .cpp file?\nModifying the Python import system is a global modification and thus affects all imports from any other package. As a result, when I first implemented `cppimport`, other packages (e.g. `scipy`) suddenly started breaking because import statements internal to those packages were importing C or C++ files instead of the modules they were intended to import. To avoid this failure mode, the import hook uses an \"opt in\" system where C and C++ files can specify they are meant to be used with cppimport by having a comment on the first line that includes the text \"cppimport\". \n\nAs an alternative to the import hook, you can use `imp` or `imp_from_filepath`. The `cppimport.imp` and `cppimport.imp_from_filepath` performs exactly the same operation as the import hook but in a slightly more explicit way:\n```\nfoobar = cppimport.imp(\"foobar\")\nfoobar = cppimport.imp_from_filepath(\"src/foobar.cpp\")\n```\nBy default, these explicit function do not require the \"cppimport\" keyword on the first line of the C++ source file. \n\n### Windows?\nThe CI system does not run on Windows. A PR would be welcome adding further Windows support. I've used `cppimport` with MinGW-w64 and Python 3.6 and had good success. I've also had reports that `cppimport` works on Windows with Python 3.6 and Visual C++ 2015 Build Tools. The main challenge is making sure that distutils is aware of your available compilers. Try out the suggestion [here](https://stackoverflow.com/questions/3297254/how-to-use-mingws-gcc-compiler-when-installing-python-package-using-pip).\n\n## cppimport uses the MIT License\n","funding_links":[],"categories":["Scripting","Python","Containers \u0026 Language Extentions \u0026 Linting","正则表达式"],"sub_categories":["For Python","脚本"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftbenthompson%2Fcppimport","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftbenthompson%2Fcppimport","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftbenthompson%2Fcppimport/lists"}