diff --git a/CMakeLists.txt b/CMakeLists.txt index cd269d5..8b4abff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ set(SRC_FILES misc/random.cpp tests/testutils.cpp ) + set(TEST_HEADER_FILES ) @@ -59,155 +60,40 @@ set(TEST_SRC_FILES tests/chronotests.cpp ) +set(CMAKE_MODULE_FILES + cmake/modules/BasicConfig.cmake + cmake/modules/LibraryTarget.cmake + cmake/modules/TestTarget.cmake + cmake/modules/AppTarget.cmake + cmake/modules/WindowsResources.cmake +) +set(CMAKE_TEMPLATE_FILES + cmake/templates/Config.cmake.in + cmake/templates/config.h.in + cmake/templates/desktop.in +) +if(MINGW) + list(APPEND CMAKE_TEMPLATE_FILES + cmake/templates/windows.rc.in + ) +endif() + +# required to include CMake modules from own project directory +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" "${CMAKE_MODULE_PATH}") + # meta data set(META_PROJECT_NAME c++utilities) +set(META_PROJECT_VARNAME CPP_UTILITIES) set(META_APP_NAME "C++ Utilities") set(META_APP_AUTHOR "Martchus") set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}") set(META_APP_DESCRIPTION "Common C++ classes and routines used by my applications such as argument parser, IO and conversion utilities.") set(META_VERSION_MAJOR 3) set(META_VERSION_MINOR 2) -set(META_VERSION_PATCH 0) -set(META_APP_VERSION ${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH}) +set(META_VERSION_PATCH 1) -# stringification of meta data -set(META_PROJECT_NAME_STR "\"${META_PROJECT_NAME}\"") -set(META_APP_NAME_STR "\"${META_APP_NAME}\"") -set(META_APP_AUTHOR_STR "\"${META_APP_AUTHOR}\"") -set(META_APP_URL_STR "\"${META_APP_URL}\"") -set(META_APP_DESCRIPTION_STR "\"${META_APP_DESCRIPTION}\"") -set(META_APP_VERSION ${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH}) -set(META_APP_VERSION_STR "\"${META_APP_VERSION}\"") - -# define project -project(${META_PROJECT_NAME}) - -# add configuration header -configure_file( - "${PROJECT_SOURCE_DIR}/resources/config.h.in" - "${PROJECT_BINARY_DIR}/resources/config.h" -) -include_directories("${PROJECT_BINARY_DIR}") - -# add windows resource file -if(MINGW) - # create windows rc file from template - set(WINDOWS_EXT "dll") - configure_file( - "${PROJECT_SOURCE_DIR}/resources/windows.rc.in" - "${PROJECT_BINARY_DIR}/resources/windows.rc" - ) - # set windres as resource compiler - set(RES_FILES "${PROJECT_BINARY_DIR}/resources/windows.rc") - set(CMAKE_RC_COMPILER_INIT windres) - set(CMAKE_RC_COMPILE_OBJECT " -O coff -i -o ") - enable_language(RC) -endif(MINGW) - -# remove library prefix when building with mingw-w64 (just for consistancy with qmake) -if(MINGW) - set(CMAKE_SHARED_LIBRARY_PREFIX "") -endif(MINGW) - -# disable new ABI (can't catch ios_base::failure with new ABI) -add_definitions( - -D_GLIBCXX_USE_CXX11_ABI=0 -) - -# executable and linking -add_library(${META_PROJECT_NAME} SHARED ${HEADER_FILES} ${SRC_FILES} ${RES_FILES} ${WINDOWS_ICON_PATH}) -set_target_properties(${META_PROJECT_NAME} PROPERTIES - VERSION ${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH} - SOVERSION ${META_VERSION_MAJOR} - CXX_STANDARD 11 -) -if(MINGW) - # enable static library when building with mingw-w64 - add_library(${META_PROJECT_NAME}_static STATIC ${HEADER_FILES} ${SRC_FILES} ${RES_FILES} ${WINDOWS_ICON_PATH}) - set_target_properties(${META_PROJECT_NAME}_static PROPERTIES - VERSION ${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH} - SOVERSION ${META_VERSION_MAJOR} - OUTPUT_NAME ${META_PROJECT_NAME} - CXX_STANDARD 11 - ) -endif(MINGW) - -# add check target -if(NOT TARGET check) - set(CMAKE_CTEST_COMMAND ctest -V) - add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}) - enable_testing() -endif() -add_executable(${META_PROJECT_NAME}_tests EXCLUDE_FROM_ALL ${TEST_HEADER_FILES} ${TEST_SRC_FILES}) -target_link_libraries(${META_PROJECT_NAME}_tests ${META_PROJECT_NAME} cppunit) -set_target_properties(${META_PROJECT_NAME}_tests PROPERTIES CXX_STANDARD 11) -add_test(NAME ${META_PROJECT_NAME}_cppunit COMMAND ${META_PROJECT_NAME}_tests -p "${CMAKE_CURRENT_SOURCE_DIR}/testfiles") -add_dependencies(check ${META_PROJECT_NAME}_tests) - -# add install target -install(TARGETS ${META_PROJECT_NAME} - RUNTIME DESTINATION bin - COMPONENT binary - LIBRARY DESTINATION lib - COMPONENT binary - ARCHIVE DESTINATION lib - COMPONENT binary -) -if(MINGW) - install(TARGETS ${META_PROJECT_NAME}_static - RUNTIME DESTINATION bin - COMPONENT binary - LIBRARY DESTINATION lib - COMPONENT binary - ARCHIVE DESTINATION lib - COMPONENT binary - ) -endif(MINGW) -foreach(HEADER_FILE ${HEADER_FILES}) - get_filename_component(HEADER_DIR ${HEADER_FILE} DIRECTORY) - install( - FILES ${HEADER_FILE} - DESTINATION include/${META_PROJECT_NAME}/${HEADER_DIR} - COMPONENT header - ) -endforeach() -if(NOT TARGET install-binary) - add_custom_target(install-binary - DEPENDS ${META_PROJECT_NAME} - COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=binary -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" - ) -endif() -if(NOT TARGET install-header) - add_custom_target(install-header - DEPENDS ${META_PROJECT_NAME} - COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=header -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" - ) -endif() -if(NOT TARGET install-mingw-w64) - add_custom_target(install-mingw-w64 - DEPENDS install-binary install-header - ) -endif() -if(NOT TARGET install-binary-strip) - add_custom_target(install-binary-strip - DEPENDS ${META_PROJECT_NAME} - COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_DO_STRIP=1 -DCMAKE_INSTALL_COMPONENT=binary -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" - ) -endif() -if(NOT TARGET install-mingw-w64-importlib-strip) - add_custom_target(install-mingw-w64-importlib-strip - DEPENDS install-binary-strip - COMMAND "${CMAKE_FIND_ROOT_PATH}/bin/strip" --strip-unneeded "${CMAKE_INSTALL_PREFIX}/lib/lib${META_PROJECT_NAME}.dll.a" - ) -endif() -if(NOT TARGET install-mingw-w64-staticlib-strip) - add_custom_target(install-mingw-w64-staticlib-strip - DEPENDS install-binary-strip - COMMAND "${CMAKE_FIND_ROOT_PATH}/bin/strip" -g "${CMAKE_INSTALL_PREFIX}/lib/lib${META_PROJECT_NAME}.a" - ) -endif() -if(NOT TARGET install-mingw-w64-strip) - add_custom_target(install-mingw-w64-strip - DEPENDS install-binary-strip install-mingw-w64-importlib-strip install-mingw-w64-staticlib-strip install-header - ) -endif() +# include modules to apply configuration +include(BasicConfig) +include(WindowsResources) +include(LibraryTarget) +include(TestTarget) diff --git a/README.md b/README.md index b8d5035..783b444 100644 --- a/README.md +++ b/README.md @@ -33,12 +33,6 @@ make check # build and run unit tests (optional) make install ``` -Building with qmake is also possible: -``` -INSTALL_ROOT="/where/you/want/to/install" qmake-qt5 "path/to/projectfile" -make && make install -``` - Building for Windows with Mingw-w64 cross compiler can be utilized using a small [cmake wrapper from Fedora](https://aur.archlinux.org/cgit/aur.git/tree/mingw-cmake.sh?h=mingw-w64-cmake): ``` @@ -58,5 +52,5 @@ PKGBUILD files to build for Windows using the Mingw-w64 compiler are also includ is currently disabled. Linking against cppunit built using new libstdc++ ABI isn't possible. ## TODO -- rewrite argument parser +- rewrite argument parser (the API might change slightly) - remove unused features diff --git a/c++utilities.pro b/c++utilities.pro deleted file mode 100644 index f12b7a2..0000000 --- a/c++utilities.pro +++ /dev/null @@ -1,93 +0,0 @@ -# meta data -projectname = c++utilities -appname = "C++ Utilities" -appauthor = Martchus -QMAKE_TARGET_DESCRIPTION = "Common C++ classes and routines used by my applications such as argument parser, IO and conversion utilities." -VERSION = 3.2.0 - -# include ../../common.pri when building as part of a subdirs project; otherwise include general.pri -!include(../../common.pri) { - !include(./general.pri) { - error("Couldn't find the common.pri or the general.pri file!") - } -} - -# basic configuration: shared library, no Qt -TEMPLATE = lib -CONFIG -= qt -CONFIG += shared - -# add project files -HEADERS += \ - application/argumentparser.h \ - application/commandlineutils.h \ - application/failure.h \ - application/fakeqtconfigarguments.h \ - application/global.h \ - chrono/datetime.h \ - chrono/period.h \ - chrono/timespan.h \ - conversion/binaryconversion.h \ - conversion/binaryconversionprivate.h \ - conversion/conversionexception.h \ - conversion/stringconversion.h \ - conversion/types.h \ - conversion/widen.h \ - io/ansiescapecodes.h \ - io/binaryreader.h \ - io/binarywriter.h \ - io/bitreader.h \ - io/copy.h \ - io/inifile.h \ - io/path.h \ - math/math.h \ - misc/memory.h \ - misc/random.h \ - tests/testutils.h \ - tests/cppunit.h \ - -SOURCES += \ - application/argumentparser.cpp \ - application/commandlineutils.cpp \ - application/failure.cpp \ - application/fakeqtconfigarguments.cpp \ - chrono/datetime.cpp \ - chrono/period.cpp \ - chrono/timespan.cpp \ - conversion/conversionexception.cpp \ - conversion/stringconversion.cpp \ - io/ansiescapecodes.cpp \ - io/binaryreader.cpp \ - io/binarywriter.cpp \ - io/bitreader.cpp \ - io/inifile.cpp \ - io/path.cpp \ - math/math.cpp \ - misc/random.cpp \ - tests/testutils.cpp - -OTHER_FILES += \ - README.md \ - LICENSE \ - CMakeLists.txt \ - resources/config.h.in \ - resources/windows.rc.in - -# installs -mingw-w64-install { - target.path = $$(INSTALL_ROOT) - target.extra = install -m755 -D $${OUT_PWD}/release/lib$(TARGET).a $$(INSTALL_ROOT)/lib/lib$(TARGET).a - INSTALLS += target - dlltarget.path = $$(INSTALL_ROOT) - dlltarget.extra = install -m755 -D $${OUT_PWD}/release/$(TARGET) $$(INSTALL_ROOT)/bin/$(TARGET) - INSTALLS += dlltarget -} else { - target.path = $$(INSTALL_ROOT)/lib - INSTALLS += target -} -for(dir, $$list(application io conversion chrono math misc tests)) { - eval(inc_$${dir} = $${dir}) - inc_$${dir}.path = $$(INSTALL_ROOT)/include/$$projectname/$${dir} - inc_$${dir}.files = $${dir}/*.h - INSTALLS += inc_$${dir} -} diff --git a/cmake/modules/AppTarget.cmake b/cmake/modules/AppTarget.cmake new file mode 100644 index 0000000..f33f9a3 --- /dev/null +++ b/cmake/modules/AppTarget.cmake @@ -0,0 +1,122 @@ +# before including this module, BasicConfig must be included + +# set the windows extension to "exe", this is required by the mingw-w64 specific WindowsResources module +if(MINGW) + set(WINDOWS_EXT "exe") +endif(MINGW) + +# add target for building the application +add_executable(${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX} ${GUI_TYPE} ${HEADER_FILES} ${SRC_FILES} ${WIDGETS_FILES} ${QML_FILES} ${RES_FILES} ${QM_FILES} ${WINDOWS_ICON_PATH}) +target_link_libraries(${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX} ${LIBRARIES}) +set_target_properties(${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX} PROPERTIES + CXX_STANDARD 11 +) + +# add install target for binary +install(TARGETS ${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX} + RUNTIME DESTINATION bin + COMPONENT binary +) + +if(NOT TARGET install-binary) + add_custom_target(install-binary + DEPENDS ${META_PROJECT_NAME} + COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=binary -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" + ) +endif() + +# add install target for localization +if(NOT TARGET install-mingw-w64) + add_custom_target(install-mingw-w64 + DEPENDS install-binary ${LOCALIZATION_TARGET} + ) +endif() + +# add install target for desktop entries and icons +foreach(DESKTOP_FILE ${DESKTOP_FILES}) + install( + FILES "${DESKTOP_FILE}" + DESTINATION "share/applications" + COMPONENT desktop + ) +endforeach() + +foreach(ICON_FILE ${ICON_FILES}) + install( + FILES "${ICON_FILE}" + DESTINATION "share/icons/hicolor/scalable/apps" + COMPONENT desktop + ) +endforeach() + +if(NOT TARGET install-desktop) + add_custom_target(install-desktop + DEPENDS ${META_PROJECT_NAME} + COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=desktop -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" + ) +endif() + +# add install target for stripped binaries +if(NOT TARGET install-binary-strip) + add_custom_target(install-binary-strip + DEPENDS ${META_PROJECT_NAME} + COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_DO_STRIP=1 -DCMAKE_INSTALL_COMPONENT=binary -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" + ) +endif() + +# add mingw-w64 specific install target +if(NOT TARGET install-mingw-w64-strip) + add_custom_target(install-mingw-w64-strip + DEPENDS install-binary-strip ${LOCALIZATION_TARGET} + ) +endif() + +# find template for *.desktop files +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/desktop.in") + # check own source directory + set(APP_DESKTOP_TEMPLATE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/desktop.in") + message(STATUS "Using template for *.desktop file from own source directory.") +elseif(EXISTS "${CPP_UTILITIES_SOURCE_DIR}/cmake/templates/desktop.in") + # check sources of c++utilities + set(APP_DESKTOP_TEMPLATE_FILE "${CPP_UTILITIES_SOURCE_DIR}/cmake/templates/desktop.in") + message(STATUS "Using template for *.desktop file from c++utilities source directory.") +elseif(EXISTS "${CMAKE_INSTALL_PREFIX}/share/c++utilities/cmake/templates/desktop.in") + # check installed version of c++utilities + set(APP_DESKTOP_TEMPLATE_FILE "${CMAKE_INSTALL_PREFIX}/share/c++utilities/cmake/templates/desktop.in") + message(STATUS "Using template for *.desktop file from c++utilities installation.") +else() + message(FATAL_ERROR "Template for *.desktop file can not be located.") +endif() + +# function to add *.desktop files +function(add_custom_desktop_file + FILE_NAME + DESKTOP_FILE_APP_NAME + DESKTOP_FILE_DESCRIPTION + DESKTOP_FILE_CATEGORIES + DESKTOP_FILE_CMD + DESKTOP_FILE_ICON) + # create desktop file from template + configure_file( + "${APP_DESKTOP_TEMPLATE_FILE}" + "${CMAKE_CURRENT_BINARY_DIR}/resources/${FILE_NAME}.desktop" + ) + # add install for the desktop file + install( + FILES "${CMAKE_CURRENT_BINARY_DIR}/resources/${FILE_NAME}.desktop" + DESTINATION "share/applications" + COMPONENT desktop + ) +endfunction() + +# convenience function to add *.desktop file from project meta data +function(add_desktop_file) + add_custom_desktop_file( + "${META_PROJECT_NAME}" + "${META_APP_NAME}" + "${META_APP_DESCRIPTION}" + "${META_APP_CATEGORIES}" + "${META_PROJECT_NAME}" + "${META_PROJECT_NAME}" + ) +endfunction() diff --git a/cmake/modules/BasicConfig.cmake b/cmake/modules/BasicConfig.cmake new file mode 100644 index 0000000..4a97f3d --- /dev/null +++ b/cmake/modules/BasicConfig.cmake @@ -0,0 +1,55 @@ +# before including this module, the project meta-data must be set + +# set project name (displayed in Qt Creator) +project(${META_PROJECT_NAME}) + +# might be useful so other projects built as part of the same subdirs project +# can access files from this project +set(${META_PROJECT_VARNAME}_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE) +set(${META_PROJECT_VARNAME}_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}" PARENT_SCOPE) +set(${META_PROJECT_NAME}_DIR "${CMAKE_CURRENT_BINARY_DIR}" PARENT_SCOPE) + +# stringify the meta data +set(META_PROJECT_NAME_STR "\"${META_PROJECT_NAME}\"") +set(META_APP_VERSION ${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH}) +set(META_APP_NAME_STR "\"${META_APP_NAME}\"") +set(META_APP_AUTHOR_STR "\"${META_APP_AUTHOR}\"") +set(META_APP_URL_STR "\"${META_APP_URL}\"") +set(META_APP_DESCRIPTION_STR "\"${META_APP_DESCRIPTION}\"") +set(META_APP_VERSION_STR "\"${META_APP_VERSION}\"") + +# find config.h template +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/config.h.in") + # check own source directory + set(CONFIG_H_TEMPLATE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/config.h.in") + message(STATUS "Using template for config.h from own source directory.") +elseif(EXISTS "${CPP_UTILITIES_SOURCE_DIR}/cmake/templates/config.h.in") + # check sources of c++utilities + set(CONFIG_H_TEMPLATE_FILE "${CPP_UTILITIES_SOURCE_DIR}/cmake/templates/config.h.in") + message(STATUS "Using template for config.h from c++utilities source directory.") +elseif(EXISTS "${CMAKE_INSTALL_PREFIX}/share/c++utilities/cmake/templates/config.h.in") + # check installed version of c++utilities + set(CONFIG_H_TEMPLATE_FILE "${CMAKE_INSTALL_PREFIX}/share/c++utilities/cmake/templates/config.h.in") + message(STATUS "Using template for config.h from c++utilities installation.") +else() + message(FATAL_ERROR "Template for config.h file can not be located.") +endif() + +# add configuration header +configure_file( + "${CONFIG_H_TEMPLATE_FILE}" + "${CMAKE_CURRENT_BINARY_DIR}/resources/config.h" +) + +# ensure generated include files are found +include_directories("${CMAKE_CURRENT_BINARY_DIR}") + +# disable new ABI (can't catch ios_base::failure with new ABI) +add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) +message(STATUS "Forcing usage of old CXX11 ABI to be able to catch std::ios_base::failure.") + +# enable debug-only code when doing a debug build +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + add_definitions(-DDEBUG_BUILD) + message(STATUS "Debug build enabled.") +endif() diff --git a/cmake/modules/LibraryTarget.cmake b/cmake/modules/LibraryTarget.cmake new file mode 100644 index 0000000..8ac509d --- /dev/null +++ b/cmake/modules/LibraryTarget.cmake @@ -0,0 +1,218 @@ +# before including this module, BasicConfig must be included + +# include for configure_package_config_file and write_basic_package_version_file +include(CMakePackageConfigHelpers) + +# find template for CMake config file +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/Config.cmake.in") + # check own source directory + set(CONFIG_TEMPLATE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/Config.cmake.in") +elseif(EXISTS "${CPP_UTILITIES_SOURCE_DIR}/cmake/templates/Config.cmake.in") + # check sources of c++utilities + set(CONFIG_TEMPLATE_FILE "${CPP_UTILITIES_SOURCE_DIR}/cmake/templates/Config.cmake.in") +elseif(EXISTS "${CMAKE_INSTALL_PREFIX}/share/c++utilities/cmake/templates/Config.cmake.in") + # check installed version of c++utilities + set(CONFIG_TEMPLATE_FILE "${CMAKE_INSTALL_PREFIX}/share/c++utilities/cmake/templates/Config.cmake.in") +else() + message(FATAL_ERROR "Template for configuration file can not be located.") +endif() + +# set install destination for the CMake modules, config files and header files +set(HEADER_INSTALL_DESTINATION "${CMAKE_INSTALL_PREFIX}/include") +set(LIB_INSTALL_DESTINATION "${CMAKE_INSTALL_PREFIX}/lib") +set(CMAKE_MODULE_INSTALL_DESTINATION "${CMAKE_INSTALL_PREFIX}/share/${META_PROJECT_NAME}/cmake/modules") +set(CMAKE_CONFIG_INSTALL_DESTINATION "${CMAKE_INSTALL_PREFIX}/share/${META_PROJECT_NAME}/cmake") + +# create the CMake config file from the template +configure_package_config_file( + "${CONFIG_TEMPLATE_FILE}" + "${CMAKE_CURRENT_BINARY_DIR}/${META_PROJECT_NAME}Config.cmake" + INSTALL_DESTINATION + "${CMAKE_CONFIG_INSTALL_DESTINATION}" + PATH_VARS + CMAKE_MODULE_INSTALL_DESTINATION + CMAKE_CONFIG_INSTALL_DESTINATION + HEADER_INSTALL_DESTINATION + LIB_INSTALL_DESTINATION +) + +# write the CMake version config file +write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/${META_PROJECT_NAME}ConfigVersion.cmake + VERSION "${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH}" + COMPATIBILITY SameMajorVersion +) + +# remove library prefix when building with mingw-w64 (just for consistency with qmake) +if(MINGW) + set(CMAKE_SHARED_LIBRARY_PREFIX "") +endif(MINGW) + +# set the windows extension to "dll", this is required by the mingw-w64 specific WindowsResources module +if(MINGW) + set(WINDOWS_EXT "dll") +endif(MINGW) + +# add target for building the library +add_library(${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX} SHARED ${HEADER_FILES} ${SRC_FILES} ${WIDGETS_FILES} ${QML_FILES} ${RES_FILES} ${QM_FILES} ${WINDOWS_ICON_PATH}) +target_link_libraries(${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX} ${LIBRARIES}) +set_target_properties(${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX} PROPERTIES + VERSION ${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH} + SOVERSION ${META_VERSION_MAJOR} + CXX_STANDARD 11 +) + +# add target for building a static version of the library when building with mingw-w64 +if(MINGW) + add_library(${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX}_static STATIC ${HEADER_FILES} ${SRC_FILES} ${WIDGETS_FILES} ${QML_FILES} ${RES_FILES} ${QM_FILES} ${WINDOWS_ICON_PATH}) + # add target link libraries for the static lib also because otherwise Qt header files can not be located + target_link_libraries(${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX}_static ${LIBRARIES}) + set_target_properties(${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX}_static PROPERTIES + VERSION ${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH} + SOVERSION ${META_VERSION_MAJOR} + OUTPUT_NAME ${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX} + CXX_STANDARD 11 + ) +endif(MINGW) + +# add install target for the CMake config files +install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/${META_PROJECT_NAME}Config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${META_PROJECT_NAME}ConfigVersion.cmake" + DESTINATION + "${CMAKE_CONFIG_INSTALL_DESTINATION}" + COMPONENT + cmake-config +) + +if(NOT TARGET install-cmake-config) + add_custom_target(install-cmake-config + DEPENDS ${META_PROJECT_NAME} + COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=cmake-config -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" + ) +endif() + +# add install target for dynamic libs +install( + TARGETS ${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX} + RUNTIME DESTINATION bin + COMPONENT binary + LIBRARY DESTINATION lib + COMPONENT binary + ARCHIVE DESTINATION lib + COMPONENT binary +) + +if(NOT TARGET install-binary) + add_custom_target(install-binary + DEPENDS ${META_PROJECT_NAME} + COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=binary -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" + ) +endif() + +# add install for static libs when building with mingw-w64 +if(MINGW) + install( + TARGETS ${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX}_static + RUNTIME DESTINATION bin + COMPONENT binary + LIBRARY DESTINATION lib + COMPONENT binary + ARCHIVE DESTINATION lib + COMPONENT binary + ) +endif(MINGW) + +# add install target for stripped libs +if(NOT TARGET install-binary-strip) + add_custom_target(install-binary-strip + DEPENDS ${META_PROJECT_NAME} + COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_DO_STRIP=1 -DCMAKE_INSTALL_COMPONENT=binary -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" + ) +endif() + +# add install target for header files +foreach(HEADER_FILE ${HEADER_FILES}) + get_filename_component(HEADER_DIR "${HEADER_FILE}" DIRECTORY) + install( + FILES "${HEADER_FILE}" + DESTINATION "include/${META_PROJECT_NAME}/${HEADER_DIR}" + COMPONENT header + ) +endforeach() + +if(NOT TARGET install-header) + add_custom_target(install-header + DEPENDS ${META_PROJECT_NAME} + COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=header -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" + ) +endif() + +# add install target for CMake modules +foreach(CMAKE_MODULE_FILE ${CMAKE_MODULE_FILES}) + get_filename_component(CMAKE_MODULE_DIR ${CMAKE_MODULE_FILE} DIRECTORY) + install( + FILES ${CMAKE_MODULE_FILE} + DESTINATION share/${META_PROJECT_NAME}/${CMAKE_MODULE_DIR} + COMPONENT cmake-modules + ) +endforeach() + +if(NOT TARGET install-cmake-modules) + add_custom_target(install-cmake-modules + DEPENDS ${META_PROJECT_NAME} + COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=cmake-modules -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" + ) +endif() + +# add install target for CMake templates +foreach(CMAKE_TEMPLATE_FILE ${CMAKE_TEMPLATE_FILES}) + get_filename_component(CMAKE_TEMPLATE_DIR ${CMAKE_TEMPLATE_FILE} DIRECTORY) + install( + FILES ${CMAKE_TEMPLATE_FILE} + DESTINATION share/${META_PROJECT_NAME}/${CMAKE_TEMPLATE_DIR} + COMPONENT cmake-templates + ) +endforeach() + +if(NOT TARGET install-cmake-templates) + add_custom_target(install-cmake-templates + DEPENDS ${META_PROJECT_NAME} + COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=cmake-templates -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" + ) +endif() + +# add install target for all the cmake stuff +if(NOT TARGET install-cmake-stuff) + add_custom_target(install-cmake-stuff + DEPENDS install-cmake-config install-cmake-modules install-cmake-templates + ) +endif() + +# add mingw-w64 specific install targets +if(NOT TARGET install-mingw-w64) + add_custom_target(install-mingw-w64 + DEPENDS install-binary install-header + ) +endif() + +if(NOT TARGET install-mingw-w64-importlib-strip) + add_custom_target(install-mingw-w64-importlib-strip + DEPENDS install-binary-strip + COMMAND "${CMAKE_FIND_ROOT_PATH}/bin/strip" --strip-unneeded "${CMAKE_INSTALL_PREFIX}/lib/lib${META_PROJECT_NAME}.dll.a" + ) +endif() + +if(NOT TARGET install-mingw-w64-staticlib-strip) + add_custom_target(install-mingw-w64-staticlib-strip + DEPENDS install-binary-strip + COMMAND "${CMAKE_FIND_ROOT_PATH}/bin/strip" -g "${CMAKE_INSTALL_PREFIX}/lib/lib${META_PROJECT_NAME}.a" + ) +endif() + +if(NOT TARGET install-mingw-w64-strip) + add_custom_target(install-mingw-w64-strip + DEPENDS install-binary-strip install-mingw-w64-importlib-strip install-mingw-w64-staticlib-strip install-header + ) +endif() diff --git a/cmake/modules/TestTarget.cmake b/cmake/modules/TestTarget.cmake new file mode 100644 index 0000000..e314a30 --- /dev/null +++ b/cmake/modules/TestTarget.cmake @@ -0,0 +1,17 @@ +# before including this module, BasicConfig must be included + +# add autotools-style check target +if(NOT TARGET check) + set(CMAKE_CTEST_COMMAND ctest -V) + add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}) + enable_testing() +endif() + +# add test executable, but exclude it from the "all target" +add_executable(${META_PROJECT_NAME}_tests EXCLUDE_FROM_ALL ${TEST_HEADER_FILES} ${TEST_SRC_FILES}) +target_link_libraries(${META_PROJECT_NAME}_tests ${META_PROJECT_NAME} ${TEST_LIBRARIES} cppunit) +set_target_properties(${META_PROJECT_NAME}_tests PROPERTIES CXX_STANDARD 11) +add_test(NAME ${META_PROJECT_NAME}_cppunit COMMAND ${META_PROJECT_NAME}_tests -p "${CMAKE_CURRENT_SOURCE_DIR}/testfiles") + +# add the test executable to the dependencies of the check target +add_dependencies(check ${META_PROJECT_NAME}_tests) diff --git a/cmake/modules/WindowsResources.cmake b/cmake/modules/WindowsResources.cmake new file mode 100644 index 0000000..009c6a0 --- /dev/null +++ b/cmake/modules/WindowsResources.cmake @@ -0,0 +1,48 @@ +# generates and adds a Windows rc file for the application/library +# also attaches the application icon if ffmpeg is available +# does nothing if not building with mingw-w64 + +# before including this module, LibraryConfig/ApplicationConfig must be included + +if(MINGW) + # find rc template + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/windows.rc.in") + # check own source directory + set(RC_TEMPLATE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/windows.rc.in") + elseif(EXISTS "${CPP_UTILITIES_SOURCE_DIR}/cmake/templates/windows.rc.in") + # check sources of c++utilities + set(RC_TEMPLATE_FILE "${CPP_UTILITIES_SOURCE_DIR}/cmake/templates/windows.rc.in") + elseif(EXISTS "${CMAKE_INSTALL_PREFIX}/share/c++utilities/cmake-templates/windows.rc.in") + # check installed version of c++utilities + set(RC_TEMPLATE_FILE "${CMAKE_INSTALL_PREFIX}/share/c++utilities/cmake-templates/windows.rc.in") + else() + message(FATAL_ERROR "Template for Windows *.rc file can not be located.") + endif() + + # create Windows icon from png with ffmpeg if available + set(WINDOWS_ICON_PATH "") + set(WINDOWS_ICON_RC_ENTRY "") + find_program(FFMPEG_BIN ffmpeg avconv) + if(FFMPEG_BIN) + set(PNG_ICON_PATH "${CMAKE_CURRENT_SOURCE_DIR}/resources/icons/hicolor/128x128/apps/${META_PROJECT_NAME}.png") + if(EXISTS "${PNG_ICON_PATH}") + set(WINDOWS_ICON_PATH "${CMAKE_CURRENT_BINARY_DIR}/${META_PROJECT_NAME}.ico") + set(WINDOWS_ICON_RC_ENTRY "IDI_ICON1 ICON DISCARDABLE \"${WINDOWS_ICON_PATH}\"") + add_custom_command( + OUTPUT "${WINDOWS_ICON_PATH}" + COMMAND ${FFMPEG_BIN} -y -i "${PNG_ICON_PATH}" -vf crop=iw-20:ih-20:10:10,scale=64:64 "${WINDOWS_ICON_PATH}" + ) + endif() + endif(FFMPEG_BIN) + + # create Windows rc file from template + configure_file( + "${RC_TEMPLATE_FILE}" + "${CMAKE_CURRENT_BINARY_DIR}/resources/windows.rc" + ) + # set windres as resource compiler + set(RES_FILES "${CMAKE_CURRENT_BINARY_DIR}/resources/windows.rc") + set(CMAKE_RC_COMPILER_INIT windres) + set(CMAKE_RC_COMPILE_OBJECT " -O coff -i -o ") + enable_language(RC) +endif(MINGW) diff --git a/cmake/templates/Config.cmake.in b/cmake/templates/Config.cmake.in new file mode 100644 index 0000000..c03d2f1 --- /dev/null +++ b/cmake/templates/Config.cmake.in @@ -0,0 +1,14 @@ +@PACKAGE_INIT@ + +set(@META_PROJECT_VARNAME@_LIBS "@META_PROJECT_NAME@") +set(@META_PROJECT_VARNAME@_INCLUDE_DIRS "@PACKAGE_HEADER_INSTALL_DESTINATION@") +set(@META_PROJECT_VARNAME@_LIB_DIR "@PACKAGE_LIB_INSTALL_DESTINATION@") +set(@META_PROJECT_VARNAME@_MODULE_DIRS "@PACKAGE_CMAKE_MODULE_INSTALL_DESTINATION@") +set(@META_PROJECT_VARNAME@_CONFIG_DIRS "@PACKAGE_CMAKE_CONFIG_INSTALL_DESTINATION@") + +macro(use_@META_PROJECT_VARNAME@) + include_directories(BEFORE SYSTEM ${@META_PROJECT_VARNAME@_INCLUDE_DIRS}) + link_directories(${@META_PROJECT_VARNAME@_LIB_DIR}) + list(APPEND LIBRARIES ${@META_PROJECT_VARNAME@_LIBS}) + list(APPEND CMAKE_MODULE_PATH ${@META_PROJECT_VARNAME@_MODULE_DIRS}) +endmacro() diff --git a/cmake/templates/config.h.in b/cmake/templates/config.h.in new file mode 100644 index 0000000..82ef75d --- /dev/null +++ b/cmake/templates/config.h.in @@ -0,0 +1,9 @@ +#ifndef APP_METADATA_AVAIL +# define APP_METADATA_AVAIL +# define PROJECT_NAME @META_PROJECT_NAME_STR@ +# define APP_NAME @META_APP_NAME_STR@ +# define APP_VERSION @META_APP_VERSION_STR@ +# define APP_AUTHOR @META_APP_AUTHOR_STR@ +# define APP_URL @META_APP_URL_STR@ +# define APP_DESCRIPTION @META_APP_DESCRIPTION_STR@ +#endif // APP_METADATA_AVAIL diff --git a/cmake/templates/desktop.in b/cmake/templates/desktop.in new file mode 100644 index 0000000..9b2e453 --- /dev/null +++ b/cmake/templates/desktop.in @@ -0,0 +1,8 @@ +[Desktop Entry] +Name=@DESKTOP_FILE_APP_NAME@ +Comment=@DESKTOP_FILE_DESCRIPTION@ +Exec=@DESKTOP_FILE_CMD@ +Icon=@DESKTOP_FILE_ICON@ +Terminal=false +Type=Application +Categories=@DESKTOP_FILE_CATEGORIES@ diff --git a/resources/windows.rc.in b/cmake/templates/windows.rc.in similarity index 100% rename from resources/windows.rc.in rename to cmake/templates/windows.rc.in diff --git a/general.pri b/general.pri deleted file mode 100644 index f417d7d..0000000 --- a/general.pri +++ /dev/null @@ -1,103 +0,0 @@ -# specify build directories for moc, object and rcc files -MOC_DIR = ./moc -OBJECTS_DIR = ./obj -RCC_DIR = ./res - -# compiler flags: enable C++11 -QMAKE_CXXFLAGS += -std=c++11 -QMAKE_LFLAGS += -std=c++11 - -# disable new ABI (can't catch ios_base::failure with new ABI) -DEFINES += _GLIBCXX_USE_CXX11_ABI=0 - -# variables to check target architecture -win32-g++:QMAKE_TARGET.arch = $$QMAKE_HOST.arch -win32-g++-32:QMAKE_TARGET.arch = x86 -win32-g++-64:QMAKE_TARGET.arch = x86_64 -linux-g++:QMAKE_TARGET.arch = $$QMAKE_HOST.arch -linux-g++-32:QMAKE_TARGET.arch = x86 -linux-g++-64:QMAKE_TARGET.arch = x86_64 - -# determine and print target prefix -targetprefix = $$(TARGET_PREFIX) -message("Using target prefix \"$${targetprefix}\".") - -# print install root -message("Using install root \"$$(INSTALL_ROOT)\".") - -# set target -CONFIG(debug, debug|release) { - TARGET = $${targetprefix}$${projectname}d -} else { - TARGET = $${targetprefix}$${projectname} -} - -# add defines for meta data -DEFINES += "APP_METADATA_AVAIL" -DEFINES += "'PROJECT_NAME=\"$${projectname}\"'" -DEFINES += "'APP_NAME=\"$${appname}\"'" -DEFINES += "'APP_AUTHOR=\"$${appauthor}\"'" -DEFINES += "'APP_URL=\"$${appurl}\"'" -DEFINES += "'APP_VERSION=\"$${VERSION}\"'" - -# configure Qt modules and defines -mobile { - DEFINES += CONFIG_MOBILE -} else:desktop { - DEFINES += CONFIG_DESKTOP -} else:android { - CONFIG += mobile - DEFINES += CONFIG_MOBILE -} else { - CONFIG += desktop - DEFINES += CONFIG_DESKTOP -} -no-gui { - QT -= gui - DEFINES += GUI_NONE - guiqtquick || guiqtwidgets { - error("Can not use no-gui with guiqtquick or guiqtwidgets.") - } else { - message("Configured for no GUI support.") - } -} else { - QT += gui - mobile { - CONFIG += guiqtquick - } - desktop { - CONFIG += guiqtwidgets - } -} -guiqtquick { - message("Configured for Qt Quick GUI support.") - QT += quick - CONFIG(debug, debug|release) { - CONFIG += qml_debug - } - DEFINES += GUI_QTQUICK -} -guiqtwidgets { - message("Configured for Qt widgets GUI support.") - QT += widgets - DEFINES += GUI_QTWIDGETS - DEFINES += MODEL_UNDO_SUPPORT -} - -# configuration for cross compliation with mingw-w64 -win32 { - QMAKE_TARGET_PRODUCT = "$${appname}" - QMAKE_TARGET_COPYRIGHT = "by $${appauthor}" -} -mingw-w64-manualstrip-dll { - QMAKE_POST_LINK=$${CROSS_COMPILE}strip --strip-unneeded ./release/$(TARGET); \ - $${CROSS_COMPILE}strip --strip-unneeded ./release/lib$(TARGET).a -} -mingw-w64-manualstrip-exe { - QMAKE_POST_LINK=$${CROSS_COMPILE}strip --strip-unneeded ./release/$(TARGET) -} -mingw-w64-noversion { - TARGET_EXT = ".dll" - TARGET_VERSION_EXT = "" - CONFIG += skip_target_version_ext -} diff --git a/io/path.h b/io/path.h index 3f68c1c..e4248a1 100644 --- a/io/path.h +++ b/io/path.h @@ -8,6 +8,18 @@ #include +#ifdef PLATFORM_WINDOWS +# define PATH_SEP_CHAR '\\' +# define SEARCH_PATH_SEP_CHAR ';' +# define PATH_SEP_STR "\\" +# define SEARCH_PATH_SEP_STR ";" +#else +# define PATH_SEP_CHAR '/' +# define SEARCH_PATH_SEP_CHAR ':' +# define PATH_SEP_STR "/" +# define SEARCH_PATH_SEP_STR ":" +#endif + namespace IoUtilities { LIB_EXPORT std::string fileName(const std::string &path); diff --git a/resources/config.h.in b/resources/config.h.in deleted file mode 100644 index 2f9ca46..0000000 --- a/resources/config.h.in +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef APP_METADATA_AVAIL -#define APP_METADATA_AVAIL -#define PROJECT_NAME @META_PROJECT_NAME_STR@ -#define APP_NAME @META_APP_NAME_STR@ -#define APP_VERSION @META_APP_VERSION_STR@ -#define APP_AUTHOR @META_APP_AUTHOR_STR@ -#define APP_URL @META_APP_URL_STR@ -#define APP_DESCRIPTION @META_APP_DESCRIPTION_STR@ -#endif // APP_METADATA_AVAIL diff --git a/tests/testutils.cpp b/tests/testutils.cpp index cd49dc1..56093a0 100644 --- a/tests/testutils.cpp +++ b/tests/testutils.cpp @@ -166,16 +166,15 @@ string TestApplication::workingCopyPath(const string &name) const if(!parts.empty()) { string currentLevel = m_workingDir; for(auto i = parts.cbegin(), end = parts.end() - 1; i != end; ++i) { - if(stat((currentLevel += *i).c_str(), ¤tStat) || !S_ISDIR(currentStat.st_mode)) { - + if(currentLevel.back() != '/') { + currentLevel += '/'; + } + currentLevel += *i; + if(stat(currentLevel.c_str(), ¤tStat) || !S_ISDIR(currentStat.st_mode)) { if(mkdir(currentLevel.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) { cerr << "Unable to create working copy for \"" << name << "\": can't create working directory." << endl; return string(); } - if(currentLevel.back() != '/') { - currentLevel += '/'; - } - currentLevel += *i; } } }