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

openblas: add v0.3.28, drop old versions and patches, add OpenMP and ILP64 support #25344

Open
wants to merge 8 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 24 additions & 18 deletions recipes/openblas/all/conandata.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
sources:
"0.3.28":
url: "https://github.com/xianyi/OpenBLAS/archive/v0.3.28.tar.gz"
sha256: "f1003466ad074e9b0c8d421a204121100b0751c96fc6fcf3d1456bd12f8a00a1"
"0.3.27":
url: "https://github.com/xianyi/OpenBLAS/archive/v0.3.27.tar.gz"
sha256: "aa2d68b1564fe2b13bc292672608e9cdeeeb6dc34995512e65c3b10f4599e897"
Expand All @@ -11,21 +14,24 @@ sources:
"0.3.24":
url: "https://github.com/xianyi/OpenBLAS/archive/v0.3.24.tar.gz"
sha256: "ceadc5065da97bd92404cac7254da66cc6eb192679cf1002098688978d4d5132"
"0.3.20":
url: "https://github.com/xianyi/OpenBLAS/archive/v0.3.20.tar.gz"
sha256: "8495c9affc536253648e942908e88e097f2ec7753ede55aca52e5dead3029e3c"
"0.3.17":
url: "https://github.com/xianyi/OpenBLAS/archive/v0.3.17.tar.gz"
sha256: "df2934fa33d04fd84d839ca698280df55c690c86a5a1133b3f7266fce1de279f"
"0.3.15":
url: "https://github.com/xianyi/OpenBLAS/archive/v0.3.15.tar.gz"
sha256: "30a99dec977594b387a17f49904523e6bc8dd88bd247266e83485803759e4bbe"
"0.3.13":
url: "https://github.com/xianyi/OpenBLAS/archive/v0.3.13.tar.gz"
sha256: "79197543b17cc314b7e43f7a33148c308b0807cd6381ee77f77e15acf3e6459e"
"0.3.12":
url: "https://github.com/xianyi/OpenBLAS/archive/v0.3.12.tar.gz"
sha256: "65a7d3a4010a4e3bd5c0baa41a234797cd3a1735449a4a5902129152601dc57b"
"0.3.10":
url: "https://github.com/xianyi/OpenBLAS/archive/v0.3.10.tar.gz"
sha256: "0484d275f87e9b8641ff2eecaa9df2830cbe276ac79ad80494822721de6e1693"
patches:
"0.3.28":
- patch_file: "patches/0001-use-openmp-target.patch"
patch_description: "Use OpenMP target instead of flags for llvm-openmp"
patch_type: "conan"
"0.3.27":
- patch_file: "patches/0001-use-openmp-target.patch"
patch_description: "Use OpenMP target instead of flags for llvm-openmp"
patch_type: "conan"
"0.3.26":
- patch_file: "patches/0001-use-openmp-target.patch"
patch_description: "Use OpenMP target instead of flags for llvm-openmp"
patch_type: "conan"
"0.3.25":
- patch_file: "patches/0001-use-openmp-target.patch"
patch_description: "Use OpenMP target instead of flags for llvm-openmp"
patch_type: "conan"
"0.3.24":
- patch_file: "patches/0001-use-openmp-target.patch"
patch_description: "Use OpenMP target instead of flags for llvm-openmp"
patch_type: "conan"
185 changes: 98 additions & 87 deletions recipes/openblas/all/conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@
from conan.errors import ConanInvalidConfiguration
from conan.tools.apple import fix_apple_shared_install_name
from conan.tools.build import cross_building
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
from conan.tools.files import copy, get, replace_in_file, rmdir
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout, CMakeDeps
from conan.tools.files import copy, get, rmdir, export_conandata_patches, apply_conandata_patches
from conan.tools.microsoft import is_msvc_static_runtime, is_msvc
from conan.tools.scm import Version
import os
import textwrap

required_conan_version = ">=1.53.0"

Expand Down Expand Up @@ -61,7 +59,7 @@

