Skip to content

Conversation

@ahnaf-tahmid-chowdhury
Copy link

@ahnaf-tahmid-chowdhury ahnaf-tahmid-chowdhury commented May 9, 2025

Description

This PR introduces a comprehensive overhaul of the NJOY CMake build system and integrates Python packaging using scikit-build-core. The primary goals are to modernize the build process, simplify configuration, enable distribution via PyPI, and improve maintainability.

Key Changes

  1. CMake Modernization & Simplification:

    • Standard Modules: Adopted standard CMake modules like GNUInstallDirs (for consistent installation paths like CMAKE_INSTALL_BINDIR, CMAKE_INSTALL_LIBDIR, CMAKE_INSTALL_INCLUDEDIR) and FeatureSummary (for clearer configuration output).
    • Library Type: Replaced custom static, static_libraries, static_njoy options with the standard BUILD_SHARED_LIBS CMake option to control whether NJOY is built as a shared or static library.
    • Link Time Optimization (LTO/IPO): Uses the standard CMAKE_INTERPROCEDURAL_OPTIMIZATION property, controlled by the new NJOY_ENABLE_LTO option (default ON).
    • Option Namespacing: All NJOY-specific CMake options are now prefixed with NJOY_ (e.g., NJOY_STRICT, NJOY_COVERAGE) for clarity and to avoid conflicts.
    • Compiler Flags Management:
      • Consolidated compiler-specific flags (e.g., for GNU, and added placeholders for Intel).
      • Introduced a CMake function njoy_apply_build_options to encapsulate the logic for applying various compile and link options based on build type, compiler, and user-selected features. This greatly reduces redundancy.
      • Removed verbose platform-specific flag duplication (e.g., njoy_GNU_Linux_..., njoy_GNU_Windows_... are now generally NJOY_GNU_...).
    • RPATH Handling:
      • Modernized RPATH handling using CMAKE_INSTALL_RPATH, CMAKE_INSTALL_RPATH_USE_LINK_PATH.
      • Specific RPATH settings for SKBUILD environments to ensure the Python package can find its bundled libraries (@loader_path or $ORIGIN).
    • Subproject Detection: Simplified logic for NJOY_IS_SUBPROJECT.
    • Fortran Modules: Fortran modules are installed to ${CMAKE_INSTALL_INCLUDEDIR}/${CMAKE_PROJECT_NAME_LOWER} (e.g., include/njoy).
    • Removed Redundancy:
      • Removed manual find_package(Python3) as Python environment is managed by the build frontend (e.g., pip).
      • Removed manual Git version queries; versioning is now handled by setuptools-scm.
  2. Python Packaging with scikit-build-core:

    • pyproject.toml: Added to define the build system (scikit-build-core, setuptools-scm) and project metadata (name, version, author, license, etc.).
    • scikit-build-core Integration: The CMake build is now driven by scikit-build-core when building the Python package.
    • Dynamic Versioning: Project version is dynamically determined from Git tags using setuptools-scm.
    • Wheel Installation Directory: Configured wheel.install-dir = "njoy" so that CMake-installed files go into an njoy subdirectory within the Python site-packages.
  3. Python Wrapper and Helper Modules:

    • cmake/GenerateScript.cmake:
      • New CMake module that defines generate_and_install_python_script.
      • This function creates a Python wrapper script for the njoy executable.
      • When installing via pip, this wrapper is placed in the Python environment's script/bin directory, making njoy directly callable from the command line and ensuring it uses the correct bundled executable.
    • njoy/__init__.py & njoy/paths.py (New Python Package Structure):
      • Introduces a basic Python package structure for njoy.
      • paths.py provides functions (get_include_path, get_core_libraries, get_extra_libraries) to locate the installed NJOY headers, libraries, and any libraries vendored by auditwheel/delocate. This allows downstream Python tools or users to easily find these components.
      • Includes a warning if the package is imported from the source directory in non-dev mode.
  4. GitHub Actions for Wheels (.github/workflows/pypi.yml):

    • New workflow to build binary wheels for Linux (manylinux_x86_64), macOS (x86_64, arm64) using cibuildwheel.
    • Uses gfortran-14 on macOS.
    • Wheels are uploaded as artifacts on every push/PR (for testing) and published to PyPI automatically upon creating a GitHub release.

Benefits

  • Modern & Maintainable Build: The CMake configuration is cleaner, more standard, and easier to understand and extend.
  • Simplified User Experience: Fewer custom options, relying more on CMake standards.
  • PyPI Distribution: NJOY can now be easily distributed as a Python package on PyPI, installable via pip install njoy.
  • Improved Portability & Reproducibility: cibuildwheel helps create widely compatible binary wheels.
  • Discoverability for Python Users: The njoy.paths module allows Python applications to easily locate and use NJOY's compiled components.
  • Automated Releases: Streamlined release process with automated wheel building and PyPI publishing.

How to Test

  1. Build and Install Locally (Python Package):
    # From the project root
    pip install .
    # or for an editable install
    # pip install -e .
  2. Verify Installation:
    • Check that the njoy executable is available in your Python environment's bin (or Scripts) directory and is runnable.
    • In a Python interpreter:
      import njoy
      import njoy.paths
      print(njoy.paths.include_path)
      print(njoy.lib_path)
  3. Traditional CMake Build (if not building the Python package):
    cmake -S . -B build -DCMAKE_INSTALL_PREFIX=./install
    cmake --build build
    cmake --install build
    Verify installed files in ./install.

Note: The original functionality regarding subproject builds (NJOY_IS_SUBPROJECT) and testing (enable_testing(), add_subdirectory(tests)) when not a subproject has been preserved. The NJOY_LINK_EXECUTABLE_STATICALLY option provides a way to attempt static linking of the executable, similar to the old static option's effect on the executable.

@shimwell
Copy link

Keen to see a pip install option for NJOY, looks like this would help with that.

Just wondering if there any interest from the maintainers or anyone else for something like this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants