Skip to content

Commit

Permalink
[wip] Cmake modernization (pytorch#2066)
Browse files Browse the repository at this point in the history
* cmake target - work in progress

* wip cmake public targets

* Add missing INTERFACE keyword

* Add cuda public dependencies

* Add dependency for test targets
  • Loading branch information
Yangqing authored Feb 28, 2018
1 parent 6341a0f commit 178c4be
Show file tree
Hide file tree
Showing 11 changed files with 156 additions and 149 deletions.
24 changes: 5 additions & 19 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,14 @@ enable_testing()

# ---[ Misc checks to cope with various compiler modes
include(cmake/MiscCheck.cmake)
include(cmake/BuildVariables.cmake)

# External projects
include(ExternalProject)

# TODO: merge the following 3 files into cmake/public/utils.cmake.
include(cmake/Utils.cmake)
include(cmake/public/utils.cmake)
include(cmake/Summary.cmake)

set(CAFFE2_WHITELIST "" CACHE STRING "A whitelist file of files that one should build.")
Expand Down Expand Up @@ -199,22 +202,6 @@ endif()

# ---[ Make configuration files for cmake to allow dependent libraries
# easier access to Caffe2.
# Since one would use glog, gflags, and protobuf functionalities, any
# dependent library will have to depend on glog, gflags, and protobuf
# as well, so we mark them as INTERFACE transitive dependency.
set(CAFFE2_INTERFACE_LIBS)
if (USE_GLOG)
list(APPEND CAFFE2_INTERFACE_LIBS glog::glog)
endif()
if (USE_GFLAGS)
list(APPEND CAFFE2_INTERFACE_LIBS gflags)
endif()
list(APPEND CAFFE2_INTERFACE_LIBS protobuf::libprotobuf)

# TODO: figure out how we should remove this public dependency.
if (USE_OPENCV)
list(APPEND CAFFE2_INTERFACE_LIBS ${OpenCV_LIBS})
endif()

if ((NOT USE_GLOG) OR (NOT USE_GFLAGS) OR BUILD_CUSTOM_PROTOBUF)
message(WARNING
Expand All @@ -223,12 +210,10 @@ if ((NOT USE_GLOG) OR (NOT USE_GFLAGS) OR BUILD_CUSTOM_PROTOBUF)
"generate files that are not well tested.")
endif()

target_link_libraries(caffe2 INTERFACE ${CAFFE2_INTERFACE_LIBS})
if (USE_CUDA)
# TODO: check if we should include other cuda dependency libraries
# to the interface as well.
target_link_libraries(caffe2_gpu INTERFACE
${CAFFE2_INTERFACE_LIBS} caffe2::cudart)

endif()

# Note(jiayq): when building static libraries, all PRIVATE dependencies
Expand Down Expand Up @@ -256,6 +241,7 @@ if (BUILD_SHARED_LIBS)
${PROJECT_SOURCE_DIR}/cmake/public/glog.cmake
${PROJECT_SOURCE_DIR}/cmake/public/gflags.cmake
${PROJECT_SOURCE_DIR}/cmake/public/protobuf.cmake
${PROJECT_SOURCE_DIR}/cmake/public/utils.cmake
DESTINATION share/cmake/Caffe2/public
COMPONENT dev)
install(EXPORT Caffe2Targets DESTINATION share/cmake/Caffe2
Expand Down
89 changes: 21 additions & 68 deletions caffe2/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
# ---[ Declare source file lists

# Caffe2_{CPU,GPU}_SRCS is the list that will have all the related source
# files for CPU and GPU respectively. They will be filled with the
# CMakeLists.txt files under each folder respectively.
set(Caffe2_CPU_SRCS)
set(Caffe2_GPU_SRCS)

# Caffe2_{CPU,GPU}_TEST_SRCS is the list that will have all the related source
# files for CPU and GPU tests respectively.
set(Caffe2_CPU_TEST_SRCS)
set(Caffe2_GPU_TEST_SRCS)

# ---[ Add respective subdirectories
# Note: the folders that are being commented out have not been properly
# addressed yet.
Expand Down Expand Up @@ -87,72 +76,39 @@ install(FILES ${PROJECT_BINARY_DIR}/caffe2/core/macros.h

# ---[ List of libraries to link with

# In the static linking + clang mode, cmake will fail to identify the build
# order because the lib becomes one single string -Wl,-force-load,libCaffe2_CPU.so
# As a result, we will create a Caffe2_MAIN_LIBS_ORDER variable simply to
# enforce the dependency.
set(Caffe2_MAIN_LIBS_ORDER)
set(Caffe2_MAIN_LIBS)

# Compile exposed libraries.
add_library(caffe2 ${Caffe2_CPU_SRCS} $<TARGET_OBJECTS:Caffe_PROTO> $<TARGET_OBJECTS:Caffe2_PROTO>)
if(USE_ACL)
# Check if 32-bit ARM: armv7, armv7-a, armv7l, etc
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^armv")
# Compilers for 32-bit ARM need extra flags to enable NEON-FP16
target_compile_options(caffe2 PRIVATE "-mfpu=neon-fp16")

include(CheckCCompilerFlag)
CHECK_C_COMPILER_FLAG(-mfp16-format=ieee CAFFE2_COMPILER_SUPPORTS_FP16_FORMAT)
if (CAFFE2_COMPILER_SUPPORTS_FP16_FORMAT)
target_compile_options(caffe2 PRIVATE "-mfp16-format=ieee")
endif()
endif()
endif()
target_link_libraries(caffe2 PUBLIC ${Caffe2_PUBLIC_DEPENDENCY_LIBS})
target_link_libraries(caffe2 PRIVATE ${Caffe2_DEPENDENCY_LIBS})
target_include_directories(caffe2 INTERFACE $<INSTALL_INTERFACE:include>)
target_compile_options(caffe2 INTERFACE "-std=c++11")
target_compile_options(caffe2 PRIVATE "-DCAFFE2_BUILD_MAIN_LIB")
install(TARGETS caffe2 EXPORT Caffe2Targets DESTINATION lib)
caffe_add_linker_flag(caffe2 Caffe2_CPU_LINK)
list(APPEND Caffe2_MAIN_LIBS_ORDER caffe2 Caffe2_PROTO)
list(APPEND Caffe2_MAIN_LIBS ${Caffe2_CPU_LINK})
caffe2_interface_library(caffe2 caffe2_library)
list(APPEND Caffe2_MAIN_LIBS caffe2_library)

# ---[ CUDA library.
if(USE_CUDA)
# A hack to deal with cuda library dependencies and modern CMake: the
# CUDA_ADD_LIBRARY includes a target_link_libraries, and as a result,
# one cannot use PUBLIC/PRIVATE/INTERFACE for the target anymore. This
# hack adds the PRIVATE keywords to CUDA_LIBRARIES so we can deal with
# it.

# it. We will then manually add the cudart library as interface libs.
set(__tmp ${CUDA_LIBRARIES})
set(CUDA_LIBRARIES PRIVATE ${CUDA_LIBRARIES})
CUDA_ADD_LIBRARY(caffe2_gpu ${Caffe2_GPU_SRCS})
set(CUDA_LIBRARIES ${__tmp})
target_link_libraries(caffe2_gpu INTERFACE caffe2::cudart)

target_include_directories(
caffe2_gpu INTERFACE $<INSTALL_INTERFACE:include>)
list(APPEND Caffe2_MAIN_LIBS_ORDER caffe2_gpu)
add_dependencies(caffe2_gpu Caffe2_PROTO)
if (BUILD_SHARED_LIBS)
target_link_libraries(
caffe2_gpu
PRIVATE
caffe2
${Caffe2_DEPENDENCY_LIBS}
${Caffe2_CUDA_DEPENDENCY_LIBS})
else()
target_link_libraries(
caffe2_gpu
PRIVATE
${Caffe2_DEPENDENCY_LIBS}
${Caffe2_CUDA_DEPENDENCY_LIBS})
endif()
caffe_add_linker_flag(caffe2_gpu Caffe2_GPU_LINK)
list(APPEND Caffe2_MAIN_LIBS_ORDER caffe2_gpu)
list(APPEND Caffe2_MAIN_LIBS ${Caffe2_GPU_LINK})
list(APPEND Caffe2_MAIN_LIBS_ORDER caffe2_gpu)
target_link_libraries(
caffe2_gpu PUBLIC caffe2 ${Caffe2_PUBLIC_CUDA_DEPENDENCY_LIBS})
target_link_libraries(
caffe2_gpu PRIVATE ${Caffe2_CUDA_DEPENDENCY_LIBS})
caffe2_interface_library(caffe2_gpu caffe2_gpu_library)
list(APPEND Caffe2_MAIN_LIBS caffe2_gpu_library)
install(TARGETS caffe2_gpu EXPORT Caffe2Targets DESTINATION lib)
endif()

Expand All @@ -166,15 +122,16 @@ if (BUILD_TEST)
foreach(test_src ${Caffe2_ALL_TEST_SRCS})
get_filename_component(test_name ${test_src} NAME_WE)
add_executable(${test_name} "${test_src}")
add_dependencies(${test_name} ${Caffe2_MAIN_LIBS_ORDER})
if (USE_CUDA)
target_link_libraries(
${test_name} ${Caffe2_MAIN_LIBS} ${Caffe2_DEPENDENCY_LIBS}
${Caffe2_CUDA_DEPENDENCY_LIBS} gtest_main)
else()
target_link_libraries(
# For tests, some of the test code actually directly call the dependent
# libraries even if they are not part of the public dependency libs. As a
# result, we will explicitly link the test against the Caffe2 dependency
# libs.
target_link_libraries(
${test_name} ${Caffe2_MAIN_LIBS} ${Caffe2_DEPENDENCY_LIBS}
gtest_main)
if (USE_CUDA)
target_link_libraries(
${test_name} ${Caffe2_CUDA_DEPENDENCY_LIBS})
endif()
if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.0)
target_compile_features(${test_name} PRIVATE cxx_range_for)
Expand Down Expand Up @@ -215,7 +172,6 @@ if (BUILD_PYTHON)
# ---[ Python.
add_library(caffe2_pybind11_state MODULE ${Caffe2_CPU_PYTHON_SRCS})
set_target_properties(caffe2_pybind11_state PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
add_dependencies(caffe2_pybind11_state ${Caffe2_MAIN_LIBS_ORDER})
set_target_properties(caffe2_pybind11_state PROPERTIES PREFIX "")
set_target_properties(caffe2_pybind11_state PROPERTIES SUFFIX ${PY_EXT_SUFFIX})
if (APPLE)
Expand All @@ -225,14 +181,12 @@ if (BUILD_PYTHON)
caffe2_pybind11_state PROPERTIES LIBRARY_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/caffe2/python)
target_link_libraries(
caffe2_pybind11_state ${Caffe2_CPU_LINK} ${Caffe2_DEPENDENCY_LIBS}
${Caffe2_PYTHON_DEPENDENCY_LIBS})
caffe2_pybind11_state caffe2_library)
install(TARGETS caffe2_pybind11_state DESTINATION "${PYTHON_LIB_REL_PATH}/caffe2/python")

if(USE_CUDA)
add_library(caffe2_pybind11_state_gpu MODULE ${Caffe2_GPU_PYTHON_SRCS})
set_target_properties(caffe2_pybind11_state_gpu PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
add_dependencies(caffe2_pybind11_state_gpu ${Caffe2_MAIN_LIBS_ORDER})
set_target_properties(caffe2_pybind11_state_gpu PROPERTIES PREFIX "")
set_target_properties(caffe2_pybind11_state_gpu PROPERTIES SUFFIX ${PY_EXT_SUFFIX})
if (APPLE)
Expand All @@ -242,8 +196,7 @@ if (BUILD_PYTHON)
caffe2_pybind11_state_gpu PROPERTIES LIBRARY_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/caffe2/python)
target_link_libraries(
caffe2_pybind11_state_gpu ${Caffe2_CPU_LINK} ${Caffe2_GPU_LINK} ${Caffe2_DEPENDENCY_LIBS}
${Caffe2_CUDA_DEPENDENCY_LIBS} ${Caffe2_PYTHON_DEPENDENCY_LIBS})
caffe2_pybind11_state_gpu caffe2_library caffe2_gpu_library)
install(TARGETS caffe2_pybind11_state_gpu DESTINATION "${PYTHON_LIB_REL_PATH}/caffe2/python")
endif()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
set(__target "caffe2_benchmark")
add_executable(${__target} "${CMAKE_CURRENT_SOURCE_DIR}/caffe2_benchmark.cc")
add_dependencies(${__target} ${Caffe2_MAIN_LIBS_ORDER})
caffe_add_linker_flag(Caffe2_CPU_OBSERVER Caffe2_CPU_OBSERVER_LINK)
target_link_libraries(${__target} ${Caffe2_CPU_OBSERVER_LINK} ${Caffe2_MAIN_LIBS} ${Caffe2_DEPENDENCY_LIBS})
install(TARGETS ${__target} DESTINATION bin)
31 changes: 31 additions & 0 deletions cmake/BuildVariables.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# ---[ Declare variables that we are going to use across the Caffe2 build.
# This file defines common, Caffe2-wide variables that we use to collect
# source files and other things. Each variable is annotated with their
# intended uses.
# Note that adding and / or deleting these variables usually involves
# changing the whole build system, so make sure you send a PR early if you
# want to change them.

