diff --git a/.gitignore b/.gitignore index d1e6e2a..817c82c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,200 @@ -CMakeLists.txt.user* +# Каталог для результатов сборки проекта _build + +# Каталог для тестирования установки _output -.cmake/ -*.autosave + +# Файлы настроек, редактируемые во время отладки, +# за исключением шаблонных файлов +files/etc/*.conf +!files/etc/*.example.conf + +# Каталоги, в которые разрешена запись данных во время работы программы files/lib/* files/log/* + +### +### Общие настройки для C, C++, Fortran, Qt, CMake, Ninja, LaTeX и редакторов +### + +### +### Временные файлы текстовых редакторов +### +*.bak +*.gho +*.tmp +*.dotdropbak + +### +### LyX +### +*.lyx~ +*.lyx# + +### +### Vim +### +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + + +### +### C++ +### + +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.so.* +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + + +### +### CMake +### +CMakeLists.txt.user* +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps + + +### +### Ninja +### +.ninja_deps +.ninja_log + + +### +### GCC coverage testing tool files +### +*.gcno +*.gcda +*.gcov + + +### +### Qt +### +object_script.*.Release +object_script.*.Debug +*_plugin_import.cpp +/.qmake.cache +/.qmake.stash +*.pro.user +*.pro.user.* +*.qbs.user +*.qbs.user.* +*.moc +moc_*.cpp +moc_*.h +qrc_*.cpp +ui_*.h +*.qmlc +*.jsc +Makefile* +*build-* +*.qm +*.prl + +# Qt unit tests +target_wrapper.* + +# QtCreator +*.autosave + +# QtCreator Qml +*.qmlproject.user +*.qmlproject.user.* + +# QtCreator local machine specific files for imported projects +*creator.user* + +*_qmlcache.qrc + + +### +### Latex +### +*.acn +*.acr +*.alg +*.aux +*.bbl +*.blg +*.dvi +*.fdb_latexmk +*.glg +*.glo +*.gls +*.idx +*.ilg +*.ind +*.ist +*.lof +*.log +*.lot +*.maf +*.mtc +*.mtc0 +*.nav +*.nlo +*.out +*.pdfsync +*.ps +*.snm +*.synctex.gz +*.toc +*.vrb +*.xdy +*.tdo + diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 04b4bc6..ddbd00e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,7 @@ include: - - local: .gitlab-ci/scheduled.yml + - project: 'f1x1t/gitlab-ci' + ref: master + file: 'scheduled.yml' smolensk15-nightly: extends: .scheduled-smolensk15 diff --git a/.gitlab-ci/scheduled.yml b/.gitlab-ci/scheduled.yml deleted file mode 100644 index 02d6f70..0000000 --- a/.gitlab-ci/scheduled.yml +++ /dev/null @@ -1,79 +0,0 @@ -variables: - GIT_SUBMODULE_STRATEGY: recursive - GET_SOURCES_ATTEMPTS: 10 - -.scheduled-test: - only: - refs: - - schedules - cache: - paths: ['*.status'] - before_script: - - > - if [ -f "${CI_JOB_NAME}.status" ]; then - if [ "$(cat ${CI_JOB_NAME}.status)" == "${CI_COMMIT_SHA}" ]; then - echo "=== Commit ${CI_COMMIT_SHORT_SHA} already tested with job ${CI_JOB_NAME} ===" - exit 0 - fi - fi - - > - if [ -n "${APT_UPDATE_CMD}" ]; then - ${APT_UPDATE_CMD} - fi - - > - if [ -n "${APT_INSTALL_CMD}" ]; then - ${APT_INSTALL_CMD} - fi - script: - - > - if [ -f "${CI_JOB_NAME}.status" ]; then - if [ "$(cat ${CI_JOB_NAME}.status)" == "${CI_COMMIT_SHA}" ]; then - echo "=== Commit ${CI_COMMIT_SHORT_SHA} already tested with job ${CI_JOB_NAME} ===" - exit 0 - fi - fi - - rm -f ${CI_JOB_NAME}.status - - mkdir build - - cd build - - cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=_output -DCPACK_PACKAGING_INSTALL_PREFIX=/opt/rtis -DMYXLIB_BUILD_EXAMPLES_HO=ON -DMYXLIB_BUILD_LIBRARIES=ON -DMYXLIB_BUILD_EXAMPLES=ON .. - - ninja - - > - if [ -z "${CI_SHARED_ENVIRONMENT+x}" ]; then - ninja install - ninja package - ninja package_source - ninja deb - fi - - echo "${CI_COMMIT_SHA}" > "../${CI_JOB_NAME}.status" - artifacts: - paths: - - build/*.xz - - build/*.deb - when: on_success - expire_in: 10 days - - -.scheduled-smolensk15: - extends: .scheduled-test - image: smolensk15-dev - tags: ['docker'] - -.scheduled-orel212: - extends: .scheduled-test - image: orel212-dev - tags: ['docker'] - -.scheduled-bionic: - extends: .scheduled-test - image: bionic-dev - tags: ['docker'] - -.scheduled-focal: - extends: .scheduled-test - image: focal-dev - tags: ['docker'] - -.scheduled-elbrus: - extends: .scheduled-test - tags: ['elbrus'] - diff --git a/CMakeLists.txt b/CMakeLists.txt index ec249c9..561029e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,11 +23,7 @@ endif() include(CMLibCommon) -option(MYXLIB_BUILD_LIBRARIES "Build libraries" OFF) -if(MYXLIB_BUILD_LIBRARIES) - option(MYXLIB_BUILD_EXAMPLES "Build examples" OFF) -endif() -option(MYXLIB_BUILD_EXAMPLES_HO "Build examples using header only version" OFF) +option(MYXLIB_BUILD_EXAMPLES "Build examples" OFF) # Поиск библиотек с помощью pkgconfig find_package(PkgConfig REQUIRED) @@ -40,14 +36,20 @@ find_package(Threads REQUIRED) find_package(Qt5 COMPONENTS Core Network REQUIRED) # Библиотеки -add_subdirectory(src/myx/base) +add_subdirectory(src/myx/backports/compiler) +add_subdirectory(src/myx/backports/cpp) +add_subdirectory(src/myx/backports/qt) +add_subdirectory(src/myx/core) add_subdirectory(src/myx/filesystem) add_subdirectory(src/myx/qt) # Примеры -if(MYXLIB_BUILD_EXAMPLES OR MYXLIB_BUILD_EXAMPLES_HO) +if(MYXLIB_BUILD_EXAMPLES) + add_subdirectory(examples/core) add_subdirectory(examples/filesystem) add_subdirectory(examples/qt) + add_custom_target(examples example-core-endian example-filesystem-paths example-qt-tranlators + example-qt-posix-signal-watcher) endif() # Документация diff --git a/cmake/etc/Variables.cmake b/cmake/etc/Variables.cmake index 5445292..0338080 100644 --- a/cmake/etc/Variables.cmake +++ b/cmake/etc/Variables.cmake @@ -9,4 +9,4 @@ set(CPACK_COMPONENTS_ALL examples) set(CPACK_PACKAGE_CONTACT "Andrei Astafev ") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Mixed functions") -set(CMLIB_GENERATED_HEADERS_PATH ${CMAKE_BINARY_DIR}/include/myx/base) +set(CMLIB_GENERATED_HEADERS_PATH ${CMAKE_BINARY_DIR}/include/myx/core) diff --git a/examples/core/01_endian/CMakeLists.txt b/examples/core/01_endian/CMakeLists.txt new file mode 100644 index 0000000..ada80fa --- /dev/null +++ b/examples/core/01_endian/CMakeLists.txt @@ -0,0 +1,51 @@ +# Название основной цели в текущем каталоге +set(TRGT example-core-endian) + +# Список файлов исходных текстов +set(TRGT_cpp ${CMAKE_CURRENT_SOURCE_DIR}/endian.cpp) + +if(MYXLIB_BUILD_EXAMPLES) + # Путь поиска библиотек внутри проекта + link_directories(${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) + + # Цель для создания исполняемого файла + add_executable(${TRGT} ${TRGT_cpp} ${TRGT_qrc}) + common_target_properties(${TRGT}) + + # Создание цели для проверки утилитой clang-tidy + add_clang_tidy_check(${TRGT} ${TRGT_cpp}) + + # Создание цели для проверки утилитой clang-analyze + add_clang_analyze_check(${TRGT} ${TRGT_cpp}) + + # Создание цели для проверки утилитой clazy + add_clazy_check(${TRGT} ${TRGT_cpp}) + + # Создание цели для проверки утилитой pvs-studio + add_pvs_check(${TRGT}) + + # Создание цели для автоматического форматирования кода + add_format_sources(${TRGT} ${TRGT_cpp}) + + # Qt5 + target_include_directories(${TRGT} PRIVATE ${CMAKE_SOURCE_DIR}/src) + target_include_directories(${TRGT} SYSTEM PUBLIC ${Qt5Core_INCLUDE_DIRS}) + + target_include_directories(${TRGT} SYSTEM PRIVATE ${CMAKE_SOURCE_DIR}/src) + add_dependencies(${TRGT} core) + + target_link_libraries(${TRGT} Qt5::Core) + target_link_libraries(${TRGT} Threads::Threads) + + # Имя выходного файла для цели + set_target_properties(${TRGT} PROPERTIES OUTPUT_NAME endian-minimal) + + add_sanitizers(${TRGT}) + + cotire(${TRGT}) + + add_dependencies(${TRGT} create_auxilary_symlinks) + + # Правила для установки + # install(TARGETS ${TRGT} COMPONENT examples RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +endif() diff --git a/examples/core/01_endian/endian.cpp b/examples/core/01_endian/endian.cpp new file mode 100644 index 0000000..f147381 --- /dev/null +++ b/examples/core/01_endian/endian.cpp @@ -0,0 +1,24 @@ +#include +#include + +#include + +//NOLINTNEXTLINE +#define CMLIB_PROJECT_NAME "myxlib" + + +int main( int argc, char** argv ) +{ + (void)argc; + (void)argv; + + beint64 bi = 1; + int64_t bii = reinterpret_cast< int64_t* >( &bi )[0]; //NOLINT + qDebug() << hex << bi << bii; + + leint64 li = 1; + int64_t lii = reinterpret_cast< int64_t* >( &li )[0]; //NOLINT + qDebug() << hex << li << lii; + + return( 0 ); +} // main diff --git a/examples/core/CMakeLists.txt b/examples/core/CMakeLists.txt new file mode 100644 index 0000000..01da3ee --- /dev/null +++ b/examples/core/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(01_endian) diff --git a/examples/filesystem/01_minimal/minimal.cpp b/examples/filesystem/01_minimal/minimal.cpp deleted file mode 100644 index 5616bcc..0000000 --- a/examples/filesystem/01_minimal/minimal.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include - -#include -#include - -#include -#include - -#define CMLIB_PROJECT_NAME "myxlib" - -namespace MF = myx::filesystem; - -// Переменные для защиты экземпляра класса MF::PathsMT -std::atomic< MF::PathsMT* > MF::PathsMT::mInstance; -std::mutex MF::PathsMT::mMutex; - - -int main( int argc, char** argv ) -{ - (void)argc; - (void)argv; - QCoreApplication::setApplicationName( QStringLiteral( CMLIB_PROJECT_NAME ) ); - MF::PathsMT& pathsMT = MF::PathsMT::instance(); - MF::Paths& paths = MF::Paths::instance(); - - pathsMT.init( QStringLiteral( CMLIB_PROJECT_NAME ), QStringLiteral( "conf" ) ); - pathsMT.findConfigFile( QStringLiteral( "test" ) ); - qDebug() << pathsMT.systemLogDirectory().path(); - qDebug() << pathsMT.systemConfigDirectory().path(); - - paths.init( QStringLiteral( CMLIB_PROJECT_NAME ), QStringLiteral( "conf" ) ); - paths.findConfigFile( QStringLiteral( "test" ) ); - qDebug() << paths.systemConstDataDirectory().path(); - qDebug() << paths.configFileName(); - - return( 0 ); -} diff --git a/examples/filesystem/01_minimal/CMakeLists.txt b/examples/filesystem/01_paths/CMakeLists.txt similarity index 58% rename from examples/filesystem/01_minimal/CMakeLists.txt rename to examples/filesystem/01_paths/CMakeLists.txt index f4d533a..aa16e57 100644 --- a/examples/filesystem/01_minimal/CMakeLists.txt +++ b/examples/filesystem/01_paths/CMakeLists.txt @@ -1,8 +1,8 @@ # Название основной цели в текущем каталоге -set(TRGT example-filesystem-minimal) +set(TRGT example-filesystem-paths) # Список файлов исходных текстов -set(TRGT_cpp ${CMAKE_CURRENT_SOURCE_DIR}/minimal.cpp) +set(TRGT_cpp ${CMAKE_CURRENT_SOURCE_DIR}/paths.cpp) if(MYXLIB_BUILD_EXAMPLES) # Путь поиска библиотек внутри проекта @@ -32,9 +32,9 @@ if(MYXLIB_BUILD_EXAMPLES) target_include_directories(${TRGT} SYSTEM PUBLIC ${Qt5Core_INCLUDE_DIRS}) target_include_directories(${TRGT} SYSTEM PRIVATE ${CMAKE_SOURCE_DIR}/src) - add_dependencies(${TRGT} base filesystem) + add_dependencies(${TRGT} core filesystem) - target_link_libraries(${TRGT} base_static filesystem_static) + target_link_libraries(${TRGT} filesystem_static) target_link_libraries(${TRGT} Qt5::Core) target_link_libraries(${TRGT} Threads::Threads) @@ -48,30 +48,5 @@ if(MYXLIB_BUILD_EXAMPLES) add_dependencies(${TRGT} create_auxilary_symlinks) # Правила для установки - install(TARGETS ${TRGT} COMPONENT examples RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -endif() - -if(MYXLIB_BUILD_EXAMPLES_HO) - # Цель для создания исполняемого файла - add_executable(${TRGT}-ho ${TRGT_cpp} ${TRGT_qrc}) - common_target_properties(${TRGT}-ho) - - target_include_directories(${TRGT}-ho PRIVATE ${CMAKE_SOURCE_DIR}/src) - target_include_directories(${TRGT}-ho SYSTEM PUBLIC ${Qt5Core_INCLUDE_DIRS}) - - add_dependencies(${TRGT}-ho base-header-only filesystem-header-only) - - target_link_libraries(${TRGT}-ho Qt5::Core) - target_link_libraries(${TRGT}-ho Threads::Threads) - - # Имя выходного файла для цели - set_target_properties(${TRGT}-ho PROPERTIES OUTPUT_NAME filesystem-minimal-ho) - - add_sanitizers(${TRGT}-ho) - cotire(${TRGT}-ho) - - add_dependencies(${TRGT}-ho create_auxilary_symlinks) - - # Правила для установки - install(TARGETS ${TRGT}-ho COMPONENT examples RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + # install(TARGETS ${TRGT} COMPONENT examples RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() diff --git a/examples/filesystem/01_paths/paths.cpp b/examples/filesystem/01_paths/paths.cpp new file mode 100644 index 0000000..c41888f --- /dev/null +++ b/examples/filesystem/01_paths/paths.cpp @@ -0,0 +1,43 @@ +#include + +#include + +#include +#include + +//NOLINTNEXTLINE +#define CMLIB_PROJECT_NAME "myxlib" + +namespace MF = myx::filesystem; + + +int main( int argc, char** argv ) +{ + (void)argc; + (void)argv; + QCoreApplication::setApplicationName( QStringLiteral( CMLIB_PROJECT_NAME ) ); + MF::Paths& paths = MF::Paths::instance(); + + paths.init( QStringLiteral( CMLIB_PROJECT_NAME ), QStringLiteral( "conf" ) ); + + qDebug() << "prefixDirectory : " << paths.prefixDirectory(); + + qDebug() << "executableName : " << paths.executableName(); + qDebug() << "executableFilePath : " << paths.executableFilePath(); + qDebug() << "executableDirectory : " << paths.executableDirectory(); + + qDebug() << "configFileName : " << paths.configFileName(); + qDebug() << "configFilePath : " << paths.configFilePath(); + + qDebug() << "systemConfigDirectory : " << paths.systemConfigDirectory(); + qDebug() << "systemConstDataDirectory : " << paths.systemConstDataDirectory(); + qDebug() << "systemVarDataDirectory : " << paths.systemVarDataDirectory(); + qDebug() << "systemLogDirectory : " << paths.systemLogDirectory(); + + qDebug() << "userConfigDirectory : " << paths.userConfigDirectory(); + qDebug() << "userConstDataDirectory : " << paths.userConstDataDirectory(); + qDebug() << "userVarDataDirectory : " << paths.userVarDataDirectory(); + qDebug() << "userLogDirectory : " << paths.userLogDirectory(); + + return( 0 ); +} // main diff --git a/examples/filesystem/CMakeLists.txt b/examples/filesystem/CMakeLists.txt index 5e9d165..1254222 100644 --- a/examples/filesystem/CMakeLists.txt +++ b/examples/filesystem/CMakeLists.txt @@ -1 +1 @@ -add_subdirectory(01_minimal) +add_subdirectory(01_paths) diff --git a/examples/qt/01_translators/CMakeLists.txt b/examples/qt/01_translators/CMakeLists.txt index 59af417..c8be1ac 100644 --- a/examples/qt/01_translators/CMakeLists.txt +++ b/examples/qt/01_translators/CMakeLists.txt @@ -11,7 +11,6 @@ qt5_translation( LANGUAGES ru_RU) if(MYXLIB_BUILD_EXAMPLES) - # Путь поиска библиотек внутри проекта link_directories(${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) @@ -39,9 +38,9 @@ if(MYXLIB_BUILD_EXAMPLES) target_include_directories(${TRGT} SYSTEM PUBLIC ${Qt5Core_INCLUDE_DIRS}) target_include_directories(${TRGT} SYSTEM PRIVATE ${CMAKE_SOURCE_DIR}/src) - add_dependencies(${TRGT} base qt) + add_dependencies(${TRGT} core qt) - target_link_libraries(${TRGT} base_static qt_static) + target_link_libraries(${TRGT} qt_static) target_link_libraries(${TRGT} Qt5::Core) target_link_libraries(${TRGT} Threads::Threads) @@ -56,30 +55,5 @@ if(MYXLIB_BUILD_EXAMPLES) add_dependencies(${TRGT} create_auxilary_symlinks) # Правила для установки - install(TARGETS ${TRGT} COMPONENT examples RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -endif() - -if(MYXLIB_BUILD_EXAMPLES_HO) - # Цель для создания исполняемого файла - add_executable(${TRGT}-ho ${TRGT_cpp} ${TRGT_qrc}) - common_target_properties(${TRGT}-ho) - - target_include_directories(${TRGT}-ho PRIVATE ${CMAKE_SOURCE_DIR}/src) - target_include_directories(${TRGT}-ho SYSTEM PUBLIC ${Qt5Core_INCLUDE_DIRS}) - - add_dependencies(${TRGT}-ho base-header-only qt-header-only) - - target_link_libraries(${TRGT}-ho Qt5::Core) - target_link_libraries(${TRGT}-ho Threads::Threads) - - # Имя выходного файла для цели - set_target_properties(${TRGT}-ho PROPERTIES OUTPUT_NAME qt-translators-ho) - - add_sanitizers(${TRGT}-ho) - cotire(${TRGT}-ho) - - add_dependencies(${TRGT}-ho create_auxilary_symlinks) - - # Правила для установки - install(TARGETS ${TRGT}-ho COMPONENT examples RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + # install(TARGETS ${TRGT} COMPONENT examples RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() diff --git a/examples/qt/02_posix-signal-watcher/CMakeLists.txt b/examples/qt/02_posix-signal-watcher/CMakeLists.txt new file mode 100644 index 0000000..ed49dbb --- /dev/null +++ b/examples/qt/02_posix-signal-watcher/CMakeLists.txt @@ -0,0 +1,53 @@ +# Название основной цели в текущем каталоге +set(TRGT example-qt-posix-signal-watcher) + +# Список файлов исходных текстов +set(TRGT_cpp ${CMAKE_CURRENT_SOURCE_DIR}/posix_signal_watcher.cpp) + +if(MYXLIB_BUILD_EXAMPLES) + # Путь поиска библиотек внутри проекта + link_directories(${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) + + # Цель для создания исполняемого файла + add_executable(${TRGT} ${TRGT_cpp}) + common_target_properties(${TRGT}) + + # Создание цели для проверки утилитой clang-tidy + add_clang_tidy_check(${TRGT} ${TRGT_cpp}) + + # Создание цели для проверки утилитой clang-analyze + add_clang_analyze_check(${TRGT} ${TRGT_cpp}) + + # Создание цели для проверки утилитой clazy + add_clazy_check(${TRGT} ${TRGT_cpp}) + + # Создание цели для проверки утилитой pvs-studio + add_pvs_check(${TRGT}) + + # Создание цели для автоматического форматирования кода + add_format_sources(${TRGT} ${TRGT_cpp}) + + # Qt5 + target_include_directories(${TRGT} PRIVATE ${CMAKE_SOURCE_DIR}/src) + target_include_directories(${TRGT} SYSTEM PUBLIC ${Qt5Core_INCLUDE_DIRS}) + + target_include_directories(${TRGT} SYSTEM PRIVATE ${CMAKE_SOURCE_DIR}/src) + add_dependencies(${TRGT} core qt) + + target_link_libraries(${TRGT} qt_static) + + target_link_libraries(${TRGT} Qt5::Core) + target_link_libraries(${TRGT} Threads::Threads) + + # Имя выходного файла для цели + set_target_properties(${TRGT} PROPERTIES OUTPUT_NAME qt-posix-signal-watcher) + + add_sanitizers(${TRGT}) + + cotire(${TRGT}) + + add_dependencies(${TRGT} create_auxilary_symlinks) + + # Правила для установки + # install(TARGETS ${TRGT} COMPONENT examples RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +endif() diff --git a/examples/qt/02_posix-signal-watcher/posix_signal_watcher.cpp b/examples/qt/02_posix-signal-watcher/posix_signal_watcher.cpp new file mode 100644 index 0000000..ccc1ca4 --- /dev/null +++ b/examples/qt/02_posix-signal-watcher/posix_signal_watcher.cpp @@ -0,0 +1,21 @@ +#include + +#include +#include + +namespace MQ = myx::qt; + +int main( int argc, char* argv[] ) +{ + QCoreApplication app( argc, argv ); + qDebug() << "Hello from process" << QCoreApplication::applicationPid(); + + MQ::PosixSignalWatcher sigwatch; + sigwatch.watchForSignal( SIGINT ); + sigwatch.watchForSignal( SIGTERM ); + QObject::connect( &sigwatch, &MQ::PosixSignalWatcher::posixSignal, &app, &QCoreApplication::quit ); + + int exitcode = QCoreApplication::exec(); + qDebug() << "Goodbye"; + return( exitcode ); +} diff --git a/examples/qt/CMakeLists.txt b/examples/qt/CMakeLists.txt index ff85cdb..b222784 100644 --- a/examples/qt/CMakeLists.txt +++ b/examples/qt/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(01_translators) +add_subdirectory(02_posix-signal-watcher) diff --git a/l10n/example-qt-translators_ru_RU.ts b/l10n/example-qt-translators_ru_RU.ts index a8264a7..f62cf2e 100644 --- a/l10n/example-qt-translators_ru_RU.ts +++ b/l10n/example-qt-translators_ru_RU.ts @@ -1,17 +1,4 @@ - - QObject - - - Yes - Да - - - - Cancel - Отмена - - diff --git a/src/myx/backports/compiler/CMakeLists.txt b/src/myx/backports/compiler/CMakeLists.txt new file mode 100644 index 0000000..d8d482d --- /dev/null +++ b/src/myx/backports/compiler/CMakeLists.txt @@ -0,0 +1,42 @@ +# Название основной цели и имя библиотеки в текущем каталоге +set(TRGT backports-compiler) + +# cmake-format: off +# Список файлов исходных текстов +set(TRGT_cpp) + +# Список заголовочных файлов +set(TRGT_hpp + ${CMAKE_CURRENT_SOURCE_DIR}/gcc.hpp + ) + +set(TRGT_headers ${TRGT_hpp}) +# cmake-format: on + +add_library(${TRGT} INTERFACE) +target_sources(${TRGT} INTERFACE ${TRGT_cpp} ${TRGT_headers}) + +# Создание цели для проверки утилитой clang-tidy +add_clang_tidy_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) + +# Создание цели для проверки утилитой clang-analyze +add_clang_analyze_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) + +# Создание цели для проверки утилитой clazy +add_clazy_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) + +# Создание цели для проверки утилитой pvs-studio +add_pvs_check(${TRGT}) + +# Создание цели для автоматического форматирования кода +add_format_sources(${TRGT} ${TRGT_cpp} ${TRGT_headers}) + +target_include_directories(${TRGT} INTERFACE ${CMAKE_SOURCE_DIR}/src) + +generate_pkgconfig(myx-${TRGT} COMPONENT base-dev INSTALL_LIBRARY ${MYXLIB_BUILD_LIBRARIES}) +install(FILES ${TRGT_headers} COMPONENT base-dev + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/backports/compiler) + +# Цель, используемая только для установки заголовочных файлов без компиляции проекта +add_custom_target(${TRGT}-install-headers COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=base-dev -P + "${CMAKE_BINARY_DIR}/cmake_install.cmake") diff --git a/src/myx/backports/compiler/gcc.hpp b/src/myx/backports/compiler/gcc.hpp new file mode 100644 index 0000000..c3e505c --- /dev/null +++ b/src/myx/backports/compiler/gcc.hpp @@ -0,0 +1,29 @@ +#ifndef MYX_BACKPORTS_COMPILER_GCC_HPP_ +#define MYX_BACKPORTS_COMPILER_GCC_HPP_ + +#pragma once + +#ifdef __GNUC__ +// NOLINTNEXTLINE +#define GCC_VERSION ( __GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ ) +#if GCC_VERSION <= 40702 + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wkeyword-macro" +#endif + +#if ( __cplusplus < 201103L ) +#define constexpr +#endif + +#define override + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif // if GCC_VERSION <= 40702 +#endif // ifdef __GNUC__ + +#endif // ifndef MYX_BACKPORTS_COMPILER_GCC_HPP_ diff --git a/src/myx/backports/cpp/CMakeLists.txt b/src/myx/backports/cpp/CMakeLists.txt new file mode 100644 index 0000000..2c81cda --- /dev/null +++ b/src/myx/backports/cpp/CMakeLists.txt @@ -0,0 +1,43 @@ +# Название основной цели и имя библиотеки в текущем каталоге +set(TRGT backports-cpp) + +# cmake-format: off +# Список файлов исходных текстов +set(TRGT_cpp) + +# Список заголовочных файлов +set(TRGT_hpp + ${CMAKE_CURRENT_SOURCE_DIR}/helpers.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/span.hpp + ) + +set(TRGT_headers ${TRGT_hpp}) +# cmake-format: on + +add_library(${TRGT} INTERFACE) +target_sources(${TRGT} INTERFACE ${TRGT_cpp} ${TRGT_headers}) + +# Создание цели для проверки утилитой clang-tidy +add_clang_tidy_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) + +# Создание цели для проверки утилитой clang-analyze +add_clang_analyze_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) + +# Создание цели для проверки утилитой clazy +add_clazy_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) + +# Создание цели для проверки утилитой pvs-studio +add_pvs_check(${TRGT}) + +# Создание цели для автоматического форматирования кода +add_format_sources(${TRGT} ${TRGT_cpp} ${TRGT_headers}) + +target_include_directories(${TRGT} INTERFACE ${CMAKE_SOURCE_DIR}/src) + +generate_pkgconfig(myx-${TRGT} COMPONENT base-dev INSTALL_LIBRARY ${MYXLIB_BUILD_LIBRARIES}) +install(FILES ${TRGT_headers} COMPONENT base-dev + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/backports/cpp) + +# Цель, используемая только для установки заголовочных файлов без компиляции проекта +add_custom_target(${TRGT}-install-headers COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=base-dev -P + "${CMAKE_BINARY_DIR}/cmake_install.cmake") diff --git a/src/myx/backports/cpp/helpers.hpp b/src/myx/backports/cpp/helpers.hpp new file mode 100644 index 0000000..3f6b1c0 --- /dev/null +++ b/src/myx/backports/cpp/helpers.hpp @@ -0,0 +1,43 @@ +#ifndef MYX_BACKPORTS_CPP_HELPERS_HPP_ +#define MYX_BACKPORTS_CPP_HELPERS_HPP_ + +#pragma once + +#if ( __cplusplus >= 201103L ) +#include +#include +#endif + +#if ( __cplusplus >= 201103L ) && ( __cplusplus < 201402L ) + +namespace std +{ + +template< class T > +using underlying_type_t = typename std::underlying_type< T >::type; + +template< typename T, typename ... Args > +std::unique_ptr< T > make_unique( Args&&... args ) +{ + return( std::unique_ptr< T >( new T( std::forward< Args >( args )... ) ) ); +} + +} // namespace std + +#endif + +#if ( ( __cplusplus >= 201103L ) && ( __cplusplus < 201402L ) ) || \ + ( ( __cplusplus >= 201402L ) && ( __cplusplus < 201702L ) && defined( __STRICT_ANSI__ ) ) + + +namespace std +{ + +template< typename ... Ts > struct make_void { typedef void type; }; +template< typename ... Ts > using void_t = typename make_void< Ts... >::type; + +} // namespace std + +#endif + +#endif // ifndef MYX_BACKPORTS_CPP_HELPERS_HPP_ diff --git a/src/myx/backports/cpp/span.hpp b/src/myx/backports/cpp/span.hpp new file mode 100644 index 0000000..ac09b51 --- /dev/null +++ b/src/myx/backports/cpp/span.hpp @@ -0,0 +1,240 @@ +// +// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/beast +// + +#ifndef MYX_BACKPORTS_CPP_SPAN_HPP_ +#define MYX_BACKPORTS_CPP_SPAN_HPP_ + +#pragma once + +#if ( __cplusplus >= 201103L ) && ( __cplusplus < 201703L ) + +#include + +#include +#include +#include +#include + +namespace std { + +template< class T, class E, class = void > +struct is_contiguous_container : std::false_type {}; // NOLINT + +template< class T, class E > +struct is_contiguous_container< T, E, void_t< + decltype( + std::declval< std::size_t& >() = std::declval< T const& >().size(), + std::declval< E*& >() = std::declval< T& >().data() ), + typename std::enable_if< + std::is_same< + typename std::remove_cv< E >::type, + typename std::remove_cv< + typename std::remove_pointer< + decltype( std::declval< T& >().data() ) + >::type + >::type + >::value + >::type > > : std::true_type +{}; + + +/** A range of bytes expressed as a ContiguousContainer + + This class implements a non-owning reference to a storage + area of a certain size and having an underlying integral + type with size of 1. + + @tparam T The type pointed to by span iterators +*/ +template< class T > +class span // NOLINT +{ + T* m_data = nullptr; + std::size_t m_size = 0; + +public: + /// The type of value, including cv qualifiers + using ElementType = T; + + /// The type of value of each span element + using ValueType = typename std::remove_const< T >::type; + + /// The type of integer used to index the span + using IndexType = std::ptrdiff_t; + + /// A pointer to a span element + using Pointer = T*; + + /// A reference to a span element + using Reference = T&; + + /// The iterator used by the container + using Iterator = Pointer; + + /// The const pointer used by the container + using ConstPointer = T const*; + + /// The const reference used by the container + using ConstReference = T const&; + + /// The const iterator used by the container + using ConstIterator = ConstPointer; + + /// Constructor + span() = default; + + /// Constructor + span( span const& ) = default; + + /// Assignment + span& operator=( span const& ) = default; + + /** Constructor + * @param data A pointer to the beginning of the range of elements + * @param size The number of elements pointed to by `data` + */ + span( T* data, std::size_t size ) : + m_data( data ), + m_size( size ) + { + } + + + /** Constructor + * @param container The container to construct from + */ + template< class ContiguousContainer, + class = typename std::enable_if< + is_contiguous_container< + ContiguousContainer, T >::value >::type + > + explicit + span( ContiguousContainer&& container ) : + m_data( container.data() ), + m_size( container.size() ) + { + } + + + template< class CharT, class Traits, class Allocator > + explicit + span( std::basic_string< CharT, Traits, Allocator >& s ) : + m_data( &s[0] ), + m_size( s.size() ) + { + } + + + template< class CharT, class Traits, class Allocator > + explicit + span( std::basic_string< CharT, Traits, Allocator > const& s ) : + m_data( s.data() ), + m_size( s.size() ) + { + } + + + /** Assignment + * @param container The container to assign from + */ + template< class ContiguousContainer > + typename std::enable_if< is_contiguous_container< //NOLINT + ContiguousContainer, T >::value, + span& >::type + operator=( ContiguousContainer&& container ) + { + m_data = container.data(); + m_size = container.size(); + return( *this ); + } + + + template< class CharT, class Traits, class Allocator > + span& + operator=( std::basic_string< + CharT, Traits, Allocator >& s ) + { + m_data = &s[0]; + m_size = s.size(); + return( *this ); + } + + + template< class CharT, class Traits, class Allocator > + span& + operator=( std::basic_string< + CharT, Traits, Allocator > const& s ) + { + m_data = s.data(); + m_size = s.size(); + return( *this ); + } + + + /// Returns `true` if the span is empty + bool + empty() const + { + return( m_size == 0 ); + } + + + /// Returns a pointer to the beginning of the span + T* + data() const + { + return( m_data ); + } + + + /// Returns the number of elements in the span + std::size_t + size() const + { + return( m_size ); + } + + + /// Returns an iterator to the beginning of the span + Iterator + begin() const + { + return( m_data ); + } + + + /// Returns an iterator to the beginning of the span + ConstIterator + cbegin() const + { + return( m_data ); + } + + + /// Returns an iterator to one past the end of the span + Iterator + end() const + { + return( m_data + m_size ); + } + + + /// Returns an iterator to one past the end of the span + ConstIterator + cend() const + { + return( m_data + m_size ); + } +}; // class span + +} // namespace std + +#endif // if ( __cplusplus >= 201103L ) && ( __cplusplus < 201703L ) + +#endif // ifndef MYX_BACKPORTS_CPP_SPAN_HPP_ diff --git a/src/myx/backports/qt/CMakeLists.txt b/src/myx/backports/qt/CMakeLists.txt new file mode 100644 index 0000000..0dcf6bb --- /dev/null +++ b/src/myx/backports/qt/CMakeLists.txt @@ -0,0 +1,42 @@ +# Название основной цели и имя библиотеки в текущем каталоге +set(TRGT backports-qt) + +# cmake-format: off +# Список файлов исходных текстов +set(TRGT_cpp) + +# Список заголовочных файлов +set(TRGT_hpp + ${CMAKE_CURRENT_SOURCE_DIR}/common.hpp + ) + +set(TRGT_headers ${TRGT_hpp}) +# cmake-format: on + +add_library(${TRGT} INTERFACE) +target_sources(${TRGT} INTERFACE ${TRGT_cpp} ${TRGT_headers}) + +# Создание цели для проверки утилитой clang-tidy +add_clang_tidy_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) + +# Создание цели для проверки утилитой clang-analyze +add_clang_analyze_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) + +# Создание цели для проверки утилитой clazy +add_clazy_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) + +# Создание цели для проверки утилитой pvs-studio +add_pvs_check(${TRGT}) + +# Создание цели для автоматического форматирования кода +add_format_sources(${TRGT} ${TRGT_cpp} ${TRGT_headers}) + +target_include_directories(${TRGT} INTERFACE ${CMAKE_SOURCE_DIR}/src) + +install(FILES ${TRGT_headers} COMPONENT base-dev + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/backports/qt) +generate_pkgconfig(myx-${TRGT} COMPONENT base-dev INSTALL_LIBRARY ${MYXLIB_BUILD_LIBRARIES}) + +# Цель, используемая только для установки заголовочных файлов без компиляции проекта +add_custom_target(${TRGT}-install-headers COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=base-dev -P + "${CMAKE_BINARY_DIR}/cmake_install.cmake") diff --git a/src/myx/qt/backports.hpp b/src/myx/backports/qt/common.hpp similarity index 61% rename from src/myx/qt/backports.hpp rename to src/myx/backports/qt/common.hpp index 0ce776d..33cc259 100644 --- a/src/myx/qt/backports.hpp +++ b/src/myx/backports/qt/common.hpp @@ -1,14 +1,13 @@ -#ifndef MYX_QT_BACKPORTS_HPP_ -#define MYX_QT_BACKPORTS_HPP_ +#ifndef MYX_BACKPORTS_QT_COMMON_HPP_ +#define MYX_BACKPORTS_QT_COMMON_HPP_ #pragma once -#if ( defined ( TARGET_LSB_ID_AstraLinuxSE ) && defined ( TARGET_LSB_CODENAME_smolensk ) ) - -#define override - -#if QT_VERSION <= 0x050700 +#if !defined( QT_VERSION ) #include +#endif + +#if ( QT_VERSION <= 0x050700 ) template< typename ... Args > struct QOverload { @@ -31,8 +30,6 @@ Q_DECL_CONSTEXPR typename std::add_const< T >::type& qAsConst( T& t ) noexcept template < typename T > void qAsConst( const T&& ) = delete; - #endif // if QT_VERSION <= 0x050700 -#endif // if ( defined ( TARGET_LSB_ID_AstraLinuxSE ) && defined ( TARGET_LSB_CODENAME_smolensk ) ) -#endif // MYX_QT_BACKPORTS_HPP_ +#endif // MYX_BACKPORTS_QT_COMMON_HPP_ diff --git a/src/myx/base/CMakeLists.txt b/src/myx/base/CMakeLists.txt deleted file mode 100644 index fa3adb8..0000000 --- a/src/myx/base/CMakeLists.txt +++ /dev/null @@ -1,59 +0,0 @@ -# Название основной цели и имя библиотеки в текущем каталоге -set(TRGT base) - -# cmake-format: off -# Список файлов исходных текстов -set(TRGT_cpp - ${CMAKE_CURRENT_SOURCE_DIR}/config.cpp) - -# Список заголовочных файлов -set(TRGT_hpp - ${CMAKE_CURRENT_SOURCE_DIR}/config.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/limits.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/enum_bitmask_operations.hpp) - -set(TRGT_headers ${TRGT_hpp}) -# cmake-format: on - -add_library(${TRGT}-header-only INTERFACE) -target_include_directories( - ${TRGT}-header-only SYSTEM INTERFACE "$" - "$") - -if(MYXLIB_BUILD_LIBRARIES) - add_common_library(${TRGT} OUTPUT_NAME myx-${TRGT} SOURCES ${TRGT_cpp} ${TRGT_headers}) - common_target_properties(${TRGT}) - - # Создание цели для проверки утилитой clang-tidy - add_clang_tidy_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) - - # Создание цели для проверки утилитой clang-analyze - add_clang_analyze_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) - - # Создание цели для проверки утилитой clazy - add_clazy_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) - - # Создание цели для проверки утилитой pvs-studio - add_pvs_check(${TRGT}) - - # Создание цели для автоматического форматирования кода - add_format_sources(${TRGT} ${TRGT_cpp} ${TRGT_headers}) - - target_compile_definitions(${TRGT} PUBLIC MYXLIB_BUILD_LIBRARIES) - target_include_directories(${TRGT} SYSTEM PRIVATE ${CMAKE_SOURCE_DIR}/src) - - install(TARGETS ${TRGT}_static COMPONENT libs-dev ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - if(BUILD_SHARED_LIBS) - install(TARGETS ${TRGT}_shared COMPONENT main LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) - endif() -else() - install(FILES ${TRGT_cpp} COMPONENT base-dev DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/${TRGT}) -endif() - -generate_pkgconfig(myx-${TRGT} COMPONENT base-dev INSTALL_LIBRARY ${MYXLIB_BUILD_LIBRARIES}) -install(FILES ${TRGT_headers} ${CMAKE_BINARY_DIR}/include/myx/base/compiler_features.hpp COMPONENT base-dev - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/${TRGT}) - -# Цель, используемая только для установки заголовочных файлов без компиляции проекта -add_custom_target(${TRGT}-install-headers COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=base-dev -P - "${CMAKE_BINARY_DIR}/cmake_install.cmake") diff --git a/src/myx/base/config.cpp b/src/myx/base/config.cpp deleted file mode 100644 index c35efbf..0000000 --- a/src/myx/base/config.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef MYX_BASE_CONFIG_CPP_ -#define MYX_BASE_CONFIG_CPP_ - -#ifndef MYXLIB_HEADER_ONLY -#include -#else -#pragma once -#endif - -#endif // MYX_BASE_CONFIG_CPP_ diff --git a/src/myx/base/config.hpp b/src/myx/base/config.hpp deleted file mode 100644 index 0473bfe..0000000 --- a/src/myx/base/config.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef MYX_BASE_CONFIG_HPP_ -#define MYX_BASE_CONFIG_HPP_ - -#pragma once - -#ifdef MYXLIB_BUILD_LIBRARIES -#undef MYXLIB_HEADER_ONLY - -#if defined( _WIN32 ) && defined( MYXLIB_SHARED_LIB ) -#ifdef myxlib_EXPORTS -#define MYXLIB_API __declspec( dllexport ) -#else -#define MYXLIB_API __declspec( dllimport ) -#endif -#else -#define MYXLIB_API -#endif -#define MYXLIB_INLINE -#else -#define MYXLIB_HEADER_ONLY -#define MYXLIB_API -#define MYXLIB_INLINE inline -#endif // ifdef MYXLIB_BUILD_LIBRARIES - -#ifdef MYXLIB_HEADER_ONLY -#include "config.cpp" -#endif - -#endif // MYX_BASE_CONFIG_HPP_ diff --git a/src/myx/base/enum_bitmask_operations.hpp b/src/myx/base/enum_bitmask_operations.hpp deleted file mode 100644 index 12a8d56..0000000 --- a/src/myx/base/enum_bitmask_operations.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef MYX_BASE_ENUM_BITWISE_OPERATIONS_HPP_ -#define MYX_BASE_ENUM_BITWISE_OPERATIONS_HPP_ - -#pragma once - -#include - -namespace myx { - -namespace base { - -template< typename Enum > -struct EnableBitMaskOperators -{ - static const bool k_Enable = false; -}; - -template< typename Enum > -typename std::enable_if< EnableBitMaskOperators< Enum >::k_Enable, Enum >::type -operator |( Enum lhs, Enum rhs ) -{ - using Underlying = typename std::underlying_type< Enum >::type; - return( static_cast< Enum >( - static_cast< Underlying >( lhs ) | - static_cast< Underlying >( rhs ) - ) ); -} - -} // namespace base - -} // namespace myx - -/** - * @brief Макрос, предоставляющий возможность выполнять битовые операции в enum class - * - * Источник: http://blog.bitwigglers.org/using-enum-classes-as-type-safe-bitmasks/ - * Пример использования: - * - * namespace ns { - * enum class Permissions - * { - * Readable = 0x4, - * Writeable = 0x2, - * Executable = 0x1 - * }; - * } - * ENABLE_BITMASK_OPERATORS(ns::Permissions) - */ - -#define ENABLE_BITMASK_OPERATORS( x ) \ - template<> \ - struct myx::base::EnableBitMaskOperators< x > \ - { \ - static const bool k_Enable = true; \ - }; - -#endif // ifndef MYX_BASE_ENUM_BITWISE_OPERATIONS_HPP_ diff --git a/src/myx/core/CMakeLists.txt b/src/myx/core/CMakeLists.txt new file mode 100644 index 0000000..8c6a34a --- /dev/null +++ b/src/myx/core/CMakeLists.txt @@ -0,0 +1,44 @@ +# Название основной цели и имя библиотеки в текущем каталоге +set(TRGT core) + +# cmake-format: off +# Список файлов исходных текстов +set(TRGT_cpp) + +# Список заголовочных файлов +set(TRGT_hpp + ${CMAKE_CURRENT_SOURCE_DIR}/config.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/limits.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/endian_types.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/enum_bitmask_operations.hpp) + +set(TRGT_headers ${TRGT_hpp}) +# cmake-format: on + +add_library(${TRGT} INTERFACE) +target_sources(${TRGT} INTERFACE ${TRGT_cpp} ${TRGT_headers}) + +# Создание цели для проверки утилитой clang-tidy +add_clang_tidy_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) + +# Создание цели для проверки утилитой clang-analyze +add_clang_analyze_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) + +# Создание цели для проверки утилитой clazy +add_clazy_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) + +# Создание цели для проверки утилитой pvs-studio +add_pvs_check(${TRGT}) + +# Создание цели для автоматического форматирования кода +add_format_sources(${TRGT} ${TRGT_cpp} ${TRGT_headers}) + +target_include_directories(${TRGT} INTERFACE ${CMAKE_SOURCE_DIR}/src) + +generate_pkgconfig(myx-${TRGT} COMPONENT base-dev INSTALL_LIBRARY ${MYXLIB_BUILD_LIBRARIES}) +install(FILES ${TRGT_headers} ${CMAKE_BINARY_DIR}/include/myx/core/compiler_features.hpp COMPONENT base-dev + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/${TRGT}) + +# Цель, используемая только для установки заголовочных файлов без компиляции проекта +add_custom_target(${TRGT}-install-headers COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=base-dev -P + "${CMAKE_BINARY_DIR}/cmake_install.cmake") diff --git a/src/myx/core/config.hpp b/src/myx/core/config.hpp new file mode 100644 index 0000000..946d1b2 --- /dev/null +++ b/src/myx/core/config.hpp @@ -0,0 +1,17 @@ +#ifndef MYX_CORE_CONFIG_HPP_ +#define MYX_CORE_CONFIG_HPP_ + +#pragma once + +#if defined( _WIN32 ) && defined( MYXLIB_SHARED_LIB ) +#ifdef myxlib_EXPORTS +#define MYXLIB_API __declspec( dllexport ) +#else +#define MYXLIB_API __declspec( dllimport ) +#endif +#else +#define MYXLIB_API +#endif +#define MYXLIB_INLINE + +#endif // MYX_CORE_CONFIG_HPP_ diff --git a/src/myx/base/config_flags.hpp.in b/src/myx/core/config_flags.hpp.in similarity index 100% rename from src/myx/base/config_flags.hpp.in rename to src/myx/core/config_flags.hpp.in diff --git a/src/myx/core/endian_types.hpp b/src/myx/core/endian_types.hpp new file mode 100644 index 0000000..a76747a --- /dev/null +++ b/src/myx/core/endian_types.hpp @@ -0,0 +1,192 @@ +#ifndef MYX_BASE_ENDIAN_TYPES_HPP_ +#define MYX_BASE_ENDIAN_TYPES_HPP_ + +#pragma once + +#include + +#include +#include +#include + +#ifdef QT_CORE_LIB +#include +#endif + +// Основа здесь: https://github.com/tatewake/endian-template/ + +namespace myx { + +namespace core { + +template< typename T > +class EndianTypesBase +{ +protected: + #if defined ( _MSC_VER ) + #pragma warning ( push ) + #endif + static T swapBytes( const T& b ) + { + T n; + std::span< uint8_t > sn( reinterpret_cast< uint8_t* >( &n ), sizeof( T ) ); //NOLINT + std::span< const uint8_t > sb( reinterpret_cast< const uint8_t* >( &b ), sizeof( T ) ); //NOLINT + std::reverse_copy( sb.begin(), sb.end(), sn.begin() ); + return( n ); + } // swapBytes + + + #if defined( _MSC_VER ) + #pragma warning ( pop ) + #endif +}; // class EndianTypesBase + +template< typename T > +class LittleEndianType : public EndianTypesBase< T > +{ +protected: + T m_data; //NOLINT + + static T transform( const T& b ) + { + const uint16_t k_i = 1; + return( ( reinterpret_cast< const char& >( k_i ) == 1 ) ? b : EndianTypesBase< T >::swapBytes( b ) ); //NOLINT + } + + +public: + // Constructors + LittleEndianType() = default; + + // If we endian swap, it happens in two places: + // 1. Set an OE from a PE + // 2. Get a PE from an OE + // Storage in + // NOLINTNEXTLINE + LittleEndianType( const T& b ) : + m_data( transform( b ) ) + {} + template < typename U > explicit LittleEndianType( U const& b ) : + m_data( transform( T( b ) ) ) + {} + // Storage out + template < typename U > explicit operator U() const { return( U( transform( m_data ) ) ); } + explicit operator T() const { return( transform( m_data ) ); } + + template < typename U > bool operator ==( U const& o ) { return( U( *this ) == o ); } + template < typename U > bool operator !=( U const& o ) { return( U( *this ) != o ); } + + // Arithmetic assignment operators + LittleEndianType& operator ++() /* prefix */ { *this = T( *this ) + T( 1 ); return( *this ); } + LittleEndianType operator ++( int ) /* suffix */ { LittleEndianType t( *this ); *this = T( *this ) + T( 1 ); return( t ); } + LittleEndianType& operator --() /* prefix */ { *this = T( *this ) - T( 1 ); return( *this ); } + LittleEndianType operator --( int ) /* suffix */ { LittleEndianType t( *this ); *this = T( *this ) - T( 1 ); return( t ); } + + // Compound assignment operators + LittleEndianType& operator +=( const T& b ) { *this = T( *this ) + b; return( *this ); } + LittleEndianType& operator -=( const T& b ) { *this = T( *this ) - b; return( *this ); } + LittleEndianType& operator *=( const T& b ) { *this = T( *this ) * b; return( *this ); } + LittleEndianType& operator /=( const T& b ) { *this = T( *this ) / b; return( *this ); } + LittleEndianType& operator %=( const T& b ) { *this = T( *this ) % b; return( *this ); } + LittleEndianType& operator &=( const T& b ) { *this = T( *this ) & b; return( *this ); } + LittleEndianType& operator |=( const T& b ) { *this = T( *this ) | b; return( *this ); } + LittleEndianType& operator ^=( const T& b ) { *this = T( *this ) ^ b; return( *this ); } + LittleEndianType& operator <<=( const T& b ) { *this = T( T( *this ) << b ); return( *this ); } + LittleEndianType& operator >>=( const T& b ) { *this = T( T( *this ) >> b ); return( *this ); } + friend std::ostream& operator <<( std::ostream& out, const LittleEndianType b ) { out << T( b ); return( out ); } + friend std::istream& operator >>( std::istream& in, LittleEndianType& b ) { T val; in >> val; b = val; return( in ); } + std::string toStdString() { return( std::to_string( transform( m_data ) ) ); } + #ifdef QT_CORE_LIB + friend QDebug& operator <<( QDebug& out, const LittleEndianType< T > b ) { out << T( b ); return( out ); } + QString toQString() { return( QString::number( transform( m_data ) ) ); } + #endif +}; // class LittleEndianType + +template< typename T > +class BigEndianType : public EndianTypesBase< T > +{ +protected: + T m_data; //NOLINT + + static T transform( const T& b ) + { + const uint16_t k_i = 1; + return( ( reinterpret_cast< const char& >( k_i ) == 1 ) ? EndianTypesBase< T >::swapBytes( b ) : b ); //NOLINT + } + + +public: + // Constructors + BigEndianType() = default; + + // If we endian swap, it happens in two places: + // 1. Set an OE from a PE + // 2. Get a PE from an OE + // Storage in + // NOLINTNEXTLINE + BigEndianType( const T& b ) : + m_data( transform( b ) ) + {} + template < typename U > explicit BigEndianType( U const& b ) : + m_data( transform( T( b ) ) ) + {} + // Storage out + template < typename U > explicit operator U() const { return( U( transform( m_data ) ) ); } + explicit operator T() const { return( transform( m_data ) ); } + + template < typename U > bool operator ==( U const& o ) { return( U( *this ) == o ); } + template < typename U > bool operator !=( U const& o ) { return( U( *this ) != o ); } + + // Arithmetic assignment operators + BigEndianType& operator ++() /* prefix */ { *this = T( *this ) + 1; return( *this ); } + BigEndianType operator ++( int ) /* suffix */ { BigEndianType t( *this ); *this = T( *this ) + 1; return( t ); } + BigEndianType& operator --() /* prefix */ { *this = T( *this ) - 1; return( *this ); } + BigEndianType operator --( int ) /* suffix */ { BigEndianType t( *this ); *this = T( *this ) - 1; return( t ); } + + // Compound assignment operators + BigEndianType& operator +=( const T& b ) { *this = T( *this ) + b; return( *this ); } + BigEndianType& operator -=( const T& b ) { *this = T( *this ) - b; return( *this ); } + BigEndianType& operator *=( const T& b ) { *this = T( *this ) * b; return( *this ); } + BigEndianType& operator /=( const T& b ) { *this = T( *this ) / b; return( *this ); } + BigEndianType& operator %=( const T& b ) { *this = T( *this ) % b; return( *this ); } + BigEndianType& operator &=( const T& b ) { *this = T( *this ) & b; return( *this ); } + BigEndianType& operator |=( const T& b ) { *this = T( *this ) | b; return( *this ); } + BigEndianType& operator ^=( const T& b ) { *this = T( *this ) ^ b; return( *this ); } + BigEndianType& operator <<=( const T& b ) { *this = T( T( *this ) << b ); return( *this ); } + BigEndianType& operator >>=( const T& b ) { *this = T( T( *this ) >> b ); return( *this ); } + friend std::ostream& operator <<( std::ostream& out, const BigEndianType b ) { out << T( b ); return( out ); } + friend std::istream& operator >>( std::istream& in, BigEndianType& b ) { T val; in >> val; b = val; return( in ); } + std::string toStdString() { return( std::to_string( transform( m_data ) ) ); } + #ifdef QT_CORE_LIB + friend QDebug& operator <<( QDebug& out, const BigEndianType< T > b ) { out << T( b ); return( out ); } + QString toQString() { return( QString::number( transform( m_data ) ) ); } + #endif +}; // class BigEndianType + +} // namespace core + +} // namespace myx + +using leint16 = myx::core::LittleEndianType< int16_t >; //NOLINT +using leint32 = myx::core::LittleEndianType< int32_t >; //NOLINT +using leint64 = myx::core::LittleEndianType< int64_t >; //NOLINT + +using leuint16 = myx::core::LittleEndianType< uint16_t >; //NOLINT +using leuint32 = myx::core::LittleEndianType< uint32_t >; //NOLINT +using leuint64 = myx::core::LittleEndianType< uint64_t >; //NOLINT + +using lefloat = myx::core::LittleEndianType< float >; //NOLINT +using ledouble = myx::core::LittleEndianType< double >; //NOLINT + +using beint16 = myx::core::BigEndianType< int16_t >; //NOLINT +using beint32 = myx::core::BigEndianType< int32_t >; //NOLINT +using beint64 = myx::core::BigEndianType< int64_t >; //NOLINT + +using beuint16 = myx::core::BigEndianType< uint16_t >; //NOLINT +using beuint32 = myx::core::BigEndianType< uint32_t >; //NOLINT +using beuint64 = myx::core::BigEndianType< uint64_t >; //NOLINT + +using befloat = myx::core::BigEndianType< float >; //NOLINT +using bedouble = myx::core::BigEndianType< double >; //NOLINT + +#endif // MYX_BASE_ENDIAN_TYPES_HPP_ diff --git a/src/myx/core/enum_bitmask_operations.hpp b/src/myx/core/enum_bitmask_operations.hpp new file mode 100644 index 0000000..1c10f8c --- /dev/null +++ b/src/myx/core/enum_bitmask_operations.hpp @@ -0,0 +1,93 @@ +#ifndef MYX_CORE_ENUM_BITWISE_OPERATIONS_HPP_ +#define MYX_CORE_ENUM_BITWISE_OPERATIONS_HPP_ + +#pragma once + +#include + +namespace myx { + +namespace core { + +template< typename Enum > +struct EnableBitMaskOperators +{ + static const bool kEnable = false; +}; + +template< typename Enum > +typename std::enable_if< EnableBitMaskOperators< Enum >::kEnable, Enum >::type +operator ~( Enum e ) +{ + using Underlying = typename std::underlying_type< Enum >::type; + return( static_cast< Enum >( ~static_cast< Underlying >( e ) ) ); +} + + +template< typename Enum > +typename std::enable_if< EnableBitMaskOperators< Enum >::kEnable, Enum >::type +operator |( Enum lhs, Enum rhs ) +{ + using Underlying = typename std::underlying_type< Enum >::type; + return( static_cast< Enum >( static_cast< Underlying >( lhs ) | static_cast< Underlying >( rhs ) ) ); +} + + +template< typename Enum > +typename std::enable_if< EnableBitMaskOperators< Enum >::kEnable, typename std::add_lvalue_reference< Enum >::type >::type +operator |=( Enum& lhs, Enum rhs ) +{ + using Underlying = typename std::underlying_type< Enum >::type; + lhs = static_cast< Enum >( static_cast< Underlying >( lhs ) | static_cast< Underlying >( rhs ) ); + return( lhs ); +} + + +template< typename Enum > +typename std::enable_if< EnableBitMaskOperators< Enum >::kEnable, Enum >::type +operator &( Enum lhs, Enum rhs ) +{ + using Underlying = typename std::underlying_type< Enum >::type; + return( static_cast< Enum >( static_cast< Underlying >( lhs ) & static_cast< Underlying >( rhs ) ) ); +} + + +template< typename Enum > +typename std::enable_if< EnableBitMaskOperators< Enum >::kEnable, typename std::add_lvalue_reference< Enum >::type >::type +operator &=( Enum& lhs, Enum rhs ) +{ + using Underlying = typename std::underlying_type< Enum >::type; + lhs = static_cast< Enum >( static_cast< Underlying >( lhs ) & static_cast< Underlying >( rhs ) ); + return( lhs ); +} + +} // namespace core + +} // namespace myx + +/** + * @brief Макрос, предоставляющий возможность выполнять битовые операции в enum class + * + * Источник: http://blog.bitwigglers.org/using-enum-classes-as-type-safe-bitmasks/ + * Пример использования: + * + * namespace ns { + * enum class Permissions + * { + * Readable = 0x4, + * Writeable = 0x2, + * Executable = 0x1 + * }; + * } + * ENABLE_BITMASK_OPERATORS(ns::Permissions) + */ + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define ENABLE_BITMASK_OPERATORS( x ) \ + template<> \ + struct myx::core::EnableBitMaskOperators< x > \ + { \ + static const bool kEnable = true; \ + }; + +#endif // ifndef MYX_CORE_ENUM_BITWISE_OPERATIONS_HPP_ diff --git a/src/myx/base/limits.hpp b/src/myx/core/limits.hpp similarity index 60% rename from src/myx/base/limits.hpp rename to src/myx/core/limits.hpp index 53c02d1..92a9e5e 100644 --- a/src/myx/base/limits.hpp +++ b/src/myx/core/limits.hpp @@ -1,5 +1,5 @@ -#ifndef MYX_BASE_LIMITS_HPP_ -#define MYX_BASE_LIMITS_HPP_ +#ifndef MYX_CORE_LIMITS_HPP_ +#define MYX_CORE_LIMITS_HPP_ #pragma once @@ -7,25 +7,25 @@ namespace myx { -namespace base { +namespace core { /** * @brief Константа, представляющая значение, не являющееся числом, для типа float */ -constexpr float k_FloatNAN { std::numeric_limits< float >::quiet_NaN() }; +constexpr float kFloatNAN { std::numeric_limits< float >::quiet_NaN() }; /** * @brief Константа, представляющая значение, не являющееся числом, для типа double */ -constexpr double k_DoubleNAN { std::numeric_limits< double >::quiet_NaN() }; +constexpr double kDoubleNAN { std::numeric_limits< double >::quiet_NaN() }; /** * @brief Константа, представляющая значение, не являющееся числом, для типа long double */ -constexpr double k_LongDoubleNAN { std::numeric_limits< long double >::quiet_NaN() }; +constexpr double kLongDoubleNAN { std::numeric_limits< long double >::quiet_NaN() }; -} // namespace base +} // namespace core } // namespace myx -#endif // MYX_BASE_LIMITS_HPP_ +#endif // MYX_CORE_LIMITS_HPP_ diff --git a/src/myx/filesystem/CMakeLists.txt b/src/myx/filesystem/CMakeLists.txt index 283eb5e..0ec1240 100644 --- a/src/myx/filesystem/CMakeLists.txt +++ b/src/myx/filesystem/CMakeLists.txt @@ -3,60 +3,44 @@ set(TRGT filesystem) # cmake-format: off # Список файлов исходных текстов -set(TRGT_cpp - ${CMAKE_CURRENT_SOURCE_DIR}/current_executable.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/paths.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/paths_mt.cpp) +set(TRGT_cpp ${CMAKE_CURRENT_SOURCE_DIR}/paths.cpp) # Список заголовочных файлов -set(TRGT_hpp - ${CMAKE_CURRENT_SOURCE_DIR}/current_executable.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/paths.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/paths_mt.hpp) +set(TRGT_hpp ${CMAKE_CURRENT_SOURCE_DIR}/paths.hpp) set(TRGT_headers ${TRGT_hpp}) # cmake-format: on -add_library(${TRGT}-header-only INTERFACE) -target_include_directories( - ${TRGT}-header-only SYSTEM INTERFACE "$" - "$") +add_common_library(${TRGT} OUTPUT_NAME myx-${TRGT} SOURCES ${TRGT_cpp} ${TRGT_headers}) +common_target_properties(${TRGT}) -if(MYXLIB_BUILD_LIBRARIES) +# Создание цели для проверки утилитой clang-tidy +add_clang_tidy_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) - add_common_library(${TRGT} OUTPUT_NAME myx-${TRGT} SOURCES ${TRGT_cpp} ${TRGT_headers}) - common_target_properties(${TRGT}) +# Создание цели для проверки утилитой clang-analyze +add_clang_analyze_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) - # Создание цели для проверки утилитой clang-tidy - add_clang_tidy_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) +# Создание цели для проверки утилитой clazy +add_clazy_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) - # Создание цели для проверки утилитой clang-analyze - add_clang_analyze_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) +# Создание цели для проверки утилитой pvs-studio +add_pvs_check(${TRGT}) - # Создание цели для проверки утилитой clazy - add_clazy_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) +# Создание цели для автоматического форматирования кода +add_format_sources(${TRGT} ${TRGT_cpp} ${TRGT_headers}) - # Создание цели для проверки утилитой pvs-studio - add_pvs_check(${TRGT}) +target_include_directories(${TRGT} SYSTEM PUBLIC ${Qt5Core_INCLUDE_DIRS}) +target_include_directories(${TRGT} SYSTEM PRIVATE ${CMAKE_SOURCE_DIR}/src) +cotire(${TRGT}) - # Создание цели для автоматического форматирования кода - add_format_sources(${TRGT} ${TRGT_cpp} ${TRGT_headers}) - - target_compile_definitions(${TRGT} PUBLIC MYXLIB_BUILD_LIBRARIES) - target_include_directories(${TRGT} SYSTEM PUBLIC ${Qt5Core_INCLUDE_DIRS}) - target_include_directories(${TRGT} SYSTEM PRIVATE ${CMAKE_SOURCE_DIR}/src) - cotire(${TRGT}) - - install(TARGETS ${TRGT}_static COMPONENT libs-dev ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - if(BUILD_SHARED_LIBS) - install(TARGETS ${TRGT}_shared COMPONENT main LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) - endif() -else() - install(FILES ${TRGT_cpp} COMPONENT base-dev DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/${TRGT}) +install(TARGETS ${TRGT}_static COMPONENT libs-dev ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +if(BUILD_SHARED_LIBS) + install(TARGETS ${TRGT}_shared COMPONENT main LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif() generate_pkgconfig(myx-${TRGT} COMPONENT base-dev INSTALL_LIBRARY ${MYXLIB_BUILD_LIBRARIES}) -install(FILES ${TRGT_headers} COMPONENT base-dev DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/${TRGT}) +install(FILES ${TRGT_headers} COMPONENT base-dev + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/${TRGT}) # Цель, используемая только для установки заголовочных файлов без компиляции проекта add_custom_target(${TRGT}-install-headers COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=base-dev -P diff --git a/src/myx/filesystem/current_executable.cpp b/src/myx/filesystem/current_executable.cpp deleted file mode 100644 index 95c8ae8..0000000 --- a/src/myx/filesystem/current_executable.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef MYX_BASE_CURRENT_EXECUTABLE_CPP_ -#define MYX_BASE_CURRENT_EXECUTABLE_CPP_ - -#ifndef MYXLIB_HEADER_ONLY -#include -#else -#pragma once -#endif - -#include - -#include - -#include -#include - -namespace myx { - -namespace filesystem { - -#if !defined ( __linux__ ) -error "Class CurrentExecutable is supported only in Linux" -#endif - -MYXLIB_INLINE CurrentExecutable::CurrentExecutable() : - m_procFilePath( QStringLiteral( "/proc/self/exe" ) ) -{ - m_canonicalFilePath = m_procFilePath.canonicalFilePath(); -} - - -MYXLIB_INLINE const QFileInfo& CurrentExecutable::canonicalFilePath() const -{ - return( m_canonicalFilePath ); -} - -} // namespace filesystem - -} // namespace myx - -#endif // MYX_BASE_CURRENT_EXECUTABLE_CPP_ diff --git a/src/myx/filesystem/current_executable.hpp b/src/myx/filesystem/current_executable.hpp deleted file mode 100644 index f0c027c..0000000 --- a/src/myx/filesystem/current_executable.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @file current_executable.hpp - * @brief Параметры исполняемого файла - */ - -#ifndef MYX_FILESYSTEM_CURRENT_EXECUTABLE_HPP_ -#define MYX_FILESYSTEM_CURRENT_EXECUTABLE_HPP_ - -#pragma once - -#include - -#include -#include -#include - - -namespace myx { - -namespace filesystem { - -class CurrentExecutable -{ - /// @brief Путь к символической ссылке, указывающей на текущий исполняемый файл - QFileInfo m_procFilePath; - - /// @brief Канонический путь к текущему исполняемому файлу - QFileInfo m_canonicalFilePath; - - friend class Paths; -public: - /** - * @brief Конструктор, собирающий информацию о текущем исполняемом файле. - */ - CurrentExecutable(); - - /** - * @brief Канонический путь к текущему исполняемому файлу - */ - const QFileInfo& canonicalFilePath() const; -}; // class CurrentExecutable - -} // namespace filesystem - -} // namespace myx - -#ifdef MYXLIB_HEADER_ONLY -#include "current_executable.cpp" -#endif - -#endif // MYX_FILESYSTEM_CURRENT_EXECUTABLE_HPP_ diff --git a/src/myx/filesystem/paths.cpp b/src/myx/filesystem/paths.cpp index dc5b611..c4d4677 100644 --- a/src/myx/filesystem/paths.cpp +++ b/src/myx/filesystem/paths.cpp @@ -1,14 +1,8 @@ -#ifndef MYX_BASE_PATHS_CPP_ -#define MYX_BASE_PATHS_CPP_ +#ifndef MYX_CORE_PATHS_CPP_ +#define MYX_CORE_PATHS_CPP_ -#ifndef MYXLIB_HEADER_ONLY +#include #include -#else -#pragma once -#endif - -#include -#include #include @@ -19,179 +13,188 @@ namespace myx { namespace filesystem { -MYXLIB_INLINE Paths::Paths() = default; +MYXLIB_INLINE Paths::Paths() +{ + QFileInfo procSelfExe( QStringLiteral( "/proc/self/exe" ) ); + QFileInfo currentExecutable = procSelfExe.canonicalFilePath(); + m_executableName = currentExecutable.fileName(); + m_executableFilePath = currentExecutable.absoluteFilePath(); + m_executableDirectory = currentExecutable.absolutePath(); +} + + +MYXLIB_INLINE void Paths::setupSystemDirectories( const QString& defaultPrefixDirectory, + const QString& defaultEtcDirectory, + const QString& defaultConstDataDirectory, + const QString& defaultVarDataDirectory, + const QString& defaultLogDirectory ) +{ + QFileInfo prefixDirInfo { defaultPrefixDirectory }; + if ( prefixDirInfo.isDir() && prefixDirInfo.isReadable() ) + { + m_prefixDirectory = defaultPrefixDirectory; + } + else + { + m_prefixDirectory = "."; + } + + QFileInfo etcDirInfo { defaultEtcDirectory }; + if ( etcDirInfo.isDir() && etcDirInfo.isReadable() ) + { + m_systemConfigDirectory = defaultEtcDirectory; + } + else + { + m_systemConfigDirectory = m_userConfigDirectory; + } + + QFileInfo constDataDirInfo { defaultConstDataDirectory }; + if ( constDataDirInfo.isDir() && constDataDirInfo.isReadable() ) + { + m_systemConstDataDirectory = defaultConstDataDirectory; + } + else + { + m_systemConstDataDirectory = m_userConstDataDirectory; + } + + QFileInfo varDataDirInfo { defaultVarDataDirectory }; + if ( varDataDirInfo.isDir() && varDataDirInfo.isWritable() ) + { + m_systemVarDataDirectory = defaultVarDataDirectory; + } + else + { + m_systemVarDataDirectory = m_userVarDataDirectory; + } + + QFileInfo logDirInfo { defaultLogDirectory }; + if ( logDirInfo.isDir() && logDirInfo.isWritable() ) + { + m_systemLogDirectory = defaultLogDirectory; + } + else + { + m_systemLogDirectory = m_userLogDirectory; + } +} // Paths::setupSystemDirectories + MYXLIB_INLINE Paths::HierarchyType Paths::getHierarchyType() { QRegExp binUnityRegexp( "/s*bin/unity$" ); - QRegExp binRegexp( "/s*bin$" ); - auto binaryDir = m_currentExecutable.m_canonicalFilePath.canonicalPath(); + auto binaryDir = m_executableDirectory; if ( binUnityRegexp.indexIn( binaryDir ) >= 0 ) { binaryDir.remove( binUnityRegexp ); - - QFileInfo etcDirInfo { binaryDir + "/etc" }; - if ( !etcDirInfo.isDir() || !etcDirInfo.isReadable() ) { return( HierarchyType::kFlat ); } - - QFileInfo constDataDirInfo { binaryDir + "/files/data" }; - if ( !constDataDirInfo.isDir() || !constDataDirInfo.isReadable() ) { return( HierarchyType::kFlat ); } - - QFileInfo varDataDirInfo { binaryDir + "/files/lib" }; - if ( !varDataDirInfo.isDir() || !varDataDirInfo.isWritable() ) { return( HierarchyType::kFlat ); } - - QFileInfo logDirInfo { binaryDir + "/files/log" }; - if ( !logDirInfo.isDir() || !logDirInfo.isWritable() ) { return( HierarchyType::kFlat ); } - - m_systemConfigDirectory = etcDirInfo.canonicalFilePath(); - m_systemConstDataDirectory = constDataDirInfo.canonicalFilePath(); - m_systemVarDataDirectory = varDataDirInfo.canonicalFilePath(); - m_systemLogDirectory = logDirInfo.canonicalFilePath(); + setupSystemDirectories( binaryDir, + binaryDir + "/etc", + binaryDir + "/files/data", + binaryDir + "/files/lib", + binaryDir + "/files/log" ); return ( HierarchyType::kDevelopment ); } + QRegExp binRegexp( "/s*bin$" ); if ( binRegexp.indexIn( binaryDir ) == -1 ) { + m_prefixDirectory = m_executableDirectory; + m_systemConstDataDirectory = m_executableDirectory; + m_systemVarDataDirectory = m_executableDirectory; + m_systemConfigDirectory = m_executableDirectory; + m_systemLogDirectory = m_executableDirectory; + return ( HierarchyType::kFlat ); } QRegExp optRegexp( "^/opt(/|/.+/)" + m_projectName + "/" ); - if ( optRegexp.indexIn( binaryDir ) >= 0 ) { binaryDir.remove( binRegexp ); - QFileInfo etcDirInfo { binaryDir + "/etc" }; - if ( !etcDirInfo.isDir() || !etcDirInfo.isReadable() ) { return( HierarchyType::kFlat ); } - - QFileInfo constDataDirInfo { binaryDir + "/files/data" }; - if ( !constDataDirInfo.isDir() || !constDataDirInfo.isReadable() ) { return( HierarchyType::kFlat ); } - - QFileInfo varDataDirInfo { binaryDir + "/files/lib" }; - if ( !varDataDirInfo.isDir() || !varDataDirInfo.isWritable() ) { return( HierarchyType::kFlat ); } - - QFileInfo logDirInfo { binaryDir + "/files/log" }; - if ( !logDirInfo.isDir() || !logDirInfo.isWritable() ) { return( HierarchyType::kFlat ); } - - m_systemConfigDirectory = etcDirInfo.canonicalFilePath(); - m_systemConstDataDirectory = constDataDirInfo.canonicalFilePath(); - m_systemVarDataDirectory = varDataDirInfo.canonicalFilePath(); - m_systemLogDirectory = logDirInfo.canonicalFilePath(); + setupSystemDirectories( binaryDir, + binaryDir + "/etc", + binaryDir + "/files/data", + binaryDir + "/files/lib", + binaryDir + "/files/log" ); return ( HierarchyType::kOpt ); } + if ( binaryDir.startsWith( QStringLiteral( "/usr/local/rtis" ) ) ) + { + setupSystemDirectories( "/usr/local/rtis", + "/usr/local/rtis/etc/" + m_projectName, + "/usr/local/rtis/share/" + m_projectName, + "/usr/local/rtis/lib/" + m_projectName, + "/usr/local/rtis/log/" + m_projectName ); + + return ( HierarchyType::kUsrLocalRtis ); + } + if ( binaryDir.startsWith( QStringLiteral( "/usr/local" ) ) ) { - QFileInfo etcDirInfo { "/usr/local/etc/" + m_projectName }; - if ( !etcDirInfo.isDir() || !etcDirInfo.isReadable() ) { return( HierarchyType::kFlat ); } + setupSystemDirectories( "/usr/local", + "/usr/local/etc/" + m_projectName, + "/usr/local/share/" + m_projectName, + "/var/lib/" + m_projectName, + "/var/log/" + m_projectName ); - QFileInfo constDataDirInfo { "/usr/local/share/" + m_projectName }; - if ( !constDataDirInfo.isDir() || !constDataDirInfo.isReadable() ) { return( HierarchyType::kFlat ); } - - QFileInfo varDataDirInfo { "/var/lib/" + m_projectName }; - if ( !varDataDirInfo.isDir() || !varDataDirInfo.isWritable() ) { return( HierarchyType::kFlat ); } - - QFileInfo logDirInfo { "/var/log/" + m_projectName }; - if ( !logDirInfo.isDir() || !logDirInfo.isWritable() ) { return( HierarchyType::kFlat ); } - - m_systemConfigDirectory = etcDirInfo.canonicalFilePath(); - m_systemConstDataDirectory = constDataDirInfo.canonicalFilePath(); - m_systemVarDataDirectory = varDataDirInfo.canonicalFilePath(); - m_systemLogDirectory = logDirInfo.canonicalFilePath(); - - return ( HierarchyType::kUsr ); + return ( HierarchyType::kUsrLocal ); } + if ( binaryDir.startsWith( QStringLiteral( "/usr" ) ) ) { - QFileInfo etcDirInfo { "/etc/" + m_projectName }; - if ( !etcDirInfo.isDir() || !etcDirInfo.isReadable() ) { return( HierarchyType::kFlat ); } - - QFileInfo constDataDirInfo { "/usr/share/" + m_projectName }; - if ( !constDataDirInfo.isDir() || !constDataDirInfo.isReadable() ) { return( HierarchyType::kFlat ); } - - QFileInfo varDataDirInfo { "/var/lib/" + m_projectName }; - if ( !varDataDirInfo.isDir() || !varDataDirInfo.isWritable() ) { return( HierarchyType::kFlat ); } - - QFileInfo logDirInfo { "/var/log/" + m_projectName }; - if ( !logDirInfo.isDir() || !logDirInfo.isWritable() ) { return( HierarchyType::kFlat ); } - - m_systemConfigDirectory = etcDirInfo.canonicalFilePath(); - m_systemConstDataDirectory = constDataDirInfo.canonicalFilePath(); - m_systemVarDataDirectory = varDataDirInfo.canonicalFilePath(); - m_systemLogDirectory = logDirInfo.canonicalFilePath(); + setupSystemDirectories( "/usr", + "/etc/" + m_projectName, + "/usr/share/" + m_projectName, + "/var/lib/" + m_projectName, + "/var/log/" + m_projectName ); return ( HierarchyType::kUsr ); } - if ( binaryDir.startsWith( m_homeDirectory.canonicalPath() + "/.local/bin" ) || - binaryDir.startsWith( m_homeDirectory.canonicalPath() + "/bin" ) ) + if ( binaryDir.startsWith( m_homeDirectory + "/.local/bin" ) || + binaryDir.startsWith( m_homeDirectory + "/bin" ) ) { - QFileInfo etcDirInfo { m_userConfigDirectory.canonicalPath() }; - if ( !etcDirInfo.isDir() || !etcDirInfo.isReadable() ) { return( HierarchyType::kFlat ); } - - QFileInfo constDataDirInfo { m_userConstDataDirectory.canonicalPath() }; - if ( !constDataDirInfo.isDir() || !constDataDirInfo.isReadable() ) { return( HierarchyType::kFlat ); } - - QFileInfo varDataDirInfo { m_userVarDataDirectory.canonicalPath() }; - if ( !varDataDirInfo.isDir() || !varDataDirInfo.isWritable() ) { return( HierarchyType::kFlat ); } - - QFileInfo logDirInfo { m_userLogDirectory.canonicalPath() }; - if ( !logDirInfo.isDir() || !logDirInfo.isWritable() ) { return( HierarchyType::kFlat ); } - - m_systemConfigDirectory = etcDirInfo.canonicalFilePath(); - m_systemConstDataDirectory = constDataDirInfo.canonicalFilePath(); - m_systemVarDataDirectory = varDataDirInfo.canonicalFilePath(); - m_systemLogDirectory = logDirInfo.canonicalFilePath(); + m_prefixDirectory = m_homeDirectory; + m_systemConfigDirectory = m_userConfigDirectory; + m_systemConstDataDirectory = m_userConstDataDirectory; + m_systemVarDataDirectory = m_userVarDataDirectory; + m_systemLogDirectory = m_userLogDirectory; return( HierarchyType::kHome ); } binaryDir.remove( binRegexp ); - - QFileInfo etcDirInfo { binaryDir + "/etc" }; - if ( !etcDirInfo.isDir() || !etcDirInfo.isReadable() ) { return( HierarchyType::kFlat ); } - - QFileInfo constDataDirInfo { binaryDir + "/files/data" }; - if ( !constDataDirInfo.isDir() || !constDataDirInfo.isReadable() ) { return( HierarchyType::kFlat ); } - - QFileInfo varDataDirInfo { binaryDir + "/files/lib" }; - if ( !varDataDirInfo.isDir() || !varDataDirInfo.isWritable() ) { return( HierarchyType::kFlat ); } - - QFileInfo logDirInfo { binaryDir + "/files/log" }; - if ( !logDirInfo.isDir() || !logDirInfo.isWritable() ) { return( HierarchyType::kFlat ); } - - m_systemConfigDirectory = etcDirInfo.canonicalFilePath(); - m_systemConstDataDirectory = constDataDirInfo.canonicalFilePath(); - m_systemVarDataDirectory = varDataDirInfo.canonicalFilePath(); - m_systemLogDirectory = logDirInfo.canonicalFilePath(); + setupSystemDirectories( binaryDir, + binaryDir + "/etc", + binaryDir + "/files/data", + binaryDir + "/files/lib", + binaryDir + "/files/log" ); return ( HierarchyType::kDevelopment ); } // Paths::getHierarchyType -MYXLIB_INLINE bool Paths::init( const QString& projectDir, const QString& configFileExtension ) +MYXLIB_INLINE bool Paths::initCommon() { - m_projectName = projectDir.isEmpty() ? m_currentExecutable.m_canonicalFilePath.fileName() - : projectDir; - m_configFileExtension = configFileExtension.isEmpty() ? QStringLiteral( "conf" ) - : configFileExtension; - m_configFileName = m_projectName + "." + m_configFileExtension; - m_homeDirectory = QDir::homePath(); m_tempDirectory = QDir::tempPath(); auto configHome = QString::fromLocal8Bit( qgetenv( "XDG_CONFIG_HOME" ) ); if ( configHome.isEmpty() ) { - configHome = m_homeDirectory.canonicalPath() + "/.config"; + configHome = m_homeDirectory + "/.config"; } m_userConfigDirectory = configHome + "/" + m_projectName; auto dataHome = QString::fromLocal8Bit( qgetenv( "XDG_DATA_HOME" ) ); if ( dataHome.isEmpty() ) { - dataHome = m_homeDirectory.canonicalPath() + "/.local/share"; + dataHome = m_homeDirectory + "/.local/share"; } dataHome += "/" + m_projectName; m_userConstDataDirectory = dataHome + "/data"; @@ -200,28 +203,53 @@ MYXLIB_INLINE bool Paths::init( const QString& projectDir, const QString& config m_hierarchyType = getHierarchyType(); - if ( m_hierarchyType == HierarchyType::kFlat ) - { - m_systemConstDataDirectory = m_currentExecutable.m_canonicalFilePath.canonicalPath(); - m_systemVarDataDirectory = m_currentExecutable.m_canonicalFilePath.canonicalPath(); - m_systemConfigDirectory = m_currentExecutable.m_canonicalFilePath.canonicalPath(); - m_systemLogDirectory = m_currentExecutable.m_canonicalFilePath.canonicalPath(); - } - - m_configFilePath = m_systemConfigDirectory.canonicalPath() + "/" + m_configFileName; + m_configFilePath = m_systemConfigDirectory + "/" + m_configFileName; return( true ); } // Paths::updatePaths +MYXLIB_INLINE bool Paths::init() +{ + m_projectName = m_executableName; + m_configFileName = m_executableName + ".conf"; + return( initCommon() ); +} + + +MYXLIB_INLINE bool Paths::init( const QString& configFileName ) +{ + m_projectName = m_executableName; + m_configFileName = configFileName; + return( initCommon() ); +} + + +MYXLIB_INLINE bool Paths::init( const QString& projectName, const QString& configFileExtension ) +{ + m_projectName = projectName.isEmpty() ? m_executableName + : projectName; + auto ext = configFileExtension.isEmpty() ? QStringLiteral( "conf" ) + : configFileExtension; + m_configFileName = m_projectName + "." + ext; + return( initCommon() ); +} + + MYXLIB_INLINE bool Paths::makeDefaultDirectories() { bool status = true; + QDir dir; + + if ( dir.mkpath( m_userConfigDirectory ) ) { status = false; } + if ( dir.mkpath( m_userVarDataDirectory ) ) { status = false; } + if ( dir.mkpath( m_userConstDataDirectory ) ) { status = false; } + if ( dir.mkpath( m_userLogDirectory ) ) { status = false; } + if ( dir.mkpath( m_systemConfigDirectory ) ) { status = false; } + if ( dir.mkpath( m_systemVarDataDirectory ) ) { status = false; } + if ( dir.mkpath( m_systemConstDataDirectory ) ) { status = false; } + if ( dir.mkpath( m_systemLogDirectory ) ) { status = false; } - if ( !m_userConfigDirectory.mkpath( m_userConfigDirectory.absolutePath() ) ) { status = false; } - if ( !m_userVarDataDirectory.mkpath( m_userVarDataDirectory.absolutePath() ) ) { status = false; } - if ( !m_userConstDataDirectory.mkpath( m_userConstDataDirectory.absolutePath() ) ) { status = false; } - if ( !m_userLogDirectory.mkpath( m_userLogDirectory.absolutePath() ) ) { status = false; } return( status ); } @@ -244,32 +272,26 @@ MYXLIB_INLINE QString Paths::findConfigFile( const QString& defaultConfigFile ) if ( QFileInfo( m_configFilePath ).isReadable() ) { - return( m_configFilePath.absoluteFilePath() ); + return( m_configFilePath ); } return( QString() ); } // Paths::findConfigFile -MYXLIB_INLINE QDir Paths::executableFileDirectory() const -{ - return( m_currentExecutable.m_canonicalFilePath.dir() ); -} - - -MYXLIB_INLINE const QDir& Paths::userConfigDirectory() const +MYXLIB_INLINE const QString& Paths::userConfigDirectory() const { return( m_userConfigDirectory ); } -MYXLIB_INLINE const QDir& Paths::systemConfigDirectory() const +MYXLIB_INLINE const QString& Paths::systemConfigDirectory() const { return( m_systemConfigDirectory ); } -MYXLIB_INLINE const QFileInfo& Paths::configFilePath() const +MYXLIB_INLINE const QString& Paths::configFilePath() const { return( m_configFilePath ); } @@ -281,55 +303,49 @@ MYXLIB_INLINE const QString& Paths::configFileName() const } -MYXLIB_INLINE const QString& Paths::configFileExtension() const -{ - return( m_configFileExtension ); -} - - -MYXLIB_INLINE const QDir& Paths::userVarDataDirectory() const +MYXLIB_INLINE const QString& Paths::userVarDataDirectory() const { return( m_userVarDataDirectory ); } -MYXLIB_INLINE const QDir& Paths::systemVarDataDirectory() const +MYXLIB_INLINE const QString& Paths::systemVarDataDirectory() const { return( m_systemVarDataDirectory ); } -MYXLIB_INLINE const QDir& Paths::userConstDataDirectory() const +MYXLIB_INLINE const QString& Paths::userConstDataDirectory() const { return( m_userConstDataDirectory ); } -MYXLIB_INLINE const QDir& Paths::systemConstDataDirectory() const +MYXLIB_INLINE const QString& Paths::systemConstDataDirectory() const { return( m_systemConstDataDirectory ); } -MYXLIB_INLINE const QDir& Paths::userLogDirectory() const +MYXLIB_INLINE const QString& Paths::userLogDirectory() const { return( m_userLogDirectory ); } -MYXLIB_INLINE const QDir& Paths::systemLogDirectory() const +MYXLIB_INLINE const QString& Paths::systemLogDirectory() const { return( m_systemLogDirectory ); } -MYXLIB_INLINE const QDir& Paths::tempDirectory() const +MYXLIB_INLINE const QString& Paths::tempDirectory() const { return( m_tempDirectory ); } -MYXLIB_INLINE const QDir& Paths::homeDirectory() const +MYXLIB_INLINE const QString& Paths::homeDirectory() const { return( m_homeDirectory ); } @@ -341,19 +357,31 @@ MYXLIB_INLINE const QString& Paths::projectName() const } -MYXLIB_INLINE QString Paths::executableFileName() const +MYXLIB_INLINE const QString& Paths::executableName() const { - return( m_currentExecutable.m_canonicalFilePath.fileName() ); + return( m_executableName ); } -MYXLIB_INLINE const QFileInfo& Paths::executableFilePath() const +MYXLIB_INLINE const QString& Paths::executableFilePath() const { - return( m_currentExecutable.m_canonicalFilePath ); + return( m_executableFilePath ); +} + + +MYXLIB_INLINE const QString& Paths::executableDirectory() const +{ + return( m_executableDirectory ); +} + + +MYXLIB_INLINE const QString& Paths::prefixDirectory() const +{ + return( m_prefixDirectory ); } } // namespace filesystem } // namespace myx -#endif // MYX_BASE_PATHS_CPP_ +#endif // MYX_CORE_PATHS_CPP_ diff --git a/src/myx/filesystem/paths.hpp b/src/myx/filesystem/paths.hpp index 6cb93be..9baf284 100644 --- a/src/myx/filesystem/paths.hpp +++ b/src/myx/filesystem/paths.hpp @@ -8,8 +8,7 @@ #pragma once -#include -#include +#include #include #include @@ -34,62 +33,17 @@ class Paths /// @brief Исполняемый файл и сопутствующие каталоги находятся в иерахии /opt kOpt = 0x02, /// @brief Исполняемый файл и сопутствующие каталоги находятся в иерахии /usr - kUsr = 0x04, + kUsr = 0x03, /// @brief Исполняемый файл и сопутствующие каталоги находятся в иерахии /usr/local - kUsrLocal = 0x08, + kUsrLocal = 0x04, + /// @brief Исполняемый файл и сопутствующие каталоги находятся в иерахии /usr/local/rtis (используется для работ в проекте Сирена) + kUsrLocalRtis = 0x05, /// @brief Исполняемый файл и сопутствующие каталоги находятся в иерахии /home - kHome = 0x10, + kHome = 0x06, /// @brief Исполняемый файл и сопутствующие каталоги находятся в каталоге программного проекта - kDevelopment = 0x20 + kDevelopment = 0x07 }; - /// @brief Тип расположения файлов по каталогам - HierarchyType m_hierarchyType { HierarchyType::kFlat }; - - /// @brief Параметры текущего исполняемого файла - CurrentExecutable m_currentExecutable; - - /// @brief Имя проекта, которое используется при формировании имён файлов и каталогов - QString m_projectName; - - /// @brief Путь к каталогу с временными файлами - QDir m_tempDirectory; - /// @brief Путь к домашнему каталогу текущего пользователя - QDir m_homeDirectory; - - /// @brief Путь к пользовательскому каталогу с изменяемыми файлами - QDir m_userVarDataDirectory; - /// @brief Путь к системному каталогу с изменяемыми файлами - QDir m_systemVarDataDirectory; - - /// @brief Путь к пользовательскому каталогу с неизменяемыми файлами - QDir m_userConstDataDirectory; - /// @brief Путь к системному каталогу с неизменяемыми файлами - QDir m_systemConstDataDirectory; - - /// @brief Путь к пользовательскому каталогу с журналами работы - QDir m_userLogDirectory; - /// @brief Путь к системному каталогу с журналами работы - QDir m_systemLogDirectory; - - /// @brief Путь к пользовательскому каталогу с файлами настройки - QDir m_userConfigDirectory; - /// @brief Путь к системному каталогу с файлами настройки - QDir m_systemConfigDirectory; - - /// @brief Полный путь к файлу настройки - QFileInfo m_configFilePath; - /// @brief Имя файла настройки - QString m_configFileName; - /// @brief Расширение для файла настройки - QString m_configFileExtension; - - HierarchyType getHierarchyType(); - -protected: - Paths(); - ~Paths() = default; - public: Paths( const Paths& ) = delete; Paths& operator=( const Paths& ) = delete; @@ -102,15 +56,28 @@ public: */ static Paths& instance() { - static Paths p; - return( p ); + static Paths sPaths; + return( sPaths ); } /** * @brief Обновление путей с учётом расположения исполняемого файла */ - bool init( const QString& projectDir, const QString& configFileExtension = QStringLiteral("conf") ); + bool init(); + + /** + * @brief Обновление путей с учётом расположения исполняемого файла + * @param configFileName Имя файла настроек + */ + bool init( const QString& configFileName ); + + /** + * @brief Обновление путей с учётом расположения исполняемого файла + * @param projectName Имя проекта + * @param configFileExtension Расширение для файла настроек + */ + bool init( const QString& projectName, const QString& configFileExtension ); /** * @brief Создание стандартных каталогов @@ -130,27 +97,22 @@ public: /** * @brief Полный путь к базовому каталогу */ - const QDir& prefixDirectory() const; + const QString& prefixDirectory() const; + + /** + * @brief Имя исполняемого файла + */ + const QString& executableName() const; + + /** + * @brief Полный путь к исполняемому файлу + */ + const QString& executableFilePath() const; /** * @brief Полный путь к каталогу с исполняемым файлом */ - QDir executableFileDirectory() const; - - /** - * @brief Полный путь к пользовательскому каталогу с файлами настройки - */ - const QDir& userConfigDirectory() const; - - /** - * @brief Полный путь к системному каталогу с файлами настройки - */ - const QDir& systemConfigDirectory() const; - - /** - * @brief Полный путь к файлу настройки - */ - const QFileInfo& configFilePath() const; + const QString& executableDirectory() const; /** * @brief Имя файла настройки @@ -162,68 +124,125 @@ public: */ const QString& configFileExtension() const; + /** + * @brief Полный путь к файлу настройки + */ + const QString& configFilePath() const; + + /** + * @brief Полный путь к пользовательскому каталогу с файлами настройки + */ + const QString& userConfigDirectory() const; + + /** + * @brief Полный путь к системному каталогу с файлами настройки + */ + const QString& systemConfigDirectory() const; + /** * @brief Полный путь к пользовательскому каталогу с изменяемыми файлами */ - const QDir& userVarDataDirectory() const; + const QString& userVarDataDirectory() const; /** * @brief Полный путь к системному каталогу с изменяемыми файлами */ - const QDir& systemVarDataDirectory() const; + const QString& systemVarDataDirectory() const; /** * @brief Полный путь к пользовательскому каталогу с неизменяемыми файлами */ - const QDir& userConstDataDirectory() const; + const QString& userConstDataDirectory() const; /** * @brief Полный путь к системному каталогу с неизменяемыми файлами */ - const QDir& systemConstDataDirectory() const; + const QString& systemConstDataDirectory() const; /** * @brief Полный путь к пользовательскому каталогу с журналами работы */ - const QDir& userLogDirectory() const; + const QString& userLogDirectory() const; /** * @brief Полный путь к системному каталогу с журналами работы */ - const QDir& systemLogDirectory() const; + const QString& systemLogDirectory() const; /** * @brief Полный путь к каталогу с временными файлами */ - const QDir& tempDirectory() const; + const QString& tempDirectory() const; /** * @brief Полный путь к домашнему каталогу текущего пользователя */ - const QDir& homeDirectory() const; + const QString& homeDirectory() const; /** * @brief Имя подкаталога для проекта */ const QString& projectName() const; - /** - * @brief Имя исполняемого файла - */ - QString executableFileName() const; +protected: + Paths(); + ~Paths() = default; - /** - * @brief Полный путь к исполняемому файлу - */ - const QFileInfo& executableFilePath() const; +private: + /// @brief Тип расположения файлов по каталогам + HierarchyType m_hierarchyType { HierarchyType::kFlat }; + + /// @brief Имя проекта, которое используется при формировании имён файлов и каталогов + QString m_projectName; + + QString m_executableName; + QString m_executableFilePath; + QString m_executableDirectory; + + /// @brief Общий префикс для файлов проекта + QString m_prefixDirectory; + + /// @brief Путь к каталогу с временными файлами + QString m_tempDirectory; + /// @brief Путь к домашнему каталогу текущего пользователя + QString m_homeDirectory; + + /// @brief Путь к пользовательскому каталогу с изменяемыми файлами + QString m_userVarDataDirectory; + /// @brief Путь к системному каталогу с изменяемыми файлами + QString m_systemVarDataDirectory; + + /// @brief Путь к пользовательскому каталогу с неизменяемыми файлами + QString m_userConstDataDirectory; + /// @brief Путь к системному каталогу с неизменяемыми файлами + QString m_systemConstDataDirectory; + + /// @brief Путь к пользовательскому каталогу с журналами работы + QString m_userLogDirectory; + /// @brief Путь к системному каталогу с журналами работы + QString m_systemLogDirectory; + + /// @brief Путь к пользовательскому каталогу с файлами настройки + QString m_userConfigDirectory; + /// @brief Путь к системному каталогу с файлами настройки + QString m_systemConfigDirectory; + + /// @brief Полный путь к файлу настройки + QString m_configFilePath; + /// @brief Имя файла настройки + QString m_configFileName; + + void setupSystemDirectories( const QString& defaultPrefixDirectory, + const QString& defaultEtcDirectory, + const QString& defaultConstDataDirectory, + const QString& defaultVarDataDirectory, + const QString& defaultLogDirectory ); + bool initCommon(); + HierarchyType getHierarchyType(); }; // class Paths } // namespace filesystem } // namespace myx -#ifdef MYXLIB_HEADER_ONLY -#include "paths.cpp" -#endif - #endif // MYX_FILESYSTEM_PATHS_HPP_ diff --git a/src/myx/filesystem/paths_mt.cpp b/src/myx/filesystem/paths_mt.cpp deleted file mode 100644 index b0c5e86..0000000 --- a/src/myx/filesystem/paths_mt.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef MYX_BASE_PATHS_MT_CPP_ -#define MYX_BASE_PATHS_MT_CPP_ - -#ifndef MYXLIB_HEADER_ONLY -#include -#else -#pragma once -#endif - -#include -#include - -#include - -#include -#include - -namespace myx { - -namespace filesystem { - -MYXLIB_INLINE PathsMT::PathsMT() = default; - -MYXLIB_INLINE PathsMT& PathsMT::instance() -{ - volatile PathsMT* localInstance = mInstance.load( std::memory_order_acquire ); - if ( localInstance == nullptr ) - { - std::lock_guard< std::mutex > myLock( mMutex ); - localInstance = mInstance.load( std::memory_order_relaxed ); - if ( localInstance == nullptr ) // -V1036 - { - localInstance = new PathsMT(); - mInstance.store( const_cast< PathsMT* >( localInstance ), std::memory_order_release ); // NOLINT - } - } - return( const_cast< PathsMT& >( *localInstance ) ); // NOLINT -} - -} // namespace filesystem - -} // namespace myx - -#endif // MYX_BASE_PATHS_MT_CPP_ diff --git a/src/myx/filesystem/paths_mt.hpp b/src/myx/filesystem/paths_mt.hpp deleted file mode 100644 index 3a5b7fd..0000000 --- a/src/myx/filesystem/paths_mt.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/** - * @file paths.hpp - * @brief Стандартные пути к каталогам и файлам - */ - -#ifndef MYX_FILESYSTEM_PATHS_MT_HPP_ -#define MYX_FILESYSTEM_PATHS_MT_HPP_ - -#pragma once - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -namespace myx { - -namespace filesystem { - -/// @brief Потокобезопасная версия класса myx::filesystem::Paths -class PathsMT : public Paths -{ - PathsMT(); - ~PathsMT() = default; - - static std::atomic< PathsMT* > mInstance; - static std::mutex mMutex; - - -public: - PathsMT( const PathsMT& ) = delete; - PathsMT& operator=( const PathsMT& ) = delete; - PathsMT( PathsMT&& ) = delete; - PathsMT& operator=( PathsMT&& ) = delete; - - /** - * @brief getInstance - * @return Уникальный экземпляр класса PathsMT - */ - static PathsMT& instance(); -}; // class PathsMT - -} // namespace filesystem - -} // namespace myx - -#ifdef MYXLIB_HEADER_ONLY -#include "paths_mt.cpp" -#endif - -#endif // MYX_FILESYSTEM_PATHS_MT_HPP_ diff --git a/src/myx/qt/CMakeLists.txt b/src/myx/qt/CMakeLists.txt index e501637..117a821 100644 --- a/src/myx/qt/CMakeLists.txt +++ b/src/myx/qt/CMakeLists.txt @@ -4,55 +4,59 @@ set(TRGT qt) # cmake-format: off # Список файлов исходных текстов set(TRGT_cpp - ${CMAKE_CURRENT_SOURCE_DIR}/translators.cpp) + ${CMAKE_CURRENT_SOURCE_DIR}/posix_signal_watcher.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/translators.cpp + ) + +set(TRGT_moc_hpp + ${CMAKE_CURRENT_SOURCE_DIR}/posix_signal_watcher.hpp + ) + +set(TRGT_moc_private_hpp + ${CMAKE_CURRENT_SOURCE_DIR}/posix_signal_watcher_p.hpp + ) -# Список заголовочных файлов (используется для установки) set(TRGT_hpp - ${CMAKE_CURRENT_SOURCE_DIR}/backports.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/translators.hpp) + ${CMAKE_CURRENT_SOURCE_DIR}/translators.hpp + ) -set(TRGT_headers ${TRGT_hpp}) +set(TRGT_headers ${TRGT_moc_hpp} ${TRGT_hpp}) # cmake-format: on -add_library(${TRGT}-header-only INTERFACE) -target_include_directories( - ${TRGT}-header-only SYSTEM INTERFACE "$" - "$") +qt5_wrap_cpp(TRGT_moc_cpp ${TRGT_moc_private_hpp} ${TRGT_moc_hpp}) -if(MYXLIB_BUILD_LIBRARIES) - add_common_library(${TRGT} OUTPUT_NAME myx-${TRGT} SOURCES ${TRGT_cpp} ${TRGT_headers}) - common_target_properties(${TRGT}) +add_common_library(${TRGT} OUTPUT_NAME myx-${TRGT} SOURCES ${TRGT_cpp} ${TRGT_moc_cpp} + ${TRGT_moc_private_hpp} ${TRGT_headers}) +common_target_properties(${TRGT}) - # Создание цели для проверки утилитой clang-tidy - add_clang_tidy_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) +# Создание цели для проверки утилитой clang-tidy +add_clang_tidy_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) - # Создание цели для проверки утилитой clang-analyze - add_clang_analyze_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) +# Создание цели для проверки утилитой clang-analyze +add_clang_analyze_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) - # Создание цели для проверки утилитой clazy - add_clazy_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) +# Создание цели для проверки утилитой clazy +add_clazy_check(${TRGT} ${TRGT_cpp} ${TRGT_headers}) - # Создание цели для проверки утилитой pvs-studio - add_pvs_check(${TRGT}) +# Создание цели для проверки утилитой pvs-studio +add_pvs_check(${TRGT}) - # Создание цели для автоматического форматирования кода - add_format_sources(${TRGT} ${TRGT_cpp} ${TRGT_headers}) +# Создание цели для автоматического форматирования кода +add_format_sources(${TRGT} ${TRGT_cpp} ${TRGT_headers} ${TRGT_moc_private_hpp}) - target_compile_definitions(${TRGT} PUBLIC MYXLIB_BUILD_LIBRARIES) - target_include_directories(${TRGT} SYSTEM PUBLIC ${Qt5Core_INCLUDE_DIRS}) - target_include_directories(${TRGT} SYSTEM PRIVATE ${CMAKE_SOURCE_DIR}/src) - cotire(${TRGT}) +target_include_directories(${TRGT} SYSTEM PUBLIC ${Qt5Core_INCLUDE_DIRS}) +target_include_directories(${TRGT} SYSTEM PRIVATE ${CMAKE_SOURCE_DIR}/src) +target_include_directories(${TRGT} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +cotire(${TRGT}) - install(TARGETS ${TRGT}_static COMPONENT libs-dev ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - if(BUILD_SHARED_LIBS) - install(TARGETS ${TRGT}_shared COMPONENT main LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) - endif() -else() - install(FILES ${TRGT_cpp} COMPONENT base-dev DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/${TRGT}) +install(TARGETS ${TRGT}_static COMPONENT libs-dev ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +if(BUILD_SHARED_LIBS) + install(TARGETS ${TRGT}_shared COMPONENT main LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif() generate_pkgconfig(myx-${TRGT} COMPONENT base-dev INSTALL_LIBRARY ${MYXLIB_BUILD_LIBRARIES}) -install(FILES ${TRGT_headers} COMPONENT base-dev DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/${TRGT}) +install(FILES ${TRGT_headers} COMPONENT base-dev + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/${TRGT}) # Цель, используемая только для установки заголовочных файлов без компиляции проекта add_custom_target(${TRGT}-install-headers COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=base-dev -P diff --git a/src/myx/qt/posix_signal_watcher.cpp b/src/myx/qt/posix_signal_watcher.cpp new file mode 100644 index 0000000..4d5cc7d --- /dev/null +++ b/src/myx/qt/posix_signal_watcher.cpp @@ -0,0 +1,131 @@ +#ifndef MYX_QT_POSIX_SIGNAL_WATCHER_CPP_ +#define MYX_QT_POSIX_SIGNAL_WATCHER_CPP_ + +#include +#include + +#include +#include + +namespace myx { + +namespace qt { + +std::array< int, 2 > PosixSignalWatcherPrivate::mSockpair { { 0, 0 } }; + +PosixSignalWatcherPrivate::~PosixSignalWatcherPrivate() = default; + +PosixSignalWatcherPrivate::PosixSignalWatcherPrivate( PosixSignalWatcher* q ) : + q_ptr( q ) +{ + #if MYX_QT_HAS_POSIX_SIGNALS + // Create socket pair + if ( ::socketpair( AF_UNIX, SOCK_STREAM, 0, mSockpair.data() ) != 0 ) + { + qDebug() << "PosixSignalWatcher: socketpair: " << ::strerror( errno ); + return; + } + #endif + + // Create a notifier for the read end of the pair + // m_notifier.reset( new QSocketNotifier( mSockpair[1], QSocketNotifier::Read ) ); + m_notifier = std::make_unique< QSocketNotifier >( mSockpair[1], QSocketNotifier::Read ); + + // Called when the signal handler has written to the socket pair. + // Emits the Posix signal as a Qt signal. + connect( m_notifier.get(), &QSocketNotifier::activated, q, [this]( int sockfd ) { + Q_Q( PosixSignalWatcher ); + + int signal = 0; + Q_UNUSED( !::read( sockfd, &signal, sizeof( signal ) ) ); + qDebug() << "Caught signal: " << ::strsignal( signal ); + Q_EMIT q->posixSignal( signal ); + } ); + + + m_notifier->setEnabled( true ); +} + + +/*! + * Registers a handler for the given Posix \a signal. The handler will write to + * a socket pair, the other end of which is connected to a QSocketNotifier. + * This provides a way to break out of the asynchronous context from which the + * signal handler is called and back into the Qt event loop. + */ +MYXLIB_INLINE void PosixSignalWatcherPrivate::watchForSignal( int signal ) +{ + if ( m_watchedSignals.contains( signal ) ) + { + qDebug() << "Already watching for signal " << signal; + return; + } + + #if MYX_QT_HAS_POSIX_SIGNALS + // Register a sigaction which will write to the socket pair + struct sigaction sigact; //NOLINT + sigact.sa_handler = PosixSignalWatcherPrivate::signalHandler; //NOLINT + sigact.sa_flags = 0; + sigemptyset( &sigact.sa_mask ); + sigact.sa_flags |= SA_RESTART; + sigact.sa_restorer = nullptr; + if ( ::sigaction( signal, &sigact, nullptr ) != 0 ) + { + qDebug() << "PosixSignalWatcher: sigaction: " << ::strerror( errno ); + return; + } + #endif + + m_watchedSignals.append( signal ); +} // PosixSignalWatcherPrivate::watchForSignal + + +/*! + * Called when a Posix \a signal is received. Write to the socket to wake up the + * QSocketNotifier. + */ +MYXLIB_INLINE void PosixSignalWatcherPrivate::signalHandler( int signal ) +{ + Q_UNUSED( !::write( mSockpair[0], &signal, sizeof( signal ) ) ); +} + + +/*! + * Create a new PosixSignalWatcher as a child of the given \a parent. + */ +MYXLIB_INLINE PosixSignalWatcher::PosixSignalWatcher( QObject* parent ) : + QObject( parent ), + d_ptr ( new PosixSignalWatcherPrivate( this ) ) +{ +} + + +/*! + * Register a signal handler for the given \a signal. + * + * After calling this method you can \c connect() to the POSIXSignal() Qt signal + * to be notified when the Posix signal is received. + */ +MYXLIB_INLINE void PosixSignalWatcher::watchForSignal( int signal ) +{ + Q_D( PosixSignalWatcher ); + d->watchForSignal( signal ); +} + + +/*! + * \fn void PosixSignalWatcher::posixSignal(int signal) + * Emitted when the given Posix \a signal is received. + * + * watchForSignal() must be called for each Posix signal that you want to receive + * via the POSIXSignal() Qt signal. If a watcher is watching multiple signals, + * POSIXSignal() will be emitted whenever *any* of the watched Posix signals are + * received, and the \a signal argument can be inspected to find out which one + * was actually received. + */ + +} // namespace qt + +} // namespace myx + +#endif // ifndef MYX_QT_POSIX_SIGNAL_WATCHER_CPP_ diff --git a/src/myx/qt/posix_signal_watcher.hpp b/src/myx/qt/posix_signal_watcher.hpp new file mode 100644 index 0000000..7b465fc --- /dev/null +++ b/src/myx/qt/posix_signal_watcher.hpp @@ -0,0 +1,49 @@ +#ifndef MYX_QT_POSIX_SIGNAL_WATCHER_HPP_ +#define MYX_QT_POSIX_SIGNAL_WATCHER_HPP_ + +#pragma once + +#include + +#include + +#include + +namespace myx { + +namespace qt { + +class PosixSignalWatcherPrivate; + +#if defined( Q_OS_WIN ) +const int SIGINT = 2; +const int SIGTERM = 15; +#endif + + +/*! + * \brief The PosixSignalWatcher class converts Posix signals to Qt signals. + * + * To watch for a given signal, e.g. \c SIGINT, call \c watchForSignal(SIGINT) + * and \c connect() your handler to posixSignal(). + */ +class PosixSignalWatcher : public QObject +{ + Q_OBJECT + +public: + explicit PosixSignalWatcher( QObject* parent = nullptr ); + + void watchForSignal( int signal ); + Q_SIGNAL void posixSignal( int signal ); + +private: + PosixSignalWatcherPrivate* const d_ptr = nullptr; + Q_DECLARE_PRIVATE( PosixSignalWatcher ) //NOLINT +}; // class PosixSignalWatcher + +} // namespace qt + +} // namespace myx + +#endif // ifndef MYX_QT_POSIX_SIGNAL_WATCHER_HPP_ diff --git a/src/myx/qt/posix_signal_watcher_p.hpp b/src/myx/qt/posix_signal_watcher_p.hpp new file mode 100644 index 0000000..d31b36c --- /dev/null +++ b/src/myx/qt/posix_signal_watcher_p.hpp @@ -0,0 +1,64 @@ +#ifndef MYX_QT_POSIX_SIGNAL_WATCHER_P_HPP_ +#define MYX_QT_POSIX_SIGNAL_WATCHER_P_HPP_ + +#pragma once + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#ifdef Q_OS_WIN +#define MYX_QT_HAS_POSIX_SIGNALS 0 +#else +#define MYX_QT_HAS_POSIX_SIGNALS 1 +#endif + +#if MYX_QT_HAS_POSIX_SIGNALS +#include +#include +#include +#include +#endif + +namespace myx { + +namespace qt { + +/*! + * \brief The PosixSignalWatcherPrivate class implements the back-end signal + * handling for the PosixSignalWatcher. + * + * \see http://qt-project.org/doc/qt-5.0/qtdoc/POSIX-signals.html + */ +class PosixSignalWatcherPrivate : public QObject +{ + Q_OBJECT + +public: + PosixSignalWatcherPrivate( PosixSignalWatcher* q ); + ~PosixSignalWatcherPrivate(); + + void watchForSignal( int signal ); + static void signalHandler( int signal ); + +private: + Q_DECLARE_PUBLIC( PosixSignalWatcher ) + + PosixSignalWatcher* const q_ptr = nullptr; + static std::array< int, 2 > mSockpair; + std::unique_ptr< QSocketNotifier > m_notifier; + QList< int > m_watchedSignals; +}; // class PosixSignalWatcherPrivate + +} // namespace qt + +} // namespace myx + +#endif // ifndef MYX_QT_POSIX_SIGNAL_WATCHER_P_HPP_ diff --git a/src/myx/qt/translators.cpp b/src/myx/qt/translators.cpp index 67e97ef..1fd5beb 100644 --- a/src/myx/qt/translators.cpp +++ b/src/myx/qt/translators.cpp @@ -1,13 +1,10 @@ #ifndef MYX_QT_TRANSLATORS_CPP_ #define MYX_QT_TRANSLATORS_CPP_ -#include +#include +#include -#ifndef MYXLIB_HEADER_ONLY #include -#else -#pragma once -#endif #include #include diff --git a/src/myx/qt/translators.hpp b/src/myx/qt/translators.hpp index a1515c5..46aa162 100644 --- a/src/myx/qt/translators.hpp +++ b/src/myx/qt/translators.hpp @@ -3,8 +3,8 @@ #pragma once -#include -#include +#include +#include #include @@ -20,8 +20,4 @@ void append_translators( QTranslatorsList& translators, const QString& appName ) } // namespace myx -#ifdef MYXLIB_HEADER_ONLY -#include "translators.cpp" -#endif - #endif // ifndef MYX_QT_TRANSLATORS_HPP_