Skip to content
Open
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
105 changes: 100 additions & 5 deletions .github/workflows/build-wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,79 @@ concurrency:


jobs:
build-core-wheels:
runs-on: ${{ matrix.os }}
name: ${{ matrix.name }}
strategy:
matrix:
include:
- name: x86_64 Linux
os: ubuntu-24.04
rust-target: x86_64-unknown-linux-gnu
cibw-arch: x86_64
- name: arm64 Linux
os: ubuntu-24.04-arm
rust-target: aarch64-unknown-linux-gnu
cibw-arch: aarch64
- name: arm64 macOS
os: macos-15
rust-target: aarch64-apple-darwin
cibw-arch: arm64
- name: x86_64 Windows
os: windows-2022
rust-target: x86_64-pc-windows-msvc
cibw-arch: AMD64
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0

- name: setup rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
target: ${{ matrix.rust-target }}

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.14"

- name: install dependencies
run: python -m pip install cibuildwheel twine

- name: build custom manylinux docker images
if: matrix.os == 'ubuntu-24.04' || matrix.os == 'ubuntu-24.04-arm'
run: |
docker buildx build \
-t rustc-manylinux_2_28_${{ matrix.cibw-arch }} \
python/scripts/rustc-manylinux_2_28_${{ matrix.cibw-arch }}

- name: build metatomic-core wheel
run: python -m cibuildwheel python/metatomic_core
env:
CIBW_BUILD: cp311-*
CIBW_SKIP: "*musllinux*"
CIBW_ARCHS: ${{ matrix.cibw-arch }}
CIBW_BUILD_VERBOSITY: 1
CIBW_MANYLINUX_X86_64_IMAGE: rustc-manylinux_2_28_x86_64
CIBW_MANYLINUX_AARCH64_IMAGE: rustc-manylinux_2_28_aarch64
CIBW_ENVIRONMENT: >
MACOSX_DEPLOYMENT_TARGET=11
# do not complain for missing shared libraries provided by other packages
CIBW_REPAIR_WHEEL_COMMAND_MACOS: |
delocate-wheel --ignore-missing-dependencies --require-archs {delocate_archs} -w {dest_dir} -v {wheel}
CIBW_REPAIR_WHEEL_COMMAND_LINUX: |
auditwheel repair --exclude libmetatensor.so -w {dest_dir} {wheel}

