From 1cd4dc1eeff622aa5d93eeba68118826fbb2abbc Mon Sep 17 00:00:00 2001 From: Radovan Bast Date: Fri, 22 May 2015 14:14:15 +0200 Subject: [PATCH] initial sandbox version --- LICENSE | 4 +- README.md | 62 +++- bootstrap.py | 314 ++++++++++++++++ compiler_flags/Clang.C.cmake | 5 + compiler_flags/Clang.CXX.cmake | 5 + compiler_flags/GNU.C.cmake | 5 + compiler_flags/GNU.CXX.cmake | 5 + compiler_flags/GNU.Fortran.cmake | 5 + compiler_flags/Intel.C.cmake | 5 + compiler_flags/Intel.CXX.cmake | 5 + compiler_flags/Intel.Fortran.cmake | 5 + compiler_flags/PGI.C.cmake | 5 + compiler_flags/PGI.CXX.cmake | 5 + compiler_flags/PGI.Fortran.cmake | 5 + compiler_flags/XL.C.cmake | 5 + compiler_flags/XL.CXX.cmake | 5 + compiler_flags/XL.Fortran.cmake | 5 + doc/doc.rst | 6 + example/cframe.cfg | 3 + lib/config.py | 122 ++++++ modules/CheckFortranSourceCompiles.cmake | 111 ++++++ modules/UseBuildInfo.cmake | 137 +++++++ modules/UseC.cmake | 13 + modules/UseCPP.cmake | 7 + modules/UseCXX.cmake | 13 + modules/UseCodeCoverage.cmake | 18 + modules/UseFortran.cmake | 15 + modules/UseInt64.cmake | 18 + modules/UseMPI.cmake | 12 + modules/UseMathLibs.cmake | 451 +++++++++++++++++++++++ modules/UseOMP.cmake | 9 + modules/UsePackager.cmake | 1 + modules/UseSafeGuards.cmake | 19 + modules/UseStaticLinking.cmake | 24 ++ 34 files changed, 1425 insertions(+), 4 deletions(-) create mode 100755 bootstrap.py create mode 100644 compiler_flags/Clang.C.cmake create mode 100644 compiler_flags/Clang.CXX.cmake create mode 100644 compiler_flags/GNU.C.cmake create mode 100644 compiler_flags/GNU.CXX.cmake create mode 100644 compiler_flags/GNU.Fortran.cmake create mode 100644 compiler_flags/Intel.C.cmake create mode 100644 compiler_flags/Intel.CXX.cmake create mode 100644 compiler_flags/Intel.Fortran.cmake create mode 100644 compiler_flags/PGI.C.cmake create mode 100644 compiler_flags/PGI.CXX.cmake create mode 100644 compiler_flags/PGI.Fortran.cmake create mode 100644 compiler_flags/XL.C.cmake create mode 100644 compiler_flags/XL.CXX.cmake create mode 100644 compiler_flags/XL.Fortran.cmake create mode 100644 doc/doc.rst create mode 100644 example/cframe.cfg create mode 100644 lib/config.py create mode 100644 modules/CheckFortranSourceCompiles.cmake create mode 100644 modules/UseBuildInfo.cmake create mode 100644 modules/UseC.cmake create mode 100644 modules/UseCPP.cmake create mode 100644 modules/UseCXX.cmake create mode 100644 modules/UseCodeCoverage.cmake create mode 100644 modules/UseFortran.cmake create mode 100644 modules/UseInt64.cmake create mode 100644 modules/UseMPI.cmake create mode 100644 modules/UseMathLibs.cmake create mode 100644 modules/UseOMP.cmake create mode 100644 modules/UsePackager.cmake create mode 100644 modules/UseSafeGuards.cmake create mode 100644 modules/UseStaticLinking.cmake diff --git a/LICENSE b/LICENSE index 5d2aa44..ffcecb3 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015, scisoft +Copyright (c) 2015, Scisoft All rights reserved. Redistribution and use in source and binary forms, with or without @@ -11,7 +11,7 @@ modification, are permitted provided that the following conditions are met: this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -* Neither the name of autocmake nor the names of its +* Neither the name of Autocmake nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/README.md b/README.md index 85543dc..38c017a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,60 @@ -# autocmake -CMake plugin composer. +# Autocmake + +A CMake plugin composer. + +## Bootstrapping a new project + +Bootstrap a CFrame infrastructure out of "nothing": + + mkdir cmake # does not have to be called "cmake" - take the name you prefer + cd cmake + wget https://github.com/scisoft/autocmake/raw/master/bootstrap.py + python bootstrap.py --init + +This downloads and creates the following files: + + cmake/ + ├── bootstrap.py # no need to edit + ├── cframe.cfg # edit this file + └── lib/ + ├── config.py # no need to edit + └── docopt.py # no need to edit + +If you use version control, then now is a good moment to status/diff/add +the newly created files. + +## Creating the CMake infrastructure + +Then edit ``cframe.cfg`` and run the ``bootstrap.py`` script which +creates ``CMakeLists.txt`` and ``setup.py`` in the path specified (here ".."): + + python bootstrap.py .. + +The script also copies or downloads CMake modules specified in ``cframe.cfg`` to a directory +called ``modules/``: + + cmake/ + ├── bootstrap.py + ├── cframe.cfg + └── lib/ + ├── config.py + └── docopt.py + └── modules/ # CMakeLists.txt includes CMake modules from this directory + +Now you have ``CMakeLists.txt`` and ``setup.py`` in the project root and you can build +the project: + + cd .. + python setup.py [-h] + cd build + make + +## Customizing the CMake modules + +The CMake modules can be customized directly inside ``modules/`` but this is +not very convenient as the customizations may be overwritten by the +``boostrap.py`` script. + +A better solution is to download the CMake modules that you wish you customize +to a separate directory and source the customized CMake modules in +``cframe.cfg``. diff --git a/bootstrap.py b/bootstrap.py new file mode 100755 index 0000000..d81c4f8 --- /dev/null +++ b/bootstrap.py @@ -0,0 +1,314 @@ +#!/usr/bin/env python + +import os +import sys +import urllib +import shutil +import tempfile +from collections import OrderedDict +from ConfigParser import ConfigParser + + +CFRAME_GITHUB_URL = 'https://github.com/scisoft/autocmake' + + +class URLopener(urllib.FancyURLopener): + def http_error_default(self, url, fp, errcode, errmsg, headers): + sys.stderr.write("ERROR: could not fetch %s\n" % url) + sys.exit(-1) + + +def fetch_url(src, dst, fail_if_dst_exists=False): + """ + Fetch file from URL src and save it to dst. + """ + dirname = os.path.dirname(dst) + if dirname != '': + if not os.path.isdir(dirname): + os.makedirs(dirname) + + if os.path.isfile(dst): + if fail_if_dst_exists: + sys.stderr.write("ERROR: %s already exists - aborting\n" % dst) + sys.exit(-1) + + opener = URLopener() + opener.retrieve(src, dst) + + +def print_progress_bar(text, done, total, width): + """ + Print progress bar. + """ + n = int(float(width)*float(done)/float(total)) + sys.stdout.write("\r%s [%s%s] (%i/%i)" % (text, '#'*n, + ' '*(width-n), done, total)) + sys.stdout.flush() + + +def align_options(options): + """ + Indendts flags and aligns help texts. + """ + l = 0 + for opt in options: + if len(opt[0]) > l: + l = len(opt[0]) + s = [] + for opt in options: + s.append(' %s%s %s' % (opt[0], ' '*(l - len(opt[0])), opt[1])) + return '\n'.join(s) + + +def gen_cmake_command(config): + """ + Generate CMake command. + """ + s = [] + + s.append("\n\ndef gen_cmake_command(options, arguments):") + s.append(' """') + s.append(" Generate CMake command based on options and arguments.") + s.append(' """') + s.append(" command = []") + + # take care of environment variables + for section in config.sections(): + if config.has_option(section, 'export'): + for env in config.get(section, 'export').split('\n'): + s.append(' command.append(%s)' % env) + + s.append(" command.append('cmake')") + + # take care of cmake definitions + for section in config.sections(): + if config.has_option(section, 'define'): + for definition in config.get(section, 'define').split('\n'): + s.append(' command.append(%s)' % definition) + + s.append("\n return ' '.join(command)") + + return '\n'.join(s) + + +def gen_setup(config, relative_path): + """ + Generate setup.py script. + """ + s = [] + s.append('#!/usr/bin/env python') + s.append('\nimport os') + s.append('import sys') + + s.append("\nsys.path.append('%s')" % os.path.join(relative_path, 'lib')) + s.append('from config import configure') + s.append('from docopt import docopt') + + s.append('\n\noptions = """') + s.append('Usage:') + s.append(' ./setup.py [options] []') + s.append(' ./setup.py (-h | --help)') + s.append('\nOptions:') + + options = [] + for section in config.sections(): + if config.has_option(section, 'docopt'): + for opt in config.get(section, 'docopt').split('\n'): + first = opt.split()[0].strip() + rest = ' '.join(opt.split()[1:]).strip() + options.append([first, rest]) + + options.append(['--show', 'Show CMake command and exit.']) + options.append(['', 'Build directory.']) + options.append(['-h --help', 'Show this screen.']) + + s.append(align_options(options)) + + s.append('"""') + + s.append(gen_cmake_command(config)) + + s.append("\n\narguments = docopt(options, argv=None)") + s.append("\nroot_directory = os.path.dirname(os.path.realpath(__file__))") + s.append("build_path = arguments['']") + s.append("cmake_command = '%s %s' % (gen_cmake_command(options, arguments), root_directory)") + s.append("configure(root_directory, build_path, cmake_command, arguments['--show'])") + + return s + + +def gen_cmakelists(config, relative_path, list_of_modules): + """ + Generate CMakeLists.txt. + """ + if not config.has_option('project', 'name'): + sys.stderr.write("ERROR: you have to specify the project name\n") + sys.stderr.write(" in cframe.cfg under [project]\n") + sys.exit(-1) + project_name = config.get('project', 'name') + + s = [] + + s.append('# set minimum cmake version') + s.append('cmake_minimum_required(VERSION 2.8 FATAL_ERROR)') + + s.append('\n') + s.append('project(%s)' % project_name) + + s.append('\n') + s.append('# do not rebuild if rules (compiler flags) change') + s.append('set(CMAKE_SKIP_RULE_DEPENDENCY TRUE)') + + s.append('\n') + s.append('# directory which holds enabled cmake modules') + s.append('set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}') + s.append(' ${PROJECT_SOURCE_DIR}/%s)' % os.path.join(relative_path, 'modules')) + + s.append('\n') + s.append('# guards against in-source builds and bad build types') + s.append('if(NOT CMAKE_BUILD_TYPE)') + s.append(' set(CMAKE_BUILD_TYPE "Debug")') + s.append('endif()') + + s.append('\n') + s.append('# python interpreter is required at many') + s.append('# places during configuration and build') + s.append('find_package(PythonInterp REQUIRED)') + + s.append('\n') + s.append('# determine program version from file, example: "14.1"') + s.append('# the reason why this information is stored') + s.append('# in a file and not as cmake variable') + s.append('# is that cmake-unaware programs can') + s.append('# parse and use it (e.g. Sphinx)') + s.append('file(READ "${PROJECT_SOURCE_DIR}/VERSION" PROGRAM_VERSION)') + s.append('string(STRIP "${PROGRAM_VERSION}" PROGRAM_VERSION)') + + s.append('\n') + s.append('# generated cmake files will be written to this path') + s.append('# only build info is generated') + s.append('# everything else is static for the user') + s.append('file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/generated_by_cmake)') + s.append('set(CMAKE_MODULE_PATH') + s.append(' ${CMAKE_MODULE_PATH}') + s.append(' ${PROJECT_BINARY_DIR}/generated_by_cmake') + s.append(' )') + + s.append('\n') + s.append('# included cmake modules') + for m in list_of_modules: + s.append('include(%s)' % os.path.splitext(m)[0]) + + return s + + +def fetch_modules(config, module_directory): + """ + Fetch modules either from remote URLs or from relative paths + and save them to module_directory from which they will + be included in CMakeLists.txt. + """ + if not os.path.exists(module_directory): + os.makedirs(module_directory) + + n = len(filter(lambda x: config.has_option(x, 'source'), + config.sections())) + + i = 0 + print_progress_bar(text='- fetching modules:', done=0, total=n, width=30) + list_of_modules = [] + for section in config.sections(): + if config.has_option(section, 'source'): + for src in config.get(section, 'source').split('\n'): + module_name = os.path.basename(src) + list_of_modules.append(module_name) + dst = os.path.join(module_directory, module_name) + if 'http' in src: + fetch_url(src, dst) + else: + if os.path.exists(src): + shutil.copyfile(src, dst) + else: + sys.stderr.write("ERROR: %s does not exist\n" % src) + sys.exit(-1) + i += 1 + print_progress_bar( + text='- fetching modules:', + done=i, + total=n, + width=30 + ) + print('') + return list_of_modules + + +def main(argv): + """ + Main function. + """ + if len(argv) != 2: + sys.stderr.write("\nYou can bootstrap a project in two steps.\n") + sys.stderr.write("First step is typically done only once.\n") + sys.stderr.write("Second step can be repeated many time without re-running the first step.\n\n") + sys.stderr.write("Step 1:\n") + sys.stderr.write("Create an example cframe.cfg and other infrastructure files\n") + sys.stderr.write("which will be needed to configure and build the project:\n") + sys.stderr.write("$ %s --init\n\n" % argv[0]) + sys.stderr.write("Step 2:\n") + sys.stderr.write("Create CMakeLists.txt and setup.py in PROJECT_ROOT:\n") + sys.stderr.write("$ %s PROJECT_ROOT\n" % argv[0]) + sys.stderr.write("example:\n") + sys.stderr.write("$ %s ..\n" % argv[0]) + sys.exit(-1) + + if argv[1] == '--init': + # empty project, create infrastructure files + print('- fetching example cframe.cfg') + fetch_url( + src='%s/raw/master/example/cframe.cfg' % CFRAME_GITHUB_URL, + dst='cframe.cfg', + fail_if_dst_exists=True + ) + print('- fetching lib/config.py') + fetch_url( + src='%s/raw/master/lib/config.py' % CFRAME_GITHUB_URL, + dst='lib/config.py' + ) + print('- fetching lib/docopt.py') + fetch_url( + src='https://github.com/docopt/docopt/raw/master/docopt.py', + dst='lib/docopt.py' + ) + sys.exit(0) + + project_root = argv[1] + if not os.path.isdir(project_root): + sys.stderr.write("ERROR: %s is not a directory\n" % project_root) + sys.exit(-1) + + # read config file + print('- parsing cframe.cfg') + config = ConfigParser(dict_type=OrderedDict) + config.read('cframe.cfg') + + # fetch modules from the web or from relative paths + list_of_modules = fetch_modules(config, module_directory='modules') + + # get relative path from setup.py script to this directory + relative_path = os.path.relpath(os.path.abspath('.'), project_root) + + # create CMakeLists.txt + print('- generating CMakeLists.txt') + s = gen_cmakelists(config, relative_path, list_of_modules) + with open(os.path.join(project_root, 'CMakeLists.txt'), 'w') as f: + f.write('%s\n' % '\n'.join(s)) + + # create setup.py + print('- generating setup.py') + s = gen_setup(config, relative_path) + with open(os.path.join(project_root, 'setup.py'), 'w') as f: + f.write('%s\n' % '\n'.join(s)) + + +if __name__ == '__main__': + main(sys.argv) diff --git a/compiler_flags/Clang.C.cmake b/compiler_flags/Clang.C.cmake new file mode 100644 index 0000000..56d2142 --- /dev/null +++ b/compiler_flags/Clang.C.cmake @@ -0,0 +1,5 @@ +if(CMAKE_C_COMPILER_ID MATCHES Clang) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") + set(CMAKE_C_FLAGS_RELEASE "-O2 -Wno-unused") + set(CMAKE_C_FLAGS_DEBUG "-O0") +endif() diff --git a/compiler_flags/Clang.CXX.cmake b/compiler_flags/Clang.CXX.cmake new file mode 100644 index 0000000..3e2d9ba --- /dev/null +++ b/compiler_flags/Clang.CXX.cmake @@ -0,0 +1,5 @@ +if(CMAKE_CXX_COMPILER_ID MATCHES Clang) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -Wno-unknown-pragmas -Wno-sign-compare -Woverloaded-virtual -Wwrite-strings -Wno-unused") + set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -march=native -DNDEBUG -Wno-unused") + set(CMAKE_CXX_FLAGS_DEBUG "-O0 -DDEBUG") +endif() diff --git a/compiler_flags/GNU.C.cmake b/compiler_flags/GNU.C.cmake new file mode 100644 index 0000000..ba295cd --- /dev/null +++ b/compiler_flags/GNU.C.cmake @@ -0,0 +1,5 @@ +if(CMAKE_C_COMPILER_ID MATCHES GNU) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") + set(CMAKE_C_FLAGS_RELEASE "-O2 -Wno-unused") + set(CMAKE_C_FLAGS_DEBUG "-O0") +endif() diff --git a/compiler_flags/GNU.CXX.cmake b/compiler_flags/GNU.CXX.cmake new file mode 100644 index 0000000..510b2d9 --- /dev/null +++ b/compiler_flags/GNU.CXX.cmake @@ -0,0 +1,5 @@ +if(CMAKE_CXX_COMPILER_ID MATCHES GNU) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -Wno-unknown-pragmas -Wno-sign-compare -Woverloaded-virtual -Wwrite-strings -Wno-unused") + set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -march=native -DNDEBUG -Wno-unused") + set(CMAKE_CXX_FLAGS_DEBUG "-O0 -DDEBUG") +endif() diff --git a/compiler_flags/GNU.Fortran.cmake b/compiler_flags/GNU.Fortran.cmake new file mode 100644 index 0000000..ce9df69 --- /dev/null +++ b/compiler_flags/GNU.Fortran.cmake @@ -0,0 +1,5 @@ +if(CMAKE_Fortran_COMPILER_ID MATCHES GNU) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -g -fbacktrace") + set(CMAKE_Fortran_FLAGS_RELEASE "-O3 -funroll-all-loops -w") + set(CMAKE_Fortran_FLAGS_DEBUG "-O0") +endif() diff --git a/compiler_flags/Intel.C.cmake b/compiler_flags/Intel.C.cmake new file mode 100644 index 0000000..9931140 --- /dev/null +++ b/compiler_flags/Intel.C.cmake @@ -0,0 +1,5 @@ +if(CMAKE_C_COMPILER_ID MATCHES Intel) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") + set(CMAKE_C_FLAGS_RELEASE "-O3") + set(CMAKE_C_FLAGS_DEBUG "-O0") +endif() diff --git a/compiler_flags/Intel.CXX.cmake b/compiler_flags/Intel.CXX.cmake new file mode 100644 index 0000000..363ff39 --- /dev/null +++ b/compiler_flags/Intel.CXX.cmake @@ -0,0 +1,5 @@ +if(CMAKE_CXX_COMPILER_ID MATCHES Intel) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-pragmas") + set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") + set(CMAKE_CXX_FLAGS_DEBUG "-O0 -debug -DDEBUG") +endif() diff --git a/compiler_flags/Intel.Fortran.cmake b/compiler_flags/Intel.Fortran.cmake new file mode 100644 index 0000000..2d857a7 --- /dev/null +++ b/compiler_flags/Intel.Fortran.cmake @@ -0,0 +1,5 @@ +if(CMAKE_Fortran_COMPILER_ID MATCHES Intel) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -w -assume byterecl -g -traceback") + set(CMAKE_Fortran_FLAGS_RELEASE "-O3 -ip") + set(CMAKE_Fortran_FLAGS_DEBUG "-O0") +endif() diff --git a/compiler_flags/PGI.C.cmake b/compiler_flags/PGI.C.cmake new file mode 100644 index 0000000..552dd7d --- /dev/null +++ b/compiler_flags/PGI.C.cmake @@ -0,0 +1,5 @@ +if(CMAKE_C_COMPILER_ID MATCHES PGI) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") + set(CMAKE_C_FLAGS_RELEASE "-O3") + set(CMAKE_C_FLAGS_DEBUG "-O0") +endif() diff --git a/compiler_flags/PGI.CXX.cmake b/compiler_flags/PGI.CXX.cmake new file mode 100644 index 0000000..fd014e6 --- /dev/null +++ b/compiler_flags/PGI.CXX.cmake @@ -0,0 +1,5 @@ +if(CMAKE_CXX_COMPILER_ID MATCHES PGI) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") + set(CMAKE_CXX_FLAGS_RELEASE "-O3") + set(CMAKE_CXX_FLAGS_DEBUG "-O0") +endif() diff --git a/compiler_flags/PGI.Fortran.cmake b/compiler_flags/PGI.Fortran.cmake new file mode 100644 index 0000000..9648f5f --- /dev/null +++ b/compiler_flags/PGI.Fortran.cmake @@ -0,0 +1,5 @@ +if(CMAKE_Fortran_COMPILER_ID MATCHES PGI) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}") + set(CMAKE_Fortran_FLAGS_RELEASE "-O3") + set(CMAKE_Fortran_FLAGS_DEBUG "-g") +endif() diff --git a/compiler_flags/XL.C.cmake b/compiler_flags/XL.C.cmake new file mode 100644 index 0000000..5afd485 --- /dev/null +++ b/compiler_flags/XL.C.cmake @@ -0,0 +1,5 @@ +if(CMAKE_C_COMPILER_ID MATCHES XL) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -qcpluscmt") + set(CMAKE_C_FLAGS_RELEASE "-O3") + set(CMAKE_C_FLAGS_DEBUG "-O0") +endif() diff --git a/compiler_flags/XL.CXX.cmake b/compiler_flags/XL.CXX.cmake new file mode 100644 index 0000000..6dad9c8 --- /dev/null +++ b/compiler_flags/XL.CXX.cmake @@ -0,0 +1,5 @@ +if(CMAKE_CXX_COMPILER_ID MATCHES XL) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") + set(CMAKE_CXX_FLAGS_RELEASE "-O3") + set(CMAKE_CXX_FLAGS_DEBUG "-O0") +endif() diff --git a/compiler_flags/XL.Fortran.cmake b/compiler_flags/XL.Fortran.cmake new file mode 100644 index 0000000..cfa260f --- /dev/null +++ b/compiler_flags/XL.Fortran.cmake @@ -0,0 +1,5 @@ +if(CMAKE_Fortran_COMPILER_ID MATCHES XL) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -qzerosize -qextname -qsuppress=cmpmsg") + set(CMAKE_Fortran_FLAGS_RELEASE "-O3") + set(CMAKE_Fortran_FLAGS_DEBUG "-g") +endif() diff --git a/doc/doc.rst b/doc/doc.rst new file mode 100644 index 0000000..81e4605 --- /dev/null +++ b/doc/doc.rst @@ -0,0 +1,6 @@ + + +Title +----- + +Write me ... diff --git a/example/cframe.cfg b/example/cframe.cfg new file mode 100644 index 0000000..d65c11f --- /dev/null +++ b/example/cframe.cfg @@ -0,0 +1,3 @@ +# uncomment and set project name +# [project] +# name: myproject diff --git a/lib/config.py b/lib/config.py new file mode 100644 index 0000000..a2f0cd0 --- /dev/null +++ b/lib/config.py @@ -0,0 +1,122 @@ + +# Copyright (c) 2015 by Radovan Bast and Jonas Juselius +# see https://github.com/scisoft/cframe/blob/master/LICENSE + + +import subprocess +import os +import sys +import shutil + + +def check_cmake_exists(cmake_command): + """ + Check whether CMake is installed. If not, print + informative error message and quits. + """ + p = subprocess.Popen('%s --version' % cmake_command, + shell=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + if not ('cmake version' in p.communicate()[0]): + sys.stderr.write(' This code is built using CMake\n\n') + sys.stderr.write(' CMake is not found\n') + sys.stderr.write(' get CMake at http://www.cmake.org/\n') + sys.stderr.write(' on many clusters CMake is installed\n') + sys.stderr.write(' but you have to load it first:\n') + sys.stderr.write(' $ module load cmake\n') + sys.exit(1) + + +def setup_build_path(build_path): + """ + Create build directory. If this already exists, print informative + error message and quit. + """ + if os.path.isdir(build_path): + fname = os.path.join(build_path, 'CMakeCache.txt') + if os.path.exists(fname): + sys.stderr.write('aborting setup\n') + sys.stderr.write('build directory %s which contains CMakeCache.txt already exists\n' % build_path) + sys.stderr.write('remove the build directory and then rerun setup\n') + sys.exit(1) + else: + os.makedirs(build_path, 0755) + + +def run_cmake(command, build_path, default_build_path): + """ + Execute CMake command. + """ + topdir = os.getcwd() + os.chdir(build_path) + p = subprocess.Popen( + command, + shell=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE + ) + s = p.communicate()[0] + # print cmake output to screen + print(s) + # write cmake output to file + f = open('cmake_output', 'w') + f.write(s) + f.close() + # change directory and return + os.chdir(topdir) + if 'Configuring incomplete' in s: + # configuration was not successful + if (build_path == default_build_path): + # remove build_path iff not set by the user + # otherwise removal can be dangerous + shutil.rmtree(default_build_path) + else: + # configuration was successful + save_configure_command(sys.argv, build_path) + print_build_help(build_path, default_build_path) + + +def print_build_help(build_path, default_build_path): + """ + Print help text after configuration step is done. + """ + print(' configure step is done') + print(' now you need to compile the sources:') + if (build_path == default_build_path): + print(' $ cd build') + else: + print(' $ cd ' + build_path) + print(' $ make') + + +def save_configure_command(argv, build_path): + """ + Save configure command to a file. + """ + file_name = os.path.join(build_path, 'configure_command') + f = open(file_name, 'w') + f.write(' '.join(argv[:]) + '\n') + f.close() + + +def configure(root_directory, build_path, cmake_command, only_show): + """ + Main configure function. + """ + default_build_path = os.path.join(root_directory, 'build') + + # check that CMake is available, if not stop + check_cmake_exists('cmake') + + # deal with build path + if build_path is None: + build_path = default_build_path + if not only_show: + setup_build_path(build_path) + + print('%s\n' % cmake_command) + if only_show: + sys.exit(0) + + run_cmake(cmake_command, build_path, default_build_path) diff --git a/modules/CheckFortranSourceCompiles.cmake b/modules/CheckFortranSourceCompiles.cmake new file mode 100644 index 0000000..38ad164 --- /dev/null +++ b/modules/CheckFortranSourceCompiles.cmake @@ -0,0 +1,111 @@ +#.rst: +# CheckFortranSourceCompiles +# -------------------------- +# +# Check if given Fortran source compiles and links into an executable:: +# +# CHECK_Fortran_SOURCE_COMPILES( [FAIL_REGEX ]) +# +# The arguments are: +# +# ```` +# Source code to try to compile. It must define a PROGRAM entry point. +# ```` +# Variable to store whether the source code compiled. +# Will be created as an internal cache variable. +# ```` +# Fail if test output matches this regex. +# +# The following variables may be set before calling this macro to modify +# the way the check is run:: +# +# CMAKE_REQUIRED_FLAGS = string of compile command line flags +# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) +# CMAKE_REQUIRED_INCLUDES = list of include directories +# CMAKE_REQUIRED_LIBRARIES = list of libraries to link +# CMAKE_REQUIRED_QUIET = execute quietly without messages + +#============================================================================= +# Copyright 2005-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + + + +macro(CHECK_Fortran_SOURCE_COMPILES SOURCE VAR) + if(NOT DEFINED "${VAR}") + set(_FAIL_REGEX) + set(_key) + foreach(arg ${ARGN}) + if("${arg}" MATCHES "^(FAIL_REGEX)$") + set(_key "${arg}") + elseif(_key) + list(APPEND _${_key} "${arg}") + else() + message(FATAL_ERROR "Unknown argument:\n ${arg}\n") + endif() + endforeach() + set(MACRO_CHECK_FUNCTION_DEFINITIONS + "-D${VAR} ${CMAKE_REQUIRED_FLAGS}") + if(CMAKE_REQUIRED_LIBRARIES) + set(CHECK_Fortran_SOURCE_COMPILES_ADD_LIBRARIES + LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) + else() + set(CHECK_Fortran_SOURCE_COMPILES_ADD_LIBRARIES) + endif() + if(CMAKE_REQUIRED_INCLUDES) + set(CHECK_Fortran_SOURCE_COMPILES_ADD_INCLUDES + "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") + else() + set(CHECK_Fortran_SOURCE_COMPILES_ADD_INCLUDES) + endif() + file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.F90" + "${SOURCE}\n") + + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VAR}") + endif() + try_compile(${VAR} + ${CMAKE_BINARY_DIR} + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.F90 + COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} + ${CHECK_Fortran_SOURCE_COMPILES_ADD_LIBRARIES} + CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} + "${CHECK_Fortran_SOURCE_COMPILES_ADD_INCLUDES}" + OUTPUT_VARIABLE OUTPUT) + + foreach(_regex ${_FAIL_REGEX}) + if("${OUTPUT}" MATCHES "${_regex}") + set(${VAR} 0) + endif() + endforeach() + + if(${VAR}) + set(${VAR} 1 CACHE INTERNAL "Test ${VAR}") + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VAR} - Success") + endif() + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Performing Fortran SOURCE FILE Test ${VAR} succeded with the following output:\n" + "${OUTPUT}\n" + "Source file was:\n${SOURCE}\n") + else() + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VAR} - Failed") + endif() + set(${VAR} "" CACHE INTERNAL "Test ${VAR}") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Performing Fortran SOURCE FILE Test ${VAR} failed with the following output:\n" + "${OUTPUT}\n" + "Source file was:\n${SOURCE}\n") + endif() + endif() +endmacro() diff --git a/modules/UseBuildInfo.cmake b/modules/UseBuildInfo.cmake new file mode 100644 index 0000000..7896acc --- /dev/null +++ b/modules/UseBuildInfo.cmake @@ -0,0 +1,137 @@ +# Copyright (c) 2015 by Radovan Bast and Jonas Juselius +# see https://github.com/scisoft/cframe/blob/master/LICENSE + +#------------------------------------------------------------------------------- + +function(get_git_info + in_python_executable + out_git_last_commit_hash + out_git_last_commit_author + out_git_last_commit_date + out_git_branch + out_git_status_at_build) + + find_package(Git) + if(GIT_FOUND) + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-list --max-count=1 --abbrev-commit HEAD + OUTPUT_VARIABLE _git_last_commit_hash + ERROR_QUIET + ) + + if(_git_last_commit_hash) + string(STRIP ${_git_last_commit_hash} _git_last_commit_hash) + endif() + + execute_process( + COMMAND ${GIT_EXECUTABLE} log --max-count=1 HEAD + OUTPUT_VARIABLE _git_last_commit + ERROR_QUIET + ) + + if(_git_last_commit) + string(REGEX MATCH "Author:[ ]*(.+)<" temp "${_git_last_commit}") + set(_git_last_commit_author ${CMAKE_MATCH_1}) + string(REGEX MATCH "Date:[ ]*(.+(\\+|-)[0-9][0-9][0-9][0-9])" temp "${_git_last_commit}") + set(_git_last_commit_date ${CMAKE_MATCH_1}) + endif() + + execute_process( + COMMAND ${in_python_executable} -c "import subprocess; import re; print(re.search(r'\\*.*', subprocess.Popen(['${GIT_EXECUTABLE}', 'branch'], stdout=subprocess.PIPE).communicate()[0], re.MULTILINE).group())" + OUTPUT_VARIABLE _git_branch + ERROR_QUIET + ) + + if(_git_branch) + string(REPLACE "*" "" _git_branch ${_git_branch}) + string(STRIP ${_git_branch} _git_branch) + endif() + + execute_process( + COMMAND ${GIT_EXECUTABLE} status -uno + OUTPUT_VARIABLE _git_status_at_build + ERROR_QUIET + ) + + set(${out_git_last_commit_hash} ${_git_last_commit_hash} PARENT_SCOPE) + set(${out_git_last_commit_author} ${_git_last_commit_author} PARENT_SCOPE) + set(${out_git_last_commit_date} ${_git_last_commit_date} PARENT_SCOPE) + set(${out_git_branch} ${_git_branch} PARENT_SCOPE) + set(${out_git_status_at_build} ${_git_status_at_build} PARENT_SCOPE) + else() + set(${out_git_last_commit_hash} "" PARENT_SCOPE) + set(${out_git_last_commit_author} "" PARENT_SCOPE) + set(${out_git_last_commit_date} "" PARENT_SCOPE) + set(${out_git_branch} "" PARENT_SCOPE) + set(${out_git_status_at_build} "" PARENT_SCOPE) + endif() +endfunction() + +get_git_info(${PYTHON_EXECUTABLE} + GIT_COMMIT_HASH + GIT_COMMIT_AUTHOR + GIT_COMMIT_DATE + GIT_BRANCH + GIT_STATUS_AT_BUILD) + +# get configuration time in UTC +execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c "import datetime; print(datetime.datetime.utcnow())" + OUTPUT_VARIABLE _configuration_time + ) +string(STRIP ${_configuration_time} _configuration_time) # delete newline + +execute_process( + COMMAND whoami + TIMEOUT 1 + OUTPUT_VARIABLE _user_name + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + +execute_process( + COMMAND hostname + TIMEOUT 1 + OUTPUT_VARIABLE _host_name + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + +get_directory_property(_list_of_definitions DIRECTORY ${PROJECT_SOURCE_DIR} COMPILE_DEFINITIONS) + +# set python version variable when it is not defined automatically +# this can happen when cmake version is equal or less than 2.8.5 +if(NOT _python_version) + execute_process( + COMMAND ${PYTHON_EXECUTABLE} -V + OUTPUT_VARIABLE _python_version + ERROR_VARIABLE _python_version + ) + string(REGEX MATCH "Python ([0-9].[0-9].[0-9])" temp "${_python_version}") + set(_python_version ${CMAKE_MATCH_1}) +endif() + +configure_file( + ${PROJECT_SOURCE_DIR}/cmake/lib/config_info.in.py + ${PROJECT_BINARY_DIR}/config_info.py + ) + +unset(_configuration_time) +unset(_user_name) +unset(_host_name) +unset(_list_of_definitions) +unset(_python_version) + +exec_program( + ${PYTHON_EXECUTABLE} + ${PROJECT_BINARY_DIR} + ARGS config_info.py Fortran > ${PROJECT_BINARY_DIR}/config_info.F90 + OUTPUT_VARIABLE _discard # we don't care about the output + ) + +exec_program( + ${PYTHON_EXECUTABLE} + ${PROJECT_BINARY_DIR} + ARGS config_info.py CMake > ${PROJECT_BINARY_DIR}/generated_by_cmake/config_info_generated.cmake + OUTPUT_VARIABLE _discard # we don't care about the output + ) + +include(config_info_generated) diff --git a/modules/UseC.cmake b/modules/UseC.cmake new file mode 100644 index 0000000..a4affc6 --- /dev/null +++ b/modules/UseC.cmake @@ -0,0 +1,13 @@ +enable_language(C) + +if(NOT DEFINED CMAKE_C_COMPILER_ID) + message(FATAL_ERROR "CMAKE_C_COMPILER_ID variable is not defined!") +endif() + +if(NOT CMAKE_C_COMPILER_WORKS) + message(FATAL_ERROR "CMAKE_C_COMPILER_WORKS is false!") +endif() + +if(DEFINED EXTRA_C_FLAGS) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_C_FLAGS}") +endif() diff --git a/modules/UseCPP.cmake b/modules/UseCPP.cmake new file mode 100644 index 0000000..62ad200 --- /dev/null +++ b/modules/UseCPP.cmake @@ -0,0 +1,7 @@ +set(CPP) + +# forward CPP directly to the code +if(NOT "${CPP}" STREQUAL "") + add_definitions(${CPP}) +endif() + diff --git a/modules/UseCXX.cmake b/modules/UseCXX.cmake new file mode 100644 index 0000000..086c27a --- /dev/null +++ b/modules/UseCXX.cmake @@ -0,0 +1,13 @@ +enable_language(CXX) + +if(NOT DEFINED CMAKE_CXX_COMPILER_ID) + message(FATAL_ERROR "CMAKE_CXX_COMPILER_ID variable is not defined!") +endif() + +if(NOT CMAKE_CXX_COMPILER_WORKS) + message(FATAL_ERROR "CMAKE_CXX_COMPILER_WORKS is false!") +endif() + +if(DEFINED EXTRA_CXX_FLAGS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXX_FLAGS}") +endif() diff --git a/modules/UseCodeCoverage.cmake b/modules/UseCodeCoverage.cmake new file mode 100644 index 0000000..9a4a06d --- /dev/null +++ b/modules/UseCodeCoverage.cmake @@ -0,0 +1,18 @@ +option(ENABLE_CODE_COVERAGE "Enable code coverage" OFF) + +if(ENABLE_CODE_COVERAGE) + if(DEFINED CMAKE_Fortran_COMPILER_ID) + if(CMAKE_Fortran_COMPILER_ID MATCHES GNU) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fprofile-arcs -ftest-coverage") + endif() + endif() + + if(DEFINED CMAKE_CXX_COMPILER_ID) + if(CMAKE_CXX_COMPILER_ID MATCHES GNU) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") + endif() + if(CMAKE_CXX_COMPILER_ID MATCHES Clang) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") + endif() + endif() +endif() diff --git a/modules/UseFortran.cmake b/modules/UseFortran.cmake new file mode 100644 index 0000000..422e601 --- /dev/null +++ b/modules/UseFortran.cmake @@ -0,0 +1,15 @@ +enable_language(Fortran) + +set(CMAKE_Fortran_MODULE_DIRECTORY ${PROJECT_BINARY_DIR}/include/fortran) + +if(NOT DEFINED CMAKE_Fortran_COMPILER_ID) + message(FATAL_ERROR "CMAKE_Fortran_COMPILER_ID variable is not defined!") +endif() + +if(NOT CMAKE_Fortran_COMPILER_WORKS) + message(FATAL_ERROR "CMAKE_Fortran_COMPILER_WORKS is false!") +endif() + +if(DEFINED EXTRA_Fortran_FLAGS) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${EXTRA_Fortran_FLAGS}") +endif() diff --git a/modules/UseInt64.cmake b/modules/UseInt64.cmake new file mode 100644 index 0000000..4e58ed9 --- /dev/null +++ b/modules/UseInt64.cmake @@ -0,0 +1,18 @@ +option(ENABLE_64BIT_INTEGERS "Enable 64-bit integers" OFF) + +if(ENABLE_64BIT_INTEGERS) + if(DEFINED CMAKE_Fortran_COMPILER_ID) + if(CMAKE_Fortran_COMPILER_ID MATCHES GNU) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fdefault-integer-8") + endif() + if(CMAKE_Fortran_COMPILER_ID MATCHES Intel) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -i8") + endif() + if(CMAKE_Fortran_COMPILER_ID MATCHES PGI) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -i8") + endif() + if(CMAKE_Fortran_COMPILER_ID MATCHES XL) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -qintsize=8 -q64") + endif() + endif() +endif() diff --git a/modules/UseMPI.cmake b/modules/UseMPI.cmake new file mode 100644 index 0000000..285fd63 --- /dev/null +++ b/modules/UseMPI.cmake @@ -0,0 +1,12 @@ +option(ENABLE_MPI "Enable MPI parallelization" OFF) + +# on Cray configure with -D MPI_FOUND=1 +if(ENABLE_MPI AND NOT MPI_FOUND) + find_package(MPI) + if(MPI_FOUND) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${MPI_COMPILE_FLAGS}") + include_directories(${MPI_INCLUDE_PATH}) + else() + message(FATAL_ERROR "-- You asked for MPI, but CMake could not find any MPI installation, check $PATH") + endif() +endif() diff --git a/modules/UseMathLibs.cmake b/modules/UseMathLibs.cmake new file mode 100644 index 0000000..53f3e3b --- /dev/null +++ b/modules/UseMathLibs.cmake @@ -0,0 +1,451 @@ + +# Copyright (c) 2015 by Radovan Bast and Jonas Juselius +# see https://github.com/scisoft/cframe/blob/master/LICENSE + +# CMake variables used: +# - MATH_LIB_SEARCH_ORDER, example: set(MATH_LIB_SEARCH_ORDER MKL ESSL ATLAS ACML SYSTEM_NATIVE) +# - ENABLE_BLAS +# - ENABLE_LAPACK +# - BLAS_FOUND +# - LAPACK_FOUND +# - BLAS_LANG +# - LAPACK_LANG +# - BLAS_TYPE +# - LAPACK_TYPE +# - ENABLE_64BIT_INTEGERS +# - CMAKE_HOST_SYSTEM_PROCESSOR +# - BLACS_IMPLEMENTATION +# - MKL_FLAG + +# Environment variables used: +# - MATH_ROOT +# - BLAS_ROOT +# - LAPACK_ROOT +# - MKL_ROOT +# - MKLROOT + +# CMake variables set: +# - MATH_LIBS +# - BLAS_FOUND +# - LAPACK_FOUND + +#------------------------------------------------------------------------------- +# SYSTEM_NATIVE + +set(SYSTEM_NATIVE_BLAS_INCLUDE_PATH_SUFFIXES) +set(SYSTEM_NATIVE_LAPACK_INCLUDE_PATH_SUFFIXES) + +set(SYSTEM_NATIVE_BLAS_HEADERS cblas.h) +set(SYSTEM_NATIVE_LAPACK_HEADERS clapack.h) + +set(SYSTEM_NATIVE_BLAS_LIBRARY_PATH_SUFFIXES) +set(SYSTEM_NATIVE_LAPACK_LIBRARY_PATH_SUFFIXES) + +set(SYSTEM_NATIVE_BLAS_LIBS blas) +set(SYSTEM_NATIVE_LAPACK_LIBS lapack) + +#------------------------------------------------------------------------------- +# ESSL + +set(ESSL_BLAS_INCLUDE_PATH_SUFFIXES) +set(ESSL_LAPACK_INCLUDE_PATH_SUFFIXES) + +set(ESSL_BLAS_HEADERS UNKNOWN) +set(ESSL_LAPACK_HEADERS UNKNOWN) + +set(ESSL_BLAS_LIBRARY_PATH_SUFFIXES) +set(ESSL_LAPACK_LIBRARY_PATH_SUFFIXES) + +if(ENABLE_64BIT_INTEGERS) + set(ESSL_BLAS_LIBS esslsmp6464) + set(ESSL_LAPACK_LIBS esslsmp6464) +else() + set(ESSL_BLAS_LIBS essl) + set(ESSL_LAPACK_LIBS essl) +endif() + +#------------------------------------------------------------------------------- +# ACML + +set(ACML_BLAS_INCLUDE_PATH_SUFFIXES) +set(ACML_LAPACK_INCLUDE_PATH_SUFFIXES) + +set(ACML_BLAS_HEADERS cblas.h) +set(ACML_LAPACK_HEADERS clapack.h) + +set(ACML_BLAS_LIBRARY_PATH_SUFFIXES libso) +set(ACML_LAPACK_LIBRARY_PATH_SUFFIXES libso) + +set(ACML_BLAS_LIBS acml) +set(ACML_LAPACK_LIBS acml) + +#------------------------------------------------------------------------------- +# ATLAS + +set(ATLAS_BLAS_INCLUDE_PATH_SUFFIXES atlas) +set(ATLAS_LAPACK_INCLUDE_PATH_SUFFIXES atlas) + +set(ATLAS_BLAS_HEADERS cblas.h) +set(ATLAS_LAPACK_HEADERS clapack.h) + +set(ATLAS_BLAS_LIBRARY_PATH_SUFFIXES atlas atlas-base atlas-base/atlas atlas-sse3) +set(ATLAS_LAPACK_LIBRARY_PATH_SUFFIXES atlas atlas-base atlas-base/atlas atlas-sse3) + +set(ATLAS_BLAS_LIBS f77blas cblas atlas) +set(ATLAS_LAPACK_LIBS atlas lapack) + +#------------------------------------------------------------------------------- +# OPENBLAS (no LAPACK in OPENBLAS) + +set(OPENBLAS_BLAS_INCLUDE_PATH_SUFFIXES) + +set(OPENBLAS_BLAS_HEADERS cblas_openblas.h) + +set(OPENBLAS_BLAS_LIBRARY_PATH_SUFFIXES) + +set(OPENBLAS_BLAS_LIBS openblas) + +#------------------------------------------------------------------------------- +# MKL + +set(MKL_BLAS_INCLUDE_PATH_SUFFIXES) +set(MKL_LAPACK_INCLUDE_PATH_SUFFIXES) + +set(MKL_BLAS_HEADERS mkl_cblas.h) +set(MKL_LAPACK_HEADERS mkl_lapack.h) + +if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64") + set(MKL_BLAS_LIBRARY_PATH_SUFFIXES intel64 em64t) + set(MKL_LAPACK_LIBRARY_PATH_SUFFIXES intel64 em64t) +else() + set(MKL_BLAS_LIBRARY_PATH_SUFFIXES ia32 32) + set(MKL_LAPACK_LIBRARY_PATH_SUFFIXES ia32 32) +endif() + +set(MKL_COMPILER_BINDINGS ${CMAKE_${BLAS_LANG}_COMPILER_ID}) + +set(_thread_lib) +if(MKL_COMPILER_BINDINGS MATCHES Intel) + set(_thread_lib mkl_intel_thread) +endif() +if(MKL_COMPILER_BINDINGS MATCHES PGI) + set(_thread_lib mkl_pgi_thread) +endif() +if(MKL_COMPILER_BINDINGS MATCHES GNU) + set(_thread_lib mkl_gnu_thread) +endif() +if(MKL_COMPILER_BINDINGS MATCHES Clang) + set(_thread_lib mkl_gnu_thread) +endif() + +if(MKL_COMPILER_BINDINGS MATCHES Intel) + set(_compiler_mkl_interface mkl_intel) +endif() +if(MKL_COMPILER_BINDINGS MATCHES PGI) + set(_compiler_mkl_interface mkl_intel) +endif() +if(MKL_COMPILER_BINDINGS MATCHES GNU) + set(_compiler_mkl_interface mkl_gf) +endif() +if(MKL_COMPILER_BINDINGS MATCHES Clang) + set(_compiler_mkl_interface mkl_gf) +endif() + +set(_lib_suffix) +if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64") + if(ENABLE_64BIT_INTEGERS) + set(_lib_suffix _ilp64) + else() + set(_lib_suffix _lp64) + endif() +endif() + +if(ENABLE_SCALAPACK) + set(_scalapack_lib mkl_scalapack${_lib_suffix}) + if(${BLACS_IMPLEMENTATION} STREQUAL "intelmpi") + set(_blacs_lib mkl_blacs_intelmpi${_lib_suffix}) + elseif(${BLACS_IMPLEMENTATION} STREQUAL "openmpi") + set(_blacs_lib mkl_blacs_openmpi${_lib_suffix}) + elseif(${BLACS_IMPLEMENTATION} STREQUAL "sgimpt") + set(_blacs_lib mkl_blacs_sgimpt${_lib_suffix}) + else() + message(FATAL_ERROR "BLACS implementation ${BLACS_IMPLEMENTATION} not recognized/supported") + endif() +else() + set(_scalapack_lib) + set(_blacs_lib) +endif() + +# MKL 10.0.1.014 +set(MKL_BLAS_LIBS ${_scalapack_lib} ${_compiler_mkl_interface}${_lib_suffix} ${_thread_lib} mkl_core mkl_def mkl_mc ${_blacs_lib} guide pthread m) +# then try this MKL BLAS combination +set(MKL_BLAS_LIBS2 ${_scalapack_lib} ${_compiler_mkl_interface}${_lib_suffix} ${_thread_lib} mkl_core ${_blacs_lib} guide pthread m) +# newer MKL BLAS versions do not have libguide +set(MKL_BLAS_LIBS3 ${_scalapack_lib} ${_compiler_mkl_interface}${_lib_suffix} ${_thread_lib} mkl_core ${_blacs_lib} pthread m) +# ancient MKL BLAS +set(MKL_BLAS_LIBS4 mkl guide m) + +set(MKL_LAPACK_LIBS mkl_lapack95${_lib_suffix} ${_compiler_mkl_interface}${_lib_suffix}) +# older MKL LAPACK +set(MKL_LAPACK_LIBS2 mkl_lapack) + +unset(_lib_suffix) +unset(_thread_lib) +unset(_compiler_mkl_interface) +unset(_scalapack_lib) +unset(_blacs_lib) + +macro(find_math_header _service _header) + string(TOUPPER ${_service} _SERVICE) + find_path(${_SERVICE}_INCLUDE_DIRS + NAMES ${_header} + PATHS ${${_SERVICE}_ROOT} + HINTS ${${_SERVICE}_ROOT}/include + PATH_SUFFIXES ${MATH_INCLUDE_PATH_SUFFIXES} + NO_DEFAULT_PATH + ) + # the following is needed for Atlas' clapack.h + # this whole code needs major cleanup soon (2014-10-31) + find_path(${_SERVICE}_INCLUDE_DIRS + NAMES ${_header} + PATH_SUFFIXES ${MATH_INCLUDE_PATH_SUFFIXES} + ) + find_path(${_SERVICE}_INCLUDE_DIRS + NAMES ${_header} + PATH_SUFFIXES include + ) + set(${_SERVICE}_H ${_header}) + unset(_SERVICE) +endmacro() + +macro(find_math_libs _service) + string(TOUPPER ${_service} _SERVICE) + if(${_SERVICE}_FOUND) + return() + endif() + set(_lib) + set(_libs) + foreach(l ${ARGN}) + find_library(_lib + NAMES ${l} + PATHS ${${_SERVICE}_ROOT} + HINTS ${${_SERVICE}_ROOT}/lib64 ${${_SERVICE}_ROOT}/lib + PATH_SUFFIXES ${MATH_LIBRARY_PATH_SUFFIXES} + NO_DEFAULT_PATH + ) + find_library(_lib + NAMES ${l} + PATH_SUFFIXES ${MATH_LIBRARY_PATH_SUFFIXES} + ) + if(_lib) + set(_libs ${_libs} ${_lib}) + else() + set(${_SERVICE}_LIBRARIES ${_SERVICE}_LIBRARIES-NOTFOUND) + set(_libs ${_SERVICE}_LIBRARIES-NOTFOUND) + break() + endif() + unset(_lib CACHE) + endforeach() + set(${_SERVICE}_LIBRARIES ${_libs}) + unset(_lib CACHE) + unset(_libs CACHE) + unset(_SERVICE) + unset(l) +endmacro() + +macro(cache_math_result _service MATH_TYPE) + string(TOUPPER ${_service} _SERVICE) + set(${_SERVICE}_FIND_QUIETLY TRUE) + if(DEFINED ${_SERVICE}_INCLUDE_DIRS) + find_package_handle_standard_args( + ${_SERVICE} + "Could NOT find ${MATH_TYPE} ${_SERVICE}" + ${_SERVICE}_LIBRARIES + ${_SERVICE}_INCLUDE_DIRS + ) + else() + find_package_handle_standard_args( + ${_SERVICE} + "Could NOT find ${MATH_TYPE} ${_SERVICE}" + ${_SERVICE}_LIBRARIES + ) + endif() + + if(${_SERVICE}_FOUND) + set(${_SERVICE}_TYPE ${MATH_TYPE} CACHE STRING + "${_SERVICE} type") + mark_as_advanced(${_SERVICE}_TYPE) + + add_definitions(-DHAVE_${MATH_TYPE}_${_SERVICE}) + set(HAVE_${_SERVICE} ON CACHE INTERNAL + "Defined if ${_SERVICE} is available" + ) + set(HAVE_${MATH_TYPE}_${_SERVICE} ON CACHE INTERNAL + "Defined if ${MATH_TYPE}_${_SERVICE} is available" + ) + set(${_SERVICE}_LIBRARIES ${${_SERVICE}_LIBRARIES} CACHE STRING + "${_SERVICE} libraries" + ) + mark_as_advanced(${_SERVICE}_LIBRARIES) + if(DEFINED ${_SERVICE}_INCLUDE_DIRS) + set(${_SERVICE}_H ${${_SERVICE}_H} CACHE STRING + "${_SERVICE} header file") + mark_as_advanced(${_SERVICE}_H) + set(${_SERVICE}_INCLUDE_DIRS ${${_SERVICE}_INCLUDE_DIRS} + CACHE STRING "${_SERVICE} include directory" + ) + mark_as_advanced(${_SERVICE}_INCLUDE_DIRS) + endif() + else() + set(${_SERVICE}_LIBRARIES ${_SERVICE}_LIBRARIES-NOTFOUND) + if(DEFINED ${_SERVICE}_H) + set(${_SERVICE}_INCLUDE_DIRS ${_SERVICE}_INCLUDE_DIRS-NOTFOUND) + unset(${_SERVICE}_H) + endif() + endif() + set(${_SERVICE}_FOUND ${${_SERVICE}_FOUND} PARENT_SCOPE) + unset(MATH_TYPE) + unset(_SERVICE) +endmacro() + +macro(config_math_service _SERVICE) + if(EXISTS $ENV{MATH_ROOT}) + if("${${_SERVICE}_ROOT}" STREQUAL "") + set(${_SERVICE}_ROOT $ENV{MATH_ROOT}) + message("-- ${_SERVICE} will be searched for based on MATH_ROOT=${${_SERVICE}_ROOT} ") + endif() + endif() + + if(EXISTS $ENV{${_SERVICE}_ROOT}) + if("${${_SERVICE}_ROOT}" STREQUAL "") + set(${_SERVICE}_ROOT $ENV{${_SERVICE}_ROOT}) + message("-- ${_SERVICE} will be searched for based on ${_SERVICE}_ROOT=${${_SERVICE}_ROOT}") + endif() + endif() + + if(EXISTS $ENV{MKL_ROOT}) + if("${${_SERVICE}_ROOT}" STREQUAL "") + set(${_SERVICE}_ROOT $ENV{MKL_ROOT}) + message("-- ${_SERVICE} will be searched for based on MKL_ROOT=${${_SERVICE}_ROOT}") + endif() + endif() + + if(EXISTS $ENV{MKLROOT}) + if("${${_SERVICE}_ROOT}" STREQUAL "") + set(${_SERVICE}_ROOT $ENV{MKLROOT}) + message("-- ${_SERVICE} will be searched for based on MKLROOT=${${_SERVICE}_ROOT}") + endif() + endif() + + if(${_SERVICE}_INCLUDE_DIRS AND ${_SERVICE}_LIBRARIES) + set(${_SERVICE}_FIND_QUIETLY TRUE) + endif() + + if(NOT ${_SERVICE}_FIND_COMPONENTS) + if(DEFINED ${_SERVICE}_TYPE) + set(${_SERVICE}_FIND_COMPONENTS ${${_SERVICE}_TYPE}) + else() + set(${_SERVICE}_FIND_COMPONENTS ${MATH_LIB_SEARCH_ORDER}) + endif() + endif() + + find_service(${_SERVICE}) + + if(${_SERVICE}_FOUND) + + # take care of omp flags + set(_omp_flag) + if(HAVE_MKL_BLAS OR HAVE_MKL_LAPACK) + if(MKL_COMPILER_BINDINGS MATCHES Intel) + set(_omp_flag -openmp) + endif() + if(MKL_COMPILER_BINDINGS MATCHES GNU) + set(_omp_flag -fopenmp) + endif() + if(MKL_COMPILER_BINDINGS MATCHES PGI) + set(_omp_flag -mp) + endif() + endif() + if(HAVE_MKL_${_SERVICE}) + set(${_SERVICE}_LIBRARIES -Wl,--start-group ${${_SERVICE}_LIBRARIES} ${_omp_flag} -Wl,--end-group) + endif() + unset(_omp_flag) + + find_package_message(${_SERVICE} + "Found ${_SERVICE}: ${${_SERVICE}_TYPE} (${${_SERVICE}_LIBRARIES})" + "[${${_SERVICE}_LIBRARIES}]" + ) + + set(MATH_LIBS + ${MATH_LIBS} + ${${_SERVICE}_LIBRARIES} + ) + else() + add_definitions(-DUSE_BUILTIN_${_SERVICE}) + set(USE_BUILTIN_${_SERVICE} TRUE) + endif() +endmacro() + +macro(find_math_library _myservice _mytype) + set(MATH_INCLUDE_PATH_SUFFIXES ${${_mytype}_${_myservice}_INCLUDE_PATH_SUFFIXES}) + if(${_myservice}_LANG STREQUAL "C") + find_math_header(${_myservice} ${${_mytype}_${_myservice}_HEADERS}) + endif() + set(MATH_LIBRARY_PATH_SUFFIXES ${${_mytype}_${_myservice}_LIBRARY_PATH_SUFFIXES}) + + find_math_libs(${_myservice} ${${_mytype}_${_myservice}_LIBS}) + # try some alternative patterns (if defined) until we find it + foreach(_i 2 3 4 5 6 7 8 9) + if(NOT ${_myservice}_LIBRARIES) + if(DEFINED ${_mytype}_${_myservice}_LIBS${_i}) + find_math_libs(${_myservice} ${${_mytype}_${_myservice}_LIBS${_i}}) + endif() + endif() + endforeach() +endmacro() + +function(find_service _myservice) + foreach(_component ${${_myservice}_FIND_COMPONENTS}) + find_math_library(${_myservice} ${_component}) + cache_math_result(${_myservice} ${_component}) + if(${_myservice}_FOUND) + break() + endif() + endforeach() +endfunction() + +foreach(_service BLAS LAPACK) + if(NOT ${_service}_LANG) + set(${_service}_LANG C) + elseif(${_service}_LANG STREQUAL "C" OR ${_service}_LANG STREQUAL "CXX") + set(${_service}_LANG C) + elseif(NOT ${_service}_LANG STREQUAL "Fortran") + message(FATAL_ERROR "Invalid ${_service} library linker language: ${${_service}_LANG}") + endif() +endforeach() + +set(MATH_LIBS) + +if(NOT MKL_FLAG STREQUAL "off") + set(EXTERNAL_LIBS ${EXTERNAL_LIBS} -mkl=${MKL_FLAG}) + message(STATUS "User set explicit MKL flag which is passed to the compiler and linker: -mkl=${MKL_FLAG}") + message(STATUS "This disables math detection and builtin math libraries") + message(STATUS "Setting -DHAVE_MKL_BLAS and -DHAVE_MKL_LAPACK") + add_definitions(-DHAVE_MKL_BLAS) + add_definitions(-DHAVE_MKL_LAPACK) + set(BLAS_FOUND TRUE) + set(LAPACK_FOUND TRUE) +endif() + +if(ENABLE_BLAS STREQUAL "auto" OR ENABLE_LAPACK STREQUAL "auto" AND NOT ${_service}_FOUND) + message(STATUS "Math lib search order is ${MATH_LIB_SEARCH_ORDER}") +endif() + +foreach(_service BLAS LAPACK) + if(ENABLE_${_service} STREQUAL "auto" AND NOT ${_service}_FOUND) + config_math_service(${_service}) + if(${_service}_FOUND) + include_directories(${${_service}_INCLUDE_DIRS}) + endif() + endif() +endforeach() diff --git a/modules/UseOMP.cmake b/modules/UseOMP.cmake new file mode 100644 index 0000000..df16146 --- /dev/null +++ b/modules/UseOMP.cmake @@ -0,0 +1,9 @@ +option(ENABLE_OPENMP "Enable OpenMP parallelization" OFF) + +if(ENABLE_OPENMP) + find_package(OpenMP) + if(OPENMP_FOUND) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${OpenMP_C_FLAGS}") + endif() +endif() diff --git a/modules/UsePackager.cmake b/modules/UsePackager.cmake new file mode 100644 index 0000000..d8f773c --- /dev/null +++ b/modules/UsePackager.cmake @@ -0,0 +1 @@ +# nothing yet diff --git a/modules/UseSafeGuards.cmake b/modules/UseSafeGuards.cmake new file mode 100644 index 0000000..bf6688d --- /dev/null +++ b/modules/UseSafeGuards.cmake @@ -0,0 +1,19 @@ +function(guard_against_in_source in_source_dir in_binary_dir) + if(${in_source_dir} STREQUAL ${in_binary_dir}) + message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there.") + endif() +endfunction() + +function(guard_against_bad_build_types in_build_type) + string(TOLOWER "${in_build_type}" cmake_build_type_tolower) + string(TOUPPER "${in_build_type}" cmake_build_type_toupper) + + if( NOT cmake_build_type_tolower STREQUAL "debug" + AND NOT cmake_build_type_tolower STREQUAL "release" + AND NOT cmake_build_type_tolower STREQUAL "relwithdebinfo") + message(FATAL_ERROR "Unknown build type \"${in_build_type}\". Allowed values are Debug, Release, RelWithDebInfo (case-insensitive).") + endif() +endfunction() + +guard_against_in_source(${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR}) +guard_against_bad_build_types(${CMAKE_BUILD_TYPE}) diff --git a/modules/UseStaticLinking.cmake b/modules/UseStaticLinking.cmake new file mode 100644 index 0000000..73bb2c4 --- /dev/null +++ b/modules/UseStaticLinking.cmake @@ -0,0 +1,24 @@ +option(ENABLE_STATIC_LINKING "Enable static libraries linking" OFF) + +if(ENABLE_STATIC_LINKING) + if(DEFINED CMAKE_Fortran_COMPILER_ID) + if(CMAKE_Fortran_COMPILER_ID MATCHES GNU) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -static") + endif() + if(CMAKE_Fortran_COMPILER_ID MATCHES Intel) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -static-libgcc -static-intel") + endif() + if(CMAKE_Fortran_COMPILER_ID MATCHES PGI) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -Bstatic") + endif() + endif() + + if(DEFINED CMAKE_C_COMPILER_ID) + if(CMAKE_C_COMPILER_ID MATCHES GNU) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static -fpic") + endif() + if(CMAKE_C_COMPILER_ID MATCHES Clang) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Bstatic -fpic") + endif() + endif() +endif()