diff --git a/Core/CppMicroServices/CMakeLists.txt b/Core/CppMicroServices/CMakeLists.txt index 08d775bc32..bee7662d00 100644 --- a/Core/CppMicroServices/CMakeLists.txt +++ b/Core/CppMicroServices/CMakeLists.txt @@ -1,430 +1,438 @@ project(CppMicroServices) set(${PROJECT_NAME}_MAJOR_VERSION 2) set(${PROJECT_NAME}_MINOR_VERSION 99) set(${PROJECT_NAME}_PATCH_VERSION 0) set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION}) cmake_minimum_required(VERSION 2.8) cmake_policy(VERSION 2.8) cmake_policy(SET CMP0017 NEW) #----------------------------------------------------------------------------- # Update CMake module path #------------------------------------------------------------------------------ set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH} ) #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(CMakeParseArguments) include(CMakePackageConfigHelpers) include(CheckCXXSourceCompiles) include(usFunctionCheckCompilerFlags) include(usFunctionEmbedResources) include(usFunctionGetGccVersion) include(usFunctionGenerateModuleInit) include(usFunctionGenerateExecutableInit) #----------------------------------------------------------------------------- # Init output directories #----------------------------------------------------------------------------- set(US_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(US_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(US_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") foreach(_type ARCHIVE LIBRARY RUNTIME) if(NOT CMAKE_${_type}_OUTPUT_DIRECTORY) set(CMAKE_${_type}_OUTPUT_DIRECTORY ${US_${_type}_OUTPUT_DIRECTORY}) endif() endforeach() #----------------------------------------------------------------------------- # Set a default build type if none was specified #----------------------------------------------------------------------------- if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'Debug' as none was specified.") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() #----------------------------------------------------------------------------- # CMake options #----------------------------------------------------------------------------- function(us_cache_var _var_name _var_default _var_type _var_help) set(_advanced 0) set(_force) foreach(_argn ${ARGN}) if(_argn STREQUAL ADVANCED) set(_advanced 1) elseif(_argn STREQUAL FORCE) set(_force FORCE) endif() endforeach() if(US_IS_EMBEDDED) if(NOT DEFINED ${_var_name} OR _force) set(${_var_name} ${_var_default} PARENT_SCOPE) endif() else() set(${_var_name} ${_var_default} CACHE ${_var_type} "${_var_help}" ${_force}) if(_advanced) mark_as_advanced(${_var_name}) endif() endif() endfunction() # Determine if we are being build inside a larger project if(NOT DEFINED US_IS_EMBEDDED) if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) set(US_IS_EMBEDDED 0) else() set(US_IS_EMBEDDED 1) endif() endif() # Determine the name of the install component for "SDK" artifacts. # The default is "sdk" if(NOT DEFINED US_SDK_INSTALL_COMPONENT) set(US_SDK_INSTALL_COMPONENT COMPONENT sdk) elseif(US_SDK_INSTALL_COMPONENT) set(US_SDK_INSTALL_COMPONENT COMPONENT ${US_SDK_INSTALL_COMPONENT}) endif() us_cache_var(US_ENABLE_AUTOLOADING_SUPPORT OFF BOOL "Enable module auto-loading support") us_cache_var(US_ENABLE_THREADING_SUPPORT OFF BOOL "Enable threading support") us_cache_var(US_ENABLE_DEBUG_OUTPUT OFF BOOL "Enable debug messages" ADVANCED) us_cache_var(US_ENABLE_RESOURCE_COMPRESSION ON BOOL "Enable resource compression" ADVANCED) us_cache_var(US_BUILD_SHARED_LIBS ON BOOL "Build shared libraries") us_cache_var(US_BUILD_TESTING OFF BOOL "Build tests") us_cache_var(US_BUILD_EXAMPLES OFF BOOL "Build example projects") if(US_BUILD_TESTING) enable_testing() endif() if(WIN32 AND NOT CYGWIN) set(default_runtime_install_dir bin/) set(default_library_install_dir bin/) set(default_archive_install_dir lib/) set(default_header_install_dir include/) set(default_auxiliary_install_dir share/) else() set(default_runtime_install_dir bin/) set(default_library_install_dir lib/${PROJECT_NAME}) set(default_archive_install_dir lib/${PROJECT_NAME}) set(default_header_install_dir include/${PROJECT_NAME}) set(default_auxiliary_install_dir share/${PROJECT_NAME}) endif() us_cache_var(RUNTIME_INSTALL_DIR ${default_runtime_install_dir} STRING "Relative install location for binaries" ADVANCED) us_cache_var(LIBRARY_INSTALL_DIR ${default_library_install_dir} STRING "Relative install location for libraries" ADVANCED) us_cache_var(ARCHIVE_INSTALL_DIR ${default_archive_install_dir} STRING "Relative install location for archives" ADVANCED) us_cache_var(HEADER_INSTALL_DIR ${default_header_install_dir} STRING "Relative install location for headers" ADVANCED) us_cache_var(AUXILIARY_INSTALL_DIR ${default_auxiliary_install_dir} STRING "Relative install location for auxiliary files" ADVANCED) set(AUXILIARY_CMAKE_INSTALL_DIR ${AUXILIARY_INSTALL_DIR}/cmake) us_cache_var(US_NAMESPACE "us" STRING "The namespace for the C++ Micro Services symbols") set(BUILD_SHARED_LIBS ${US_BUILD_SHARED_LIBS}) set(US_MODULE_INIT_TEMPLATE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/usModuleInit.cpp" CACHE INTERNAL "The module initialization template code") set(US_EXECUTABLE_INIT_TEMPLATE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/usExecutableInit.cpp" CACHE INTERNAL "The executable initialization template code") #----------------------------------------------------------------------------- # US C/CXX Flags #----------------------------------------------------------------------------- if(US_IS_EMBEDDED) set(CMAKE_C_FLAGS) set(CMAKE_C_FLAGS_RELEASE) set(CMAKE_C_FLAGS_DEBUG) set(CMAKE_CXX_FLAGS) set(CMAKE_CXX_FLAGS_RELEASE) set(CMAKE_CXX_FLAGS_DEBUG) set(CMAKE_LINK_FLAGS) set(CMAKE_LINK_FLAGS_RELEASE) set(CMAKE_LINK_FLAGS_DEBUG) endif() # Set C++ compiler flags if(NOT MSVC) foreach(_cxxflag -Werror -Wall -Wextra -Wpointer-arith -Winvalid-pch -Wcast-align -Wwrite-strings -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast -Wstrict-null-sentinel -Wsign-promo -fdiagnostics-show-option) usFunctionCheckCompilerFlags(${_cxxflag} US_CXX_FLAGS) endforeach() endif() set(US_HAVE_VISIBILITY_ATTRIBUTE 0) if(CMAKE_COMPILER_IS_GNUCXX) usFunctionGetGccVersion(${CMAKE_CXX_COMPILER} GCC_VERSION) if(${GCC_VERSION} VERSION_LESS "4.0.0") message(FATAL_ERROR "gcc version ${GCC_VERSION} not supported. Please use gcc >= 4.") endif() # With older versions of gcc the flag -fstack-protector-all requires an extra dependency to libssp.so. # If the gcc version is lower than 4.4.0 and the build type is Release let's not include the flag. if(${GCC_VERSION} VERSION_GREATER "4.4.0" OR (CMAKE_BUILD_TYPE STREQUAL "Debug" AND ${GCC_VERSION} VERSION_LESS "4.4.0")) usFunctionCheckCompilerFlags("-fstack-protector-all" US_CXX_FLAGS) endif() if(MINGW) # suppress warnings about auto imported symbols set(US_CXX_FLAGS "-Wl,--enable-auto-import ${US_CXX_FLAGS}") # we need to define a Windows version set(US_CXX_FLAGS "-D_WIN32_WINNT=0x0500 ${US_CXX_FLAGS}") else() # Enable visibility support if(NOT ${GCC_VERSION} VERSION_LESS "4.5") usFunctionCheckCompilerFlags("-fvisibility=hidden -fvisibility-inlines-hidden" _have_visibility) if(_have_visibility) set(US_CXX_FLAGS "${US_CXX_FLAGS} ${_have_visibility}") set(US_HAVE_VISIBILITY_ATTRIBUTE 1) endif() else() set(US_GCC_RTTI_WORKAROUND_NEEDED 1) endif() endif() usFunctionCheckCompilerFlags("-O1 -D_FORTIFY_SOURCE=2" _fortify_source_flag) if(_fortify_source_flag) set(US_CXX_FLAGS_RELEASE "${US_CXX_FLAGS_RELEASE} -D_FORTIFY_SOURCE=2") endif() else() usFunctionCheckCompilerFlags("-fvisibility=hidden -fvisibility-inlines-hidden" _have_visibility) if(_have_visibility) - set(US_CXX_FLAGS "${US_CXX_FLAGS} ${_have_visibility}") set(US_HAVE_VISIBILITY_ATTRIBUTE 1) + # We only support hidden visibility with gcc for now, so no -fvisibility=hidden flag here. + # Clang has troubles with correctly marking template declarations and explicit template + # instantiations as exported across shared library boundaries. Specifically, comparing + # type_info objects from STL types does not work (used in us::Any::Type() == typeid(std::string)) + # which could be related to the default visibility of STL types declared in libstdc++ and/or libc++ + # but also to using RTLD_LOCAL or RTLD_GLOBAL when loading shared libraries via dlopen(). + # + # See http://comments.gmane.org/gmane.comp.compilers.clang.scm/50028 + # and http://llvm.org/bugs/show_bug.cgi?id=10113 endif() endif() if(MSVC) set(US_CXX_FLAGS "/MP /WX /wd4996 /wd4251 /wd4503 ${US_CXX_FLAGS}") endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${US_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${US_CXX_FLAGS_RELEASE}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${US_C_FLAGS}") set(CMAKE_C_FLAGS_REALEASE "${CMAKE_C_FLAGS_RELEASE} ${US_C_FLAGS_RELEASE}") #----------------------------------------------------------------------------- # US Link Flags #----------------------------------------------------------------------------- set(US_LINK_FLAGS ) if(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) foreach(_linkflag -Wl,--no-undefined) set(_add_flag) usFunctionCheckCompilerFlags("${_linkflag}" _add_flag) if(_add_flag) set(US_LINK_FLAGS "${US_LINK_FLAGS} ${_linkflag}") endif() endforeach() endif() #----------------------------------------------------------------------------- # US Header Checks #----------------------------------------------------------------------------- include(CheckIncludeFileCXX) include(CheckCXXSourceCompiles) CHECK_INCLUDE_FILE_CXX(stdint.h US_HAVE_STDINT_H) CHECK_INCLUDE_FILE_CXX(tr1/unordered_map US_HAVE_TR1_UNORDERED_MAP_H) CHECK_INCLUDE_FILE_CXX(tr1/unordered_set US_HAVE_TR1_UNORDERED_SET_H) CHECK_INCLUDE_FILE_CXX(tr1/functional US_HAVE_TR1_FUNCTIONAL_H) CHECK_INCLUDE_FILE_CXX(unordered_map US_HAVE_UNORDERED_MAP_H) CHECK_INCLUDE_FILE_CXX(unordered_set US_HAVE_UNORDERED_SET_H) CHECK_INCLUDE_FILE_CXX(functional US_HAVE_FUNCTIONAL_H) if(US_HAVE_UNORDERED_MAP_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_map m; return 0; }" US_HAVE_TR1_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_map m; return 0; }" US_HAVE_STD_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::hash(); return 0; }" US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::hash(); return 0; }" US_HAVE_STD_HASH) if(US_HAVE_STD_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_CLASS) elseif(US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_CLASS) endif() elseif(US_HAVE_TR1_UNORDERED_MAP_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_map m; return 0; }" US_HAVE_TR1_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_map m; return 0; }" US_HAVE_STD_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::hash(); return 0; }" US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::hash(); return 0; }" US_HAVE_STD_HASH) if(US_HAVE_STD_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_CLASS) elseif(US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_CLASS) endif() else() message(SEND_ERROR "The header file \"unordered_map\" is not available.") endif() if(NOT (US_HAVE_TR1_UNORDERED_MAP OR US_HAVE_STD_UNORDERED_MAP)) message(SEND_ERROR "The \"unordered_map\" type is not available.") endif() if(US_HAVE_UNORDERED_SET_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_set s; return 0; }" US_HAVE_TR1_UNORDERED_SET) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_set s; return 0; }" US_HAVE_STD_UNORDERED_SET) elseif(US_HAVE_TR1_UNORDERED_SET_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_set s; return 0; }" US_HAVE_TR1_UNORDERED_SET) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_set s; return 0; }" US_HAVE_STD_UNORDERED_SET) else() message(SEND_ERROR "The header file \"unordered_set\" is not available.") endif() if(NOT (US_HAVE_TR1_UNORDERED_SET OR US_HAVE_STD_UNORDERED_SET)) message(SEND_ERROR "The \"unordered_set\" type is not available.") endif() if(NOT (US_HAVE_FUNCTIONAL_H OR US_HAVE_TR1_FUNCTIONAL_H)) message(SEND_ERROR "The header file \"functional\" is not available.") endif() if(US_HAVE_FUNCTIONAL_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::function f(main); return 0; }" US_HAVE_TR1_FUNCTION) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::function f(main); return 0; }" US_HAVE_STD_FUNCTION) endif() if((NOT (US_HAVE_STD_FUNCTION OR US_HAVE_TR1_FUNCTION)) AND US_HAVE_TR1_FUNCTIONAL_H) unset(US_HAVE_TR1_FUNCTION CACHE) unset(US_HAVE_STD_FUNCTION CACHE) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::function f(main); return 0; }" US_HAVE_TR1_FUNCTION) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::function f(main); return 0; }" US_HAVE_STD_FUNCTION) endif() if(NOT (US_HAVE_STD_FUNCTION OR US_HAVE_TR1_FUNCTION)) message(SEND_ERROR "The \"function\" type is not available.") endif() #----------------------------------------------------------------------------- # Source directory #----------------------------------------------------------------------------- set(US_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/include ${PROJECT_BINARY_DIR}/include) # Configure CppMicroServicesConfig.cmake for the build tree. # The file is used in sub-directories. set(PACKAGE_CONFIG_INCLUDE_DIR ${US_INCLUDE_DIRS}) set(PACKAGE_CONFIG_RUNTIME_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) set(PACKAGE_CONFIG_CMAKE_DIR ${PROJECT_SOURCE_DIR}/cmake) set(US_RCC_EXECUTABLE_NAME usResourceCompiler) set(CppMicroServices_RCC_EXECUTABLE_NAME ${US_RCC_EXECUTABLE_NAME} CACHE INTERNAL "The target name of the usResourceCompiler executable.") configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY ) set(us_global_config_h_file "${PROJECT_BINARY_DIR}/include/usGlobalConfig.h") configure_file(${PROJECT_SOURCE_DIR}/cmake/usGlobalConfig.h.in ${us_global_config_h_file}) include_directories(${US_INCLUDE_DIRS}) add_subdirectory(tools) add_subdirectory(core) #----------------------------------------------------------------------------- # Documentation #----------------------------------------------------------------------------- add_subdirectory(doc) #----------------------------------------------------------------------------- # Last configuration and install steps #----------------------------------------------------------------------------- export(TARGETS ${US_RCC_EXECUTABLE_NAME} FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake) install(EXPORT ${PROJECT_NAME}Targets FILE ${PROJECT_NAME}Targets.cmake DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR}) set(_install_cmake_scripts ${US_MODULE_INIT_TEMPLATE} ${US_EXECUTABLE_INIT_TEMPLATE} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/CMakeParseArguments.cmake ${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindPackageHandleStandardArgs.cmake ${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindPackageMessage.cmake ${CMAKE_CURRENT_SOURCE_DIR}/cmake/usFunctionGenerateModuleInit.cmake ${CMAKE_CURRENT_SOURCE_DIR}/cmake/usFunctionGenerateExecutableInit.cmake ${CMAKE_CURRENT_SOURCE_DIR}/cmake/usFunctionEmbedResources.cmake ) install(FILES ${_install_cmake_scripts} DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR}) install(FILES ${us_global_config_h_file} DESTINATION ${HEADER_INSTALL_DIR}) # Configure CppMicroServicesConfig.cmake for the install tree set(CONFIG_INCLUDE_DIR ${HEADER_INSTALL_DIR}) set(CONFIG_RUNTIME_DIR ${RUNTIME_INSTALL_DIR}) set(CONFIG_CMAKE_DIR ${AUXILIARY_CMAKE_INSTALL_DIR}) configure_package_config_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake INSTALL_DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR} PATH_VARS CONFIG_INCLUDE_DIR CONFIG_RUNTIME_DIR CONFIG_CMAKE_DIR NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO ) # Version information configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}ConfigVersion.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake @ONLY ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR} ${US_SDK_INSTALL_COMPONENT} ) diff --git a/Core/CppMicroServices/cmake/usFunctionCheckCompilerFlags.cmake b/Core/CppMicroServices/cmake/usFunctionCheckCompilerFlags.cmake index 5aef7e2ccd..0ec97da19f 100644 --- a/Core/CppMicroServices/cmake/usFunctionCheckCompilerFlags.cmake +++ b/Core/CppMicroServices/cmake/usFunctionCheckCompilerFlags.cmake @@ -1,64 +1,68 @@ # # Helper macro allowing to check if the given flags are supported # by the underlying build tool # # If the flag(s) is/are supported, they will be appended to the string identified by RESULT_VAR # # Usage: # usFunctionCheckCompilerFlags(FLAGS_TO_CHECK VALID_FLAGS_VAR) # # Example: # # set(myflags) # usFunctionCheckCompilerFlags("-fprofile-arcs" myflags) # message(1-myflags:${myflags}) # usFunctionCheckCompilerFlags("-fauto-bugfix" myflags) # message(2-myflags:${myflags}) # usFunctionCheckCompilerFlags("-Wall" myflags) # message(1-myflags:${myflags}) # # The output will be: # 1-myflags: -fprofile-arcs # 2-myflags: -fprofile-arcs # 3-myflags: -fprofile-arcs -Wall include(CheckCXXCompilerFlag) function(usFunctionCheckCompilerFlags FLAG_TO_TEST RESULT_VAR) if(FLAG_TO_TEST STREQUAL "") message(FATAL_ERROR "FLAG_TO_TEST shouldn't be empty") endif() + # Save the contents of RESULT_VAR temporarily. + # This is needed in case ${RESULT_VAR} is one of the CMAKE__FLAGS_* variables. + set(_saved_result_var ${${RESULT_VAR}}) + # Clear all flags. If not, existing flags triggering warnings might lead to # false-negatives when checking for certain compiler flags. set(CMAKE_C_FLAGS ) set(CMAKE_C_FLAGS_DEBUG ) set(CMAKE_C_FLAGS_MINSIZEREL ) set(CMAKE_C_FLAGS_RELEASE ) set(CMAKE_C_FLAGS_RELWITHDEBINFO ) set(CMAKE_CXX_FLAGS ) set(CMAKE_CXX_FLAGS_DEBUG ) set(CMAKE_CXX_FLAGS_MINSIZEREL ) set(CMAKE_CXX_FLAGS_RELEASE ) set(CMAKE_CXX_FLAGS_RELWITHDEBINFO ) # Internally, the macro CMAKE_CXX_COMPILER_FLAG calls TRY_COMPILE. To avoid # the cost of compiling the test each time the project is configured, the variable set by # the macro is added to the cache so that following invocation of the macro with # the same variable name skip the compilation step. # For that same reason, the usFunctionCheckCompilerFlags function appends a unique suffix to # the HAS_CXX_FLAG variable. This suffix is created using a 'clean version' of the # flag to test. The value of HAS_CXX_FLAG_${suffix} additonally needs to be a valid # pre-processor token because CHECK_CXX_COMPILER_FLAG adds it as a definition to the compiler # arguments. An invalid token triggers compiler warnings, which in case of the "-Werror" flag # leads to false-negative checks. string(REGEX REPLACE "[/-]" "_" suffix ${FLAG_TO_TEST}) string(REGEX REPLACE "[, \\$\\+\\*\\{\\}\\(\\)\\#]" "" suffix ${suffix}) CHECK_CXX_COMPILER_FLAG(${FLAG_TO_TEST} HAS_CXX_FLAG_${suffix}) if(HAS_CXX_FLAG_${suffix}) - set(${RESULT_VAR} "${${RESULT_VAR}} ${FLAG_TO_TEST}" PARENT_SCOPE) + set(${RESULT_VAR} "${_saved_result_var} ${FLAG_TO_TEST}" PARENT_SCOPE) endif() endfunction() diff --git a/Core/CppMicroServices/cmake/usFunctionEmbedResources.cmake b/Core/CppMicroServices/cmake/usFunctionEmbedResources.cmake index 6e9dbe8ce4..65d5add29d 100644 --- a/Core/CppMicroServices/cmake/usFunctionEmbedResources.cmake +++ b/Core/CppMicroServices/cmake/usFunctionEmbedResources.cmake @@ -1,147 +1,155 @@ #! \ingroup MicroServicesCMake #! \brief Embed resources into a shared library or executable. #! #! This CMake function uses an external command line program to generate a source #! file containing data from external resources such as text files or images. The path #! to the generated source file is appended to the \c src_var variable. #! #! Each module can call this function (at most once) to embed resources and make them #! available at runtime through the Module class. Resources can also be embedded into #! executables, using the EXECUTABLE_NAME argument instead of LIBRARY_NAME. #! #! Example usage: #! \code{.cmake} #! set(module_srcs ) #! usFunctionEmbedResources(module_srcs #! LIBRARY_NAME "mylib" #! ROOT_DIR resources #! FILES config.properties logo.png #! ) #! \endcode #! #! \param LIBRARY_NAME (required if EXECUTABLE_NAME is empty) The library name of the module #! which will include the generated source file, without extension. #! \param EXECUTABLE_NAME (required if LIBRARY_NAME is empty) The name of the executable #! which will include the generated source file. #! \param COMPRESSION_LEVEL (optional) The zip compression level. Defaults to the default zip #! level. Level 0 disables compression. #! \param COMPRESSION_THRESHOLD (optional) The compression threshold ranging from 0 to 100 for #! actually compressing the resource data. The default threshold is 30, meaning a size #! reduction of 30 percent or better results in the resource data being compressed. #! \param ROOT_DIR (optional) The root path for all resources listed after the FILES argument. #! If no or a relative path is given, it is considered relativ to the current CMake source directory. #! \param FILES (optional) A list of resources (paths to external files in the file system) relative #! to the ROOT_DIR argument or the current CMake source directory if ROOT_DIR is empty. #! #! The ROOT_DIR and FILES arguments may be repeated any number of times to merge files from #! different root directories into the embedded resource tree (hence the relative file paths #! after the FILES argument must be unique). #! function(usFunctionEmbedResources src_var) set(prefix US_RESOURCE) set(arg_names LIBRARY_NAME EXECUTABLE_NAME COMPRESSION_LEVEL COMPRESSION_THRESHOLD ROOT_DIR FILES) foreach(arg_name ${arg_names}) set(${prefix}_${arg_name}) endforeach(arg_name) set(cmd_line_args ) set(absolute_res_files ) set(current_arg_name DEFAULT_ARGS) set(current_arg_list) set(current_root_dir ${CMAKE_CURRENT_SOURCE_DIR}) foreach(arg ${ARGN}) list(FIND arg_names "${arg}" is_arg_name) if(is_arg_name GREATER -1) set(${prefix}_${current_arg_name} ${current_arg_list}) set(current_arg_name "${arg}") set(current_arg_list) else() set(current_arg_list ${current_arg_list} "${arg}") if(current_arg_name STREQUAL "ROOT_DIR") set(current_root_dir "${arg}") if(NOT IS_ABSOLUTE ${current_root_dir}) set(current_root_dir "${CMAKE_CURRENT_SOURCE_DIR}/${current_root_dir}") endif() if(NOT IS_DIRECTORY ${current_root_dir}) message(SEND_ERROR "The ROOT_DIR argument is not a directory: ${current_root_dir}") endif() get_filename_component(current_root_dir "${current_root_dir}" REALPATH) + if(WIN32) + string(REPLACE "/" "\\" current_root_dir "${current_root_dir}") + endif() list(APPEND cmd_line_args -d "${current_root_dir}") elseif(current_arg_name STREQUAL "FILES") set(res_file "${current_root_dir}/${arg}") - file(TO_NATIVE_PATH "${res_file}" res_file_native) + if(WIN32) + string(REPLACE "/" "\\" res_file_native "${res_file}") + else() + set(res_file_native "${res_file}") + endif() if(IS_DIRECTORY ${res_file}) message(SEND_ERROR "A resource cannot be a directory: ${res_file_native}") endif() if(NOT EXISTS ${res_file}) message(SEND_ERROR "Resource does not exists: ${res_file_native}") endif() list(APPEND absolute_res_files ${res_file}) - list(APPEND cmd_line_args "${arg}") + file(TO_NATIVE_PATH "${arg}" res_filename_native) + list(APPEND cmd_line_args "${res_filename_native}") endif() endif(is_arg_name GREATER -1) endforeach(arg ${ARGN}) set(${prefix}_${current_arg_name} ${current_arg_list}) if(NOT src_var) message(SEND_ERROR "Output variable name not specified.") endif() if(US_RESOURCE_EXECUTABLE_NAME AND US_RESOURCE_LIBRARY_NAME) message(SEND_ERROR "Only one of LIBRARY_NAME or EXECUTABLE_NAME can be specified.") endif() if(NOT US_RESOURCE_LIBRARY_NAME AND NOT US_RESOURCE_EXECUTABLE_NAME) message(SEND_ERROR "LIBRARY_NAME or EXECUTABLE_NAME argument not specified.") endif() if(NOT US_RESOURCE_FILES) message(WARNING "No FILES argument given. Skipping resource processing.") return() endif() list(GET cmd_line_args 0 first_arg) if(NOT first_arg STREQUAL "-d") set(cmd_line_args -d "${CMAKE_CURRENT_SOURCE_DIR}" ${cmd_line_args}) endif() if(US_RESOURCE_COMPRESSION_LEVEL) set(cmd_line_args -c ${US_RESOURCE_COMPRESSION_LEVEL} ${cmd_line_args}) endif() if(US_RESOURCE_COMPRESSION_THRESHOLD) set(cmd_line_args -t ${US_RESOURCE_COMPRESSION_THRESHOLD} ${cmd_line_args}) endif() if(US_RESOURCE_LIBRARY_NAME) set(us_cpp_resource_file "${CMAKE_CURRENT_BINARY_DIR}/${US_RESOURCE_LIBRARY_NAME}_resources.cpp") set(us_lib_name ${US_RESOURCE_LIBRARY_NAME}) else() set(us_cpp_resource_file "${CMAKE_CURRENT_BINARY_DIR}/${US_RESOURCE_EXECUTABLE_NAME}_resources.cpp") set(us_lib_name "") endif() set(resource_compiler ${CppMicroServices_RCC_EXECUTABLE}) if(TARGET ${CppMicroServices_RCC_EXECUTABLE_NAME}) set(resource_compiler ${CppMicroServices_RCC_EXECUTABLE_NAME}) elseif(NOT resource_compiler) message(FATAL_ERROR "The CppMicroServices resource compiler was not found. Check the CppMicroServices_RCC_EXECUTABLE CMake variable.") endif() add_custom_command( OUTPUT ${us_cpp_resource_file} COMMAND ${resource_compiler} "${us_lib_name}" ${us_cpp_resource_file} ${cmd_line_args} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${absolute_res_files} ${resource_compiler} COMMENT "Generating embedded resource file ${us_cpp_resource_name}" VERBATIM ) set(${src_var} "${${src_var}};${us_cpp_resource_file}" PARENT_SCOPE) endfunction() diff --git a/Core/CppMicroServices/core/test/usModuleTest.cpp b/Core/CppMicroServices/core/test/usModuleTest.cpp index db8f5fafc1..2194399d9b 100644 --- a/Core/CppMicroServices/core/test/usModuleTest.cpp +++ b/Core/CppMicroServices/core/test/usModuleTest.cpp @@ -1,343 +1,343 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics 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. =============================================================================*/ #include #include #include #include #include #include #include #include #include #include "usTestUtilModuleListener.h" #include "usTestingMacros.h" #include "usTestingConfig.h" US_USE_NAMESPACE namespace { #ifdef US_PLATFORM_WINDOWS static const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; static const char PATH_SEPARATOR = '\\'; #else static const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; static const char PATH_SEPARATOR = '/'; #endif // Verify that the same member function pointers registered as listeners // with different receivers works. void frame02a() { ModuleContext* mc = GetModuleContext(); TestModuleListener listener1; TestModuleListener listener2; try { mc->RemoveModuleListener(&listener1, &TestModuleListener::ModuleChanged); mc->AddModuleListener(&listener1, &TestModuleListener::ModuleChanged); mc->RemoveModuleListener(&listener2, &TestModuleListener::ModuleChanged); mc->AddModuleListener(&listener2, &TestModuleListener::ModuleChanged); } catch (const std::logic_error& ise) { US_TEST_FAILED_MSG( << "module listener registration failed " << ise.what() << " : frameSL02a:FAIL" ); } SharedLibrary target(LIB_PATH, "TestModuleA"); #ifdef US_BUILD_SHARED_LIBS // Start the test target try { target.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG( << "Failed to load module, got exception: " << e.what() << " + in frameSL02a:FAIL" ); } Module* moduleA = ModuleRegistry::GetModule("TestModuleA Module"); US_TEST_CONDITION_REQUIRED(moduleA != 0, "Test for existing module TestModuleA") #endif std::vector pEvts; #ifdef US_BUILD_SHARED_LIBS pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleA)); pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleA)); #endif std::vector seEvts; US_TEST_CONDITION(listener1.CheckListenerEvents(pEvts, seEvts), "Check first module listener") US_TEST_CONDITION(listener2.CheckListenerEvents(pEvts, seEvts), "Check second module listener") mc->RemoveModuleListener(&listener1, &TestModuleListener::ModuleChanged); mc->RemoveModuleListener(&listener2, &TestModuleListener::ModuleChanged); target.Unload(); } // Verify information from the ModuleInfo struct void frame005a(ModuleContext* mc) { Module* m = mc->GetModule(); // check expected headers #ifdef US_BUILD_SHARED_LIBS US_TEST_CONDITION("usCoreTestDriver" == m->GetName(), "Test module name") US_TEST_CONDITION(ModuleVersion(0,1,0) == m->GetVersion(), "Test test driver module version") US_TEST_CONDITION(ModuleVersion(CppMicroServices_MAJOR_VERSION, CppMicroServices_MINOR_VERSION, CppMicroServices_PATCH_VERSION) == ModuleRegistry::GetModule(1)->GetVersion(), "Test CppMicroServices version") #else US_TEST_CONDITION("CppMicroServices" == m->GetName(), "Test module name") - US_TEST_CONDITION(ModuleVersion(CppMicroServices_MAJOR_VERSION, CppMicroServices_MINOR_VERSION, CppMicroServices_PATCH_VERSION) == m->GetVersion(), "Test module version") + US_TEST_CONDITION(ModuleVersion(US_CORE_MAJOR_VERSION, US_CORE_MINOR_VERSION, US_CORE_PATCH_VERSION) == m->GetVersion(), "Test module version") #endif } // Get context id, location and status of the module void frame010a(ModuleContext* mc) { Module* m = mc->GetModule(); long int contextid = m->GetModuleId(); US_DEBUG << "CONTEXT ID:" << contextid; std::string location = m->GetLocation(); US_DEBUG << "LOCATION:" << location; US_TEST_CONDITION(!location.empty(), "Test for non-empty module location") US_TEST_CONDITION(m->IsLoaded(), "Test for loaded flag") US_TEST_CONDITION(ModuleSettings::GetStoragePath().empty(), "Test for empty base storage path") US_TEST_CONDITION(m->GetModuleContext()->GetDataFile("").empty(), "Test for empty data path") US_TEST_CONDITION(m->GetModuleContext()->GetDataFile("bla").empty(), "Test for empty data file path") } //---------------------------------------------------------------------------- //Test result of GetService(ServiceReference()). Should throw std::invalid_argument void frame018a(ModuleContext* mc) { try { mc->GetService(ServiceReferenceU()); US_DEBUG << "Got service object, expected std::invalid_argument exception"; US_TEST_FAILED_MSG(<< "Got service object, excpected std::invalid_argument exception") } catch (const std::invalid_argument& ) {} catch (...) { US_TEST_FAILED_MSG(<< "Got wrong exception, expected std::invalid_argument") } } // Load libA and check that it exists and that the service it registers exists, // also check that the expected events occur and that the storage paths are correct void frame020a(ModuleContext* mc, TestModuleListener& listener, #ifdef US_BUILD_SHARED_LIBS SharedLibrary& libA) { ModuleSettings::SetStoragePath(std::string("/tmp") + PATH_SEPARATOR); US_TEST_CONDITION(ModuleSettings::GetStoragePath() == "/tmp", "Test for valid base storage path") try { libA.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } Module* moduleA = ModuleRegistry::GetModule("TestModuleA Module"); US_TEST_CONDITION_REQUIRED(moduleA != 0, "Test for existing module TestModuleA") US_TEST_CONDITION(moduleA->GetName() == "TestModuleA Module", "Test module name") std::cout << moduleA->GetModuleContext()->GetDataFile(""); std::stringstream ss; ss << moduleA->GetModuleId(); const std::string baseStoragePath = std::string("/tmp") + PATH_SEPARATOR + ss.str() + "_TestModuleA" + PATH_SEPARATOR; US_TEST_CONDITION(moduleA->GetModuleContext()->GetDataFile("") == baseStoragePath, "Test for valid data path") US_TEST_CONDITION(moduleA->GetModuleContext()->GetDataFile("bla") == baseStoragePath + "bla", "Test for valid data file path") #else SharedLibrary& /*libA*/) { #endif // Check if libA registered the expected service try { ServiceReferenceU sr1 = mc->GetServiceReference("org.cppmicroservices.TestModuleAService"); InterfaceMap o1 = mc->GetService(sr1); US_TEST_CONDITION(!o1.empty(), "Test if service object found"); try { US_TEST_CONDITION(mc->UngetService(sr1), "Test if Service UnGet returns true"); } catch (const std::logic_error le) { US_TEST_FAILED_MSG(<< "UnGetService exception: " << le.what()) } // check the listeners for events std::vector pEvts; #ifdef US_BUILD_SHARED_LIBS pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleA)); pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleA)); #endif std::vector seEvts; #ifdef US_BUILD_SHARED_LIBS seEvts.push_back(ServiceEvent(ServiceEvent::REGISTERED, sr1)); #endif US_TEST_CONDITION(listener.CheckListenerEvents(pEvts, seEvts), "Test for unexpected events"); } catch (const ServiceException& /*se*/) { US_TEST_FAILED_MSG(<< "test module, expected service not found"); } #ifdef US_BUILD_SHARED_LIBS US_TEST_CONDITION(moduleA->IsLoaded() == true, "Test if loaded correctly"); #endif } // Unload libA and check for correct events void frame030b(ModuleContext* mc, TestModuleListener& listener, SharedLibrary& libA) { #ifdef US_BUILD_SHARED_LIBS Module* moduleA = ModuleRegistry::GetModule("TestModuleA Module"); US_TEST_CONDITION_REQUIRED(moduleA != 0, "Test for non-null module") #endif ServiceReferenceU sr1 = mc->GetServiceReference("org.cppmicroservices.TestModuleAService"); US_TEST_CONDITION(sr1, "Test for valid service reference") try { libA.Unload(); #ifdef US_BUILD_SHARED_LIBS US_TEST_CONDITION(moduleA->IsLoaded() == false, "Test for unloaded state") #endif } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "UnLoad module exception: " << e.what()) } std::vector pEvts; #ifdef US_BUILD_SHARED_LIBS pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADING, moduleA)); pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADED, moduleA)); #endif std::vector seEvts; #ifdef US_BUILD_SHARED_LIBS seEvts.push_back(ServiceEvent(ServiceEvent::UNREGISTERING, sr1)); #endif US_TEST_CONDITION(listener.CheckListenerEvents(pEvts, seEvts), "Test for unexpected events"); } struct LocalListener { void ServiceChanged(const ServiceEvent) {} }; // Add a service listener with a broken LDAP filter to Get an exception void frame045a(ModuleContext* mc) { LocalListener sListen1; std::string brokenFilter = "A broken LDAP filter"; try { mc->AddServiceListener(&sListen1, &LocalListener::ServiceChanged, brokenFilter); } catch (const std::invalid_argument& /*ia*/) { //assertEquals("InvalidSyntaxException.GetFilter should be same as input string", brokenFilter, ise.GetFilter()); } catch (...) { US_TEST_FAILED_MSG(<< "test module, wrong exception on broken LDAP filter:"); } } } // end unnamed namespace int usModuleTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ModuleTest"); frame02a(); ModuleContext* mc = GetModuleContext(); TestModuleListener listener; try { mc->AddModuleListener(&listener, &TestModuleListener::ModuleChanged); } catch (const std::logic_error& ise) { US_TEST_OUTPUT( << "module listener registration failed " << ise.what() ); throw; } try { mc->AddServiceListener(&listener, &TestModuleListener::ServiceChanged); } catch (const std::logic_error& ise) { US_TEST_OUTPUT( << "service listener registration failed " << ise.what() ); throw; } frame005a(mc); frame010a(mc); frame018a(mc); SharedLibrary libA(LIB_PATH, "TestModuleA"); frame020a(mc, listener, libA); frame030b(mc, listener, libA); frame045a(mc); mc->RemoveModuleListener(&listener, &TestModuleListener::ModuleChanged); mc->RemoveServiceListener(&listener, &TestModuleListener::ServiceChanged); US_TEST_END() }