- name: check wheels with twine
run: twine check wheelhouse/*.whl

- uses: actions/upload-artifact@v7
with:
name: core-wheel-${{ matrix.os }}-${{ matrix.cibw-arch }}
path: ./wheelhouse/*.whl

build-torch-wheels:
runs-on: ${{ matrix.os }}
name: ${{ matrix.name }} (torch v${{ matrix.torch-version }})
Expand Down Expand Up @@ -89,8 +162,8 @@ jobs:
if: matrix.os == 'ubuntu-24.04' || matrix.os == 'ubuntu-24.04-arm'
run: |
docker buildx build \
-t gcc11-manylinux_2_28_${{ matrix.cibw-arch }} \
python/scripts/gcc11-manylinux_2_28_${{ matrix.cibw-arch }}
-t rustc-manylinux_2_28_${{ matrix.cibw-arch }} \
python/scripts/rustc-manylinux_2_28_${{ matrix.cibw-arch }}

- name: build metatomic-torch wheel
run: python -m cibuildwheel python/metatomic_torch
Expand All @@ -99,8 +172,8 @@ jobs:
CIBW_SKIP: "*musllinux*"
CIBW_ARCHS: ${{ matrix.cibw-arch }}
CIBW_BUILD_VERBOSITY: 1
CIBW_MANYLINUX_X86_64_IMAGE: gcc11-manylinux_2_28_x86_64
CIBW_MANYLINUX_AARCH64_IMAGE: gcc11-manylinux_2_28_aarch64
CIBW_MANYLINUX_X86_64_IMAGE: rustc-manylinux_2_28_x86_64
CIBW_MANYLINUX_AARCH64_IMAGE: rustc-manylinux_2_28_aarch64
# METATOMIC_NO_LOCAL_DEPS is set to 1 when building a tag of
# metatomic-torch, which will force to use the version of
# metatomic-core already released on PyPI. Otherwise, this will use
Expand Down Expand Up @@ -214,6 +287,9 @@ jobs:
- name: install dependencies
run: python -m pip install wheel build twine

- name: build metatomic-core sdist
run: python -m build python/metatomic_core --sdist --outdir=dist/

- name: build metatomic-torch sdist
run: python -m build python/metatomic_torch --sdist --outdir=dist/

Expand All @@ -231,6 +307,7 @@ jobs:

- name: create C++ tarballs
run: |
./scripts/package-core.sh dist/cxx/
./scripts/package-torch.sh dist/cxx/

- uses: actions/upload-artifact@v7
Expand All @@ -243,12 +320,19 @@ jobs:

merge-and-release:
name: Merge and release wheels/sdists
needs: [merge-torch-wheels, build-others]
needs: [build-core-wheels, merge-torch-wheels, build-others]
runs-on: ubuntu-24.04
permissions:
contents: write
pull-requests: write
steps:
- name: Download metatomic-core wheels
uses: actions/download-artifact@v8
with:
path: wheels
pattern: core-wheel-*
merge-multiple: true

- name: Download metatomic-torch wheels
uses: actions/download-artifact@v8
with:
Expand Down Expand Up @@ -277,6 +361,17 @@ jobs:
name: wheels
description: ⚙️ Download Python wheels for this pull-request (you can install these with pip)

- name: upload to GitHub release (metatomic-core)
if: startsWith(github.ref, 'refs/tags/metatomic-core-v')
uses: softprops/action-gh-release@v3
with:
files: |
wheels/cxx/metatomic-core-cxx-*.tar.gz
wheels/metatomic_core-*
prerelease: ${{ contains(github.ref, '-rc') }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: upload to GitHub release (metatomic)
if: startsWith(github.ref, 'refs/tags/metatomic-v')
uses: softprops/action-gh-release@v3
Expand Down
11 changes: 11 additions & 0 deletions metatomic-core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -461,3 +461,14 @@ install(FILES
${PROJECT_BINARY_DIR}/metatomic-config.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/metatomic
)

if (NOT nlohmann_json_FOUND)
# nlohmann_json was fetched and vendored by us: install its headers (used
# by metatomic's own public headers), but remove the CMake package config
# and pkg-config files it installs, since we don't want to advertise a
# system-wide nlohmann_json package to external users.
install(CODE "
file(REMOVE_RECURSE \"\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/cmake/nlohmann_json\")
file(REMOVE \"\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/pkgconfig/nlohmann_json.pc\")
")
endif()
Comment on lines +465 to +474

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the back and forth here, I did not realized we were using the cmake files from our own metatomic-config.cmake …

Maybe the best solution here would be to install these to a different directory, i.e. to CMAKE_INSTALL_PREFIX/lib/metatomic/external instead of CMAKE_INSTALL_PREFIX? This way we can find the headers with normal cmake configuration, and also hide them from most users by default.

@RMeli what do you think here?

16 changes: 12 additions & 4 deletions metatomic-core/cmake/metatomic-config.in.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,16 @@ enable_language(CXX)
set(REQUIRED_METATENSOR_VERSION @REQUIRED_METATENSOR_VERSION@)
find_package(metatensor ${REQUIRED_METATENSOR_VERSION} CONFIG REQUIRED)

# Find nlohmann_json dependency
find_dependency(nlohmann_json 3.11.0)
# nlohmann_json is either vendored by us (its headers are installed alongside
# metatomic's own, in the same include directory, but not its CMake package
# config) or was found as a system package when building metatomic; only look
# for the system package in the latter case.
if (@nlohmann_json_FOUND@)
find_dependency(nlohmann_json 3.11.0)
set(METATOMIC_NLOHMANN_JSON_LIBRARY "nlohmann_json::nlohmann_json")
else()
set(METATOMIC_NLOHMANN_JSON_LIBRARY "")
endif()

get_filename_component(METATOMIC_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/@PACKAGE_RELATIVE_PATH@" ABSOLUTE)

Expand Down Expand Up @@ -49,7 +57,7 @@ if (@METATOMIC_INSTALL_BOTH_STATIC_SHARED@ OR @BUILD_SHARED_LIBS@)
)

target_compile_features(metatomic::shared INTERFACE cxx_std_17)
target_link_libraries(metatomic::shared INTERFACE metatensor nlohmann_json::nlohmann_json)
target_link_libraries(metatomic::shared INTERFACE metatensor ${METATOMIC_NLOHMANN_JSON_LIBRARY})

if (WIN32)
if (NOT EXISTS ${METATOMIC_IMPLIB_LOCATION})
Expand Down Expand Up @@ -80,7 +88,7 @@ if (@METATOMIC_INSTALL_BOTH_STATIC_SHARED@ OR NOT @BUILD_SHARED_LIBS@)
target_compile_features(metatomic::static INTERFACE cxx_std_17)

target_link_libraries(metatomic::static INTERFACE metatensor)
target_link_libraries(metatomic::static INTERFACE nlohmann_json::nlohmann_json)
target_link_libraries(metatomic::static INTERFACE ${METATOMIC_NLOHMANN_JSON_LIBRARY})

if(APPLE)
target_link_libraries(metatomic::static INTERFACE
Expand Down
3 changes: 3 additions & 0 deletions metatomic-core/cmake/nlohmann_json.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ else()
)

set(JSON_BuildTests OFF CACHE INTERNAL "")
# We need nlohmann_json's headers to be installed alongside metatomic's own
# (they are used in our public headers), but not its own CMake package
# config / pkg-config files, which we strip after install below.
set(JSON_Install ON CACHE INTERNAL "")

FetchContent_MakeAvailable(nlohmann_json)
Expand Down
7 changes: 5 additions & 2 deletions python/metatomic_ase/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,15 @@ def git_version_info():
f"stdout: {output.stdout}\n"
f"stderr: {output.stderr}\n"
)
elif output.stderr:
if output.stderr:
print(output.stderr, file=sys.stderr)

lines = output.stdout.splitlines()
if len(lines) < 2:
# the script gave up early (cf. `warn_and_exit`)
n_commits = 0
git_hash = ""
else:
lines = output.stdout.splitlines()
n_commits = int(lines[0].strip())
git_hash = lines[1].strip()

Expand Down
62 changes: 62 additions & 0 deletions python/metatomic_core/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# This file allow the python module in metatomic-core to either use an
# externally-provided version of the shared metatomic library; or to build the
# code from source and bundle the shared library inside the wheel.
#
# The first case is used when distributing the code in conda (since we have a
# separate libmetatomic package), the second one is used everywhere else (for
# local development builds and for the PyPI distribution).

cmake_minimum_required(VERSION 3.22)
project(metatomic-python NONE)

option(METATOMIC_CORE_PYTHON_USE_EXTERNAL_LIB "Force the usage of an external version of metatomic-core" OFF)
set(METATOMIC_CORE_SOURCE_DIR "" CACHE PATH "Path to the sources of metatomic-core")

file(REMOVE ${CMAKE_INSTALL_PREFIX}/_external.py)

set(REQUIRED_METATOMIC_VERSION "0.1.0")
if(${METATOMIC_CORE_PYTHON_USE_EXTERNAL_LIB})
# when building a source checkout, update version to include git information
# this will not apply when building a sdist
if (EXISTS ${CMAKE_SOURCE_DIR}/../../metatomic-core/cmake/dev-versions.cmake)
include(${CMAKE_SOURCE_DIR}/../../metatomic-core/cmake/dev-versions.cmake)
create_development_version("${REQUIRED_METATOMIC_VERSION}" REQUIRED_METATOMIC_VERSION "metatomic-core-v")
# strip any -dev/-rc suffix on the version since find_package does not support it
string(REGEX REPLACE "([0-9]*)\\.([0-9]*)\\.([0-9]*).*" "\\1.\\2.\\3" REQUIRED_METATOMIC_VERSION ${REQUIRED_METATOMIC_VERSION})
endif()

find_package(metatomic ${REQUIRED_METATOMIC_VERSION} REQUIRED)

get_target_property(METATOMIC_LOCATION metatomic::shared LOCATION)
message(STATUS "Using external metatomic-core v${metatomic_VERSION} at ${METATOMIC_LOCATION}")

# Get the prefix to use as cmake_prefix_path when trying to load this
# version of the library again
get_filename_component(METATOMIC_PREFIX "${METATOMIC_LOCATION}" DIRECTORY)
get_filename_component(METATOMIC_PREFIX "${METATOMIC_PREFIX}" DIRECTORY)

file(WRITE ${CMAKE_INSTALL_PREFIX}/_external.py
"EXTERNAL_METATOMIC_PATH = \"${METATOMIC_LOCATION}\"\n\n"
)
file(APPEND ${CMAKE_INSTALL_PREFIX}/_external.py
"EXTERNAL_METATOMIC_PREFIX = \"${METATOMIC_PREFIX}\"\n"
)

install(CODE "message(STATUS \"nothing to install\")")
else()
if ("${METATOMIC_CORE_SOURCE_DIR}" STREQUAL "")
message(FATAL_ERROR
"Missing METATOMIC_CORE_SOURCE_DIR, please specify where to \
find the source code for metatomic-core"
)
endif()

message(STATUS "Using internal metatomic-core from ${METATOMIC_CORE_SOURCE_DIR}")

set(BUILD_SHARED_LIBS ON)
set(METATOMIC_INSTALL_BOTH_STATIC_SHARED OFF)
# strip dynamic library for smaller wheels to download/install
set(EXTRA_RUST_FLAGS "-Cstrip=symbols")

add_subdirectory("${METATOMIC_CORE_SOURCE_DIR}" metatomic-core)
endif()
2 changes: 2 additions & 0 deletions python/metatomic_core/MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ include AUTHORS
include LICENSE

include git_version_info

include metatomic-core-cxx-*.tar.gz
Loading
Loading