class OpenblasConan(ConanFile):
name = "openblas"
description = "An optimized BLAS library based on GotoBLAS2 1.13 BSD version"
description = "An optimized BLAS library based on GotoBLAS2, with LAPACK"
license = "BSD-3-Clause"
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://www.openblas.net"
Expand All @@ -71,30 +69,45 @@ class OpenblasConan(ConanFile):
options = {
"shared": [True, False],
"fPIC": [True, False],
"ilp64": [True, False],
"build_lapack": [True, False],
"build_relapack": [True, False],
"build_bfloat16": [True, False],
"use_openmp": [True, False],
"use_thread": [True, False],
"use_locking": [True, False],
"dynamic_arch": [True, False],
"target": [None] + available_openblas_targets
"target": [None] + available_openblas_targets,
"max_threads": ["auto", "ANY"],
"max_omp_parallel": ["ANY"],
}
default_options = {
"shared": False,
"fPIC": True,
"ilp64": False,
"build_lapack": True,
"build_relapack": False,
"build_bfloat16": False,
"use_openmp": True,
"use_thread": True,
"use_locking": True,
"dynamic_arch": False,
"target": None,
"max_threads": 128,
"max_omp_parallel": 1,
}
options_description = {
"ilp64": "Build with ILP64 interface instead of LP64 (incompatible with the standard API)",
"build_lapack": "Build LAPACK and LAPACKE",
"build_relapack": "Build with ReLAPACK (recursive implementation of several LAPACK functions on top of standard LAPACK)",
"build_bfloat16": "Build with bfloat16 support",
"use_openmp": "Enable OpenMP support",
"use_thread": "Enable threads support",
"use_locking": "Use locks even in single-threaded builds to make them callable from multiple threads",
"dynamic_arch": "Include support for multiple CPU targets, with automatic selection at runtime (x86/x86_64, aarch64 or ppc only)",
"target": "OpenBLAS TARGET variable (see TargetList.txt)",
"max_threads": "The maximum number of parallel threads you expect to need (defaults to the number of cores in the build cpu)",
"max_omp_parallel": "Number of OpenMP instances that your code may use for parallel calls into OpenBLAS",
}
short_paths = True

Expand All @@ -105,47 +118,45 @@ def _fortran_compiler(self):
return comp_exe["fortran"]
return None

def export_sources(self):
export_conandata_patches(self)

def config_options(self):
if self.settings.os == "Windows":
del self.options.fPIC
# When no Fortran compiler is available, OpenBLAS builds LAPACK from an f2c-converted copy of LAPACK unless the NO_LAPACK option is specified.
# This is not available before v0.3.21.
if Version(self.version) < "0.3.21":
self.options.build_lapack = False
self.options.build_relapack = False

def configure(self):
if self.options.shared:
self.options.rm_safe("fPIC")
if not self.options.build_lapack:
del self.options.build_relapack
if not self.options.use_thread:
del self.options.max_threads
if not self.options.use_openmp:
del self.options.max_omp_parallel

# When cross-compiling, OpenBLAS requires explicitly setting TARGET
if cross_building(self, skip_x64_x86=True) and not self.options.target:
# Try inferring the target from settings.arch
target = conan_arch_to_openblas_target.get(str(self.settings.arch))
if target:
self.output.warning(f'Setting OpenBLAS TARGET={target} based on settings.arch. This may result in suboptimal performance. Set the "{self.name}/*:target=XXX" option to silence this warning.')
self.output.warning(
f"Setting OpenBLAS TARGET={target} based on settings.arch. "
"This may result in suboptimal performance. "
f'Set the "{self.name}/*:target=XXX" option to silence this warning.'
)
self.options.target = target

def requirements(self):
if self.options.use_openmp and self.settings.compiler in ["clang", "apple-clang"]:
self.requires("llvm-openmp/17.0.6")

