From 3c6d5d70923e5f5b878e4a8cf626a32a2f6c090a Mon Sep 17 00:00:00 2001 From: Bharat Medasani Date: Mon, 21 Oct 2024 21:51:30 -0500 Subject: [PATCH] Updated build for VMEC that works with numpy 2.0 --- Sources/CMakeLists.txt | 3 + pyproject.toml | 3 +- python/CMakeLists.txt | 222 ++++++++++++++++++----------------------- 3 files changed, 101 insertions(+), 127 deletions(-) diff --git a/Sources/CMakeLists.txt b/Sources/CMakeLists.txt index b54c815..00e2280 100644 --- a/Sources/CMakeLists.txt +++ b/Sources/CMakeLists.txt @@ -65,3 +65,6 @@ get_target_property(VMEC_LINK_LIB vmec LINK_LIBRARIES) message(STATUS "vmec linked libraries are ${VMEC_LINK_LIB}") set(VMEC_LINK_LIB ${VMEC_LINK_LIB} PARENT_SCOPE) +install(TARGETS xvmec RUNTIME DESTINATION bin) +install(TARGETS vmec RUNTIME DESTINATION lib) + diff --git a/pyproject.toml b/pyproject.toml index 44521f4..a96c5fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,6 @@ requires = [ "scikit-build", "cmake", "ninja", - "numpy>=2.0.0; python_version > '3.8'", - "numpy<2.0.0; python_version <= '3.8'", + "numpy", "f90wrap" ] diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index c166718..9bbe282 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -1,27 +1,35 @@ -#cmake_minimum_required(VERSION 3.17) - -#project(cylinder VERSION 1.0 LANGUAGES C CXX Fortran) -#list(APPEND CMAKE_MODULE_PATH "/home/mbkumar/anaconda3/envs/testv/lib/python3.8/site-packages/skbuild/resources/cmake") -#list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - -#list(APPEND CMAKE_MODULE_PATH /u/bmedasan/.conda/envs/stlopt_v/lib/python3.8/site-packages/skbuild/resources/cmake) -find_package(PythonExtensions REQUIRED) -find_package(NumPy REQUIRED) -find_package(F2PY REQUIRED) +set(Python_FIND_STRATEGY LOCATION) +find_package(Python REQUIRED COMPONENTS Interpreter Development.Module NumPy) +find_program(F2PY_EXECUTABLE NAMES f2py${PYTHON_VERSION_MAJOR} f2py) find_package(F90Wrap REQUIRED) -#if(NOT APPLE) -# set(CMAKE_INSTALL_RPATH $ORIGIN) -#endif() +find_package(PythonExtensions REQUIRED) + +execute_process( + COMMAND "${PYTHON_EXECUTABLE}" + -c "import numpy; print(numpy.get_include())" + OUTPUT_VARIABLE NumPy_INCLUDE_DIRS + OUTPUT_STRIP_TRAILING_WHITESPACE +) +# F2PY headers +execute_process( + COMMAND "${PYTHON_EXECUTABLE}" + -c "import numpy.f2py; print(numpy.f2py.get_include())" + OUTPUT_VARIABLE F2PY_INCLUDE_DIRS + OUTPUT_STRIP_TRAILING_WHITESPACE +) +message(STATUS "Python headers are at ${PYTHON_INCLUDE_DIRS}") +message(STATUS "NumPy headers are at ${NumPy_INCLUDE_DIRS}") +message(STATUS "F2PY headers are at ${F2PY_INCLUDE_DIRS}") # Fortran preprocessing compiler if(CMAKE_Fortran_COMPILER_ID STREQUAL Intel) - set(FPP_COMPILER fpp) + set(FPP_COMPILER fpp) set(FPP_COMPILE_FLAGS "") elseif(CMAKE_Fortran_COMPILER_ID STREQUAL GNU) - set(FPP_COMPILER gfortran) + set(FPP_COMPILER gfortran) set(FPP_COMPILE_FLAGS "-E -cpp") elseif(CMAKE_Fortran_COMPILER_ID STREQUAL Cray) - set(FPP_COMPILER ftn) + set(FPP_COMPILER ftn) set(FPP_COMPILE_FLAGS "-e Z") endif() @@ -37,38 +45,36 @@ function(preprocess_fortran outvar) foreach(f ${ARGN}) # is it a Fortran file? if(f MATCHES "\\.[Ff](9[05])?") - message(STATUS "Got fortran file: ${f}") - # construct output filename - if(NOT IS_ABSOLUTE "${f}") - get_filename_component(f "${f}" ABSOLUTE) - endif() - file(RELATIVE_PATH r "${CMAKE_CURRENT_SOURCE_DIR}" "${f}") - get_filename_component(e "${r}" EXT) - get_filename_component(n "${r}" NAME_WE) - get_filename_component(p "${r}" PATH) - set(of "${CMAKE_CURRENT_BINARY_DIR}/${n}_fpp${e}") - message(STATUS "Output name: ${of}") - # preprocess the thing - if (CMAKE_Fortran_COMPILER_ID STREQUAL Intel) - add_custom_command(OUTPUT "${of}" - #COMMAND ${FPP_EXE} ${incflags} "${defflags}" "${f}" "${of}" - #COMMAND ${CMAKE_Fortran_COMPILER} -E -cpp "${f}" -o "${of}" - COMMAND ${FPP_COMPILER} ${FPP_COMPILE_FLAGS} ${COMP_DEF_STR} "${f}" "${of}" - IMPLICIT_DEPENDS Fortran "${f}" - COMMENT "Preprocessing ${f}" - VERBATIM - ) - else() - add_custom_command(OUTPUT "${of}" - COMMAND ${FPP_COMPILER} ${FPP_COMPILE_FLAGS} ${COMP_DEF_STR} "${f}" -o "${of}" - IMPLICIT_DEPENDS Fortran "${f}" - COMMENT "Preprocessing ${f}" - VERBATIM - ) - endif() - list(APPEND srcs "${of}") - #else() - # list(APPEND srcs "${f}") + message(STATUS "Got fortran file: ${f}") + # construct output filename + if(NOT IS_ABSOLUTE "${f}") + get_filename_component(f "${f}" ABSOLUTE) + endif() + file(RELATIVE_PATH r "${CMAKE_CURRENT_SOURCE_DIR}" "${f}") + get_filename_component(e "${r}" EXT) + get_filename_component(n "${r}" NAME_WE) + get_filename_component(p "${r}" PATH) + set(of "${CMAKE_CURRENT_BINARY_DIR}/${n}_fpp${e}") + message(STATUS "Output name: ${of}") + # preprocess the thing + if (CMAKE_Fortran_COMPILER_ID STREQUAL Intel) + add_custom_command(OUTPUT "${of}" + #COMMAND ${FPP_EXE} ${incflags} "${defflags}" "${f}" "${of}" + #COMMAND ${CMAKE_Fortran_COMPILER} -E -cpp "${f}" -o "${of}" + COMMAND ${FPP_COMPILER} ${FPP_COMPILE_FLAGS} ${COMP_DEF_STR} "${f}" "${of}" + IMPLICIT_DEPENDS Fortran "${f}" + COMMENT "Preprocessing ${f}" + VERBATIM + ) + else() + add_custom_command(OUTPUT "${of}" + COMMAND ${FPP_COMPILER} ${FPP_COMPILE_FLAGS} ${COMP_DEF_STR} "${f}" -o "${of}" + IMPLICIT_DEPENDS Fortran "${f}" + COMMENT "Preprocessing ${f}" + VERBATIM + ) + endif() + list(APPEND srcs "${of}") endif() endforeach() # return the (preprocessed) sources @@ -85,46 +91,14 @@ message(STATUS "fortran_src_files is ${fortran_src_files}") preprocess_fortran(fpp_files ${fortran_src_files}) message(STATUS "fpp_files is ${fpp_files}") -#add_library(cyl_lib SHARED ${fpp_files}) - -#function(f90wrap_outputs outvar) -# message(STATUS "process f90 files with f90wrap") -# set(srcs) -# foreach(f ${ARGN}) -# # is it a Fortran file? -# if(f MATCHES "\\.[Ff](9[05])?") -# message(STATUS "Got fortran file: ${f}") -# # construct output filename -# if(NOT IS_ABSOLUTE "${f}") -# get_filename_component(f "${f}" ABSOLUTE) -# endif() -# file(RELATIVE_PATH r "${CMAKE_CURRENT_BINARY_DIR}" "${f}") -# get_filename_component(e "${r}" EXT) -# get_filename_component(n "${r}" NAME_WE) -# get_filename_component(p "${r}" PATH) -# set(of "${CMAKE_CURRENT_BINARY_DIR}/f90wrap_${n}${e}") -# message(STATUS "Output name: ${of}") - -# list(APPEND srcs "${of}") -# #else() -# # list(APPEND srcs "${f}") -# endif() -# endforeach() -# # return the (preprocesysed) sources -# set(${outvar} "${srcs}" PARENT_SCOPE) -#endfunction() - -#f90wrap_outputs(f90wrap_output_files ${fpp_files}) -#f90wrap_outputs(f90wrap_output_files ${fortran_src_files}) - # ---------------------------------------------------------------------------- # NOTE: There is no way to identify the f90wrap---.f90 files ahead of running f90wrap # NOTE: The files produced have no one->one relation with the source files. # NOTE: So giving the names of f90wrap_---.f90 files manually #----------------------------------------------------------------------------- set(f90wrap_output_files ${CMAKE_CURRENT_BINARY_DIR}/f90wrap_toplevel.f90 - ${CMAKE_CURRENT_BINARY_DIR}/f90wrap_read_wout_mod.f90 - ${CMAKE_CURRENT_BINARY_DIR}/f90wrap_vmec_input.f90 + ${CMAKE_CURRENT_BINARY_DIR}/f90wrap_read_wout_mod.f90 + ${CMAKE_CURRENT_BINARY_DIR}/f90wrap_vmec_input.f90 ) set(kind_map_file ${CMAKE_CURRENT_SOURCE_DIR}/kind_map) @@ -138,64 +112,62 @@ add_custom_command(OUTPUT ${python_mod_file} ${f90wrap_output_files} COMMENT "Executing F90Wrap for" ${fortran_src_files} VERBATIM ) -#execute_process( -# COMMAND ${F90Wrap_EXECUTABLE} -m ${python_mod_name} ${fortran_src_files} -k ${kind_map_file} -# WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} -#) -#FILE(GLOB f90wrap_output_files ${CMAKE_CURRENT_BINARY_DIR}/f90wrap_*.f*) add_custom_target("${python_mod_name}_pymod" - DEPENDS ${python_mod_file} ${f90wrap_output_files} + DEPENDS ${python_mod_file} ${f90wrap_output_files} ) -#file(GLOB f90wrap_output_files CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/f90wrap_*.f90") set(f2py_module_name "_${python_mod_name}") -set(generated_module_file ${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_name}${PYTHON_EXTENSION_MODULE_SUFFIX}) +set(generated_module_file ${CMAKE_BINARY_DIR}/build/lib/${f2py_module_name}${PYTHON_EXTENSION_MODULE_SUFFIX}) message(STATUS "Python exten suffix expansion: ${PYTHON_EXTENSION_MODULE_SUFFIX}") message(STATUS "f90_wrap_output_files: " ${f90wrap_output_files}) message(STATUS "f2py_module_name: ${f2py_module_name}") message(STATUS "generated_module_name: ${generated_module_file}") -#set(CMAKE_BUILD_RPATH_USE_ORIGIN TRUE) -#set(CMAKE_SKIP_BUILD_PATH FALSE) -#set(CMAKE_BUILD_WITH_INSTALL_RPATH ON) -#set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}") -#set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) -include_directories("${NumPy_INCLUDE_DIRS}" "${F2PY_INCLUDE_DIRS}" "${CMAKE_CURRENT_BINARY_DIR}") -add_custom_target(${f2py_module_name} ALL - #DEPENDS ${generated_module_file} ${python_mod_name} cyl_lib ${f90wrap_output_files} +add_custom_target(${f2py_module_name_ct} ALL DEPENDS ${generated_module_file} vmec ${f90wrap_output_files} ) +set(f2py_module_c "${f2py_module_name}module.c") add_custom_command( - OUTPUT ${generated_module_file} - COMMAND ${F2PY_EXECUTABLE} - -m ${f2py_module_name} - --build-dir ${CMAKE_CURRENT_BINARY_DIR} - --f90exec=${CMAKE_Fortran_COMPILER} - --f77exec=${CMAKE_Fortran_COMPILER} - -c - #${SCALAPACK_LIB} ${NETCDF_F} ${NETCDF_C} - ${f90wrap_output_files} - -I${CMAKE_BINARY_DIR}/build/modules/vmec - --verbose - ${CMAKE_BINARY_DIR}/build/lib/libvmec.a - ${VMEC_LINK_LIB} - #IMPLICIT_DEPENDS Fortran ${f90wrap_output_files} - DEPENDS vmec ${f90wrap_output_files} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - #VERBATIM - COMMAND_EXPAND_LISTS + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_c}" # "${CMAKE_CURRENT_BINARY_DIR}/${f2py_f90_wrapper}" + COMMAND ${F2PY_EXECUTABLE} + -m "${f2py_module_name}" + --build-dir ${CMAKE_CURRENT_BINARY_DIR} + --lower # Important + "${f90wrap_output_files}" + DEPENDS ${fortran_src_files} ${f2py_module_name_ct} # Fortran source + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND_EXPAND_LISTS ) - -python_extension_module(${generated_module_file}) - -install(FILES ${python_mod_file} ${generated_module_file} #${CMAKE_CURRENT_SOURCE_DIR}/__init__.py - DESTINATION python/vmec +add_library(${f2py_module_name} MODULE + "${f2py_module_name}module.c" + "${F2PY_INCLUDE_DIRS}/fortranobject.c" + ${f90wrap_output_files} + # ${f2py_f90_wrapper} ) -install(TARGETS xvmec vmec) -# LIBRARY DESTINATION ${CMAKE_INSTALL_DIR}/. -# RUNTIME DESTINATION bin -#) +target_include_directories(${f2py_module_name} PUBLIC + ${F2PY_INCLUDE_DIRS} + ${NumPy_INCLUDE_DIRS} + ${PYTHON_INCLUDE_DIRS} + ${CMAKE_BINARY_DIR}/build/modules/vmec) +target_link_libraries(${f2py_module_name} vmec) +set_target_properties(${f2py_module_name} PROPERTIES SUFFIX "${PYTHON_EXTENSION_MODULE_SUFFIX}") +set_target_properties(${f2py_module_name} PROPERTIES PREFIX "") + +# Linker fixes +if (UNIX) + if (APPLE) + set_target_properties(${f2py_module_name} PROPERTIES + LINK_FLAGS '-Wl,-dylib,-undefined,dynamic_lookup') + else() + set_target_properties(${f2py_module_name} PROPERTIES + LINK_FLAGS '-Wl,--allow-shlib-undefined') + endif() +endif() +install(FILES ${python_mod_file} # ${generated_module_file} #${CMAKE_CURRENT_SOURCE_DIR}/__init__.py + DESTINATION python/vmec +) +install(TARGETS ${f2py_module_name} DESTINATION python/vmec)