diff --git a/.envrc b/.envrc new file mode 100644 index 000000000..3550a30f2 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9db15845c..719d4fde9 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -6,93 +6,61 @@ on: - push - pull_request jobs: - build-project: + nix-build: name: ${{ matrix.os }}-${{ github.workflow }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - os: [ubuntu-22.04, ubuntu-24.04, macos-15, windows-2022] - env: - # Indicates the location of the vcpkg as a Git submodule of the project repository. - # Not using "VCPKG_ROOT" because a variable with the same name is defined in the VS's - # Developer Command Prompt environment in VS 2022 17.6, which would override this one - # if it had the same name. - _VCPKG_: ${{ github.workspace }}/vcpkg - # Tells vcpkg where binary packages are stored. - VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg/bincache - # Let's use GitHub Action cache as storage for the vcpkg Binary Caching feature. - VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" + os: [ubuntu-22.04, ubuntu-24.04] #windows-2022, macos-15 steps: - - uses: actions/github-script@v7 - with: - script: | - core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); - core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); - uses: actions/checkout@v4 with: - submodules: true + submodules: recursive - - name: "Create directory '${{ env.VCPKG_DEFAULT_BINARY_CACHE }}'" - run: mkdir -p $VCPKG_DEFAULT_BINARY_CACHE - shell: bash + - name: Install Nix + uses: cachix/install-nix-action@v31 + with: + nix_path: nixpkgs=channel:nixos-24.11 + extra_nix_config: | + experimental-features = nix-command flakes + allow-import-from-derivation = true + sandbox = false - # Setup the build machine with the most recent versions of CMake and Ninja. Both are cached if not already: on subsequent runs both will be quickly restored from GitHub cache service. - - uses: lukka/get-cmake@latest + - name: Build the nix package + run: nix-build + + hand-build: + name: ${{ matrix.os }}-${{ github.workflow }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-22.04, ubuntu-24.04] #windows-2022, macos-15 + steps: + - name: Install Nix + uses: cachix/install-nix-action@v31 + with: + nix_path: nixpkgs=channel:nixos-24.11 + extra_nix_config: | + experimental-features = nix-command flakes + allow-import-from-derivation = true + sandbox = false - # Restore vcpkg from the GitHub Action cache service. Note that packages are restored by vcpkg's binary caching - # when it is being run afterwards by CMake. - - name: Restore vcpkg - uses: actions/cache@v4 + - uses: actions/checkout@v4 with: - # The first path is the location of vcpkg: it contains the vcpkg executable and data files, as long as the - # built package archives (aka binary cache) which are located by VCPKG_DEFAULT_BINARY_CACHE env var. - # The other paths starting with '!' are exclusions: they contain termporary files generated during the build of the installed packages. - path: | - ${{ env._VCPKG_ }} - !${{ env._VCPKG_ }}/buildtrees - !${{ env._VCPKG_ }}/packages - !${{ env._VCPKG_ }}/downloads - !${{ env._VCPKG_ }}/installed - # The key is composed in a way that it gets properly invalidated whenever a different version of vcpkg is being used. - key: | - ${{ hashFiles( '.git/modules/vcpkg/HEAD' )}} + submodules: recursive - # On Windows runners, let's ensure to have the Developer Command Prompt environment setup correctly. - # As used here the Developer Command Prompt created is targeting x64 and using the default the Windows SDK. - - uses: ilammy/msvc-dev-cmd@v1 + - name: Configure the project + run: nix-shell ${{github.workspace}} --run "cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=Release" - # Run CMake to generate Ninja project files. - - name: Configure the build system - run: | - cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=Release + - name: Build the project + run: nix-shell ${{github.workspace}} --run "cmake --build ${{github.workspace}}/build -j4 --config Release" - name: Check code formatting - if: runner.os == 'Linux' - run: | - cmake --build ${{github.workspace}}/build -j4 -t check-src-format --config Release - - # Build (Release configuration only) the whole project with Ninja (which is spawn by CMake). - - name: Build (Release configuration) - run: | - cmake --build ${{github.workspace}}/build -j4 --config Release + run: nix-shell ${{github.workspace}} --run "cmake --build ${{github.workspace}}/build -j4 -t check-src-format --config Release" # Test the whole project with CTest - name: Test (Release configuration) working-directory: ${{github.workspace}}/build - run: | - ctest -j 4 --output-on-failure -C Release - - - name: Package the project (python packages include more) - run: | - cmake --build ${{github.workspace}}/build -j4 -t package --config Release - - - name: Upload packages as artifacts - uses: actions/upload-artifact@v4 - with: - name: dynamo-${{ matrix.os }} - path: | - ${{ github.workspace }}/build/*.deb - ${{ github.workspace }}/build/*.sh - ${{ github.workspace }}/build/*.tar.gz - ${{ github.workspace }}/build/*.exe + run: nix-shell ${{github.workspace}} --run "ctest -j 4 --output-on-failure -C Release" \ No newline at end of file diff --git a/.github/workflows/python_wheels.yaml b/.github/workflows/python_wheels.yaml index 9dd96f492..1ac1591ad 100644 --- a/.github/workflows/python_wheels.yaml +++ b/.github/workflows/python_wheels.yaml @@ -11,31 +11,28 @@ jobs: matrix: os: [ ubuntu-latest, - #ubuntu-24.04-arm, - windows-latest, - #macos-13, + ubuntu-24.04-arm, + macos-13, macos-latest, + # windows-latest, # Needs a way to install the build dependencies (or VCPKG) ] steps: - uses: actions/checkout@v4 with: - submodules: true + submodules: recursive - uses: actions/setup-python@v5 with: python-version: 3.11 - name: Install cibuildwheel - run: python -m pip install cibuildwheel==2.23.2 - + run: python -m pip install cibuildwheel==2.23.3 + - name: Build wheels run: python -m cibuildwheel --output-dir wheelhouse - env: - CIBW_ARCHS_LINUX: auto64 # Seems 32 bit vcpkg dependencies are missing, so force 64 bit on linux - CIBW_SKIP: "*-musllinux_* pp*" # Skip musllinux builds for now as they fail, and skip pypy builds as they'll be disabled in cibuildwheel 3 anyway - + - uses: actions/upload-artifact@v4 with: name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }} - path: ./wheelhouse/*.whl + path: ./wheelhouse/*.whl \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5f6d4b286..9f98cc17f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ __pycache__ Testing/Temporary/CTestCostData.txt .eggs -wheelhouse \ No newline at end of file +wheelhouse +vcpkg_installed \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 499547f6f..1d2c96bf4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "extern/stator"] path = extern/stator url = https://github.com/toastedcrumpets/stator.git -[submodule "vcpkg"] - path = extern/vcpkg - url = https://github.com/microsoft/vcpkg.git diff --git a/CMakeLists.txt b/CMakeLists.txt index d8f491c16..eacc8ab17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,15 @@ cmake_minimum_required(VERSION 3.28) -if(POLICY CMP0167) # Must be before project otherwise VCPKG hooks trigger the warning - cmake_policy(SET CMP0167 NEW) # Use the new boost configuration +# We want to set this to new, but the python wheels need boost 1.70 minimum before this can happen +if(POLICY CMP0167) + cmake_policy(SET CMP0167 OLD) endif() -set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/extern/vcpkg/scripts/buildsystems/vcpkg.cmake) +# Disabled VCPKG as we move to nix +if(DEFINED ENV{DYNAMO_VCPKG_ROOT}) + message(STATUS "DYNAMO_VCPKG_ROOT is set to $ENV{DYNAMO_VCPKG_ROOT}, enabling VCPKG") + set(CMAKE_TOOLCHAIN_FILE $ENV{DYNAMO_VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake) +endif() project(DynamO) #Project name enable_testing() #Enable build of test executables and 'make test' command @@ -99,7 +104,12 @@ endif() set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_MULTITHREADED ON) set(Boost_USE_STATIC_RUNTIME OFF) -find_package(Boost 1.70.0 REQUIRED system filesystem program_options unit_test_framework) +find_package(Boost 1.66.0 COMPONENTS system filesystem program_options unit_test_framework) +if(NOT Boost_FOUND) + message(WARNING "Static Boost not found, trying shared Boost") + set(Boost_USE_STATIC_LIBS OFF) + find_package(Boost 1.66.0 REQUIRED COMPONENTS system filesystem program_options unit_test_framework) +endif() add_subdirectory(src/magnet) find_package(Eigen3) diff --git a/default.nix b/default.nix new file mode 100644 index 000000000..469c3f9b1 --- /dev/null +++ b/default.nix @@ -0,0 +1,2 @@ +{ pkgs ? import {} }: +pkgs.callPackage ./derivation.nix {} diff --git a/derivation.nix b/derivation.nix new file mode 100644 index 000000000..0f5870721 --- /dev/null +++ b/derivation.nix @@ -0,0 +1,50 @@ +# see https://unix.stackexchange.com/questions/717168/how-to-package-my-software-in-nix-or-write-my-own-package-derivation-for-nixpkgs +# To install `nix-env -u -f default.nix` +# To develop `nix-shell` (will build the shell with dependencies) +# To test build `nix-build` +{ pkgs, python3 }: +python3.pkgs.buildPythonPackage rec { + name = "pydynamo"; + src = ./.; + pyproject = true; + + dontUseCmakeConfigure = true; + + propagatedBuildInputs = with python3.pkgs; [ + scikit-build-core + numpy + alive-progress + uncertainties + pandas + scipy + freud + networkx + pytest + ]; + + nativeBuildInputs = with pkgs; [ + cmake + ninja + git + gcc + pkg-config + clang-tools + wrapGAppsHook3 + ] ++ propagatedBuildInputs; + + buildInputs = with pkgs; [ + # Basic build dependencies + bzip2.dev + boost.dev + eigen + + # Visualiser + libGL.dev + gtkmm3.dev + ffmpeg.dev + freeglut + glew + cairomm.dev + libpng + ]; +} diff --git a/extern/vcpkg b/extern/vcpkg deleted file mode 160000 index b02e341c9..000000000 --- a/extern/vcpkg +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b02e341c927f16d991edbd915d8ea43eac52096c diff --git a/pyproject.toml b/pyproject.toml index df39c0331..51e3f380a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,9 @@ [build-system] -requires = ["scikit-build-core>=0.10", "numpy", "pytest"] +requires = [ + "scikit-build-core>=0.10", + "numpy", + "pytest", +] build-backend = "scikit_build_core.build" @@ -16,15 +20,13 @@ classifiers = [ "Development Status :: 4 - Beta", "License :: OSI Approved :: GPL License", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", ] -dependencies = ["alive-progress", "pandas", "scipy", "uncertainties", "freud", "networkx"] +dependencies = ["alive-progress", "pandas", "scipy", "uncertainties", "networkx"] [tool.scikit-build] cmake.build-type = "Release" @@ -47,7 +49,36 @@ minimum-version = "build-system.requires" #testpaths = ["tests"] # # -#[tool.cibuildwheel] + +[tool.cibuildwheel] +# Skip the pypy builds (they're deprecated and use an old toolchain) +# Skip 32bit builds due to issues with build tools +# Dropping some older python versions too +skip = "pp* *i686 *win32" +# More modern install/build with uv +# Doesn't work on macos github actions! Need to install it using brew? #build-frontend = "build[uv]" -#test-command = "pytest {project}/tests" -#test-extras = ["test"] + +# For future reference on a windows build +# To use VCPKG, add the environment variable +#environment = {DYNAMO_VCPKG_ROOT="/opt/vcpkg/"} +# And add this to before-all to download vcpkg +#&& git clone https://github.com/microsoft/vcpkg.git /opt/vcpkg && /opt/vcpkg/bootstrap-vcpkg.sh -disableMetrics && /opt/vcpkg/vcpkg install + + +[tool.cibuildwheel.linux] +# We switch to the 2025 default images now +manylinux-x86_64-image = "manylinux_2_28" +manylinux-aarch64-image = "manylinux_2_28" +musllinux-x86_64-image = "musllinux_1_2" +musllinux-aarch64-image = "musllinux_1_2" +before-all = "yum install -y zip unzip make boost-devel boost-static eigen3-devel bzip2-devel" + +[[tool.cibuildwheel.overrides]] +# musllinux uses apk instead of yum +select = "*-musllinux*" +#install ninja-is-really-ninja, as the ninja package is a link to samurai which is incompatible with vcpkg it seems +before-all = "apk add zip unzip ninja-is-really-ninja boost-dev boost-static eigen-dev bzip2-dev" + +[tool.cibuildwheel.macos] +before-all = "brew install cmake eigen boost" \ No newline at end of file diff --git a/src/dynamo/programs/dynahist_rw.cpp b/src/dynamo/programs/dynahist_rw.cpp index 96ed251f4..c5089857f 100644 --- a/src/dynamo/programs/dynahist_rw.cpp +++ b/src/dynamo/programs/dynahist_rw.cpp @@ -520,7 +520,7 @@ int main(int argc, char *argv[]) { << "under certain conditions. See the licence you obtained with\n" << "the code\n"; -#if !defined(__APPLE__) && !defined(_WIN32) +#ifdef __GLIBC__ // This is so the program crashes out when floating point errors occur feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW); #endif diff --git a/src/magnet/CMakeLists.txt b/src/magnet/CMakeLists.txt index 98cf98fcc..9fecb218d 100644 --- a/src/magnet/CMakeLists.txt +++ b/src/magnet/CMakeLists.txt @@ -1,6 +1,6 @@ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DMAGNET_DEBUG") -find_package(Boost 1.70.0 REQUIRED) +find_package(Boost 1.66.0 REQUIRED) add_library(magnet INTERFACE) target_include_directories(magnet INTERFACE diff --git a/src/magnet/magnet/GL/context.hpp b/src/magnet/magnet/GL/context.hpp index 12b12d826..5d4241d0e 100644 --- a/src/magnet/magnet/GL/context.hpp +++ b/src/magnet/magnet/GL/context.hpp @@ -24,6 +24,9 @@ #ifdef _WIN32 #include typedef HGLRC ContextKey; +#elif __APPLE__ +#include +typedef CGLContextObj ContextKey; #else #include typedef GLXContext ContextKey; @@ -74,6 +77,8 @@ class Context { inline static ContextKey getCurrentContextKey() { #ifdef _WIN32 ContextKey key = wglGetCurrentContext(); +#elif __APPLE__ + ContextKey key = CGLGetCurrentContext(); #else ContextKey key = glXGetCurrentContext(); #endif