def validate(self):
if Version(self.version) < "0.3.24" and self.settings.arch == "armv8":
# OpenBLAS fails to detect the appropriate target architecture for armv8 for versions < 0.3.24, as it matches the 32 bit variant instead of 64.
# This was fixed in https://github.com/OpenMathLib/OpenBLAS/pull/4142, which was introduced in 0.3.24.
# This would be a reasonably trivial hotfix to backport.
raise ConanInvalidConfiguration("armv8 builds are not currently supported for versions lower than 0.3.24. Contributions to support this are welcome.")

if self.options.build_relapack:
if not self.options.build_lapack:
raise ConanInvalidConfiguration(f'"{self.name}/*:build_relapack=True" option requires "{self.name}/*:build_lapack=True"')
if self.settings.compiler not in ["gcc", "clang"]:
# ld: unknown option: --allow-multiple-definition on apple-clang
raise ConanInvalidConfiguration(f'"{self.name}/*:build_relapack=True" option is only supported for GCC and Clang')
if self.options.get_safe("build_relapack") and self.settings.compiler not in ["gcc", "clang"]:
# ld: unknown option: --allow-multiple-definition on apple-clang
raise ConanInvalidConfiguration(f'"{self.name}/*:build_relapack=True" option is only supported for GCC and Clang')

def validate_build(self):
if Version(self.version) < "0.3.22" and cross_building(self, skip_x64_x86=True):
# OpenBLAS CMake builds did not support some of the cross-compilation targets in 0.3.20/21 and earlier.
# This was fixed in https://github.com/OpenMathLib/OpenBLAS/pull/3714 and https://github.com/OpenMathLib/OpenBLAS/pull/3958
raise ConanInvalidConfiguration(f"Cross-building is not supported for {self.name}/0.3.21 and earlier.")

# If we're cross-compiling, and the user didn't provide the target, and
# we couldn't infer the target from settings.arch, fail
if cross_building(self, skip_x64_x86=True) and not self.options.target:
Expand All @@ -164,24 +175,29 @@ def generate(self):
tc.variables["BUILD_TESTING"] = False

tc.variables["NOFORTRAN"] = not self.options.build_lapack
# This checks explicit user-specified fortran compiler
if self.options.build_lapack and not self._fortran_compiler:
if Version(self.version) < "0.3.21":
self.output.warning("Building with LAPACK support requires a Fortran compiler.")
else:
tc.variables["C_LAPACK"] = True
tc.variables["NOFORTRAN"] = True
self.output.info("Building LAPACK without a Fortran compiler")
tc.variables["C_LAPACK"] = True
tc.variables["NOFORTRAN"] = True
self.output.info("Building LAPACK without a Fortran compiler")

tc.variables["BUILD_WITHOUT_LAPACK"] = not self.options.build_lapack
tc.variables["BUILD_RELAPACK"] = self.options.build_relapack

tc.variables["BUILD_RELAPACK"] = self.options.get_safe("build_relapack", False)
tc.variables["BUILD_BFLOAT16"] = self.options.build_bfloat16
tc.variables["INTERFACE64"] = self.options.ilp64
tc.variables["DYNAMIC_ARCH"] = self.options.dynamic_arch
tc.variables["USE_OPENMP"] = self.options.use_openmp
tc.variables["USE_THREAD"] = self.options.use_thread
tc.variables["USE_LOCKING"] = self.options.use_locking
if self.options.get_safe("max_threads", "auto") != "auto":
tc.variables["NUM_PARALLEL"] = self.options.max_threads
if self.options.get_safe("max_omp_parallel"):
tc.variables["NUM_THREADS"] = self.options.max_omp_parallel

tc.variables["MSVC_STATIC_CRT"] = is_msvc_static_runtime(self)

# Needed for $<$<LINK_LANGUAGE:C>:OpenMP::OpenMP_C> to work correctly
tc.cache_variables["CMAKE_POLICY_DEFAULT_CMP0022"] = "NEW"

# This is a workaround to add the libm dependency on linux,
# which is required to successfully compile on older gcc versions.
tc.variables["ANDROID"] = self.settings.os in ["Linux", "Android"]
Expand All @@ -192,41 +208,11 @@ def generate(self):
tc.cache_variables["CMAKE_POLICY_DEFAULT_CMP0077"] = "NEW"
tc.generate()

