Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
BasedOnStyle: LLVM

Language: Cpp
Standard: c++17
PointerAlignment: Left

IncludeCategories:
- Regex: '^"[^/]+\"'
Priority: 10
- Regex: '^"clang/'
Priority: 30
- Regex: '^"llvm/'
Priority: 40
- Regex: '^<'
Priority: 50
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Cling/LLVM code generation: since cppyy is a python module, there is no
# Cling/LLVM code generation: since cppjit is a python module, there is no
# proper control over offload ands since functions may be used during atexit()
# calls, we'll just leak all JITed code rather than risk spurious crashes in
# hard-to-reproduce cases.
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ jobs:
matrix:
# Superset of the PR matrix + breadth (py 3.12/3.13, C++17, LLVM 20, arm)
# and one cling cell. valgrind only where a supp is vendored: the LLVM 21
# cells (clang21) and the arm LLVM 22 cell (clang22), both under etc/.
# cells (clang21) and the arm LLVM 22 cell (clang22), both under
# .github/valgrind/.
include:
- { os: ubuntu-24.04, llvm: '20', flavor: system, py: '3.12', cxx: '17' }
- { os: ubuntu-24.04, llvm: '21', flavor: system, py: '3.13', cxx: '20', vg: true }
Expand Down
131 changes: 14 additions & 117 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,134 +1,31 @@
# Byte-compiled / optimized / DLL files
# Byte-compiled
__pycache__/
*.py[codz]
*$py.class
*.py[cod]

# C extensions
# Built test dictionaries and extension modules
*.so

# Distribution / packaging
.Python
# Packaging
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
wheelhouse/

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
# Test and coverage artifacts
.pytest_cache/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py.cover
.hypothesis/
.pytest_cache/
cover/

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
.python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
Pipfile.lock

# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
uv.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
poetry.lock
poetry.toml

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
pdm.lock
pdm.toml
.pdm-python
.pdm-build/

# pixi
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
# pixi.lock
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
# in the .venv directory. It is recommended not to include this directory in version control.
.pixi

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
htmlcov/

# Environments
# Environments and local config
.venv/
venv/
.env
.envrc
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# mkdocs documentation
/site

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/
.python-version

# IDEs and editors
# Editors / OS
.idea/
.vscode/
.DS_Store
60 changes: 34 additions & 26 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,77 +74,85 @@ execute_process(
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(_python_platlib)
set(CPPINTEROP_INSTALL_DIR "${_python_platlib}/cppjit/cppyy_backend")
set(CPPINTEROP_INSTALL_DIR "${_python_platlib}/cppjit_backend")
else()
set(CPPINTEROP_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/cppjit/cppyy_backend")
set(CPPINTEROP_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/cppjit_backend")
endif()

# Include cmake for CppInterOp config and build using ExternalProject.
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/AddCppInterOp.cmake)
cppjit_add_cppinterop()

# this libcppyy.so merges both CPyCppyy and clingwrapper
file(GLOB CPYCPPYY_SOURCES CONFIGURE_DEPENDS src/CPyCppyy/src/*.cxx)
set(BACKEND_SOURCES
src/backend/clingwrapper.cxx
src/backend/cppinterop_dispatch.cxx
# this libcppjit.so merges both cpyrt and the interop wrapper
file(GLOB CPYRT_SOURCES CONFIGURE_DEPENDS src/cpyrt/*.cxx)
set(INTEROP_SOURCES
src/interop/interop_wrapper.cxx
src/interop/cppinterop_dispatch.cxx
)

add_library(cppyy SHARED ${CPYCPPYY_SOURCES} ${BACKEND_SOURCES})
add_dependencies(cppyy CppInterOp)
add_library(cppjit SHARED ${CPYRT_SOURCES} ${INTEROP_SOURCES})
add_dependencies(cppjit CppInterOp)


target_compile_definitions(cppyy PRIVATE
target_compile_definitions(cppjit PRIVATE
CPPINTEROP_DIR="${CPPINTEROP_INSTALL_DIR}"
CMAKE_SHARED_LIBRARY_SUFFIX="${CMAKE_SHARED_LIBRARY_SUFFIX}"
)

target_include_directories(cppyy PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src/CPyCppyy/include
${CMAKE_CURRENT_SOURCE_DIR}/src/CPyCppyy/src
${CMAKE_CURRENT_SOURCE_DIR}/src/backend
target_include_directories(cppjit PRIVATE
# src/ itself resolves the public "cpyrt/*.h" spellings against the
# flattened src/cpyrt/ directory
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/src/cpyrt
${CMAKE_CURRENT_SOURCE_DIR}/src/interop
${CPPINTEROP_INSTALL_DIR}/include
${Python_INCLUDE_DIRS}
)

target_compile_options(cppyy PRIVATE
target_compile_options(cppjit PRIVATE
-Wall -Wno-strict-aliasing -Wno-register
)

if(CMAKE_COMPILER_IS_GNUCXX)
target_link_options(cppyy PRIVATE -Wl,-Bsymbolic-functions)
target_link_options(cppjit PRIVATE -Wl,-Bsymbolic-functions)
endif()

# macOS needs to allow undefined Python symbols
if(APPLE)
set_target_properties(cppyy PROPERTIES
set_target_properties(cppjit PROPERTIES
LINK_FLAGS "-undefined dynamic_lookup"
SUFFIX ".so"
)
endif()

set_target_properties(cppyy PROPERTIES
OUTPUT_NAME "cppyy"
set_target_properties(cppjit PROPERTIES
OUTPUT_NAME "cppjit"
PREFIX "lib"
)

# libcppyy.so is installed in cppjit/ root (import cppjit.libcppyy)
install(TARGETS cppyy
LIBRARY DESTINATION cppjit
# libcppjit.so is installed at the site-packages root (import libcppjit)
install(TARGETS cppjit
LIBRARY DESTINATION .
)

# install CppInterOp libraries and headers
install(CODE "
file(GLOB _interop_libs \"${CPPINTEROP_INSTALL_DIR}/lib/libclangCppInterOp*\")
foreach(_lib \${_interop_libs})
file(INSTALL \${_lib} DESTINATION \${CMAKE_INSTALL_PREFIX}/cppjit/cppyy_backend/lib)
file(INSTALL \${_lib} DESTINATION \${CMAKE_INSTALL_PREFIX}/cppjit_backend/lib)
endforeach()
")

install(CODE "
file(INSTALL \"${CPPINTEROP_INSTALL_DIR}/include/\" DESTINATION \${CMAKE_INSTALL_PREFIX}/cppjit/cppyy_backend/include)
file(INSTALL \"${CPPINTEROP_INSTALL_DIR}/include/\" DESTINATION \${CMAKE_INSTALL_PREFIX}/cppjit_backend/include)
")

install(DIRECTORY src/CPyCppyy/include/CPyCppyy
DESTINATION cppjit/cppyy_backend/include
# the public cpyrt API headers keep their installed cpyrt/ prefix
install(FILES
src/cpyrt/API.h
src/cpyrt/CommonDefs.h
src/cpyrt/DispatchPtr.h
src/cpyrt/PyException.h
src/cpyrt/Reflex.h
DESTINATION cppjit_backend/include/cpyrt
)
35 changes: 30 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,50 @@ build-backend = "scikit_build_core.build"

[project]
name = "cppjit"
version = "0.1.0"
dynamic = ["version"]
description = "CppJIT: fast and automatic Python-C++ interoperability"
license = {text = "LBNL BSD"}
requires-python = ">=3.8"
requires-python = ">=3.12"
authors = [
{name = "Aaron Jomy"},
{name = "Baidyanath Kundu"},
{name = "Jonas Rembser"},
{name = "Vassil Vassilev"},
{name = "Vipul Cariappa"},
{name = "Wim Lavrijsen"},
{name = "compiler-research"}
{name = "Wim Lavrijsen"}
]
maintainers = [
{name = "Aaron Jomy", email = "aaronjomyjoseph@gmail.com"}
]

[tool.scikit-build]
wheel.install-dir = "."
wheel.packages = ["python/cppjit"]
wheel.packages = ["python/cppjit", "python/cppjit_backend"]
cmake.build-type = "Release"
metadata.version.provider = "scikit_build_core.metadata.regex"
metadata.version.input = "python/cppjit/_version.py"

[tool.pytest.ini_options]
testpaths = ["test"]
pythonpath = ["test"]

[tool.ruff]
show-fixes = true

[tool.ruff.lint]
# pyflakes/pycodestyle errors plus import sorting; wider rule sets are a
# post-squash cleanup
select = ["E4", "E7", "E9", "F", "I"]
ignore = [
"E722", # bare excepts deliberately swallow C++-originated exceptions
]

[tool.ruff.lint.per-file-ignores]
# the star import is load-bearing: it pulls the merged extension's names into
# the package namespace, and everything below it depends on them
"python/cppjit/__init__.py" = ["F403", "F405"]
"test/assert_interactive.py" = ["F403", "F405"]
# binding-test idioms: == True/False and type(x) == y assert proxy comparison
# semantics, fixtures use short upstream names, and unused locals hold
# references to control C++ object lifetimes
"test/**" = ["E712", "E721", "E741", "E742", "F841"]
Loading
Loading