# Caffe2_{CPU,GPU}_SRCS is the list that will have all the related source
# files for CPU and GPU respectively. They will be filled with the
# CMakeLists.txt files under each folder respectively.
set(Caffe2_CPU_SRCS)
set(Caffe2_GPU_SRCS)

# Caffe2_{CPU,GPU}_TEST_SRCS is the list that will have all the related source
# files for CPU and GPU tests respectively.
set(Caffe2_CPU_TEST_SRCS)
set(Caffe2_GPU_TEST_SRCS)

# Caffe2_MAIN_LIBS is a list of the libraries that a dependent library should
# depend on when it links against Caffe2.
set(Caffe2_MAIN_LIBS)

# Lists for Caffe2 dependency libraries, for CPU and CUDA respectively.
set(Caffe2_DEPENDENCY_LIBS "")
set(Caffe2_CUDA_DEPENDENCY_LIBS "")

# Lists for Caffe2 public dependency libraries. These libraries will be
# transitive to any libraries that depends on Caffe2.
set(Caffe2_PUBLIC_DEPENDENCY_LIBS "")
set(Caffe2_PUBLIC_CUDA_DEPENDENCY_LIBS "")
9 changes: 9 additions & 0 deletions cmake/Caffe2Config.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ set(CAFFE2_VERSION_MINOR @CAFFE2_VERSION_MINOR@)
set(CAFFE2_VERSION_PATCH @CAFFE2_VERSION_PATCH@)
set(CAFFE2_VERSION "@CAFFE2_VERSION@")

