# Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
#
# 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
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# 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.
#
# generic.cmake defines CMakes functions that look like Bazel's
# building rules (https://bazel.build/).
#
#
# -------------------------------------------
# C++ CUDA C++ Go
# -------------------------------------------
# cc_library nv_library go_library
# cc_binary nv_binary go_binary
# cc_test nv_test go_test
# -------------------------------------------
#
# To build a static library example.a from example.cc using the system
# compiler (like GCC):
#
# cc_library(example SRCS example.cc)
#
# To build a static library example.a from multiple source files
# example{1,2,3}.cc:
#
# 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)
#
# To build a library using Nvidia's NVCC from .cu file(s), use the nv_
# prefixed version:
#
# 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)
#
# To build an executable binary file from some source files and
# dependent libraries:
#
# cc_binary(example SRCS main.cc something.cc DEPS example1 example2)
#
# To build an executable binary file using NVCC, use the nv_ prefixed
# version:
#
# nv_binary(example SRCS main.cc something.cu DEPS example1 example2)
#
# To build a unit test binary, which is an executable binary with
# GoogleTest linked:
#
# 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)
#
# It is pretty often that executable and test binaries depend on
# pre-defined external libaries like glog and gflags defined in
# /cmake/external/*.cmake:
#
# cc_test(example_test SRCS example_test.cc DEPS example glog gflags)
#
# 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)
#
# including binary directory for generated headers.
include_directories ( ${ CMAKE_CURRENT_BINARY_DIR } )
if ( NOT APPLE AND NOT ANDROID )
find_package ( Threads REQUIRED )
link_libraries ( ${ CMAKE_THREAD_LIBS_INIT } )
set ( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -ldl -lrt" )
endif ( NOT APPLE AND NOT ANDROID )
function ( merge_static_libs TARGET_NAME )
set ( libs ${ ARGN } )
list ( REMOVE_DUPLICATES libs )
# Get all propagation dependencies from the merged libraries
foreach ( lib ${ libs } )
list ( APPEND libs_deps ${ ${lib } _LIB_DEPENDS} )
endforeach ( )
list ( REMOVE_DUPLICATES libs_deps )
# To produce a library we need at least one source file.
# It is created by add_custom_command below and will helps
# also help to track dependencies.
set ( target_SRCS ${ CMAKE_CURRENT_BINARY_DIR } / ${ TARGET_NAME } _dummy.c )
if ( APPLE ) # Use OSX's libtool to merge archives
# Make the generated dummy source file depended on all static input
# libs. If input lib changes,the source file is touched
# which causes the desired effect (relink).
add_custom_command ( OUTPUT ${ target_SRCS }
C O M M A N D $ { C M A K E _ C O M M A N D } - E t o u c h $ { t a r g e t _ S R C S }
D E P E N D S $ { l i b s } )
# Generate dummy staic lib
file ( WRITE ${ target_SRCS } "const char *dummy = \" ${ target_SRCS } \";")
add_library ( ${ TARGET_NAME } STATIC ${ target_SRCS } )
target_link_libraries ( ${ TARGET_NAME } ${ libs_deps } )
foreach ( lib ${ libs } )
# Get the file names of the libraries to be merged
set ( libfiles ${ libfiles } $< TARGET_FILE:${lib} > )
endforeach ( )
add_custom_command ( TARGET ${ TARGET_NAME } POST_BUILD
C O M M A N D r m " $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } / l i b $ { T A R G E T _ N A M E } . a "
C O M M A N D / u s r / b i n / l i b t o o l - s t a t i c - o " $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } / l i b $ { T A R G E T _ N A M E } . a " $ { l i b f i l e s }
)
else ( ) # general UNIX: use "ar" to extract objects and re-add to a common lib
set ( target_DIR ${ CMAKE_CURRENT_BINARY_DIR } / ${ TARGET_NAME } .dir )
foreach ( lib ${ libs } )
set ( objlistfile ${ target_DIR } / ${ lib } .objlist ) # list of objects in the input library
set ( objdir ${ target_DIR } / ${ lib } .objdir )
add_custom_command ( OUTPUT ${ objdir }
C O M M A N D $ { C M A K E _ C O M M A N D } - E m a k e _ d i r e c t o r y $ { o b j d i r }
D E P E N D S $ { l i b } )
add_custom_command ( OUTPUT ${ objlistfile }
C O M M A N D $ { C M A K E _ A R } - x " $ < T A R G E T _ F I L E : $ { l i b } > "
C O M M A N D $ { C M A K E _ A R } - t " $ < T A R G E T _ F I L E : $ { l i b } > " > $ { o b j l i s t f i l e }
D E P E N D S $ { l i b } $ { o b j d i r }
W O R K I N G _ D I R E C T O R Y $ { o b j d i r } )
list ( APPEND target_OBJS "${objlistfile}" )
endforeach ( )
# Make the generated dummy source file depended on all static input
# libs. If input lib changes,the source file is touched
# which causes the desired effect (relink).
add_custom_command ( OUTPUT ${ target_SRCS }
C O M M A N D $ { C M A K E _ C O M M A N D } - E t o u c h $ { t a r g e t _ S R C S }
D E P E N D S $ { l i b s } $ { t a r g e t _ O B J S } )
# Generate dummy staic lib
file ( WRITE ${ target_SRCS } "const char *dummy = \" ${ target_SRCS } \";")
add_library ( ${ TARGET_NAME } STATIC ${ target_SRCS } )
target_link_libraries ( ${ TARGET_NAME } ${ libs_deps } )
# Get the file name of the generated library
set ( target_LIBNAME "$<TARGET_FILE:${TARGET_NAME}>" )
add_custom_command ( TARGET ${ TARGET_NAME } POST_BUILD
C O M M A N D $ { C M A K E _ A R } c r s $ { t a r g e t _ L I B N A M E } ` f i n d $ { t a r g e t _ D I R } - n a m e ' * . o ' `
C O M M A N D $ { C M A K E _ R A N L I B } $ { t a r g e t _ L I B N A M E }
W O R K I N G _ D I R E C T O R Y $ { t a r g e t _ D I R } )
endif ( )
endfunction ( merge_static_libs )
function ( cc_library TARGET_NAME )
set ( options STATIC static SHARED shared )
set ( oneValueArgs "" )
set ( multiValueArgs SRCS DEPS )
cmake_parse_arguments ( cc_library "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ ARGN } )
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 } )
target_link_libraries ( ${ TARGET_NAME } ${ cc_library_DEPS } )
endif ( )
# cpplint code style
foreach ( source_file ${ cc_library_SRCS } )
string ( REGEX REPLACE "\\.[^.]*$" "" source ${ source_file } )
if ( EXISTS ${ CMAKE_CURRENT_SOURCE_DIR } / ${ source } .h )
list ( APPEND cc_library_HEADERS ${ CMAKE_CURRENT_SOURCE_DIR } / ${ source } .h )
endif ( )
endforeach ( )
add_style_check_target ( ${ TARGET_NAME } ${ cc_library_SRCS } ${ cc_library_HEADERS } )
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 )
endfunction ( cc_library )
function ( cc_binary TARGET_NAME )
set ( options "" )
set ( oneValueArgs "" )
set ( multiValueArgs SRCS DEPS )
cmake_parse_arguments ( cc_binary "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ ARGN } )
add_executable ( ${ TARGET_NAME } ${ cc_binary_SRCS } )
if ( cc_binary_DEPS )
target_link_libraries ( ${ TARGET_NAME } ${ cc_binary_DEPS } )
add_dependencies ( ${ TARGET_NAME } ${ cc_binary_DEPS } )
endif ( )
endfunction ( cc_binary )
function ( cc_test TARGET_NAME )
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 } )
target_link_libraries ( ${ TARGET_NAME } ${ cc_test_DEPS } gtest gtest_main )
add_dependencies ( ${ TARGET_NAME } ${ cc_test_DEPS } gtest gtest_main )
add_test ( NAME ${ TARGET_NAME } COMMAND ${ TARGET_NAME } WORKING_DIRECTORY ${ CMAKE_CURRENT_SOURCE_DIR } )
endif ( )
endfunction ( cc_test )
function ( nv_library TARGET_NAME )
if ( WITH_GPU )
set ( options STATIC static SHARED shared )
set ( oneValueArgs "" )
set ( multiValueArgs SRCS DEPS )
cmake_parse_arguments ( nv_library "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ ARGN } )
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 } )
target_link_libraries ( ${ TARGET_NAME } ${ nv_library_DEPS } )
endif ( )
# cpplint code style
foreach ( source_file ${ nv_library_SRCS } )
string ( REGEX REPLACE "\\.[^.]*$" "" source ${ source_file } )
if ( EXISTS ${ CMAKE_CURRENT_SOURCE_DIR } / ${ source } .h )
list ( APPEND nv_library_HEADERS ${ CMAKE_CURRENT_SOURCE_DIR } / ${ source } .h )
endif ( )
endforeach ( )
add_style_check_target ( ${ TARGET_NAME } ${ nv_library_SRCS } ${ nv_library_HEADERS } )
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 )
endif ( )
endfunction ( nv_library )
function ( nv_binary TARGET_NAME )
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 ( )
endif ( )
endfunction ( nv_binary )
function ( nv_test TARGET_NAME )
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 } )
target_link_libraries ( ${ TARGET_NAME } ${ nv_test_DEPS } gtest gtest_main )
add_dependencies ( ${ TARGET_NAME } ${ nv_test_DEPS } gtest gtest_main )
add_test ( ${ TARGET_NAME } ${ TARGET_NAME } )
endif ( )
endfunction ( nv_test )
function ( go_library TARGET_NAME )
set ( options STATIC static SHARED shared )
set ( oneValueArgs "" )
set ( multiValueArgs DEPS )
cmake_parse_arguments ( go_library "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ ARGN } )
if ( go_library_SHARED OR go_library_shared )
set ( BUILD_MODE "-buildmode=c-shared" )
set ( ${ TARGET_NAME } _LIB_NAME "${CMAKE_SHARED_LIBRARY_PREFIX}${TARGET_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE STRING "output library name for target ${TARGET_NAME}" )
else ( )
set ( BUILD_MODE "-buildmode=c-archive" )
set ( ${ TARGET_NAME } _LIB_NAME "${CMAKE_STATIC_LIBRARY_PREFIX}${TARGET_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}" CACHE STRING "output library name for target ${TARGET_NAME}" )
endif ( )
set ( dummyfile ${ CMAKE_CURRENT_BINARY_DIR } / ${ TARGET_NAME } _dummy.c )
# This custom command will always run since it depends on a not
# existing file.
add_custom_command (
O U T P U T d u m m y _ r e b u l i d _ $ { T A R G E T _ N A M E }
C O M M A N D c m a k e - E t o u c h $ { d u m m y f i l e }
)
# Create a custom target that depends on the custom command output
# file, so the custom command can be referenced as a dependency by
# `add_dependencies`.
add_custom_target ( rebuild_ ${ TARGET_NAME }
D E P E N D S d u m m y _ r e b u l i d _ $ { T A R G E T _ N A M E }
)
# Add dummy code to support `make target_name` under Terminal Command
file ( WRITE ${ dummyfile } "const char * dummy = \" ${ dummyfile } \";")
if ( go_library_SHARED OR go_library_shared )
add_library ( ${ TARGET_NAME } SHARED ${ dummyfile } )
else ( )
add_library ( ${ TARGET_NAME } STATIC ${ dummyfile } )
endif ( )
if ( go_library_DEPS )
add_dependencies ( ${ TARGET_NAME } ${ go_library_DEPS } )
endif ( go_library_DEPS )
# The "source file" of the library is `${dummyfile}` which never
# change, so the target will never rebuild. Make the target depends
# on the custom command that touches the library "source file", so
# rebuild will always happen.
add_dependencies ( ${ TARGET_NAME } rebuild_ ${ TARGET_NAME } )
set ( ${ TARGET_NAME } _LIB_PATH "${CMAKE_CURRENT_BINARY_DIR}/${${TARGET_NAME}_LIB_NAME}" CACHE STRING "output library path for target ${TARGET_NAME}" )
file ( GLOB GO_SOURCE RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "*.go" )
string ( REPLACE "${PADDLE_GO_PATH}/" "" CMAKE_CURRENT_SOURCE_REL_DIR ${ CMAKE_CURRENT_SOURCE_DIR } )
add_custom_command ( TARGET ${ TARGET_NAME } POST_BUILD
C O M M A N D r m " $ { $ { T A R G E T _ N A M E } _ L I B _ P A T H } "
# Golang build source code
C O M M A N D G O P A T H = $ { G O P A T H } $ { C M A K E _ G o _ C O M P I L E R } b u i l d $ { B U I L D _ M O D E }
- o " $ { $ { T A R G E T _ N A M E } _ L I B _ P A T H } "
" . / $ { C M A K E _ C U R R E N T _ S O U R C E _ R E L _ D I R } / $ { G O _ S O U R C E } "
# must run under GOPATH
W O R K I N G _ D I R E C T O R Y " $ { P A D D L E _ I N _ G O P A T H } / g o " )
add_dependencies ( ${ TARGET_NAME } go_vendor )
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 } )
string ( REPLACE "${PADDLE_GO_PATH}/" "" CMAKE_CURRENT_SOURCE_REL_DIR ${ CMAKE_CURRENT_SOURCE_DIR } )
add_custom_command ( OUTPUT ${ TARGET_NAME } _timestamp
C O M M A N D e n v G O P A T H = $ { G O P A T H } $ { C M A K E _ G o _ C O M P I L E R } b u i l d
- o " $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } / $ { T A R G E T _ N A M E } "
" . / $ { C M A K E _ C U R R E N T _ S O U R C E _ R E L _ D I R } / $ { g o _ b i n a r y _ S R C S } "
W O R K I N G _ D I R E C T O R Y " $ { P A D D L E _ I N _ G O P A T H } / g o " )
add_custom_target ( ${ TARGET_NAME } ALL DEPENDS go_vendor ${ TARGET_NAME } _timestamp ${ go_binary_DEPS } )
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 DEPS )
cmake_parse_arguments ( go_test "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ ARGN } )
string ( REPLACE "${PADDLE_GO_PATH}" "" CMAKE_CURRENT_SOURCE_REL_DIR ${ CMAKE_CURRENT_SOURCE_DIR } )
add_custom_target ( ${ TARGET_NAME } ALL DEPENDS go_vendor ${ go_test_DEPS } )
add_custom_command ( TARGET ${ TARGET_NAME } POST_BUILD
C O M M A N D e n v G O P A T H = $ { G O P A T H } $ { C M A K E _ G o _ C O M P I L E R } t e s t - r a c e
- c - o " $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } / $ { T A R G E T _ N A M E } "
" . $ { C M A K E _ C U R R E N T _ S O U R C E _ R E L _ D I R } "
W O R K I N G _ D I R E C T O R Y " $ { P A D D L E _ I N _ G O P A T H } / g o " )
add_test ( NAME ${ TARGET_NAME }
C O M M A N D $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } / $ { T A R G E T _ N A M E }
W O R K I N G _ D I R E C T O R Y $ { C M A K E _ C U R R E N T _ S O U R C E _ D I R } )
endfunction ( go_test )
# Modification of standard 'protobuf_generate_cpp()' with protobuf-lite support
# Usage:
# paddle_protobuf_generate_cpp(<proto_srcs> <proto_hdrs> <proto_files>)
function ( paddle_protobuf_generate_cpp SRCS HDRS )
if ( NOT ARGN )
message ( SEND_ERROR "Error: paddle_protobuf_generate_cpp() called without any proto files" )
return ( )
endif ( )
set ( ${ SRCS } )
set ( ${ HDRS } )
if ( MOBILE_INFERENCE )
set ( EXTRA_FLAG "lite:" )
else ( )
set ( EXTRA_FLAG "" )
endif ( )
foreach ( FIL ${ ARGN } )
get_filename_component ( ABS_FIL ${ FIL } ABSOLUTE )
get_filename_component ( FIL_WE ${ FIL } NAME_WE )
set ( _protobuf_protoc_src "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc" )
set ( _protobuf_protoc_hdr "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h" )
list ( APPEND ${ SRCS } "${_protobuf_protoc_src}" )
list ( APPEND ${ HDRS } "${_protobuf_protoc_hdr}" )
add_custom_command (
O U T P U T " $ { _ p r o t o b u f _ p r o t o c _ s r c } "
" $ { _ p r o t o b u f _ p r o t o c _ h d r } "
C O M M A N D $ { C M A K E _ C O M M A N D } - E m a k e _ d i r e c t o r y " $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } "
C O M M A N D $ { P R O T O B U F _ P R O T O C _ E X E C U T A B L E }
- I $ { C M A K E _ C U R R E N T _ S O U R C E _ D I R }
- - c p p _ o u t " $ { E X T R A _ F L A G } $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } " $ { A B S _ F I L }
D E P E N D S $ { A B S _ F I L } p r o t o c
C O M M E N T " R u n n i n g C + + p r o t o c o l b u f f e r c o m p i l e r o n $ { F I L } "
V E R B A T I M )
endforeach ( )
set_source_files_properties ( ${ ${SRCS } } ${ ${HDRS } } PROPERTIES GENERATED TRUE )
set ( ${ SRCS } ${ ${SRCS } } PARENT_SCOPE )
set ( ${ HDRS } ${ ${HDRS } } PARENT_SCOPE )
endfunction ( )
function ( proto_library TARGET_NAME )
set ( oneValueArgs "" )
set ( multiValueArgs SRCS DEPS )
cmake_parse_arguments ( proto_library "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ ARGN } )
set ( proto_srcs )
set ( proto_hdrs )
paddle_protobuf_generate_cpp ( proto_srcs proto_hdrs ${ proto_library_SRCS } )
cc_library ( ${ TARGET_NAME } SRCS ${ proto_srcs } DEPS ${ proto_library_DEPS } protobuf )
endfunction ( )
function ( py_proto_compile TARGET_NAME )
set ( oneValueArgs "" )
set ( multiValueArgs SRCS )
cmake_parse_arguments ( py_proto_compile "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ ARGN } )
set ( py_srcs )
protobuf_generate_python ( py_srcs ${ py_proto_compile_SRCS } )
add_custom_target ( ${ TARGET_NAME } ALL DEPENDS ${ py_srcs } )
endfunction ( )
function ( py_test TARGET_NAME )
if ( WITH_TESTING )
set ( options STATIC static SHARED shared )
set ( oneValueArgs "" )
set ( multiValueArgs SRCS DEPS )
cmake_parse_arguments ( py_test "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ ARGN } )
add_test ( NAME ${ TARGET_NAME }
C O M M A N D e n v P Y T H O N P A T H = $ { P A D D L E _ P Y T H O N _ B U I L D _ D I R } / l i b - p y t h o n
p y t h o n 2 $ { p y _ t e s t _ S R C S }
W O R K I N G _ D I R E C T O R Y $ { C M A K E _ C U R R E N T _ S O U R C E _ D I R } )
endif ( )
endfunction ( )