Search code examples
windowscmakelinkerblasopenblas

Undefined reference to cblas_* with cmake on windows


I'working on a project that uses SAF (Spatial Audio Framework) which has OpenBlas and LAPACK as Dependecies. (The Project includes a lot of libraries so I only show the code that relates to my problem: BLAS)

I'm trying to figure out how I can link the project with OpenBlas, but nothing worked. I use cmake's FETCHCONTENT to get LAPACK which also contains BLAS. I tried:

target_link_libraries(dev_example PUBLIC openblas) # or libopenblas or cblas or libblas

which resulted in cannot find -lopenblas.

Now I tried to specify the library directly SET(OPENBLAS_LIBRARY ${lapack_BINARY_DIR}/lib/libblas.a) and get a lot of undefined references like undefined reference to 'cblas_sgemm'

I also tried linking against libopenblas.a from the precompiled binaries from the OpenBlas Repo - same as above.


My CMakeLists.txt

cmake_minimum_required(VERSION 3.16)
project(dev_example VERSION 1.0 LANGUAGES C CXX)

include(FetchContent)

FETCHCONTENT_DECLARE(
        lapack
        GIT_REPOSITORY https://github.com/Reference-lapack/lapack
        GIT_TAG        master
)
FetchContent_MakeAvailable(lapack)
FetchContent_GetProperties(lapack)
if(NOT lapack_POPULATED)
    FetchContent_Populate(lapack)
endif()

set(OPENBLAS_HEADER_PATH ${lapack_SOURCE_DIR}/CBLAS/include)
set(LAPACKE_HEADER_PATH ${lapack_SOURCE_DIR}/LAPACKE/include ${lapack_BINARY_DIR}/include)

SET(LAPACKE_LIBRARY ${lapack_BINARY_DIR}/lib/liblapack.a)
SET(OPENBLAS_LIBRARY ${lapack_BINARY_DIR}/lib/libblas.a)

add_executable(dev_example WIN32
        main.cpp
        )

target_include_directories(dev_example PUBLIC
        ${lapack_SOURCE_DIR}/CBLAS/include
        ${lapack_BINARY_DIR}/include
)


target_link_libraries(dev_example PUBLIC
        ${OPENBLAS_LIBRARY}
        )

How can I link Blas correctly? I made sure that libblas.a is located in the given directory.

I was also wondering if I'm even using the correct BLAS library because all the undefined refences are prefixed with cblas_ like cblas_sgemm while libblas.a only contains Symbols like sgemm without the prefix.

Compiler: gcc.exe (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0


Solution

  • In your own answer:

    I assume that LAPACK on Github contains a different implementation of BLAS and not OpenBLAS.

    The libblas.a that is built along with liblapack.a with repo https://github.com/Reference-lapack/lapack is a Fortran BLAS library. That is why all its symbols lack the CBLAS prefix cblas_. As per the repo's README, it does contain a CBLAS source tree but it does not tell you that this is not built by default. Or that you have to configure the CMake build with -DCBLAS=ON, and then, instead of (or after) running make you must run make cblas. The build will then output a libcblas.a.

    As you found, OpenBLAS builds a CBLAS library libopenblas.a by default with header files equipped for linkage with C++. Regarding that repo:

    FetchContent didn't set any library variable for BLAS, unlike find_package usually would.

    It doesn't, but it does set:

    openblas_SOURCE_DIR
    openblas_BINARY_DIR
    

    So just as far as linking against libopenblas is concerned, you can have a CMakeLists.txt on the lines:

    cmake_minimum_required(VERSION 3.16)
    project(dev_example VERSION 1.0 LANGUAGES C CXX)
    
    include(FetchContent)
    
    FetchContent_Declare(
            openblas
            GIT_REPOSITORY https://github.com/OpenMathLib/OpenBLAS.git
            GIT_TAG        v0.3.28
    )
    FetchContent_MakeAvailable(openblas)
    FetchContent_GetProperties(openblas)
    
    set(openblas_HDR_DIRS ${openblas_SOURCE_DIR} ${openblas_BINARY_DIR})
    set(openblas_LIB_DIRS ${openblas_BINARY_DIR}/lib)
    
    add_executable(dev_example
            main.cpp
            )
    
    target_include_directories(dev_example PRIVATE
            ${openblas_HDR_DIRS}
            )
    
    target_link_directories(dev_example PRIVATE
            ${openblas_LIB_DIRS}
            )
    
    target_link_libraries(dev_example PRIVATE
            openblas
            )
            
    

    The reason for the inclusion of ${openblas_BINARY_DIR} in target_include_directories is the fact that an autotools-style header config.h is generated in the build directory.