diff --git a/.github/workflows/readme_listings.yml b/.github/workflows/readme_listings.yml index 238d1b07..63dedfb7 100644 --- a/.github/workflows/readme_listings.yml +++ b/.github/workflows/readme_listings.yml @@ -97,7 +97,7 @@ jobs: assert: runs-on: ubuntu-latest - needs: [julia, python, matlab, fortran] + needs: [julia, python, matlab, fortran, cpp] steps: - uses: actions/setup-python@v2 - run: pip install numpy @@ -107,6 +107,60 @@ jobs: merge-multiple: true path: readme_output - run : python -c 'import numpy as np; import os; dir="readme_output/"; data=[float(np.loadtxt(dir+file)) for file in os.listdir(dir)]; print("data:", data); similar_as_first = np.array([abs(data[0]-k)/data[0] for k in data[1:]]); print("similar_as_first", similar_as_first); assert((similar_as_first < .5).all())' + + cpp: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, ubuntu-24.04-arm, macos-15, macos-15-intel, windows-latest] + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + + - uses: actions/setup-python@v6 + with: + python-version: "3.12" + + - uses: jwlawson/actions-setup-cmake@v2.2.0 + with: + cmake-version: '3.26.x' + + - if: matrix.os == 'windows-latest' + run: | + echo CMAKE_ARGS="-DCMAKE_MAKE_PROGRAM=D:/a/_temp/msys64/mingw64/bin/ninja.exe" >> $GITHUB_ENV + echo CMAKE_PROGRAM_PATH="D:/a/_temp/msys64/usr/bin" >> $GITHUB_ENV + echo CMAKE_GENERATOR="Ninja" >> $GITHUB_ENV + echo TEMP="D:/a/_temp/" >> $GITHUB_ENV + + - if: matrix.os == 'windows-latest' + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + update: false + install: >- + mingw-w64-x86_64-gcc-fortran + mingw-w64-x86_64-ninja + m4 + + - if: startsWith(matrix.os, 'macos-') + run: | + brew reinstall gcc + + - run: pip install . + - name: build + run: | + cd readme_cpp + mkdir build + cd build + cmake .. + cmake --build . + - name: Execute tests + run: | + cd readme_cpp + cd build + ctest --output-on-failure matlab: runs-on: ubuntu-22.04 diff --git a/.github/workflows/urlcheck.yml b/.github/workflows/urlcheck.yml.off similarity index 100% rename from .github/workflows/urlcheck.yml rename to .github/workflows/urlcheck.yml.off diff --git a/CMakeLists.txt b/CMakeLists.txt index d6282368..50759e3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -293,7 +293,7 @@ function(scoped_sundials_setup_config) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/sundials) execute_process( - COMMAND ${PYTHON_EXECUTABLE} "-c" "import sys; print(''.join([line for line in sys.stdin if line.startswith('set(PACKAGE_VERSION_')]))" + COMMAND ${Python_EXECUTABLE} "-c" "import sys; print(''.join([line for line in sys.stdin if line.startswith('set(PACKAGE_VERSION_')]))" INPUT_FILE ${CMAKE_SOURCE_DIR}/gitmodules/sundials/CMakeLists.txt OUTPUT_FILE ${CMAKE_BINARY_DIR}/sundials/CMakeLists.txt ) @@ -339,7 +339,7 @@ target_include_directories(camplib PRIVATE ) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/include/camp) execute_process( - COMMAND ${PYTHON_EXECUTABLE} "-c" "import sys; print(''.join([line.replace(')','').replace('set(','#define ').replace('PACKAGE_', 'CAMP_') for line in sys.stdin if line.startswith('set(PACKAGE_VERSION')]))" + COMMAND ${Python_EXECUTABLE} "-c" "import sys; print(''.join([line.replace(')','').replace('set(','#define ').replace('PACKAGE_', 'CAMP_') for line in sys.stdin if line.startswith('set(PACKAGE_VERSION')]))" INPUT_FILE ${CMAKE_SOURCE_DIR}/gitmodules/camp/CMakeLists.txt OUTPUT_FILE ${CMAKE_BINARY_DIR}/include/camp/version.h ) @@ -366,7 +366,7 @@ endif() foreach(file ${hdf5_GENERATED_HEADERS}) execute_process( - COMMAND ${PYTHON_EXECUTABLE} "-c" "import re;open(1,'wb').write(re.sub(b'\\r',b'',open(0,'rb').read()))" + COMMAND ${Python_EXECUTABLE} "-c" "import re;open(1,'wb').write(re.sub(b'\\r',b'',open(0,'rb').read()))" INPUT_FILE ${CMAKE_SOURCE_DIR}/${file} OUTPUT_FILE ${CMAKE_BINARY_DIR}/${file} ) @@ -391,7 +391,7 @@ string(CONCAT cmd ) include(CheckFunctionExists) execute_process( - COMMAND ${PYTHON_EXECUTABLE} "-c" "${cmd}" + COMMAND ${Python_EXECUTABLE} "-c" "${cmd}" INPUT_FILE ${CMAKE_SOURCE_DIR}/gitmodules/netcdf-c/CMakeLists.txt OUTPUT_FILE ${CMAKE_BINARY_DIR}/netcdf/CMakeLists.txt ) @@ -516,7 +516,7 @@ string(CONCAT include(CheckFunctionExists) foreach(file aero_data;gas_data;output) execute_process( - COMMAND ${PYTHON_EXECUTABLE} "-c" "${cmd}" + COMMAND ${Python_EXECUTABLE} "-c" "${cmd}" INPUT_FILE ${CMAKE_SOURCE_DIR}/gitmodules/partmc/src/${file}.F90 OUTPUT_FILE ${CMAKE_BINARY_DIR}/include/${file}_parameters.hpp ) @@ -546,7 +546,13 @@ endif() find_package(nanobind CONFIG REQUIRED) add_subdirectory(gitmodules/nanobind) -nanobind_add_module(_PyPartMC STABLE_ABI ${PyPartMC_sources}) +if(APPLE) + set(PYPARTMC_MODULE_TYPE SHARED) +else() + set(PYPARTMC_MODULE_TYPE MODULE) +endif() + +nanobind_add_module(_PyPartMC ${PYPARTMC_MODULE_TYPE} STABLE_ABI ${PyPartMC_sources}) add_dependencies(_PyPartMC partmclib) set(PYPARTMC_INCLUDE_DIRS "${CMAKE_BINARY_DIR}/include;" @@ -627,3 +633,23 @@ foreach(file ${PyPartMC_headers}) endforeach() _install(TARGETS _PyPartMC LIBRARY DESTINATION PyPartMC) + +# for C++ users who wish to link against the PyPartMC shared library +set_target_properties(_PyPartMC PROPERTIES CXX_VISIBILITY_PRESET default C_VISIBILITY_PRESET default) + +set_target_properties(_PyPartMC PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) + +if(WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_link_options(_PyPartMC PRIVATE -Wl,--export-all-symbols) +endif() + +_install( + DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/ + DESTINATION PyPartMC/include + FILES_MATCHING PATTERN "*.hpp" +) + +_install(TARGETS partmclib + ARCHIVE DESTINATION PyPartMC/lib +) + diff --git a/readme_cpp/CMakeLists.txt b/readme_cpp/CMakeLists.txt new file mode 100644 index 00000000..647d7670 --- /dev/null +++ b/readme_cpp/CMakeLists.txt @@ -0,0 +1,73 @@ +cmake_minimum_required(VERSION 3.22) +project(PyPartMC_CXX LANGUAGES CXX) + +enable_testing() + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED YES) + +find_package(Python 3.8 REQUIRED COMPONENTS Interpreter Development) +message(STATUS "Python_EXECUTABLE= ${Python_EXECUTABLE}") + +execute_process( + COMMAND ${Python_EXECUTABLE} -c "from pathlib import Path; import PyPartMC; print(f'{Path(PyPartMC.__file__).parent}')" + OUTPUT_VARIABLE PYPARTMC_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE res +) +if(res) + message(FATAL_ERROR "Failed to find PyPartMC directory. Exit code: ${res}") +endif() + +message(STATUS "PYPARTMC_DIR= ${PYPARTMC_DIR}") + +execute_process( + COMMAND ${Python_EXECUTABLE} -c "import nanobind; print(nanobind.include_dir())" + OUTPUT_VARIABLE NANOBIND_INCLUDE_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE res_nano +) +if(res_nano) + message(FATAL_ERROR "Failed to find nanobind include directory. Exit code: ${res_nano}") +endif() +message(STATUS "NANOBIND_INCLUDE_DIR= ${NANOBIND_INCLUDE_DIR}") + +execute_process( + COMMAND ${Python_EXECUTABLE} -c "from PyPartMC import _PyPartMC; print(f'{_PyPartMC.__file__}')" + OUTPUT_VARIABLE PYPARTMC_LIB + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE res_lib +) +if(res_lib) + message(FATAL_ERROR "Failed to find PyPartMC library. Exit code: ${res_lib}") +endif() + +message(STATUS "PYPARTMC_LIB= ${PYPARTMC_LIB}") + +add_executable(my_test test.cpp) + +target_include_directories(my_test PUBLIC + ${PYPARTMC_DIR}/include + ${NANOBIND_INCLUDE_DIR} + ${Python_INCLUDE_DIRS} +) + +add_library(PyPartMC_ext UNKNOWN IMPORTED) +set_target_properties(PyPartMC_ext PROPERTIES IMPORTED_LOCATION "${PYPARTMC_LIB}") + +# Link against the imported target, NOT the raw variable +target_link_libraries(my_test PRIVATE + PyPartMC_ext + ${PYPARTMC_DIR}/lib/libpartmclib.a + ${Python_LIBRARIES} +) + +# Copying .pyd file +add_custom_command(TARGET my_test POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${PYPARTMC_LIB} + $ +) + +add_test(NAME maketest + COMMAND my_test) \ No newline at end of file diff --git a/readme_cpp/test.cpp b/readme_cpp/test.cpp new file mode 100644 index 00000000..49468bc7 --- /dev/null +++ b/readme_cpp/test.cpp @@ -0,0 +1,7 @@ +#include "bin_grid.hpp" +#include + +int main(){ + BinGrid a; + std::cout << "Success\n"; +} \ No newline at end of file