Something went wrong on our end
-
Rafal Gumienny authoredRafal Gumienny authored
OST.cmake 38.89 KiB
#-------------------------------------------------------------------------------
# Authors: Marco Biasini, Juergen Haas, Andreas Schenk
#
# This file contains a bunch of useful macros to facilitate the build-system
# configuration for the modules.
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# map macro
#
# this function emulates a map/dict data type
#-------------------------------------------------------------------------------
function(map COMMAND MAPNAME)
set (_KEYS ${MAPNAME}_MAP_KEYS )
set (_VALUES ${MAPNAME}_MAP_VALUES)
if(${COMMAND} STREQUAL SET)
list(REMOVE_AT ARGN 0)
list(FIND ${_KEYS} ${ARGV2} _MAP_INDEX)
if(_MAP_INDEX EQUAL -1)
list(APPEND ${_KEYS} ${ARGV2})
set(${_KEYS} ${${_KEYS}} PARENT_SCOPE)
set(${_VALUES}_${ARGV2} ${ARGN} PARENT_SCOPE)
else()
set(${_VALUES}_${ARGV2} ${ARGN} PARENT_SCOPE)
endif()
elseif(${COMMAND} STREQUAL GET)
list(FIND ${_KEYS} ${ARGV2} _MAP_INDEX)
if(_MAP_INDEX EQUAL -1)
MESSAGE(FATAL_ERROR "Unknown key: " ${ARGV2})
endif()
set(${ARGV3} ${${_VALUES}_${ARGV2}} PARENT_SCOPE)
elseif(${COMMAND} STREQUAL KEYS)
set(${ARGV2} ${${_KEYS}} PARENT_SCOPE)
elseif(${COMMAND} STREQUAL CREATE)
set(${_KEYS} "" PARENT_SCOPE)
elseif(${COMMAND} STREQUAL LENGTH)
list(LENGTH ${_KEYS} _L)
set(${ARGV2} ${_L} PARENT_SCOPE)
else()
MESSAGE(FATAL_ERROR "Unknown map command:" ${COMMAND})
endif()
endfunction()
#-------------------------------------------------------------------------------
# check_architecture
#
# detect architecture based on void pointer size. the output is stored in the
# 3 variables OS_32_BITS, OS_64_BITS and CMAKE_NATIVE_ARCH. The former two are
# set to 0 and 1 accordingly and CMAKE_NATIVE_ARCH is set to the 32 or 64 bit.
#-------------------------------------------------------------------------------
macro(check_architecture)
include(CheckTypeSize)
check_type_size(void* SIZEOF_VOID_PTR)
if(${SIZEOF_VOID_PTR} MATCHES "^8$")
set(OS_32_BITS 0)
set(OS_64_BITS 1)
set(CMAKE_NATIVE_ARCH 64)
else()
set(OS_32_BITS 1)
set(OS_64_BITS 0)
set(CMAKE_NATIVE_ARCH 32)
endif()
endmacro()
#-------------------------------------------------------------------------------
# this macro has been adapted from
# http://www.cmake.org/Wiki/CMakeMacroParseArguments
#-------------------------------------------------------------------------------
macro(parse_argument_list PREFIX ARG_NAMES OPT_NAMES)
set(_DEFAULT_ARGS)
# reset variables
foreach(${_ARG_NAME} ${ARG_NAMES})
set(PREFIX_${_ARG_NAME})
endforeach()
foreach(_OPT_NAME ${OPT_NAMES})
set(PREFIX_${_OPT_NAME} FALSE)
endforeach()
set(_CURR_ARG_NAME DEF_ARGS)
set(_CURR_ARG_LIST)
# loop over parameter list and split by ARG_NAMES
foreach(_ARG ${ARGN})
set(_LARG_NAMES ${ARG_NAMES})
list(FIND _LARG_NAMES ${_ARG} _IS_ARG_NAME)
if (_IS_ARG_NAME GREATER -1)
set(${PREFIX}_${_CURR_ARG_NAME} ${_CURR_ARG_LIST})
set(_CURR_ARG_NAME "${_ARG}")
set(_CURR_ARG_LIST)
else()
set(_LOPT_NAMES ${OPT_NAMES})
list(FIND _LOPT_NAMES ${_ARG} _IS_OPT_NAME)
if (_IS_OPT_NAME GREATER -1)
set(${PREFIX}_${_ARG} TRUE)
else()
list(APPEND _CURR_ARG_LIST "${_ARG}")
endif()
endif()
endforeach()
set(${PREFIX}_${_CURR_ARG_NAME} ${_CURR_ARG_LIST})
endmacro()
#-------------------------------------------------------------------------------
# copy_if_different
#
# copies file from source directory to destination directory, but only if its
# content changed.
#-------------------------------------------------------------------------------
macro(copy_if_different FROM_DIR TO_DIR FILES TARGETS TARGET)
foreach(SRC ${FILES})
set(SRCFILE ${SRC})
if("${FROM_DIR}" STREQUAL "" OR "${FROM_DIR}" STREQUAL "./")
set(FROM ${SRC})
else()
set(FROM ${FROM_DIR}/${SRC})
endif()
if("${TO_DIR}" STREQUAL "")
set(TO ${SRCFILE})
else()
get_filename_component(TOFILE ${SRC} NAME)
set(TO ${TO_DIR}/${TOFILE})
endif()
file(MAKE_DIRECTORY ${TO_DIR})
add_custom_command(TARGET "${TARGET}" PRE_BUILD
DEPENDS ${FROM}
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${FROM} ${TO})
endforeach()
endmacro()
#-------------------------------------------------------------------------------
# parse_file_list
#
# this macro splits a list of files with IN_DIR statements and fills them into a map
# where the key is the directory name
#-------------------------------------------------------------------------------
macro(parse_file_list FILELIST FILEMAP)
set(_EXPECT_IN_DIR FALSE)
map(CREATE ${FILEMAP})
set(_CURRENT_LIST)
foreach(_ITEM ${FILELIST})
if (_ITEM STREQUAL "IN_DIR")
set(_EXPECT_IN_DIR TRUE)
else()
if (_EXPECT_IN_DIR)
set(_EXPECT_IN_DIR FALSE)
map(SET ${FILEMAP} ${_ITEM} ${_CURRENT_LIST})
set(_CURRENT_LIST)
else()
list(APPEND _CURRENT_LIST "${_ITEM}")
endif()
endif()
endforeach()
if(_CURRENT_LIST)
map(SET ${FILEMAP} "." ${_CURRENT_LIST})
endif()
endmacro()
#-------------------------------------------------------------------------------
# Synopsis:
# module(NAME name SOURCES source1 source2 HEADERS header1 header2
# [IN_DIR dir] [header3 header4 [IN_DIR dir]] [DEPENDS_ON dep1 dep2]
# [HEADER_OUTPUT_DIR dir]
# [LINK link_cmds])
# Description:
# Define an OpenStructure module.
#-------------------------------------------------------------------------------
macro(module)
#-----------------------------------------------------------------------------
# deal with arguments
#-----------------------------------------------------------------------------
set(_ARGS "NAME;SOURCES;HEADERS;DEPENDS_ON;LINK;HEADER_OUTPUT_DIR;PREFIX")
set(_ARG_PREFIX ost)
parse_argument_list(_ARG "${_ARGS}" "NO_STATIC" ${ARGN})
if (NOT _ARG_NAME)
message(FATAL_ERROR
"invalid use of module(): a module name must be provided")
endif()
if (ENABLE_STATIC AND _ARG_NO_STATIC)
return()
endif()
if (_ARG_HEADER_OUTPUT_DIR)
set(_HEADER_OUTPUT_DIR ${_ARG_HEADER_OUTPUT_DIR})
else()
set(_HEADER_OUTPUT_DIR "${_ARG_PREFIX}/${_ARG_NAME}")
endif()
set(_LIB_NAME ${_ARG_PREFIX}_${_ARG_NAME})
string(TOUPPER ${_LIB_NAME} _UPPER_LIB_NAME)
#-----------------------------------------------------------------------------
# create library
#-----------------------------------------------------------------------------
file(MAKE_DIRECTORY ${LIB_STAGE_PATH})
file(MAKE_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
file(MAKE_DIRECTORY ${LIBEXEC_STAGE_PATH})
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
if (NOT TARGET create_stage)
add_custom_target(create_stage COMMAND ${CMAKE_COMMAND} -E make_directory ${LIB_STAGE_PATH}
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
COMMAND ${CMAKE_COMMAND} -E make_directory ${LIBEXEC_STAGE_PATH}
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/tests")
endif()
if (_ARG_SOURCES)
# when there is at least one source file, we build a library
set(_ABS_SOURCE_NAMES)
foreach(_SOURCE ${_ARG_SOURCES})
if (IS_ABSOLUTE ${_SOURCE})
list(APPEND _ABS_SOURCE_NAMES "${_SOURCE}")
else()
list(APPEND _ABS_SOURCE_NAMES "${CMAKE_CURRENT_SOURCE_DIR}/${_SOURCE}")
endif()
endforeach()
if (ENABLE_STATIC AND NOT _ARG_NO_STATIC)
add_library(${_LIB_NAME} STATIC ${_ABS_SOURCE_NAMES})
else()
add_library(${_LIB_NAME} SHARED ${_ABS_SOURCE_NAMES})
endif()
set_target_properties(${_LIB_NAME}
PROPERTIES OUTPUT_NAME ${_LIB_NAME}
PROJECT_LABEL ${_ARG_NAME}
EchoString ${_ARG_NAME}
MODULE_DEPS "${_ARG_DEPENDS_ON}")
get_target_property(_DEFS ${_LIB_NAME} COMPILE_DEFINITIONS)
add_dependencies(${_LIB_NAME} create_stage)
set_target_properties(${_LIB_NAME} PROPERTIES
COMPILE_DEFINITIONS OST_MODULE_${_UPPER_LIB_NAME})
set_target_properties(${_LIB_NAME} PROPERTIES
VERSION ${OST_VERSION_STRING}
SOVERSION ${OST_VERSION_MAJOR}.${OST_VERSION_MINOR})
set_target_properties(${_LIB_NAME} PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${LIB_STAGE_PATH}
ARCHIVE_OUTPUT_DIRECTORY ${LIB_STAGE_PATH}
RUNTIME_OUTPUT_DIRECTORY ${LIB_STAGE_PATH})
if (APPLE)
set_target_properties(${_LIB_NAME} PROPERTIES
LINK_FLAGS "-Wl,-rpath,@loader_path"
INSTALL_NAME_DIR "@rpath")
endif()
if (WIN32)
install(TARGETS ${_LIB_NAME} RUNTIME DESTINATION bin)
else()
if (ENABLE_STATIC)
install(TARGETS ${_LIB_NAME} ARCHIVE DESTINATION "${LIB_DIR}")
else()
install(TARGETS ${_LIB_NAME} LIBRARY DESTINATION "${LIB_DIR}")
endif()
endif()
if (_ARG_LINK)
target_link_libraries(${_LIB_NAME} ${_ARG_LINK})
endif()
foreach(_DEPENDENCY ${_ARG_DEPENDS_ON})
target_link_libraries(${_LIB_NAME} ${_DEPENDENCY})
endforeach()
if (ENABLE_STATIC)
target_link_libraries(${_LIB_NAME} ${STATIC_LIBRARIES})
endif()
else()
add_custom_target("${_LIB_NAME}" ALL)
set_target_properties("${_LIB_NAME}" PROPERTIES HEADER_ONLY 1
MODULE_DEPS "${_ARG_DEPENDS_ON}")
endif()
#-----------------------------------------------------------------------------
# stage headers
#-----------------------------------------------------------------------------
if (_ARG_HEADERS)
stage_and_install_headers("${_ARG_HEADERS}" "${_HEADER_OUTPUT_DIR}" "${_LIB_NAME}")
endif()
endmacro()
#-------------------------------------------------------------------------------
# macro stage_and_install_headers
#-------------------------------------------------------------------------------
macro(stage_and_install_headers HEADERLIST HEADER_OUTPUT_DIR TARGET)
add_custom_target("${TARGET}_headers" COMMENT "")
add_dependencies("${TARGET}" "${TARGET}_headers")
add_dependencies("${TARGET}_headers" create_stage)
parse_file_list("${HEADERLIST}" _HEADER_MAP)
map(KEYS _HEADER_MAP _HEADER_MAP_KEYS)
foreach(_DIR ${_HEADER_MAP_KEYS})
map(GET _HEADER_MAP ${_DIR} _HEADERS)
set(_HDR_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${_DIR}")
set(_ABS_HEADER_NAMES)
foreach(_HDR ${_HEADERS})
list(APPEND _ABS_HEADER_NAMES ${_HDR_SOURCE_DIR}/${_HDR})
endforeach()
set(_HDR_STAGE_DIR "${HEADER_OUTPUT_DIR}/${_DIR}")
set(_FULL_HEADER_DIR "${HEADER_STAGE_PATH}/${_HDR_STAGE_DIR}")
copy_if_different("" "${_FULL_HEADER_DIR}" "${_ABS_HEADER_NAMES}" "" "${TARGET}_headers")
if(NOT WIN32)
install(FILES ${_ABS_HEADER_NAMES} DESTINATION "include/${_HDR_STAGE_DIR}")
endif(NOT WIN32)
endforeach()
endmacro()
#-------------------------------------------------------------------------------
# Synopsis
# executable(NAME exe_name SOURCES source1 source2 LINK link1 link2)
#
# Description:
# Compile, link and stage a C++ executable
#-------------------------------------------------------------------------------
macro(executable)
parse_argument_list(_ARG
"NAME;SOURCES;LINK;DEPENDS_ON" "NO_RPATH;STATIC" ${ARGN})
if (NOT _ARG_NAME)
message(FATAL_ERROR "invalid use of executable(): a name must be provided")
endif()
add_executable(${_ARG_NAME} ${_ARG_SOURCES})
if (APPLE AND NOT _ARG_NO_RPATH AND NOT ENABLE_STATIC)
set_target_properties(${_ARG_NAME} PROPERTIES
LINK_FLAGS "-Wl,-rpath,@loader_path/../lib/")
endif()
if (_ARG_LINK)
target_link_libraries(${_ARG_NAME} ${_ARG_LINK})
endif()
foreach(_DEP ${_ARG_DEPENDS_ON})
target_link_libraries(${_ARG_NAME} ${_DEP})
endforeach()
if (ENABLE_STATIC AND _ARG_STATIC)
target_link_libraries(${_ARG_NAME} ${STATIC_LIBRARIES})
if (UNIX AND NOT APPLE)
if (OST_GCC_45)
set_target_properties(${_ARG_NAME}
PROPERTIES LINK_SEARCH_END_STATIC TRUE
LINK_FLAGS "-static-libgcc -static-libstdc++ -static -pthread")
else()
set_target_properties(${_ARG_NAME}
PROPERTIES LINK_SEARCH_END_STATIC TRUE
LINK_FLAGS "-static-libgcc -static -pthread")
endif()
endif()
endif()
install(TARGETS ${_ARG_NAME} DESTINATION bin)
endmacro()
#-------------------------------------------------------------------------------
# Synopsis
# executable_libexec(NAME exe_name SOURCES source1 source2 LINK link1 link2)
#
# Description:
# Compile, link and stage a C++ executable into the libexec directory
#-------------------------------------------------------------------------------
macro(executable_libexec)
parse_argument_list(_ARG
"NAME;SOURCES;LINK;DEPENDS_ON" "NO_RPATH;STATIC" ${ARGN})
if (NOT _ARG_NAME)
message(FATAL_ERROR "invalid use of executable(): a name must be provided")
endif()
add_executable(${_ARG_NAME} ${_ARG_SOURCES})
set_target_properties(${_ARG_NAME}
PROPERTIES RUNTIME_OUTPUT_DIRECTORY
"${LIBEXEC_STAGE_PATH}")
set_target_properties(${_ARG_NAME}
PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE
"${LIBEXEC_STAGE_PATH}")
set_target_properties(${_ARG_NAME}
PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG
"${LIBEXEC_STAGE_PATH}")
if (NOT _ARG_NO_RPATH AND NOT _ARG_STATIC)
if (APPLE)
set_target_properties(${_ARG_NAME} PROPERTIES
LINK_FLAGS "-Wl,-rpath,@loader_path/../../lib")
elseif (UNIX)
set_target_properties(${_ARG_NAME} PROPERTIES INSTALL_RPATH "$ORIGIN/../../${LIB_DIR}")
endif (APPLE)
endif (NOT _ARG_NO_RPATH AND NOT _ARG_STATIC)
if (_ARG_LINK)
target_link_libraries(${_ARG_NAME} ${_ARG_LINK})
endif()
if (ENABLE_STATIC AND _ARG_STATIC)
target_link_libraries(${_ARG_NAME} ${STATIC_LIBRARIES})
set_target_properties(${_ARG_NAME}
PROPERTIES LINK_SEARCH_END_STATIC TRUE)
endif()
foreach(_DEP ${_ARG_DEPENDS_ON})
target_link_libraries(${_ARG_NAME} ${_DEP})
endforeach()
install(TARGETS ${_ARG_NAME} DESTINATION ${LIBEXEC_PATH})
endmacro()
#-------------------------------------------------------------------------------
# Synopsis:
# substitute(IN_FILE in_file OUT_FILE out_file DICT a=b c=d)
#
#-------------------------------------------------------------------------------
macro(substitute)
parse_argument_list(_ARG
"IN_FILE;OUT_FILE;DICT" "" ${ARGN})
if (NOT _ARG_IN_FILE)
message(FATAL_ERROR "invalid use of substitute(): no IN_FILE given")
endif()
if (NOT _ARG_OUT_FILE)
message(FATAL_ERROR "invalid use of substitute(): no OUT_FILE given")
endif()
set(_SUBST_DICT -DINPUT_FILE=${_ARG_IN_FILE} -DOUT_FILE=${_ARG_OUT_FILE})
foreach(_SUBST ${_ARG_DICT})
list(APPEND _SUBST_DICT -D${_SUBST})
endforeach()
add_custom_target(subst_${_ARG_OUT_FILE} ALL COMMAND
${CMAKE_COMMAND} ${_SUBST_DICT}
-P ${CMAKE_SOURCE_DIR}/cmake_support/substitute.cmake)
endmacro()
#-------------------------------------------------------------------------------
# Synopsis:
# script(NAME script_name INPUT input_name SUBSTITUTE key=val key=val
# [OUTPUT_DIR dir] [TARGET target])
#-------------------------------------------------------------------------------
macro(script)
set(_ARG_OUTPUT_DIR bin)
parse_argument_list(_ARG
"NAME;INPUT;SUBSTITUTE;TARGET;OUTPUT_DIR" "" ${ARGN})
if (NOT _ARG_NAME)
message(FATAL_ERROR "invalid use of executable(): a name must be provided")
endif()
set(_INPUT ${_ARG_NAME})
if (_ARG_INPUT)
set(_INPUT ${_ARG_INPUT})
endif()
if (_ARG_SUBSTITUTE)
if (NOT _ARG_INPUT)
message(FATAL_ERROR "script() can only substitute when INPUT is present.")
endif()
substitute(IN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${_INPUT}" OUT_FILE ${_ARG_NAME}
DICT ${_ARG_SUBSTITUTE})
endif()
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${_ARG_NAME} DESTINATION ${_ARG_OUTPUT_DIR}
PERMISSIONS WORLD_EXECUTE GROUP_EXECUTE OWNER_EXECUTE
WORLD_READ GROUP_READ OWNER_READ)
copy_if_different("./" "${STAGE_DIR}/${_ARG_OUTPUT_DIR}"
"${_ARG_NAME}" "TARGETS" ${_ARG_TARGET})
add_dependencies(${_ARG_TARGET} subst_${_ARG_NAME})
endmacro()
#-------------------------------------------------------------------------------
# Synopsis:
# ui_to_python(libname stagedir[input_file1 ...])
# Description:
# Calls pyuic on every input file. The resulting python files are stored in
# the variable with name out_files.
#-------------------------------------------------------------------------------
macro(ui_to_python LIBNAME PYMODDIR STAGEDIR)
set(_input_files ${ARGN})
add_custom_target("${LIBNAME}_ui" ALL)
add_dependencies("_${LIBNAME}" "${LIBNAME}_ui")
find_program(_PYUIC_EXECUTABLE
NAMES pyuic4-${PYTHON_VERSION} pyuic4 pyuic pyuic4.bat
PATHS ENV PATH
)
if(NOT _PYUIC_EXECUTABLE)
message(FATAL_ERROR "Could not find pyuic command in " ${QT_BINARY_DIR} " for python version " ${PYTHON_VERSION})
endif(NOT _PYUIC_EXECUTABLE)
set(out_files)
foreach(input_file ${_input_files})
get_filename_component(_out_file ${input_file} NAME_WE)
get_filename_component(_in_file ${input_file} ABSOLUTE)
set(_out_file ${_out_file}_ui.py)
set(_abs_out_file ${STAGEDIR}/${_out_file})
add_custom_command(TARGET ${LIBNAME}_ui
COMMAND ${_PYUIC_EXECUTABLE} -o ${_abs_out_file} ${_in_file}
VERBATIM DEPENDS ${input_file}
)
list(APPEND out_files ${_abs_out_file})
endforeach()
compile_py_files(_${LIBNAME} ${STAGEDIR} compiled_files ${out_files})
install(FILES ${out_files} DESTINATION "${LIB_DIR}/${PYMODDIR}")
install(FILES ${compiled_files} DESTINATION "${LIB_DIR}/${PYMODDIR}")
endmacro()
#-------------------------------------------------------------------------------
# Synopsis:
# compile_py_files(module out_dir compiled_files [input_file1 ...])
# Description:
# Calls pyuic on every input file. The resulting python files are stored in
# the variable with name compiled_files.
#-------------------------------------------------------------------------------
macro(compile_py_files module out_dir compiled_files_name)
set(_input_files ${ARGN})
set(${compiled_files_name})
foreach(input_file ${_input_files})
get_filename_component(_out_file ${input_file} NAME_WE)
get_filename_component(_in_file ${input_file} ABSOLUTE)
set(_out_file ${out_dir}/${_out_file}.pyc)
list(APPEND ${compiled_files_name} ${_out_file})
get_filename_component(_in_name ${input_file} NAME)
file(MAKE_DIRECTORY ${out_dir})
add_custom_command(TARGET ${module}
COMMAND ${PYTHON_BINARY} -c "import py_compile;py_compile.compile(\"${_in_file}\",\"${_out_file}\",\"${_in_name}\",doraise=True)"
VERBATIM DEPENDS ${input_file}
)
endforeach()
endmacro()
#-------------------------------------------------------------------------------
# Synopsis:
# pymod(NAME name CPP source1 source2 PY source source2 [IN_DIR dir]
# source3 source4 [IN_DIR dir] [LINK link] [OUTPUT_DIR dir] [UI user_interface_files])
#
# Description:
# Define a python module consisting of C++ type wrappers and/or code written in
# Python.
# NAME is the name of
#-------------------------------------------------------------------------------
macro(pymod)
#-----------------------------------------------------------------------------
# deal with arguments
#-----------------------------------------------------------------------------
set(_ARG_PREFIX ost)
parse_argument_list(_ARG
"NAME;CPP;PY;LINK;OUTPUT_DIR;UI;PREFIX" "" ${ARGN})
if (NOT _ARG_NAME)
message(FATAL_ERROR "invalid use of pymod(): a name must be provided")
endif()
if (ENABLE_STATIC)
return()
endif()
if (_ARG_OUTPUT_DIR)
set(PYMOD_DIR "python${PYTHON_VERSION}/site-packages/${_ARG_OUTPUT_DIR}")
else()
set(PYMOD_DIR "python${PYTHON_VERSION}/site-packages/${_ARG_PREFIX}/${_ARG_NAME}")
endif()
set(_LIB_NAME ${_ARG_PREFIX}_${_ARG_NAME})
set(PYMOD_STAGE_DIR "${LIB_STAGE_PATH}/${PYMOD_DIR}")
file(MAKE_DIRECTORY ${PYMOD_STAGE_DIR})
include_directories(${PYTHON_INCLUDE_PATH})
#-----------------------------------------------------------------------------
# compile and link C++ wrappers
#-----------------------------------------------------------------------------
if (_ARG_CPP)
add_library("_${_LIB_NAME}" MODULE ${_ARG_CPP})
set_target_properties("_${_LIB_NAME}"
PROPERTIES ECHO_STRING
"Building Python Module ${_ARG_NAME}")
if (_ARG_PREFIX)
set(_PARENT_NAME "${_ARG_PREFIX}_${_ARG_NAME}")
else()
set(_PARENT_NAME "${_ARG_NAME}")
endif()
get_target_property(_CUSTOM_CHECK "${_PARENT_NAME}" HEADER_ONLY)
if (NOT _CUSTOM_CHECK)
set(_PARENT_LIB_NAME "${_PARENT_NAME}")
endif()
target_link_libraries("_${_LIB_NAME}" ${_PARENT_LIB_NAME}
${PYTHON_LIBRARIES} ${BOOST_PYTHON_LIBRARIES})
set_target_properties("_${_LIB_NAME}"
PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PYMOD_STAGE_DIR})
set_target_properties("_${_LIB_NAME}"
PROPERTIES LIBRARY_OUTPUT_DIRECTORY_RELEASE ${PYMOD_STAGE_DIR})
set_target_properties("_${_LIB_NAME}"
PROPERTIES LIBRARY_OUTPUT_DIRECTORY_DEBUG ${PYMOD_STAGE_DIR})
if (NOT ENABLE_STATIC)
if (_USE_RPATH)
string(REGEX REPLACE "/[^/]*" "/.." inv_pymod_path "/${PYMOD_DIR}")
set_target_properties("_${_LIB_NAME}"
PROPERTIES INSTALL_RPATH "$ORIGIN${inv_pymod_path}/")
else()
set_target_properties("_${_LIB_NAME}"
PROPERTIES INSTALL_RPATH "")
endif()
endif()
if (APPLE)
file(RELATIVE_PATH _REL_PATH "${PYMOD_STAGE_DIR}" "${LIB_STAGE_PATH}")
set_target_properties("_${_LIB_NAME}" PROPERTIES
LINK_FLAGS "-Wl,-rpath,@loader_path/${_REL_PATH}"
INSTALL_NAME_DIR "@rpath")
endif()
if (NOT WIN32)
set_target_properties("_${_LIB_NAME}"
PROPERTIES PREFIX "")
else ()
set_target_properties("_${_LIB_NAME}"
PROPERTIES SUFFIX ".pyd")
endif()
install(TARGETS "_${_LIB_NAME}" LIBRARY DESTINATION
"${LIB_DIR}/${PYMOD_DIR}")
else()
add_custom_target("_${_LIB_NAME}" ALL)
endif()
#-----------------------------------------------------------------------------
# build ui files
#-----------------------------------------------------------------------------
if (_ARG_UI)
ui_to_python(${_LIB_NAME} ${PYMOD_DIR} ${PYMOD_STAGE_DIR} ${_ARG_UI})
endif()
#-----------------------------------------------------------------------------
# compile python files
#-----------------------------------------------------------------------------
if (_ARG_PY)
parse_file_list("${_ARG_PY}" _PYFILE_MAP)
map(KEYS _PYFILE_MAP _PYFILE_MAP_KEYS)
foreach(_DIR ${_PYFILE_MAP_KEYS})
map(GET _PYFILE_MAP ${_DIR} _PY_FILES)
set(_ABS_PY_FILES)
set(_PY_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${_DIR}")
foreach(_PY ${_PY_FILES})
list(APPEND _ABS_PY_FILES "${_PY_SOURCE_DIR}/${_PY}")
endforeach()
install(FILES ${_ABS_PY_FILES} DESTINATION "${LIB_DIR}/${PYMOD_DIR}/${_DIR}")
string(REPLACE "/" "_" _DIR_NO_SLASH "${_DIR}")
set(_PYMOD_TARGET "${_LIB_NAME}_${_DIR_NO_SLASH}_pymod")
string(REPLACE "_." "" _PYMOD_TARGET "${_PYMOD_TARGET}")
add_custom_target(${_PYMOD_TARGET} ALL)
copy_if_different("./" "${PYMOD_STAGE_DIR}/${_DIR}"
"${_ABS_PY_FILES}" "TARGETS"
"${_PYMOD_TARGET}")
compile_py_files(_${_LIB_NAME} ${PYMOD_STAGE_DIR}/${_DIR} compiled_files ${_ABS_PY_FILES})
install(FILES ${compiled_files} DESTINATION "${LIB_DIR}/${PYMOD_DIR}/${_DIR}")
endforeach()
endif()
get_target_property(_MOD_DEPS "${_PARENT_NAME}" MODULE_DEPS)
if(_MOD_DEPS)
foreach(dep ${_MOD_DEPS})
add_dependencies("_${_LIB_NAME}" "_${dep}")
endforeach()
endif()
endmacro()
add_custom_target(check)
add_custom_target(check_xml)
if (WIN32)
set_target_properties(check PROPERTIES EXCLUDE_FROM_ALL "1")
set_target_properties(check_xml PROPERTIES EXCLUDE_FROM_ALL "1")
endif()
#-------------------------------------------------------------------------------
# ost_unittest
#
# define a unit test
#-------------------------------------------------------------------------------
macro(ost_unittest)
set(_ARG_PREFIX ost)
parse_argument_list(_ARG
"MODULE;PREFIX;SOURCES;LINK" "" ${ARGN})
set(_SOURCES ${_ARG_SOURCES})
set(CPP_TESTS)
set(PY_TESTS)
set(CMAKE_CURRENT_BINARY_DIR "${CMAKE_BINARY_DIR}/tests")
foreach(src ${_SOURCES})
if (${src} MATCHES "\\.py$")
list(APPEND PY_TESTS "${src}")
else()
list(APPEND CPP_TESTS "${CMAKE_CURRENT_SOURCE_DIR}/${src}")
endif()
endforeach()
set(_SOURCES ${CPP_TESTS})
set(_test_name "${_ARG_PREFIX}_${_ARG_MODULE}_tests")
if(DEFINED CPP_TESTS)
if(COMPILE_TESTS)
add_executable(${_test_name} ${_SOURCES})
else()
add_executable(${_test_name} EXCLUDE_FROM_ALL ${_SOURCES})
endif()
set_target_properties(${_test_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests" )
set_target_properties(${_test_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/tests" )
set_target_properties(${_test_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/tests" )
target_link_libraries(${_test_name} ${BOOST_UNIT_TEST_LIBRARIES} "${_ARG_PREFIX}_${_ARG_MODULE}")
if (WIN32)
set(TEST_COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${_test_name}.exe || echo)
message(${TEST_COMMAND})
set(ENV{PP} ${STAGE_DIR}/bin)
add_custom_target("${_test_name}_run"
COMMAND echo %PP%
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "running checks for module ${_ARG_MODULE}"
DEPENDS ${_test_name})
add_test("${_test_name}" ${CMAKE_CURRENT_BINARY_DIR}/${_test_name}.exe)
set_target_properties("${_test_name}_run" PROPERTIES EXCLUDE_FROM_ALL "1")
add_dependencies(check "${_test_name}_run")
else()
add_custom_target("${_test_name}_run"
COMMAND OST_ROOT=${STAGE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${_test_name}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "running checks for module ${_ARG_MODULE}"
DEPENDS ${_test_name})
add_custom_target("${_test_name}_run_xml"
COMMAND OST_ROOT=${STAGE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${_test_name} --log_format=xml --log_level=all > ${_test_name}_log.xml || echo
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "running checks for module ${_ARG_MODULE}"
DEPENDS ${_test_name})
add_test("${_test_name}" ${CMAKE_CURRENT_BINARY_DIR}/${_test_name} )
add_dependencies(check_xml "${_test_name}_run_xml")
add_dependencies(check "${_test_name}_run")
endif()
if (_ARG_LINK)
target_link_libraries("${_test_name}" ${_ARG_LINK})
endif()
set_target_properties(${_test_name}
PROPERTIES RUNTIME_OUTPUT_DIRECTORY
"${CMAKE_CURRENT_BINARY_DIR}")
endif()
foreach(py_test ${PY_TESTS})
set(python_path $ENV{PYTHONPATH})
if(python_path)
set(python_path "${python_path}:")
endif(python_path)
set(python_path "${python_path}${LIB_STAGE_PATH}/python${PYTHON_VERSION}/site-packages")
if(WIN32)
set (PY_TESTS_CMD "PYTHONPATH=${python_path} ${PYTHON_BINARY}")
# todo fix python unit test running for Windows
#set (PY_TESTS_CMD "${EXECUTABLE_OUTPUT_PATH}/ost.bat")
#add_custom_target("${py_test}_run"
# CALL "${PY_TESTS_CMD} ${CMAKE_CURRENT_SOURCE_DIR}/${py_test} || echo"
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
# COMMENT "running checks ${py_test}" VERBATIM)
#set_target_properties("${py_test}_run" PROPERTIES EXCLUDE_FROM_ALL "1")
#add_dependencies("${py_test}_run" ost_scripts "_${_ARG_PREFIX}_${_ARG_MODULE}")
#add_dependencies(check "${py_test}_run")
else()
set (PY_TESTS_CMD "PYTHONPATH=${python_path} ${PYTHON_BINARY}")
add_custom_target("${py_test}_run"
sh -c "${PY_TESTS_CMD} ${CMAKE_CURRENT_SOURCE_DIR}/${py_test}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "running checks ${py_test}" VERBATIM)
add_custom_target("${py_test}_run_xml"
sh -c "${PY_TESTS_CMD} ${CMAKE_CURRENT_SOURCE_DIR}/${py_test} xml || echo"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "running checks ${py_test}" VERBATIM)
add_dependencies("${py_test}_run_xml" ost_scripts "_${_ARG_PREFIX}_${_ARG_MODULE}")
add_dependencies("${py_test}_run" ost_scripts "_${_ARG_PREFIX}_${_ARG_MODULE}")
add_dependencies(check "${py_test}_run")
add_dependencies(check_xml "${py_test}_run_xml")
endif()
endforeach()
# get_target_property(OUTT ${_test_name} GENERATOR_FILE_NAME)
# message("${OUTT}")
# get_target_property(OUTT check GENERATOR_FILE_NAME)
# message("${OUTT}")
endmacro()
#-------------------------------------------------------------------------------
# make sure the previously detected Python interpreter has the given module
#-------------------------------------------------------------------------------
macro(ost_find_python_module MODULE)
if (NOT PYTHON_MODULE_${MODULE})
message(STATUS "Searching for python module ${MODULE} for ${PYTHON_BINARY}")
execute_process(COMMAND ${PYTHON_BINARY} -c "import ${MODULE}"
OUTPUT_QUIET ERROR_QUIET
RESULT_VARIABLE _IMPORT_ERROR)
if (_IMPORT_ERROR)
message(FATAL_ERROR "Could not find python module ${MODULE}. Please install it")
else()
message(STATUS "Found python module ${MODULE}")
set("PYTHON_MODULE_${MODULE}" FOUND CACHE STRING "" FORCE)
endif()
endif()
endmacro()
#-------------------------------------------------------------------------------
# this macro tries to detect a very common problem during configuration stage:
# it makes sure that boost python is linked against the same version of python
# that we are linking against.
#-------------------------------------------------------------------------------
macro(ost_match_boost_python_version)
include(CheckCXXSourceRuns)
# this variable may either be a simple library path or list that contains
# different libraries for different build-options. For example:
# optimized;<lib1>;debug;<lib2>
set(_BOOST_PYTHON_LIBRARY ${Boost_PYTHON_LIBRARY})
list(LENGTH _BOOST_PYTHON_LIBRARY _BP_LENGTH)
if (_BP_LENGTH GREATER 1)
list(FIND _BOOST_PYTHON_LIBRARY optimized _OPTIMIZED_INDEX)
if (_OPTIMIZED_INDEX EQUAL -1)
message(FATAL_ERROR
"Error while trying to get path of boost python library")
endif()
math(EXPR _LIB_INDEX 1+${_OPTIMIZED_INDEX})
list(GET _BOOST_PYTHON_LIBRARY ${_LIB_INDEX} _BP_LIB_PATH)
set(_BOOST_PYTHON_LIBRARY ${_BP_LIB_PATH})
endif()
set(CMAKE_REQUIRED_FLAGS "-I${PYTHON_INCLUDE_PATH} -I${Boost_INCLUDE_DIR} ${PYTHON_LIBRARIES} ${_BOOST_PYTHON_LIBRARY}")
check_cxx_source_runs(
"#include <boost/python.hpp>
using namespace boost::python;
int main( int argc, char ** argv ) {
try {
Py_Initialize();
object main_module((
handle<>(borrowed(PyImport_AddModule(\"__main__\")))));
object main_namespace = main_module.attr(\"__dict__\");
handle<> ignored(( PyRun_String( \"print 'Hello, World'\",
Py_file_input,
main_namespace.ptr(),
main_namespace.ptr() ) ));
} catch( error_already_set ) {
PyErr_Print();
return 1;
}
return 0;
}" PYTHON_VERSION_FOUND_MATCHES_PYTHON_VERSION_BOOST_WAS_COMPILED_WITH)
if(NOT PYTHON_VERSION_FOUND_MATCHES_PYTHON_VERSION_BOOST_WAS_COMPILED_WITH)
message(FATAL_ERROR "Python versions mismatch!\n"
"Make sure the python version for boost match the one you "
"specified during configuration\n")
endif()
endmacro()
#-------------------------------------------------------------------------------
# this macro sets up the stage directories
#-------------------------------------------------------------------------------
macro(setup_stage)
set(STAGE_DIR "${CMAKE_BINARY_DIR}/stage")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${STAGE_DIR}/bin )
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${STAGE_DIR}/bin )
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${STAGE_DIR}/bin )
set(HEADER_STAGE_PATH ${STAGE_DIR}/include )
set(SHARED_DATA_PATH ${STAGE_DIR}/share/openstructure )
if (WIN32)
set(ENV{PATH} ${STAGE_DIR}/bin\;$ENV{PATH})
endif (WIN32)
if (UNIX AND NOT APPLE)
check_architecture()
endif()
set (ARCH ${CMAKE_NATIVE_ARCH})
if ("${ARCH}" MATCHES "64" AND NOT _UBUNTU_LAYOUT)
set(LIB_DIR lib64 )
set(LIB_STAGE_PATH "${STAGE_DIR}/lib64" )
else()
set(LIB_DIR lib )
set(LIB_STAGE_PATH "${STAGE_DIR}/lib" )
endif()
if (_UBUNTU_LAYOUT)
set(LIBEXEC_PATH ${LIB_DIR}/openstructure/libexec )
set(LIBEXEC_STAGE_PATH ${LIB_STAGE_PATH}/openstructure/libexec )
else()
set(LIBEXEC_PATH libexec/openstructure )
set(LIBEXEC_STAGE_PATH ${STAGE_DIR}/libexec/openstructure )
endif()
include_directories("${HEADER_STAGE_PATH}")
link_directories(${LIB_STAGE_PATH})
endmacro()
#-------------------------------------------------------------------------------
# get compiler version
#-------------------------------------------------------------------------------
function(get_compiler_version _OUTPUT_VERSION)
exec_program(${CMAKE_CXX_COMPILER}
ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion
OUTPUT_VARIABLE _COMPILER_VERSION
)
string(REGEX REPLACE "([0-9])\\.([0-9])(\\.[0-9])?" "\\1\\2"
_COMPILER_VERSION ${_COMPILER_VERSION})
set(${_OUTPUT_VERSION} ${_COMPILER_VERSION} PARENT_SCOPE)
endfunction()
macro(setup_compiler_flags)
if (WIN32)
# add_definitions(-DBOOST_TEST_INCLUDED)
add_definitions(-D_USE_MATH_DEFINES -D_CRT_SECURE_NO_DEPRECATE
-D_SCL_SECURE_NO_DEPRECATE -DNOMINMAX)
#add_definitions(-Zc:wchar_t-) #
# add_definitions(-MDd -vmg -EHsc -GR)
#GR:Uses the __fastcall calling convention (x86 only).
#-EHsc to specify the synchronous exception handling mode/
#-vmg Uses full generality for pointers to members.
#add_definitions(-DBOOST_ZLIB_BINARY=zdll)
#add_definitions(-NODEFAULTLIB:LIBCMTD.lib)
endif()
if (CMAKE_COMPILER_IS_GNUCXX)
get_compiler_version(_GCC_VERSION)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall" )
if (_GCC_VERSION MATCHES "44")
# gcc 4.4. is very strict about aliasing rules. the shared_count
# implementation that is used boost's shared_ptr violates these rules. To
# silence the warnings and prevent miscompiles, enable
# -fno-strict-aliasing
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing" )
endif()
endif()
endmacro()
set(_BOOST_MIN_VERSION 1.31)
macro(setup_boost)
set (Boost_NO_BOOST_CMAKE TRUE)
find_package(Boost ${_BOOST_MIN_VERSION} COMPONENTS python REQUIRED)
set(BOOST_PYTHON_LIBRARIES ${Boost_LIBRARIES})
set(Boost_LIBRARIES)
find_package(Boost ${_BOOST_MIN_VERSION}
COMPONENTS unit_test_framework REQUIRED)
set(BOOST_UNIT_TEST_LIBRARIES ${Boost_LIBRARIES})
set(Boost_LIBRARIES)
if (ENABLE_STATIC)
set(Boost_USE_STATIC_LIBS ON)
endif()
find_package(Boost ${_BOOST_MIN_VERSION}
COMPONENTS filesystem system REQUIRED)
set(BOOST_LIBRARIES ${Boost_LIBRARIES})
set(Boost_LIBRARIES)
find_package(Boost ${_BOOST_MIN_VERSION} COMPONENTS iostreams REQUIRED)
set(BOOST_IOSTREAM_LIBRARIES ${Boost_LIBRARIES})
set(Boost_LIBRARIES)
find_package(Boost ${_BOOST_MIN_VERSION} COMPONENTS program_options REQUIRED)
set(BOOST_PROGRAM_OPTIONS ${Boost_LIBRARIES})
set(Boost_LIBRARIES)
find_package(Boost ${_BOOST_MIN_VERSION} COMPONENTS regex REQUIRED)
set(BOOST_REGEX_LIBRARIES ${Boost_LIBRARIES})
set(Boost_LIBRARIES)
find_package(Boost ${_BOOST_MIN_VERSION} COMPONENTS thread REQUIRED)
set(BOOST_THREAD ${Boost_LIBRARIES})
set(Boost_LIBRARIES)
endmacro()
#-------------------------------------------------------------------------------
# Synopsis:
# ost_action_init()
#
# Description:
# Initialise cached variables
#-------------------------------------------------------------------------------
macro(ost_action_init)
set(OST_ACTION_NAMES "" CACHE INTERNAL "" FORCE)
endmacro(ost_action_init)
#-------------------------------------------------------------------------------
# Synopsis:
# ost_action(ACTION TARGET)
#
# Description:
# Add a script to actions.
# ACTION script to be added (needs to have permissions to be executed)
# TARGET make target to add the action to
#-------------------------------------------------------------------------------
macro(ost_action ACTION TARGET)
copy_if_different("${CMAKE_CURRENT_SOURCE_DIR}"
"${STAGE_DIR}/${LIBEXEC_PATH}"
"${ACTION}" "TARGETS" ${TARGET})
install(FILES "${ACTION}" DESTINATION "${LIBEXEC_PATH}"
PERMISSIONS WORLD_EXECUTE GROUP_EXECUTE OWNER_EXECUTE
WORLD_READ GROUP_READ OWNER_READ)
# storing tool names for bash completion
string(REGEX REPLACE "^ost-" "" stripped_action ${ACTION})
if(DEFINED OST_ACTION_NAMES)
if(${OST_ACTION_NAMES} MATCHES "${stripped_action}")
set(_ACTION_NAMES "${OST_ACTION_NAMES}")
else()
if("${OST_ACTION_NAMES}" STREQUAL "")
set(_ACTION_NAMES "${stripped_action}")
else()
set(_ACTION_NAMES "${OST_ACTION_NAMES} ${stripped_action}")
endif()
endif()
else()
set(_ACTION_NAMES "${stripped_action}")
endif()
set(OST_ACTION_NAMES "${_ACTION_NAMES}" CACHE INTERNAL "" FORCE)
endmacro(ost_action)