generic.cmake 11.5 KB
Newer Older
L
liaogang 已提交
1
# Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
2
#
L
liaogang 已提交
3 4 5
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
6
#
L
liaogang 已提交
7
# http://www.apache.org/licenses/LICENSE-2.0
8
#
L
liaogang 已提交
9 10 11 12 13
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
14
#
L
liaogang 已提交
15 16 17
# To simplify the build process of PaddlePaddle, we defined couple of
# fundamental abstractions, e.g., how to build library, binary and
# test in C++, CUDA and Go.
18
#
L
liaogang 已提交
19
# -------------------------------------------
20
#     C++        CUDA C++       Go
L
liaogang 已提交
21
# -------------------------------------------
22 23 24
# cc_library    nv_library   go_library
# cc_binary     nv_binary    go_binary
# cc_test       nv_test      go_test
L
liaogang 已提交
25 26 27 28
# -------------------------------------------
#
# cmake_parse_arguments can help us to achieve this goal.
# https://cmake.org/cmake/help/v3.0/module/CMakeParseArguments.html
L
liaogang 已提交
29
#
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
# cc_library|nv_library(<target_name> [STATIC SHARED] SRCS <file>... DEPS <libs>...)
#
# cc_library and nv_library can generate *.a, or *.so
# if the corresponding keyword STATIC or SHARED is specified.
#
# cc_binary|nv_binary(<target_name> SRCS <file>... DEPS <libs>...)
#
# cc_binary and nv_binary can build souce code and link the dependent
# libraries to generate a binary.
#
# cc_test|nv_test(<target_name> SRCS <file>... DEPS <libs>...)
#
# cc_test and nv_test can build test code, link gtest and other dependent
# libraries to generate test suite.
#
# For example, in one folder, it contains
#   ddim{.h, .cc, _test.cc, _test.cu}
#   place{.h, cc, _test.cc}
#
# We can add build script as follows: 
# 
# cc_library(place STATIC SRCS place.cc)
#
# place.cc -> place.a
# cc_library's STATIC OPTION will generate libplace.a.
#
# cc_test(place_test
#    SRCS place_test.cc
#    DEPS place glog gflags)
#
# place_test.cc, place, glog, gflags -> place_test
# cc_test will combine place_test.cc, libplace.a with libglog.a.
# and libgflags.a to generate place_test.
#
# cc_library(ddim STATIC SRCS ddim.cc)
#
# ddim.cc -> ddim.a
# cc_library's STATIC OPTION will generate libddim.a.
#
# cc_test(ddim_test
#    SRCS ddim_test.cc
#    DEPS ddim)
#
# ddim_test.cc, ddim.a -> ddim_test
# cc_test will build ddim_test.cc with libddim.a to generate ddim_test.
#
# nv_test(dim_test
#    SRCS dim_test.cu
#    DEPS ddim)
#
# dim_test.cu, ddim.a -> dim_test
# nv_test will build dim_test.cu with libddim.a to generate dim_test.
#
# cc_library(framework DEPS place ddim)
#
# place.a, ddim.a -> framework.a
# If no SRCS exists, merging libplace.a and libddim.a to generate libframework.a.
#
L
liaogang 已提交
88

L
liaogang 已提交
89 90 91 92
if(NOT APPLE)
    find_package(Threads REQUIRED)
    link_libraries(${CMAKE_THREAD_LIBS_INIT})
endif(NOT APPLE)
93

94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
function(merge_static_libs TARGET_NAME)
	set(libs ${ARGN})
	list(REMOVE_DUPLICATES libs)

	# First get the file names of the libraries to be merged
	foreach(lib ${libs})
		get_target_property(libtype ${lib} TYPE)
		if(NOT libtype STREQUAL "STATIC_LIBRARY")
			message(FATAL_ERROR "merge_static_libs can only process static libraries")
		endif()
		set(libfiles ${libfiles} $<TARGET_FILE:${lib}>)
  endforeach()

  if(APPLE) # Use OSX's libtool to merge archives
    add_custom_target(${TARGET_NAME}_archive
      COMMAND libtool -static -o "${CMAKE_CURRENT_BINARY_DIR}/lib${TARGET_NAME}.a" ${libfiles}
      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
      DEPENDS ${libs}
      )
    add_library(${TARGET_NAME} STATIC IMPORTED GLOBAL)
    set_property(TARGET ${TARGET_NAME} PROPERTY
      IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/lib${TARGET_NAME}.a")
    add_dependencies(${TARGET_NAME} ${TARGET_NAME}_archive)
	else() # general UNIX: use "ar" to extract objects and re-add to a common lib
		foreach(lib ${libs})
			set(objlistfile ${lib}.objlist) # list of objects in the input library
			set(objdir ${lib}.objdir)

			add_custom_command(OUTPUT ${objdir}
					COMMAND ${CMAKE_COMMAND} -E make_directory ${objdir})

			add_custom_command(OUTPUT ${objlistfile}
					COMMAND ${CMAKE_AR} -x "$<TARGET_FILE:${lib}>"
					COMMAND ${CMAKE_AR} -t "$<TARGET_FILE:${lib}>" > ../${objlistfile}
					DEPENDS ${lib} ${objdir}
					WORKING_DIRECTORY ${objdir})

			# Empty dummy source file that goes into merged library
			set(mergebase ${lib}.mergebase.c)
			add_custom_command(OUTPUT ${mergebase}
					COMMAND ${CMAKE_COMMAND} -E touch ${mergebase}
					DEPENDS ${objlistfile})

			list(APPEND mergebases "${mergebase}")
		endforeach()

		# We need a target for the output merged library
		add_library(${TARGET_NAME} STATIC ${mergebases})
		set(outlibfile "$<TARGET_FILE:${TARGET_NAME}>")

		foreach(lib ${libs})
			add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
					COMMAND ${CMAKE_AR} ru ${outlibfile} @"../${objlistfile}"
					WORKING_DIRECTORY ${objdir})
		endforeach()

		add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
				COMMAND ${CMAKE_RANLIB} ${outlibfile})
	endif()
