Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable building primme with CMake (also under MSVC) #64

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,6 @@

# Debug files
*.dSYM/

# CMake build directories
build*/
92 changes: 92 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
cmake_minimum_required(VERSION 3.18)

# If not set by the user, make a release build.
if (NOT CMAKE_BUILD_TYPE)
set (CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
endif()
message(STATUS "CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")

project(primme
VERSION 3.2
DESCRIPTION "PRIMME: PReconditioned Iterative MultiMethod Eigensolver"
LANGUAGES C CXX
HOMEPAGE_URL https://github.com/primme/primme)

option(WITH_FLOAT "Build PRIMME with support for floats" OFF)
option(WITH_HALF "Build PRIMME with support for half floats" OFF)
option(WITH_FORTRAN "Build PRIMME Fortran 90 tests" OFF)

# set C99 standard
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED True)

if (POLICY CMP0042)
# enable MACOSX_RPATH by default
cmake_policy (SET CMP0042 NEW)
endif ()

# Find our extra modules
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
include(PrimmeTests)
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)

set(PRIMME_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}/primme")
set(PRIMME_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/primme")

if (WITH_HALF)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPRIMME_WITH_HALF")
endif()
if (WITH_FLOAT)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPRIMME_WITH_FLOAT")
endif()

find_package(BLAS REQUIRED)
if (NOT TARGET LAPACK::LAPACK)
find_package(LAPACK REQUIRED)
endif()
primme_test_fortran_underscore()

CHECK_LIBRARY_EXISTS(m sin "" HAVE_LIB_M)
if (HAVE_LIB_M)
set(EXTRA_LIBS ${EXTRA_LIBS} m)
endif()

add_library(primme)
set(primme_MAJOR_VERSION 3)
set(primme_MINOR_VERSION 9)
set(primme_VERSION ${primme_MAJOR_VERSION}.${primme_MINOR_VERSION})
target_include_directories(primme
PUBLIC
$<INSTALL_INTERFACE:${PRIMME_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src/include>
)
target_link_libraries(primme PUBLIC LAPACK::LAPACK BLAS::BLAS ${EXTRA_LIBS})

add_subdirectory(include)
add_subdirectory(src)

enable_testing()
add_subdirectory(examples)

install(TARGETS primme
EXPORT primmeTargets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

configure_file(cmake/primme-config.cmake.in "${PROJECT_BINARY_DIR}/primme-config.cmake" @ONLY)
write_basic_package_version_file(
${PROJECT_BINARY_DIR}/primme-config-version.cmake
VERSION ${PACKAGE_VERSION}
COMPATIBILITY SameMajorVersion
)
install(EXPORT primmeTargets DESTINATION "${PRIMME_INSTALL_CMAKEDIR}")
install(
FILES
"${PROJECT_BINARY_DIR}/primme-config.cmake"
"${PROJECT_BINARY_DIR}/primme-config-version.cmake"
DESTINATION "${PRIMME_INSTALL_CMAKEDIR}"
)
26 changes: 26 additions & 0 deletions cmake/PrimmeTests.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
include(CheckSymbolExists)

function(primme_test_fortran_underscore)
if(WITH_FORTRAN)
enable_language(Fortran)
include(FortranCInterface)
FortranCInterface_VERIFY()
if (FortranCInterface_GLOBAL_SUFFIX STREQUAL "_")
set(F77_UNDERSCORE TRUE)
else()
set(F77_UNDERSCORE FALSE)
endif()
else()
set(CMAKE_REQUIRED_LIBRARIES BLAS::BLAS)
check_c_source_compiles(
"int main() { extern void sasum_(); sasum_(); }"
F77_UNDERSCORE
)
endif()
message(STATUS "Checking whether Fortran adds underscore - ${F77_UNDERSCORE}")
if(F77_UNDERSCORE)
set(CMAKE_REQUIRED_LIBRARIES BLAS::BLAS)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DF77UNDERSCORE" PARENT_SCOPE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DF77UNDERSCORE" PARENT_SCOPE)
endif()
endfunction()
33 changes: 33 additions & 0 deletions cmake/primme-config.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Config file for the arpack-ng package.
#
# To use arpack from CMake, use ARPACK::ARPACK target:
# find_package(arpackng)
# add_executable(main main.f)
# target_include_directories(main INTERFACE ARPACK::ARPACK)
# target_link_libraries(main ARPACK::ARPACK)
#
# To use parpack from CMake, use PARPACK::PARPACK target:
# find_package(arpackng)
# add_executable(main main.f)
# target_include_directories(main INTERFACE PARPACK::PARPACK)
# target_link_libraries(main PARPACK::PARPACK)

include(CMakeFindDependencyMacro)
# Find dependencies
if (NOT TARGET BLAS::BLAS)
find_dependency(BLAS REQUIRED)
endif()
if (NOT TARGET LAPACK::LAPACK)
find_dependency(LAPACK REQUIRED)
endif()
if (@ICB@)
enable_language(Fortran)
endif()
if (@MPI@)
include(FindMPI)
if (NOT TARGET MPI::Fortran)
find_dependency(MPI REQUIRED COMPONENTS Fortran)
endif()
endif()

include("${CMAKE_CURRENT_LIST_DIR}/primmeTargets.cmake")
31 changes: 31 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
function(add_primme_test)
set(option_args)
set(one_value_args NAME SOURCE)
set(multi_value_args OTHER_SOURCES)
cmake_parse_arguments(ARGP "${option_args}" "${one_value_args}" "${multi_value_args}" ${ARGN})

if ("${ARGP_NAME}" STREQUAL "")
get_filename_component(ARGP_NAME ${ARGP_SOURCE} NAME_WE)
endif()
message(STATUS "Added test ${ARGP_NAME}_test with executable ${ARGP_NAME}")
add_executable(${ARGP_NAME})
target_link_libraries(${ARGP_NAME} PUBLIC ${ARGP_LIBRARIES} primme)
target_sources(${ARGP_NAME} PRIVATE ${ARGP_SOURCE} ${ARGP_OTHER_SOURCES})
add_test(${ARGP_NAME}_test ${ARGP_NAME})
endfunction()

set(C_SOURCES ex_eigs_dseq.c ex_eigs_zseq.c ex_eigs_zseq_normal.c ex_svds_dseq.c ex_svds_zseq.c)
set(CXX_SOURCES ex_eigs_zseqxx.cxx ex_svds_zseqxx.cxx)
if(WITH_FORTRAN)
set(F77_SOURCES ex_eigs_dseqf77.f ex_eigs_zseqf77.f ex_svds_dseqf77.f ex_svds_zseqf77.f)
set(F90_SOURCES ex_eigs_dseqf90.f90 ex_svds_dseqf90.f90)
endif()

foreach(f ${C_SOURCES} ${CXX_SOURCES} ${F90_SOURCES})
add_primme_test(SOURCE ${f} LIBRARIES LAPACK::LAPACK BLAS::BLAS primme)
endforeach()

if(MSVC)
set_source_files_properties(${C_SOURCES}
PROPERTIES LANGUAGE CXX)
endif()
22 changes: 11 additions & 11 deletions examples/ex_eigs_zseq.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <complex.h>
#include "primme.h" /* header file is required to run primme */
typedef PRIMME_COMPLEX_DOUBLE cdouble;

void LaplacianMatrixMatvec(void *x, PRIMME_INT *ldx, void *y, PRIMME_INT *ldy, int *blockSize, primme_params *primme, int *ierr);
void LaplacianApplyPreconditioner(void *x, PRIMME_INT *ldx, void *y, PRIMME_INT *ldy, int *blockSize, primme_params *primme, int *ierr);
Expand All @@ -46,7 +46,7 @@ int main (int argc, char *argv[]) {
/* Solver arrays and parameters */
double *evals; /* Array with the computed eigenvalues */
double *rnorms; /* Array with the computed eigenpairs residual norms */
complex double *evecs; /* Array with the computed eigenvectors;
cdouble *evecs; /* Array with the computed eigenvectors;
first vector starts in evecs[0],
second vector starts in evecs[primme.n],
third vector starts in evecs[primme.n*2]... */
Expand Down Expand Up @@ -96,7 +96,7 @@ int main (int argc, char *argv[]) {

/* Allocate space for converged Ritz values and residual norms */
evals = (double*)malloc(primme.numEvals*sizeof(double));
evecs = (complex double*)malloc(primme.n*primme.numEvals*sizeof(complex double));
evecs = (cdouble*)malloc(primme.n*primme.numEvals*sizeof(cdouble));
rnorms = (double*)malloc(primme.numEvals*sizeof(double));

/* Call primme */
Expand Down Expand Up @@ -306,12 +306,12 @@ void LaplacianMatrixMatvec(void *x, PRIMME_INT *ldx, void *y, PRIMME_INT *ldy, i

int i; /* vector index, from 0 to *blockSize-1*/
int row; /* Laplacian matrix row index, from 0 to matrix dimension */
complex double *xvec; /* pointer to i-th input vector x */
complex double *yvec; /* pointer to i-th output vector y */
cdouble *xvec; /* pointer to i-th input vector x */
cdouble *yvec; /* pointer to i-th output vector y */

for (i=0; i<*blockSize; i++) {
xvec = (complex double *)x + *ldx*i;
yvec = (complex double *)y + *ldy*i;
xvec = (cdouble *)x + *ldx*i;
yvec = (cdouble *)y + *ldy*i;
for (row=0; row<primme->n; row++) {
yvec[row] = 0.0;
if (row-1 >= 0) yvec[row] += -1.0*xvec[row-1];
Expand All @@ -333,12 +333,12 @@ void LaplacianApplyPreconditioner(void *x, PRIMME_INT *ldx, void *y, PRIMME_INT

int i; /* vector index, from 0 to *blockSize-1*/
int row; /* Laplacian matrix row index, from 0 to matrix dimension */
complex double *xvec; /* pointer to i-th input vector x */
complex double *yvec; /* pointer to i-th output vector y */
cdouble *xvec; /* pointer to i-th input vector x */
cdouble *yvec; /* pointer to i-th output vector y */

for (i=0; i<*blockSize; i++) {
xvec = (complex double *)x + *ldx*i;
yvec = (complex double *)y + *ldy*i;
xvec = (cdouble *)x + *ldx*i;
yvec = (cdouble *)y + *ldy*i;
for (row=0; row<primme->n; row++) {
yvec[row] = xvec[row]/2.;
}
Expand Down
36 changes: 22 additions & 14 deletions examples/ex_eigs_zseq_normal.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,26 @@
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <complex.h>
#include "primme.h" /* header file is required to run primme */
#include "primme.h" /* header file is required to run primme */
typedef PRIMME_COMPLEX_DOUBLE cdouble;

#ifdef __cplusplus
#define creal(x) std::real(x)
#define cimag(x) std::imag(x)
#define cabs(x) std::abs(x)
#define conj(x) std::conj(x)
#define I cdouble(0,1)
#endif

void LaplacianLikeMatrixMatvec(void *x, PRIMME_INT *ldx, void *y, PRIMME_INT *ldy, int *blockSize, primme_params *primme, int *ierr);
void LaplacianLikeApplyPreconditioner(void *x, PRIMME_INT *ldx, void *y, PRIMME_INT *ldy, int *blockSize, primme_params *primme, int *ierr);

int main (int argc, char *argv[]) {

/* Solver arrays and parameters */
complex double *evals; /* Array with the computed eigenvalues */
cdouble *evals; /* Array with the computed eigenvalues */
double *rnorms; /* Array with the computed eigenpairs residual norms */
complex double *evecs; /* Array with the computed eigenvectors;
cdouble *evecs; /* Array with the computed eigenvectors;
first vector starts in evecs[0],
second vector starts in evecs[primme.n],
third vector starts in evecs[primme.n*2]... */
Expand Down Expand Up @@ -102,8 +110,8 @@ int main (int argc, char *argv[]) {
primme_display_params(primme);

/* Allocate space for converged Ritz values and residual norms */
evals = (complex double*)malloc(primme.numEvals*sizeof(complex double));
evecs = (complex double*)malloc(primme.n*primme.numEvals*sizeof(complex double));
evals = (cdouble*)malloc(primme.numEvals*sizeof(cdouble));
evecs = (cdouble*)malloc(primme.n*primme.numEvals*sizeof(cdouble));
rnorms = (double*)malloc(primme.numEvals*sizeof(double));

/* Call primme */
Expand Down Expand Up @@ -313,12 +321,12 @@ void LaplacianLikeMatrixMatvec(void *x, PRIMME_INT *ldx, void *y, PRIMME_INT *ld

int i; /* vector index, from 0 to *blockSize-1*/
int row; /* Laplacian matrix row index, from 0 to matrix dimension */
complex double *xvec; /* pointer to i-th input vector x */
complex double *yvec; /* pointer to i-th output vector y */
cdouble *xvec; /* pointer to i-th input vector x */
cdouble *yvec; /* pointer to i-th output vector y */

for (i=0; i<*blockSize; i++) {
xvec = (complex double *)x + *ldx*i;
yvec = (complex double *)y + *ldy*i;
xvec = (cdouble *)x + *ldx*i;
yvec = (cdouble *)y + *ldy*i;
for (row=0; row<primme->n; row++) {
yvec[row] = 0.0;
if (row-1 >= 0) yvec[row] += (-1.0+I)*xvec[row-1];
Expand All @@ -340,12 +348,12 @@ void LaplacianLikeApplyPreconditioner(void *x, PRIMME_INT *ldx, void *y, PRIMME_

int i; /* vector index, from 0 to *blockSize-1*/
int row; /* Laplacian matrix row index, from 0 to matrix dimension */
complex double *xvec; /* pointer to i-th input vector x */
complex double *yvec; /* pointer to i-th output vector y */
cdouble *xvec; /* pointer to i-th input vector x */
cdouble *yvec; /* pointer to i-th output vector y */

for (i=0; i<*blockSize; i++) {
xvec = (complex double *)x + *ldx*i;
yvec = (complex double *)y + *ldy*i;
xvec = (cdouble *)x + *ldx*i;
yvec = (cdouble *)y + *ldy*i;
for (row=0; row<primme->n; row++) {
yvec[row] = xvec[row]/2.;
}
Expand Down