generic.cmake 13.6 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
#
15 16


Y
Yi Wang 已提交
17 18 19
# generic.cmake defines CMakes functions that look like Bazel's
# building rules (https://bazel.build/).
#
20
# 
L
liaogang 已提交
21
# -------------------------------------------
22
#     C++        CUDA C++       Go
L
liaogang 已提交
23
# -------------------------------------------
24 25 26
# cc_library    nv_library   go_library
# cc_binary     nv_binary    go_binary
# cc_test       nv_test      go_test
L
liaogang 已提交
27
# -------------------------------------------
28
# 
Y
Yi Wang 已提交
29 30
# To build a static library example.a from example.cc using the system
#  compiler (like GCC):
31 32 33
# 
#   cc_library(example SRCS example.cc)
# 
Y
Yi Wang 已提交
34 35
# To build a static library example.a from multiple source files
# example{1,2,3}.cc:
36 37 38 39 40 41 42
# 
#   cc_library(example SRCS example1.cc example2.cc example3.cc)
# 
# To build a shared library example.so from example.cc:
# 
#   cc_library(example SHARED SRCS example.cc)
# 
Y
Yi Wang 已提交
43 44
# To build a library using Nvidia's NVCC from .cu file(s), use the nv_
# prefixed version:
45 46 47 48 49 50 51 52 53 54 55
# 
#   nv_library(example SRCS example.cu)
# 
# To specify that a library new_example.a depends on other libraies:
# 
#   cc_library(new_example SRCS new_example.cc DEPS example)
# 
# Static libraries can be composed of other static libraries:
# 
#   cc_library(composed DEPS dependent1 dependent2 dependent3)
# 
Y
Yi Wang 已提交
56 57
# To build an executable binary file from some source files and
# dependent libraries:
58 59 60
# 
#   cc_binary(example SRCS main.cc something.cc DEPS example1 example2)
# 
Y
Yi Wang 已提交
61 62
# To build an executable binary file using NVCC, use the nv_ prefixed
# version:
63 64 65
# 
#   nv_binary(example SRCS main.cc something.cu DEPS example1 example2)
# 
Y
Yi Wang 已提交
66 67
# To build a unit test binary, which is an executable binary with
# GoogleTest linked:
68 69 70 71 72 73
# 
#   cc_test(example_test SRCS example_test.cc DEPS example)
# 
# To build a unit test binary using NVCC, use the nv_ prefixed version:
# 
#   nv_test(example_test SRCS example_test.cu DEPS example)
74
#
Y
Yi Wang 已提交
75 76 77
# It is pretty often that executable and test binaries depend on
# pre-defined external libaries like glog and gflags defined in
# /cmake/external/*.cmake:
78
#
79
#   cc_test(example_test SRCS example_test.cc DEPS example glog gflags)
L
liaogang 已提交
80 81 82 83 84 85 86 87 88
#
# To build a go static library using Golang, use the go_ prefixed version:
#
#   go_library(example STATIC)
#
# To build a go shared library using Golang, use the go_ prefixed version:
#
#   go_library(example SHARED)
#
L
liaogang 已提交
89

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

95
function(merge_static_libs TARGET_NAME)
L
liaogang 已提交
96 97
  set(libs ${ARGN})
  list(REMOVE_DUPLICATES libs)
98

L
liaogang 已提交
99 100 101 102 103 104 105
  # 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}>)
106 107 108 109 110 111 112 113 114 115 116 117 118
  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
L
liaogang 已提交
119 120 121
    foreach(lib ${libs})
      set(objlistfile ${lib}.objlist) # list of objects in the input library
      set(objdir ${lib}.objdir)
122

L
liaogang 已提交
123 124
      add_custom_command(OUTPUT ${objdir}
        COMMAND ${CMAKE_COMMAND} -E make_directory ${objdir})
125

L
liaogang 已提交
126 127 128 129 130
      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})
131

L
liaogang 已提交
132 133 134 135 136
      # 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})
137

L
liaogang 已提交
138 139
      list(APPEND mergebases "${mergebase}")
    endforeach()
