Skip to content

Commit

Permalink
Merge featomic and featomic-c-api as a single crate
Browse files Browse the repository at this point in the history
This will make it easier to distirbute a single source archive
containing everything. featomic-c-api is now the `c-api` module in
featomic, enabled by the `c-api` cargo feature.
  • Loading branch information
Luthaf committed Nov 25, 2024
1 parent 8d0b9d7 commit e8655a0
Show file tree
Hide file tree
Showing 66 changed files with 259 additions and 249 deletions.
4 changes: 1 addition & 3 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,11 @@ jobs:
echo "CMAKE_CXX_COMPILER_LAUNCHER=sccache" >> $GITHUB_ENV
- name: collect rust and C/C++ coverage
# env:
# FEATOMIC_TEST_WITH_STATIC_LIB: "1"
run: |
cargo tarpaulin --all-features --workspace --engine=llvm --out=xml --output-dir=target/tarpaulin --objects target/debug/libfeatomic.so
# cleanup C/C++ coverage
lcov --directory . --capture --output-file coverage.info
lcov --remove coverage.info '/usr/*' "$(pwd)/featomic-c-api/tests/*" "$(pwd)/featomic-c-api/examples/*" --output-file coverage.info
lcov --remove coverage.info '/usr/*' "$(pwd)/featomic/tests/*" "$(pwd)/featomic/examples/*" --output-file coverage.info
- name: collect Python coverage
run: |
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/rust-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ jobs:
FEATOMIC_TEST_WITH_STATIC_LIB: ${{ matrix.test-static-lib || 0 }}
run: |
cargo test --test "*" --package featomic --target ${{ matrix.rust-target }} ${{ matrix.cargo-build-flags }}
cargo test --test "*" --package featomic-c-api --target ${{ matrix.rust-target }} ${{ matrix.cargo-build-flags }}
# second set of jobs checking that (non-test) code still compiles/run as expected
prevent-bitrot:
Expand Down
3 changes: 1 addition & 2 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,7 @@ Github CI workflows.
You can also run only a subset of tests with one of these commands:

- ``cargo test`` runs everything
- ``cargo test --package=featomic`` to run the calculators tests;
- ``cargo test --package=featomic-c-api`` to run the C/C++ tests only;
- ``cargo test --package=featomic`` to run the main tests;

- ``cargo test --test=run-cxx-tests`` will run the unit tests for the C/C++
API. If `valgrind`_ is installed, it will be used to check for memory
Expand Down
3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ resolver = "2"

members = [
"featomic",
"featomic-c-api",
"python",
"featomic-torch",
"python",
"docs/featomic-json-schema",
]
4 changes: 0 additions & 4 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ global-exclude .DS_Store
prune docs

recursive-include featomic *
recursive-include featomic-c-api *
recursive-include docs/featomic-json-schema *

# include the minimal crates from the Cargo workspace
Expand All @@ -25,7 +24,4 @@ prune featomic/tests
prune featomic/benches/data
prune featomic/examples/data

prune featomic-c-api/tests
prune featomic-c-api/examples

exclude tox.ini
2 changes: 1 addition & 1 deletion docs/Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -944,7 +944,7 @@ WARN_LOGFILE =
# Note: If this tag is empty the current directory is searched.

INPUT = \
../featomic-c-api/include/ \
../featomic/include/ \
../featomic-torch/include/featomic \
../featomic-torch/include/featomic/torch

Expand Down
2 changes: 1 addition & 1 deletion docs/src/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def extract_json_schema():

def build_doxygen_docs():
# we need to run a build to make sure the header is up to date
subprocess.run(["cargo", "build", "--package", "featomic-c-api"])
subprocess.run(["cargo", "build", "--package", "featomic"])
subprocess.run(["doxygen", "Doxyfile"], cwd=os.path.join(ROOT, "docs"))


Expand Down
8 changes: 4 additions & 4 deletions docs/src/devdoc/explanations/architecture.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ The code is organized in three main products, each in a separate directory:

- ``featomic/`` contains the main Rust implementation of all calculators, and
the corresponding unit and regression tests;
- ``featomic-c-api/`` is a Rust crate containing the implementation of the
featomic C API;
- ``python/`` contains the Python interface to featomic, and the corresponding
tests
- ``featomic-torch/`` contains the TorchScript bindings to featomic, written in
C++;
- ``python/`` contains the Python interface to featomic and featomic-torch, and
the corresponding tests

Finally, ``docs/`` contains the documentation for everything related to
featomic.
Expand Down
46 changes: 23 additions & 23 deletions docs/src/devdoc/explanations/interfaces.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,32 @@ Python and C interface
How is the C interface exported
-------------------------------

Featomic exports a C interface, defined in ``featomic-c-api``. This C
interface is created directly in Rust, without involving any C code.
Featomic exports a C interface, created directly in Rust without involving any C
code.

