From 9358247014eb8322160c7feaad46091412d75d3f Mon Sep 17 00:00:00 2001 From: Anatoly Baksheev Date: Wed, 17 Dec 2014 12:09:14 +0300 Subject: [PATCH] improve CMake build --- .gitignore | 3 - CMakeLists.txt | 199 +++------- CMakeScripts/FindLMDB.cmake | 28 -- CMakeScripts/FindLevelDB.cmake | 37 -- CMakeScripts/FindNumPy.cmake | 103 ----- CMakeScripts/FindProtobuf.cmake | 152 -------- CMakeScripts/FindSnappy.cmake | 33 -- cmake/ConfigGen.cmake | 86 +++++ cmake/Cuda.cmake | 243 ++++++++++++ cmake/Dependencies.cmake | 124 ++++++ cmake/Misc.cmake | 47 +++ .../Modules}/FindAtlas.cmake | 25 +- .../Modules}/FindGFlags.cmake | 6 +- .../Modules}/FindGlog.cmake | 14 +- .../Modules}/FindLAPACK.cmake | 0 cmake/Modules/FindLMDB.cmake | 28 ++ cmake/Modules/FindLevelDB.cmake | 44 +++ {CMakeScripts => cmake/Modules}/FindMKL.cmake | 0 cmake/Modules/FindMatlabMex.cmake | 48 +++ cmake/Modules/FindNumPy.cmake | 58 +++ .../Modules}/FindOpenBLAS.cmake | 0 cmake/Modules/FindSnappy.cmake | 28 ++ cmake/Modules/FindvecLib.cmake | 34 ++ cmake/ProtoBuf.cmake | 90 +++++ cmake/Summary.cmake | 166 ++++++++ cmake/Targets.cmake | 170 ++++++++ cmake/Templates/CaffeConfig.cmake.in | 58 +++ cmake/Templates/CaffeConfigVersion.cmake.in | 11 + cmake/Templates/caffe_config.h.in | 32 ++ cmake/Utils.cmake | 365 ++++++++++++++++++ {CMakeScripts => cmake}/lint.cmake | 0 docs/CMakeLists.txt | 106 +++++ examples/CMakeLists.txt | 41 +- include/caffe/test/test_caffe_main.hpp | 2 +- matlab/CMakeLists.txt | 73 +++- python/CMakeLists.txt | 77 ++-- src/caffe/CMakeLists.txt | 75 ++-- src/caffe/proto/CMakeLists.txt | 46 --- src/caffe/test/CMakeLists.txt | 135 ++----- src/caffe/test/cmake_test_defines.hpp.in | 4 - .../test/test_data/sample_data_list.txt.in | 2 - src/gtest/CMakeLists.txt | 9 +- tools/CMakeLists.txt | 47 ++- 43 files changed, 2017 insertions(+), 832 deletions(-) delete mode 100644 CMakeScripts/FindLMDB.cmake delete mode 100644 CMakeScripts/FindLevelDB.cmake delete mode 100644 CMakeScripts/FindNumPy.cmake delete mode 100644 CMakeScripts/FindProtobuf.cmake delete mode 100644 CMakeScripts/FindSnappy.cmake create mode 100644 cmake/ConfigGen.cmake create mode 100644 cmake/Cuda.cmake create mode 100644 cmake/Dependencies.cmake create mode 100644 cmake/Misc.cmake rename {CMakeScripts => cmake/Modules}/FindAtlas.cmake (63%) rename {CMakeScripts => cmake/Modules}/FindGFlags.cmake (79%) rename {CMakeScripts => cmake/Modules}/FindGlog.cmake (70%) rename {CMakeScripts => cmake/Modules}/FindLAPACK.cmake (100%) create mode 100644 cmake/Modules/FindLMDB.cmake create mode 100644 cmake/Modules/FindLevelDB.cmake rename {CMakeScripts => cmake/Modules}/FindMKL.cmake (100%) create mode 100644 cmake/Modules/FindMatlabMex.cmake create mode 100644 cmake/Modules/FindNumPy.cmake rename {CMakeScripts => cmake/Modules}/FindOpenBLAS.cmake (100%) create mode 100644 cmake/Modules/FindSnappy.cmake create mode 100644 cmake/Modules/FindvecLib.cmake create mode 100644 cmake/ProtoBuf.cmake create mode 100644 cmake/Summary.cmake create mode 100644 cmake/Targets.cmake create mode 100644 cmake/Templates/CaffeConfig.cmake.in create mode 100644 cmake/Templates/CaffeConfigVersion.cmake.in create mode 100644 cmake/Templates/caffe_config.h.in create mode 100644 cmake/Utils.cmake rename {CMakeScripts => cmake}/lint.cmake (100%) create mode 100644 docs/CMakeLists.txt delete mode 100644 src/caffe/proto/CMakeLists.txt delete mode 100644 src/caffe/test/cmake_test_defines.hpp.in delete mode 100644 src/caffe/test/test_data/sample_data_list.txt.in diff --git a/.gitignore b/.gitignore index 58adc5cb106..73bba6cb364 100644 --- a/.gitignore +++ b/.gitignore @@ -29,9 +29,6 @@ # IPython notebook checkpoints .ipynb_checkpoints -# CMake generated files -*.gen.cmake - # Editor temporaries *.swp *~ diff --git a/CMakeLists.txt b/CMakeLists.txt index d6b08470a7f..d3d50da218b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,177 +1,64 @@ cmake_minimum_required(VERSION 2.8.8) -project( Caffe ) -### Build Options ########################################################################## +# ---[ Caffe project +project(Caffe C CXX) -option(CPU_ONLY "Build Caffe without GPU support" OFF) -option(BUILD_PYTHON "Build Python wrapper" OFF) -option(BUILD_MATLAB "Build Matlab wrapper" OFF) -option(BUILD_EXAMPLES "Build examples" ON) -option(BUILD_SHARED_LIBS "Build SHARED libs if ON and STATIC otherwise" OFF) +# ---[ Using cmake scripts and modules +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) -if(NOT BLAS) - set(BLAS atlas) -endif() +include(cmake/Utils.cmake) +include(cmake/Targets.cmake) +include(cmake/Misc.cmake) +include(cmake/Summary.cmake) +include(cmake/ConfigGen.cmake) -if(NOT CUDA_TEST_DEVICE) - set(CUDA_TEST_DEVICE -1) -endif() +# ---[ Options +caffe_option(CPU_ONLY "Build Caffe wihtout CUDA support" OFF) # TODO: rename to USE_CUDA +caffe_option(USE_CUDNN "Build Caffe with cuDNN libary support" ON IF NOT CPU_ONLY) +caffe_option(BUILD_SHARED_LIBS "Build shared libraries" ON) +caffe_option(BUILD_python "Build Python wrapper" ON) +caffe_option(BUILD_matlab "Build Matlab wrapper" OFF IF UNIX OR APPLE) +caffe_option(BUILD_docs "Build documentation" ON IF UNIX OR APPLE) -# Install Prefix -if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set (CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE PATH "Default install path" FORCE ) -endif() +# ---[ Dependencies +include(cmake/Dependencies.cmake) -### Configuration ########################################################################### -# Compiler Flags -set(CMAKE_CXX_COMPILER_FLAGS ${CMAKE_CXX_COMPILER_FLAGS} -Wall) -set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -fPIC) # set global flags -set(CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) # set debug flags -set(CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) # set release flags - -# Link Flags -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # clang++ - set(CAFFE_STATIC_LINK -Wl,-force_load $(STATIC_NAME)) -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") # g++ - set(CAFFE_STATIC_LINK -Wl,--whole-archive caffe -Wl,--no-whole-archive) +# ---[ Flags +if(UNIX OR APLE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall") endif() -# Global Definitions -if(CPU_ONLY) - add_definitions(-DCPU_ONLY) -endif() - -# Include Directories -set(${PROJECT_NAME}_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/include) -include_directories(${${PROJECT_NAME}_INCLUDE_DIRS}) -include_directories(${CMAKE_SOURCE_DIR}/src) - -# CMake Scripts dir -set(CMAKE_SCRIPT_DIR ${CMAKE_SOURCE_DIR}/CMakeScripts) - -# CMake module path for custom module finding -set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SCRIPT_DIR}) - -### Dependencies ########################################################################## - -# Boost -find_package(Boost 1.46 COMPONENTS system thread REQUIRED) -include_directories(${Boost_INCLUDE_DIR}) -link_directories(${Boost_LIBRARY_DIRS}) - -# CUDA -if(NOT CPU_ONLY) - find_package(CUDA 5.5 REQUIRED) - include_directories(${CUDA_INCLUDE_DIRS}) - - set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} - -gencode arch=compute_20,code=sm_20 - -gencode arch=compute_20,code=sm_21 - -gencode arch=compute_30,code=sm_30 - -gencode arch=compute_35,code=sm_35 - ) - - # https://github.com/ComputationalRadiationPhysics/picongpu/blob/master/src/picongpu/CMakeLists.txt - # work-arounds - if(Boost_VERSION EQUAL 105500) - # see https://svn.boost.org/trac/boost/ticket/9392 - message(STATUS "Boost: Applying noinline work around") - # avoid warning for CMake >= 2.8.12 - set(CUDA_NVCC_FLAGS - "${CUDA_NVCC_FLAGS} \"-DBOOST_NOINLINE=__attribute__((noinline))\" ") - endif(Boost_VERSION EQUAL 105500) +if(APPLE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++") endif() -# Threads -find_package(Threads REQUIRED) - -# Google-glog -find_package(Glog REQUIRED) -include_directories(${GLOG_INCLUDE_DIRS}) - -# Google-gflags -find_package(GFlags REQUIRED) -include_directories(${GFLAGS_INCLUDE_DIRS}) - -# BLAS -if(BLAS STREQUAL "atlas") - - find_package(Atlas REQUIRED) - include_directories(${Atlas_INCLUDE_DIR}) - set(BLAS_LIBRARIES ${Atlas_LIBRARIES}) - -elseif(BLAS STREQUAL "open") +add_definitions(-DGTEST_USE_OWN_TR1_TUPLE) - find_package(OpenBLAS REQUIRED) - include_directories(${OpenBLAS_INCLUDE_DIR}) - set(BLAS_LIBRARIES ${OpenBLAS_LIB}) +# ---[ Warnings +caffe_warnings_disable(CMAKE_CXX_FLAGS -Wno-sign-compare -Wno-uninitialized) -elseif(BLAS STREQUAL "mkl") +# ---[ Config generation +configure_file(cmake/Templates/caffe_config.h.in "${CMAKE_BINARY_DIR}/caffe_config.h") - find_package(MKL REQUIRED) - include_directories(${MKL_INCLUDE_DIR}) - set(BLAS_LIBRARIES ${MKL_LIBRARIES}) - -endif() - -# HDF5 -find_package(HDF5 COMPONENTS HL REQUIRED) -include_directories(${HDF5_INCLUDE_DIRS}) - -# LevelDB -find_package(LevelDB REQUIRED) -include_directories(${LEVELDB_INCLUDE}) -if(LEVELDB_FOUND) - find_package(Snappy REQUIRED) - include_directories(${SNAPPY_INCLUDE_DIR}) - set(LEVELDB_LIBS - ${LEVELDB_LIBS} - ${SNAPPY_LIBS} - ) -endif() - -# LMDB -find_package(LMDB REQUIRED) -include_directories(${LMDB_INCLUDE_DIR}) - -# OpenCV -find_package(OpenCV REQUIRED) -include_directories(${OpenCV_INCLUDE_DIRS}) - -### Subdirectories ########################################################################## +# ---[ Includes +set(Caffe_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include) +include_directories(${Caffe_INCLUDE_DIR} ${CMAKE_BINARY_DIR}) +include_directories(BEFORE src) # This is needed for gtest. +# ---[ Subdirectories add_subdirectory(src/gtest) add_subdirectory(src/caffe) add_subdirectory(tools) +add_subdirectory(examples) +add_subdirectory(python) +add_subdirectory(matlab) +add_subdirectory(docs) -if(BUILD_EXAMPLES) - message(STATUS "Examples enabled") - add_subdirectory(examples) -endif() - -if(BUILD_PYTHON) - message(STATUS "Python enabled") - add_subdirectory(python) -endif() - -if(BUILD_MATLAB) - message(STATUS "Matlab enabled") - add_subdirectory(matlab) -endif() - -### Lint Target Setup ########################################################################## - -set(LINT_TARGET lint) -set(LINT_SCRIPT ${CMAKE_SCRIPT_DIR}/lint.cmake) -add_custom_target( - ${LINT_TARGET} - COMMAND ${CMAKE_COMMAND} -P ${LINT_SCRIPT} -) - -### Install ################################################################################# - -# Install Includes -file(GLOB folders ${${PROJECT_NAME}_INCLUDE_DIRS}/*) -install(DIRECTORY ${folders} DESTINATION include) +# ---[ Linter target +add_custom_target(lint COMMAND ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/cmake/lint.cmake) +# ---[ Configuration summary +caffe_print_configuration_summary() +# ---[ Export configs generation +caffe_generate_export_configs() diff --git a/CMakeScripts/FindLMDB.cmake b/CMakeScripts/FindLMDB.cmake deleted file mode 100644 index e615f542335..00000000000 --- a/CMakeScripts/FindLMDB.cmake +++ /dev/null @@ -1,28 +0,0 @@ -# Try to find the LMBD libraries and headers -# LMDB_FOUND - system has LMDB lib -# LMDB_INCLUDE_DIR - the LMDB include directory -# LMDB_LIBRARIES - Libraries needed to use LMDB - -# FindCWD based on FindGMP by: -# Copyright (c) 2006, Laurent Montel, -# -# Redistribution and use is allowed according to the terms of the BSD license. - -# Adapted from FindCWD by: -# Copyright 2013 Conrad Steenberg -# Aug 31, 2013 - -if (LMDB_INCLUDE_DIR AND LMDB_LIBRARIES) - # Already in cache, be silent - set(LMDB_FIND_QUIETLY TRUE) -endif (LMDB_INCLUDE_DIR AND LMDB_LIBRARIES) - -find_path(LMDB_INCLUDE_DIR NAMES "lmdb.h" HINTS "$ENV{LMDB_DIR}/include") -find_library(LMDB_LIBRARIES NAMES lmdb HINTS $ENV{LMDB_DIR}/lib ) -MESSAGE(STATUS "LMDB lib: " ${LMDB_LIBRARIES} ) -MESSAGE(STATUS "LMDB include: " ${LMDB_INCLUDE} ) - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(LMDB DEFAULT_MSG LMDB_INCLUDE_DIR LMDB_LIBRARIES) - -mark_as_advanced(LMDB_INCLUDE_DIR LMDB_LIBRARIES) diff --git a/CMakeScripts/FindLevelDB.cmake b/CMakeScripts/FindLevelDB.cmake deleted file mode 100644 index f3386f26dbf..00000000000 --- a/CMakeScripts/FindLevelDB.cmake +++ /dev/null @@ -1,37 +0,0 @@ -# - Find LevelDB -# -# LEVELDB_INCLUDE - Where to find leveldb/db.h -# LEVELDB_LIBS - List of libraries when using LevelDB. -# LEVELDB_FOUND - True if LevelDB found. - -get_filename_component(module_file_path ${CMAKE_CURRENT_LIST_FILE} PATH) - -# Look for the header file. -find_path(LEVELDB_INCLUDE NAMES leveldb/db.h PATHS $ENV{LEVELDB_ROOT}/include /opt/local/include /usr/local/include /usr/include DOC "Path in which the file leveldb/db.h is located." ) -mark_as_advanced(LEVELDB_INCLUDE) - -# Look for the library. -# Does this work on UNIX systems? (LINUX) -find_library(LEVELDB_LIBS NAMES leveldb PATHS /usr/lib $ENV{LEVELDB_ROOT}/lib DOC "Path to leveldb library." ) -mark_as_advanced(LEVELDB_LIBS) - -# Copy the results to the output variables. -if (LEVELDB_INCLUDE AND LEVELDB_LIBS) - message(STATUS "Found leveldb in ${LEVELDB_INCLUDE} ${LEVELDB_LIBS}") - set(LEVELDB_FOUND 1) - include(CheckCXXSourceCompiles) - set(CMAKE_REQUIRED_LIBRARY ${LEVELDB_LIBS} pthread) - set(CMAKE_REQUIRED_INCLUDES ${LEVELDB_INCLUDE}) - else () - set(LEVELDB_FOUND 0) - endif () - - # Report the results. - if (NOT LEVELDB_FOUND) - set(LEVELDB_DIR_MESSAGE "LEVELDB was not found. Make sure LEVELDB_LIBS and LEVELDB_INCLUDE are set.") - if (LEVELDB_FIND_REQUIRED) - message(FATAL_ERROR "${LEVELDB_DIR_MESSAGE}") - elseif (NOT LEVELDB_FIND_QUIETLY) - message(STATUS "${LEVELDB_DIR_MESSAGE}") - endif () - endif () \ No newline at end of file diff --git a/CMakeScripts/FindNumPy.cmake b/CMakeScripts/FindNumPy.cmake deleted file mode 100644 index baf21541e63..00000000000 --- a/CMakeScripts/FindNumPy.cmake +++ /dev/null @@ -1,103 +0,0 @@ -# - Find the NumPy libraries -# This module finds if NumPy is installed, and sets the following variables -# indicating where it is. -# -# TODO: Update to provide the libraries and paths for linking npymath lib. -# -# NUMPY_FOUND - was NumPy found -# NUMPY_VERSION - the version of NumPy found as a string -# NUMPY_VERSION_MAJOR - the major version number of NumPy -# NUMPY_VERSION_MINOR - the minor version number of NumPy -# NUMPY_VERSION_PATCH - the patch version number of NumPy -# NUMPY_VERSION_DECIMAL - e.g. version 1.6.1 is 10601 -# NUMPY_INCLUDE_DIRS - path to the NumPy include files - -#============================================================================ -# Copyright 2012 Continuum Analytics, Inc. -# -# MIT License -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files -# (the "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to permit -# persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR -# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -# OTHER DEALINGS IN THE SOFTWARE. -# -#============================================================================ - -# Finding NumPy involves calling the Python interpreter -if(NumPy_FIND_REQUIRED) - find_package(PythonInterp REQUIRED) -else() - find_package(PythonInterp) -endif() - -if(NOT PYTHONINTERP_FOUND) - set(NUMPY_FOUND FALSE) - return() -endif() - -execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" - "import numpy as n; print(n.__version__); print(n.get_include());" - RESULT_VARIABLE _NUMPY_SEARCH_SUCCESS - OUTPUT_VARIABLE _NUMPY_VALUES_OUTPUT - ERROR_VARIABLE _NUMPY_ERROR_VALUE - OUTPUT_STRIP_TRAILING_WHITESPACE) - -if(NOT _NUMPY_SEARCH_SUCCESS MATCHES 0) - if(NumPy_FIND_REQUIRED) - message(FATAL_ERROR - "NumPy import failure:\n${_NUMPY_ERROR_VALUE}") - endif() - set(NUMPY_FOUND FALSE) - return() -endif() - -# Convert the process output into a list -string(REGEX REPLACE ";" "\\\\;" _NUMPY_VALUES ${_NUMPY_VALUES_OUTPUT}) -string(REGEX REPLACE "\n" ";" _NUMPY_VALUES ${_NUMPY_VALUES}) -# Just in case there is unexpected output from the Python command. -list(GET _NUMPY_VALUES -2 NUMPY_VERSION) -list(GET _NUMPY_VALUES -1 NUMPY_INCLUDE_DIRS) - -string(REGEX MATCH "^[0-9]+\\.[0-9]+\\.[0-9]+" _VER_CHECK "${NUMPY_VERSION}") -if("${_VER_CHECK}" STREQUAL "") - # The output from Python was unexpected. Raise an error always - # here, because we found NumPy, but it appears to be corrupted somehow. - message(FATAL_ERROR - "Requested version and include path from NumPy, got instead:\n${_NUMPY_VALUES_OUTPUT}\n") - return() -endif() - -# Make sure all directory separators are '/' -string(REGEX REPLACE "\\\\" "/" NUMPY_INCLUDE_DIRS ${NUMPY_INCLUDE_DIRS}) - -# Get the major and minor version numbers -string(REGEX REPLACE "\\." ";" _NUMPY_VERSION_LIST ${NUMPY_VERSION}) -list(GET _NUMPY_VERSION_LIST 0 NUMPY_VERSION_MAJOR) -list(GET _NUMPY_VERSION_LIST 1 NUMPY_VERSION_MINOR) -list(GET _NUMPY_VERSION_LIST 2 NUMPY_VERSION_PATCH) -string(REGEX MATCH "[0-9]*" NUMPY_VERSION_PATCH ${NUMPY_VERSION_PATCH}) -math(EXPR NUMPY_VERSION_DECIMAL - "(${NUMPY_VERSION_MAJOR} * 10000) + (${NUMPY_VERSION_MINOR} * 100) + ${NUMPY_VERSION_PATCH}") - -find_package_message(NUMPY - "Found NumPy: version \"${NUMPY_VERSION}\" ${NUMPY_INCLUDE_DIRS}" - "${NUMPY_INCLUDE_DIRS}${NUMPY_VERSION}") - -set(NUMPY_FOUND TRUE) - - diff --git a/CMakeScripts/FindProtobuf.cmake b/CMakeScripts/FindProtobuf.cmake deleted file mode 100644 index 0f94f498197..00000000000 --- a/CMakeScripts/FindProtobuf.cmake +++ /dev/null @@ -1,152 +0,0 @@ -# Locate and configure the Google Protocol Buffers library. -# Defines the following variables: -# -# PROTOBUF_FOUND - Found the Google Protocol Buffers library -# PROTOBUF_INCLUDE_DIRS - Include directories for Google Protocol Buffers -# PROTOBUF_LIBRARIES - The protobuf library -# -# The following cache variables are also defined: -# PROTOBUF_LIBRARY - The protobuf library -# PROTOBUF_PROTOC_LIBRARY - The protoc library -# PROTOBUF_INCLUDE_DIR - The include directory for protocol buffers -# PROTOBUF_PROTOC_EXECUTABLE - The protoc compiler -# -# ==================================================================== -# Example: -# -# find_package(Protobuf REQUIRED) -# include_directories(${PROTOBUF_INCLUDE_DIRS}) -# -# include_directories(${CMAKE_CURRENT_BINARY_DIR}) -# PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS foo.proto) -# add_executable(bar bar.cc ${PROTO_SRCS} ${PROTO_HDRS}) -# target_link_libraries(bar ${PROTOBUF_LIBRARY}) -# -# NOTE: You may need to link against pthreads, depending -# on the platform. -# ==================================================================== -# -# PROTOBUF_GENERATE_CPP (public function) -# SRCS = Variable to define with autogenerated -# source files -# HDRS = Variable to define with autogenerated -# header files -# ARGN = proto files -# -# ==================================================================== - - -#============================================================================= -# Copyright 2009 Kitware, Inc. -# Copyright 2009 Philip Lowman -# Copyright 2008 Esben Mose Hansen, Ange Optimization ApS -# -# 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 distributed this file outside of CMake, substitute the full -# License text for the above reference.) - -function(PROTOBUF_GENERATE_PYTHON SRCS) - if(NOT ARGN) - message(SEND_ERROR "Error: PROTOBUF_GENERATE_PYTHON() called without any proto files") - return() - endif(NOT ARGN) - - set(${SRCS}) - foreach(FIL ${ARGN}) - get_filename_component(ABS_FIL ${FIL} ABSOLUTE) - get_filename_component(FIL_WE ${FIL} NAME_WE) - - - list(APPEND ${SRCS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}_pb2.py") - - add_custom_command( - OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}_pb2.py" - COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} - ARGS --python_out ${CMAKE_CURRENT_BINARY_DIR} --proto_path ${CMAKE_CURRENT_SOURCE_DIR} -${ABS_FIL} - DEPENDS ${ABS_FIL} - COMMENT "Running Python protocol buffer compiler on ${FIL}" - VERBATIM ) - endforeach() - - - set_source_files_properties(${${SRCS}} PROPERTIES GENERATED TRUE) - set(${SRCS} ${${SRCS}} PARENT_SCOPE) -endfunction() - - -function(PROTOBUF_GENERATE_CPP SRCS HDRS) - if(NOT ARGN) - message(SEND_ERROR "Error: PROTOBUF_GENERATE_CPP() called without any proto files") - return() - endif(NOT ARGN) - - set(${SRCS}) - set(${HDRS}) - foreach(FIL ${ARGN}) - get_filename_component(ABS_FIL ${FIL} ABSOLUTE) - get_filename_component(FIL_WE ${FIL} NAME_WE) - - list(APPEND ${SRCS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc") - list(APPEND ${HDRS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h") - - add_custom_command( - OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc" - "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h" - COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} - ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR} --proto_path ${CMAKE_CURRENT_SOURCE_DIR} -${ABS_FIL} - DEPENDS ${ABS_FIL} - COMMENT "Running C++ protocol buffer compiler on ${FIL}" - VERBATIM ) - endforeach() - - set_source_files_properties(${${SRCS}} ${${HDRS}} PROPERTIES GENERATED TRUE) - set(${SRCS} ${${SRCS}} PARENT_SCOPE) - set(${HDRS} ${${HDRS}} PARENT_SCOPE) -endfunction() - - -find_path(PROTOBUF_INCLUDE_DIR google/protobuf/service.h) - -# Google's provided vcproj files generate libraries with a "lib" -# prefix on Windows -if(WIN32) - set(PROTOBUF_ORIG_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}") - set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "") -endif() - -find_library(PROTOBUF_LIBRARY NAMES protobuf - DOC "The Google Protocol Buffers Library" -) -find_library(PROTOBUF_PROTOC_LIBRARY NAMES protoc - DOC "The Google Protocol Buffers Compiler Library" -) -find_program(PROTOBUF_PROTOC_EXECUTABLE NAMES protoc - DOC "The Google Protocol Buffers Compiler" -) - -mark_as_advanced(PROTOBUF_INCLUDE_DIR - PROTOBUF_LIBRARY - PROTOBUF_PROTOC_LIBRARY - PROTOBUF_PROTOC_EXECUTABLE) - -# Restore original find library prefixes -if(WIN32) - set(CMAKE_FIND_LIBRARY_PREFIXES "${PROTOBUF_ORIG_FIND_LIBRARY_PREFIXES}") -endif() - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(PROTOBUF DEFAULT_MSG - PROTOBUF_LIBRARY PROTOBUF_INCLUDE_DIR) - -if(PROTOBUF_FOUND) - set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIR}) - set(PROTOBUF_LIBRARIES ${PROTOBUF_LIBRARY}) -endif() diff --git a/CMakeScripts/FindSnappy.cmake b/CMakeScripts/FindSnappy.cmake deleted file mode 100644 index d769b442812..00000000000 --- a/CMakeScripts/FindSnappy.cmake +++ /dev/null @@ -1,33 +0,0 @@ -# Find the Snappy libraries -# -# The following variables are optionally searched for defaults -# Snappy_ROOT_DIR: Base directory where all Snappy components are found -# -# The following are set after configuration is done: -# Snappy_FOUND -# Snappy_INCLUDE_DIRS -# Snappy_LIBS - -find_path(SNAPPY_INCLUDE_DIR - NAMES snappy.h - HINTS ${SNAPPY_ROOT_DIR} - ${SNAPPY_ROOT_DIR}/include -) - -find_library(SNAPPY_LIBS - NAMES snappy - HINTS ${SNAPPY_ROOT_DIR} - ${SNAPPY_ROOT_DIR}/lib -) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Snappy - DEFAULT_MSG - SNAPPY_LIBS - SNAPPY_INCLUDE_DIR -) - -mark_as_advanced( - SNAPPY_LIBS - SNAPPY_INCLUDE_DIR -) diff --git a/cmake/ConfigGen.cmake b/cmake/ConfigGen.cmake new file mode 100644 index 00000000000..24f23e9c494 --- /dev/null +++ b/cmake/ConfigGen.cmake @@ -0,0 +1,86 @@ + +################################################################################################ +# Helper function to fetch caffe includes which will be passed to dependent projects +# Usage: +# caffe_get_current_includes() +function(caffe_get_current_includes includes_variable) + get_property(current_includes DIRECTORY PROPERTY INCLUDE_DIRECTORIES) + caffe_convert_absolute_paths(current_includes) + + # remove at most one ${CMAKE_BINARY_DIR} include added for caffe_config.h + list(FIND current_includes ${CMAKE_BINARY_DIR} __index) + list(REMOVE_AT current_includes ${__index}) + + caffe_list_unique(current_includes) + set(${includes_variable} ${current_includes} PARENT_SCOPE) +endfunction() + +################################################################################################ +# Helper function to get all list items that begin with given prefix +# Usage: +# caffe_get_items_with_prefix( ) +function(caffe_get_items_with_prefix prefix list_variable output_variable) + set(__result "") + foreach(__e ${${list_variable}}) + if(__e MATCHES "^${prefix}.*") + list(APPEND __result ${__e}) + endif() + endforeach() + set(${output_variable} ${__result} PARENT_SCOPE) +endfunction() + +################################################################################################ +# Function for generation Caffe build- and install- tree export config files +# Usage: +# caffe_generate_export_configs() +function(caffe_generate_export_configs) + set(install_cmake_suffix "share/Caffe") + + # ---[ Configure build-tree CaffeConfig.cmake file ]--- + caffe_get_current_includes(Caffe_INCLUDE_DIRS) + if(NOT HAVE_CUDA) + set(HAVE_CUDA FALSE) + set(Caffe_DEFINITIONS -DCPU_ONLY) + endif() + if(NOT HAVE_CUDNN) + set(HAVE_CUDNN FALSE) + else() + set(Caffe_DEFINITIONS -DUSE_CUDNN) + endif() + + configure_file("cmake/Templates/CaffeConfig.cmake.in" "${CMAKE_BINARY_DIR}/CaffeConfig.cmake" @ONLY) + + # Add targets to the build-tree export set + export(TARGETS caffe proto FILE "${CMAKE_BINARY_DIR}/CaffeTargets.cmake") + export(PACKAGE Caffe) + + # ---[ Configure install-tree CaffeConfig.cmake file ]--- + + # remove source and build dir includes + caffe_get_items_with_prefix(${CMAKE_SOURCE_DIR} Caffe_INCLUDE_DIRS __insource) + caffe_get_items_with_prefix(${CMAKE_BINARY_DIR} Caffe_INCLUDE_DIRS __inbinary) + list(REMOVE_ITEM Caffe_INCLUDE_DIRS ${__insource} ${__inbinary}) + + # add `install` include folder + set(lines + "get_filename_component(__caffe_include \"\${Caffe_CMAKE_DIR}/../../include\" ABSOLUTE)\n" + "list(APPEND Caffe_INCLUDE_DIRS \${__caffe_include})\n" + "unset(__caffe_include)\n") + string(REPLACE ";" "" Caffe_INSTALL_INCLUDE_DIR_APPEND_COMMAND ${lines}) + + configure_file("cmake/Templates/CaffeConfig.cmake.in" "${CMAKE_BINARY_DIR}/cmake/CaffeConfig.cmake" @ONLY) + + # Install the CaffeConfig.cmake and export set to use wuth install-tree + install(FILES "${CMAKE_BINARY_DIR}/cmake/CaffeConfig.cmake" DESTINATION ${install_cmake_suffix}) + install(EXPORT CaffeTargets DESTINATION ${install_cmake_suffix}) + + # ---[ Configure and install version file ]--- + + # TODO: Lines below are commented because Caffe does't declare its version in headers. + # When the declarations are added, modify `caffe_extract_caffe_version()` macro and uncomment + + # configure_file(cmake/Templates/CaffeConfigVersion.cmake.in "${CMAKE_BINARY_DIR}/CaffeConfigVersion.cmake" @ONLY) + # install(FILES "${CMAKE_BINARY_DIR}/CaffeConfigVersion.cmake" DESTINATION ${install_cmake_suffix}) +endfunction() + + diff --git a/cmake/Cuda.cmake b/cmake/Cuda.cmake new file mode 100644 index 00000000000..42a94e5a295 --- /dev/null +++ b/cmake/Cuda.cmake @@ -0,0 +1,243 @@ +if(CPU_ONLY) + return() +endif() + +# Known NVIDIA GPU achitectures Caffe can be compiled for. +# This list will be used for CUDA_ARCH_NAME = All option +set(Caffe_known_gpu_archs "20 21(20) 30 35 50") + +################################################################################################ +# A function for automatic detection of GPUs installed (if autodetection is enabled) +# Usage: +# caffe_detect_installed_gpus(out_variable) +function(caffe_detect_installed_gpus out_variable) + if(NOT CUDA_gpu_detect_output) + set(__cufile ${CMAKE_BINARY_DIR}/detect_cuda_archs.cu) + + file(WRITE ${__cufile} "" + "#include \n" + "int main()\n" + "{\n" + " int count = 0;\n" + " if (cudaSuccess != cudaGetDeviceCount(&count)) return -1;\n" + " if (count == 0) return -1;\n" + " for (int device = 0; device < count; ++device)\n" + " {\n" + " cudaDeviceProp prop;\n" + " if (cudaSuccess == cudaGetDeviceProperties(&prop, device))\n" + " std::printf(\"%d.%d \", prop.major, prop.minor);\n" + " }\n" + " return 0;\n" + "}\n") + + execute_process(COMMAND "${CUDA_NVCC_EXECUTABLE}" "--run" "${__cufile}" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/CMakeFiles/" + RESULT_VARIABLE __nvcc_res OUTPUT_VARIABLE __nvcc_out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(__nvcc_res EQUAL 0) + string(REPLACE "2.1" "2.1(2.0)" __nvcc_out "${__nvcc_out}") + set(CUDA_gpu_detect_output ${__nvcc_out} CACHE INTERNAL "Returned GPU architetures from caffe_detect_gpus tool" FORCE) + endif() + endif() + + if(NOT CUDA_gpu_detect_output) + message(STATUS "Automatic GPU detection failed. Building for all known architectures.") + set(${out_variable} ${Caffe_known_gpu_archs} PARENT_SCOPE) + else() + set(${out_variable} ${CUDA_gpu_detect_output} PARENT_SCOPE) + endif() +endfunction() + + +################################################################################################ +# Function for selecting GPU arch flags for nvcc based on CUDA_ARCH_NAME +# Usage: +# caffe_select_nvcc_arch_flags(out_variable) +function(caffe_select_nvcc_arch_flags out_variable) + # List of arch names + set(__archs_names "Fermi" "Kepler" "Maxwell" "All" "Manual") + set(__archs_name_default "All") + if(NOT CMAKE_CROSSCOMPILING) + list(APPEND __archs_names "Auto") + set(__archs_name_default "Auto") + endif() + + # set CUDA_ARCH_NAME strings (so it will be seen as dropbox in CMake-Gui) + set(CUDA_ARCH_NAME ${__archs_name_default} CACHE STRING "Select target NVIDIA GPU achitecture.") + set_property( CACHE CUDA_ARCH_NAME PROPERTY STRINGS "" ${__archs_names} ) + mark_as_advanced(CUDA_ARCH_NAME) + + # verify CUDA_ARCH_NAME value + if(NOT ";${__archs_names};" MATCHES ";${CUDA_ARCH_NAME};") + string(REPLACE ";" ", " __archs_names "${__archs_names}") + message(FATAL_ERROR "Only ${__archs_names} architeture names are supported.") + endif() + + if(${CUDA_ARCH_NAME} STREQUAL "Manual") + set(CUDA_ARCH_BIN ${Caffe_known_gpu_archs} CACHE STRING "Specify 'real' GPU architectures to build binaries for, BIN(PTX) format is supported") + set(CUDA_ARCH_PTX "50" CACHE STRING "Specify 'virtual' PTX architectures to build PTX intermediate code for") + mark_as_advanced(CUDA_ARCH_BIN CUDA_ARCH_PTX) + else() + unset(CUDA_ARCH_BIN CACHE) + unset(CUDA_ARCH_PTX CACHE) + endif() + + if(${CUDA_ARCH_NAME} STREQUAL "Fermi") + set(__cuda_arch_bin "20 21(20)") + elseif(${CUDA_ARCH_NAME} STREQUAL "Kepler") + set(__cuda_arch_bin "30 35") + elseif(${CUDA_ARCH_NAME} STREQUAL "Maxwell") + set(__cuda_arch_bin "50") + elseif(${CUDA_ARCH_NAME} STREQUAL "All") + set(__cuda_arch_bin ${Caffe_known_gpu_archs}) + elseif(${CUDA_ARCH_NAME} STREQUAL "Auto") + caffe_detect_installed_gpus(__cuda_arch_bin) + else() # (${CUDA_ARCH_NAME} STREQUAL "Manual") + set(__cuda_arch_bin ${CUDA_ARCH_BIN}) + endif() + + # remove dots and convert to lists + string(REGEX REPLACE "\\." "" __cuda_arch_bin "${__cuda_arch_bin}") + string(REGEX REPLACE "\\." "" __cuda_arch_ptx "${CUDA_ARCH_PTX}") + string(REGEX MATCHALL "[0-9()]+" __cuda_arch_bin "${__cuda_arch_bin}") + string(REGEX MATCHALL "[0-9]+" __cuda_arch_ptx "${__cuda_arch_ptx}") + caffe_list_unique(__cuda_arch_bin __cuda_arch_ptx) + + set(__nvcc_flags "") + set(__nvcc_archs_readable "") + + # Tell NVCC to add binaries for the specified GPUs + foreach(__arch ${__cuda_arch_bin}) + if(__arch MATCHES "([0-9]+)\\(([0-9]+)\\)") + # User explicitly specified PTX for the concrete BIN + list(APPEND __nvcc_flags -gencode arch=compute_${CMAKE_MATCH_2},code=sm_${CMAKE_MATCH_1}) + list(APPEND __nvcc_archs_readable sm_${CMAKE_MATCH_1}) + else() + # User didn't explicitly specify PTX for the concrete BIN, we assume PTX=BIN + list(APPEND __nvcc_flags -gencode arch=compute_${__arch},code=sm_${__arch}) + list(APPEND __nvcc_archs_readable sm_${__arch}) + endif() + endforeach() + + # Tell NVCC to add PTX intermediate code for the specified architectures + foreach(__arch ${__cuda_arch_ptx}) + list(APPEND __nvcc_flags -gencode arch=compute_${__arch},code=compute_${__arch}) + list(APPEND __nvcc_archs_readable compute_${__arch}) + endforeach() + + string(REPLACE ";" " " __nvcc_archs_readable "${__nvcc_archs_readable}") + set(${out_variable} ${__nvcc_flags} PARENT_SCOPE) + set(${out_variable}_readable ${__nvcc_archs_readable} PARENT_SCOPE) +endfunction() + +################################################################################################ +# Short command for cuda comnpilation +# Usage: +# caffe_cuda_compile( ) +macro(caffe_cuda_compile objlist_variable) + foreach(var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG) + set(${var}_backup_in_cuda_compile_ "${${var}}") + + # we remove /EHa as it generates warnings under windows + string(REPLACE "/EHa" "" ${var} "${${var}}") + + endforeach() + + if(UNIX OR APPLE) + list(APPEND CUDA_NVCC_FLAGS -Xcompiler -fPIC) + endif() + + if(APPLE) + list(APPEND CUDA_NVCC_FLAGS -Xcompiler -Wno-unused-function) + endif() + + cuda_compile(cuda_objcs ${ARGN}) + + foreach(var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG) + set(${var} "${${var}_backup_in_cuda_compile_}") + unset(${var}_backup_in_cuda_compile_) + endforeach() + + set(${objlist_variable} ${cuda_objcs}) +endmacro() + +################################################################################################ +# Short command for cuDNN detection. Believe it soon will be a part of CUDA toolkit distribution. +# That's why not FindcuDNN.cmake file, but just the macro +# Usage: +# detect_cuDNN() +function(detect_cuDNN) + set(CUDNN_ROOT "" CACHE PATH "CUDNN root folder") + + find_path(CUDNN_INCLUDE cudnn.h + PATHS ${CUDNN_ROOT} $ENV{CUDNN_ROOT} ${CUDA_TOOLKIT_INCLUDE} + DOC "Path to cuDNN include directory." ) + + get_filename_component(__libpath_hist ${CUDA_CUDART_LIBRARY} PATH) + find_library(CUDNN_LIBRARY NAMES libcudnn.so # libcudnn_static.a + PATHS ${CUDNN_ROOT} $ENV{CUDNN_ROOT} ${CUDNN_INCLUDE} ${__libpath_hist} + DOC "Path to cuDNN library.") + + if(CUDNN_INCLUDE AND CUDNN_LIBRARY) + set(HAVE_CUDNN TRUE PARENT_SCOPE) + set(CUDNN_FOUND TRUE PARENT_SCOPE) + + mark_as_advanced(CUDNN_INCLUDE CUDNN_LIBRARY CUDNN_ROOT) + message(STATUS "Found cuDNN (include: ${CUDNN_INCLUDE}, library: ${CUDNN_LIBRARY})") + endif() +endfunction() + + +################################################################################################ +### Non macro section +################################################################################################ + +find_package(CUDA 5.5 QUIET) + +if(NOT CUDA_FOUND) + return() +endif() + +set(HAVE_CUDA TRUE) +message(STATUS "CUDA detected: " ${CUDA_VERSION}) +include_directories(SYSTEM ${CUDA_INCLUDE_DIRS}) +list(APPEND Caffe_LINKER_LIBS ${CUDA_CUDART_LIBRARY} + ${CUDA_curand_LIBRARY} ${CUDA_CUBLAS_LIBRARIES}) + +# cudnn detection +if(USE_CUDNN) + detect_cuDNN() + if(HAVE_CUDNN) + add_definitions(-DUSE_CUDNN) + include_directories(SYSTEM ${CUDNN_INCLUDE}) + list(APPEND Caffe_LINKER_LIBS ${CUDNN_LIBRARY}) + endif() +endif() + +# setting nvcc arch flags +caffe_select_nvcc_arch_flags(NVCC_FLAGS_EXTRA) +list(APPEND CUDA_NVCC_FLAGS ${NVCC_FLAGS_EXTRA}) +message(STATUS "Added CUDA NVCC flags for: ${NVCC_FLAGS_EXTRA_readable}") + +# Boost 1.55 workaround, see https://svn.boost.org/trac/boost/ticket/9392 or +# https://github.com/ComputationalRadiationPhysics/picongpu/blob/master/src/picongpu/CMakeLists.txt +if(Boost_VERSION EQUAL 105500) + message(STATUS "Cuda + Boost 1.55: Applying noinline work around") + # avoid warning for CMake >= 2.8.12 + set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} \"-DBOOST_NOINLINE=__attribute__((noinline))\" ") +endif() + +# disable some nvcc diagnostic that apears in boost, glog, glags, opencv, etc. +foreach(diag cc_clobber_ignored integer_sign_change useless_using_declaration set_but_not_used) + list(APPEND CUDA_NVCC_FLAGS -Xcudafe --diag_suppress=${diag}) +endforeach() + +# setting default testing device +if(NOT CUDA_TEST_DEVICE) + set(CUDA_TEST_DEVICE -1) +endif() + +mark_as_advanced(CUDA_BUILD_CUBIN CUDA_BUILD_EMULATION CUDA_VERBOSE_BUILD) +mark_as_advanced(CUDA_SDK_ROOT_DIR CUDA_SEPARABLE_COMPILATION) + diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake new file mode 100644 index 00000000000..5de435c350d --- /dev/null +++ b/cmake/Dependencies.cmake @@ -0,0 +1,124 @@ +# This list is required for static linking and exported to CaffeConfig.cmake +set(Caffe_LINKER_LIBS "") + +# ---[ Boost +find_package(Boost 1.46 REQUIRED COMPONENTS system thread) +include_directories(SYSTEM ${Boost_INCLUDE_DIR}) +list(APPEND Caffe_LINKER_LIBS ${Boost_LIBRARIES}) + +# ---[ Threads +find_package(Threads REQUIRED) +list(APPEND Caffe_LINKER_LIBS ${CMAKE_THREAD_LIBS_INIT}) + +# ---[ Google-glog +find_package(Glog REQUIRED) +include_directories(SYSTEM ${GLOG_INCLUDE_DIRS}) +list(APPEND Caffe_LINKER_LIBS ${GLOG_LIBRARIES}) + +# ---[ Google-gflags +find_package(GFlags REQUIRED) +include_directories(SYSTEM ${GFLAGS_INCLUDE_DIRS}) +list(APPEND Caffe_LINKER_LIBS ${GFLAGS_LIBRARIES}) + +# ---[ Google-protobuf +include(cmake/ProtoBuf.cmake) + +# ---[ HDF5 +find_package(HDF5 COMPONENTS HL REQUIRED) +include_directories(SYSTEM ${HDF5_INCLUDE_DIRS}) +list(APPEND Caffe_LINKER_LIBS ${HDF5_LIBRARIES}) + +# ---[ LMDB +find_package(LMDB REQUIRED) +include_directories(SYSTEM ${LMDB_INCLUDE_DIR}) +list(APPEND Caffe_LINKER_LIBS ${LMDB_LIBRARIES}) + +# ---[ LevelDB +find_package(LevelDB REQUIRED) +include_directories(SYSTEM ${LEVELDB_INCLUDE}) +list(APPEND Caffe_LINKER_LIBS ${LevelDB_LIBRARIES}) + +# ---[ Snappy +find_package(Snappy REQUIRED) +include_directories(SYSTEM ${Snappy_INCLUDE_DIR}) +list(APPEND Caffe_LINKER_LIBS ${Snappy_LIBRARIES}) + +# ---[ CUDA +include(cmake/Cuda.cmake) +if(NOT HAVE_CUDA) + if(CPU_ONLY) + message("-- CUDA is disabled. Building without it...") + else() + message("-- CUDA is not detected by cmake. Building without it...") + endif() + + # TODO: remove this not cross platform define in future. Use caffe_config.h instead. + add_definitions(-DCPU_ONLY) +endif() + +# ---[ OpenCV +find_package(OpenCV QUIET COMPONENTS core highgui imgproc imgcodecs) +if(NOT OpenCV_FOUND) # if not OpenCV 3.x, then imgcodecs are not found + find_package(OpenCV REQUIRED COMPONENTS core highgui imgproc) +endif() +include_directories(SYSTEM ${OpenCV_INCLUDE_DIRS}) +list(APPEND Caffe_LINKER_LIBS ${OpenCV_LIBS}) +message(STATUS "OpenCV found (${OpenCV_CONFIG_PATH})") + +# ---[ BLAS +if(NOT APPLE) + set(BLAS "Atlas" CACHE STRING "Selected BLAS library") + set_property(CACHE BLAS PROPERTY STRINGS "Atlas;Open;MLK") + + if(BLAS STREQUAL "Atlas" OR BLAS STREQUAL "atlas") + find_package(Atlas REQUIRED) + include_directories(SYSTEM ${Atlas_INCLUDE_DIR}) + list(APPEND Caffe_LINKER_LIBS ${Atlas_LIBRARIES}) + elseif(BLAS STREQUAL "Open" OR BLAS STREQUAL "open") + find_package(OpenBLAS REQUIRED) + include_directories(SYSTEM ${OpenBLAS_INCLUDE_DIR}) + list(APPEND Caffe_LINKER_LIBS ${OpenBLAS_LIB}) + elseif(BLAS STREQUAL "MLK" OR BLAS STREQUAL "mkl") + find_package(MKL REQUIRED) + include_directories(SYSTEM ${MKL_INCLUDE_DIR}) + list(APPEND Caffe_LINKER_LIBS ${MKL_LIBRARIES}) + endif() +elseif(APPLE) + find_package(vecLib REQUIRED) + include_directories(SYSTEM ${vecLib_INCLUDE_DIR}) + list(APPEND Caffe_LINKER_LIBS ${vecLib_LINKER_LIBS}) +endif() + +# ---[ Python +if(BUILD_python) + # disable Python 3 search + find_package(PythonInterp 2.7) + find_package(PythonLibs 2.7) + find_package(NumPy 1.7.1) + find_package(Boost 1.46 COMPONENTS python) + + if(PYTHONLIBS_FOUND AND NUMPY_FOUND AND Boost_PYTHON_FOUND) + set(HAVE_PYTHON TRUE) + endif() +endif() + +# ---[ Matlab +if(BUILD_matlab) + find_package(MatlabMex) + if(MATLABMEX_FOUND) + set(HAVE_MATLAB TRUE) + endif() + + # sudo apt-get install liboctave-dev + find_program(Octave_compiler NAMES mkoctfile DOC "Octave C++ compiler") + + if(HAVE_MATLAB AND Octave_compiler) + set(Matlab_build_mex_using "Matlab" CACHE STRING "Select Matlab or Octave if both detected") + set_property(CACHE Matlab_build_mex_using PROPERTY STRINGS "Matlab;Octave") + endif() +endif() + +# ---[ Doxygen +if(BUILD_docs) + find_package(Doxygen) +endif() diff --git a/cmake/Misc.cmake b/cmake/Misc.cmake new file mode 100644 index 00000000000..68e8a662126 --- /dev/null +++ b/cmake/Misc.cmake @@ -0,0 +1,47 @@ +# ---[ Configurations types +set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Possible configurations" FORCE) +mark_as_advanced(CMAKE_CONFIGURATION_TYPES) + +if(DEFINED CMAKE_BUILD_TYPE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${CMAKE_CONFIGURATION_TYPES}) +endif() + +# --[ If user doesn't specify build type then assume release +if("${CMAKE_BUILD_TYPE}" STREQUAL "") + set(CMAKE_BUILD_TYPE Release) +endif() + +if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set(CMAKE_COMPILER_IS_CLANGXX TRUE) +endif() + +# ---[ Solution folders +caffe_option(USE_PROJECT_FOLDERS "IDE Solution folders" (MSVC_IDE OR CMAKE_GENERATOR MATCHES Xcode) ) + +if(USE_PROJECT_FOLDERS) + set_property(GLOBAL PROPERTY USE_FOLDERS ON) + set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "CMakeTargets") +endif() + +# ---[ Install options +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE PATH "Default install path" FORCE) +endif() + +# ---[ RPATH settings +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE CACHE BOOLEAN "Use link paths for shared library rpath") +set(CMAKE_MACOSX_RPATH TRUE) + +# ---[ Funny target +if(UNIX OR APPLE) + add_custom_target(simlink_to_build COMMAND "ln" "-sf" "${CMAKE_BINARY_DIR}" "${CMAKE_SOURCE_DIR}/build" + COMMENT "Adding simlink: /build -> ${CMAKE_BINARY_DIR}" ) +endif() + +# ---[ Set debug postfix +set(Caffe_DEBUG_POSTFIX "-d") + +set(CAffe_POSTFIX "") +if(CMAKE_BUILD_TYPE MATCHES "Debug") + set(CAffe_POSTFIX ${Caffe_DEBUG_POSTFIX}) +endif() diff --git a/CMakeScripts/FindAtlas.cmake b/cmake/Modules/FindAtlas.cmake similarity index 63% rename from CMakeScripts/FindAtlas.cmake rename to cmake/Modules/FindAtlas.cmake index 27657a6c7d7..6e1564351c7 100644 --- a/CMakeScripts/FindAtlas.cmake +++ b/cmake/Modules/FindAtlas.cmake @@ -23,14 +23,14 @@ set(Atlas_LIB_SEARCH_PATHS $ENV{Atlas_ROOT_DIR}/lib ) -find_path(Atlas_CBLAS_INCLUDE_DIR NAMES cblas.h PATHS ${Atlas_INCLUDE_SEARCH_PATHS}) +find_path(Atlas_CBLAS_INCLUDE_DIR NAMES cblas.h PATHS ${Atlas_INCLUDE_SEARCH_PATHS}) find_path(Atlas_CLAPACK_INCLUDE_DIR NAMES clapack.h PATHS ${Atlas_INCLUDE_SEARCH_PATHS}) -find_library(Atlas_CBLAS_LIBRARY NAMES ptcblas_r ptcblas cblas_r cblas PATHS ${Atlas_LIB_SEARCH_PATHS}) -find_library(Atlas_BLAS_LIBRARY NAMES atlas_r atlas PATHS ${Atlas_LIB_SEARCH_PATHS}) -find_library(Atlas_LAPACK_LIBRARY NAMES alapack_r alapack lapack_atlas PATHS ${Atlas_LIB_SEARCH_PATHS}) -set(LOOKED_FOR +find_library(Atlas_CBLAS_LIBRARY NAMES ptcblas_r ptcblas cblas_r cblas PATHS ${Atlas_LIB_SEARCH_PATHS}) +find_library(Atlas_BLAS_LIBRARY NAMES atlas_r atlas PATHS ${Atlas_LIB_SEARCH_PATHS}) +find_library(Atlas_LAPACK_LIBRARY NAMES alapack_r alapack lapack_atlas PATHS ${Atlas_LIB_SEARCH_PATHS}) +set(LOOKED_FOR Atlas_CBLAS_INCLUDE_DIR Atlas_CLAPACK_INCLUDE_DIR @@ -43,19 +43,10 @@ include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Atlas DEFAULT_MSG ${LOOKED_FOR}) if(ATLAS_FOUND) - + set(Atlas_INCLUDE_DIR ${Atlas_CBLAS_INCLUDE_DIR} ${Atlas_CLAPACK_INCLUDE_DIR}) + set(Atlas_LIBRARIES ${Atlas_LAPACK_LIBRARY} ${Atlas_CBLAS_LIBRARY} ${Atlas_BLAS_LIBRARY}) mark_as_advanced(${LOOKED_FOR}) - set(Atlas_INCLUDE_DIR - ${Atlas_CBLAS_INCLUDE_DIR} - ${Atlas_CLAPACK_INCLUDE_DIR} - ) - - set(Atlas_LIBRARIES - ${Atlas_LAPACK_LIBRARY} - ${Atlas_CBLAS_LIBRARY} - ${Atlas_BLAS_LIBRARY} - ) - + message(STATUS "Found Atlas (include: ${Atlas_CBLAS_INCLUDE_DIR}, library: ${Atlas_BLAS_LIBRARY})") endif(ATLAS_FOUND) diff --git a/CMakeScripts/FindGFlags.cmake b/cmake/Modules/FindGFlags.cmake similarity index 79% rename from CMakeScripts/FindGFlags.cmake rename to cmake/Modules/FindGFlags.cmake index f93c57136a1..146e8455a50 100644 --- a/CMakeScripts/FindGFlags.cmake +++ b/cmake/Modules/FindGFlags.cmake @@ -38,11 +38,13 @@ else() find_library(GFLAGS_LIBRARY gflags) endif() -find_package_handle_standard_args(GFLAGS DEFAULT_MSG - GFLAGS_INCLUDE_DIR GFLAGS_LIBRARY) +find_package_handle_standard_args(GFLAGS DEFAULT_MSG GFLAGS_INCLUDE_DIR GFLAGS_LIBRARY) if(GFLAGS_FOUND) set(GFLAGS_INCLUDE_DIRS ${GFLAGS_INCLUDE_DIR}) set(GFLAGS_LIBRARIES ${GFLAGS_LIBRARY}) + message(STATUS "Found gflags (include: ${GFLAGS_INCLUDE_DIR}, library: ${GFLAGS_LIBRARY})") + mark_as_advanced(GFLAGS_LIBRARY_DEBUG GFLAGS_LIBRARY_RELEASE + GFLAGS_LIBRARY GFLAGS_INCLUDE_DIR GFLAGS_ROOT_DIR) endif() diff --git a/CMakeScripts/FindGlog.cmake b/cmake/Modules/FindGlog.cmake similarity index 70% rename from CMakeScripts/FindGlog.cmake rename to cmake/Modules/FindGlog.cmake index 0dc30abdbf5..56c76434897 100644 --- a/CMakeScripts/FindGlog.cmake +++ b/cmake/Modules/FindGlog.cmake @@ -34,15 +34,15 @@ if(MSVC) else() find_library(GLOG_LIBRARY glog PATHS ${GLOG_ROOT_DIR} - PATH_SUFFIXES - lib - lib64) + PATH_SUFFIXES lib lib64) endif() -find_package_handle_standard_args(GLOG DEFAULT_MSG - GLOG_INCLUDE_DIR GLOG_LIBRARY) +find_package_handle_standard_args(GLOG DEFAULT_MSG GLOG_INCLUDE_DIR GLOG_LIBRARY) if(GLOG_FOUND) - set(GLOG_INCLUDE_DIRS ${GLOG_INCLUDE_DIR}) - set(GLOG_LIBRARIES ${GLOG_LIBRARY}) + set(GLOG_INCLUDE_DIRS ${GLOG_INCLUDE_DIR}) + set(GLOG_LIBRARIES ${GLOG_LIBRARY}) + message(STATUS "Found glog (include: ${GLOG_INCLUDE_DIR}, library: ${GLOG_LIBRARY})") + mark_as_advanced(GLOG_ROOT_DIR GLOG_LIBRARY_RELEASE GLOG_LIBRARY_DEBUG + GLOG_LIBRARY GLOG_INCLUDE_DIR) endif() diff --git a/CMakeScripts/FindLAPACK.cmake b/cmake/Modules/FindLAPACK.cmake similarity index 100% rename from CMakeScripts/FindLAPACK.cmake rename to cmake/Modules/FindLAPACK.cmake diff --git a/cmake/Modules/FindLMDB.cmake b/cmake/Modules/FindLMDB.cmake new file mode 100644 index 00000000000..8a817fd6f10 --- /dev/null +++ b/cmake/Modules/FindLMDB.cmake @@ -0,0 +1,28 @@ +# Try to find the LMBD libraries and headers +# LMDB_FOUND - system has LMDB lib +# LMDB_INCLUDE_DIR - the LMDB include directory +# LMDB_LIBRARIES - Libraries needed to use LMDB + +# FindCWD based on FindGMP by: +# Copyright (c) 2006, Laurent Montel, +# +# Redistribution and use is allowed according to the terms of the BSD license. + +# Adapted from FindCWD by: +# Copyright 2013 Conrad Steenberg +# Aug 31, 2013 + +find_path(LMDB_INCLUDE_DIR NAMES lmdb.h PATHS "$ENV{LMDB_DIR}/include") +find_library(LMDB_LIBRARIES NAMES lmdb PATHS "$ENV{LMDB_DIR}/lib" ) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LMDB DEFAULT_MSG LMDB_INCLUDE_DIR LMDB_LIBRARIES) + +if(LMDB_FOUND) + message(STATUS "Found lmdb (include: ${LMDB_INCLUDE_DIR}, library: ${LMDB_LIBRARIES})") + mark_as_advanced(LMDB_INCLUDE_DIR LMDB_LIBRARIES) + + caffe_parse_header(${LMDB_INCLUDE_DIR}/lmdb.h + LMDB_VERSION_LINES MDB_VERSION_MAJOR MDB_VERSION_MINOR MDB_VERSION_PATCH) + set(LMDB_VERSION "${MDB_VERSION_MAJOR}.${MDB_VERSION_MINOR}.${MDB_VERSION_PATCH}") +endif() diff --git a/cmake/Modules/FindLevelDB.cmake b/cmake/Modules/FindLevelDB.cmake new file mode 100644 index 00000000000..97f08ac9349 --- /dev/null +++ b/cmake/Modules/FindLevelDB.cmake @@ -0,0 +1,44 @@ +# - Find LevelDB +# +# LevelDB_INCLUDES - List of LevelDB includes +# LevelDB_LIBRARIES - List of libraries when using LevelDB. +# LevelDB_FOUND - True if LevelDB found. + +# Look for the header file. +find_path(LevelDB_INCLUDE NAMES leveldb/db.h + PATHS $ENV{LEVELDB_ROOT}/include /opt/local/include /usr/local/include /usr/include + DOC "Path in which the file leveldb/db.h is located." ) + +# Look for the library. +find_library(LevelDB_LIBRARY NAMES leveldb + PATHS /usr/lib $ENV{LEVELDB_ROOT}/lib + DOC "Path to leveldb library." ) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LevelDB DEFAULT_MSG LevelDB_INCLUDE LevelDB_LIBRARY) + +if(LEVELDB_FOUND) + message(STATUS "Found LevelDB (include: ${LevelDB_INCLUDE}, library: ${LevelDB_LIBRARY})") + set(LevelDB_INCLUDES ${LevelDB_INCLUDE}) + set(LevelDB_LIBRARIES ${LevelDB_LIBRARY}) + mark_as_advanced(LevelDB_INCLUDE LevelDB_LIBRARY) + + if(EXISTS "${LevelDB_INCLUDE}/leveldb/db.h") + file(STRINGS "${LevelDB_INCLUDE}/leveldb/db.h" __version_lines + REGEX "static const int k[^V]+Version[ \t]+=[ \t]+[0-9]+;") + + foreach(__line ${__version_lines}) + if(__line MATCHES "[^k]+kMajorVersion[ \t]+=[ \t]+([0-9]+);") + set(LEVELDB_VERSION_MAJOR ${CMAKE_MATCH_1}) + elseif(__line MATCHES "[^k]+kMinorVersion[ \t]+=[ \t]+([0-9]+);") + set(LEVELDB_VERSION_MINOR ${CMAKE_MATCH_1}) + endif() + endforeach() + + if(LEVELDB_VERSION_MAJOR AND LEVELDB_VERSION_MINOR) + set(LEVELDB_VERSION "${LEVELDB_VERSION_MAJOR}.${LEVELDB_VERSION_MINOR}") + endif() + + caffe_clear_vars(__line __version_lines) + endif() +endif() diff --git a/CMakeScripts/FindMKL.cmake b/cmake/Modules/FindMKL.cmake similarity index 100% rename from CMakeScripts/FindMKL.cmake rename to cmake/Modules/FindMKL.cmake diff --git a/cmake/Modules/FindMatlabMex.cmake b/cmake/Modules/FindMatlabMex.cmake new file mode 100644 index 00000000000..28ae65e7cbb --- /dev/null +++ b/cmake/Modules/FindMatlabMex.cmake @@ -0,0 +1,48 @@ +# This module looks for MatlabMex compiler +# Defines variables: +# Matlab_DIR - Matlab root dir +# Matlab_mex - path to mex compiler +# Matlab_mexext - path to mexext + +if(MSVC) + foreach(__ver "9.30" "7.14" "7.11" "7.10" "7.9" "7.8" "7.7") + get_filename_component(__matlab_root "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB\\${__ver};MATLABROOT]" ABSOLUTE) + if(__matlab_root) + break() + endif() + endforeach() +endif() + +if(APPLE) + foreach(__ver "R2014b" "R2014a" "R2013b" "R2013a" "R2012b" "R2012a" "R2011b" "R2011a" "R2010b" "R2010a") + if(EXISTS /Applications/MATLAB_${__ver}.app) + set(__matlab_root /Applications/MATLAB_${__ver}.app) + break() + endif() + endforeach() +endif() + +if(UNIX) + execute_process(COMMAND which matlab OUTPUT_STRIP_TRAILING_WHITESPACE + OUTPUT_VARIABLE __out RESULT_VARIABLE __res) + + if(__res MATCHES 0) # Suppress `readlink` warning if `which` returned nothing + execute_process(COMMAND which matlab COMMAND xargs readlink + COMMAND xargs dirname COMMAND xargs dirname COMMAND xargs echo -n + OUTPUT_VARIABLE __matlab_root OUTPUT_STRIP_TRAILING_WHITESPACE) + endif() +endif() + + +find_path(Matlab_DIR NAMES bin/mex bin/mexext PATHS ${__matlab_root} + DOC "Matlab directory" NO_DEFAULT_PATH) + +find_program(Matlab_mex NAMES mex mex.bat HINTS ${Matlab_DIR} PATH_SUFFIXES bin NO_DEFAULT_PATH) +find_program(Matlab_mexext NAMES mexext mexext.bat HINTS ${Matlab_DIR} PATH_SUFFIXES bin NO_DEFAULT_PATH) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(MatlabMex DEFAULT_MSG Matlab_mex Matlab_mexext) + +if(MATLABMEX_FOUND) + mark_as_advanced(Matlab_mex Matlab_mexext) +endif() diff --git a/cmake/Modules/FindNumPy.cmake b/cmake/Modules/FindNumPy.cmake new file mode 100644 index 00000000000..a671494caba --- /dev/null +++ b/cmake/Modules/FindNumPy.cmake @@ -0,0 +1,58 @@ +# - Find the NumPy libraries +# This module finds if NumPy is installed, and sets the following variables +# indicating where it is. +# +# TODO: Update to provide the libraries and paths for linking npymath lib. +# +# NUMPY_FOUND - was NumPy found +# NUMPY_VERSION - the version of NumPy found as a string +# NUMPY_VERSION_MAJOR - the major version number of NumPy +# NUMPY_VERSION_MINOR - the minor version number of NumPy +# NUMPY_VERSION_PATCH - the patch version number of NumPy +# NUMPY_VERSION_DECIMAL - e.g. version 1.6.1 is 10601 +# NUMPY_INCLUDE_DIR - path to the NumPy include files + +unset(NUMPY_VERSION) +unset(NUMPY_INCLUDE_DIR) + +if(PYTHONINTERP_FOUND) + execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" + "import numpy as n; print(n.__version__); print(n.get_include());" + RESULT_VARIABLE __result + OUTPUT_VARIABLE __output + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(__result MATCHES 0) + string(REGEX REPLACE ";" "\\\\;" __values ${__output}) + string(REGEX REPLACE "\r?\n" ";" __values ${__values}) + list(GET __values 0 NUMPY_VERSION) + list(GET __values 1 NUMPY_INCLUDE_DIR) + + string(REGEX MATCH "^([0-9])+\\.([0-9])+\\.([0-9])+" __ver_check "${NUMPY_VERSION}") + if(NOT "${__ver_check}" STREQUAL "") + set(NUMPY_VERSION_MAJOR ${CMAKE_MATCH_1}) + set(NUMPY_VERSION_MINOR ${CMAKE_MATCH_2}) + set(NUMPY_VERSION_PATCH ${CMAKE_MATCH_3}) + math(EXPR NUMPY_VERSION_DECIMAL + "(${NUMPY_VERSION_MAJOR} * 10000) + (${NUMPY_VERSION_MINOR} * 100) + ${NUMPY_VERSION_PATCH}") + string(REGEX REPLACE "\\\\" "/" NUMPY_INCLUDE_DIR ${NUMPY_INCLUDE_DIR}) + else() + unset(NUMPY_VERSION) + unset(NUMPY_INCLUDE_DIR) + message(STATUS "Requested NumPy version and include path, but got instead:\n${__output}\n") + endif() + endif() +else() + message(STATUS "To find NumPy Python interpretator is required to be found.") +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(NumPy REQUIRED_VARS NUMPY_INCLUDE_DIR NUMPY_VERSION + VERSION_VAR NUMPY_VERSION) + +if(NUMPY_FOUND) + message(STATUS "NumPy ver. ${NUMPY_VERSION} found (include: ${NUMPY_INCLUDE_DIR})") +endif() + +caffe_clear_vars(__result __output __error_value __values __ver_check __error_value) + diff --git a/CMakeScripts/FindOpenBLAS.cmake b/cmake/Modules/FindOpenBLAS.cmake similarity index 100% rename from CMakeScripts/FindOpenBLAS.cmake rename to cmake/Modules/FindOpenBLAS.cmake diff --git a/cmake/Modules/FindSnappy.cmake b/cmake/Modules/FindSnappy.cmake new file mode 100644 index 00000000000..eff2a864a7b --- /dev/null +++ b/cmake/Modules/FindSnappy.cmake @@ -0,0 +1,28 @@ +# Find the Snappy libraries +# +# The following variables are optionally searched for defaults +# Snappy_ROOT_DIR: Base directory where all Snappy components are found +# +# The following are set after configuration is done: +# SNAPPY_FOUND +# Snappy_INCLUDE_DIR +# Snappy_LIBRARIES + +find_path(Snappy_INCLUDE_DIR NAMES snappy.h + PATHS ${SNAPPY_ROOT_DIR} ${SNAPPY_ROOT_DIR}/include) + +find_library(Snappy_LIBRARIES NAMES snappy + PATHS ${SNAPPY_ROOT_DIR} ${SNAPPY_ROOT_DIR}/lib) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Snappy DEFAULT_MSG Snappy_INCLUDE_DIR Snappy_LIBRARIES) + +if(SNAPPY_FOUND) + message(STATUS "Found Snappy (include: ${Snappy_INCLUDE_DIR}, library: ${Snappy_LIBRARIES})") + mark_as_advanced(Snappy_INCLUDE_DIR Snappy_LIBRARIES) + + caffe_parse_header(${Snappy_INCLUDE_DIR}/snappy-stubs-public.h + SNAPPY_VERION_LINES SNAPPY_MAJOR SNAPPY_MINOR SNAPPY_PATCHLEVEL) + set(Snappy_VERSION "${SNAPPY_MAJOR}.${SNAPPY_MINOR}.${SNAPPY_PATCHLEVEL}") +endif() + diff --git a/cmake/Modules/FindvecLib.cmake b/cmake/Modules/FindvecLib.cmake new file mode 100644 index 00000000000..9600da43647 --- /dev/null +++ b/cmake/Modules/FindvecLib.cmake @@ -0,0 +1,34 @@ +# Find the vecLib libraries as part of Accelerate.framework or as standalon framework +# +# The following are set after configuration is done: +# VECLIB_FOUND +# vecLib_INCLUDE_DIR +# vecLib_LINKER_LIBS + + +if(NOT APPLE) + return() +endif() + +set(__veclib_include_suffix "Frameworks/vecLib.framework/Versions/Current/Headers") + +find_path(vecLib_INCLUDE_DIR vecLib.h + DOC "vecLib include directory" + PATHS /System/Library/${__veclib_include_suffix} + /System/Library/Frameworks/Accelerate.framework/Versions/Current/${__veclib_include_suffix} + /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/System/Library/Frameworks/Accelerate.framework/Versions/Current/Frameworks/vecLib.framework/Headers/) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(vecLib DEFAULT_MSG vecLib_INCLUDE_DIR) + +if(VECLIB_FOUND) + if(vecLib_INCLUDE_DIR MATCHES "^/System/Library/Frameworks/vecLib.framework.*") + set(vecLib_LINKER_LIBS -lcblas "-framework vecLib") + message(STATUS "Found standalone vecLib.framework") + else() + set(vecLib_LINKER_LIBS -lcblas "-framework Accelerate") + message(STATUS "Found vecLib as part of Accelerate.framework") + endif() + + mark_as_advanced(vecLib_INCLUDE_DIR) +endif() diff --git a/cmake/ProtoBuf.cmake b/cmake/ProtoBuf.cmake new file mode 100644 index 00000000000..bb63c9ed736 --- /dev/null +++ b/cmake/ProtoBuf.cmake @@ -0,0 +1,90 @@ +# Finds Google Protocol Buffers library and compilers and extends +# the standart cmake script with version and python generation support + +find_package( Protobuf REQUIRED ) +include_directories(SYSTEM ${PROTOBUF_INCLUDE_DIR}) +list(APPEND Caffe_LINKER_LIBS ${PROTOBUF_LIBRARIES}) + +# As of Ubuntu 14.04 protoc is no longer a part of libprotobuf-dev package +# and should be installed separately as in: sudo apt-get install protobuf-compiler +if(EXISTS ${PROTOBUF_PROTOC_EXECUTABLE}) + message(STATUS "Found PROTOBUF Compiler: ${PROTOBUF_PROTOC_EXECUTABLE}") +else() + message(FATAL_ERROR "Could not find PROTOBUF Compiler") +endif() + +if(PROTOBUF_FOUND) + # fetches protobuf version + caffe_parse_header(${PROTOBUF_INCLUDE_DIR}/google/protobuf/stubs/common.h VERION_LINE GOOGLE_PROTOBUF_VERSION) + string(REGEX MATCH "([0-9])00([0-9])00([0-9])" PROTOBUF_VERSION ${GOOGLE_PROTOBUF_VERSION}) + set(PROTOBUF_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}") + unset(GOOGLE_PROTOBUF_VERSION) +endif() + +# place where to generate protobuf sources +set(proto_gen_folder "${CMAKE_BINARY_DIR}/include/caffe/proto") +include_directories(SYSTEM "${CMAKE_BINARY_DIR}/include") + +set(PROTOBUF_GENERATE_CPP_APPEND_PATH TRUE) + +################################################################################################ +# Modification of standard 'protobuf_generate_cpp()' with output dir parameter and python support +# Usage: +# caffe_protobuf_generate_cpp_py( ) +function(caffe_protobuf_generate_cpp_py output_dir srcs_var hdrs_var python_var) + if(NOT ARGN) + message(SEND_ERROR "Error: caffe_protobuf_generate_cpp_py() called without any proto files") + return() + endif() + + if(PROTOBUF_GENERATE_CPP_APPEND_PATH) + # Create an include path for each file specified + foreach(fil ${ARGN}) + get_filename_component(abs_fil ${fil} ABSOLUTE) + get_filename_component(abs_path ${abs_fil} PATH) + list(FIND _protoc_include ${abs_path} _contains_already) + if(${_contains_already} EQUAL -1) + list(APPEND _protoc_include -I ${abs_path}) + endif() + endforeach() + else() + set(_protoc_include -I ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + + if(DEFINED PROTOBUF_IMPORT_DIRS) + foreach(dir ${PROTOBUF_IMPORT_DIRS}) + get_filename_component(abs_path ${dir} ABSOLUTE) + list(FIND _protoc_include ${abs_path} _contains_already) + if(${_contains_already} EQUAL -1) + list(APPEND _protoc_include -I ${abs_path}) + endif() + endforeach() + endif() + + set(${srcs_var}) + set(${hdrs_var}) + set(${python_var}) + foreach(fil ${ARGN}) + get_filename_component(abs_fil ${fil} ABSOLUTE) + get_filename_component(fil_we ${fil} NAME_WE) + + list(APPEND ${srcs_var} "${output_dir}/${fil_we}.pb.cc") + list(APPEND ${hdrs_var} "${output_dir}/${fil_we}.pb.h") + list(APPEND ${python_var} "${output_dir}/${fil_we}_pb2.py") + + add_custom_command( + OUTPUT "${output_dir}/${fil_we}.pb.cc" + "${output_dir}/${fil_we}.pb.h" + "${output_dir}/${fil_we}_pb2.py" + COMMAND ${CMAKE_COMMAND} -E make_directory "${output_dir}" + COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} --cpp_out ${output_dir} ${_protoc_include} ${abs_fil} + COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} --python_out ${output_dir} ${_protoc_include} ${abs_fil} + DEPENDS ${abs_fil} + COMMENT "Running C++/Python protocol buffer compiler on ${fil}" VERBATIM ) + endforeach() + + set_source_files_properties(${${srcs_var}} ${${hdrs_var}} ${${python_var}} PROPERTIES GENERATED TRUE) + set(${srcs_var} ${${srcs_var}} PARENT_SCOPE) + set(${hdrs_var} ${${hdrs_var}} PARENT_SCOPE) + set(${python_var} ${${python_var}} PARENT_SCOPE) +endfunction() diff --git a/cmake/Summary.cmake b/cmake/Summary.cmake new file mode 100644 index 00000000000..756a738c9ab --- /dev/null +++ b/cmake/Summary.cmake @@ -0,0 +1,166 @@ +################################################################################################ +# Caffe status report function. +# Automatically align right column and selects text based on condition. +# Usage: +# caffe_status() +# caffe_status( [ ...]) +# caffe_status( THEN ELSE ) +function(caffe_status text) + set(status_cond) + set(status_then) + set(status_else) + + set(status_current_name "cond") + foreach(arg ${ARGN}) + if(arg STREQUAL "THEN") + set(status_current_name "then") + elseif(arg STREQUAL "ELSE") + set(status_current_name "else") + else() + list(APPEND status_${status_current_name} ${arg}) + endif() + endforeach() + + if(DEFINED status_cond) + set(status_placeholder_length 23) + string(RANDOM LENGTH ${status_placeholder_length} ALPHABET " " status_placeholder) + string(LENGTH "${text}" status_text_length) + if(status_text_length LESS status_placeholder_length) + string(SUBSTRING "${text}${status_placeholder}" 0 ${status_placeholder_length} status_text) + elseif(DEFINED status_then OR DEFINED status_else) + message(STATUS "${text}") + set(status_text "${status_placeholder}") + else() + set(status_text "${text}") + endif() + + if(DEFINED status_then OR DEFINED status_else) + if(${status_cond}) + string(REPLACE ";" " " status_then "${status_then}") + string(REGEX REPLACE "^[ \t]+" "" status_then "${status_then}") + message(STATUS "${status_text} ${status_then}") + else() + string(REPLACE ";" " " status_else "${status_else}") + string(REGEX REPLACE "^[ \t]+" "" status_else "${status_else}") + message(STATUS "${status_text} ${status_else}") + endif() + else() + string(REPLACE ";" " " status_cond "${status_cond}") + string(REGEX REPLACE "^[ \t]+" "" status_cond "${status_cond}") + message(STATUS "${status_text} ${status_cond}") + endif() + else() + message(STATUS "${text}") + endif() +endfunction() + + +################################################################################################ +# Function for fetching Caffe version from git and headers +# Usage: +# caffe_extract_caffe_version() +function(caffe_extract_caffe_version) + set(Caffe_GIT_VERSION "unknown") + find_package(Git) + if(GIT_FOUND) + execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --always --dirty + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE Caffe_GIT_VERSION + RESULT_VARIABLE __git_result) + if(NOT ${__git_result} EQUAL 0) + set(Caffe_GIT_VERSION "unknown") + endif() + endif() + + set(Caffe_GIT_VERSION ${Caffe_GIT_VERSION} PARENT_SCOPE) + set(Caffe_VERSION " (Caffe doesn't declare its version in headers)" PARENT_SCOPE) + + # caffe_parse_header(${Caffe_INCLUDE_DIR}/caffe/version.hpp Caffe_VERSION_LINES CAFFE_MAJOR CAFFE_MINOR CAFFE_PATCH) + # set(Caffe_VERSION "${CAFFE_MAJOR}.${CAFFE_MINOR}.${CAFFE_PATCH}" PARENT_SCOPE) + + # or for #define Caffe_VERSION "x.x.x" + # caffe_parse_header_single_define(Caffe ${Caffe_INCLUDE_DIR}/caffe/version.hpp Caffe_VERSION) + # set(Caffe_VERSION ${Caffe_VERSION_STRING} PARENT_SCOPE) + +endfunction() + + +################################################################################################ +# Prints accumulatd caffe configuration summary +# Usage: +# caffe_print_configuration_summary() + +function(caffe_print_configuration_summary) + caffe_extract_caffe_version() + set(Caffe_VERSION ${Caffe_VERSION} PARENT_SCOPE) + + caffe_merge_flag_lists(__flags_rel CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS) + caffe_merge_flag_lists(__flags_deb CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS) + + caffe_status("") + caffe_status("******************* Caffe Configuration Summary *******************") + caffe_status("General:") + caffe_status(" Version : ${Caffe_VERSION}") + caffe_status(" Git : ${Caffe_GIT_VERSION}") + caffe_status(" System : ${CMAKE_SYSTEM_NAME}") + caffe_status(" C++ compiler : ${CMAKE_CXX_COMPILER}") + caffe_status(" Release CXX flags : ${__flags_rel}") + caffe_status(" Debug CXX flags : ${__flags_deb}") + caffe_status(" BUILD_SHARED_LIBS : ${BUILD_SHARED_LIBS}") + caffe_status(" Build type : ${CMAKE_BUILD_TYPE}") + caffe_status(" BUILD_python : ${BUILD_python}") + caffe_status(" BUILD_matlab : ${BUILD_matlab}") + caffe_status(" BUILD_docs : ${BUILD_docs}") + caffe_status(" CPU_ONLY : ${CPU_ONLY}") + caffe_status("") + caffe_status("Dependencies:") + caffe_status(" BLAS : " APPLE THEN "Yes (vecLib)" ELSE "Yes (${BLAS})") + caffe_status(" glog : Yes") + caffe_status(" gflags : Yes") + caffe_status(" protobuf : " PROTOBUF_FOUND THEN "Yes (ver. ${PROTOBUF_VERSION})" ELSE "No" ) + caffe_status(" lmdb : " LMDB_FOUND THEN "Yes (ver. ${LMDB_VERSION})" ELSE "No") + caffe_status(" Snappy : " SNAPPY_FOUND THEN "Yes (ver. ${Snappy_VERSION})" ELSE "No" ) + caffe_status(" LevelDB : " LEVELDB_FOUND THEN "Yes (ver. ${LEVELDB_VERSION})" ELSE "No") + caffe_status(" OpenCV : Yes (ver. ${OpenCV_VERSION})") + caffe_status(" CUDA : " HAVE_CUDA THEN "Yes (ver. ${CUDA_VERSION})" ELSE "No" ) + caffe_status("") + if(HAVE_CUDA) + caffe_status("NVIDIA CUDA:") + caffe_status(" Target GPU(s) : ${CUDA_ARCH_NAME}" ) + caffe_status(" GPU arch(s) : ${NVCC_FLAGS_EXTRA_readable}") + if(USE_CUDNN) + caffe_status(" cuDNN : " HAVE_CUDNN THEN "Yes" ELSE "Not found") + else() + caffe_status(" cuDNN : Disabled") + endif() + caffe_status("") + endif() + if(HAVE_PYTHON) + caffe_status("Python:") + caffe_status(" Interpreter :" PYTHON_EXECUTABLE THEN "${PYTHON_EXECUTABLE} (ver. ${PYTHON_VERSION_STRING})" ELSE "No") + caffe_status(" Libraries :" PYTHONLIBS_FOUND THEN "${PYTHON_LIBRARIES} (ver ${PYTHONLIBS_VERSION_STRING})" ELSE "No") + caffe_status(" NumPy :" NUMPY_FOUND THEN "${NUMPY_INCLUDE_DIR} (ver ${NUMPY_VERSION})" ELSE "No") + caffe_status("") + endif() + if(BUILD_matlab) + caffe_status("Matlab:") + caffe_status(" Matlab :" HAVE_MATLAB THEN "Yes (${Matlab_mex}, ${Matlab_mexext}" ELSE "No") + caffe_status(" Octave :" Octave_compiler THEN "Yes (${Octave_compiler})" ELSE "No") + if(HAVE_MATLAB AND Octave_compiler) + caffe_status(" Build mex using : ${Matlab_build_mex_using}") + endif() + caffe_status("") + endif() + if(BUILD_docs) + caffe_status("Documentaion:") + caffe_status(" Doxygen :" DOXYGEN_FOUND THEN "${DOXYGEN_EXECUTABLE} (${DOXYGEN_VERSION})" ELSE "No") + caffe_status(" config_file : ${DOXYGEN_config_file}") + + caffe_status("") + endif() + caffe_status("Install:") + caffe_status(" Install path : ${CMAKE_INSTALL_PREFIX}") + caffe_status("") +endfunction() + diff --git a/cmake/Targets.cmake b/cmake/Targets.cmake new file mode 100644 index 00000000000..84a2aaf58e9 --- /dev/null +++ b/cmake/Targets.cmake @@ -0,0 +1,170 @@ +################################################################################################ +# Defines global Caffe_LINK flag, This flag is required to prevent linker from excluding +# some objects which are not addressed directly but are registered via static constructors +if(BUILD_SHARED_LIBS) + set(Caffe_LINK caffe) +else() + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set(Caffe_LINK -Wl,-force_load caffe) + elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + set(Caffe_LINK -Wl,--whole-archive caffe -Wl,--no-whole-archive) + endif() +endif() + +################################################################################################ +# Convenient command to setup source group for IDEs that support this feature (VS, XCode) +# Usage: +# caffe_source_group( GLOB[_RECURSE] ) +function(caffe_source_group group) + cmake_parse_arguments(CAFFE_SOURCE_GROUP "" "" "GLOB;GLOB_RECURSE" ${ARGN}) + if(CAFFE_SOURCE_GROUP_GLOB) + file(GLOB srcs1 ${CAFFE_SOURCE_GROUP_GLOB}) + source_group(${group} FILES ${srcs1}) + endif() + + if(CAFFE_SOURCE_GROUP_GLOB_RECURSE) + file(GLOB_RECURSE srcs2 ${CAFFE_SOURCE_GROUP_GLOB_RECURSE}) + source_group(${group} FILES ${srcs2}) + endif() +endfunction() + +################################################################################################ +# Collecting sources from globbing and appending to output list variable +# Usage: +# caffe_source_group( GLOB[_RECURSE] ) +function(caffe_collect_sources variable) + cmake_parse_arguments(CAFFE_COLLECT_SOURCES "" "" "GLOB;GLOB_RECURSE" ${ARGN}) + if(CAFFE_COLLECT_SOURCES_GLOB) + file(GLOB srcs1 ${CAFFE_COLLECT_SOURCES_GLOB}) + set(${variable} ${variable} ${srcs1}) + endif() + + if(CAFFE_COLLECT_SOURCES_GLOB_RECURSE) + file(GLOB_RECURSE srcs2 ${CAFFE_COLLECT_SOURCES_GLOB_RECURSE}) + set(${variable} ${variable} ${srcs2}) + endif() +endfunction() + +################################################################################################ +# Short command getting caffe sources (assuming standard Caffe code tree) +# Usage: +# caffe_pickup_caffe_sources() +function(caffe_pickup_caffe_sources root) + # put all files in source groups (visible as subfolder in many IDEs) + caffe_source_group("Include" GLOB "${root}/include/caffe/*.h*") + caffe_source_group("Include\\Util" GLOB "${root}/include/caffe/util/*.h*") + caffe_source_group("Include" GLOB "${CMAKE_BINARY_DIR}/caffe_config.h*") + caffe_source_group("Source" GLOB "${root}/src/caffe/*.cpp") + caffe_source_group("Source\\Util" GLOB "${root}/src/caffe/util/*.cpp") + caffe_source_group("Source\\Layers" GLOB "${root}/src/caffe/layers/*.cpp") + caffe_source_group("Source\\Cuda" GLOB "${root}/src/caffe/layers/*.cu") + caffe_source_group("Source\\Cuda" GLOB "${root}/src/caffe/util/*.cu") + caffe_source_group("Source\\Proto" GLOB "${root}/src/caffe/proto/*.proto") + + # source groups for test target + caffe_source_group("Include" GLOB "${root}/include/caffe/test/test_*.h*") + caffe_source_group("Source" GLOB "${root}/src/caffe/test/test_*.cpp") + caffe_source_group("Source\\Cuda" GLOB "${root}/src/caffe/test/test_*.cu") + + # collect files + file(GLOB test_hdrs ${root}/include/caffe/test/test_*.h*) + file(GLOB test_srcs ${root}/src/caffe/test/test_*.cpp) + file(GLOB_RECURSE hdrs ${root}/include/caffe/*.h*) + file(GLOB_RECURSE srcs ${root}/src/caffe/*.cpp) + list(REMOVE_ITEM hdrs ${test_hdrs}) + list(REMOVE_ITEM srcs ${test_srcs}) + + # adding headers to make the visible in some IDEs (Qt, VS, Xcode) + list(APPEND srcs ${hdrs} ${CMAKE_BINARY_DIR}/caffe_config.h) + list(APPEND test_srcs ${test_hdrs}) + + # collect cuda files + file(GLOB test_cuda ${root}/src/caffe/test/test_*.cu) + file(GLOB_RECURSE cuda ${root}/src/caffe/*.cu) + list(REMOVE_ITEM cuda ${test_cuda}) + + # add proto to make them editable in IDEs too + file(GLOB_RECURSE proto_files ${root}/src/caffe/*.proto) + list(APPEND srcs ${proto_files}) + + # convet to absolute paths + caffe_convert_absolute_paths(srcs) + caffe_convert_absolute_paths(cuda) + caffe_convert_absolute_paths(test_srcs) + caffe_convert_absolute_paths(test_cuda) + + # propogate to parent scope + set(srcs ${srcs} PARENT_SCOPE) + set(cuda ${cuda} PARENT_SCOPE) + set(test_srcs ${test_srcs} PARENT_SCOPE) + set(test_cuda ${test_cuda} PARENT_SCOPE) +endfunction() + +################################################################################################ +# Short command for setting defeault target properties +# Usage: +# caffe_default_properties() +function(caffe_default_properties target) + set_target_properties(${target} PROPERTIES + DEBUG_POSTFIX ${Caffe_DEBUG_POSTFIX} + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") +endfunction() + +################################################################################################ +# Short command for setting runtime directory for build target +# Usage: +# caffe_set_runtime_directory( ) +function(caffe_set_runtime_directory target dir) + set_target_properties(${target} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${dir}") +endfunction() + +################################################################################################ +# Short command for setting solution folder property for target +# Usage: +# caffe_set_solution_folder( ) +function(caffe_set_solution_folder target folder) + if(USE_PROJECT_FOLDERS) + set_target_properties(${target} PROPERTIES FOLDER "${folder}") + endif() +endfunction() + +################################################################################################ +# Reads lines from input file, prepends source directory to each line and writes to output file +# Usage: +# caffe_configure_testdatafile() +function(caffe_configure_testdatafile file) + file(STRINGS ${file} __lines) + set(result "") + foreach(line ${__lines}) + set(result "${result}${CMAKE_SOURCE_DIR}/${line}\n") + endforeach() + dmsg(${result}) + file(WRITE ${file}.gen.cmake ${result}) +endfunction() + +################################################################################################ +# Filter outs all files that are not inlcuded in selected list +# Usage: +# caffe_leave_only_selected_tests( ) +function(caffe_leave_only_selected_tests file_list) + if(NOT ARGN) + return() # blank list means leave all + endif() + string(REPLACE "," ";" __selected ${ARGN}) + list(APPEND __selected caffe_main) + + set(result "") + foreach(f ${${file_list}}) + get_filename_component(name ${f} NAME_WE) + string(REGEX REPLACE "^test_" "" name ${name}) + list(FIND __selected ${name} __index) + if(NOT __index EQUAL -1) + list(APPEND result ${f}) + endif() + endforeach() + set(${file_list} ${result} PARENT_SCOPE) +endfunction() + diff --git a/cmake/Templates/CaffeConfig.cmake.in b/cmake/Templates/CaffeConfig.cmake.in new file mode 100644 index 00000000000..a4b03d961e0 --- /dev/null +++ b/cmake/Templates/CaffeConfig.cmake.in @@ -0,0 +1,58 @@ +# Config file for the Caffe package. +# +# Note: +# Caffe and this config file depends on opencv, +# so put `find_package(OpenCV)` before searching Caffe +# via `find_package(Caffe)`. All other lib/includes +# dependencies are hard coded int the file +# +# After successful configuration the following variables +# will be defined: +# +# Caffe_INCLUDE_DIRS - Caffe include directories +# Caffe_LIBRARIES - libraries to link against +# Caffe_DEFINITIONS - a list of definitions to pass to compiler +# +# Caffe_HAVE_CUDA - signals about CUDA support +# Caffe_HAVE_CUDNN - signals about cuDNN support + + +# OpenCV dependency + +if(NOT OpenCV_FOUND) + set(Caffe_OpenCV_CONFIG_PATH "@OpenCV_CONFIG_PATH@") + if(Caffe_OpenCV_CONFIG_PATH) + get_filename_component(Caffe_OpenCV_CONFIG_PATH ${Caffe_OpenCV_CONFIG_PATH} ABSOLUTE) + + if(EXISTS ${Caffe_OpenCV_CONFIG_PATH} AND NOT TARGET opencv_core) + message(STATUS "Caffe: using OpenCV config from ${Caffe_OpenCV_CONFIG_PATH}") + include(${Caffe_OpenCV_CONFIG_PATH}/OpenCVModules.cmake) + endif() + + else() + find_package(OpenCV REQUIRED) + endif() + unset(Caffe_OpenCV_CONFIG_PATH) +endif() + +# Compute paths +get_filename_component(Caffe_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +set(Caffe_INCLUDE_DIRS "@Caffe_INCLUDE_DIRS@") + +@Caffe_INSTALL_INCLUDE_DIR_APPEND_COMMAND@ + +# Our library dependencies +if(NOT TARGET caffe AND NOT caffe_BINARY_DIR) + include("${Caffe_CMAKE_DIR}/CaffeTargets.cmake") +endif() + +# List of IMPORTED libs created by CaffeTargets.cmake +set(Caffe_LIBRARIES caffe) + +# Definitions +set(Caffe_DEFINITIONS "@Caffe_DEFINITIONS@") + +# Cuda support variables +set(Caffe_CPU_ONLY @CPU_ONLY@) +set(Caffe_HAVE_CUDA @HAVE_CUDA@) +set(Caffe_HAVE_CUDNN @HAVE_CUDNN@) diff --git a/cmake/Templates/CaffeConfigVersion.cmake.in b/cmake/Templates/CaffeConfigVersion.cmake.in new file mode 100644 index 00000000000..cbfa514f1a6 --- /dev/null +++ b/cmake/Templates/CaffeConfigVersion.cmake.in @@ -0,0 +1,11 @@ +set(PACKAGE_VERSION "@Caffe_VERSION@") + +# Check whether the requested PACKAGE_FIND_VERSION is compatible +if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_EXACT TRUE) + endif() +endif() diff --git a/cmake/Templates/caffe_config.h.in b/cmake/Templates/caffe_config.h.in new file mode 100644 index 00000000000..6aa22ed7b5c --- /dev/null +++ b/cmake/Templates/caffe_config.h.in @@ -0,0 +1,32 @@ +/* Sources directory */ +#define SOURCE_FOLDER "${CMAKE_SOURCE_DIR}" + +/* Binaries directory */ +#define BINARY_FOLDER "${CMAKE_BINARY_DIR}" + +/* NVIDA Cuda */ +#cmakedefine HAVE_CUDA + +/* NVIDA cuDNN */ +#cmakedefine HAVE_CUDNN +#cmakedefine USE_CUDNN + +/* NVIDA cuDNN */ +#cmakedefine CPU_ONLY + +/* Test device */ +#define CUDA_TEST_DEVICE ${CUDA_TEST_DEVICE} + +/* Temporary (TODO: remove) */ +#if 1 + #define CMAKE_SOURCE_DIR SOURCE_FOLDER "/src/" + #define EXAMPLES_SOURCE_DIR BINARY_FOLDER "/examples/" + #define CMAKE_EXT ".gen.cmake" +#else + #define CMAKE_SOURCE_DIR "src/" + #define EXAMPLES_SOURCE_DIR "examples/" + #define CMAKE_EXT "" +#endif + +/* Matlab */ +#cmakedefine HAVE_MATLAB diff --git a/cmake/Utils.cmake b/cmake/Utils.cmake new file mode 100644 index 00000000000..048123dbe10 --- /dev/null +++ b/cmake/Utils.cmake @@ -0,0 +1,365 @@ +################################################################################################ +# Command alias for debugging messages +# Usage: +# dmgs() +function(dmsg) + message(STATUS ${ARGN}) +endfunction() + +################################################################################################ +# Removes duplicates from list(s) +# Usage: +# caffe_list_unique( [] [...]) +macro(caffe_list_unique) + foreach(__lst ${ARGN}) + if(${__lst}) + list(REMOVE_DUPLICATES ${__lst}) + endif() + endforeach() +endmacro() + +################################################################################################ +# Clears variables from lsit +# Usage: +# caffe_list_unique() +macro(caffe_clear_vars) + foreach(_var ${ARGN}) + unset(${_var}) + endforeach() +endmacro() + +################################################################################################ +# Removes duplicates from string +# Usage: +# caffe_string_unique() +function(caffe_string_unique __string) + if(${__string}) + set(__list ${${__string}}) + separate_arguments(__list) + list(REMOVE_DUPLICATES __list) + foreach(__e ${__list}) + set(__str "${__str} ${__e}") + endforeach() + set(${__string} ${__str} PARENT_SCOPE) + endif() +endfunction() + +################################################################################################ +# Prints list element per line +# Usage: +# caffe_print_list() +function(caffe_print_list) + foreach(e ${ARGN}) + message(STATUS ${e}) + endforeach() +endfunction() + +################################################################################################ +# Function merging lists of compiler flags to single string. +# Usage: +# caffe_merge_flag_lists(out_variable [] [] ...) +function(caffe_merge_flag_lists out_var) + set(__result "") + foreach(__list ${ARGN}) + foreach(__flag ${${__list}}) + string(STRIP ${__flag} __flag) + set(__result "${__result} ${__flag}") + endforeach() + endforeach() + string(STRIP ${__result} __result) + set(${out_var} ${__result} PARENT_SCOPE) +endfunction() + +################################################################################################ +# Converts all paths in list to absolute +# Usage: +# caffe_convert_absolute_paths() +function(caffe_convert_absolute_paths variable) + set(__dlist "") + foreach(__s ${${variable}}) + get_filename_component(__abspath ${__s} ABSOLUTE) + list(APPEND __list ${__abspath}) + endforeach() + set(${variable} ${__list} PARENT_SCOPE) +endfunction() + +################################################################################################ +# Reads set of version defines from the header file +# Usage: +# caffe_parse_header( ..) +macro(caffe_parse_header FILENAME FILE_VAR) + set(vars_regex "") + set(__parnet_scope OFF) + set(__add_cache OFF) + foreach(name ${ARGN}) + if("${name}" STREQUAL "PARENT_SCOPE") + set(__parnet_scope ON) + elseif("${name}" STREQUAL "CACHE") + set(__add_cache ON) + elseif(vars_regex) + set(vars_regex "${vars_regex}|${name}") + else() + set(vars_regex "${name}") + endif() + endforeach() + if(EXISTS "${FILENAME}") + file(STRINGS "${FILENAME}" ${FILE_VAR} REGEX "#define[ \t]+(${vars_regex})[ \t]+[0-9]+" ) + else() + unset(${FILE_VAR}) + endif() + foreach(name ${ARGN}) + if(NOT "${name}" STREQUAL "PARENT_SCOPE" AND NOT "${name}" STREQUAL "CACHE") + if(${FILE_VAR}) + if(${FILE_VAR} MATCHES ".+[ \t]${name}[ \t]+([0-9]+).*") + string(REGEX REPLACE ".+[ \t]${name}[ \t]+([0-9]+).*" "\\1" ${name} "${${FILE_VAR}}") + else() + set(${name} "") + endif() + if(__add_cache) + set(${name} ${${name}} CACHE INTERNAL "${name} parsed from ${FILENAME}" FORCE) + elseif(__parnet_scope) + set(${name} "${${name}}" PARENT_SCOPE) + endif() + else() + unset(${name} CACHE) + endif() + endif() + endforeach() +endmacro() + +################################################################################################ +# Reads single version define from the header file and parses it +# Usage: +# caffe_parse_header_single_define( ) +function(caffe_parse_header_single_define LIBNAME HDR_PATH VARNAME) + set(${LIBNAME}_H "") + if(EXISTS "${HDR_PATH}") + file(STRINGS "${HDR_PATH}" ${LIBNAME}_H REGEX "^#define[ \t]+${VARNAME}[ \t]+\"[^\"]*\".*$" LIMIT_COUNT 1) + endif() + + if(${LIBNAME}_H) + string(REGEX REPLACE "^.*[ \t]${VARNAME}[ \t]+\"([0-9]+).*$" "\\1" ${LIBNAME}_VERSION_MAJOR "${${LIBNAME}_H}") + string(REGEX REPLACE "^.*[ \t]${VARNAME}[ \t]+\"[0-9]+\\.([0-9]+).*$" "\\1" ${LIBNAME}_VERSION_MINOR "${${LIBNAME}_H}") + string(REGEX REPLACE "^.*[ \t]${VARNAME}[ \t]+\"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" ${LIBNAME}_VERSION_PATCH "${${LIBNAME}_H}") + set(${LIBNAME}_VERSION_MAJOR ${${LIBNAME}_VERSION_MAJOR} ${ARGN} PARENT_SCOPE) + set(${LIBNAME}_VERSION_MINOR ${${LIBNAME}_VERSION_MINOR} ${ARGN} PARENT_SCOPE) + set(${LIBNAME}_VERSION_PATCH ${${LIBNAME}_VERSION_PATCH} ${ARGN} PARENT_SCOPE) + set(${LIBNAME}_VERSION_STRING "${${LIBNAME}_VERSION_MAJOR}.${${LIBNAME}_VERSION_MINOR}.${${LIBNAME}_VERSION_PATCH}" PARENT_SCOPE) + + # append a TWEAK version if it exists: + set(${LIBNAME}_VERSION_TWEAK "") + if("${${LIBNAME}_H}" MATCHES "^.*[ \t]${VARNAME}[ \t]+\"[0-9]+\\.[0-9]+\\.[0-9]+\\.([0-9]+).*$") + set(${LIBNAME}_VERSION_TWEAK "${CMAKE_MATCH_1}" ${ARGN} PARENT_SCOPE) + endif() + if(${LIBNAME}_VERSION_TWEAK) + set(${LIBNAME}_VERSION_STRING "${${LIBNAME}_VERSION_STRING}.${${LIBNAME}_VERSION_TWEAK}" ${ARGN} PARENT_SCOPE) + else() + set(${LIBNAME}_VERSION_STRING "${${LIBNAME}_VERSION_STRING}" ${ARGN} PARENT_SCOPE) + endif() + endif() +endfunction() + +######################################################################################################## +# An option that the user can select. Can accept condition to control when option is available for user. +# Usage: +# caffe_option( "doc string" [IF ]) +function(caffe_option variable description value) + set(__value ${value}) + set(__condition "") + set(__varname "__value") + foreach(arg ${ARGN}) + if(arg STREQUAL "IF" OR arg STREQUAL "if") + set(__varname "__condition") + else() + list(APPEND ${__varname} ${arg}) + endif() + endforeach() + unset(__varname) + if("${__condition}" STREQUAL "") + set(__condition 2 GREATER 1) + endif() + + if(${__condition}) + if("${__value}" MATCHES ";") + if(${__value}) + option(${variable} "${description}" ON) + else() + option(${variable} "${description}" OFF) + endif() + elseif(DEFINED ${__value}) + if(${__value}) + option(${variable} "${description}" ON) + else() + option(${variable} "${description}" OFF) + endif() + else() + option(${variable} "${description}" ${__value}) + endif() + else() + unset(${variable} CACHE) + endif() +endfunction() + +################################################################################################ +# Utility macro for comparing two lists. Used for CMake debugging purposes +# Usage: +# caffe_compare_lists( [description]) +function(caffe_compare_lists list1 list2 desc) + set(__list1 ${${list1}}) + set(__list2 ${${list2}}) + list(SORT __list1) + list(SORT __list2) + list(LENGTH __list1 __len1) + list(LENGTH __list2 __len2) + + if(NOT ${__len1} EQUAL ${__len2}) + message(FATAL_ERROR "Lists are not equal. ${__len1} != ${__len2}. ${desc}") + endif() + + foreach(__i RANGE 1 ${__len1}) + math(EXPR __index "${__i}- 1") + list(GET __list1 ${__index} __item1) + list(GET __list2 ${__index} __item2) + if(NOT ${__item1} STREQUAL ${__item2}) + message(FATAL_ERROR "Lists are not equal. Differ at element ${__index}. ${desc}") + endif() + endforeach() +endfunction() + +################################################################################################ +# Command for disabling warnings for different platforms (see below for gcc and VisualStudio) +# Usage: +# caffe_warnings_disable( -Wshadow /wd4996 ..,) +macro(caffe_warnings_disable) + set(_flag_vars "") + set(_msvc_warnings "") + set(_gxx_warnings "") + + foreach(arg ${ARGN}) + if(arg MATCHES "^CMAKE_") + list(APPEND _flag_vars ${arg}) + elseif(arg MATCHES "^/wd") + list(APPEND _msvc_warnings ${arg}) + elseif(arg MATCHES "^-W") + list(APPEND _gxx_warnings ${arg}) + endif() + endforeach() + + if(NOT _flag_vars) + set(_flag_vars CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + + if(MSVC AND _msvc_warnings) + foreach(var ${_flag_vars}) + foreach(warning ${_msvc_warnings}) + set(${var} "${${var}} ${warning}") + endforeach() + endforeach() + elseif((CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGXX) AND _gxx_warnings) + foreach(var ${_flag_vars}) + foreach(warning ${_gxx_warnings}) + if(NOT warning MATCHES "^-Wno-") + string(REPLACE "${warning}" "" ${var} "${${var}}") + string(REPLACE "-W" "-Wno-" warning "${warning}") + endif() + set(${var} "${${var}} ${warning}") + endforeach() + endforeach() + endif() + caffe_clear_vars(_flag_vars _msvc_warnings _gxx_warnings) +endmacro() + +################################################################################################ +# Helper function get current definitions +# Usage: +# caffe_get_current_definitions() +function(caffe_get_current_definitions definitions_var) + get_property(current_definitions DIRECTORY PROPERTY COMPILE_DEFINITIONS) + set(result "") + + foreach(d ${current_definitions}) + list(APPEND result -D${d}) + endforeach() + + caffe_list_unique(result) + set(${definitions_var} ${result} PARENT_SCOPE) +endfunction() + +################################################################################################ +# Helper function get current includes/definitions +# Usage: +# caffe_get_current_cflags() +function(caffe_get_current_cflags cflags_var) + get_property(current_includes DIRECTORY PROPERTY INCLUDE_DIRECTORIES) + caffe_convert_absolute_paths(current_includes) + caffe_get_current_definitions(cflags) + + foreach(i ${current_includes}) + list(APPEND cflags "-I${i}") + endforeach() + + caffe_list_unique(cflags) + set(${cflags_var} ${cflags} PARENT_SCOPE) +endfunction() + +################################################################################################ +# Helper function to parse current linker libs into link directoris, libflags and osx frameworks +# Usage: +# caffe_parse_linker_libs( ) +function(caffe_parse_linker_libs Caffe_LINKER_LIBS_variable folders_var flags_var frameworks_var) + + set(__unspec "") + set(__debug "") + set(__optimized "") + set(__framework "") + set(__varname "__unspec") + + # split libs into debug, optimized, unspecified and frameworks + foreach(list_elem ${${Caffe_LINKER_LIBS_variable}}) + if(list_elem STREQUAL "debug") + set(__varname "__debug") + elseif(list_elem STREQUAL "optimized") + set(__varname "__optimized") + elseif(list_elem MATCHES "^-framework[ \t]+([^ \t].*)") + list(APPEND __framework -framework ${CMAKE_MATCH_1}) + else() + list(APPEND ${__varname} ${list_elem}) + set(__varname "__unspec") + endif() + endforeach() + + # attach debug or optimized libs to unspecified according to current configuration + if(CMAKE_BUILD_TYPE MATCHES "Debug") + set(__libs ${__unspec} ${__debug}) + else() + set(__libs ${__unspec} ${__optimized}) + endif() + + set(libflags "") + set(folders "") + + # convert linker libraries list to link flags + foreach(lib ${__libs}) + if(TARGET ${lib}) + list(APPEND folders $) + list(APPEND libflags -l${lib}) + elseif(lib MATCHES "^-l.*") + list(APPEND libflags ${lib}) + elseif(IS_ABSOLUTE ${lib}) + get_filename_component(name_we ${lib} NAME_WE) + get_filename_component(folder ${lib} PATH) + + string(REGEX MATCH "^lib(.*)" __match ${name_we}) + list(APPEND libflags -l${CMAKE_MATCH_1}) + list(APPEND folders ${folder}) + else() + message(FATAL_ERROR "Logic error. Need to update cmake script") + endif() + endforeach() + + caffe_list_unique(libflags folders) + + set(${folders_var} ${folders} PARENT_SCOPE) + set(${flags_var} ${libflags} PARENT_SCOPE) + set(${frameworks_var} ${__framework} PARENT_SCOPE) +endfunction() diff --git a/CMakeScripts/lint.cmake b/cmake/lint.cmake similarity index 100% rename from CMakeScripts/lint.cmake rename to cmake/lint.cmake diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt new file mode 100644 index 00000000000..927bf5bc731 --- /dev/null +++ b/docs/CMakeLists.txt @@ -0,0 +1,106 @@ +# Building docs script +# Requirements: +# sudo apt-get install doxygen texlive ruby-dev +# sudo gem install jekyll execjs therubyracer + +if(NOT BUILD_docs OR NOT DOXYGEN_FOUND) + return() +endif() + +################################################################################################# +# Gather docs from /examples/**/readme.md +function(gather_readmes_as_prebuild_cmd target gathered_dir root) + set(full_gathered_dir ${root}/${gathered_dir}) + + file(GLOB_RECURSE readmes ${root}/examples/readme.md ${root}/examples/README.md) + foreach(file ${readmes}) + # Only use file if it is to be included in docs. + file(STRINGS ${file} file_lines REGEX "include_in_docs: true") + + if(file_lines) + # Since everything is called readme.md, rename it by its dirname. + file(RELATIVE_PATH file ${root} ${file}) + get_filename_component(folder ${file} PATH) + set(new_filename ${full_gathered_dir}/${folder}.md) + + # folder value might be like /readme.md. That's why make directory. + get_filename_component(new_folder ${new_filename} PATH) + add_custom_command(TARGET ${target} PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${new_folder} + COMMAND ln -sf ${root}/${file} ${new_filename} + COMMENT "Creating simlink ${new_filename} -> ${root}/${file}" + WORKING_DIRECTORY ${root} VERBATIM) + endif() + endforeach() +endfunction() + +################################################################################################ +# Gather docs from examples/*.ipynb and add YAML front-matter. +function(gather_notebooks_as_prebuild_cmd target gathered_dir root) + set(full_gathered_dir ${root}/${gathered_dir}) + + if(NOT PYTHON_EXECUTABLE) + message(STATUS "Python interpeter is not found. Can't include *.ipynb files in docs. Skipping...") + return() + endif() + + file(GLOB_RECURSE notebooks ${root}/examples/*.ipynb) + foreach(file ${notebooks}) + file(RELATIVE_PATH file ${root} ${file}) + set(new_filename ${full_gathered_dir}/${file}) + + get_filename_component(new_folder ${new_filename} PATH) + add_custom_command(TARGET ${target} PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${new_folder} + COMMAND ${PYTHON_EXECUTABLE} scripts/copy_notebook.py ${file} ${new_filename} + COMMENT "Copying notebook ${file} to ${new_filename}" + WORKING_DIRECTORY ${root} VERBATIM) + endforeach() + + set(${outputs_var} ${outputs} PARENT_SCOPE) +endfunction() + +################################################################################################ +########################## [ Non macro part ] ################################################## + +# Gathering is done at each 'make doc' +file(REMOVE_RECURSE ${CMAKE_SOURCE_DIR}/docs/gathered) + +# Doxygen config file path +set(DOXYGEN_config_file ${CMAKE_SOURCE_DIR}/.Doxyfile CACHE FILEPATH "Doxygen config file") + +# Adding docs target +add_custom_target(docs COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_config_file} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMENT "Launching doxygen..." VERBATIM) + +# Gathering examples into docs subfolder +gather_notebooks_as_prebuild_cmd(docs docs/gathered ${CMAKE_SOURCE_DIR}) +gather_readmes_as_prebuild_cmd(docs docs/gathered ${CMAKE_SOURCE_DIR}) + +# Auto detect output directory +file(STRINGS ${DOXYGEN_config_file} config_line REGEX "OUTPUT_DIRECTORY[ \t]+=[^=].*") +if(config_line) + string(REGEX MATCH "OUTPUT_DIRECTORY[ \t]+=([^=].*)" __ver_check "${config_line}") + string(STRIP ${CMAKE_MATCH_1} output_dir) + message(STATUS "Detected Doxygen OUTPUT_DIRECTORY: ${output_dir}") +else() + set(output_dir ./doxygen/) + message(STATUS "Can't find OUTPUT_DIRECTORY in doxygen config file. Try to use default: ${output_dir}") +endif() + +if(NOT IS_ABSOLUTE ${output_dir}) + set(output_dir ${CMAKE_SOURCE_DIR}/${output_dir}) + get_filename_component(output_dir ${output_dir} ABSOLUTE) +endif() + +# creates simlink in docs subfolder to code documentation built by doxygen +add_custom_command(TARGET docs POST_BUILD VERBATIM + COMMAND ln -sfn "${output_dir}/html" doxygen + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/docs + COMMENT "Creating simlink ${CMAKE_SOURCE_DIR}/docs/doxygen -> ${output_dir}/html") + +# for quick launch of jekyll +add_custom_target(jekyll COMMAND jekyll serve -w -s . -d _site --port=4000 + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/docs + COMMENT "Launching jekyll..." VERBATIM) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 055f4ef0d35..4df14afbb98 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,16 +1,31 @@ -project( Examples ) +file(GLOB_RECURSE examples_srcs "${CMAKE_SOURCE_DIR}/examples/*.cpp") -file(GLOB_RECURSE EXAMPLES_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - -foreach(source ${EXAMPLES_SOURCES}) - # get file name - get_filename_component(name ${source} NAME_WE) +foreach(source_file ${examples_srcs}) + # get file name + get_filename_component(name ${source_file} NAME_WE) - #get folder name - get_filename_component(path ${source} PATH) - get_filename_component(folder ${path} NAME_WE) + # get folder name + get_filename_component(path ${source_file} PATH) + get_filename_component(folder ${path} NAME_WE) - add_executable(${name} ${source}) - target_link_libraries(${name} caffe) - set_target_properties(${name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${folder}) -endforeach(source) + add_executable(${name} ${source_file}) + target_link_libraries(${name} ${Caffe_LINK}) + caffe_default_properties(${name}) + + # set back RUNTIME_OUTPUT_DIRECTORY + set_target_properties(${name} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/examples/${folder}") + + caffe_set_solution_folder(${name} examples) + + # install + install(TARGETS ${name} DESTINATION bin) + + if(UNIX OR APPLE) + # Funny command to make tutorials work + # TODO: remove in future as soon as naming is standartaized everywhere + set(__outname ${CMAKE_BINARY_DIR}/examples/${folder}/${name}${CAffe_POSTFIX}) + add_custom_command(TARGET ${name} POST_BUILD + COMMAND ln -sf "${__outname}" "${__outname}.bin") + endif() +endforeach() diff --git a/include/caffe/test/test_caffe_main.hpp b/include/caffe/test/test_caffe_main.hpp index 438acf2bf17..bd5f31e063f 100644 --- a/include/caffe/test/test_caffe_main.hpp +++ b/include/caffe/test/test_caffe_main.hpp @@ -15,7 +15,7 @@ using std::cout; using std::endl; #ifdef CMAKE_BUILD - #include + #include "caffe_config.h" #else #define CUDA_TEST_DEVICE -1 #define CMAKE_SOURCE_DIR "src/" diff --git a/matlab/CMakeLists.txt b/matlab/CMakeLists.txt index f6a03ee4625..40d8729ae76 100644 --- a/matlab/CMakeLists.txt +++ b/matlab/CMakeLists.txt @@ -1 +1,72 @@ -project( Matlab ) \ No newline at end of file +# Builds Matlab (or Octave) interface. In case of Matlab caffe must be +# compield as shared library. Octave can link static or shared caffe library +# To install octave run: sudo apt-get install liboctave-dev + +if(NOT BUILD_matlab) + return() +endif() + +if(HAVE_MATLAB AND Octave_compiler) + set(build_using ${Matlab_build_mex_using}) +elseif(HAVE_MATLAB AND NOT Octave_compiler) + set(build_using "Matlab") +elseif(NOT HAVE_MATLAB AND Octave_compiler) + set(build_using "Octave") +else() + return() +endif() + +if(NOT BUILD_SHARED_LIBS AND build_using MATCHES Matlab) + message(FATAL_ERROR "Matlab MEX interface (with default mex options file) can only be built if caffe is compiled as shared library. Please enable 'BUILD_SHARED_LIBS' in CMake. Aternativelly you can switch to Octave compiler.") +endif() + +# helper function to set proper mex file extention +function(caffe_fetch_and_set_proper_mexext mexfile_variable) + execute_process(COMMAND ${Matlab_mexext} OUTPUT_STRIP_TRAILING_WHITESPACE RESULT_VARIABLE res OUTPUT_VARIABLE ext) + if(res MATCHES 0) + get_filename_component(folder ${${mexfile_variable}} PATH) + get_filename_component(name_we ${${mexfile_variable}} NAME_WE) + set(${mexfile_variable} ${folder}/${name_we}.${ext} PARENT_SCOPE) + endif() +endfunction() + +# global settings +file(GLOB Matlab_srcs caffe/matcaffe.cpp) +set(Matlab_caffe_mex ${CMAKE_SOURCE_DIR}/matlab/caffe/caffe.mex) + +caffe_get_current_cflags(cflags) +caffe_parse_linker_libs(Caffe_LINKER_LIBS folders libflags macos_framewoks) +set(folders $ ${folders}) + +# prepare linker flag lists +string(REPLACE ";" ";-L" link_folders "-L${folders}") +string(REPLACE ";" ":" rpath_folders "${folders}") + +if(build_using MATCHES "Matlab") + set(libflags -lcaffe${CAffe_POSTFIX} ${libflags}) # Matlab R2014a complans for -Wl,--whole-archive + + caffe_fetch_and_set_proper_mexext(Matlab_caffe_mex) + add_custom_command(OUTPUT ${Matlab_caffe_mex} COMMAND ${Matlab_mex} + ARGS -output ${Matlab_caffe_mex} ${Matlab_srcs} ${cflags} ${link_folders} ${libflags} + DEPENDS caffe COMMENT "Building Matlab interface: ${Matlab_caffe_mex}" VERBATIM) + add_custom_target(matlab ALL DEPENDS ${Matlab_caffe_mex} SOURCES ${Matlab_srcs}) + +elseif(build_using MATCHES "Octave") + + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set(libflags -Wl,-force_load,$ ${libflags}) + elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + set(libflags -Wl,--whole-archive -lcaffe${CAffe_POSTFIX} -Wl,--no-whole-archive ${libflags}) + endif() + + add_custom_command(OUTPUT ${Matlab_caffe_mex} COMMAND ${Octave_compiler} + ARGS --mex -o ${Matlab_caffe_mex} ${Matlab_srcs} ${cflags} ${link_folders} ${libflags} -Wl,-rpath,${rpath_folders} + DEPENDS caffe COMMENT "Building Octave interface: ${Matlab_caffe_mex}" VERBATIM) + + add_custom_target(octave ALL DEPENDS ${Matlab_caffe_mex} SOURCES ${Matlab_srcs}) +endif() + +# ---[ Install +file(GLOB mfiles caffe/*.m) +install(FILES ${mfiles} ${Matlab_caffe_mex} DESTINATION matlab) + diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 6470517d213..e943f691c49 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -1,58 +1,27 @@ -project( Python ) - -# Python -find_package(PythonLibs 2.7 REQUIRED) - -# Numpy -find_package(NumPy REQUIRED) - -# Boost.Python -find_package(Boost 1.46 COMPONENTS python REQUIRED) - - - -#In case you have both python2 and python3 installed the quickest way to -#compile pycaffe with cmake is to replace the following hardcoded paths. -#Althernativley the Find* scripts could be rewritten to support choice of -#of python version. -#if(${PYTHONLIBS_VERSION_STRING} MATCHES "^[3-9]+\\.[0-9]+(\\.[0-9]+.*)?$") -# -# set( PYTHON_INCLUDE_DIRS "/usr/include/python2.7") -# set( PYTHON_LIBRARIES "/usr/lib64/libpython2.7.so") -# set( NUMPY_INCLUDE_DIRS "/usr/lib64/python2.7/site-packages/numpy/core/include/") -# set( PYTHON_LIBRARIES "/usr/lib64/python2.7/site-packages/numpy/lib/") -# set(Boost_LIBRARIES "/usr/lib64/libboost_python-2.7-mt.so") -# -# message( "Warning: cmake found python3 by default, switching to hardcoded paths") -# -# message( "PYTHON_INCLUDE_DIRS =/usr/include/python2.7") -# message( "PYTHON_LIBRARIES =/usr/lib64/libpython2.7.so") -# message( "NUMPY_INCLUDE_DIRS =/usr/lib64/python2.7/site-packages/numpy/core/include/") -# message( "PYTHON_LIBRARIES =/usr/lib64/python2.7/site-packages/numpy/lib/") -# message( "Boost_LIBRARIES =/usr/lib64/libboost_python-2.7-mt.so") -#endif() - - -include_directories(${PYTHON_INCLUDE_DIRS} ${NUMPY_INCLUDE_DIRS} - ${Boost_INCLUDE_DIRS}) - -file(GLOB_RECURSE Python_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - -add_library(pycaffe SHARED ${Python_SOURCES}) - -add_dependencies(pycaffe protoPy) - -target_link_libraries(pycaffe ${CAFFE_STATIC_LINK} ${PYTHON_LIBRARIES} ${Boost_LIBRARIES}) - -set_target_properties(pycaffe PROPERTIES PREFIX "") -set_target_properties(pycaffe PROPERTIES OUTPUT_NAME "_caffe") - -### Install ############################################################# - +if(NOT HAVE_PYTHON) + message(STATUS "Python interface is disabled or not all required dependecies found. Building without it...") + return() +endif() + +include_directories(${PYTHON_INCLUDE_DIRS} ${NUMPY_INCLUDE_DIR} ${Boost_INCLUDE_DIRS}) +file(GLOB_RECURSE python_srcs ${CMAKE_SOURCE_DIR}/python/*.cpp) + +add_library(pycaffe SHARED ${python_srcs}) +target_link_libraries(pycaffe ${Caffe_LINK} ${PYTHON_LIBRARIES} ${Boost_LIBRARIES}) +set_target_properties(pycaffe PROPERTIES PREFIX "" OUTPUT_NAME "_caffe") +caffe_default_properties(pycaffe) + +if(UNIX OR APPLE) + set(__linkname "${CMAKE_SOURCE_DIR}/python/_caffe.so") + add_custom_command(TARGET pycaffe POST_BUILD + COMMAND ln -sf $ "${CMAKE_SOURCE_DIR}/python/_caffe.so" + COMMENT "Creating simlink ${__linkname} -> ${CMAKE_BINARY_DIR}/lib/_caffe${CAffe_POSTFIX}.so") +endif() + +# ---[ Install +file(GLOB files *.py requirements.txt) +install(FILES ${files} DESTINATION python) install(DIRECTORY caffe DESTINATION python) -install(FILES requirements.txt DESTINATION python) - -#This installs a library named "libpycaffe.so" install(TARGETS pycaffe DESTINATION python/caffe) diff --git a/src/caffe/CMakeLists.txt b/src/caffe/CMakeLists.txt index dda072688f8..ef74e1f004b 100644 --- a/src/caffe/CMakeLists.txt +++ b/src/caffe/CMakeLists.txt @@ -1,55 +1,36 @@ -project( CaffeSrc ) +# generate protobuf sources +file(GLOB proto_files proto/*.proto) +caffe_protobuf_generate_cpp_py(${proto_gen_folder} proto_srcs proto_hdrs proto_python ${proto_files}) +# include python files either to force generation +add_library(proto STATIC ${proto_hdrs} ${proto_srcs} ${proto_python}) +set(Caffe_LINKER_LIBS proto ${Caffe_LINKER_LIBS}) # note, crucial to prepend! +caffe_default_properties(proto) -add_subdirectory(proto) +# --[ Caffe library -# Recursively find source files -## test sources -file(GLOB_RECURSE TEST_CPP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_*.cpp) +# creates 'test_srcs', 'srcs', 'test_cuda', 'cuda' lists +caffe_pickup_caffe_sources(${CMAKE_SOURCE_DIR}) -## all cpp sources -file(GLOB_RECURSE CPP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +if(HAVE_CUDA) + caffe_cuda_compile(cuda_objs ${cuda}) + list(APPEND srcs ${cuda_objs} ${cuda}) +endif() -## remove test sources from cpp sources -list(REMOVE_ITEM CPP_SOURCES ${TEST_CPP_SOURCES}) +add_library(caffe ${srcs}) +target_link_libraries(caffe proto ${Caffe_LINKER_LIBS}) +caffe_default_properties(caffe) -add_library(caffe ${CPP_SOURCES}) -# both depend on proto -add_dependencies(caffe proto) +# ---[ Tests + add_subdirectory(test) + +# ---[ Install +install(DIRECTORY ${Caffe_INCLUDE_DIR}/caffe DESTINATION include) +install(FILES ${proto_hdrs} DESTINATION include/caffe/proto) +install(TARGETS caffe proto EXPORT CaffeTargets DESTINATION lib) + +file(WRITE ${CMAKE_BINARY_DIR}/__init__.py) +list(APPEND proto_python ${CMAKE_BINARY_DIR}/__init__.py) +install(PROGRAMS ${proto_python} DESTINATION python/caffe/proto) -# cuda sources -if(NOT CPU_ONLY) - file(GLOB_RECURSE CU_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cu) - file(GLOB_RECURSE TEST_CU_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_*.cu) - list(REMOVE_ITEM CU_SOURCES ${TEST_CU_SOURCES}) - cuda_add_library(caffe_cu ${CU_SOURCES}) - add_dependencies(caffe_cu proto) - target_link_libraries(caffe caffe_cu - ${CUDA_CUBLAS_LIBRARIES} - ${CUDA_curand_LIBRARY} - ) -endif() -target_link_libraries(caffe proto - ${BLAS_LIBRARIES} - ${Boost_LIBRARIES} - ${GFLAGS_LIBRARIES} - ${GLOG_LIBRARIES} - ${HDF5_LIBRARIES} - ${LEVELDB_LIBS} - ${LMDB_LIBRARIES} - ${OpenCV_LIBS} - ${CMAKE_THREAD_LIBS_INIT} -) - -#set output directory -set_target_properties(caffe PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib - LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib -) - -add_subdirectory(test) - -### Install ################################################################################# - -install(TARGETS caffe DESTINATION lib) diff --git a/src/caffe/proto/CMakeLists.txt b/src/caffe/proto/CMakeLists.txt deleted file mode 100644 index 12e7ce0a326..00000000000 --- a/src/caffe/proto/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -project( Proto ) - -# Google Protocol Buffers -find_package( Protobuf REQUIRED ) - -# As of Ubuntu 14.04 protoc is no longer a part of libprotobuf-dev package and should be installed -# separately as in: sudo apt-get install protobuf-compiler -if(PROTOBUF_PROTOC_EXECUTABLE) - message(STATUS "Found PROTOBUF Compiler: ${PROTOBUF_PROTOC_EXECUTABLE}") -else() - message(FATAL_ERROR "Could not find PROTOBUF Compiler") -endif() - -include_directories(${PROTOBUF_INCLUDE_DIR}) -file(GLOB ProtoFiles "${CMAKE_CURRENT_SOURCE_DIR}/*.proto") -PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders ${ProtoFiles}) -PROTOBUF_GENERATE_PYTHON(ProtoSourcesPy ${ProtoFiles}) - -add_custom_target(protoPy DEPENDS ${ProtoSourcesPy}) - -add_library(proto - ${ProtoSources} - ${ProtoHeaders} - ) - - -target_link_libraries(proto ${PROTOBUF_LIBRARIES}) - -# Create proto include directory -file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/include/caffe/proto) - -# Copy proto headers to include/caffe/proto/ -foreach(header ${ProtoHeaders}) - - ADD_CUSTOM_COMMAND(TARGET proto - COMMAND cmake -E copy ${header} - ${Caffe_INCLUDE_DIRS}/caffe/proto/ - DEPENDS ${header} -) - -endforeach(header) - -file(WRITE __init__.py) -install(PROGRAMS __init__.py DESTINATION python/caffe/proto) -install(PROGRAMS ${ProtoSourcesPy} DESTINATION python/caffe/proto) - diff --git a/src/caffe/test/CMakeLists.txt b/src/caffe/test/CMakeLists.txt index ce0aa4c5148..ed374e8e110 100644 --- a/src/caffe/test/CMakeLists.txt +++ b/src/caffe/test/CMakeLists.txt @@ -1,105 +1,36 @@ -# -# -# All test files' names must begin with a "test_" prefix -# -# -project( Test ) - -# Configuration -set(TEST_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/test) # test executables are going to be placed there -set(TEST_EXT .testbin) # test executable extension -set(ALL_TEST test${TEST_EXT}) # name of an executable comprising of all tests -set(RUN_TEST runtest) # dummy target for running tests -set(TEST_MAIN test_caffe_main.cpp) # main test file (with main function) - -# Generate config files -add_definitions(-DCMAKE_BUILD) # definition needed in order to include CMake's generated files -set(IN_EXT .in) # generator input file extension -set(GEN_EXT .gen.cmake) # generated output file extension -set(TEST_DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake_test_defines.hpp) -set(TEST_DATA_FILE ${CMAKE_CURRENT_SOURCE_DIR}/test_data/sample_data_list.txt) - -# Function prepares name of a test executable -# @output_name - output variable's name -# @filename - test_*.cpp file path -function(test_name output_name filename) - get_filename_component(name ${filename} NAME_WE) - set(${output_name} ${name}${TEST_EXT} PARENT_SCOPE) -endfunction() - -set(IN_FILES # generator input files - ${TEST_DEFINES_FILE} - ${TEST_DATA_FILE} -) - -foreach(in_file ${IN_FILES}) - configure_file( - ${in_file}${IN_EXT} - ${in_file}${GEN_EXT} - ) -endforeach() - -include_directories( - ${Caffe_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR} -) - -# Remove main from test sources and prepare an Object lib with main -file(GLOB TEST_MAIN ${TEST_MAIN}) -list(REMOVE_ITEM TEST_CPP_SOURCES ${TEST_MAIN}) -add_library(main_obj EXCLUDE_FROM_ALL OBJECT ${TEST_MAIN}) - -# Build each test separately from *.cpp files -foreach(source ${TEST_CPP_SOURCES}) - test_name(TEST_NAME ${source}) - - # - add_library(${TEST_NAME}.obj EXCLUDE_FROM_ALL OBJECT ${source}) - set(TEST_OBJ_LIB $) - - add_executable(${TEST_NAME} EXCLUDE_FROM_ALL ${TEST_OBJ_LIB} $) - target_link_libraries(${TEST_NAME} gtest ${CAFFE_STATIC_LINK}) - - # output dir - set_target_properties(${TEST_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/test) - - # Targets and object libs - set(TEST_TARGETS ${TEST_TARGETS} ${TEST_NAME}) - set(TEST_OBJ_LIBS ${TEST_OBJ_LIBS} ${TEST_OBJ_LIB}) -endforeach() - -# Build each test separately from *.cu files -foreach(source ${TEST_CU_SOURCES}) - test_name(TEST_NAME ${source}) - - cuda_add_library(${TEST_NAME}.lib EXCLUDE_FROM_ALL ${source}) - - add_executable(${TEST_NAME} EXCLUDE_FROM_ALL $) - target_link_libraries(${TEST_NAME} ${TEST_NAME}.lib gtest ${CAFFE_STATIC_LINK}) - - # output dir - set_target_properties(${TEST_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/test) - - # Targets and object libs - set(TEST_TARGETS ${TEST_TARGETS} ${TEST_NAME}) - set(TEST_CU_LIBS ${TEST_CU_LIBS} ${TEST_NAME}.lib) -endforeach() - -# Build a compound test excluded from the ALL target -add_executable(${ALL_TEST} EXCLUDE_FROM_ALL ${TEST_OBJ_LIBS} $) -if(NOT CPU_ONLY) - target_link_libraries(${ALL_TEST} ${TEST_CU_LIBS}) +# The option allows to include in build only selected test files and exclude all others +# Usage example: +# cmake -DBUILD_only_tests="common,net,blob,im2col_kernel" +set(BUILD_only_tests "" CACHE STRING "Blank or comma-separated list of test files to build without 'test_' prefix and extention") +caffe_leave_only_selected_tests(test_srcs ${BUILD_only_tests}) +caffe_leave_only_selected_tests(test_cuda ${BUILD_only_tests}) + +# For 'make runtest' target we don't need to embed test data paths to +# source files, because test target is executed in source directory +# That's why the lines below are commented. TODO: remove them + +# definition needed to include CMake generated files +#add_definitions(-DCMAKE_BUILD) + +# generates test_data/sample_data_list.txt.gen.cmake +#caffe_configure_testdatafile(test_data/sample_data_list.txt) + +set(the_target test.testbin) +set(test_args --gtest_shuffle) + +if(HAVE_CUDA) + caffe_cuda_compile(test_cuda_objs ${test_cuda}) + list(APPEND test_srcs ${test_cuda_objs} ${test_cuda}) +else() + list(APPEND test_args --gtest_filter="-*GPU*") endif() -target_link_libraries(${ALL_TEST} gtest ${CAFFE_STATIC_LINK}) -add_dependencies(${ALL_TEST} ${TEST_TARGETS}) -# Output directory -set_target_properties(${ALL_TEST} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${TEST_OUTPUT_DIRECTORY}) - -# Test command -set(TEST_ARGS --gtest_shuffle) -if(CPU_ONLY) - set(TEST_ARGS ${TEST_ARGS} --gtest_filter="-*GPU*") -endif() +# ---[ Adding test target +add_executable(${the_target} EXCLUDE_FROM_ALL ${test_srcs}) +target_link_libraries(${the_target} gtest ${Caffe_LINK}) +caffe_default_properties(${the_target}) +caffe_set_runtime_directory(${the_target} "${CMAKE_BINARY_DIR}/test") -add_custom_target(${RUN_TEST} COMMAND ${ALL_TEST} ${TEST_ARGS}) +# ---[ Adding runtest +add_custom_target(runtest COMMAND ${the_target} ${test_args} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) diff --git a/src/caffe/test/cmake_test_defines.hpp.in b/src/caffe/test/cmake_test_defines.hpp.in deleted file mode 100644 index 870eaf5c26e..00000000000 --- a/src/caffe/test/cmake_test_defines.hpp.in +++ /dev/null @@ -1,4 +0,0 @@ -#define CUDA_TEST_DEVICE @CUDA_TEST_DEVICE@ -#define CMAKE_SOURCE_DIR "@CMAKE_SOURCE_DIR@/src/" -#define EXAMPLES_SOURCE_DIR "@CMAKE_SOURCE_DIR@/examples/" -#define CMAKE_EXT ".gen.cmake" diff --git a/src/caffe/test/test_data/sample_data_list.txt.in b/src/caffe/test/test_data/sample_data_list.txt.in deleted file mode 100644 index 9860ef583ab..00000000000 --- a/src/caffe/test/test_data/sample_data_list.txt.in +++ /dev/null @@ -1,2 +0,0 @@ -@CMAKE_SOURCE_DIR@/src/caffe/test/test_data/sample_data.h5 -@CMAKE_SOURCE_DIR@/src/caffe/test/test_data/sample_data_2_gzip.h5 \ No newline at end of file diff --git a/src/gtest/CMakeLists.txt b/src/gtest/CMakeLists.txt index 82a4120ca3f..ef7ff7ed14b 100644 --- a/src/gtest/CMakeLists.txt +++ b/src/gtest/CMakeLists.txt @@ -1,6 +1,5 @@ -project(gtest CXX C) -cmake_minimum_required(VERSION 2.6.2) +add_library(gtest STATIC EXCLUDE_FROM_ALL gtest.h gtest-all.cpp) +caffe_default_properties(gtest) -add_library(gtest gtest-all.cpp) -add_library(gtest_main gtest_main.cc) -target_link_libraries(gtest_main gtest) \ No newline at end of file +#add_library(gtest_main gtest_main.cc) +#target_link_libraries(gtest_main gtest) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 110f368b2c8..4e43ba2cf25 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,20 +1,29 @@ -project( Tools ) - -# Find all source files -file(GLOB_RECURSE TOOLS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - - -# Build each source file independently -foreach(source ${TOOLS_SOURCES}) - get_filename_component(name ${source} NAME_WE) - add_executable(${name}.bin ${source}) - set_target_properties(${name}.bin PROPERTIES OUTPUT_NAME ${name}) - target_link_libraries(${name}.bin ${CAFFE_STATIC_LINK}) - -### Install ################################################################################# - - install(TARGETS ${name}.bin DESTINATION tools) - - +# Collect source files +file(GLOB_RECURSE srcs ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) + +# Build each source file independently +foreach(source ${srcs}) + get_filename_component(name ${source} NAME_WE) + + # caffe target already exits + if(name MATCHES "caffe") + set(name ${name}.bin) + endif() + + # target + add_executable(${name} ${source}) + target_link_libraries(${name} ${Caffe_LINK}) + caffe_default_properties(${name}) + + # set back RUNTIME_OUTPUT_DIRECTORY + caffe_set_runtime_directory(${name} "${CMAKE_BINARY_DIR}/tools") + caffe_set_solution_folder(${name} tools) + + # restore output name without suffix + if(name MATCHES "caffe.bin") + set_target_properties(${name} PROPERTIES OUTPUT_NAME caffe) + endif() + + # Install + install(TARGETS ${name} DESTINATION bin) endforeach(source) -