140

L
liaogang 已提交
141 142 143
    # We need a target for the output merged library
    add_library(${TARGET_NAME} STATIC ${mergebases})
    set(outlibfile "$<TARGET_FILE:${TARGET_NAME}>")
144

L
liaogang 已提交
145 146 147 148 149
    foreach(lib ${libs})
    add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
      COMMAND ${CMAKE_AR} ru ${outlibfile} @"../${objlistfile}"
      WORKING_DIRECTORY ${objdir})
    endforeach()
150

L
liaogang 已提交
151 152 153
    add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
      COMMAND ${CMAKE_RANLIB} ${outlibfile})
  endif()
154 155
endfunction(merge_static_libs)

L
liaogang 已提交
156
function(cc_library TARGET_NAME)
157
  set(options STATIC static SHARED shared)
L
liaogang 已提交
158 159 160
  set(oneValueArgs "")
  set(multiValueArgs SRCS DEPS)
  cmake_parse_arguments(cc_library "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
  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 已提交
177 178
endfunction(cc_library)

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

L
liaogang 已提交
191
function(cc_test TARGET_NAME)
192 193 194 195 196 197
  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 已提交
198 199
    target_link_libraries(${TARGET_NAME} ${cc_test_DEPS} gtest gtest_main)
    add_dependencies(${TARGET_NAME} ${cc_test_DEPS} gtest gtest_main)
200
    add_test(${TARGET_NAME} ${TARGET_NAME})
L
liaogang 已提交
201
  endif()
L
liaogang 已提交
202
endfunction(cc_test)
L
liaogang 已提交
203 204

function(nv_library TARGET_NAME)
205
  if (WITH_GPU)
206
    set(options STATIC static SHARED shared)
207 208 209
    set(oneValueArgs "")
    set(multiValueArgs SRCS DEPS)
    cmake_parse_arguments(nv_library "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
    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)
226
  endif()
L
liaogang 已提交
227 228 229
endfunction(nv_library)

function(nv_binary TARGET_NAME)
230 231 232 233 234 235 236 237 238 239
  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 已提交
240
  endif()
L
liaogang 已提交
241 242 243
endfunction(nv_binary)

function(nv_test TARGET_NAME)
244 245 246 247 248 249
  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 已提交
250 251
    target_link_libraries(${TARGET_NAME} ${nv_test_DEPS} gtest gtest_main)
    add_dependencies(${TARGET_NAME} ${nv_test_DEPS} gtest gtest_main)
252
    add_test(${TARGET_NAME} ${TARGET_NAME})
L
liaogang 已提交
253
  endif()
L
liaogang 已提交
254
endfunction(nv_test)
L
liaogang 已提交
255 256 257

set(GOPATH "${CMAKE_CURRENT_BINARY_DIR}/go")
file(MAKE_DIRECTORY ${GOPATH})
258
set(PADDLE_IN_GOPATH "${GOPATH}/src/github.com/PaddlePaddle/Paddle")
L
liaogang 已提交
259 260

function(go_library TARGET_NAME)
L
liaogang 已提交
261
  set(options STATIC static SHARED shared)
L
liaogang 已提交
262
  set(oneValueArgs "")
L
liaogang 已提交
263
  set(multiValueArgs DEPS)
L
liaogang 已提交
264
  cmake_parse_arguments(go_library "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
L
liaogang 已提交
265 266

  if (go_library_SHARED OR go_library_shared)
L
liaogang 已提交
267
    set(BUILD_MODE "-buildmode=c-shared")
L
liaogang 已提交
268
    set(LIB_NAME "${CMAKE_SHARED_LIBRARY_PREFIX}${TARGET_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}")
L
liaogang 已提交
269 270
  else()
    set(BUILD_MODE "-buildmode=c-archive")
L
liaogang 已提交
271
    set(LIB_NAME "${CMAKE_STATIC_LIBRARY_PREFIX}${TARGET_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}")
L
liaogang 已提交
272
  endif()
L
liaogang 已提交
273

274
  # Add dummy code to support `make target_name` under Terminal Command
L
liaogang 已提交
275 276
  set(dummyfile ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}_dummy.c)
  file(WRITE ${dummyfile} "const char * dummy = \"${dummyfile}\";")
L
liaogang 已提交
277 278 279 280 281
  if (go_library_SHARED OR go_library_shared)
    add_library(${TARGET_NAME} SHARED ${dummyfile})
  else()
    add_library(${TARGET_NAME} STATIC ${dummyfile})
  endif()
282 283 284
  if(go_library_DEPS)
    add_dependencies(${TARGET_NAME} ${go_library_DEPS})
  endif(go_library_DEPS)
L
liaogang 已提交
285

286 287 288 289 290
  # we need to symlink Paddle directory into GOPATH. If we
  # don't do it and we have code that depends on Paddle, go
  # get ./... will download a new Paddle repo from Github,
  # without the changes in our current Paddle repo that we
  # want to build.
L
liaogang 已提交
291 292 293
  file(GLOB GO_SOURCE RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "*.go")
  add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
    COMMAND rm "${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}"
294 295 296 297 298
    # Symlink Paddle directory into GOPATH
    COMMAND mkdir -p ${PADDLE_IN_GOPATH}
    COMMAND rm -rf ${PADDLE_IN_GOPATH}                                                                                                                                         
    COMMAND ln -sf ${CMAKE_SOURCE_DIR} ${PADDLE_IN_GOPATH}
    # Automatically get all dependencies specified in the source code                                                                                                                                 
W
wuyi05 已提交
299
    COMMAND env GOPATH=${GOPATH} ${CMAKE_Go_COMPILER} get -d ./...
300
    # Golang build source code
L
liaogang 已提交
301 302
    COMMAND env GOPATH=${GOPATH} ${CMAKE_Go_COMPILER} build ${BUILD_MODE}
    -o "${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}"
L
liaogang 已提交
303
    ${GO_SOURCE}
304
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
L
liaogang 已提交
305 306 307 308 309 310 311 312 313 314 315
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}
316
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
317
  add_custom_target(${TARGET_NAME} ALL DEPENDS ${TARGET_NAME}_timestamp ${go_binary_DEPS})
