diff --git a/Applications/mitkWorkbench/CMakeLists.txt b/Applications/mitkWorkbench/CMakeLists.txt index b32ad156a3..cd499afc9e 100644 --- a/Applications/mitkWorkbench/CMakeLists.txt +++ b/Applications/mitkWorkbench/CMakeLists.txt @@ -1,47 +1,51 @@ project(mitkWorkbench) set(_app_options) if(MITK_SHOW_CONSOLE_WINDOW) list(APPEND _app_options SHOW_CONSOLE) endif() MITK_USE_MODULE(qtsingleapplication Mitk) + +if(MITK_USE_Breakpad) +MITK_USE_MODULE(BreakpadCrashReporting) +endif() + include_directories(${ALL_INCLUDE_DIRECTORIES}) # Create a cache entry for the provisioning file which is used to export # the file name in the MITKConfig.cmake file. This will keep external projects # which rely on this file happy. set(MITK_EXTAPP_PROVISIONING_FILE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/mitkWorkbench.provisioning" CACHE INTERNAL "mitkWorkbench provisioning file" FORCE) # Plug-ins listed below will not be # - added as a build-time dependency to the executable # - listed in the provisioning file for the executable # - installed if they are external plug-ins set(_exclude_plugins org.blueberry.test org.blueberry.uitest org.mitk.gui.qt.coreapplication org.mitk.gui.qt.diffusionimagingapp ) FunctionCreateBlueBerryApplication( NAME mitkWorkbench DESCRIPTION "MITK Workbench" EXCLUDE_PLUGINS ${_exclude_plugins} LINK_LIBRARIES ${ALL_LIBRARIES} ${_app_options} ) #Setting application icon for mac os x systems set_target_properties(mitkWorkbench PROPERTIES MACOSX_BUNDLE_ICON_FILE "icon.icns") if(APPLE) install(FILES "icons/icon.icns" DESTINATION "mitkWorkbench.app/Contents/Resources") endif(APPLE) # Add a build time dependency to legacy BlueBerry bundles. if(MITK_MODULES_ENABLED_PLUGINS) add_dependencies(mitkWorkbench ${MITK_MODULES_ENABLED_PLUGINS}) endif() - diff --git a/Applications/mitkWorkbench/mitkWorkbench.cpp b/Applications/mitkWorkbench/mitkWorkbench.cpp index 94c97fa9e3..dfbb67a880 100644 --- a/Applications/mitkWorkbench/mitkWorkbench.cpp +++ b/Applications/mitkWorkbench/mitkWorkbench.cpp @@ -1,156 +1,161 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include +#include class QtSafeApplication : public QtSingleApplication { public: QtSafeApplication(int& argc, char** argv) : QtSingleApplication(argc, argv) {} /** * Reimplement notify to catch unhandled exceptions and open an error message. * * @param receiver * @param event * @return */ bool notify(QObject* receiver, QEvent* event) { QString msg; try { return QApplication::notify(receiver, event); } catch (mitk::Exception& e) { msg = QString("MITK Exception:\n\n") + QString("Desciption: ") + QString(e.GetDescription()) + QString("\n\n") + QString("Filename: ") + QString(e.GetFile()) + QString("\n\n") + QString("Line: ") + QString::number(e.GetLine()); } catch (Poco::Exception& e) { msg = QString::fromStdString(e.displayText()); } catch (std::exception& e) { msg = e.what(); } catch (...) { msg = "Unknown exception"; } MITK_ERROR << "An error occurred: " << msg.toStdString(); QMessageBox msgBox; msgBox.setText("An error occurred. You should save all data and quit the program to prevent possible data loss."); msgBox.setDetailedText(msg); msgBox.setIcon(QMessageBox::Critical); msgBox.addButton(trUtf8("Exit immediately"), QMessageBox::YesRole); msgBox.addButton(trUtf8("Ignore"), QMessageBox::NoRole); int ret = msgBox.exec(); switch(ret) { case 0: MITK_ERROR << "The program was closed."; this->closeAllWindows(); break; case 1: MITK_ERROR << "The error was ignored by the user. The program may be in a corrupt state and don't behave like expected!"; break; } return false; } }; int main(int argc, char** argv) { + mitk::BreakpadCrashReporting myBreakpad; + myBreakpad.StartCrashServer(true); + myBreakpad.InitializeClientHandler( true ); + // Create a QApplication instance first QtSafeApplication qSafeApp(argc, argv); qSafeApp.setApplicationName("MITK Workbench"); qSafeApp.setOrganizationName("DKFZ"); // This function checks if an instance is already running // and either sends a message to it (containing the command // line arguments) or checks if a new instance was forced by // providing the BlueBerry.newInstance command line argument. // In the latter case, a path to a temporary directory for // the new application's storage directory is returned. QString storageDir = handleNewAppInstance(&qSafeApp, argc, argv, "BlueBerry.newInstance"); // These paths replace the .ini file and are tailored for installation // packages created with CPack. If a .ini file is presented, it will // overwrite the settings in MapConfiguration Poco::Path basePath(argv[0]); basePath.setFileName(""); Poco::Path provFile(basePath); provFile.setFileName("mitkWorkbench.provisioning"); Poco::Path extPath(basePath); extPath.pushDirectory("ExtBundles"); std::string pluginDirs = extPath.toString(); Poco::Util::MapConfiguration* extConfig(new Poco::Util::MapConfiguration()); if (!storageDir.isEmpty()) { extConfig->setString(berry::Platform::ARG_STORAGE_DIR, storageDir.toStdString()); } extConfig->setString(berry::Platform::ARG_PLUGIN_DIRS, pluginDirs); extConfig->setString(berry::Platform::ARG_PROVISIONING, provFile.toString()); extConfig->setString(berry::Platform::ARG_APPLICATION, "org.mitk.qt.extapplication"); #ifdef Q_OS_WIN #define CTK_LIB_PREFIX #else #define CTK_LIB_PREFIX "lib" #endif // Preload the org.mitk.gui.qt.ext plug-in (and hence also QmitkExt) to speed // up a clean-cache start. This also works around bugs in older gcc and glibc implementations, // which have difficulties with multiple dynamic opening and closing of shared libraries with // many global static initializers. It also helps if dependent libraries have weird static // initialization methods and/or missing de-initialization code. extConfig->setString(berry::Platform::ARG_PRELOAD_LIBRARY, "liborg_mitk_gui_qt_ext," CTK_LIB_PREFIX "CTKDICOMCore:0.1"); // Seed the random number generator, once at startup. QTime time = QTime::currentTime(); qsrand((uint)time.msec()); // Run the workbench. return berry::Starter::Run(argc, argv, extConfig); } diff --git a/CMake/FindBreakpad.cmake b/CMake/FindBreakpad.cmake new file mode 100644 index 0000000000..c265885625 --- /dev/null +++ b/CMake/FindBreakpad.cmake @@ -0,0 +1,120 @@ +# Attempts to find a build directory of the Breakpad project (as provided by the MITK superbuild) +# +# Fills the following variables: +# Breakpad_FOUND +# Breakpad_INCLUDE_DIR +# Breakpad_LIBRARIES +# + +function(checkWindowsCompilerFlags) + # TODO simplify this with foreach and some string functions + set (WINDOWS_CXX_FLAGS_OK_ZI 0) + if ( CMAKE_CXX_FLAGS_DEBUG MATCHES .*/Zi.* ) + set(WINDOWS_CXX_FLAGS_OK_ZI 1) + endif() + if ( CMAKE_CXX_FLAGS_RELEASE MATCHES .*/Zi.* ) + set(WINDOWS_CXX_FLAGS_OK_ZI 1) + endif() + if ( CMAKE_CXX_FLAGS MATCHES .*/Zi.* ) + set(WINDOWS_CXX_FLAGS_OK_ZI 1) + endif() + + set (WINDOWS_C_FLAGS_OK_ZI 0) + if ( CMAKE_C_FLAGS_DEBUG MATCHES .*/Zi.* ) + set(WINDOWS_C_FLAGS_OK_ZI 1) + endif() + if ( CMAKE_C_FLAGS_RELEASE MATCHES .*/Zi.* ) + set(WINDOWS_C_FLAGS_OK_ZI 1) + endif() + if ( CMAKE_C_FLAGS MATCHES .*/Zi.* ) + set(WINDOWS_C_FLAGS_OK_ZI 1) + endif() + + if (NOT WINDOWS_CXX_FLAGS_OK_ZI) + message(WARNING "When using the breakpad crash reporting module, you should use the /Zi flag in CMAKE_CXX_FLAGS (_RELEASE)") + endif() + if (NOT WINDOWS_C_FLAGS_OK_ZI) + message(WARNING "When using the breakpad crash reporting module, you should use the /Zi flag in CMAKE_C_FLAGS (_RELEASE)") + endif() + +endfunction() + +function(checkLinuxCompilerFlags) + # TODO simplify this with foreach and some string functions + set (LINUX_CXX_FLAGS_OK_G 0) + if ( CMAKE_CXX_FLAGS_RELEASE MATCHES .*-g.* ) + set(LINUX_CXX_FLAGS_OK_G 1) + endif() + if ( CMAKE_CXX_FLAGS MATCHES .*-g.* ) + set(LINUX_CXX_FLAGS_OK_G 1) + endif() + + set (LINUX_C_FLAGS_OK_G 0) + if ( CMAKE_C_FLAGS_RELEASE MATCHES .*-g.* ) + set(LINUX_C_FLAGS_OK_G 1) + endif() + if ( CMAKE_C_FLAGS MATCHES .*-g.* ) + set(LINUX_C_FLAGS_OK_G 1) + endif() + + if (NOT LINUX_CXX_FLAGS_OK_G) + message(WARNING "When using the breakpad crash reporting module, you should use the -g flag in CMAKE_CXX_FLAGS (_RELEASE)") + endif() + if (NOT LINUX_C_FLAGS_OK_G) + message(WARNING "When using the breakpad crash reporting module, you should use the -g flag in CMAKE_C_FLAGS (_RELEASE)") + endif() + + +endfunction() + + + +# -------------------- end functions ---------------------------- + +find_path(Breakpad_INCLUDE_DIR breakpad_googletest_includes.h DOC "Directory breakpad/src/" PATHS ${Breakpad_SRC}/src ${Breakpad_DIR}) + +if(CMAKE_SYSTEM MATCHES "Windows") + + message(STATUS "Checking Windows build requirements for breakpad") + + checkWindowsCompilerFlags() # without debug information, Breakpad makes not much sense, so inform developer + + find_library(Breakpad_CLIENT_LIB crash_generation_client PATHS ${Breakpad_SRC}/src ${Breakpad_DIR} PATH_SUFFIXES Release Debug) + find_library(Breakpad_SERVER_LIB crash_generation_server PATHS ${Breakpad_SRC}/src ${Breakpad_DIR} PATH_SUFFIXES Release Debug) + find_library(Breakpad_EXCEPTIONHANDLER_LIB exception_handler PATHS ${Breakpad_SRC}/src ${Breakpad_DIR} PATH_SUFFIXES Release Debug) + find_library(Breakpad_COMMON_LIB common PATHS ${Breakpad_SRC}/src ${Breakpad_DIR} PATH_SUFFIXES Release Debug) + + set(Breakpad_LIBRARIES + ${Breakpad_CLIENT_LIB} + ${Breakpad_SERVER_LIB} + ${Breakpad_EXCEPTIONHANDLER_LIB} + ${Breakpad_COMMON_LIB} + ) + +elseif(CMAKE_SYSTEM MATCHES "Linux") + + message(STATUS "Checking Linux build requirements for breakpad") + + checkLinuxCompilerFlags() # without debug information, Breakpad makes not much sense, so inform developer + + find_library(Breakpad_CLIENT_LIB breakpad_client PATHS ${Breakpad_SRC}/src ${Breakpad_DIR}) + + set(Breakpad_LIBRARIES + ${Breakpad_CLIENT_LIB} + ) + +else() + message(FATAL_ERROR "Unsupported platform for Breakpad crash reporting: ${CMAKE_SYSTEM}") +endif() + +if (Breakpad_LIBRARIES MATCHES "NOTFOUND") + set(Breakpad_FOUND FALSE) +elseif(Breakpad_INCLUDE_DIR MATCHES "NOTFOUND") + set(Breakpad_FOUND FALSE) +else() + set(Breakpad_FOUND TRUE) +endif() + +#message(STATUS "FindBreakpad... found it: ${Breakpad_FOUND}") +#message(STATUS " .. include at ${Breakpad_INCLUDE_DIR}") +#message(STATUS " .. link libraries ${Breakpad_LIBRARIES}") diff --git a/CMakeExternals/Breakpad.cmake b/CMakeExternals/Breakpad.cmake new file mode 100644 index 0000000000..8a38a016b1 --- /dev/null +++ b/CMakeExternals/Breakpad.cmake @@ -0,0 +1,45 @@ +#----------------------------------------------------------------------------- +# Breakpad +#----------------------------------------------------------------------------- + +if(MITK_USE_Breakpad) + + # Sanity checks + if(DEFINED Breakpad_DIR AND NOT EXISTS ${Breakpad_DIR}) + message(FATAL_ERROR "Breakpad_DIR variable is defined but corresponds to non-existing directory") + endif() + + set(proj Breakpad) + set(proj_DEPENDENCIES ) + set(Breakpad_DEPENDS ${proj}) + + if(NOT DEFINED Breakpad_DIR) + + set(revision_tag 1140) + + ExternalProject_Add(${proj} + SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj}-src + BINARY_DIR ${proj}-build + PREFIX ${proj}-cmake + URL http://www.mint-medical.de/downloads/Breakpad_${revision_tag}.tar.gz + URL_MD5 36fd68dc0e21f049417a4969b220ee89 + #SVN_REPOSITORY http://google-breakpad.googlecode.com/svn/trunk + #SVN_REVISION -r ${revision_tag} + PATCH_COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/CMakeExternals/build-breakpad.cmake /CMakeLists.txt + UPDATE_COMMAND "" + INSTALL_COMMAND "" + CMAKE_GENERATOR ${gen} + CMAKE_ARGS + ${ep_common_args} + DEPENDS ${proj_DEPENDENCIES} + ) + set(Breakpad_DIR ${CMAKE_CURRENT_BINARY_DIR}/${proj}-build) + set(Breakpad_SRC ${CMAKE_CURRENT_BINARY_DIR}/${proj}-src) + + else() + + mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") + + endif() + +endif() diff --git a/CMakeExternals/build-breakpad.cmake b/CMakeExternals/build-breakpad.cmake new file mode 100644 index 0000000000..c986b740b1 --- /dev/null +++ b/CMakeExternals/build-breakpad.cmake @@ -0,0 +1,195 @@ +# CMakeLists.txt for Breakpad +# - supports builds on Windows and Linux only +# - needs to keep updated when updating the SVN revision in Breakpad.cmake +# - imitates the library structure of google's build system +# - does not build libraries which are not required by the MITK breakpad module + +cmake_minimum_required(VERSION 2.8) + +project (BreakpadForMITK CXX) + +if (WIN32) + + include_directories(src) + + # Windows... + set(exceptionhandler_CPPs + src/client/windows/handler/exception_handler.cc + ) + + set(server_CPPs + src/client/windows/crash_generation/client_info.cc + src/client/windows/crash_generation/crash_generation_server.cc + src/client/windows/crash_generation/minidump_generator.cc + ) + + set(client_CPPs + src/client/windows/crash_generation/crash_generation_client.cc + ) + + set(common_CPPs + src/common/convert_UTF.c + src/common/language.cc + src/common/string_conversion.cc + src/common/module.cc + src/common/windows/http_upload.cc + src/common/windows/string_utils.cc + src/common/windows/guid_string.cc + ) + + # this was copied from http://svn.code.sf.net/p/safir/svn/safir_sdk_core/trunk/src/lluf/lluf_crash_reporter.ss/src/google-breakpad/build-breakpad-windows.cmake + # check if this is actually required or not + add_definitions(-DBREAKPAD_NO_TERMINATE_THREAD) + add_definitions(-DUNICODE -D_UNICODE) + add_definitions(/wd4127 /wd4245) + + set_source_files_properties(src/common/convert_UTF.c PROPERTIES LANGUAGE CXX) # seems more simple than tell CMake about two compilers + # following line is inspired by breakpad issue 465 where the following definition was suggested as a patch for MSVC 2005/8 + # TODO: do we need a if MSVC2005/8? (check MITK requirements) + set_source_files_properties(src/client/windows/handler/exception_handler.cc PROPERTIES COMPILE_DEFINITIONS "STATUS_INVALID_PARAMETER=((DWORD)0xC000000DL)") + + include_directories(src) + + add_library(common STATIC ${common_CPPs}) + add_library(crash_generation_client STATIC ${client_CPPs}) + add_library(crash_generation_server STATIC ${server_CPPs}) + add_library(exception_handler STATIC ${exceptionhandler_CPPs}) + +else() + + # Linux + # commented code is not required right now and depends on other libraries (e.g. glog) + set(client_CPPs + src/client/minidump_file_writer.cc + src/client/linux/handler/minidump_descriptor.cc + src/client/linux/handler/exception_handler.cc + src/client/linux/log/log.cc + src/client/linux/minidump_writer/linux_core_dumper.cc + src/client/linux/minidump_writer/linux_ptrace_dumper.cc + src/client/linux/minidump_writer/linux_dumper.cc + src/client/linux/minidump_writer/minidump_writer.cc + src/client/linux/crash_generation/crash_generation_server.cc + src/client/linux/crash_generation/crash_generation_client.cc + ) + + set(common_CPPs + src/common/convert_UTF.c + src/common/md5.cc + src/common/language.cc + src/common/dwarf_cfi_to_module.cc + src/common/dwarf_line_to_module.cc + src/common/string_conversion.cc + src/common/stabs_reader.cc + src/common/module.cc + src/common/dwarf_cu_to_module.cc + src/common/stabs_to_module.cc + src/common/test_assembler.cc + src/common/dwarf/bytereader.cc + src/common/dwarf/cfi_assembler.cc + src/common/dwarf/dwarf2diehandler.cc + src/common/dwarf/dwarf2reader.cc + src/common/dwarf/functioninfo.cc + src/common/linux/libcurl_wrapper.cc + src/common/linux/safe_readlink.cc + src/common/linux/http_upload.cc + src/common/linux/google_crashdump_uploader.cc + src/common/linux/elf_symbols_to_module.cc + src/common/linux/guid_creator.cc + src/common/linux/memory_mapped_file.cc + src/common/linux/linux_libc_support.cc + src/common/linux/dump_symbols.cc + src/common/linux/file_id.cc + src/common/linux/synth_elf.cc + src/common/linux/elfutils.cc + src/common/linux/elf_core_dump.cc + ) + + set(processor_CPPs + src/processor/basic_code_modules.cc + src/processor/basic_source_line_resolver.cc + src/processor/binarystream.cc + src/processor/call_stack.cc + src/processor/cfi_frame_info.cc + src/processor/disassembler_x86.cc + src/processor/exploitability.cc + src/processor/exploitability_win.cc + src/processor/fast_source_line_resolver.cc + src/processor/logging.cc + src/processor/minidump.cc + src/processor/minidump_processor.cc + src/processor/module_comparer.cc + src/processor/module_serializer.cc + src/processor/pathname_stripper.cc + src/processor/process_state.cc + src/processor/simple_symbol_supplier.cc + src/processor/source_line_resolver_base.cc + src/processor/stack_frame_symbolizer.cc + src/processor/stackwalker_amd64.cc + src/processor/stackwalker_arm.cc + src/processor/stackwalker.cc + src/processor/stackwalker_ppc.cc + src/processor/stackwalker_sparc.cc + src/processor/stackwalker_x86.cc + src/processor/synth_minidump.cc + src/processor/tokenize.cc + ) + + set(libdisasm_Cs + src/third_party/libdisasm/ia32_implicit.c + src/third_party/libdisasm/ia32_insn.c + src/third_party/libdisasm/ia32_invariant.c + src/third_party/libdisasm/ia32_modrm.c + src/third_party/libdisasm/ia32_opcode_tables.c + src/third_party/libdisasm/ia32_operand.c + src/third_party/libdisasm/ia32_reg.c + src/third_party/libdisasm/ia32_settings.c + src/third_party/libdisasm/x86_disasm.c + src/third_party/libdisasm/x86_format.c + src/third_party/libdisasm/x86_imm.c + src/third_party/libdisasm/x86_insn.c + src/third_party/libdisasm/x86_misc.c + src/third_party/libdisasm/x86_operand_list.c + ) + + # commented code is not required right now and depends on other libraries (e.g. glog) + set_source_files_properties(src/common/convert_UTF.c PROPERTIES LANGUAGE CXX) # seems more simple than tell CMake about two compilers + set_source_files_properties(src/common/stabs_reader.cc PROPERTIES COMPILE_DEFINITIONS "N_UNDF=0x00") + include_directories(src) + add_definitions(-fPIC) + + # the client library. This would be enough for dumping dumps + add_library(breakpad_client STATIC + ${client_CPPs} + ${common_CPPs} + ) + + # to create symbol files that make dumps readable, we need the dump_syms tool + add_executable(dump_syms src/tools/linux/dump_syms/dump_syms.cc) + target_link_libraries(dump_syms breakpad_client) + + # to display stacktraces by combination of dumps and symbol files, we need minidump_stackwalk + # the disasm library needs to be translated by C, not C++ + # the following lines seem unnecessary complicated because they use g++ with a -x c switch to compile C + + if(NOT CMAKE_C_CREATE_STATIC_LIBRARY) + SET(CMAKE_C_CREATE_STATIC_LIBRARY " cr ") + endif(NOT CMAKE_C_CREATE_STATIC_LIBRARY) + + IF(NOT CMAKE_C_COMPILE_OBJECT) + SET(CMAKE_C_COMPILE_OBJECT " -o -x c -c ") + ENDIF(NOT CMAKE_C_COMPILE_OBJECT) + + foreach (source ${libdisasm_Cs}) + set_source_files_properties(${source} PROPERTIES LANGUAGE "C") + endforeach() + + add_library(disasm STATIC ${libdisasm_Cs}) + set_target_properties(disasm PROPERTIES LINKER_LANGUAGE "C") + + add_library(processor STATIC ${processor_CPPs}) + target_link_libraries(processor disasm) + + add_executable(minidump_stackwalk src/processor/minidump_stackwalk.cc) + target_link_libraries(minidump_stackwalk breakpad_client processor) + +endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a5a4cd041..b6cd5dc478 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,944 +1,945 @@ if(APPLE) # With XCode 4.3, the SDK location changed. Older CMake # versions are not able to find it. cmake_minimum_required(VERSION 2.8.8) else() cmake_minimum_required(VERSION 2.8.5) endif() #----------------------------------------------------------------------------- # 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() #----------------------------------------------------------------------------- # Superbuild Option - Enabled by default #----------------------------------------------------------------------------- option(MITK_USE_SUPERBUILD "Build MITK and the projects it depends on via SuperBuild.cmake." ON) if(MITK_USE_SUPERBUILD) project(MITK-superbuild) set(MITK_SOURCE_DIR ${PROJECT_SOURCE_DIR}) set(MITK_BINARY_DIR ${PROJECT_BINARY_DIR}) else() project(MITK) endif() #----------------------------------------------------------------------------- # Warn if source or build path is too long #----------------------------------------------------------------------------- if(WIN32) set(_src_dir_length_max 50) set(_bin_dir_length_max 50) if(MITK_USE_SUPERBUILD) set(_src_dir_length_max 43) # _src_dir_length_max - strlen(ITK-src) set(_bin_dir_length_max 40) # _bin_dir_length_max - strlen(MITK-build) endif() string(LENGTH "${MITK_SOURCE_DIR}" _src_n) string(LENGTH "${MITK_BINARY_DIR}" _bin_n) # The warnings should be converted to errors if(_src_n GREATER _src_dir_length_max) message(WARNING "MITK source code directory path length is too long (${_src_n} > ${_src_dir_length_max})." "Please move the MITK source code directory to a directory with a shorter path." ) endif() if(_bin_n GREATER _bin_dir_length_max) message(WARNING "MITK build directory path length is too long (${_bin_n} > ${_bin_dir_length_max})." "Please move the MITK build directory to a directory with a shorter path." ) endif() endif() #----------------------------------------------------------------------------- # See http://cmake.org/cmake/help/cmake-2-8-docs.html#section_Policies for details #----------------------------------------------------------------------------- set(project_policies CMP0001 # NEW: CMAKE_BACKWARDS_COMPATIBILITY should no longer be used. CMP0002 # NEW: Logical target names must be globally unique. CMP0003 # NEW: Libraries linked via full path no longer produce linker search paths. CMP0004 # NEW: Libraries linked may NOT have leading or trailing whitespace. CMP0005 # NEW: Preprocessor definition values are now escaped automatically. CMP0006 # NEW: Installing MACOSX_BUNDLE targets requires a BUNDLE DESTINATION. CMP0007 # NEW: List command no longer ignores empty elements. CMP0008 # NEW: Libraries linked by full-path must have a valid library file name. CMP0009 # NEW: FILE GLOB_RECURSE calls should not follow symlinks by default. CMP0010 # NEW: Bad variable reference syntax is an error. CMP0011 # NEW: Included scripts do automatic cmake_policy PUSH and POP. CMP0012 # NEW: if() recognizes numbers and boolean constants. CMP0013 # NEW: Duplicate binary directories are not allowed. CMP0014 # NEW: Input directories must have CMakeLists.txt ) foreach(policy ${project_policies}) if(POLICY ${policy}) cmake_policy(SET ${policy} NEW) endif() endforeach() #----------------------------------------------------------------------------- # Update CMake module path #------------------------------------------------------------------------------ set(CMAKE_MODULE_PATH ${MITK_SOURCE_DIR}/CMake ${CMAKE_MODULE_PATH} ) #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(mitkMacroEmptyExternalProject) include(mitkFunctionGenerateProjectXml) include(mitkFunctionSuppressWarnings) SUPPRESS_VC_DEPRECATED_WARNINGS() #----------------------------------------------------------------------------- # Output directories. #----------------------------------------------------------------------------- foreach(type LIBRARY RUNTIME ARCHIVE) # Make sure the directory exists if(DEFINED MITK_CMAKE_${type}_OUTPUT_DIRECTORY AND NOT EXISTS ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}) message("Creating directory MITK_CMAKE_${type}_OUTPUT_DIRECTORY: ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}") file(MAKE_DIRECTORY "${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}") endif() if(MITK_USE_SUPERBUILD) set(output_dir ${MITK_BINARY_DIR}/bin) if(NOT DEFINED MITK_CMAKE_${type}_OUTPUT_DIRECTORY) set(MITK_CMAKE_${type}_OUTPUT_DIRECTORY ${MITK_BINARY_DIR}/MITK-build/bin) endif() else() if(NOT DEFINED MITK_CMAKE_${type}_OUTPUT_DIRECTORY) set(output_dir ${MITK_BINARY_DIR}/bin) else() set(output_dir ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}) endif() endif() set(CMAKE_${type}_OUTPUT_DIRECTORY ${output_dir} CACHE INTERNAL "Single output directory for building all libraries.") mark_as_advanced(CMAKE_${type}_OUTPUT_DIRECTORY) endforeach() #----------------------------------------------------------------------------- # Additional MITK Options (also shown during superbuild) #----------------------------------------------------------------------------- option(BUILD_SHARED_LIBS "Build MITK with shared libraries" ON) option(WITH_COVERAGE "Enable/Disable coverage" OFF) option(BUILD_TESTING "Test the project" ON) option(MITK_BUILD_ALL_APPS "Build all MITK applications" OFF) set(MITK_BUILD_TUTORIAL OFF CACHE INTERNAL "Deprecated! Use MITK_BUILD_EXAMPLES instead!") option(MITK_BUILD_EXAMPLES "Build the MITK Examples" ${MITK_BUILD_TUTORIAL}) option(MITK_USE_ACVD "Use Approximated Centroidal Voronoi Diagrams" OFF) option(MITK_USE_Boost "Use the Boost C++ library" OFF) option(MITK_USE_BLUEBERRY "Build the BlueBerry platform" ON) +option(MITK_USE_Breakpad "Use Breakpad crash reporting in MITK" ${MITK_USE_Breakpad}) option(MITK_USE_CTK "Use CTK in MITK" ${MITK_USE_BLUEBERRY}) option(MITK_USE_QT "Use Nokia's Qt library" ${MITK_USE_CTK}) option(MITK_USE_DCMTK "EXPERIMENTAL, superbuild only: Use DCMTK in MITK" ${MITK_USE_CTK}) option(MITK_DCMTK_BUILD_SHARED_LIBS "EXPERIMENTAL, superbuild only: build DCMTK as shared libs" OFF) option(MITK_USE_OpenCV "Use Intel's OpenCV library" OFF) option(MITK_USE_OpenCL "Use OpenCL GPU-Computing library" OFF) option(MITK_USE_SOFA "Use Simulation Open Framework Architecture" OFF) option(MITK_USE_Python "Use Python wrapping in MITK" OFF) set(MITK_USE_CableSwig ${MITK_USE_Python}) if(MITK_USE_Python) FIND_PACKAGE(PythonLibs REQUIRED) FIND_PACKAGE(PythonInterp REQUIRED) endif() mark_as_advanced(MITK_BUILD_ALL_APPS MITK_USE_CTK MITK_USE_DCMTK ) if(MITK_USE_Boost) option(MITK_USE_SYSTEM_Boost "Use the system Boost" OFF) set(MITK_USE_Boost_LIBRARIES "" CACHE STRING "A semi-colon separated list of required Boost libraries") endif() if(MITK_USE_BLUEBERRY) option(MITK_BUILD_ALL_PLUGINS "Build all MITK plugins" OFF) mark_as_advanced(MITK_BUILD_ALL_PLUGINS) if(NOT MITK_USE_CTK) message("Forcing MITK_USE_CTK to ON because of MITK_USE_BLUEBERRY") set(MITK_USE_CTK ON CACHE BOOL "Use CTK in MITK" FORCE) endif() endif() if(MITK_USE_CTK) if(NOT MITK_USE_QT) message("Forcing MITK_USE_QT to ON because of MITK_USE_CTK") set(MITK_USE_QT ON CACHE BOOL "Use Nokia's Qt library in MITK" FORCE) endif() if(NOT MITK_USE_DCMTK) message("Setting MITK_USE_DCMTK to ON because DCMTK needs to be build for CTK") set(MITK_USE_DCMTK ON CACHE BOOL "Use DCMTK in MITK" FORCE) endif() endif() if(MITK_USE_QT) # find the package at the very beginning, so that QT4_FOUND is available find_package(Qt4 4.6.2 REQUIRED) endif() if(MITK_USE_SOFA) set(SOFA_CMAKE_VERSION 2.8.8) if(${CMAKE_VERSION} VERSION_LESS ${SOFA_CMAKE_VERSION} OR APPLE) set(MITK_USE_SOFA OFF CACHE BOOL "" FORCE) message(WARNING "Switched off MITK_USE_SOFA\n Minimum required CMake version: ${SOFA_CMAKE_VERSION}\n Installed CMake version: ${CMAKE_VERSION}") endif() endif() # Customize the default pixel types for multiplex macros set(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES "int, unsigned int, short, unsigned short, char, unsigned char" CACHE STRING "List of integral pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES "double, float" CACHE STRING "List of floating pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES "itk::RGBPixel, itk::RGBAPixel" CACHE STRING "List of composite pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_DIMENSIONS "2,3" CACHE STRING "List of dimensions used in AccessByItk and InstantiateAccessFunction macros") mark_as_advanced(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES MITK_ACCESSBYITK_DIMENSIONS ) # consistency checks if(NOT MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES) set(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES "int, unsigned int, short, unsigned short, char, unsigned char" CACHE STRING "List of integral pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES) set(MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES "double, float" CACHE STRING "List of floating pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES) set(MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES "itk::RGBPixel, itk::RGBAPixel" CACHE STRING "List of composite pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_DIMENSIONS) set(MITK_ACCESSBYITK_DIMENSIONS "2,3" CACHE STRING "List of dimensions used in AccessByItk and InstantiateAccessFunction macros") endif() #----------------------------------------------------------------------------- # Project.xml #----------------------------------------------------------------------------- # A list of topologically ordered targets set(CTEST_PROJECT_SUBPROJECTS) if(MITK_USE_BLUEBERRY) list(APPEND CTEST_PROJECT_SUBPROJECTS BlueBerry) endif() list(APPEND CTEST_PROJECT_SUBPROJECTS MITK-Core MITK-CoreUI MITK-IGT MITK-ToF MITK-DTI MITK-Registration MITK-Modules # all modules not contained in a specific subproject MITK-Plugins # all plugins not contained in a specific subproject MITK-Examples Unlabeled # special "subproject" catching all unlabeled targets and tests ) # Configure CTestConfigSubProject.cmake that could be used by CTest scripts configure_file(${MITK_SOURCE_DIR}/CTestConfigSubProject.cmake.in ${MITK_BINARY_DIR}/CTestConfigSubProject.cmake) if(CTEST_PROJECT_ADDITIONAL_TARGETS) # those targets will be executed at the end of the ctest driver script # and they also get their own subproject label set(subproject_list "${CTEST_PROJECT_SUBPROJECTS};${CTEST_PROJECT_ADDITIONAL_TARGETS}") else() set(subproject_list "${CTEST_PROJECT_SUBPROJECTS}") endif() # Generate Project.xml file expected by the CTest driver script mitkFunctionGenerateProjectXml(${MITK_BINARY_DIR} MITK "${subproject_list}" ${MITK_USE_SUPERBUILD}) #----------------------------------------------------------------------------- # Superbuild script #----------------------------------------------------------------------------- if(MITK_USE_SUPERBUILD) include("${CMAKE_CURRENT_SOURCE_DIR}/SuperBuild.cmake") return() endif() #***************************************************************************** #**************************** END OF SUPERBUILD **************************** #***************************************************************************** #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(CheckCXXSourceCompiles) include(mitkFunctionCheckCompilerFlags) include(mitkFunctionGetGccVersion) include(MacroParseArguments) include(mitkFunctionSuppressWarnings) # includes several functions include(mitkFunctionOrganizeSources) include(mitkFunctionGetVersion) include(mitkFunctionGetVersionDescription) include(mitkFunctionCreateWindowsBatchScript) include(mitkFunctionInstallProvisioningFiles) include(mitkFunctionInstallAutoLoadModules) include(mitkFunctionGetLibrarySearchPaths) include(mitkFunctionCompileSnippets) include(mitkMacroCreateModuleConf) include(mitkMacroCreateModule) include(mitkMacroCheckModule) include(mitkMacroCreateModuleTests) include(mitkFunctionAddCustomModuleTest) include(mitkMacroUseModule) include(mitkMacroMultiplexPicType) include(mitkMacroInstall) include(mitkMacroInstallHelperApp) include(mitkMacroInstallTargets) include(mitkMacroGenerateToolsLibrary) include(mitkMacroGetLinuxDistribution) include(mitkMacroGetPMDPlatformString) #----------------------------------------------------------------------------- # Prerequesites #----------------------------------------------------------------------------- find_package(ITK REQUIRED) find_package(VTK REQUIRED) find_package(GDCM PATHS ${ITK_GDCM_DIR} REQUIRED) include(${GDCM_USE_FILE}) #----------------------------------------------------------------------------- # Set MITK specific options and variables (NOT available during superbuild) #----------------------------------------------------------------------------- # ASK THE USER TO SHOW THE CONSOLE WINDOW FOR CoreApp and mitkWorkbench option(MITK_SHOW_CONSOLE_WINDOW "Use this to enable or disable the console window when starting MITK GUI Applications" ON) mark_as_advanced(MITK_SHOW_CONSOLE_WINDOW) # TODO: check if necessary option(USE_ITKZLIB "Use the ITK zlib for pic compression." ON) mark_as_advanced(USE_ITKZLIB) if(NOT MITK_FAST_TESTING) if(DEFINED MITK_CTEST_SCRIPT_MODE AND (MITK_CTEST_SCRIPT_MODE STREQUAL "continuous" OR MITK_CTEST_SCRIPT_MODE STREQUAL "experimental") ) set(MITK_FAST_TESTING 1) endif() endif() #----------------------------------------------------------------------------- # Get MITK version info #----------------------------------------------------------------------------- mitkFunctionGetVersion(${MITK_SOURCE_DIR} MITK) mitkFunctionGetVersionDescription(${MITK_SOURCE_DIR} MITK) #----------------------------------------------------------------------------- # Installation preparation # # These should be set before any MITK install macros are used #----------------------------------------------------------------------------- # on Mac OSX all BlueBerry plugins get copied into every # application bundle (.app directory) specified here if(MITK_USE_BLUEBERRY AND APPLE) include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/AppList.cmake") foreach(mitk_app ${MITK_APPS}) # extract option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 1 option_name) list(GET target_info_list 0 app_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) set(MACOSX_BUNDLE_NAMES ${MACOSX_BUNDLE_NAMES} ${app_name}) endif() endforeach() endif() #----------------------------------------------------------------------------- # Set symbol visibility Flags #----------------------------------------------------------------------------- # MinGW does not export all symbols automatically, so no need to set flags if(CMAKE_COMPILER_IS_GNUCXX AND NOT MINGW) set(VISIBILITY_CXX_FLAGS ) #"-fvisibility=hidden -fvisibility-inlines-hidden") endif() #----------------------------------------------------------------------------- # Set coverage Flags #----------------------------------------------------------------------------- if(WITH_COVERAGE) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(coverage_flags "-g -fprofile-arcs -ftest-coverage -O0 -DNDEBUG") set(COVERAGE_CXX_FLAGS ${coverage_flags}) set(COVERAGE_C_FLAGS ${coverage_flags}) endif() endif() #----------------------------------------------------------------------------- # MITK C/CXX Flags #----------------------------------------------------------------------------- set(MITK_C_FLAGS "${COVERAGE_C_FLAGS}") set(MITK_C_FLAGS_DEBUG ) set(MITK_C_FLAGS_RELEASE ) set(MITK_CXX_FLAGS "${VISIBILITY_CXX_FLAGS} ${COVERAGE_CXX_FLAGS}") set(MITK_CXX_FLAGS_DEBUG ) set(MITK_CXX_FLAGS_RELEASE ) set(MITK_EXE_LINKER_FLAGS ) set(MITK_SHARED_LINKER_FLAGS ) include(mitkSetupC++0xVariables) if(WIN32) set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} -D_WIN32_WINNT=0x0501 -DPOCO_NO_UNWINDOWS -DWIN32_LEAN_AND_MEAN") set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} /wd4231") # warning C4231: nonstandard extension used : 'extern' before template explicit instantiation endif() if(NOT MSVC_VERSION) foreach(_flag -Wall -Wextra -Wpointer-arith -Winvalid-pch -Wcast-align -Wwrite-strings -Wno-error=gnu -Woverloaded-virtual -Wstrict-null-sentinel #-Wold-style-cast #-Wsign-promo # the following two lines should be removed after ITK-3097 has # been resolved, see also MITK bug 15279 -Wno-unused-local-typedefs -Wno-array-bounds -fdiagnostics-show-option ) mitkFunctionCheckCAndCXXCompilerFlags(${_flag} MITK_C_FLAGS MITK_CXX_FLAGS) endforeach() endif() if(CMAKE_COMPILER_IS_GNUCXX) mitkFunctionCheckCompilerFlags("-Wl,--no-undefined" MITK_SHARED_LINKER_FLAGS) mitkFunctionCheckCompilerFlags("-Wl,--as-needed" MITK_SHARED_LINKER_FLAGS) if(MITK_USE_C++0x) mitkFunctionCheckCompilerFlags("-std=c++0x" MITK_CXX_FLAGS) endif() mitkFunctionGetGccVersion(${CMAKE_CXX_COMPILER} GCC_VERSION) # With older version of gcc supporting the flag -fstack-protector-all, an extra dependency to libssp.so # is introduced. If gcc is smaller than 4.4.0 and the build type is Release let's not include the flag. # Doing so should allow to build package made for distribution using older linux distro. if(${GCC_VERSION} VERSION_GREATER "4.4.0" OR (CMAKE_BUILD_TYPE STREQUAL "Debug" AND ${GCC_VERSION} VERSION_LESS "4.4.0")) mitkFunctionCheckCAndCXXCompilerFlags("-fstack-protector-all" MITK_C_FLAGS MITK_CXX_FLAGS) endif() if(MINGW) # suppress warnings about auto imported symbols set(MITK_SHARED_LINKER_FLAGS "-Wl,--enable-auto-import ${MITK_SHARED_LINKER_FLAGS}") endif() set(MITK_CXX_FLAGS_RELEASE "-D_FORTIFY_SOURCE=2 ${MITK_CXX_FLAGS_RELEASE}") endif() set(MITK_MODULE_LINKER_FLAGS ${MITK_SHARED_LINKER_FLAGS}) set(MITK_EXE_LINKER_FLAGS ${MITK_SHARED_LINKER_FLAGS}) #----------------------------------------------------------------------------- # MITK Packages #----------------------------------------------------------------------------- set(MITK_MODULES_PACKAGE_DEPENDS_DIR ${MITK_SOURCE_DIR}/CMake/PackageDepends) set(MODULES_PACKAGE_DEPENDS_DIRS ${MITK_MODULES_PACKAGE_DEPENDS_DIR}) #----------------------------------------------------------------------------- # Testing #----------------------------------------------------------------------------- if(BUILD_TESTING) enable_testing() include(CTest) mark_as_advanced(TCL_TCLSH DART_ROOT) option(MITK_ENABLE_GUI_TESTING OFF "Enable the MITK GUI tests") # Setup file for setting custom ctest vars configure_file( CMake/CTestCustom.cmake.in ${MITK_BINARY_DIR}/CTestCustom.cmake @ONLY ) # Configuration for the CMake-generated test driver set(CMAKE_TESTDRIVER_EXTRA_INCLUDES "#include ") set(CMAKE_TESTDRIVER_BEFORE_TESTMAIN " try {") set(CMAKE_TESTDRIVER_AFTER_TESTMAIN " } catch( std::exception & excp ) { fprintf(stderr,\"%s\\n\",excp.what()); return EXIT_FAILURE; } catch( ... ) { printf(\"Exception caught in the test driver\\n\"); return EXIT_FAILURE; } ") set(MITK_TEST_OUTPUT_DIR "${MITK_BINARY_DIR}/test_output") if(NOT EXISTS ${MITK_TEST_OUTPUT_DIR}) file(MAKE_DIRECTORY ${MITK_TEST_OUTPUT_DIR}) endif() # Test the external project template if(MITK_USE_BLUEBERRY) include(mitkTestProjectTemplate) endif() # Test the package target include(mitkPackageTest) endif() configure_file(mitkTestingConfig.h.in ${MITK_BINARY_DIR}/mitkTestingConfig.h) #----------------------------------------------------------------------------- # MITK_SUPERBUILD_BINARY_DIR #----------------------------------------------------------------------------- # If MITK_SUPERBUILD_BINARY_DIR isn't defined, it means MITK is *NOT* build using Superbuild. # In that specific case, MITK_SUPERBUILD_BINARY_DIR should default to MITK_BINARY_DIR if(NOT DEFINED MITK_SUPERBUILD_BINARY_DIR) set(MITK_SUPERBUILD_BINARY_DIR ${MITK_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # Compile Utilities and set-up MITK variables #----------------------------------------------------------------------------- include(mitkSetupVariables) #----------------------------------------------------------------------------- # Cleanup #----------------------------------------------------------------------------- file(GLOB _MODULES_CONF_FILES ${PROJECT_BINARY_DIR}/${MODULES_CONF_DIRNAME}/*.cmake) if(_MODULES_CONF_FILES) file(REMOVE ${_MODULES_CONF_FILES}) endif() add_subdirectory(Utilities) if(MITK_USE_BLUEBERRY) # We need to hack a little bit because MITK applications may need # to enable certain BlueBerry plug-ins. However, these plug-ins # are validated separately from the MITK plug-ins and know nothing # about potential MITK plug-in dependencies of the applications. Hence # we cannot pass the MITK application list to the BlueBerry # ctkMacroSetupPlugins call but need to extract the BlueBerry dependencies # from the applications and set them explicitly. include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/AppList.cmake") foreach(mitk_app ${MITK_APPS}) # extract target_dir and option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 0 target_dir) list(GET target_info_list 1 option_name) # check if the application is enabled and if target_libraries.cmake exists if((${option_name} OR MITK_BUILD_ALL_APPS) AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/Applications/${target_dir}/target_libraries.cmake") include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/${target_dir}/target_libraries.cmake") foreach(_target_dep ${target_libraries}) if(_target_dep MATCHES org_blueberry_) string(REPLACE _ . _app_bb_dep ${_target_dep}) # explicitly set the build option for the BlueBerry plug-in set(BLUEBERRY_BUILD_${_app_bb_dep} ON CACHE BOOL "Build the ${_app_bb_dep} plug-in") endif() endforeach() endif() endforeach() set(mbilog_DIR "${mbilog_BINARY_DIR}") if(MITK_BUILD_ALL_PLUGINS) set(BLUEBERRY_BUILD_ALL_PLUGINS ON) endif() set(BLUEBERRY_XPDOC_OUTPUT_DIR ${MITK_DOXYGEN_OUTPUT_DIR}/html/extension-points/html/) add_subdirectory(BlueBerry) set(BlueBerry_DIR ${CMAKE_CURRENT_BINARY_DIR}/BlueBerry CACHE PATH "The directory containing a CMake configuration file for BlueBerry" FORCE) include(mitkMacroCreateCTKPlugin) endif() #----------------------------------------------------------------------------- # Set C/CXX and linker flags for MITK code #----------------------------------------------------------------------------- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MITK_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${MITK_CXX_FLAGS_DEBUG}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${MITK_CXX_FLAGS_RELEASE}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MITK_C_FLAGS}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${MITK_C_FLAGS_DEBUG}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${MITK_C_FLAGS_RELEASE}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MITK_EXE_LINKER_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${MITK_SHARED_LINKER_FLAGS}") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${MITK_MODULE_LINKER_FLAGS}") if(MITK_USE_QT) add_definitions(-DQWT_DLL) endif() #----------------------------------------------------------------------------- # Add custom targets representing CDash subprojects #----------------------------------------------------------------------------- foreach(subproject ${CTEST_PROJECT_SUBPROJECTS}) if(NOT TARGET ${subproject} AND NOT subproject MATCHES "Unlabeled") add_custom_target(${subproject}) endif() endforeach() #----------------------------------------------------------------------------- # Add subdirectories #----------------------------------------------------------------------------- link_directories(${MITK_LINK_DIRECTORIES}) add_subdirectory(Core) add_subdirectory(Modules) if(MITK_USE_BLUEBERRY) find_package(BlueBerry REQUIRED) set(MITK_DEFAULT_SUBPROJECTS MITK-Plugins) # Plug-in testing (needs some work to be enabled again) if(BUILD_TESTING) include(berryTestingHelpers) set(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/CoreApp") get_target_property(_is_macosx_bundle CoreApp MACOSX_BUNDLE) if(APPLE AND _is_macosx_bundle) set(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/CoreApp.app/Contents/MacOS/CoreApp") endif() set(BLUEBERRY_TEST_APP_ID "org.mitk.qt.coreapplication") endif() include("${CMAKE_CURRENT_SOURCE_DIR}/Plugins/PluginList.cmake") set(mitk_plugins_fullpath ) foreach(mitk_plugin ${MITK_EXT_PLUGINS}) list(APPEND mitk_plugins_fullpath Plugins/${mitk_plugin}) endforeach() if(EXISTS ${MITK_PRIVATE_MODULES}/PluginList.cmake) include(${MITK_PRIVATE_MODULES}/PluginList.cmake) foreach(mitk_plugin ${MITK_PRIVATE_PLUGINS}) list(APPEND mitk_plugins_fullpath ${MITK_PRIVATE_MODULES}/${mitk_plugin}) endforeach() endif() # Specify which plug-ins belong to this project macro(GetMyTargetLibraries all_target_libraries varname) set(re_ctkplugin_mitk "^org_mitk_[a-zA-Z0-9_]+$") set(re_ctkplugin_bb "^org_blueberry_[a-zA-Z0-9_]+$") set(_tmp_list) list(APPEND _tmp_list ${all_target_libraries}) ctkMacroListFilter(_tmp_list re_ctkplugin_mitk re_ctkplugin_bb OUTPUT_VARIABLE ${varname}) endmacro() # Get infos about application directories and build options include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/AppList.cmake") set(mitk_apps_fullpath ) foreach(mitk_app ${MITK_APPS}) list(APPEND mitk_apps_fullpath "${CMAKE_CURRENT_SOURCE_DIR}/Applications/${mitk_app}") endforeach() ctkMacroSetupPlugins(${mitk_plugins_fullpath} BUILD_OPTION_PREFIX MITK_BUILD_ APPS ${mitk_apps_fullpath} BUILD_ALL ${MITK_BUILD_ALL_PLUGINS} COMPACT_OPTIONS) set(MITK_PLUGIN_USE_FILE "${MITK_BINARY_DIR}/MitkPluginUseFile.cmake") if(${PROJECT_NAME}_PLUGIN_LIBRARIES) ctkFunctionGeneratePluginUseFile(${MITK_PLUGIN_USE_FILE}) else() file(REMOVE ${MITK_PLUGIN_USE_FILE}) set(MITK_PLUGIN_USE_FILE ) endif() # 11.3.13, change, muellerm: activate python bundle if python and blueberry is active if( MITK_USE_Python ) set(MITK_BUILD_org.mitk.gui.qt.python ON) endif() endif() #----------------------------------------------------------------------------- # Python Wrapping #----------------------------------------------------------------------------- option(MITK_USE_Python "Build Python integration for MITK (requires CableSwig)." OFF) #----------------------------------------------------------------------------- # Documentation #----------------------------------------------------------------------------- add_subdirectory(Documentation) #----------------------------------------------------------------------------- # Installation #----------------------------------------------------------------------------- # set MITK cpack variables # These are the default variables, which can be overwritten ( see below ) include(mitkSetupCPack) set(use_default_config ON) # MITK_APPS is set in Applications/AppList.cmake (included somewhere above # if MITK_USE_BLUEBERRY is set to ON). if(MITK_APPS) set(activated_apps_no 0) list(LENGTH MITK_APPS app_count) # Check how many apps have been enabled # If more than one app has been activated, the we use the # default CPack configuration. Otherwise that apps configuration # will be used, if present. foreach(mitk_app ${MITK_APPS}) # extract option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 1 option_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) MATH(EXPR activated_apps_no "${activated_apps_no} + 1") endif() endforeach() if(app_count EQUAL 1 AND (activated_apps_no EQUAL 1 OR MITK_BUILD_ALL_APPS)) # Corner case if there is only one app in total set(use_project_cpack ON) elseif(activated_apps_no EQUAL 1 AND NOT MITK_BUILD_ALL_APPS) # Only one app is enabled (no "build all" flag set) set(use_project_cpack ON) else() # Less or more then one app is enabled set(use_project_cpack OFF) endif() foreach(mitk_app ${MITK_APPS}) # extract target_dir and option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 0 target_dir) list(GET target_info_list 1 option_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) # check whether application specific configuration files will be used if(use_project_cpack) # use files if they exist if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/Applications/${target_dir}/CPackOptions.cmake") include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/${target_dir}/CPackOptions.cmake") endif() if(EXISTS "${PROJECT_SOURCE_DIR}/Applications/${target_dir}/CPackConfig.cmake.in") set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_BINARY_DIR}/Applications/${target_dir}/CPackConfig.cmake") configure_file(${PROJECT_SOURCE_DIR}/Applications/${target_dir}/CPackConfig.cmake.in ${CPACK_PROJECT_CONFIG_FILE} @ONLY) set(use_default_config OFF) endif() endif() # add link to the list list(APPEND CPACK_CREATE_DESKTOP_LINKS "${target_dir}") endif() endforeach() endif() # if no application specific configuration file was used, use default if(use_default_config) configure_file(${MITK_SOURCE_DIR}/MITKCPackOptions.cmake.in ${MITK_BINARY_DIR}/MITKCPackOptions.cmake @ONLY) set(CPACK_PROJECT_CONFIG_FILE "${MITK_BINARY_DIR}/MITKCPackOptions.cmake") endif() # include CPack model once all variables are set include(CPack) # Additional installation rules include(mitkInstallRules) #----------------------------------------------------------------------------- # Last configuration steps #----------------------------------------------------------------------------- # This is for installation support of external projects depending on # MITK plugins and modules. The export file should not be used for linking to MITK # libraries without using LINK_DIRECTORIES, since the exports are incomplete # yet (depending libraries are not exported). set(MITK_EXPORTS_FILE "${MITK_BINARY_DIR}/MitkExports.cmake") file(REMOVE ${MITK_EXPORTS_FILE}) set(targets_to_export) get_property(module_targets GLOBAL PROPERTY MITK_MODULE_TARGETS) if(module_targets) list(APPEND targets_to_export ${module_targets}) endif() if(MITK_USE_BLUEBERRY) if(MITK_PLUGIN_LIBRARIES) list(APPEND targets_to_export ${MITK_PLUGIN_LIBRARIES}) endif() endif() export(TARGETS ${targets_to_export} APPEND FILE ${MITK_EXPORTS_FILE}) set(MITK_EXPORTED_TARGET_PROPERTIES ) foreach(target_to_export ${targets_to_export}) get_target_property(autoload_targets ${target_to_export} MITK_AUTOLOAD_TARGETS) if(autoload_targets) set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES} set_target_properties(${target_to_export} PROPERTIES MITK_AUTOLOAD_TARGETS \"${autoload_targets}\")") endif() get_target_property(autoload_dir ${target_to_export} MITK_AUTOLOAD_DIRECTORY) if(autoload_dir) set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES} set_target_properties(${target_to_export} PROPERTIES MITK_AUTOLOAD_DIRECTORY \"${autoload_dir}\")") endif() endforeach() get_property(MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS_CONFIG GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS) configure_file(${MITK_SOURCE_DIR}/CMake/ToolExtensionITKFactory.cpp.in ${MITK_BINARY_DIR}/ToolExtensionITKFactory.cpp.in COPYONLY) configure_file(${MITK_SOURCE_DIR}/CMake/ToolExtensionITKFactoryLoader.cpp.in ${MITK_BINARY_DIR}/ToolExtensionITKFactoryLoader.cpp.in COPYONLY) configure_file(${MITK_SOURCE_DIR}/CMake/ToolGUIExtensionITKFactory.cpp.in ${MITK_BINARY_DIR}/ToolGUIExtensionITKFactory.cpp.in COPYONLY) set(VISIBILITY_AVAILABLE 0) set(visibility_test_flag "") mitkFunctionCheckCompilerFlags("-fvisibility=hidden" visibility_test_flag) if(visibility_test_flag) # The compiler understands -fvisiblity=hidden (probably gcc >= 4 or Clang) set(VISIBILITY_AVAILABLE 1) endif() configure_file(mitkExportMacros.h.in ${MITK_BINARY_DIR}/mitkExportMacros.h) configure_file(mitkVersion.h.in ${MITK_BINARY_DIR}/mitkVersion.h) configure_file(mitkConfig.h.in ${MITK_BINARY_DIR}/mitkConfig.h) set(VECMATH_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/vecmath) set(IPFUNC_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/ipFunc) set(UTILITIES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities) file(GLOB _MODULES_CONF_FILES RELATIVE ${PROJECT_BINARY_DIR}/${MODULES_CONF_DIRNAME} ${PROJECT_BINARY_DIR}/${MODULES_CONF_DIRNAME}/*.cmake) set(MITK_MODULE_NAMES) foreach(_module ${_MODULES_CONF_FILES}) string(REPLACE Config.cmake "" _module_name ${_module}) list(APPEND MITK_MODULE_NAMES ${_module_name}) endforeach() configure_file(mitkConfig.h.in ${MITK_BINARY_DIR}/mitkConfig.h) configure_file(MITKConfig.cmake.in ${MITK_BINARY_DIR}/MITKConfig.cmake @ONLY) # If we are under Windows, create two batch files which correctly # set up the environment for the application and for Visual Studio if(WIN32) include(mitkFunctionCreateWindowsBatchScript) set(VS_SOLUTION_FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME}.sln") foreach(VS_BUILD_TYPE debug release) mitkFunctionCreateWindowsBatchScript("${MITK_SOURCE_DIR}/CMake/StartVS.bat.in" ${PROJECT_BINARY_DIR}/StartVS_${VS_BUILD_TYPE}.bat ${VS_BUILD_TYPE}) endforeach() endif(WIN32) #----------------------------------------------------------------------------- # MITK Applications #----------------------------------------------------------------------------- # This must come after MITKConfig.h was generated, since applications # might do a find_package(MITK REQUIRED). add_subdirectory(Applications) #----------------------------------------------------------------------------- # MITK Examples #----------------------------------------------------------------------------- if(MITK_BUILD_EXAMPLES) # This must come after MITKConfig.h was generated, since applications # might do a find_package(MITK REQUIRED). add_subdirectory(Examples) endif() diff --git a/Modules/BreakpadCrashReporting/CMakeLists.txt b/Modules/BreakpadCrashReporting/CMakeLists.txt new file mode 100644 index 0000000000..3acecde186 --- /dev/null +++ b/Modules/BreakpadCrashReporting/CMakeLists.txt @@ -0,0 +1,36 @@ +# TODOs +# LATER nicer separation of Linux/Window/.. code +# OK test should check existence of dump file +# - find nice script to use linux symbol writer tool dump_.. on all relevant libraries +# - update documentation +# OK check buildtype (O2/-g/..) in cmake +# OK use the same library structure in "our" cmake script as google uses in their build +# OK otherwise we cannot switch between custom-built versions of breakpad and our superbuild version +# [optional] add install step to our Breakpad build + +if(MITK_USE_Breakpad) # from top-level CMakeLists.txt + + find_package(Breakpad) + if (NOT Breakpad_FOUND) + message(FATAL_ERROR "MITK_USE_Breakpad was set but Breakpad build cannot be found. Plaese check CMake cache variables regarding Breakpad") + endif() + + MITK_CREATE_MODULE(BreakpadCrashReporting + INTERNAL_INCLUDE_DIRS ${Breakpad_INCLUDE_DIR} + ADDITIONAL_LIBS ${Breakpad_LIBRARIES} + FORCE_STATIC + ) + + if(CMAKE_SYSTEM MATCHES "Windows") + add_executable(CrashReportingServer mitkCrashReportingServer.cpp) + target_link_libraries(CrashReportingServer ${ALL_LIBRARIES} BreakpadCrashReporting) + MITK_INSTALL(TARGETS CrashReportingServer) + endif() + + if(CMAKE_SYSTEM MATCHES "Linux") + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ProduceBreakpadSymbols.sh.in ${MITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ProduceBreakpadSymbols.sh) + endif() + +add_subdirectory(Testing) + +endif(MITK_USE_Breakpad) diff --git a/Modules/BreakpadCrashReporting/ProduceBreakpadSymbols.sh.in b/Modules/BreakpadCrashReporting/ProduceBreakpadSymbols.sh.in new file mode 100755 index 0000000000..4b8f168cf8 --- /dev/null +++ b/Modules/BreakpadCrashReporting/ProduceBreakpadSymbols.sh.in @@ -0,0 +1,34 @@ +#!/bin/bash +# +# This script can be used to convert the debugging symbols of binaries to text-format symbol files. +# This needs to be done so that Breakpad can produce useful stack traces. +# The script takes as argument the path to the binary for which the symbols should be converted. +# +# To produce the stack trace use the application @Breakpad_DIR@/minidump_stackwalk +# For further details have a look at the offical documentation of google breakpad: https://code.google.com/p/google-breakpad/wiki/LinuxStarterGuide + +# path to binary +BINARY_PATH=$1 + +# path to dump_sys +DUMPSYMS=@Breakpad_DIR@/dump_syms + +# output path +OUTPUT=@MITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY@/CrashDumps + +# if output folder does not exist yet +mkdir -p $OUTPUT + +OUTPUTFILEPATH=$OUTPUT/symbols.sym + +$DUMPSYMS $BINARY_PATH > $OUTPUTFILEPATH + +HASH=$(head -n1 $OUTPUTFILEPATH | awk '{ print $4 }' ) +echo $HASH + +EXENAME=$(head -n1 $OUTPUTFILEPATH | awk '{ print $5 }' ) +echo $EXENAME + +mkdir -p $OUTPUT/./symbols/$EXENAME/$HASH +mv $OUTPUTFILEPATH $OUTPUT/./symbols/$EXENAME/$HASH + diff --git a/Modules/BreakpadCrashReporting/Testing/CMakeLists.txt b/Modules/BreakpadCrashReporting/Testing/CMakeLists.txt new file mode 100644 index 0000000000..42a24eb824 --- /dev/null +++ b/Modules/BreakpadCrashReporting/Testing/CMakeLists.txt @@ -0,0 +1,13 @@ +if(BUILD_TESTING) + # currently breakpad testing is only available for windows + # ToDo: currently a problem can occure during crash dump generation on linux. please have a look at the documentation of mitkBreakpadCrashReportingDumpTest + #set_tests_properties(mitkBreakpadCrashReportingDumpTest PROPERTIES TIMEOUT 5) # the test should not need 5 seconds + +if(CMAKE_SYSTEM MATCHES "Windows") + MITK_CREATE_MODULE_TESTS() + + add_executable(BreakpadCrashReportingDumpTestApplication mitkBreakpadCrashReportingDumpTestApplication.cpp) + target_link_libraries(BreakpadCrashReportingDumpTestApplication ${ALL_LIBRARIES} BreakpadCrashReporting) +endif() + +endif() diff --git a/Modules/BreakpadCrashReporting/Testing/files.cmake b/Modules/BreakpadCrashReporting/Testing/files.cmake new file mode 100644 index 0000000000..212116a521 --- /dev/null +++ b/Modules/BreakpadCrashReporting/Testing/files.cmake @@ -0,0 +1,5 @@ +if(CMAKE_SYSTEM MATCHES "Windows") # currently only for windows (see documentation of test mitkBreakpadCrashReportingDumpTest) +set(MODULE_TESTS + mitkBreakpadCrashReportingDumpTest.cpp +) +endif() diff --git a/Modules/BreakpadCrashReporting/Testing/mitkBreakpadCrashReportingDumpTest.cpp b/Modules/BreakpadCrashReporting/Testing/mitkBreakpadCrashReportingDumpTest.cpp new file mode 100644 index 0000000000..656e352f52 --- /dev/null +++ b/Modules/BreakpadCrashReporting/Testing/mitkBreakpadCrashReportingDumpTest.cpp @@ -0,0 +1,156 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkTestingMacros.h" + +#include "mitkBreakpadCrashReporting.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +std::string CreateEmptyTestFolder() +{ + std::string modulePath = mitk::BreakpadCrashReporting::GetModulePath(); // get path of executable + + char dateTime[15]; + time_t now = time(0); + tm* time = localtime( &now ); + strftime( dateTime, 15, "%Y%m%d%H%M%S", time ); + + std::string dirName = modulePath + "/breakpadtestdump/" + "mitkBreakpadCrashReportingDumpTest-" + dateTime; + + if( itksys::SystemTools::MakeDirectory(dirName.c_str()) ) + { + return dirName; + } + return ""; +}; + +/** + \brief Start crash reporting and crash (expectedly). + + This method is excpected to setup BreakpadCrashReporting, + then provoke a crash, thus creating a crash dump in a configured + folder. Then we check the actual existence of the crash dump and if it has any content. + If the dump generation was not successful the dump file will be empty or not existent. + + In order to get the output of ctest correctly we provoke the + crash in a different process, else the test itself would crash. + +Linux: + The test is currently deactivated for Linux. + ToDo: + Currently there seems to be a problem in linux with crash dump generation. In this test we + provoke a segfault. Sometimes the crash dump generation gets in a state where it waits for + the child process (the process which crashed) to change the process state, but the child + process is allready attach via ptrace to the parent process and therefore has allready the state + stopped and does not change until it gets a signal from the parent process. The parent process + itself waits for the child process to change the state. +*/ +int mitkBreakpadCrashReportingDumpTest(int argc, char** const argv) +{ + // always start with this! + MITK_TEST_BEGIN("mitkBreakpadCrashReportingDumpTest") + + std::string emptyTempFolder = CreateEmptyTestFolder(); + + MITK_TEST_OUTPUT( << "Dumping files to " << emptyTempFolder ); +#ifdef WIN32 + mitk::BreakpadCrashReporting crashReporting( emptyTempFolder ); + + // start out-of-process crash dump server + MITK_TEST_CONDITION_REQUIRED( crashReporting.StartCrashServer(true) == true, "Start out-of-process crash reporting server"); + + // in-process reporting client (minimal code to tell other process to dump information) + crashReporting.InitializeClientHandler(true); + + MITK_TEST_CONDITION_REQUIRED( true, "Start crash reporting client (in crashing process)"); + + // provoke a seg-fault to make test crash -> call external application which will crash + std::string commandline = mitk::BreakpadCrashReporting::GetModulePath() + "/BreakpadCrashReportingDumpTestApplication" + " " + emptyTempFolder; + system( commandline.c_str() ); +#elif __gnu_linux__ + pid_t child_pid = fork(); + + if ( child_pid != 0) + { + waitpid(child_pid, NULL, __WALL); + /* + if( waitpid(child_pid, NULL, __WALL) != child_pid ) { + // the child process does not complete within 30 seconds + kill(child_pid, SIGTERM); + } + */ + } + else + { + //alarm(5); + mitk::BreakpadCrashReporting crashReporting( emptyTempFolder ); + + // start out-of-process crash dump server + crashReporting.StartCrashServer(true); + + // in-process reporting client (minimal code to tell other process to dump information) + crashReporting.InitializeClientHandler(true); + + // provoke a seg-fault to make test crash + crashReporting.CrashAppForTestPurpose(); + } +#endif + + // check dump creation +#ifdef WIN32 + // Waiting a bit to let the crash reporting server do its work + // This is not neccessary on Linux because we run the SERVER as + // the unittest, so when it is done, the crash dump must exist. + // (On Windows, we run the client and this in turn starts a server) + Sleep( 3000 ); +#endif + itk::Directory::Pointer crashDumpDirectory = itk::Directory::New(); + MITK_TEST_CONDITION_REQUIRED( crashDumpDirectory->Load( emptyTempFolder.c_str() ), "Crash dump folder exists." ); + + // since the folder is only used for this testing purposes, there should only be crash dump folders here + // so we only have to check if the crash dump directory contains anything + MITK_TEST_CONDITION_REQUIRED( crashDumpDirectory->GetNumberOfFiles() > 0, "Found at least one file in crash dump directory."); + bool dmpFileFound = false; + for ( unsigned int i = 0; i < crashDumpDirectory->GetNumberOfFiles(); ++i ) + { + std::string filename = emptyTempFolder + "/" + crashDumpDirectory->GetFile( i ); + + std::string extension = itksys::SystemTools::GetFilenameExtension(filename.c_str()); + + if(extension.compare(".dmp")==0) + { + dmpFileFound = true; + std::ifstream in(filename.c_str(), std::ifstream::in | std::ifstream::binary); + in.seekg(0, std::ifstream::end); + MITK_TEST_CONDITION( in.tellg() > 0, "The dump file is not empty." ); + } + remove( filename.c_str() ); + } + MITK_TEST_CONDITION( dmpFileFound, "Dump file was created." ); + rmdir( emptyTempFolder.c_str() ); + + // always end with this! + MITK_TEST_END() +} diff --git a/Modules/BreakpadCrashReporting/Testing/mitkBreakpadCrashReportingDumpTestApplication.cpp b/Modules/BreakpadCrashReporting/Testing/mitkBreakpadCrashReportingDumpTestApplication.cpp new file mode 100644 index 0000000000..34c7812d6c --- /dev/null +++ b/Modules/BreakpadCrashReporting/Testing/mitkBreakpadCrashReportingDumpTestApplication.cpp @@ -0,0 +1,49 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkBreakpadCrashReporting.h" + +#include +#include "mitkLogMacros.h" +#include +#include +#include + +int main(int argc, char* argv[]) +{ + std::string folderForCrashDumps =""; + + if (argc != 2) + { + MITK_ERROR << "Exactly 2 argument expected, got " << argc << " instead!"; + exit(2); + } + else + { + folderForCrashDumps = argv[1]; + } + + mitk::BreakpadCrashReporting crashReporting( folderForCrashDumps ); + + // start out-of-process crash dump server + crashReporting.StartCrashServer(true); + + // in-process reporting client (minimal code to tell other process to dump information) + crashReporting.InitializeClientHandler(true); + + // provoke a seg-fault to make test crash + crashReporting.CrashAppForTestPurpose(); +} diff --git a/Modules/BreakpadCrashReporting/files.cmake b/Modules/BreakpadCrashReporting/files.cmake new file mode 100644 index 0000000000..f3c9800d44 --- /dev/null +++ b/Modules/BreakpadCrashReporting/files.cmake @@ -0,0 +1,4 @@ +set(CPP_FILES + mitkBreakpadCrashReporting.cpp +# mitkCrashReportingServer.cpp +) diff --git a/Modules/BreakpadCrashReporting/mitkBreakpadCrashReporting.cpp b/Modules/BreakpadCrashReporting/mitkBreakpadCrashReporting.cpp new file mode 100644 index 0000000000..9ae7698e67 --- /dev/null +++ b/Modules/BreakpadCrashReporting/mitkBreakpadCrashReporting.cpp @@ -0,0 +1,463 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkBreakpadCrashReporting.h" + +#include "mitkLogMacros.h" + + +#ifdef WIN32 + +#include +#include +#include "client/windows/crash_generation/client_info.h" +#include "client/windows/crash_generation/crash_generation_server.h" +#include "client/windows/handler/exception_handler.h" +#include "client/windows/common/ipc_protocol.h" + +#elif __APPLE__ + +#include +#include +#include + +#elif __gnu_linux__ + +#include +#include +#include +#include +#include + +#endif + +#include + +static bool breakpadOnceConnected = false; // indicates a server having had at least one client connection +static int breakpadNumberOfConnections = 0; // current number of connected clients + +#ifdef WIN32 +static int numberOfConnectionAttemptsPerformed = 1; // number of performed re-connect attempts of a crash client +#endif + +// Get application path: there is no cross-plattform standard c++ method which can get the executable path +// (other toolkits offer it, e.g. Qt). +// Currently only for Windows and Linux implemented: +std::string mitk::BreakpadCrashReporting::GetModulePath() { +#ifdef WIN32 + TCHAR path[MAX_PATH]; + if( GetModuleFileName( NULL, path, MAX_PATH ) ) + { + std::string pathString = path; + pathString.erase( pathString.find_last_of("\\") ); + return pathString; + } +#elif __gnu_linux__ + char buff[1024]; + ssize_t len = ::readlink("/proc/self/exe", buff, sizeof(buff)-1); + if (len != -1) { + buff[len] = '\0'; + std::string path = buff; + path.erase( path.find_last_of("/") ); + return path; + } else { + /* handle error condition */ + } +#endif + return ""; +} + +mitk::BreakpadCrashReporting::BreakpadCrashReporting( const std::string& dumpPath ) +: m_CrashServer(NULL) +, m_ExceptionHandler(NULL) +, m_CrashDumpPath( dumpPath ) + // Linux connection parameters +, server_fd(-1) +, client_fd(-1) + // Windows connection parameters +, m_NamedPipeString("\\\\.\\pipe\\MitkCrashServices\\MitkBasedApplication") +, m_CrashReportingServerExecutable( GetModulePath() + "/CrashReportingServer.exe" ) +, m_NumberOfConnectionAttempts(3) +, m_ReconnectDelay(300) +{ + if ( m_CrashDumpPath.empty() ) + { + m_CrashDumpPath = GetModulePath() + "/CrashDumps"; // ToDo: what happens if GetModulePath returns emtpy string + } +} + +mitk::BreakpadCrashReporting::~BreakpadCrashReporting() +{ + if (m_ExceptionHandler) + { + delete m_ExceptionHandler; + } + if (m_CrashServer) + { + delete m_CrashServer; + } +} + +#ifdef WIN32 +//This function gets called in the event of a crash. +bool BreakpadCrashReportingDumpCallbackWindows(const wchar_t* dump_path, + const wchar_t* minidump_id, + void* context, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion, + bool succeeded) +{ + /* + NO STACK USE, NO HEAP USE IN THIS FUNCTION + Creating QString's, using qDebug, etc. - everything is crash-unfriendly. + */ + return succeeded; +} + +#elif __gnu_linux__ +bool BreakpadCrashReportingDumpCallbackLinux( + const google_breakpad::MinidumpDescriptor& /*descriptor*/, + void* /*context*/, + bool succeeded) +{ + return succeeded; +} +#endif + +bool mitk::BreakpadCrashReporting::DumpCallbackPlatformIndependent() +{ + return true; +} + +void mitk::BreakpadCrashReporting::InitializeClientHandler(bool connectToCrashGenerationServer) +{ +#ifdef WIN32 // http://stackoverflow.com/questions/5625884/conversion-of-stdwstring-to-qstring-throws-linker-error + std::wstring dump_path( m_CrashDumpPath.begin(), m_CrashDumpPath.end() ); +#else + std::string dump_path = m_CrashDumpPath; +#endif + + + +#ifdef WIN32 + /* This is needed for CRT to not show dialog for invalid param + failures and instead let the code handle it.*/ + _CrtSetReportMode(_CRT_ASSERT, 0); + + const wchar_t* pipe; + if(connectToCrashGenerationServer) + { + pipe = (const wchar_t*)m_NamedPipeString.c_str(); + MITK_INFO << "Initializing Breakpad Crash Handler, connecting to named pipe: " << m_NamedPipeString.c_str() << "\n"; + } + else + { + pipe = (const wchar_t*) L""; + MITK_INFO << "Initializing Breakpad Crash Handler, connecting to named pipe: "; + } + + m_ExceptionHandler = new google_breakpad::ExceptionHandler( + dump_path, + NULL, + BreakpadCrashReportingDumpCallbackWindows, + NULL, + google_breakpad::ExceptionHandler::HANDLER_ALL, + MiniDumpNormal, //see DbgHelp.h + pipe, + NULL); // custom client info (unused) + + if(connectToCrashGenerationServer) + { + if(!m_ExceptionHandler->IsOutOfProcess()) + { // we want to connect to a server but connection handler did not connect to OOP server. + + MITK_INFO << "Initializing Breakpad Crash Handler: connection attempt to crash report server failed. Server started?"; + + if(numberOfConnectionAttemptsPerformed < this->m_NumberOfConnectionAttempts) + { + itksys::SystemTools::Delay(m_ReconnectDelay); //sleep a little + numberOfConnectionAttemptsPerformed++; + InitializeClientHandler(connectToCrashGenerationServer); + } + else + { + MITK_INFO << "Initializing Breakpad Crash Handler: connection attempt to crash report server failed - will proceed with in process handler."; + } + } + } + +#elif __gnu_linux__ + + google_breakpad::MinidumpDescriptor dumpDescriptor( dump_path ); + + if (client_fd == -1) + { + MITK_WARN << "In-process crash dump handling, the unsafer method"; + } + + m_ExceptionHandler = new google_breakpad::ExceptionHandler( + dumpDescriptor, // descriptor (where to dump) + NULL, // filter (we don't filter) + BreakpadCrashReportingDumpCallbackLinux, // our callback in cases of crashes + NULL, // callback_context (no idea.. custom data probably) + true, // install_handler (yes, write dumps with each crash, not only on request) + client_fd ); // should be initialized in StopCrashServer() by ealier call + + +#endif +} + +#ifdef WIN32 +static void + _cdecl +ShowClientConnected(void* /*context*/, + const google_breakpad::ClientInfo* client_info) +{ // callback of the crash generation server on client connect + MITK_INFO << "Breakpad Client connected: " << client_info->pid(); + + breakpadOnceConnected = true; // static variables indicate server shutdown after usage + breakpadNumberOfConnections++; +} +#endif + +#ifdef WIN32 +static void _cdecl ShowClientCrashed(void* /*context*/, const google_breakpad::ClientInfo* client_info, const std::wstring* /*dump_path*/) +#elif __gnu_linux__ +static void ShowClientCrashed(void* context, const google_breakpad::ClientInfo* /*client_info*/, const std::string* /*dump_path*/) +#endif +{ // callback of the crash generation server on client crash + +#ifdef WIN32 + MITK_INFO << "Breakpad Client request dump: " << client_info->pid(); + // we may add some log info here along the dump file + google_breakpad::CustomClientInfo custom_info = client_info->GetCustomInfo(); +#else + MITK_INFO << "Breakpad Client request dump: TODO proc-info"; +#endif + +} + +static void +#ifdef WIN32 + _cdecl +#endif +ShowClientExited(void* /*context*/, + const google_breakpad::ClientInfo* client_info) +{ // callback of the crash generation server on client exit +#ifdef WIN32 + MITK_INFO << "Breakpad Client exited :" << client_info->pid(); +#else + MITK_INFO << "Breakpad Client exited : TODO proc-info"; +#endif + + // we'd like to shut down server if there is no further client connected, + // but no access to private server members in this callback + breakpadNumberOfConnections--; + if(breakpadNumberOfConnections == 0 && breakpadOnceConnected) + { + MITK_INFO << "Breakpad Server: no more client connections. Shuting down..."; + exit(0); + } +} + +bool mitk::BreakpadCrashReporting::StartCrashServer(bool lauchOutOfProcessExecutable) +{ + + if (m_CrashServer) + { // Do not create another instance of the server. + MITK_INFO << "Crash Server object already generated."; + return true; + } + +#ifdef __gnu_linux__ + google_breakpad::CrashGenerationServer::CreateReportChannel(&server_fd, &client_fd); // both OUT parameters + + pid_t child_pid = fork(); + + if ( child_pid != 0) + { + // server process + InitializeServer(server_fd); + + MITK_INFO << "Wait for observed breakpad child to finish/crash..."; + int status; + do { + pid_t w = waitpid(child_pid, &status, WUNTRACED | WCONTINUED); + if (w == -1) { + perror("waitpid"); + exit(EXIT_FAILURE); + } + + if (WIFEXITED(status)) { + printf("exited, status=%d\n", WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + printf("killed by signal %d\n", WTERMSIG(status)); + } else if (WIFSTOPPED(status)) { + printf("stopped by signal %d\n", WSTOPSIG(status)); + } else if (WIFCONTINUED(status)) { + printf("continued\n"); + } + } while (!WIFEXITED(status) && !WIFSIGNALED(status)); + MITK_INFO << "Breakpad child terminated, so I also terminate..."; + exit(EXIT_SUCCESS); + } + else + { + // child process + return true; // assume we are fine since we got here.. + } + +#elif WIN32 + + if(lauchOutOfProcessExecutable) + { // spawn process and launch CrashReportingServer executable + std::string commandline = m_CrashReportingServerExecutable + " \"" + m_NamedPipeString + "\" " + m_CrashDumpPath; + int success = system( commandline.c_str() ); + + return ( success != -1 ); + } + else + { // directly open up server instance in this thread + return InitializeServer(); + } + +#endif +} + +bool mitk::BreakpadCrashReporting::InitializeServer( int listen_fd ) +{ + itksys::SystemTools::MakeDirectory(m_CrashDumpPath.c_str()); // Make sure directory is created. + + google_breakpad::CrashGenerationServer::OnClientDumpRequestCallback dump_callback = &ShowClientCrashed; +#ifdef WIN32 + google_breakpad::CrashGenerationServer::OnClientExitedCallback exit_callback = &ShowClientExited; // this... +#elif __gnu_linux__ + google_breakpad::CrashGenerationServer::OnClientExitingCallback exit_callback = &ShowClientExited; // and that.. tell much about cross-platform.. +#endif + + void* dump_context = NULL; + void* exit_context = NULL; + +#ifdef WIN32 // http://stackoverflow.com/questions/5625884/conversion-of-stdwstring-to-qstring-throws-linker-error + std::wstring dump_path(m_CrashDumpPath.begin(), m_CrashDumpPath.end() ); + std::wstring pipe_name( m_NamedPipeString.begin(), m_NamedPipeString.end() ); + m_CrashServer = new google_breakpad::CrashGenerationServer(pipe_name, + NULL, + ShowClientConnected, // connect callback + NULL, + dump_callback, + dump_context, + exit_callback, // exit callback + exit_context, + NULL, + NULL, + true, + &dump_path); +#elif __gnu_linux__ + std::string dump_path = m_CrashDumpPath; + + MITK_INFO << "Start Breakpad crash dump generation server with file descriptor " << listen_fd; + + m_CrashServer = new google_breakpad::CrashGenerationServer(listen_fd, + dump_callback, + dump_context, + exit_callback, + exit_context, + true, // generate_dumps + &dump_path); +#endif + + if (!m_CrashServer->Start()) + { + MITK_ERROR << "Unable to start Breakpad crash dump generation server."; + delete m_CrashServer; + m_CrashServer = NULL; + return false; + } + else + { + MITK_INFO << "Breakpad crash dump generation server started."; + return true; + } + + return false; + +} + +bool mitk::BreakpadCrashReporting::RequestDump() +{ + if(this->m_ExceptionHandler != NULL) + { + if(m_ExceptionHandler->WriteMinidump()) + { + MITK_INFO << "Breakpad Crash Reporting: Successfully requested a minidump."; + return true; + } + else + { + MITK_INFO << "Breakpad Crash Reporting: Requested of minidump failed."; + return false; + } + } + return false; +} + +void mitk::BreakpadCrashReporting::CrashAppForTestPurpose() +{ + int* x = 0; + *x = 1; +} + +int mitk::BreakpadCrashReporting::GetNumberOfConnections() const +{ + return breakpadNumberOfConnections; +} + +void mitk::BreakpadCrashReporting::SetNamedPipeName(const std::string& name) +{ + m_NamedPipeString = name; +} + +std::string mitk::BreakpadCrashReporting::GetNamedPipeName() const +{ + return m_NamedPipeString; +} + +void mitk::BreakpadCrashReporting::SetCrashDumpPath(const std::string& path) +{ + m_CrashDumpPath = path; +} + +std::string mitk::BreakpadCrashReporting::GetCrashDumpPath() const +{ + return m_CrashDumpPath; +} + + +void mitk::BreakpadCrashReporting::SetCrashReportingServerExecutable(const std::string& exe) +{ + m_CrashReportingServerExecutable = exe; +} + +void mitk::BreakpadCrashReporting::SetNumberOfConnectionAttempts(int no) +{ + m_NumberOfConnectionAttempts = no; +} + +void mitk::BreakpadCrashReporting::SetReconnectDelayInMilliSeconds(int ms) +{ + m_ReconnectDelay = ms; +} diff --git a/Modules/BreakpadCrashReporting/mitkBreakpadCrashReporting.h b/Modules/BreakpadCrashReporting/mitkBreakpadCrashReporting.h new file mode 100644 index 0000000000..7ca1437e58 --- /dev/null +++ b/Modules/BreakpadCrashReporting/mitkBreakpadCrashReporting.h @@ -0,0 +1,167 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef MITK_BREAKPAD_CRASH_REPORTING_H +#define MITK_BREAKPAD_CRASH_REPORTING_H + +#include + +namespace google_breakpad { + + class ExceptionHandler; + class CrashGenerationServer; +} + +namespace mitk { + + /** + * \brief Integration of Google's Breakpad Project in MITK. + * + * Breakpad is a library and tool suite that allows you to distribute an application to users with compiler-provided + * debugging information removed, record crashes in compact "minidump" files, send them back to your server, and + * produce C and C++ stack traces from these minidumps. Breakpad can also write minidumps on request for programs that + * have not crashed (from http://code.google.com/p/google-breakpad/wiki/GettingStartedWithBreakpad). + * + * Usage: + * + * In-process usage: + * Instantiate this class, and initialize an event handler for 'unhandled' exceptions by calling + * InitializeClientHandler(false). In the event of a crash your application will try to generate a dump file. + * + * Out-of-process (OOP) usage: + * However,your application crashed - therefore using your application's process for dealing with unhandled exceptions is + * not safe. Heap and stack may be corrupted. Having a separated process that invoces the generation of a minidump of your process is best, + * this is called out-of-process exception handling. + * + * Sample code for simple OOP usage: + * mitk::BreakpadCrashReporting myBreakpad; + * myBreakpad.StartCrashServer(true); + * [... some code ...] + * myBreakpad.InitializeClientHandler(true); + * + * Note 1: The start of a detached process takes some time. Either you call InitializeClientHandler(true) a while after calling + * StartCrashServer(true), or it may take some time and a few connection attempts (configurable, see re-connect handling). + * + * Note 2: If there is no connection to the server possible, there is an automatic fallback to in-process usage. + * Client and server output will indicate the operating mode. + * + * Note 3: The crash reporting server process will automatically shutdown, if there was a client connected and exits + * (either due to shutdown or due to crash). Also, the sample server will shutdown automatically, if there is already + * one server instance running. + * + * Note 4: LINUX + * Currently there seems to be a problem on linux with crash dump generation. For example in case of a segfault, + * the crash dump generation sometimes (seems to be random) gets in a state where it waits for + * the child process (the process which crashed) to change the process state, but the child + * process is allready attached via ptrace to the parent process (crash server) and therefore has allready the state + * "stopped" and does not change until it gets a signal from the parent process. The parent process + * itself waits for the child process to change the state. If this happens all processes are in a waiting state and + * no crash dump will be generated and only an empty dump file exists. + * This is currently only a assumption! The problem seems to lay in the google breakpad class + * linux_ptrace_dumper.cc in the method SuspendThread(pid_t pid). + * + */ + class BreakpadCrashReporting + { + public: + + BreakpadCrashReporting( const std::string& dumpPath = "" ); + ~BreakpadCrashReporting(); + + /** Initializes an event handler for 'unhandled exceptions' that will dump a so-called 'minidump' to a defined folder. + * For usage as "in-process" exception handler set connectToCrashGenerationServer = false. + * For usage as "out-of-process" (OOP) exception handler, set connectToCrashGenerationServer = true. + * + * Related params: + * Are defined by means of SetNamedPipeName() and SetCrashDumpPath(). + * + * OOP Usage: + * In OOP use case, the handler uses a crash generation client that connects to a crash generation server via named pipes. + * Such a crash generation server should be started then on beforehand by means of the function StartCrashServer() below. + * + * If the connection attempt to a server fails, reconnects attempt may be scheduled by SetNumberOfConnectionAttempts() + * and SetReconnectDelayInMilliSeconds(). Note that during re-connect attempts, your application will be blocked. + */ + void InitializeClientHandler(bool connectToCrashGenerationServer); + + /** Starts a crash generation server for "out-of-process" exception handling. + * For usage outside of your main application (i.e. already in a separate process), set launchOutOfProcessExecutable = false. + * For usage inside of your main application, set launchOutOfProcessExecutable = true. + * + * In the latter case, StartCrashServer() will spawn a detached process launching the crash generation server. + * This server process will automatically shutdown again, if a once connected client exits due to client shutdown or crash. + * + * By default, an instance of the sample crash reporting server, mitk::CrashReportingServer will be used. Alternatively, + * you may define a process to be started by SetCrashReportingServerExecutable(). + * + * Related params are defined by means of SetNamedPipeName() and SetCrashDumpPath(). + */ + bool StartCrashServer(bool launchOutOfProcessExecutable); + + // Named pipe string to communicate with OutOfProcessCrashReporter. + void SetNamedPipeName(const std::string& name); + std::string GetNamedPipeName() const; + + // Directory path to save crash dumps. + void SetCrashDumpPath(const std::string& path); + std::string GetCrashDumpPath() const; + + // Re-connect handling in case a crash server cannot be reached. + void SetNumberOfConnectionAttempts(int no); + void SetReconnectDelayInMilliSeconds(int ms); + + // Do not call this without purpose :-) + void CrashAppForTestPurpose(); + + // Writes a minidump immediately. This can be used to capture the + // execution state independently of a crash. Returns true on success. + bool RequestDump(); + + // returns the number of currently connected clients + int GetNumberOfConnections() const; + + // Get the path of the breakpad module + static std::string GetModulePath(); + + protected: + + bool InitializeServer(int listen_fd = -1); + + // External out-of-process (OOP) Crash Reporting Server file path - if OOP is used. + void SetCrashReportingServerExecutable(const std::string& exe); + + + bool DumpCallbackPlatformIndependent(); + + google_breakpad::CrashGenerationServer* m_CrashServer; + google_breakpad::ExceptionHandler* m_ExceptionHandler; + + std::string m_CrashDumpPath; + + // Linux connection parameters + int server_fd; + int client_fd; + + // Windows connection parameters + std::string m_NamedPipeString; + std::string m_CrashReportingServerExecutable; + int m_NumberOfConnectionAttempts; + int m_ReconnectDelay; + + }; +} // namespace mitk + +#endif /* _H_HEADER_INCLUDED_ */ diff --git a/Modules/BreakpadCrashReporting/mitkCrashReportingServer.cpp b/Modules/BreakpadCrashReporting/mitkCrashReportingServer.cpp new file mode 100644 index 0000000000..9dff2da4ca --- /dev/null +++ b/Modules/BreakpadCrashReporting/mitkCrashReportingServer.cpp @@ -0,0 +1,129 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkBreakpadCrashReporting.h" + +#include +#include "mitkLogMacros.h" +#include +#include +#include +#ifdef WIN32 + #include +#elif __gnu_linux__ + #include +#endif + + +// Simple server process for out-of-process crash reporting. By default this server will log to the executables directory, or +// to the crash dump path if provided properly. +// Arguments: +// NamedPipeName: Quotated string of the named pipe to communicate with the client. +// FolderForCrashDumps: Quotated string of the folder to save minidump files in the event of a crash. + +static mitk::BreakpadCrashReporting* myBreakpad; + +/*class Timer : public QTimer { + Q_OBJECT +public: + explicit Timer(QObject *parent = 0) : QTimer(parent) { + connect(this, SIGNAL(timeout()), this, SLOT(CheckForServerShutdown())); + } +private slots: + void CheckForServerShutdown() + { + MITK_INFO << "mitk Crash Reporting Server check for server shutdown."; + MITK_INFO << "number of active connections: " << QString(myBreakpad->GetNumberOfConnections()).toStdString().c_str(); + } +}; + +#include "main.moc"*/ + +int main(int argc, char* argv[]) +{ + std::string folderForCrashDumps =""; + std::string namedPipeName = ""; + + if (argc != 3) + { + MITK_WARN << "mitk Crash Reporting Server using default arguments"; + } + else + { + namedPipeName = argv[1]; + folderForCrashDumps = argv[2]; + } + try + { + // set up logging to file + mitk::LoggingBackend::Register(); + + time_t now = time(0); + tm* time = localtime( &now ); + char dateTime[20]; + + strftime( dateTime, 20, "%Y-%m-%d_%H-%M-%S", time ); + if(folderForCrashDumps.empty()) + folderForCrashDumps = mitk::BreakpadCrashReporting::GetModulePath(); + + std::stringstream pid; + pid << getpid(); + + std::string logfile = folderForCrashDumps + "/" + dateTime + "-CrashReportingServer-" + pid.str() + ".log"; + + MITK_INFO << "** Logging to " << logfile << std::endl; + mitk::LoggingBackend::SetLogFile( logfile.c_str() ); + + // init breakpad server + myBreakpad = new mitk::BreakpadCrashReporting(); + + if(!namedPipeName.empty()) + { + MITK_INFO << "Using arg[1] as named pipe name" << namedPipeName; + myBreakpad->SetNamedPipeName(namedPipeName); + } + if(!folderForCrashDumps.empty()) + { + MITK_INFO << "Using arg[2] as crash dump path" << folderForCrashDumps; + myBreakpad->SetCrashDumpPath(folderForCrashDumps); + } + + MITK_INFO << "NamedPipeName: " << myBreakpad->GetNamedPipeName() << "\n"; + MITK_INFO << "FolderForCrashDumps: " << myBreakpad->GetCrashDumpPath() << "\n"; + + if(myBreakpad->StartCrashServer(false)) // false = we are already in a separate process. + { + MITK_INFO << "mitk Crash Reporting Server successfully started."; + } + else + { + MITK_WARN << "Error during start of mitk Crash Reporting Server. Shutting down."; + exit(2); // a server might be already running. + } + + //Timer* shutdownTimer = new Timer(); + // shutdownTimer->start(3000); + + //qtapplication.exec(); + } + catch(...) + { + MITK_WARN << "mitk Crash Reporting Server exception caught, shutdown."; + exit(2); + } + + MITK_INFO << "mitk Crash Reporting Server shuting down."; +} diff --git a/Modules/CMakeLists.txt b/Modules/CMakeLists.txt index 3943c52f02..93d8d43421 100644 --- a/Modules/CMakeLists.txt +++ b/Modules/CMakeLists.txt @@ -1,65 +1,66 @@ set(LIBPOSTFIX "Ext") # Modules must be listed according to their dependencies set(module_dirs SeedsImage SceneSerializationBase PlanarFigure ImageExtraction ImageStatistics LegacyAdaptors IpPicSupport MitkExt SceneSerialization GraphAlgorithms SurfaceInterpolation Segmentation PlanarFigureSegmentation Qmitk QmitkExt SegmentationUI Properties DiffusionImaging GPGPU IGT CameraCalibration IGTUI RigidRegistration RigidRegistrationUI DeformableRegistration DeformableRegistrationUI OpenCL OpenCVVideoSupport Overlays InputDevices ToFHardware ToFProcessing ToFUI US ClippingTools USUI DicomUI Simulation Remeshing Python + BreakpadCrashReporting ) set(MITK_DEFAULT_SUBPROJECTS MITK-Modules) foreach(module_dir ${module_dirs}) add_subdirectory(${module_dir}) endforeach() if(MITK_PRIVATE_MODULES) file(GLOB all_subdirs RELATIVE ${MITK_PRIVATE_MODULES} ${MITK_PRIVATE_MODULES}/*) foreach(subdir ${all_subdirs}) string(FIND ${subdir} "." _result) if(_result EQUAL -1) if(EXISTS ${MITK_PRIVATE_MODULES}/${subdir}/CMakeLists.txt) message(STATUS "Found private module ${subdir}") add_subdirectory(${MITK_PRIVATE_MODULES}/${subdir} private_modules/${subdir}) endif() endif() endforeach() endif(MITK_PRIVATE_MODULES) diff --git a/SuperBuild.cmake b/SuperBuild.cmake index f70deb3293..0c81ac349c 100644 --- a/SuperBuild.cmake +++ b/SuperBuild.cmake @@ -1,366 +1,371 @@ #----------------------------------------------------------------------------- # Convenient macro allowing to download a file #----------------------------------------------------------------------------- macro(downloadFile url dest) file(DOWNLOAD ${url} ${dest} STATUS status) list(GET status 0 error_code) list(GET status 1 error_msg) if(error_code) message(FATAL_ERROR "error: Failed to download ${url} - ${error_msg}") endif() endmacro() #----------------------------------------------------------------------------- # MITK Prerequisites #----------------------------------------------------------------------------- if(UNIX AND NOT APPLE) include(mitkFunctionCheckPackageHeader) # Check for libxt-dev mitkFunctionCheckPackageHeader(StringDefs.h libxt-dev /usr/include/X11/) # Check for libtiff4-dev mitkFunctionCheckPackageHeader(tiff.h libtiff4-dev) # Check for libwrap0-dev mitkFunctionCheckPackageHeader(tcpd.h libwrap0-dev) endif() #----------------------------------------------------------------------------- # ExternalProjects #----------------------------------------------------------------------------- set(external_projects VTK ACVD GDCM CableSwig ITK Boost + Breakpad DCMTK CTK OpenCV SOFA MITKData ) set(MITK_USE_CableSwig ${MITK_USE_Python}) set(MITK_USE_GDCM 1) set(MITK_USE_ITK 1) set(MITK_USE_VTK 1) foreach(proj VTK ACVD GDCM CableSwig ITK DCMTK CTK OpenCV SOFA) if(MITK_USE_${proj}) set(EXTERNAL_${proj}_DIR "${${proj}_DIR}" CACHE PATH "Path to ${proj} build directory") mark_as_advanced(EXTERNAL_${proj}_DIR) if(EXTERNAL_${proj}_DIR) set(${proj}_DIR ${EXTERNAL_${proj}_DIR}) endif() endif() endforeach() if(MITK_USE_Boost) set(EXTERNAL_BOOST_ROOT "${BOOST_ROOT}" CACHE PATH "Path to Boost directory") mark_as_advanced(EXTERNAL_BOOST_ROOT) if(EXTERNAL_BOOST_ROOT) set(BOOST_ROOT ${EXTERNAL_BOOST_ROOT}) endif() endif() if(BUILD_TESTING) set(EXTERNAL_MITK_DATA_DIR "${MITK_DATA_DIR}" CACHE PATH "Path to the MITK data directory") mark_as_advanced(EXTERNAL_MITK_DATA_DIR) if(EXTERNAL_MITK_DATA_DIR) set(MITK_DATA_DIR ${EXTERNAL_MITK_DATA_DIR}) endif() endif() # Look for git early on, if needed if((BUILD_TESTING AND NOT EXTERNAL_MITK_DATA_DIR) OR (MITK_USE_CTK AND NOT EXTERNAL_CTK_DIR)) find_package(Git REQUIRED) endif() #----------------------------------------------------------------------------- # External project settings #----------------------------------------------------------------------------- include(ExternalProject) set(ep_base "${CMAKE_BINARY_DIR}/CMakeExternals") set_property(DIRECTORY PROPERTY EP_BASE ${ep_base}) set(ep_install_dir ${ep_base}/Install) #set(ep_build_dir ${ep_base}/Build) set(ep_source_dir ${ep_base}/Source) #set(ep_parallelism_level) set(ep_build_shared_libs ON) set(ep_build_testing OFF) if(NOT MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL) set(MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL http://mitk.org/download/thirdparty) endif() # Compute -G arg for configuring external projects with the same CMake generator: if(CMAKE_EXTRA_GENERATOR) set(gen "${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}") else() set(gen "${CMAKE_GENERATOR}") endif() # Use this value where semi-colons are needed in ep_add args: set(sep "^^") ## if(MSVC_VERSION) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /bigobj /MP") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj /MP") endif() set(ep_common_args -DBUILD_TESTING:BOOL=${ep_build_testing} -DCMAKE_INSTALL_PREFIX:PATH=${ep_install_dir} -DBUILD_SHARED_LIBS:BOOL=ON -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} #debug flags -DCMAKE_CXX_FLAGS_DEBUG:STRING=${CMAKE_CXX_FLAGS_DEBUG} -DCMAKE_C_FLAGS_DEBUG:STRING=${CMAKE_C_FLAGS_DEBUG} #release flags -DCMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE} -DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE} #relwithdebinfo -DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DCMAKE_C_FLAGS_RELWITHDEBINFO:STRING=${CMAKE_C_FLAGS_RELWITHDEBINFO} #link flags -DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS} -DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_MODULE_LINKER_FLAGS} ) # Include external projects foreach(p ${external_projects}) include(CMakeExternals/${p}.cmake) endforeach() #----------------------------------------------------------------------------- # Set superbuild boolean args #----------------------------------------------------------------------------- set(mitk_cmake_boolean_args BUILD_SHARED_LIBS WITH_COVERAGE BUILD_TESTING MITK_USE_QT MITK_BUILD_ALL_PLUGINS MITK_BUILD_ALL_APPS MITK_BUILD_TUTORIAL # Deprecated. Use MITK_BUILD_EXAMPLES instead MITK_BUILD_EXAMPLES MITK_USE_ACVD MITK_USE_Boost + MITK_USE_Breakpad MITK_USE_SYSTEM_Boost MITK_USE_BLUEBERRY MITK_USE_CTK MITK_USE_DCMTK MITK_DCMTK_BUILD_SHARED_LIBS MITK_USE_OpenCV MITK_USE_SOFA MITK_USE_Python MITK_USE_OpenCL ) #----------------------------------------------------------------------------- # Create the final variable containing superbuild boolean args #----------------------------------------------------------------------------- set(mitk_superbuild_boolean_args) foreach(mitk_cmake_arg ${mitk_cmake_boolean_args}) list(APPEND mitk_superbuild_boolean_args -D${mitk_cmake_arg}:BOOL=${${mitk_cmake_arg}}) endforeach() if(MITK_BUILD_ALL_PLUGINS) list(APPEND mitk_superbuild_boolean_args -DBLUEBERRY_BUILD_ALL_PLUGINS:BOOL=ON) endif() #----------------------------------------------------------------------------- # MITK Utilities #----------------------------------------------------------------------------- set(proj MITK-Utilities) ExternalProject_Add(${proj} DOWNLOAD_COMMAND "" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" DEPENDS # Mandatory dependencies ${VTK_DEPENDS} ${ITK_DEPENDS} # Optionnal dependencies ${ACVD_DEPENDS} ${Boost_DEPENDS} + ${Breakpad_DEPENDS} ${CTK_DEPENDS} ${DCMTK_DEPENDS} ${OpenCV_DEPENDS} ${SOFA_DEPENDS} ${MITK-Data_DEPENDS} ) #----------------------------------------------------------------------------- # Additional MITK CXX/C Flags #----------------------------------------------------------------------------- set(MITK_ADDITIONAL_C_FLAGS "" CACHE STRING "Additional C Flags for MITK") set(MITK_ADDITIONAL_C_FLAGS_RELEASE "" CACHE STRING "Additional Release C Flags for MITK") set(MITK_ADDITIONAL_C_FLAGS_DEBUG "" CACHE STRING "Additional Debug C Flags for MITK") mark_as_advanced(MITK_ADDITIONAL_C_FLAGS MITK_ADDITIONAL_C_FLAGS_DEBUG MITK_ADDITIONAL_C_FLAGS_RELEASE) set(MITK_ADDITIONAL_CXX_FLAGS "" CACHE STRING "Additional CXX Flags for MITK") set(MITK_ADDITIONAL_CXX_FLAGS_RELEASE "" CACHE STRING "Additional Release CXX Flags for MITK") set(MITK_ADDITIONAL_CXX_FLAGS_DEBUG "" CACHE STRING "Additional Debug CXX Flags for MITK") mark_as_advanced(MITK_ADDITIONAL_CXX_FLAGS MITK_ADDITIONAL_CXX_FLAGS_DEBUG MITK_ADDITIONAL_CXX_FLAGS_RELEASE) set(MITK_ADDITIONAL_EXE_LINKER_FLAGS "" CACHE STRING "Additional exe linker flags for MITK") set(MITK_ADDITIONAL_SHARED_LINKER_FLAGS "" CACHE STRING "Additional shared linker flags for MITK") set(MITK_ADDITIONAL_MODULE_LINKER_FLAGS "" CACHE STRING "Additional module linker flags for MITK") mark_as_advanced(MITK_ADDITIONAL_EXE_LINKER_FLAGS MITK_ADDITIONAL_SHARED_LINKER_FLAGS MITK_ADDITIONAL_MODULE_LINKER_FLAGS) #----------------------------------------------------------------------------- # MITK Configure #----------------------------------------------------------------------------- if(MITK_INITIAL_CACHE_FILE) set(mitk_initial_cache_arg -C "${MITK_INITIAL_CACHE_FILE}") endif() set(mitk_optional_cache_args ) foreach(type RUNTIME ARCHIVE LIBRARY) if(DEFINED CTK_PLUGIN_${type}_OUTPUT_DIRECTORY) list(APPEND mitk_optional_cache_args -DCTK_PLUGIN_${type}_OUTPUT_DIRECTORY:PATH=${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}) endif() endforeach() # Optional python variables if(MITK_USE_Python) list(APPEND mitk_optional_cache_args -DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE} -DPYTHON_INCLUDE_DIR:PATH=${PYTHON_INCLUDE_DIR} -DPYTHON_LIBRARY:FILEPATH=${PYTHON_LIBRARY} -DPYTHON_INCLUDE_DIR2:PATH=${PYTHON_INCLUDE_DIR2} ) endif() set(proj MITK-Configure) ExternalProject_Add(${proj} LIST_SEPARATOR ^^ DOWNLOAD_COMMAND "" CMAKE_GENERATOR ${gen} CMAKE_CACHE_ARGS # --------------- Build options ---------------- -DBUILD_TESTING:BOOL=${ep_build_testing} -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/MITK-build/install -DBUILD_SHARED_LIBS:BOOL=ON -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} # --------------- Compile options ---------------- -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} ${MITK_ADDITIONAL_C_FLAGS}" "-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} ${MITK_ADDITIONAL_CXX_FLAGS}" # debug flags "-DCMAKE_CXX_FLAGS_DEBUG:STRING=${CMAKE_CXX_FLAGS_DEBUG} ${MITK_ADDITIONAL_CXX_FLAGS_DEBUG}" "-DCMAKE_C_FLAGS_DEBUG:STRING=${CMAKE_C_FLAGS_DEBUG} ${MITK_ADDITIONAL_C_FLAGS_DEBUG}" # release flags "-DCMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE} ${MITK_ADDITIONAL_CXX_FLAGS_RELEASE}" "-DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE} ${MITK_ADDITIONAL_C_FLAGS_RELEASE}" # relwithdebinfo -DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DCMAKE_C_FLAGS_RELWITHDEBINFO:STRING=${CMAKE_C_FLAGS_RELWITHDEBINFO} # link flags "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS} ${MITK_ADDITIONAL_EXE_LINKER_FLAGS}" "-DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS} ${MITK_ADDITIONAL_SHARED_LINKER_FLAGS}" "-DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_MODULE_LINKER_FLAGS} ${MITK_ADDITIONAL_MODULE_LINKER_FLAGS}" # Output directories -DMITK_CMAKE_LIBRARY_OUTPUT_DIRECTORY:PATH=${MITK_CMAKE_LIBRARY_OUTPUT_DIRECTORY} -DMITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY:PATH=${MITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY} -DMITK_CMAKE_ARCHIVE_OUTPUT_DIRECTORY:PATH=${MITK_CMAKE_ARCHIVE_OUTPUT_DIRECTORY} # ------------- Boolean build options -------------- ${mitk_superbuild_boolean_args} ${mitk_optional_cache_args} -DMITK_USE_SUPERBUILD:BOOL=OFF -DCTEST_USE_LAUNCHERS:BOOL=${CTEST_USE_LAUNCHERS} # ----------------- Miscellaneous --------------- -DMITK_CTEST_SCRIPT_MODE:STRING=${MITK_CTEST_SCRIPT_MODE} -DMITK_SUPERBUILD_BINARY_DIR:PATH=${MITK_BINARY_DIR} -DMITK_MODULES_TO_BUILD:INTERNAL=${MITK_MODULES_TO_BUILD} -DMITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES:STRING=${MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES} -DMITK_ACCESSBYITK_FLOATING_PIXEL_TYPES:STRING=${MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES} -DMITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES:STRING=${MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES} -DMITK_ACCESSBYITK_DIMENSIONS:STRING=${MITK_ACCESSBYITK_DIMENSIONS} # --------------- External project dirs --------------- -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE} -DMITK_KWSTYLE_EXECUTABLE:FILEPATH=${MITK_KWSTYLE_EXECUTABLE} -DCTK_DIR:PATH=${CTK_DIR} -DDCMTK_DIR:PATH=${DCMTK_DIR} -DVTK_DIR:PATH=${VTK_DIR} # FindVTK expects VTK_DIR -DITK_DIR:PATH=${ITK_DIR} # FindITK expects ITK_DIR -DACVD_DIR:PATH=${ACVD_DIR} -DOpenCV_DIR:PATH=${OpenCV_DIR} -DSOFA_DIR:PATH=${SOFA_DIR} -DGDCM_DIR:PATH=${GDCM_DIR} -DBOOST_ROOT:PATH=${BOOST_ROOT} + -DBreakpad_DIR:PATH=${Breakpad_DIR} + -DBreakpad_SRC:PATH=${Breakpad_SRC} -DMITK_USE_Boost_LIBRARIES:STRING=${MITK_USE_Boost_LIBRARIES} -DMITK_DATA_DIR:PATH=${MITK_DATA_DIR} CMAKE_ARGS ${mitk_initial_cache_arg} SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} BINARY_DIR ${CMAKE_BINARY_DIR}/MITK-build BUILD_COMMAND "" INSTALL_COMMAND "" DEPENDS MITK-Utilities ) #----------------------------------------------------------------------------- # MITK #----------------------------------------------------------------------------- if(CMAKE_GENERATOR MATCHES ".*Makefiles.*") set(mitk_build_cmd "$(MAKE)") else() set(mitk_build_cmd ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/MITK-build --config ${CMAKE_CFG_INTDIR}) endif() if(NOT DEFINED SUPERBUILD_EXCLUDE_MITKBUILD_TARGET OR NOT SUPERBUILD_EXCLUDE_MITKBUILD_TARGET) set(MITKBUILD_TARGET_ALL_OPTION "ALL") else() set(MITKBUILD_TARGET_ALL_OPTION "") endif() add_custom_target(MITK-build ${MITKBUILD_TARGET_ALL_OPTION} COMMAND ${mitk_build_cmd} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/MITK-build DEPENDS MITK-Configure ) #----------------------------------------------------------------------------- # Custom target allowing to drive the build of the MITK project itself #----------------------------------------------------------------------------- add_custom_target(MITK COMMAND ${mitk_build_cmd} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/MITK-build )