deps = CMakeDeps(self)
deps.generate()

def _patch_sources(self):
if Version(self.version) <= "0.3.15":
replace_in_file(self, os.path.join(self.source_folder, "cmake", "utils.cmake"),
"set(obj_defines ${defines_in})", textwrap.dedent("""\
set(obj_defines ${defines_in})

list(FIND obj_defines "RC" def_idx)
if (${def_idx} GREATER -1)
list(REMOVE_ITEM obj_defines "RC")
list(APPEND obj_defines "RC=RC")
endif ()
list(FIND obj_defines "CR" def_idx)
if (${def_idx} GREATER -1)
list(REMOVE_ITEM obj_defines "CR")
list(APPEND obj_defines "CR=CR")
endif ()"""))
if Version(self.version) < "0.3.21":
f_check_cmake = os.path.join(self.source_folder, "cmake", "f_check.cmake")
if Version(self.version) >= "0.3.12":
replace_in_file(self, f_check_cmake,
'message(STATUS "No Fortran compiler found, can build only BLAS but not LAPACK")',
'message(FATAL_ERROR "No Fortran compiler found. Cannot build with LAPACK.")')
else:
replace_in_file(self, f_check_cmake,
"enable_language(Fortran)",
textwrap.dedent("""\
include(CheckLanguage)
check_language(Fortran)
if(CMAKE_Fortran_COMPILER)
enable_language(Fortran)
else()
message(FATAL_ERROR "No Fortran compiler found. Cannot build with LAPACK.")
set (NOFORTRAN 1)
set (NO_LAPACK 1)
endif()"""))
apply_conandata_patches(self)

def build(self):
self._patch_sources()
Expand All @@ -245,23 +231,25 @@ def package(self):

@property
def _lib_name(self):
name = "openblas"
if self.options.ilp64:
name += "_64"
if self.options.shared and self.settings.build_type == "Debug" and not is_msvc(self):
return "openblas_d"
return "openblas"
name += "_d"
return name

@property
def _64bit(self):
return "64" if self.options.ilp64 else ""

def package_info(self):
# CMake config file:
# - OpenBLAS always has one and only one of these components: openmp, pthread or serial.
# - Whatever if this component is requested or not, official CMake imported target is always OpenBLAS::OpenBLAS
# - TODO: add openmp component when implemented in this recipe
self.cpp_info.set_property("cmake_file_name", "OpenBLAS")
self.cpp_info.set_property("cmake_file_name", f"OpenBLAS{self._64bit}")
self.cpp_info.set_property("cmake_target_name", "OpenBLAS::OpenBLAS")
self.cpp_info.set_property("pkg_config_name", "openblas")
# 'pthread' causes issues without namespace
cmake_component_name = "pthread" if self.options.use_thread else "serial" # TODO: how to model this in CMakeDeps?
self.cpp_info.components["openblas_component"].set_property("cmake_target_name", f"OpenBLAS::{cmake_component_name}")
self.cpp_info.components["openblas_component"].set_property("pkg_config_name", "openblas")
self.cpp_info.components["openblas_component"].includedirs.append(os.path.join("include", "openblas"))
if self.options.ilp64:
self.cpp_info.set_property("cmake_target_aliases", ["OpenBLAS64::OpenBLAS"])
self.cpp_info.set_property("pkg_config_name", f"openblas{self._64bit}")
self.cpp_info.components["openblas_component"].set_property("pkg_config_name", f"openblas{self._64bit}")
self.cpp_info.components["openblas_component"].includedirs.append(os.path.join("include", f"openblas{self._64bit}"))
self.cpp_info.components["openblas_component"].libs = [self._lib_name]
if self.settings.os in ["Linux", "FreeBSD"]:
self.cpp_info.components["openblas_component"].system_libs.append("m")
Expand All @@ -270,12 +258,35 @@ def package_info(self):
if self.options.build_lapack and self._fortran_compiler:
self.cpp_info.components["openblas_component"].system_libs.append("gfortran")

