Files
mlpack/CMake/mlpack.cmake
T
Ryan CurtinandDirk Eddelbuettel e70a04fbba Add Docker deployment documentation (#3907)
* Add a first attempt at explicitly using Jenkinsfiles.

* A first attempt...

* Put code in a script block.

* Add first attempt at link check job pipeline.

* Hopefully correct shell block.

* Install git.

* Install packages as root.

* Use custom image that already has dependencies installed.

* Try processing the JUnit results.

* Fix syntax (hopefully).

* Try to get the build to set its status on Github.

* Try and see if I can get the snippet build to run too.

* A first attempt at reviving the static code analysis build.

* Refactor style check job a bit.

* Try to clean up other files and have them set statuses.

* Set status in script blocks.

* Fix directory (this may not fix my problem).

* Should I load in the script step?

* Maybe I can just load it without a name.

* Maybe I have my path wrong.

* Will this work?  Just a test...

* Try using a plugin instead.

* And if I define the function manually at the top?

* Maybe this will fix the load.

* Try to turn unstable into failed.

* Hopefully fix documentation builds.

* Fix script blocks.

* Maybe fix static code analysis job.

* Try to adapt PR number variable.

* First attempt at cross-compilation job.

* Try to fix some syntax.

* Clean workspaces after build.

* Try to put the matrix in the right place.

* Another attempt at the matrix configuration.

* Maybe I have to nest it deeper.

* Maybe I have to clean always?

* What we need is more tabbing.

* Use try/catch to handle failed junit processing.

* Better handling of environment variables.

* Try a differernt approach than try/catch.

* Try to get some more information about ccache.

* Is it possible we could store the ccache at a higher level?

* Maybe I have the variable name wrong.

* Clean the cross-compilation workspace.

* Try mounting the ccache so it can be shared across multiple jobs.

* Always pull images.

* We need to run on the same node.

* Run on only one core.

* Try building in the Docker container in a different way.

* Do I have the order backwards?

* Can I run anything at all in the container?

* The static code analysis job isn't helpful.

* Try to set the user of the docker container.

* Rebuild the Docker container instead.

* Always pull an updated image.

* Download any necessary dependencies too.

* Oops, use the correct CMake options.

* Fix line break in the wrong place.

* Make sure to use the correct architecture.

* We can't use MATCHES, that is a regex.

* Oops, we need to use STREQUAL.

* Bump to an older version since newer versions don't have gfortran.

* Try to run the tests on the target.

* Correct syntax.

* Okay, I'm not allowed to generate a stage name.

* Try cleaning the workspace at the start of the build.

* Okay, so I just can't depend on the workspace cleaning job, wonderful.

* Try and add the passphrase correctly.

* Fix path for memory checks.

* Fix path to test.

* Fix PR number variable.

* Try to fix path for test copying.

* Try to get the PR number correct.

* Try and centralize where the link cache is stored.

* Why is it being printed strangely?

* Is there some weird restriction where this all has to be on one line?

* Always publish the HTML, and fix a link.

* Try to fix SSH host key check.

* Make the reports directory.

* Try to fix file parsing.

* Try to enable ccache.

* Try to set ccache directory correctly.

* Try to get the full pipeline set up correctly for cross-compilation.

* Fix path to test data.

* Allow debug builds when cross-compiling.

* Remember to unpack all the test data!

* Fail tests when the data isn't there.

* Maybe I can use find instead.

* Double escape for backslash?

* What if we just run the test?

* Port Catch2 improvement for junit runner.

See https://github.com/catchorg/Catch2/commit/c29e198eab0ccdb190495397854b937677385e2e.

* Re-enable junit testing (hopefully it will work now).

* Output directly to the xml file.

* Try to clean up regex.

* Try to set IN PROGRESS status.

* Could it be called RUNNING?

* I guess I don't get access to set jobs in progress through this API.

* Fix regex for test name extraction.

* Try to clean up Jenkinsfiles.

* Fix parameter name.

* Maybe fix syntax?

* Does it work without keyword arguments?

* Correctly accept named parameters.

* Abort previous builds to reduce load on Jenkins.

* Use optimization when compiling.

* Fix syntax for abortPrevious.

* Fix missing closing brace...

* Update links in CI documentation and try to fix memory check job.

* Add Docker deployment page.

* Fix link.

* Fix missing link in pipeline.

* Apply suggestions from code review

Co-authored-by: Dirk Eddelbuettel <edd@debian.org>

* Try to get some more information on the build failure.

* Fix link that now redirects.

* Try to get some more information about why we are not linking against OpenBLAS.

* I think the variable name was wrong, we will see...

* Clean things up since the build should work now.

---------

Co-authored-by: Dirk Eddelbuettel <edd@debian.org>
2025-03-12 16:49:34 -04:00

728 lines
26 KiB
CMake

# - Find mlpack
# Find the mlpack C++ library
#
# author Omar Shrit
##===================================================
## FUNCTION DOCUMENTATION
##===================================================
#
# find_mlpack()
#----------------------
#
# Call this macro to find mlpack and its dependencies (Armadillo, ensmallen,
# cereal, and any Armadillo dependencies).
#
# This function will not automatically download any missing dependencies, and
# will instead throw errors if dependencies are not found. For a version that
# automatically downloads dependencies, see `fetch_mlpack()`.
#
# Configuration options:
#
# MLPACK_DISABLE_OPENMP: if set, parallelism via OpenMP will be disabled.
# MLPACK_USE_SYSTEM_STB: if set, STB will be searched for on the system,
# instead of using the version bundled with mlpack.
#
# If mlpack is successfully found, the `MLPACK_FOUND` variable will be set to
# `TRUE`; otherwise, it will be set to `FALSE`.
#
# This macro will set the following variables:
#
# MLPACK_INCLUDE_DIRS: list of all include directories for mlpack and its
# dependencies (Armadillo, cereal, ensmallen)
# MLPACK_LIBRARIES: list of all dependency libraries to link against (typically
# just OpenBLAS)
#
#
# fetch_mlpack(COMPILE_OPENBLAS)
#-----------------------
#
# This macro downloads the mlpack library and its dependencies. Call this
# function to find mlpack and its dependencies (Armadillo, ensmallen, cereal) on
# a system where mlpack or those dependencies may not be available.
#
# fetch_mlpack() accepts one parameter, `COMPILE_OPENBLAS`. When this is set to
# `TRUE`, then OpenBLAS will be downloaded and compiled as a dependency of
# Armadillo. If `COMPILE_OPENBLAS` is set to `FALSE`, then it is expected that
# OpenBLAS or a BLAS/LAPACK library is already available on the system. When
# CMAKE_CROSSCOMPILING is set, then OpenBLAS is always compiled for the target
# architecture.
#
# Other dependencies of mlpack do not need compilation, as they are all
# header-only.
#
# If mlpack is not found on the system, `fetch_mlpack()` will download the
# latest stable version of mlpack.
#
# Configuration options:
#
# MLPACK_DISABLE_OPENMP: if set, parallelism via OpenMP will be disabled.
# MLPACK_USE_SYSTEM_STB: if set, STB will be searched for on the system,
# instead of using the version bundled with mlpack.
#
# After all libraries are downloaded and set up, the macro will set the
# following variables:
#
# MLPACK_INCLUDE_DIRS: list of all include directories for mlpack and its
# dependencies (Armadillo, cereal, ensmallen)
# MLPACK_LIBRARIES: list of all dependency libraries to link against (typically
# just OpenBLAS)
#
##===================================================
## INTERNAL FUNCTION DOCUMENTATION
##===================================================
#
# get_deps(LINK DEPS_NAME PACKAGE)
#-------------------
#
# This macro allows to download dependenices from the link that is provided to
# them. You need to pass the LINK to download from, the name of
# the dependency, and the filename to store the downloaded package to such
# as armadillo.tar.gz and they are downloaded into
# ${CMAKE_BINARY_DIR}/deps/${PACKAGE}
# At each download, this module sets a GENERIC_INCLUDE_DIR path,
# which means that you need to set the main path for the include
# directories for each package.
# Note that, the package should be compressed only as .tar.gz
#
#
# find_armadillo()
#------------------
#
# This macro finds armadillo library, and sets the necessary paths to each
# one of the parameters. If the library is not found this macro will set
# ARMADILLO_FOUND to false.
#
# This macro sets the following variables:
# ARMADILLO_FOUND - set to true if the library is found
# ARMADILLO_INCLUDE_DIRS - list of required include directories
# ARMADILLO_LIBRARIES - list of libraries to be linked
# ARMADILLO_VERSION_MAJOR - major version number
# ARMADILLO_VERSION_MINOR - minor version number
# ARMADILLO_VERSION_PATCH - patch version number
# ARMADILLO_VERSION_STRING - version number as a string (ex: "1.0.4")
# ARMADILLO_VERSION_NAME - name of the version (ex: "Antipodean Antileech")
#
#
# find_ensmallen
#------------------
#
# This macro finds ensmallen library and sets the necessary paths to each
# one of the parameters. If the library is not found this function will set
# ENSMALLEN_FOUND to false.
#
# This module sets the following variables:
# ENSMALLEN_FOUND - set to true if the library is found
# ENSMALLEN_INCLUDE_DIR - list of required include directories
# ENSMALLEN_VERSION_MAJOR - major version number
# ENSMALLEN_VERSION_MINOR - minor version number
# ENSMALLEN_VERSION_PATCH - patch version number
# ENSMALLEN_VERSION_STRING - version number as a string (ex: "1.0.4")
# ENSMALLEN_VERSION_NAME - name of the version (ex: "Antipodean Antileech")
#
#
# find_cereal()
#------------------
#
# This macro finds cereal library and sets the necessary paths to each
# one of the parameters. If the library is not found this macro will set
# CEREAL_FOUND to false.
# This module sets the following variables:
# CEREAL_FOUND - set to true if the library is found
# CEREAL_INCLUDE_DIR - list of required include directories
# CEREAL_VERSION_MAJOR - major version number
# CEREAL_VERSION_MINOR - minor version number
# CEREAL_VERSION_PATCH - patch version number
# CEREAL_VERSION_STRING - version number as a string (ex: "1.0.4")
#
#
# find stb()
#------------------
#
# This macro finds STB library and sets the necessary paths to each
# one of the parameters. If the library is not found this macro will set
# STB_FOUND to false.
#
# - Find STB_IMAGE
#
# This module sets the following variables:
# STB_IMAGE_FOUND - set to true if the library is found
# STB_IMAGE_INCLUDE_DIR - list of required include directories
# STB_INCLUDE_NEEDS_STB_SUFFIX - whether or not the include files are under an
# stb/ directory; if "YES", then includes must be done as, e.g.,
# stb/stb_image.h.
#
#
# find_openmp()
#-----------------------
#
# This macro finds if OpenMP library is installed and supported by the
# compiler. if the library found then it sets the following parameters:
#
# OpenMP_FOUND - set to true if the library is found
#
#
# find_mlpack_internal()
#-----------------------
#
# This macro finds the mlpack library and sets the necessary paths to each one
# of the parameters. If the library is not found this macro will set
# MLPACK_FOUND to false.
#
# This module sets the following variables:
# MLPACK_FOUND - set to true if the library is found
# MLPACK_VERSION_MAJOR - major version number
# MLPACK_VERSION_MINOR - minor version number
# MLPACK_VERSION_PATCH - patch version number
# MLPACK_VERSION_STRING - version number as a string (ex: "1.0.4")
# MLPACK_INCLUDE_DIR - list of mlpack include directories
#
#
##===================================================
## MLPACK DEPENDENCIES SETTINGS.
##===================================================
# Set minimum library versions required by mlpack.
#
# For Armadillo, try to keep the minimum required version less than or equal to
# what's available on the current Ubuntu LTS or most recent stable RHEL release.
# See https://github.com/mlpack/mlpack/issues/3033 for some more discussion.
set(ARMADILLO_VERSION "10.8.2")
set(ENSMALLEN_VERSION "2.10.0")
set(CEREAL_VERSION "1.1.2")
set(OPENBLAS_VERSION "0.3.29")
# Set library version to be used when fetching them from the source.
set(ARMADILLO_FETCH_VERSION "12.6.5")
set(ENSMALLEN_FETCH_VERSION "latest")
set(CEREAL_FETCH_VERSION "1.3.2")
set(MLPACK_FETCH_VERSION "latest")
# Set required standard to C++17.
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(MLPACK_DISABLE_OPENMP OFF)
##===================================================
## MLPACK AUTODOWNLOADER DEPENDENCIES FUNCTIONS
##===================================================
# This function auto-downloads mlpack dependencies.
macro(get_deps LINK DEPS_NAME PACKAGE)
if (NOT EXISTS "${CMAKE_BINARY_DIR}/deps/${PACKAGE}")
file(DOWNLOAD ${LINK}
"${CMAKE_BINARY_DIR}/deps/${PACKAGE}"
STATUS DOWNLOAD_STATUS_LIST LOG DOWNLOAD_LOG
SHOW_PROGRESS)
list(GET DOWNLOAD_STATUS_LIST 0 DOWNLOAD_STATUS)
if (DOWNLOAD_STATUS EQUAL 0)
execute_process(COMMAND ${CMAKE_COMMAND} -E
tar xf "${CMAKE_BINARY_DIR}/deps/${PACKAGE}"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/deps/")
else ()
list(GET DOWNLOAD_STATUS_LIST 1 DOWNLOAD_ERROR)
message(FATAL_ERROR
"Could not download ${DEPS_NAME}! Error code ${DOWNLOAD_STATUS}: ${DOWNLOAD_ERROR}! Error log: ${DOWNLOAD_LOG}")
endif()
endif()
# Get the name of the directory.
file (GLOB DIRECTORIES RELATIVE "${CMAKE_BINARY_DIR}/deps/"
"${CMAKE_BINARY_DIR}/deps/${DEPS_NAME}*.*")
if(${DEPS_NAME} MATCHES "stb")
file (GLOB DIRECTORIES RELATIVE "${CMAKE_BINARY_DIR}/deps/"
"${CMAKE_BINARY_DIR}/deps/${DEPS_NAME}")
endif()
# list(FILTER) is not available on 3.5 or older, but try to keep
# configuring without filtering the list anyway
# (it works only if the file is present as .tar.gz).
list(FILTER DIRECTORIES EXCLUDE REGEX ".*\.tar\.gz")
list(LENGTH DIRECTORIES DIRECTORIES_LEN)
if (DIRECTORIES_LEN GREATER 0)
list(GET DIRECTORIES 0 DEPENDENCY_DIR)
set(GENERIC_INCLUDE_DIR "${CMAKE_BINARY_DIR}/deps/${DEPENDENCY_DIR}/include")
install(DIRECTORY "${GENERIC_INCLUDE_DIR}/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
else ()
message(FATAL_ERROR
"Problem unpacking ${DEPS_NAME}! Expected only one directory "
"${DEPS_NAME};. Try to remove the directory ${CMAKE_BINARY_DIR}/deps and reconfigure.")
endif ()
endmacro()
macro(find_armadillo)
cmake_policy(PUSH)
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.29")
cmake_policy(SET CMP0159 NEW) # file(STRINGS) with REGEX updates CMAKE_MATCH_<n>
endif()
set(CURRENT_PATH ${ARGN})
if (CURRENT_PATH)
find_path(ARMADILLO_INCLUDE_DIR
NAMES armadillo
PATHS "${CURRENT_PATH}/deps/Armadillo/include"
NO_DEFAULT_PATH)
else()
find_path(ARMADILLO_INCLUDE_DIR
NAMES armadillo
PATHS "$ENV{ProgramFiles}/Armadillo/include")
endif()
if (ARMADILLO_INCLUDE_DIR)
# ------------------------------------------------------------------------
# Extract version information from <armadillo>
# ------------------------------------------------------------------------
# WARNING: Early releases of Armadillo didn't have the arma_version.hpp file.
# (e.g. v.0.9.8-1 in ubuntu maverick packages (2001-03-15))
# If the file is missing, set all values to 0
set(ARMADILLO_VERSION_MAJOR 0)
set(ARMADILLO_VERSION_MINOR 0)
set(ARMADILLO_VERSION_PATCH 0)
set(ARMADILLO_VERSION_NAME "EARLY RELEASE")
if (EXISTS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/arma_version.hpp")
# Read and parse armdillo version header file for version number
file(STRINGS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/arma_version.hpp" _ARMA_HEADER_CONTENTS REGEX "#define ARMA_VERSION_[A-Z]+ ")
string(REGEX REPLACE ".*#define ARMA_VERSION_MAJOR ([0-9]+).*" "\\1" ARMADILLO_VERSION_MAJOR "${_ARMA_HEADER_CONTENTS}")
string(REGEX REPLACE ".*#define ARMA_VERSION_MINOR ([0-9]+).*" "\\1" ARMADILLO_VERSION_MINOR "${_ARMA_HEADER_CONTENTS}")
string(REGEX REPLACE ".*#define ARMA_VERSION_PATCH ([0-9]+).*" "\\1" ARMADILLO_VERSION_PATCH "${_ARMA_HEADER_CONTENTS}")
# WARNING: The number of spaces before the version name is not one.
string(REGEX REPLACE ".*#define ARMA_VERSION_NAME\ +\"([0-9a-zA-Z\ _-]+)\".*" "\\1" ARMADILLO_VERSION_NAME "${_ARMA_HEADER_CONTENTS}")
set(ARMADILLO_FOUND YES)
endif()
set(ARMADILLO_VERSION_STRING "${ARMADILLO_VERSION_MAJOR}.${ARMADILLO_VERSION_MINOR}.${ARMADILLO_VERSION_PATCH}")
endif()
if (EXISTS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/config.hpp")
file(STRINGS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/config.hpp" _ARMA_CONFIG_CONTENTS REGEX "^#define ARMA_USE_[A-Z]+")
string(REGEX MATCH "ARMA_USE_WRAPPER" _ARMA_USE_WRAPPER "${_ARMA_CONFIG_CONTENTS}")
string(REGEX MATCH "ARMA_USE_LAPACK" _ARMA_USE_LAPACK "${_ARMA_CONFIG_CONTENTS}")
string(REGEX MATCH "ARMA_USE_BLAS" _ARMA_USE_BLAS "${_ARMA_CONFIG_CONTENTS}")
string(REGEX MATCH "ARMA_USE_ARPACK" _ARMA_USE_ARPACK "${_ARMA_CONFIG_CONTENTS}")
string(REGEX MATCH "ARMA_USE_HDF5" _ARMA_USE_HDF5 "${_ARMA_CONFIG_CONTENTS}")
endif()
# If _ARMA_USE_WRAPPER is set, then we just link to armadillo, but if it's not then we need support libraries instead
set(_ARMA_SUPPORT_LIBRARIES)
if(_ARMA_USE_WRAPPER)
# Link to the armadillo wrapper library.
find_library(ARMADILLO_LIBRARY
NAMES armadillo
NAMES_PER_DIR
PATHS
"$ENV{ProgramFiles}/Armadillo/lib"
"$ENV{ProgramFiles}/Armadillo/lib64"
"$ENV{ProgramFiles}/Armadillo"
)
set(_ARMA_REQUIRED_VARS ARMADILLO_LIBRARY)
else()
set(ARMADILLO_LIBRARY "")
endif()
# Transitive linking with the wrapper does not work with MSVC,
# so we must *also* link against Armadillo's dependencies.
if(NOT _ARMA_USE_WRAPPER OR MSVC)
# Link directly to individual components.
foreach(pkg
LAPACK
BLAS
ARPACK
HDF5
)
if(_ARMA_USE_${pkg})
find_package(${pkg} QUIET)
list(APPEND _ARMA_REQUIRED_VARS "${pkg}_FOUND")
if(${pkg}_FOUND)
list(APPEND _ARMA_SUPPORT_LIBRARIES ${${pkg}_LIBRARIES})
endif()
endif()
endforeach()
endif()
if (ARMADILLO_FOUND)
set(ARMADILLO_INCLUDE_DIRS ${ARMADILLO_INCLUDE_DIR})
set(ARMADILLO_LIBRARIES ${ARMADILLO_LIBRARY} ${_ARMA_SUPPORT_LIBRARIES})
endif()
# Clean up internal variables
unset(_ARMA_REQUIRED_VARS)
unset(_ARMA_SUPPORT_LIBRARIES)
unset(_ARMA_USE_WRAPPER)
unset(_ARMA_USE_LAPACK)
unset(_ARMA_USE_BLAS)
unset(_ARMA_USE_ARPACK)
unset(_ARMA_USE_HDF5)
unset(_ARMA_CONFIG_CONTENTS)
unset(_ARMA_HEADER_CONTENTS)
cmake_policy(POP)
endmacro()
# Findcereal.cmake
macro(find_cereal)
set(CURRENT_PATH ${ARGN})
if (CURRENT_PATH)
find_path(CEREAL_INCLUDE_DIR
NAMES cereal
PATHS "${CURRENT_PATH}/deps/cereal/include"
NO_DEFAULT_PATH)
else()
find_path(CEREAL_INCLUDE_DIR
NAMES cereal
PATHS "$ENV{ProgramFiles}/cereal/include")
endif()
if (CEREAL_INCLUDE_DIR)
# ------------------------------------------------------------------------
# Extract version information from <CEREAL>
# ------------------------------------------------------------------------
set(CEREAL_FOUND YES)
set(CEREAL_VERSION_MAJOR 0)
set(CEREAL_VERSION_MINOR 0)
set(CEREAL_VERSION_PATCH 0)
if (EXISTS "${CEREAL_INCLUDE_DIR}/cereal/version.hpp")
# Read and parse cereal version header file for version number
file(READ "${CEREAL_INCLUDE_DIR}/cereal/version.hpp"
_CEREAL_HEADER_CONTENTS)
string(REGEX REPLACE ".*#define CEREAL_VERSION_MAJOR ([0-9]+).*" "\\1"
CEREAL_VERSION_MAJOR "${_CEREAL_HEADER_CONTENTS}")
string(REGEX REPLACE ".*#define CEREAL_VERSION_MINOR ([0-9]+).*" "\\1"
CEREAL_VERSION_MINOR "${_CEREAL_HEADER_CONTENTS}")
string(REGEX REPLACE ".*#define CEREAL_VERSION_PATCH ([0-9]+).*" "\\1"
CEREAL_VERSION_PATCH "${_CEREAL_HEADER_CONTENTS}")
elseif (EXISTS "${CEREAL_INCLUDE_DIR}/cereal/details/polymorphic_impl_fwd.hpp")
set(CEREAL_VERSION_MAJOR 1)
set(CEREAL_VERSION_MINOR 2)
set(CEREAL_VERSION_PATCH 0)
elseif (EXISTS "${CEREAL_INCLUDE_DIR}/cereal/types/valarray.hpp")
set(CEREAL_VERSION_MAJOR 1)
set(CEREAL_VERSION_MINOR 1)
set(CEREAL_VERSION_PATCH 2)
elseif (EXISTS "${CEREAL_INCLUDE_DIR}/cereal/cereal.hpp")
set(CEREAL_VERSION_MAJOR 1)
set(CEREAL_VERSION_MINOR 1)
set(CEREAL_VERSION_PATCH 1)
else()
set(CEREAL_FOUND NO)
endif()
set(CEREAL_VERSION_STRING "${CEREAL_VERSION_MAJOR}.${CEREAL_VERSION_MINOR}.${CEREAL_VERSION_PATCH}")
endif ()
endmacro()
macro(find_ensmallen)
set(CURRENT_PATH ${ARGN})
if (CURRENT_PATH)
find_path(ENSMALLEN_INCLUDE_DIR
NAMES ensmallen.hpp
PATHS "${CURRENT_PATH}/deps/ensmallen/include"
NO_DEFAULT_PATH)
else()
file(GLOB ENSMALLEN_SEARCH_PATHS
${CMAKE_BINARY_DIR}/deps/ensmallen-[0-9]*.[0-9]*.[0-9]*)
find_path(ENSMALLEN_INCLUDE_DIR
NAMES ensmallen.hpp
PATHS ${ENSMALLEN_SEARCH_PATHS}/include)
endif()
if (ENSMALLEN_INCLUDE_DIR)
# ------------------------------------------------------------------------
# Extract version information from <ensmallen>
# ------------------------------------------------------------------------
set(ENSMALLEN_VERSION_MAJOR 0)
set(ENSMALLEN_VERSION_MINOR 0)
set(ENSMALLEN_VERSION_PATCH 0)
set(ENSMALLEN_VERSION_NAME "unknown")
if(EXISTS "${ENSMALLEN_INCLUDE_DIR}/ensmallen_bits/ens_version.hpp")
set(ENSMALLEN_FOUND YES)
# Read and parse Ensmallen version header file for version number
file(READ "${ENSMALLEN_INCLUDE_DIR}/ensmallen_bits/ens_version.hpp"
_ensmallen_HEADER_CONTENTS)
string(REGEX REPLACE ".*#define ENS_VERSION_MAJOR ([0-9]+).*" "\\1"
ENSMALLEN_VERSION_MAJOR "${_ensmallen_HEADER_CONTENTS}")
string(REGEX REPLACE ".*#define ENS_VERSION_MINOR ([0-9]+).*" "\\1"
ENSMALLEN_VERSION_MINOR "${_ensmallen_HEADER_CONTENTS}")
string(REGEX REPLACE ".*#define ENS_VERSION_PATCH ([0-9]+).*" "\\1"
ENSMALLEN_VERSION_PATCH "${_ensmallen_HEADER_CONTENTS}")
# WARNING: The number of spaces before the version name is not one.
string(REGEX REPLACE
".*#define ENS_VERSION_NAME\ +\"([0-9a-zA-Z\ _-]+)\".*" "\\1"
ENSMALLEN_VERSION_NAME "${_ensmallen_HEADER_CONTENTS}")
endif()
set(ENSMALLEN_VERSION_STRING "${ENSMALLEN_VERSION_MAJOR}.${ENSMALLEN_VERSION_MINOR}.${ENSMALLEN_VERSION_PATCH}")
endif ()
endmacro()
macro(find_stb)
file(GLOB STB_IMAGE_SEARCH_PATHS
${CMAKE_BINARY_DIR}/deps/
${CMAKE_BINARY_DIR}/deps/stb)
find_path(STB_IMAGE_INCLUDE_DIR_1
NAMES stb_image.h stb_image_write.h stb_image_resize2.h
PATHS ${STB_IMAGE_SEARCH_PATHS} ${STB_IMAGE_INCLUDE_DIR})
if(STB_IMAGE_INCLUDE_DIR_1)
set(STB_IMAGE_INCLUDE_DIR "${STB_IMAGE_INCLUDE_DIR_1}" CACHE PATH
"stb_image include directory")
# Either we found /usr/include/stb_image.h (or similar), or the user passed
# a directory in STB_IMAGE_SEARCH_PATHS that directly contains stb_image.h.
# In either of those cases, we want to include <stb_image.h>, not
# <stb/stb_image.h>.
set(STB_INCLUDE_NEEDS_STB_SUFFIX "NO")
else ()
find_path(STB_IMAGE_INCLUDE_DIR_2
NAMES stb_image.h stb_image_write.h stb_image_resize2.h
PATHS ${STB_IMAGE_SEARCH_PATHS} ${STB_IMAGE_INCLUDE_DIR}
PATH_SUFFIXES stb/)
if (STB_IMAGE_INCLUDE_DIR_2)
set(STB_IMAGE_INCLUDE_DIR "${STB_IMAGE_INCLUDE_DIR_2}" CACHE PATH
"stb_image include directory")
# Since we searched the same paths but allowed an stb/ suffix this time,
# then there is definitely a suffix.
set(STB_INCLUDE_NEEDS_STB_SUFFIX "YES")
# Strip the suffix.
string(REGEX REPLACE ".*stb[/]?$" "" STB_IMAGE_INCLUDE_DIR
"${STB_IMAGE_INCLUDE_DIR}")
endif ()
endif ()
endmacro()
macro(find_openmp)
find_package(OpenMP)
if (OpenMP_FOUND AND OpenMP_CXX_VERSION VERSION_GREATER_EQUAL 3.0.0)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${OpenMP_CXX_LIBRARIES})
else ()
# Disable warnings for all the unknown OpenMP pragmas.
if (NOT MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-pragmas")
else ()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4068")
endif ()
set(OpenMP_CXX_FLAGS "")
endif ()
endmacro()
macro(find_mlpack_internal)
set(CURRENT_PATH ${ARGN})
if (CURRENT_PATH)
file(GLOB MLPACK_SEARCH_PATHS
${CURRENT_PATH}/deps/mlpack-[0-9]*.[0-9]*.[0-9]*/src/)
list(POP_BACK MLPACK_SEARCH_PATHS MLPACK_SEARCH_PATH)
if (EXISTS ${MLPACK_SEARCH_PATH}/mlpack.hpp)
set(MLPACK_INCLUDE_DIR ${MLPACK_SEARCH_PATH})
endif()
else()
file(GLOB MLPACK_SEARCH_PATHS
${CMAKE_BINARY_DIR}/deps/mlpack-[0-9]*.[0-9]*.[0-9]*)
# This will be executed if mlpack is installed already.
find_path(MLPACK_INCLUDE_DIR
NAMES mlpack.hpp
PATHS ${MLPACK_SEARCH_PATHS}/include)
# This will be executed when compiling mlpack bindings and tests.
if (NOT MLPACK_INCLUDE_DIR)
find_path(MLPACK_INCLUDE_DIR
NAMES mlpack.hpp
PATHS "${CMAKE_CURRENT_SOURCE_DIR}/src/")
endif()
endif()
if (MLPACK_INCLUDE_DIR)
# ------------------------------------------------------------------------
# Extract version information from <mlpack>
# ------------------------------------------------------------------------
set(MLPACK_VERSION_MAJOR 0)
set(MLPACK_VERSION_MINOR 0)
set(MLPACK_VERSION_PATCH 0)
if (EXISTS "${MLPACK_INCLUDE_DIR}/mlpack/core/util/version.hpp")
set(MLPACK_FOUND YES)
# Read and parse mlpack version header file for version number
file(READ "${MLPACK_INCLUDE_DIR}/mlpack/core/util/version.hpp"
_mlpack_HEADER_CONTENTS)
string(REGEX REPLACE ".*#define MLPACK_VERSION_MAJOR ([0-9]+).*" "\\1"
MLPACK_VERSION_MAJOR "${_mlpack_HEADER_CONTENTS}")
string(REGEX REPLACE ".*#define MLPACK_VERSION_MINOR ([0-9]+).*" "\\1"
MLPACK_VERSION_MINOR "${_mlpack_HEADER_CONTENTS}")
string(REGEX REPLACE ".*#define MLPACK_VERSION_PATCH ([0-9]+).*" "\\1"
MLPACK_VERSION_PATCH "${_mlpack_HEADER_CONTENTS}")
endif()
set(MLPACK_VERSION_STRING "${MLPACK_VERSION_MAJOR}.${MLPACK_VERSION_MINOR}.${MLPACK_VERSION_PATCH}")
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(mlpack
REQUIRED_VARS MLPACK_INCLUDE_DIR
VERSION_VAR MLPACK_VERSION_STRING)
endmacro()
macro(fetch_mlpack COMPILE_OPENBLAS)
if (CMAKE_CROSSCOMPILING)
search_openblas(${OPENBLAS_VERSION})
# Set to cross compile openblas if the user forgot to do so.
set(COMPILE_OPENBLAS ON)
endif()
find_package(BLAS PATHS ${CMAKE_BINARY_DIR})
if (NOT BLAS_FOUND OR (NOT BLAS_LIBRARIES))
get_deps(https://github.com/xianyi/OpenBLAS/releases/download/v${OPENBLAS_VERSION}/OpenBLAS-${OPENBLAS_VERSION}.tar.gz
OpenBLAS OpenBLAS-${OPENBLAS_VERSION}.tar.gz)
if (NOT COMPILE_OPENBLAS)
message(WARNING "OpenBLAS is downloaded but not compiled. Please compile
OpenBLAS before compiling mlpack")
else()
execute_process(COMMAND make NO_SHARED=1 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/deps/OpenBLAS-${OPENBLAS_VERSION})
file(GLOB OPENBLAS_LIBRARIES "${CMAKE_BINARY_DIR}/deps/OpenBLAS-${OPENBLAS_VERSION}/libopenblas.a")
set(BLAS_openblas_LIBRARY ${OPENBLAS_LIBRARIES})
set(LAPACK_openblas_LIBRARY ${OPENBLAS_LIBRARIES})
set(BLAS_FOUND ON)
endif()
endif()
find_armadillo(${CMAKE_BINARY_DIR})
if (NOT ARMADILLO_FOUND)
if (NOT CMAKE_CROSSCOMPILING)
find_package(BLAS QUIET)
find_package(LAPACK QUIET)
endif()
get_deps(https://files.mlpack.org/armadillo-${ARMADILLO_FETCH_VERSION}.tar.gz armadillo armadillo-${ARMADILLO_FETCH_VERSION}.tar.gz)
set(ARMADILLO_INCLUDE_DIR ${GENERIC_INCLUDE_DIR})
find_armadillo(${CMAKE_BINARY_DIR})
endif()
if (ARMADILLO_FOUND)
# Include directories for the previous dependencies.
set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${ARMADILLO_INCLUDE_DIRS})
set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${ARMADILLO_LIBRARIES})
endif()
find_ensmallen(${CMAKE_BINARY_DIR})
if (NOT ENSMALLEN_FOUND)
get_deps(https://www.ensmallen.org/files/ensmallen-${ENSMALLEN_FETCH_VERSION}.tar.gz ensmallen ensmallen-${ENSMALLEN_FETCH_VERSION}.tar.gz)
set(ENSMALLEN_INCLUDE_DIR ${GENERIC_INCLUDE_DIR})
find_ensmallen(${CMAKE_BINARY_DIR})
endif()
if (ENSMALLEN_FOUND)
set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${ENSMALLEN_INCLUDE_DIR})
endif()
find_cereal(${CMAKE_BINARY_DIR})
if (NOT CEREAL_FOUND)
get_deps(https://github.com/USCiLab/cereal/archive/refs/tags/v${CEREAL_FETCH_VERSION}.tar.gz cereal cereal-${CEREAL_FETCH_VERSION}.tar.gz)
set(CEREAL_INCLUDE_DIR ${GENERIC_INCLUDE_DIR})
find_cereal(${CMAKE_BINARY_DIR})
endif()
if (CEREAL_FOUND)
set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${CEREAL_INCLUDE_DIR})
endif()
find_mlpack_internal(${CMAKE_BINARY_DIR})
if (NOT MLPACK_FOUND)
get_deps(https://www.mlpack.org/files/mlpack-${MLPACK_FETCH_VERSION}.tar.gz mlpack mlpack-${MLPACK_FETCH_VERSION}.tar.gz)
set(MLPACK_INCLUDE_DIR ${GENERIC_INCLUDE_DIR})
find_mlpack_internal(${CMAKE_BINARY_DIR})
endif()
if (MLPACK_FOUND)
set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${MLPACK_INCLUDE_DIR})
endif()
find_openmp()
endmacro()
##===================================================
## MLPACK MAIN FUNCTIONS CALL.
##===================================================
macro(find_mlpack)
# If we're using gcc, then we need to link against pthreads to use std::thread,
# which we do in the tests.
if (CMAKE_COMPILER_IS_GNUCC)
find_package(Threads)
set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
endif()
if (NOT MLPACK_DISABLE_OPENMP)
find_openmp()
endif ()
find_armadillo()
if (ARMADILLO_FOUND)
set(MLPACK_INCLUDE_DIRS ${ARMADILLO_INCLUDE_DIRS})
set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${ARMADILLO_LIBRARIES})
else()
message(FATAL_ERROR "Armadillo not found, (required dependency of mlpack).")
endif ()
find_ensmallen()
if (ENSMALLEN_FOUND)
set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${ENSMALLEN_INCLUDE_DIR})
else()
message(FATAL_ERROR "Ensmallen not found, (required dependency of mlpack).")
endif()
find_cereal()
if (CEREAL_FOUND)
set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${CEREAL_INCLUDE_DIR})
else()
message(FATAL_ERROR "Cereal not found, (required dependency of mlpack).")
endif()
if (MLPACK_USE_SYSTEM_STB)
find_stb()
endif()
if (StbImage_FOUND)
set(STB_AVAILABLE "1")
add_definitions(-DMLPACK_USE_SYSTEM_STB)
set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${STB_IMAGE_INCLUDE_DIR})
endif()
find_mlpack_internal()
if (MLPACK_FOUND)
set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${MLPACK_INCLUDE_DIR})
else()
message(FATAL_ERROR "mlpack not found!")
endif()
mark_as_advanced(MLPACK_INCLUDE_DIR)
mark_as_advanced(MLPACK_INCLUDE_DIRS)
mark_as_advanced(MLPACK_LIBRARIES)
endmacro()