endfunction(merge_static_libs)

L
liaogang 已提交
155
function(cc_library TARGET_NAME)
156
  set(options STATIC static SHARED shared)
L
liaogang 已提交
157 158 159
  set(oneValueArgs "")
  set(multiValueArgs SRCS DEPS)
  cmake_parse_arguments(cc_library "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
  if (cc_library_SRCS)
    if (cc_library_SHARED OR cc_library_shared) # build *.so
      add_library(${TARGET_NAME} SHARED ${cc_library_SRCS})
    else()
      add_library(${TARGET_NAME} STATIC ${cc_library_SRCS})
    endif()
    if (cc_library_DEPS)
      add_dependencies(${TARGET_NAME} ${cc_library_DEPS})
    endif()
  else(cc_library_SRCS)
    if (cc_library_DEPS)
      merge_static_libs(${TARGET_NAME} ${cc_library_DEPS})
    else()
      message(FATAL "Please specify source file or library in cc_library.")
    endif()
  endif(cc_library_SRCS)
L
liaogang 已提交
176 177
endfunction(cc_library)

L
liaogang 已提交
178
function(cc_binary TARGET_NAME)
179
  set(options "")
L
liaogang 已提交
180 181 182 183
  set(oneValueArgs "")
  set(multiValueArgs SRCS DEPS)
  cmake_parse_arguments(cc_binary "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  add_executable(${TARGET_NAME} ${cc_binary_SRCS})
184
  if(cc_binary_DEPS)
L
liaogang 已提交
185 186 187
    target_link_libraries(${TARGET_NAME} ${cc_binary_DEPS})
    add_dependencies(${TARGET_NAME} ${cc_binary_DEPS})
  endif()
L
liaogang 已提交
188 189
endfunction(cc_binary)

L
liaogang 已提交
190
function(cc_test TARGET_NAME)
191 192 193 194 195 196
  if(WITH_TESTING)
    set(options "")
    set(oneValueArgs "")
    set(multiValueArgs SRCS DEPS)
    cmake_parse_arguments(cc_test "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
    add_executable(${TARGET_NAME} ${cc_test_SRCS})
L
liaogang 已提交
197 198
    target_link_libraries(${TARGET_NAME} ${cc_test_DEPS} gtest gtest_main)
    add_dependencies(${TARGET_NAME} ${cc_test_DEPS} gtest gtest_main)
199
    add_test(${TARGET_NAME} ${TARGET_NAME})
L
liaogang 已提交
200
  endif()
L
liaogang 已提交
201
endfunction(cc_test)
L
liaogang 已提交
202 203

function(nv_library TARGET_NAME)
204
  if (WITH_GPU)
205
    set(options STATIC static SHARED shared)
206 207 208
    set(oneValueArgs "")
    set(multiValueArgs SRCS DEPS)
    cmake_parse_arguments(nv_library "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
    if(nv_library_SRCS)
      if (nv_library_SHARED OR nv_library_shared) # build *.so
        cuda_add_library(${TARGET_NAME} SHARED ${nv_library_SRCS})
      else()
          cuda_add_library(${TARGET_NAME} STATIC ${nv_library_SRCS})
      endif()
      if (nv_library_DEPS)
        add_dependencies(${TARGET_NAME} ${nv_library_DEPS})
      endif()
    else(nv_library_SRCS)
      if (nv_library_DEPS)
        merge_static_libs(${TARGET_NAME} ${nv_library_DEPS})
      else()
        message(FATAL "Please specify source file or library in nv_library.")
      endif()
    endif(nv_library_SRCS)
225
  endif()
L
liaogang 已提交
226 227 228
endfunction(nv_library)

function(nv_binary TARGET_NAME)
229 230 231 232 233 234 235 236 237 238
  if (WITH_GPU)
    set(options "")
    set(oneValueArgs "")
    set(multiValueArgs SRCS DEPS)
    cmake_parse_arguments(nv_binary "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
    cuda_add_executable(${TARGET_NAME} ${nv_binary_SRCS})
    if(nv_binary_DEPS)
      target_link_libraries(${TARGET_NAME} ${nv_binary_DEPS})
      add_dependencies(${TARGET_NAME} ${nv_binary_DEPS})
    endif()
L
liaogang 已提交
239
  endif()
L
liaogang 已提交
240 241 242
endfunction(nv_binary)

function(nv_test TARGET_NAME)
243 244 245 246 247 248
  if (WITH_GPU AND WITH_TESTING)
    set(options "")
    set(oneValueArgs "")
    set(multiValueArgs SRCS DEPS)
    cmake_parse_arguments(nv_test "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
    cuda_add_executable(${TARGET_NAME} ${nv_test_SRCS})
L
liaogang 已提交
249 250
    target_link_libraries(${TARGET_NAME} ${nv_test_DEPS} gtest gtest_main)
    add_dependencies(${TARGET_NAME} ${nv_test_DEPS} gtest gtest_main)
251
    add_test(${TARGET_NAME} ${TARGET_NAME})
L
liaogang 已提交
252
  endif()
L
liaogang 已提交
253
endfunction(nv_test)
L
liaogang 已提交
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277

set(GOPATH "${CMAKE_CURRENT_BINARY_DIR}/go")
file(MAKE_DIRECTORY ${GOPATH})

# Because api.go defines a GO wrapper to ops and tensor, it depends on
# both.  This implies that if any of tensor.{h,cc}, ops.{h,cu}, or
# api.go is changed, api need to be re-built.
# go_library(api
#   SRCS
#   api.go
#   DEPS
#   tensor # Because ops depend on tensor, this line is optional.
#   ops)
function(go_library TARGET_NAME)
  set(options OPTIONAL)
  set(oneValueArgs "")
  set(multiValueArgs SRCS DEPS)
  cmake_parse_arguments(go_library "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  if (${go_library_OPTIONAL} STREQUAL "SHARED")
    set(BUILD_MODE "-buildmode=c-shared")
    if(APPLE)
      set(LIB_NAME "lib${TARGET_NAME}.dylib")
    else()
      set(LIB_NAME "lib${TARGET_NAME}.so")
278
    endif()
L
liaogang 已提交
279 280 281 282 283 284 285 286
  else()
    set(BUILD_MODE "-buildmode=c-archive")
    set(LIB_NAME "lib${TARGET_NAME}.a")
  endif()
  add_custom_command(OUTPUT ${TARGET_NAME}_timestamp
    COMMAND env GOPATH=${GOPATH} ${CMAKE_Go_COMPILER} build ${BUILD_MODE}
    -o "${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}"
    ${go_library_SRCS}
287
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
L
liaogang 已提交
288 289
  add_custom_target(${TARGET_NAME}_lib ALL DEPENDS ${TARGET_NAME}_timestamp ${go_library_DEPS})
  add_library(${TARGET_NAME} STATIC IMPORTED)
L
liaogang 已提交
290 291 292
  set_property(TARGET ${TARGET_NAME} PROPERTY
    IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}")
  add_dependencies(${TARGET_NAME} ${TARGET_NAME}_lib)
L
liaogang 已提交
293 294 295 296 297 298 299 300 301 302 303
endfunction(go_library)

function(go_binary TARGET_NAME)
  set(options OPTIONAL)
  set(oneValueArgs "")
  set(multiValueArgs SRCS DEPS)
  cmake_parse_arguments(go_binary "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  add_custom_command(OUTPUT ${TARGET_NAME}_timestamp
    COMMAND env GOPATH=${GOPATH} ${CMAKE_Go_COMPILER} build
    -o "${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}"
    ${go_library_SRCS}
304
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
305
  add_custom_target(${TARGET_NAME} ALL DEPENDS ${TARGET_NAME}_timestamp ${go_binary_DEPS})
L
liaogang 已提交
306 307 308 309 310 311 312 313 314 315 316 317
  install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME} DESTINATION bin)
endfunction(go_binary)

function(go_test TARGET_NAME)
  set(options OPTIONAL)
  set(oneValueArgs "")
  set(multiValueArgs SRCS DEPS)
  cmake_parse_arguments(go_test "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  add_custom_command(OUTPUT ${TARGET_NAME}_timestamp
    COMMAND env GOPATH=${GOPATH} ${CMAKE_Go_COMPILER} test
    -c -o "${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}"
    ${go_test_SRCS}
318
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
319
  add_custom_target(${TARGET_NAME} ALL DEPENDS ${TARGET_NAME}_timestamp ${go_test_DEPS})
L
liaogang 已提交
320 321
  add_test(${TARGET_NAME} ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME})
endfunction(go_test)
L
liaogang 已提交
322 323 324 325 326 327 328

# go_extern will download extern go project.
# go_extern(target_name extern_source)
# go_extern(go_redis github.com/hoisie/redis)
function(go_extern TARGET_NAME)
  add_custom_target(${TARGET_NAME} env GOPATH=${GOPATH} ${CMAKE_Go_COMPILER} get ${ARGN})
endfunction(go_extern)