diff --git a/.gitignore b/.gitignore index c409e787..e0c43e7f 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ generated-docs/ *.md~ *.swp +out.cmake GPATH GRTAGS GTAGS diff --git a/.travis.yml b/.travis.yml index df69900b..d692df59 100644 --- a/.travis.yml +++ b/.travis.yml @@ -160,9 +160,6 @@ script: - cd build; - | CC=mpicc CXX=mpic++ cmake -DMFEM_DIR="/home/travis/build/LLNL/mfem-install" \ - -DHYPRE_DIR="/home/travis/build/LLNL/hypre-install" \ - -DSuiteSparse_DIR="/home/travis/build/LLNL/SuiteSparse-install" \ - -DMETIS_DIR="/home/travis/build/LLNL/metis-install" \ -DUSE_ARPACK=OFF -DCMAKE_BUILD_TYPE=Debug \ -DSPE10_PERM="/home/travis/build/LLNL/spe10-install/spe_perm.dat" \ -DSMOOTHG_TEST_PROCS=2 ..; diff --git a/CMakeLists.txt b/CMakeLists.txt index d758f752..f2f45410 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,3 @@ -#!/bin/sh # BHEADER #################################################################### # # Copyright (c) 2018, Lawrence Livermore National Security, LLC. @@ -33,9 +32,7 @@ set(${PROJECT_NAME}_GRAPHDATA ${PROJECT_SOURCE_DIR}/graphdata) ##### # set up external dependencies -# (this is a mess, seems to work, but I don't know what -# I'm doing and I'm sure it can be greatly simplified) -# (also should take some directory hints from config.sh) +# (we outsource a lot of this to MFEM) ##### # This is a list of TPLs that are used by all targets @@ -44,7 +41,7 @@ set(TPL_LIBRARIES "") # This is a list of linker flags to be used with TPLs for all targets set(TPL_LINKER_FLAGS "") -# SAAMGE_PARALLEL +# SAAMGE option(USE_SAAMGE "Should SAAMGE be enabled?" OFF) if(USE_SAAMGE) find_path(SAAMGE_INCLUDE_PATH saamge.hpp @@ -64,6 +61,14 @@ else() set(${PROJECT_NAME}_USE_SAAMGE 0) endif() +# MPI +find_package(MPI REQUIRED) +include_directories(${MPI_INCLUDE_PATH}) +list(APPEND TPL_LIBRARIES ${MPI_LIBRARIES}) +if(MPI_CXX_COMPILE_FLAGS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MPI_CXX_COMPILE_FLAGS}") +endif() + # MFEM find_path(MFEM_INCLUDE_PATH mfem.hpp HINTS ${MFEM_DIR}/include) @@ -75,41 +80,24 @@ add_library(MFEM_LIB STATIC IMPORTED) set_property(TARGET MFEM_LIB PROPERTY IMPORTED_LOCATION ${MFEM_LIBRARY_PATH}/${MFEM_LIB_NAME}) list(APPEND TPL_LIBRARIES ${MFEM_LIBRARY_PATH}/${MFEM_LIB_NAME}) -# Hypre -find_path(HYPRE_INCLUDE_PATH HYPRE.h - HINTS ${HYPRE_DIR}/include) -include_directories(${HYPRE_INCLUDE_PATH}) -set(HYPRE_LIB_NAME libHYPRE.a) -find_library(HYPRE_LIB HYPRE - ${HYPRE_DIR}/lib) -list(APPEND TPL_LIBRARIES ${HYPRE_LIB}) - -# MPI -find_package(MPI REQUIRED) -include_directories(${MPI_INCLUDE_PATH}) -list(APPEND TPL_LIBRARIES ${MPI_LIBRARIES}) -if(MPI_CXX_COMPILE_FLAGS) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MPI_CXX_COMPILE_FLAGS}") +option(ADOPT_MFEM_DEPENDENCIES "Take include and link paths from MFEM installation?" ON) +if(ADOPT_MFEM_DEPENDENCIES) + # steal all of MFEM's dependencies + find_path(MFEM_CONFIG_PATH config.mk + PATHS ${MFEM_DIR}/share/mfem ${MFEM_DIR}) + execute_process(COMMAND python parsemk.py ${MFEM_CONFIG_PATH}/config.mk + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + include("out.cmake") + include_directories(${MK_INCLUDES}) + list(APPEND TPL_LIBRARIES ${MK_LIBRARIES}) +else() + include("explicitdependencies.cmake") + include_directories(${EI_INCLUDES}) + list(APPEND TPL_LIBRARIES ${EI_LIBRARIES}) endif() -# Metis -find_path(METIS_INCLUDE_PATH metis.h - HINTS ${METIS_DIR}/include) -set(METIS_LIB_NAME libmetis.a) -find_path(METIS_LIBRARY_PATH ${METIS_LIB_NAME} - ${METIS_DIR}/lib) -include_directories(${METIS_INCLUDE_PATH}) -add_library(METIS_LIB STATIC IMPORTED) -set_property(TARGET METIS_LIB PROPERTY IMPORTED_LOCATION ${METIS_LIBRARY_PATH}/${METIS_LIB_NAME}) -list(APPEND TPL_LIBRARIES ${METIS_LIBRARY_PATH}/${METIS_LIB_NAME}) - -# SuiteSparse -find_package(SuiteSparse REQUIRED UMFPACK KLU AMD BTF CHOLMOD COLAMD CAMD CCOLAMD config) -include_directories(${SuiteSparse_INCLUDE_DIRS}) -list(APPEND TPL_LIBRARIES ${SuiteSparse_LIBRARIES}) - # ARPACK -# there are several sources for ARPACK, I recommend +# there are several sources for ARPACK, we recommend # https://github.com/opencollab/arpack-ng.git # and # https://github.com/m-reuter/arpackpp.git @@ -135,13 +123,6 @@ else() set(${PROJECT_NAME}_USE_ARPACK 0) endif() -# BLAS/LAPACK -find_package(BLAS REQUIRED) -find_package(LAPACK REQUIRED) -list(APPEND TPL_LIBRARIES ${LAPACK_LIBRARIES}) -list(APPEND TPL_LIBRARIES ${BLAS_LIBRARIES}) -list(APPEND TPL_LIBRARIES "gfortran") - list(REMOVE_DUPLICATES TPL_LIBRARIES) # SPE10 data (not a package, but we want it for testing) diff --git a/config/example_config_debug.sh b/config/example_config_debug.sh index 4b0e836b..3ea6e4a7 100755 --- a/config/example_config_debug.sh +++ b/config/example_config_debug.sh @@ -32,10 +32,9 @@ rm CMakeCache.txt rm -rf CMakeFiles cmake \ + -DADOPT_MFEM_DEPENDENCIES=ON \ + \ -DMFEM_DIR=/path/to/the/directory/where/mfem/is/installed \ - -DMETIS_DIR=/path/to/the/directory/where/metis/is/installed \ - -DHYPRE_DIR=/path/to/the/directory/where/hypre/is/installed \ - -DSuiteSparse_DIR=/path/to/the/directory/where/SuiteSparse/is/installed \ -DSPE10_DIR=/path/to/the/directory/where/spe_perm.dat/is/located \ \ -DMEMORYCHECK_COMMAND=/path/to/valgrind/binary \ @@ -44,8 +43,6 @@ cmake \ -DUSE_ARPACK=OFF \ \ -DCMAKE_BUILD_TYPE=Debug \ - -DBLAS_LIBRARIES=/path/to/the/blas/library/file \ - -DLAPACK_LIBRARIES=/path/to/the/lapack/library/file \ \ ${EXTRA_ARGS} \ ${BASE_DIR} diff --git a/config/example_config_release.sh b/config/example_config_release.sh index 7517a69a..34cbc241 100755 --- a/config/example_config_release.sh +++ b/config/example_config_release.sh @@ -32,10 +32,9 @@ rm CMakeCache.txt rm -rf CMakeFiles cmake \ + -DADOPT_MFEM_DEPENDENCIES=ON \ + \ -DMFEM_DIR=/path/to/the/directory/where/mfem/is/installed \ - -DMETIS_DIR=/path/to/the/directory/where/metis/is/installed \ - -DHYPRE_DIR=/path/to/the/directory/where/hypre/is/installed \ - -DSuiteSparse_DIR=/path/to/the/directory/where/SuiteSparse/is/installed \ -DSPE10_DIR=/path/to/the/directory/where/spe_perm.dat/is/located \ \ -DMEMORYCHECK_COMMAND=/path/to/valgrind/binary \ @@ -44,8 +43,6 @@ cmake \ -DUSE_ARPACK=OFF \ \ -DCMAKE_BUILD_TYPE=Release \ - -DBLAS_LIBRARIES=/path/to/the/blas/library/file \ - -DLAPACK_LIBRARIES=/path/to/the/lapack/library/file \ \ ${EXTRA_ARGS} \ ${BASE_DIR} diff --git a/config/example_config_release_with_arpack.sh b/config/example_config_release_with_arpack.sh index 4dade9f6..58dda7ce 100755 --- a/config/example_config_release_with_arpack.sh +++ b/config/example_config_release_with_arpack.sh @@ -33,9 +33,6 @@ rm -rf CMakeFiles cmake \ -DMFEM_DIR=/path/to/the/directory/where/mfem/is/installed \ - -DMETIS_DIR=/path/to/the/directory/where/metis/is/installed \ - -DHYPRE_DIR=/path/to/the/directory/where/hypre/is/installed \ - -DSuiteSparse_DIR=/path/to/the/directory/where/SuiteSparse/is/installed \ -DSPE10_DIR=/path/to/the/directory/where/spe_perm.dat/is/located \ \ -DUSE_ARPACK=ON \ @@ -43,8 +40,6 @@ cmake \ -DARPACKPP_DIR=/path/to/the/root/directory/of/arpackpp \ \ -DCMAKE_BUILD_TYPE=Release \ - -DBLAS_LIBRARIES=/path/to/the/blas/library/file \ - -DLAPACK_LIBRARIES=/path/to/the/lapack/library/file \ \ ${EXTRA_ARGS} \ ${BASE_DIR} diff --git a/explicitdependencies.cmake b/explicitdependencies.cmake new file mode 100644 index 00000000..7c59a5a9 --- /dev/null +++ b/explicitdependencies.cmake @@ -0,0 +1,51 @@ +# BHEADER #################################################################### +# +# Copyright (c) 2018, Lawrence Livermore National Security, LLC. +# Produced at the Lawrence Livermore National Laboratory. +# LLNL-CODE-745247. All Rights reserved. See file COPYRIGHT for details. +# +# This file is part of smoothG. For more information and source code +# availability, see https://www.github.com/llnl/smoothG. +# +# smoothG is free software; you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License (as published by the Free +# Software Foundation) version 2.1 dated February 1999. +# +#################################################################### EHEADER # + +set(EI_INCLUDES "") +set(EI_LIBRARIES "") + +# Hypre +find_path(HYPRE_INCLUDE_PATH HYPRE.h + HINTS ${HYPRE_DIR}/include) +list(APPEND EI_INCLUDES ${HYPRE_INCLUDE_PATH}) +set(HYPRE_LIB_NAME libHYPRE.a) +find_library(HYPRE_LIB HYPRE + ${HYPRE_DIR}/lib) +list(APPEND EI_LIBRARIES ${HYPRE_LIB}) + +# Metis +find_path(METIS_INCLUDE_PATH metis.h + HINTS ${METIS_DIR}/include) +set(METIS_LIB_NAME libmetis.a) +find_path(METIS_LIBRARY_PATH ${METIS_LIB_NAME} + ${METIS_DIR}/lib) +list(APPEND EI_INCLUDES ${METIS_INCLUDE_PATH}) +add_library(METIS_LIB STATIC IMPORTED) +set_property(TARGET METIS_LIB PROPERTY IMPORTED_LOCATION ${METIS_LIBRARY_PATH}/${METIS_LIB_NAME}) +list(APPEND EI_LIBRARIES ${METIS_LIBRARY_PATH}/${METIS_LIB_NAME}) + +# SuiteSparse +find_package(SuiteSparse REQUIRED UMFPACK KLU AMD BTF CHOLMOD COLAMD CAMD CCOLAMD config) +list(APPEND EI_INCLUDES ${SuiteSparse_INCLUDE_DIRS}) +list(APPEND EI_LIBRARIES ${SuiteSparse_LIBRARIES}) + +# BLAS/LAPACK +find_package(BLAS REQUIRED) +find_package(LAPACK REQUIRED) +list(APPEND EI_LIBRARIES ${LAPACK_LIBRARIES}) +list(APPEND EI_LIBRARIES ${BLAS_LIBRARIES}) +list(APPEND EI_LIBRARIES "gfortran") + +list(REMOVE_DUPLICATES EI_LIBRARIES) diff --git a/parsemk.py b/parsemk.py new file mode 100644 index 00000000..bc2a61ed --- /dev/null +++ b/parsemk.py @@ -0,0 +1,168 @@ +# BHEADER #################################################################### +# +# Copyright (c) 2018, Lawrence Livermore National Security, LLC. +# Produced at the Lawrence Livermore National Laboratory. +# LLNL-CODE-745247. All Rights reserved. See file COPYRIGHT for details. +# +# This file is part of smoothG. For more information and source code +# availability, see https://www.github.com/llnl/smoothG. +# +# smoothG is free software; you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License (as published by the Free +# Software Foundation) version 2.1 dated February 1999. +# +#################################################################### EHEADER # + +""" +This essentially translates the config.mk file from MFEM +into a out.cmake file to import the dependencies that MFEM +uses into our configuration process. + +This was originally written to divide libraries/includes into +'packages' that were understandable by a human. At some point +we gave up on that and just threw everything into a pile of +include and link flags. +""" +from __future__ import print_function +from __future__ import division + +import sys + + +def matchopencheck(item, op): + if len(item) > len(op) and item[:len(op)] == op: + return True + else: + return False + + +def matchopen(item, op, l): + b = matchopencheck(item, op) + if b: + l.append(item[len(op):]) + return b + + +def name_package(p, expected_names): + """ + loop order here together with order of + expected_names expresses the naming preference I want + (ie, I want ["HYPRE", "lapack", "blas"] to be named "HYPRE", not "lapack") + """ + for en in expected_names: + for l in p["libraries"]: + if en == l: + p["name"] = en + return + p["name"] = "unexpected:" + p["libraries"][0] + + +def parse_lib_line(line, status, packages, other): + rpathopen = "-Wl,-rpath," + linkpathopen = "-L" + libraryopen = "-l" + for item in line: + b = False + rp = matchopencheck(item, rpathopen) + if status == "library" and rp: + packages.append({"rpaths": [], + "linkpaths": [], + "libraries": []}) + if rp: + status = "rpath" + b = b or matchopen(item, rpathopen, packages[-1]["rpaths"]) + lp = matchopen(item, linkpathopen, packages[-1]["linkpaths"]) + if lp: + status = "library" + b = b or lp + b = b or matchopen(item, libraryopen, packages[-1]["libraries"]) + if item == "$(MFEM_EXT_LIBS)": + b = True + if not b: + other.append(item) + + +def parse_packages(filename="config.mk", verbose=False): + other = [] + packages = [{"rpaths": [], + "linkpaths": [], + "libraries": []}] + alt_packages = [{"rpaths": [], + "linkpaths": [], + "libraries": []}] + includes = [] + status = "begin" + found_ext_libs = False + with open(filename, "r") as fd: + print("parsemk.py: Found config file", filename) + for line in fd: + p = line.split() + if len(p) > 0 and p[0] == "MFEM_TPLFLAGS": + print("parsemk.py: Found MFEM_TPLFLAGS") + for item in p[2:]: + if len(item) > 2 and item[0:2] == "-I": + includes.append(item[2:]) + if len(p) > 0 and p[0] == "MFEM_EXT_LIBS": + found_ext_libs = True + print("parsemk.py: Found MFEM_EXT_LIBS.") + parse_lib_line(p[2:], status, packages, other) + if len(p) > 0 and p[0] == "MFEM_LIBS": + print("parsemk.py: Found MFEM_LIBS.") + parse_lib_line(p[2:], status, alt_packages, other) + if not found_ext_libs: + packages = alt_packages + if len(other) > 0: + print("WARNING: could not parse external MFEM libraries: " + "did not understand following tokens:") + for o in other: + print(" ", o) + if len(packages) == 0: + print("WARNING: did not find any external MFEM libraries!") + expected_names = ["HYPRE", "metis", "suitesparseconfig", + "unwind", "z", "lapack"] + if len(packages) == 0 or len(includes) == 0: + print("WARNING: could not parse config.mk!") + for p in packages: + name_package(p, expected_names) + if verbose: + print("packages:") + for p in packages: + print("\n ", p["name"]) + print(" ", "rpaths:") + for r in p["rpaths"]: + print(" ", r) + print(" ", "linkpaths:") + for l in p["linkpaths"]: + print(" ", l) + print(" ", "libraries:") + for l in p["libraries"]: + print(" ", l) + return packages, includes + + +def save_cmake_packages(packages, includes, filename="out.cmake"): + with open(filename, "w") as fd: + fd.write('set(MK_INCLUDES "")\n\n') + for i in includes: + fd.write("list(APPEND MK_INCLUDES " + i + ")\n") + fd.write("\n") + fd.write('set(MK_LIBRARIES "")\n\n') + for p in packages: + fd.write("# " + p["name"] + "\n") + for l in p["libraries"]: + cmake_name = l + "_LIB" + fd.write("find_library(" + cmake_name + " " + l + " PATHS ") + for lp in p["linkpaths"]: + fd.write(lp + " ") + fd.write(")\n") + fd.write("list(APPEND MK_LIBRARIES ${" + cmake_name + "})\n") + fd.write("\n") + fd.write("list(REMOVE_DUPLICATES MK_LIBRARIES)\n") + + +if __name__ == "__main__": + if len(sys.argv) > 1: + packages, includes = parse_packages(filename=sys.argv[1], verbose=False) + else: + packages, includes = parse_packages(verbose=False) + save_cmake_packages(packages, includes)