diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..029b340 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,37 @@ +name: ci + +on: + push: + paths: + - "**.c" + - "**.cmake" + - "**/CMakeLists.txt" + - ".github/workflows/ci.yml" + +jobs: + + unix: + + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + intsize: [32, 64] + + runs-on: ${{ matrix.os }} + timeout-minutes: 5 + + steps: + - uses: actions/checkout@v4 + + - name: Install MPI (Linux) + if: ${{ runner.os == 'Linux' }} + run: sudo apt install libopenmpi-dev + + - name: Install MPI (MacOS) + if: ${{ runner.os == 'macOS' }} + run: brew install open-mpi + + - run: cmake -B build -DIDXTYPEWIDTH=${{ matrix.intsize }} + - run: cmake --build build --parallel + + - run: ctest --test-dir build -V diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29..0000000 diff --git a/CMakeLists.txt b/CMakeLists.txt index 146bc5f..392e0ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,41 +1,43 @@ -cmake_minimum_required(VERSION 2.8) -project(ParMETIS C) +cmake_minimum_required(VERSION 3.14...3.28) +project(ParMETIS LANGUAGES C) +# --- need METIS first +include(FetchContent) -# Search for MPI. -# GK commented this out as it seems to be creating problems -# include(FindMPI) -# if(NOT MPI_FOUND) -# message(FATAL_ERROR "mpi is not found") -# endif() -# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MPI_COMPILE_FLAGS}") +FetchContent_Declare(GKlib +GIT_REPOSITORY https://github.com/scivision/GKlib.git +GIT_TAG 44630ca +GIT_SHALLOW true +) +FetchContent_MakeAvailable(GKlib) +FetchContent_Declare(metis_fc +GIT_REPOSITORY https://github.com/scivision/metis.git +GIT_TAG fd7799b +GIT_SHALLOW true +) -# Prepare libraries. -if(SHARED) - set(ParMETIS_LIBRARY_TYPE SHARED) -else() - set(ParMETIS_LIBRARY_TYPE STATIC) +FetchContent_MakeAvailable(metis_fc) + +if(NOT DEFINED REALTYPEWIDTH) + set(REALTYPEWIDTH 32) +endif() +if(NOT DEFINED IDXTYPEWIDTH) + set(IDXTYPEWIDTH 32) endif() +add_compile_definitions(REALTYPEWIDTH=${REALTYPEWIDTH} IDXTYPEWIDTH=${IDXTYPEWIDTH}) + +message(STATUS "${PROJECT_NAME} ${PROJECT_VERSION} CMake ${CMAKE_VERSION} +REALTYPEWIDTH=${REALTYPEWIDTH} IDXTYPEWIDTH=${IDXTYPEWIDTH}") +message(STATUS "METIS ${metis_fc_SOURCE_DIR}") +message(STATUS "GKlib ${gklib_SOURCE_DIR}") + +find_package(MPI REQUIRED) include(./conf/gkbuild.cmake) -# List of paths that the compiler will search for header files. -# i.e., the -I equivalent -include_directories(include) -include_directories(${MPI_INCLUDE_PATH}) -include_directories(${GKLIB_PATH}/include) -include_directories(${METIS_PATH}/include) -include_directories(${CMAKE_INSTALL_PREFIX}/include) - -# List of paths that the compiler will search for library files. -# i.e., the -L equivalent -link_directories(${GKLIB_PATH}/lib) -link_directories(${METIS_PATH}/lib) -link_directories(${CMAKE_INSTALL_PREFIX}/lib) - -# List of directories that cmake will look for CMakeLists.txt -add_subdirectory(include) +install(FILES include/parmetis.h TYPE INCLUDE) + add_subdirectory(libparmetis) add_subdirectory(programs) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..f0bf935 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,72 @@ +{ + "version": 6, + +"configurePresets": [ +{ + "name": "default", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "CMAKE_COMPILE_WARNING_AS_ERROR": true + } +} +], +"buildPresets": [ + { + "name": "default", + "configurePreset": "default" + }, + { + "name": "release", + "configurePreset": "default", + "configuration": "Release" + } +], +"testPresets": [ +{ + "name": "default", + "configurePreset": "default", + "output": { + "outputOnFailure": true, + "verbosity": "verbose" + }, + "execution": { + "noTestsAction": "error", + "scheduleRandom": true, + "stopOnFailure": false, + "timeout": 60 + } +}, +{ + "name": "release", "inherits": "default", + "configuration": "Release" +} +], +"workflowPresets": [ + { + "name": "default", + "steps": [ + { + "type": "configure", + "name": "default" + }, + { + "type": "build", + "name": "default" + } + ] + }, + { + "name": "release", + "steps": [ + { + "type": "configure", + "name": "default" + }, + { + "type": "build", + "name": "release" + } + ] + } +] +} diff --git a/README.md b/README.md index ca03a05..5d293ac 100644 --- a/README.md +++ b/README.md @@ -1,82 +1,26 @@ -# ParMETIS +# ParMETIS -ParMETIS is an MPI-based library for partitioning graphs, partitioning finite element meshes, -and producing fill reducing orderings for sparse matrices. The algorithms implemented in -ParMETIS are based on the multilevel recursive-bisection, multilevel k-way, and multi-constraint +[![ci](https://github.com/scivision/ParMETIS/actions/workflows/ci.yml/badge.svg)](https://github.com/scivision/ParMETIS/actions/workflows/ci.yml) + +ParMETIS is an MPI-based library for partitioning graphs, partitioning finite element meshes, +and producing fill reducing orderings for sparse matrices. The algorithms implemented in +ParMETIS are based on the multilevel recursive-bisection, multilevel k-way, and multi-constraint partitioning schemes developed in our lab. -## Downloading ParMETIS +## Downloading ParMETIS You can download ParMETIS by simply cloning it using the command: ``` git clone https://github.com/KarypisLab/ParMETIS.git ``` -## Building the ParMETIS library To build ParMETIS you can follow the instructions below: -### Dependencies - -General dependencies for building ParMETIS are: gcc, cmake, build-essential, and an MPI library. -In Ubuntu systems these can be obtained from the apt package manager (e.g., apt-get install cmake, mpich, etc) - -``` -sudo apt-get install build-essential -sudo apt-get install cmake -``` - -In addition, you need to download and install -[GKlib](https://github.com/KarypisLab/GKlib) and -[METIS](https://github.com/KarypisLab/METIS) by following the instructions there. - - -### Building and installing ParMETIS - -ParMETIS is primarily configured by passing options to make config. For example: - -``` -make config cc=mpicc prefix=~/local -make install +```sh +cmake --workflow --preset default ``` -will configure ParMETIS to be built using mpicc and then install the binaries, header files, and libraries at - -``` -~/local/bin -~/local/include -~/local/lib -``` - -directories, respectively. - -### Common configuration options are: - - cc=[compiler] - The C compiler to use [default is determined by CMake] - shared=1 - Build a shared library instead of a static one [off by default] - prefix=[PATH] - Set the installation prefix [~/local by default] - gklib_path=[PATH] - Set the prefix path where GKlib has been installed. You can skip - this if GKlib's installation prefix is the same as that of ParMETIS. - metis_path=[PATH] - Set the prefix path where METIS has been installed. You can skip - this if METIS' installation prefix is the same as that of ParMETIS. - -### Advanced debugging related options: - - gdb=1 - Build with support for GDB [off by default] - debug=1 - Enable debugging support [off by default] - assert=1 - Enable asserts [off by default] - assert2=1 - Enable very expensive asserts [off by default] - -### Other make commands - - make uninstall - Removes all files installed by 'make install'. - - make clean - Removes all object files but retains the configuration options. - - make distclean - Performs clean and completely removes the build directory. ### Definitions of supported data types @@ -85,8 +29,6 @@ ParMETIS uses the same data types for integers and floating point numbers (32/64 integers and single/double precision floating point numbers) as used when configuring and building METIS. - ## Copyright & License Notice -Copyright 1998-2020, Regents of the University of Minnesota - +Copyright 1998-2020, Regents of the University of Minnesota diff --git a/conf/gkbuild.cmake b/conf/gkbuild.cmake index ec91224..11271c3 100644 --- a/conf/gkbuild.cmake +++ b/conf/gkbuild.cmake @@ -3,141 +3,97 @@ include(CheckFunctionExists) include(CheckIncludeFile) # Setup options. -option(GDB "enable use of GDB" OFF) -option(ASSERT "turn asserts on" OFF) -option(ASSERT2 "additional assertions" OFF) -option(DEBUG "add debugging support" OFF) -option(GPROF "add gprof support" OFF) option(OPENMP "enable OpenMP support" OFF) option(PCRE "enable PCRE support" OFF) option(GKREGEX "enable GKREGEX support" OFF) option(GKRAND "enable GKRAND support" OFF) + # Add compiler flags. if(MSVC) - set(GK_COPTS "/Ox") - set(GK_COPTIONS "-DWIN32 -DMSC -D_CRT_SECURE_NO_DEPRECATE -DUSE_GKREGEX") -elseif(MINGW) - set(GK_COPTS "-DUSE_GKREGEX") + set(GKlib_COPTIONS WIN32 MSC _CRT_SECURE_NO_DEPRECATE USE_GKREGEX) +elseif(WIN32) + set(GKlib_COPTIONS USE_GKREGEX) else() - set(GK_COPTIONS "-DLINUX -D_FILE_OFFSET_BITS=64") + set(GKlib_COPTIONS LINUX FILE_OFFSET_BITS=64) endif(MSVC) + if(CYGWIN) - set(GK_COPTIONS "${GK_COPTIONS} -DCYGWIN") -endif(CYGWIN) -if(CMAKE_COMPILER_IS_GNUCC) -# GCC opts. - set(GK_COPTIONS "${GK_COPTIONS} -std=c99 -fno-strict-aliasing") -# -march=native is not a valid flag on PPC: -if(CMAKE_SYSTEM_PROCESSOR MATCHES "power|ppc|powerpc|ppc64|powerpc64" OR (APPLE AND CMAKE_OSX_ARCHITECTURES MATCHES "ppc|ppc64")) - set(GK_COPTIONS "${GK_COPTIONS} -mtune=native") -else() - set(GK_COPTIONS "${GK_COPTIONS} -march=native") -endif() - if(NOT MINGW) - set(GK_COPTIONS "${GK_COPTIONS} -fPIC") - endif(NOT MINGW) -# GCC warnings. - set(GK_COPTIONS "${GK_COPTIONS} -Werror -Wall -pedantic -Wno-unused-function -Wno-unused-but-set-variable -Wno-unused-variable -Wno-unknown-pragmas -Wno-unused-label") -elseif(${CMAKE_C_COMPILER_ID} MATCHES "Sun") -# Sun insists on -xc99. - set(GK_COPTIONS "${GK_COPTIONS} -xc99") -endif(CMAKE_COMPILER_IS_GNUCC) - -if(${CMAKE_C_COMPILER_ID} STREQUAL "Intel") - set(GK_COPTIONS "${GK_COPTIONS} -xHost") - # set(GK_COPTIONS "${GK_COPTIONS} -fast") + list(APPEND GKlib_COPTIONS CYGWIN) endif() -# Add support for the Accelerate framework in OS X if(APPLE) - set(GK_COPTIONS "${GK_COPTIONS} -framework Accelerate") -endif(APPLE) - -# Find OpenMP if it is requested. -if(OPENMP) - include(FindOpenMP) - if(OPENMP_FOUND) - set(GK_COPTIONS "${GK_COPTIONS} -D__OPENMP__ ${OpenMP_C_FLAGS}") - else() - message(WARNING "OpenMP was requested but support was not found") - endif(OPENMP_FOUND) -endif(OPENMP) - - -# Add various definitions. -if(GDB) - set(GK_COPTS "${GK_COPTS} -g") - set(GK_COPTIONS "${GK_COPTIONS} -Werror") -else() - set(GK_COPTS "-O3") -endif(GDB) - - -if(DEBUG) - set(GK_COPTS "-Og") - set(GK_COPTIONS "${GK_COPTIONS} -DDEBUG") -endif(DEBUG) + list(APPEND GKlib_COPTIONS MACOS) +endif() -if(GPROF) - set(GK_COPTS "-pg") -endif(GPROF) +if(CMAKE_C_COMPILER_ID STREQUAL "GNU") + list(APPEND GKlib_COPTS -fno-strict-aliasing -Werror -Wall -pedantic -Wno-unused-function -Wno-unused-but-set-variable -Wno-unused-variable -Wno-unknown-pragmas -Wno-unused-label) +endif() -if(NOT ASSERT) - set(GK_COPTIONS "${GK_COPTIONS} -DNDEBUG") -endif(NOT ASSERT) +if(UNIX) +include(CheckPIESupported) +check_pie_supported() +set(CMAKE_POSITION_INDEPENDENT_CODE true) +endif() -if(NOT ASSERT2) - set(GK_COPTIONS "${GK_COPTIONS} -DNDEBUG2") -endif(NOT ASSERT2) +# Find OpenMP if it is requested. +if(OPENMP) + find_package(OpenMP REQUIRED) + list(APPEND GKlib_COPTIONS __OPENMP__) +endif() +# Set the CPU type +if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") + list(APPEND GKlib_COPTIONS NO_X86=1) +endif() # Add various options if(PCRE) - set(GK_COPTIONS "${GK_COPTIONS} -D__WITHPCRE__") -endif(PCRE) + list(APPEND GKlib_COPTIONS __WITHPCRE__) +endif() if(GKREGEX) - set(GK_COPTIONS "${GK_COPTIONS} -DUSE_GKREGEX") -endif(GKREGEX) +list(APPEND GKlib_COPTIONS USE_GKREGEX) +endif() if(GKRAND) - set(GK_COPTIONS "${GK_COPTIONS} -DUSE_GKRAND") -endif(GKRAND) +list(APPEND GKlib_COPTIONS USE_GKRAND) +endif() # Check for features. check_include_file(execinfo.h HAVE_EXECINFO_H) if(HAVE_EXECINFO_H) - set(GK_COPTIONS "${GK_COPTIONS} -DHAVE_EXECINFO_H") + list(APPEND GKlib_COPTIONS HAVE_EXECINFO_H) endif(HAVE_EXECINFO_H) check_function_exists(getline HAVE_GETLINE) if(HAVE_GETLINE) - set(GK_COPTIONS "${GK_COPTIONS} -DHAVE_GETLINE") + list(APPEND GKlib_COPTIONS HAVE_GETLINE) endif(HAVE_GETLINE) # Custom check for TLS. if(MSVC) - set(GK_COPTIONS "${GK_COPTIONS} -D__thread=__declspec(thread)") + list(APPEND GKlib_COPTIONS __thread=__declspec(thread)) # This if checks if that value is cached or not. if("${HAVE_THREADLOCALSTORAGE}" MATCHES "^${HAVE_THREADLOCALSTORAGE}$") + message(CHECK_START "checking for thread-local storage") try_compile(HAVE_THREADLOCALSTORAGE ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/conf/check_thread_storage.c) + ${CMAKE_CURRENT_LIST_DIR}/check_thread_storage.c) if(HAVE_THREADLOCALSTORAGE) - message(STATUS "checking for thread-local storage - found") + message(CHECK_PASS "found") else() - message(STATUS "checking for thread-local storage - not found") + message(CHECK_FAIL "not found") endif() endif() if(NOT HAVE_THREADLOCALSTORAGE) - set(GK_COPTIONS "${GK_COPTIONS} -D__thread=") + list(APPEND GKlib_COPTIONS __thread=) endif() endif() # Finally set the official C flags. -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GK_COPTIONS} ${GK_COPTS}") - +add_compile_options("$<$:${GKlib_COPTS}>") +add_compile_definitions("$<$:${GKlib_COPTIONS}>") diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt deleted file mode 100644 index 6a27074..0000000 --- a/include/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -install(FILES parmetis.h DESTINATION include) \ No newline at end of file diff --git a/libparmetis/CMakeLists.txt b/libparmetis/CMakeLists.txt index b9d6d84..99ae0f1 100644 --- a/libparmetis/CMakeLists.txt +++ b/libparmetis/CMakeLists.txt @@ -1,17 +1,27 @@ -# Include directories for library code. -include_directories(.) - # Find sources. -file(GLOB parmetis_sources *.c) +set(parmetis_sources diffutil.c initmsection.c move.c rename.h wave.c +akwayfm.c frename.c initpart.c msetup.c renumber.c weird.c +ametis.c gklib.c kmetis.c node_refine.c rmetis.c wspace.c +balancemylink.c gklib_defs.h kwayrefine.c ometis.c selectq.c xyzpart.c +comm.c gklib_rename.h macros.h parmetislib.h serial.c +csrmatch.c gkmetis.c match.c proto.h stat.c +ctrl.c gkmpi.c mdiffusion.c pspases.c struct.h +debug.c graph.c mesh.c redomylink.c timer.c +defs.h initbalance.c mmetis.c remap.c util.c) # Create libparmetis -add_library(parmetis ${ParMETIS_LIBRARY_TYPE} ${parmetis_sources}) +add_library(parmetis ${parmetis_sources}) +target_include_directories(parmetis PUBLIC +"$" +$ +PRIVATE +${gklib_SOURCE_DIR} +${metis_fc_SOURCE_DIR}/include +) +target_link_libraries(parmetis PRIVATE MPI::MPI_C) if(SHARED) - target_link_libraries(parmetis metis GKlib) + target_link_libraries(parmetis PRIVATE metis GKlib) endif() - -install(TARGETS parmetis - LIBRARY DESTINATION lib - RUNTIME DESTINATION lib - ARCHIVE DESTINATION lib) + +install(TARGETS parmetis) diff --git a/programs/CMakeLists.txt b/programs/CMakeLists.txt index 2f9341c..bba4c28 100644 --- a/programs/CMakeLists.txt +++ b/programs/CMakeLists.txt @@ -1,5 +1,3 @@ -include_directories(.) - # Create programs. add_executable(pm_ptest ptest.c io.c adaptgraph.c) add_executable(pm_mtest mtest.c io.c) @@ -7,10 +5,11 @@ add_executable(pm_parmetis parmetis.c io.c adaptgraph.c) add_executable(pm_pometis pometis.c io.c) add_executable(pm_dglpart dglpart.c) -# Link with the required libraries -foreach(prog pm_ptest pm_mtest pm_parmetis pm_pometis pm_dglpart) - target_link_libraries(${prog} parmetis metis GKlib m) +# Link with the required libraries +foreach(prog IN ITEMS pm_ptest pm_mtest pm_parmetis pm_pometis pm_dglpart) + target_include_directories(${prog} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${metis_fc_SOURCE_DIR}/include) + target_link_libraries(${prog} PRIVATE parmetis metis GKlib MPI::MPI_C + $<$:m>) endforeach(prog) -install(TARGETS pm_ptest pm_mtest pm_parmetis pm_pometis pm_dglpart - RUNTIME DESTINATION bin) +install(TARGETS pm_ptest pm_mtest pm_parmetis pm_pometis pm_dglpart)