diff --git a/.travis.yml b/.travis.yml index 9591dbb..14218be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ matrix: - os: linux python: 2.7 compiler: gcc - env: SOURCES=ubuntu-toolchain-r-test + env: SOURCES=ubuntu-toolchain-r-test TEST_SCRIPT=test.py addons: apt: sources: @@ -32,7 +32,7 @@ matrix: - os: linux python: 3.5 compiler: gcc - env: SOURCES=ubuntu-toolchain-r-test + env: SOURCES=ubuntu-toolchain-r-test TEST_SCRIPT=test.py addons: apt: sources: @@ -53,6 +53,44 @@ matrix: # boost - libboost-all-dev + - os: linux + python: 2.7 + compiler: gcc + env: SOURCES=ubuntu-toolchain-r-test TEST_SCRIPT=test_openblas.py + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + # compilers + - g++ + - gfortran + - cmake + # math libraries, can not mix with lapack/atlas packages ! + - libblas-dev + - libopenblas-dev + # python libraries ... + - libpython2.7 + + - os: linux + python: 3.5 + compiler: gcc + env: SOURCES=ubuntu-toolchain-r-test TEST_SCRIPT=test_openblas.py + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + # compilers + - g++ + - gfortran + - cmake + # math libraries, can not mix with lapack/atlas packages ! + - libblas-dev + - libopenblas-dev + # python libraries + #- libpython2.7 + - os: osx osx_image: xcode6.4 compiler: gcc @@ -79,7 +117,7 @@ script: - pep8 --ignore E501,E265 autocmake # unit tests - py.test -vv autocmake/* - - py.test -vv test/test.py + - py.test -vv test/$TEST_SCRIPT notifications: email: false diff --git a/modules/math/openblas.cmake b/modules/math/openblas.cmake new file mode 100644 index 0000000..98ebd3f --- /dev/null +++ b/modules/math/openblas.cmake @@ -0,0 +1,80 @@ +#.rst: +# +# Find and link to OpenBLAS. +# +# Variables defined:: +# +# OpenBLAS_FOUND +# OpenBLAS_LIB +# OpenBLAS_INCLUDE_DIR +# +# autocmake.yml configuration:: +# +# docopt: "--openblas Find and link to OpenBLAS [default: False]." +# define: "'-DENABLE_OPENBLAS={0}'.format(arguments['--openblas'])" + +option(ENABLE_OPENBLAS "Find and link to OpenBLAS" OFF) + +if (ENABLE_OPENBLAS) +SET(Open_BLAS_INCLUDE_SEARCH_PATHS + /usr/include + /usr/include/openblas + /usr/include/openblas-base + /usr/local/include + /usr/local/include/openblas + /usr/local/include/openblas-base + /opt/OpenBLAS/include + $ENV{OpenBLAS_HOME} + $ENV{OpenBLAS_HOME}/include +) + +SET(Open_BLAS_LIB_SEARCH_PATHS + /lib/ + /lib/openblas-base + /lib64/ + /usr/lib + /usr/lib/openblas-base + /usr/lib64 + /usr/local/lib + /usr/local/lib64 + /opt/OpenBLAS/lib + $ENV{OpenBLAS}cd + $ENV{OpenBLAS}/lib + $ENV{OpenBLAS_HOME} + $ENV{OpenBLAS_HOME}/lib + ) + +FIND_PATH(OpenBLAS_INCLUDE_DIR NAMES cblas.h PATHS ${Open_BLAS_INCLUDE_SEARCH_PATHS}) +FIND_LIBRARY(OpenBLAS_LIB NAMES openblas PATHS ${Open_BLAS_LIB_SEARCH_PATHS}) + +SET(OpenBLAS_FOUND ON) + +# Check include files +IF(NOT OpenBLAS_INCLUDE_DIR) + SET(OpenBLAS_FOUND OFF) + MESSAGE(STATUS "Could not find OpenBLAS include. Turning OpenBLAS_FOUND off") +ENDIF() + +# Check libraries +IF(NOT OpenBLAS_LIB) + SET(OpenBLAS_FOUND OFF) + MESSAGE(STATUS "Could not find OpenBLAS lib. Turning OpenBLAS_FOUND off") +ENDIF() + +IF (OpenBLAS_FOUND) + IF (NOT OpenBLAS_FIND_QUIETLY) + MESSAGE(STATUS "Found OpenBLAS libraries: ${OpenBLAS_LIB}") + MESSAGE(STATUS "Found OpenBLAS include: ${OpenBLAS_INCLUDE_DIR}") + ENDIF (NOT OpenBLAS_FIND_QUIETLY) +ELSE (OpenBLAS_FOUND) + IF (OpenBLAS_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find OpenBLAS") + ENDIF (OpenBLAS_FIND_REQUIRED) +ENDIF (OpenBLAS_FOUND) + +MARK_AS_ADVANCED( + OpenBLAS_INCLUDE_DIR + OpenBLAS_LIB + OpenBLAS +) +endif() diff --git a/test/fc_blas/cmake/autocmake.yml b/test/fc_blas/cmake/autocmake.yml index 0ed452b..a8eadbc 100644 --- a/test/fc_blas/cmake/autocmake.yml +++ b/test/fc_blas/cmake/autocmake.yml @@ -3,8 +3,10 @@ min_cmake_version: 2.8 modules: - fc: - source: ../../../modules/fc.cmake -- math: +- math1: - source: ../../../modules/math/blas.cmake +- math2: + - source: ../../../modules/math/openblas.cmake - default_build_paths: - source: ../../../modules/default_build_paths.cmake - src: diff --git a/test/fc_blas/src/CMakeLists.txt b/test/fc_blas/src/CMakeLists.txt index 682fdba..6ebea0e 100644 --- a/test/fc_blas/src/CMakeLists.txt +++ b/test/fc_blas/src/CMakeLists.txt @@ -1,6 +1,17 @@ +if (ENABLE_BLAS) if(BLAS_FOUND) add_executable(example example.f90) target_link_libraries(example ${BLAS_LIBRARIES}) else() message(FATAL_ERROR "BLAS library not found") endif() +endif() + +if (ENABLE_OPENBLAS) +if(OpenBLAS_FOUND) + add_executable(example example.f90) + target_link_libraries(example ${OpenBLAS_LIB}) +else() + message(FATAL_ERROR "OpenBLAS library not found") +endif() +endif() diff --git a/test/test_openblas.py b/test/test_openblas.py new file mode 100644 index 0000000..b23c321 --- /dev/null +++ b/test/test_openblas.py @@ -0,0 +1,92 @@ +import os +import sys +import subprocess +import shlex +import shutil +import sys +import time +import datetime +import pytest + +HERE = os.path.abspath(os.path.dirname(__file__)) + +skip_on_osx = pytest.mark.skipif('sys.platform == "darwin"', reason="not working on osx") +skip_on_linux = pytest.mark.skipif('sys.platform == "linux2"', reason="not working on linux") +skip_always = pytest.mark.skipif('1 == 1', reason="tests are broken") + + +def exe(command): + """ + Executes command and returns string representations of stdout and stderr captured from the console. + When universal_newlines=True stdout and stderr are opened in text mode. + Otherwise, they are opened in binary mode. In that case captured stdout and stderr + are not strings and Python 3 throws type error when compared against strings later in tests. + Note: + This feature is only available if Python is built with universal newline support (the default). + Also, the newlines attribute of the file objects stdout, stdin and stderr are not updated by the + communicate() method. + See https://docs.python.org/2/library/subprocess.html + """ + stdout, stderr = subprocess.Popen(shlex.split(command), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True).communicate() + + if stderr: + sys.stderr.write(stdout) + sys.stderr.write(stderr) + + return stdout, stderr + + +def configure_build_and_exe(name, setup_command, launcher=None): + + stamp = datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d-%H-%M-%S') + + os.chdir(os.path.join(HERE, name, 'cmake')) + shutil.copy(os.path.join('..', '..', '..', 'update.py'), 'update.py') + + if os.path.exists('autocmake'): + shutil.rmtree('autocmake') + shutil.copytree(os.path.join('..', '..', '..', 'autocmake'), 'autocmake') + + stdout, stderr = exe('python update.py ..') + os.chdir(os.path.join(HERE, name)) + + make_command = 'make' + binary = './bin/example' + if sys.platform == 'win32': + setup_command += ' --generator="MinGW Makefiles"' + make_command = 'mingw32-make' + binary = 'bin\\\example.exe' + + if launcher: + binary = '%s %s' % (launcher, binary) + + setup_command += ' build-%s' % stamp + + stdout, stderr = exe(setup_command) + assert stderr == '' + + os.chdir(os.path.join(HERE, name, 'build-%s' % stamp)) + + stdout, stderr = exe(make_command) + # we do not check for empty stderr due to warnings flushed to stderr + + stdout, stderr = exe(binary) + assert stderr == '' + + assert 'PASSED' in stdout + + +def test_fc(): + configure_build_and_exe('fc', 'python setup --fc=gfortran') + + +def test_fc_blas(): + configure_build_and_exe('fc_blas', 'python setup --fc=gfortran --blas') + + +@skip_on_osx +def test_fc_openblas(): + configure_build_and_exe('fc_blas', 'python setup --fc=gfortran --openblas')