if self.options.use_openmp:
if self.options.use_openmp and self.settings.compiler in ["clang", "apple-clang"]:
self.cpp_info.components["openblas_component"].requires.append("llvm-openmp::llvm-openmp")
else:
if is_msvc(self):
openmp_flags = ["-openmp"]
elif self.settings.compiler == "gcc":
openmp_flags = ["-fopenmp"]
elif self.settings.compiler == "intel-cc":
openmp_flags = ["-Qopenmp"]
self.cpp_info.exelinkflags.extend(openmp_flags)
self.cpp_info.sharedlinkflags.extend(openmp_flags)

# OpenBLAS always has one and only one of these components defined: openmp, pthread or serial.
if self.options.use_openmp:
component = "openmp"
elif self.options.use_thread:
component = "pthread"
else:
component = "serial"
self.cpp_info.components[component].set_property("cmake_target_name", f"OpenBLAS::{component}")
self.cpp_info.components[component].requires = ["openblas_component"]

self.buildenv_info.define_path("OpenBLAS_HOME", self.package_folder)
self.runenv_info.define_path("OpenBLAS_HOME", self.package_folder)

# TODO: to remove in conan v2 once cmake_find_package_* generators removed
self.cpp_info.filenames["cmake_find_package"] = f"OpenBLAS{self._64bit}"
self.cpp_info.filenames["cmake_find_package_multi"] = f"OpenBLAS{self._64bit}"
self.cpp_info.names["cmake_find_package"] = "OpenBLAS"
self.cpp_info.names["cmake_find_package_multi"] = "OpenBLAS"
self.cpp_info.components["openblas_component"].names["cmake_find_package"] = cmake_component_name
self.cpp_info.components["openblas_component"].names["cmake_find_package_multi"] = cmake_component_name
self.env_info.OpenBLAS_HOME = self.package_folder
20 changes: 20 additions & 0 deletions recipes/openblas/all/patches/0001-use-openmp-target.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--- a/cmake/arch.cmake
+++ b/cmake/arch.cmake
@@ -35,9 +35,14 @@ if (USE_OPENMP)
# USE_SIMPLE_THREADED_LEVEL3 = 1
# NO_AFFINITY = 1
find_package(OpenMP REQUIRED)
- if (OpenMP_FOUND)
- set(CCOMMON_OPT "${CCOMMON_OPT} ${OpenMP_C_FLAGS} -DUSE_OPENMP")
- set(FCOMMON_OPT "${FCOMMON_OPT} ${OpenMP_Fortran_FLAGS}")
+ if(OpenMP_FOUND) # TODO: use OpenMP_C_FOUND when llvm-openmp has been fixed
+ set(CCOMMON_OPT "${CCOMMON_OPT} -DUSE_OPENMP")
+ link_libraries($<$<LINK_LANGUAGE:C>:OpenMP::OpenMP_C>)
+ include_directories(${OpenMP_C_INCLUDE_DIRS})
+ endif()
+ if(OpenMP_Fortran_FOUND)
+ link_libraries($<$<LINK_LANGUAGE:Fortran>:OpenMP::OpenMP_Fortran>)
+ include_directories(${OpenMP_Fortran_INCLUDE_DIRS})
endif()
endif ()

8 changes: 6 additions & 2 deletions recipes/openblas/all/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
cmake_minimum_required(VERSION 3.1)
cmake_minimum_required(VERSION 3.15)
project(test_package)

find_package(OpenBLAS REQUIRED CONFIG)
find_package(OpenBLAS CONFIG)
find_package(OpenBLAS64 CONFIG)
if(NOT OpenBLAS_FOUND AND NOT OpenBLAS64_FOUND)
message(FATAL_ERROR "OpenBLAS not found")
endif()

add_executable(${PROJECT_NAME} test_package.cpp)
target_link_libraries(${PROJECT_NAME} OpenBLAS::OpenBLAS)
Loading
Loading