L
liaogang 已提交
318 319 320 321 322 323 324 325 326 327 328 329
  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}
330
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
331
  add_custom_target(${TARGET_NAME} ALL DEPENDS ${TARGET_NAME}_timestamp ${go_test_DEPS})
L
liaogang 已提交
332 333
  add_test(${TARGET_NAME} ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME})
endfunction(go_test)
Y
Yu Yang 已提交
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366

function(pb_cc_library TARGET_NAME)
  set(oneValueArgs "")
  set(multiValueArgs SRCS)
  cmake_parse_arguments(pb_cc_library "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  set(proto_srcs)
  set(proto_hdrs)
  foreach(FIL ${pb_cc_library_SRCS})
    get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
    get_filename_component(FIL_WE ${FIL} NAME_WE)
    if(NOT PROTOBUF_GENERATE_CPP_APPEND_PATH)
      get_filename_component(FIL_DIR ${FIL} DIRECTORY)
      if(FIL_DIR)
        set(FIL_WE "${FIL_DIR}/${FIL_WE}")
      endif()
    endif()

    list(APPEND proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc")
    list(APPEND proto_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=${DLL_EXPORT_DECL}${CMAKE_CURRENT_BINARY_DIR}" "-I" ${CMAKE_CURRENT_SOURCE_DIR} ${ABS_FIL}
            DEPENDS ${ABS_FIL} protoc
            COMMENT "Running C++ protocol buffer compiler on ${FIL}"
            VERBATIM )
  endforeach()
  set_source_files_properties(${proto_srcs} ${proto_hdrs} PROPERTIES GENERATED TRUE)
  include_directories(${CMAKE_CURRENT_BINARY_DIR})
  cc_library(${TARGET_NAME} SRCS ${proto_srcs})
endfunction()