This is done by marking functions as ``#[no_mangle] extern pub fn <XXX>`` in
``featomic-c-api``, and only using types safe to send to C (mostly pointers and
basic values such as floats or integers). Of these markers, ``pub`` ensures that
the function is exported from the library (it should appear as a ``T`` symbol in
``nm`` output); ``extern`` forces the function to use the C calling convention
(a calling convention describes where in memory/CPU registers the caller should
put data that the function expects); and ``#[no_mangle]`` tells the compiler to
export the function under this exact name, instead of using a mangled named
containing the module path and functions parameters.
``featomic/src/c-api/*.rs``, and only using types safe to send to C (mostly
pointers and basic values such as floats or integers). Of these markers, ``pub``
ensures that the function is exported from the library (it should appear as a
``T`` symbol in ``nm`` output); ``extern`` forces the function to use the C
calling convention (a calling convention describes where in memory/CPU registers
the caller should put data that the function expects); and ``#[no_mangle]``
tells the compiler to export the function under this exact name, instead of
using a mangled named containing the module path and functions parameters.

Additionally, the C interfaces expose C-compatible structs declared with
``#[repr(C)] pub struct <XXX> {}``; where ``#[repr(C)]`` ensures that the
compiler lays out the fields in the exact order they are declared, without
re-organizing them.

``featomic-c-api`` is then compiled to a shared library (``libfeatomic.so`` /
``libfeatomic.dylib`` / ``libfeatomic.dll``), which can be used by any
language able to call C code to call the exported functions without ever
realizing it is speaking with Rust code.
``featomic`` is then compiled to a shared library (``libfeatomic.so`` /
``libfeatomic.dylib`` / ``libfeatomic.dll``), which can be used by any language
able to call C code to call the exported functions without ever realizing it is
speaking with Rust code.

The list of exported functions, together with the types of the function's
parameters, and struct definitions are extracted from the rust source code using
`cbindgen`_, which creates the ``featomic-c-api/featomic.h`` header file
`cbindgen`_, which creates the ``featomic/include/featomic.h`` header file
containing all of this information in a C compatible syntax. All of the
documentation is also reproduced using `doxygen`_ syntax.

Expand All @@ -41,13 +41,13 @@ The Python interface used the `ctypes`_ module to call exported symbols from the
shared library. For the Python code to be able to call exported function safely,
it needs to know a few things. In particular, it needs to know the name of the
function, the number and types of parameters and the return type of the
function. All this information is available in ``featomic-c-api/featomic.h``,
function. All this information is available in ``featomic/include/featomic.h``,
but not in a way that is easily accessible from `ctypes`_. There is a script in
``python/scripts/generate-declaration.py`` which reads the header file using
`pycparser`_, and creates the `python/featomic/_featomic.py` file which
`pycparser`_, and creates the `python/featomic/_c_api.py` file which
declares all functions in the way expected by the `ctypes`_ module. You will
need to manually re-run this script if you modify any of the exported functions
in `featomic-c-api`.
in `featomic/src/c-api`.

The schematic below describes all the relationships between the components
involved in creating the Python interface.
Expand All @@ -57,11 +57,11 @@ involved in creating the Python interface.
:align: center

Schematic representation of all components in the Python interface. The rust
crate ``featomic-c-api`` is compiled to a shared library
(``libfeatomic.so`` on Linux), and `cbindgen`_ is used to generate the
corresponding header. This header is then read with `pycparser`_ to create
ctypes' compatible declarations, used to ensure that Python and rust agree
fully on the parameters types, allowing Python to directly call Rust code.
crate ``featomic`` is compiled to a shared library (``libfeatomic.so`` on
Linux), and `cbindgen`_ is used to generate the corresponding header. This
header is then read with `pycparser`_ to create ctypes' compatible
declarations, used to ensure that Python and rust agree fully on the
parameters types, allowing Python to directly call Rust code.

.. _ctypes: https://docs.python.org/3/library/ctypes.html
.. _pycparser: https://github.com/eliben/pycparser
Expand Down
4 changes: 2 additions & 2 deletions docs/src/devdoc/how-to/profiling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ You can obtain a dataset for profiling from our :download:`website <../../../sta

.. group-tab:: C++

.. literalinclude:: ../../../../featomic-c-api/examples/profiling.cpp
.. literalinclude:: ../../../../featomic/examples/profiling.cpp
:language: c++

.. group-tab:: C

.. literalinclude:: ../../../../featomic-c-api/examples/profiling.c
.. literalinclude:: ../../../../featomic/examples/profiling.c
:language: c
2 changes: 1 addition & 1 deletion docs/src/get-started/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ well as CMake files that can be used with ``find_package(featomic)``.
.. code-block:: bash
git clone https://github.com/metatensor/featomic
cd featomic/featomic-c-api
cd featomic/featomic
mkdir build
cd build
cmake <CMAKE_OPTIONS_HERE> ..
Expand Down
4 changes: 2 additions & 2 deletions docs/src/how-to/computing-soap.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ You can obtain a testing dataset from our :download:`website <../../static/datas

.. group-tab:: C++

.. literalinclude:: ../../../featomic-c-api/examples/compute-soap.cpp
.. literalinclude:: ../../../featomic/examples/compute-soap.cpp
:language: c++

.. group-tab:: C

.. literalinclude:: ../../../featomic-c-api/examples/compute-soap.c
.. literalinclude:: ../../../featomic/examples/compute-soap.c
:language: c
10 changes: 5 additions & 5 deletions docs/src/references/api/c/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ functions (in particular, this includes Python, Fortran with ``iso_c_env``, C++,
and most languages used nowadays). Convenient wrappers of the C API are also
provided for :ref:`Python <python-api-reference>` users.

The C API is implemented in Rust, in the ``featomic-c-api`` crate. You can use
these functions in your own code by :ref:`installing the corresponding shared
library and header <install-c-lib>`, and then including ``featomic.h`` and
linking with ``-lfeatomic``. Alternatively, we provide a cmake package config
file, allowing you to do use featomic like this (after installation):
You can use these functions in your own code by :ref:`installing the
corresponding shared library and header <install-c-lib>`, and then including
``featomic.h`` and linking with ``-lfeatomic``. Alternatively, we provide a
cmake package config file, allowing you to do use featomic like this (after
installation):

.. code-block:: cmake
Expand Down
35 changes: 0 additions & 35 deletions featomic-c-api/Cargo.toml

This file was deleted.

45 changes: 0 additions & 45 deletions featomic-c-api/build.rs

This file was deleted.

4 changes: 2 additions & 2 deletions featomic-torch/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# re-use catch from featomic-c-api C++ tests
add_subdirectory(../../featomic-c-api/tests/catch catch)
# re-use catch from featomic C++ tests
add_subdirectory(../../featomic/tests/utils/catch catch)

# make sure we compile catch with the flags that torch requires. In particular,
# torch sets -D_GLIBCXX_USE_CXX11_ABI=0 on Linux, which changes some of the
Expand Down
4 changes: 2 additions & 2 deletions featomic-torch/tests/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use std::path::PathBuf;
use std::process::Command;

#[path = "../../../featomic-c-api/tests/utils/mod.rs"]
#[path = "../../../featomic/tests/utils/mod.rs"]
mod core_utils;

pub use core_utils::cmake_build;
Expand Down Expand Up @@ -114,7 +114,7 @@ pub fn setup_pytorch(build_dir: PathBuf) -> PathBuf {
/// Build featomic in `build_dir`, and return the installation prefix
pub fn setup_featomic(build_dir: PathBuf) -> PathBuf {
let mut featomic_source_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
featomic_source_dir.extend(["..", "featomic-c-api"]);
featomic_source_dir.extend(["..", "featomic"]);

// configure cmake for featomic
let mut cmake_config = cmake_config(&featomic_source_dir, &build_dir);
Expand Down
16 changes: 15 additions & 1 deletion featomic-c-api/CMakeLists.txt → featomic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ endif()

set(CARGO_TARGET_DIR ${CMAKE_CURRENT_BINARY_DIR}/target)
set(CARGO_BUILD_ARG "${CARGO_BUILD_ARG};--target-dir=${CARGO_TARGET_DIR}")
set(CARGO_BUILD_ARG "${CARGO_BUILD_ARG};--features=c-api")

# Handle cross compilation with RUST_BUILD_TARGET
if ("${RUST_BUILD_TARGET}" STREQUAL "")
Expand Down Expand Up @@ -303,13 +304,26 @@ if (NOT "$ENV{RUSTC_WRAPPER}" STREQUAL "")
list(APPEND CARGO_ENV "RUSTC_WRAPPER=$ENV{RUSTC_WRAPPER}")
endif()

if (FEATOMIC_INSTALL_BOTH_STATIC_SHARED)
set(CARGO_BUILD_ARG "${CARGO_BUILD_ARG};--crate-type=cdylib;--crate-type=staticlib")
set(FILES_CREATED_BY_CARGO "${FEATOMIC_SHARED_LIB_NAME} and ${FEATOMIC_STATIC_LIB_NAME}")
else()
if (BUILD_SHARED_LIBS)
set(CARGO_BUILD_ARG "${CARGO_BUILD_ARG};--crate-type=cdylib")
set(FILES_CREATED_BY_CARGO "${FEATOMIC_SHARED_LIB_NAME}")
else()
set(CARGO_BUILD_ARG "${CARGO_BUILD_ARG};--crate-type=staticlib")
set(FILES_CREATED_BY_CARGO "${FEATOMIC_STATIC_LIB_NAME}")
endif()
endif()

add_custom_target(cargo-build-featomic ALL
COMMAND
${CMAKE_COMMAND} -E env ${CARGO_ENV}
cargo rustc ${CARGO_BUILD_ARG} -- ${CARGO_RUSTC_ARGS}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
DEPENDS ${ALL_RUST_SOURCES}
COMMENT "Building ${FEATOMIC_SHARED_LIB_NAME} and ${FEATOMIC_STATIC_LIB_NAME} with cargo"
COMMENT "Building ${FILES_CREATED_BY_CARGO} with cargo"
BYPRODUCTS ${FEATOMIC_STATIC_LOCATION} ${FEATOMIC_SHARED_LOCATION} ${FEATOMIC_IMPLIB_LOCATION}
)

Expand Down
Loading

0 comments on commit e8655a0

Please sign in to comment.