# Utils functions.
include("${CMAKE_CURRENT_LIST_DIR}/public/utils.cmake")

# Depending on whether Caffe2 uses gflags during compile time or
# not, invoke gflags.
if (@USE_GFLAGS@)
Expand Down Expand Up @@ -71,6 +74,12 @@ endif()
# import targets
include ("${CMAKE_CURRENT_LIST_DIR}/Caffe2Targets.cmake")

# Interface libraries, that allows one to build proper link flags.
caffe2_interface_library(caffe2 caffe2_library)
if (@USE_CUDA@)
caffe2_interface_library(caffe2_gpu caffe2_gpu_library)
endif()

# include directory.
#
# Newer versions of CMake set the INTERFACE_INCLUDE_DIRECTORIES property
Expand Down
40 changes: 26 additions & 14 deletions cmake/Dependencies.cmake
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
# This list is required for static linking and exported to Caffe2Config.cmake
set(Caffe2_DEPENDENCY_LIBS "")
set(Caffe2_CUDA_DEPENDENCY_LIBS "")
set(Caffe2_PYTHON_DEPENDENCY_LIBS "")

# ---[ Custom Protobuf
include("cmake/ProtoBuf.cmake")

Expand Down Expand Up @@ -46,21 +41,21 @@ if(BLAS STREQUAL "Eigen")
elseif(BLAS STREQUAL "ATLAS")
find_package(Atlas REQUIRED)
include_directories(${ATLAS_INCLUDE_DIRS})
list(APPEND Caffe2_DEPENDENCY_LIBS ${ATLAS_LIBRARIES})
list(APPEND Caffe2_DEPENDENCY_LIBS cblas)
list(APPEND Caffe2_PUBLIC_DEPENDENCY_LIBS ${ATLAS_LIBRARIES})
list(APPEND Caffe2_PUBLIC_DEPENDENCY_LIBS cblas)
elseif(BLAS STREQUAL "OpenBLAS")
find_package(OpenBLAS REQUIRED)
include_directories(${OpenBLAS_INCLUDE_DIR})
list(APPEND Caffe2_DEPENDENCY_LIBS ${OpenBLAS_LIB})
list(APPEND Caffe2_PUBLIC_DEPENDENCY_LIBS ${OpenBLAS_LIB})
elseif(BLAS STREQUAL "MKL")
find_package(MKL REQUIRED)
include_directories(${MKL_INCLUDE_DIR})
list(APPEND Caffe2_DEPENDENCY_LIBS ${MKL_LIBRARIES})
list(APPEND Caffe2_PUBLIC_DEPENDENCY_LIBS ${MKL_LIBRARIES})
set(CAFFE2_USE_MKL 1)
elseif(BLAS STREQUAL "vecLib")
find_package(vecLib REQUIRED)
include_directories(${vecLib_INCLUDE_DIR})
list(APPEND Caffe2_DEPENDENCY_LIBS ${vecLib_LINKER_LIBS})
list(APPEND Caffe2_PUBLIC_DEPENDENCY_LIBS ${vecLib_LINKER_LIBS})
else()
message(FATAL_ERROR "Unrecognized blas option:" ${BLAS})
endif()
Expand Down Expand Up @@ -99,7 +94,7 @@ if(USE_GFLAGS)
include(cmake/public/gflags.cmake)
if (TARGET gflags)
set(CAFFE2_USE_GFLAGS 1)
list(APPEND Caffe2_DEPENDENCY_LIBS gflags)
list(APPEND Caffe2_PUBLIC_DEPENDENCY_LIBS gflags)
else()
message(WARNING
"gflags is not found. Caffe2 will build without gflags support but "
Expand All @@ -114,7 +109,7 @@ if(USE_GLOG)
include(cmake/public/glog.cmake)
if (TARGET glog::glog)
set(CAFFE2_USE_GOOGLE_GLOG 1)
list(APPEND Caffe2_DEPENDENCY_LIBS glog::glog)
list(APPEND Caffe2_PUBLIC_DEPENDENCY_LIBS glog::glog)
else()
message(WARNING
"glog is not found. Caffe2 will build without glog support but it is "
Expand Down Expand Up @@ -340,7 +335,14 @@ endif()
# ---[ CUDA
if(USE_CUDA)
include(cmake/public/cuda.cmake)
if(NOT CAFFE2_FOUND_CUDA)
if(CAFFE2_FOUND_CUDA)
# A helper variable recording the list of Caffe2 dependent librareis
# caffe2::cuda is dealt with separately, due to CUDA_ADD_LIBRARY
# design reason (it adds CUDA_LIBRARIES itself).
set(Caffe2_PUBLIC_CUDA_DEPENDENCY_LIBS
caffe2::cudart caffe2::curand
caffe2::cublas caffe2::cudnn caffe2::nvrtc)
else()
message(WARNING
"Not compiling with CUDA. Suppress this warning with "
"-DUSE_CUDA=OFF.")
Expand Down Expand Up @@ -439,6 +441,7 @@ if (USE_MOBILE_OPENGL)
endif()
endif()

# ---[ ARM Compute Library: check compatibility.
if (USE_ACL)
if (NOT ANDROID)
message(WARNING "ARM Compute Library is only supported for Android builds.")
Expand All @@ -447,6 +450,15 @@ if (USE_ACL)
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^armv")
# 32-bit ARM (armv7, armv7-a, armv7l, etc)
set(ACL_ARCH "armv7a")
# Compilers for 32-bit ARM need extra flags to enable NEON-FP16
add_definitions("-mfpu=neon-fp16")

include(CheckCCompilerFlag)
CHECK_C_COMPILER_FLAG(
-mfp16-format=ieee CAFFE2_COMPILER_SUPPORTS_FP16_FORMAT)
if (CAFFE2_COMPILER_SUPPORTS_FP16_FORMAT)
add_definitions("-mfp16-format=ieee")
endif()
elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)$")
# 64-bit ARM
set(ACL_ARCH "arm64-v8a")
Expand All @@ -457,7 +469,7 @@ if (USE_ACL)
endif()
endif()

# ---[ ARM Compute Library
# ---[ ARM Compute Library: build the target.
if (USE_ACL)
list(APPEND ARM_COMPUTE_INCLUDE_DIRS "third_party/ComputeLibrary/")
list(APPEND ARM_COMPUTE_INCLUDE_DIRS "third_party/ComputeLibrary/include")
Expand Down
Loading

0 comments on commit 178c4be

Please sign in to comment.