Compare commits

...

39 Commits

Author SHA1 Message Date
Martchus 0c652a774e Fix definition of GOROOT in presets
It needs to be an env variable; not a CMake variable.
2024-05-01 23:20:19 +02:00
Martchus 9c687bd723 Fix include directories of test targets after a7fdc1af1
The include directories need to be set for test targets as well; otherwise
they cannot compile unless tests link against the main target as well.
2024-04-26 22:55:58 +02:00
Martchus 65ffed8151 Remove reference to non-existent script 2024-04-13 17:06:41 +02:00
Martchus 957c044e63 Enable targets for mingw-w64 cross-packaging in mingw-w64 CMake presets 2024-04-13 17:02:54 +02:00
Martchus a4c18017b7 Avoid duplications in mingw-w64 CMake presets 2024-04-13 17:00:04 +02:00
Martchus 73a837962d Adapt the `arch-…-w64-mingw32-static` presets
Not sure what has changed but it seems that these extra variables are now
required to avoid linking against certain shared libraries.
2024-04-12 00:43:41 +02:00
Martchus 8502d1bc2a Add `arch-…-w64-mingw32…-devel-qt6` presets 2024-04-11 23:35:33 +02:00
Martchus afc3413e9c Add `arch-i686-w64-mingw32…`-presets 2024-04-11 23:28:19 +02:00
Martchus ae908283a0 Bump patch version 2024-04-08 12:34:27 +02:00
Martchus d31092b7d9 Apply clang-format 2024-04-08 12:33:57 +02:00
Martchus dfbf300c65 Expose name of default desktop file via config header 2024-04-08 12:33:40 +02:00
Martchus 909346c199 Fix reserving size for error message in `charToDigit()` 2024-02-27 02:16:52 +01:00
Martchus c9cd44ceee Apply clang-format 2024-02-22 19:41:29 +01:00
Martchus a43affa81a Avoid `global.h` changing depending on target prefix/suffix
Just using the project name should be sufficient and this avoid `global.h`
from changing when a different target prefix/suffix is used.
2024-02-22 19:41:15 +01:00
Martchus d8e144d312 Optimize `numberToString()`
This function is slower than it needs to be due to the expensive inserts at
the front of the string. The new version is 38 times faster for a 9-digit
number using GCC 13.2 with full optimizations according to Quick Bench.
2024-02-21 21:21:11 +01:00
Martchus a337452179 Fix typo in README 2024-02-16 17:42:15 +01:00
Martchus 6cb0e63921 Avoid warnings about unused return values by MSVC 2024-02-15 18:40:44 +01:00
Martchus a4625b8e34 Bump patch version 2024-02-15 18:40:11 +01:00
Martchus a4be8a56d1 Avoid problems with CppUnit's macros when doing unity builds 2024-02-04 20:56:27 +01:00
Martchus ce31de2c6f Fix tests when making a unity build
The formatting for chrono types needs to be included before CppUnit
headers. This change makes sure of that by simply including that header via
`tests/testutils.h`. The `chrono/format.h` header is not big (including the
header it includes) so this should not be a big deal.
2024-01-30 23:08:14 +01:00
Martchus bc00bdcdc9 Apply cmake-format 2024-01-30 22:38:52 +01:00
Martchus 57579f0164 Add preset for unity builds
This is not working for most of my projects due to conflicting macros.
2024-01-30 22:38:39 +01:00
Martchus a7fdc1af1b Allow writing public compile definitions to a header file
This is useful as it makes consuming libraries less dependent on using the
CMake module or pkg-config file correctly. This should especially decrease
the likelihood of running into linker errors when consuming a static build
of the libraries where e.g. `CPP_UTILITIES_STATIC` needs to be defined.
2024-01-30 22:13:25 +01:00
Martchus 27043d2be0 Fix typo in comment 2024-01-30 00:44:54 +01:00
Martchus b526d79eaf Always use a process group in helper for involing test applications
So far only the implementation using Boost.Process was using a process
group; with this change also the implementation using POSIX APIs uses a
process group. This way the code can wait until all sub processes have
terminated.
2024-01-28 21:55:13 +01:00
Martchus 995c315377 Allow semicolons in categories and additional entries for desktop file
Pass these variables as multi-value arguments to get more than just the
part before the first semicolon.
2024-01-27 02:54:27 +01:00
Martchus d08794b11d Allow setting `DESKTOP_FILE_ADDITIONAL_ENTRIES` manually 2024-01-27 02:51:41 +01:00
Martchus 1a0c4fbce0 Update copyright date 2024-01-23 00:25:55 +01:00
Martchus c25a3c9c9a Improve error handling when launching test process
* Use `EXIT_FAILURE` instead of an arbitrary exit status
* Print the error message
2024-01-20 17:38:14 +01:00
Martchus c9dea06cfe Remove outdated remarks about `execApp()` and similar test helpers
These functions are supported also on other platforms via Boost.Process.
2024-01-20 17:35:17 +01:00
Martchus ad686a1be7 Bump patch version 2024-01-20 17:33:47 +01:00
Martchus 85c76708c9 Mention setting GOROOT for building with MSYS2 mingw-w64 packaging 2024-01-02 15:32:14 +01:00
Martchus c17c8e7815 Set `GOROOT` for `x64-windows-static` preset in accordance with `GO_BIN`
Unfortunately the final linking still doesn't work due to conflicting
symbols (and using the ucrt64 version doesn't change that).
2023-12-30 19:34:22 +01:00
Martchus f97320816a Change Bash completion code for dirs/files to new coding style 2023-12-29 16:34:26 +01:00
Martchus 6f924da4f0 Make code for processing escaping in Bash completion more generic 2023-12-29 16:30:55 +01:00
Martchus b3b7166812 Fix bash completion when path contains round brackets 2023-12-29 16:09:55 +01:00
Martchus 8bffc93316 Improve instructions about building on Windows 2023-12-25 00:56:50 +01:00
Martchus 456bbfc54e Avoid hardcoding the versioned subdirectory within `WIN_KITS_ROOT` 2023-12-25 00:56:50 +01:00
Martchus b0be8817ad Bump patch version 2023-12-25 00:56:50 +01:00
18 changed files with 283 additions and 103 deletions

View File

@ -96,10 +96,6 @@ set(CMAKE_TEMPLATE_FILES
cmake/templates/global.h.in
cmake/templates/version.h.in
cmake/templates/template.pc.in)
set(SCRIPT_FILES)
if (MINGW)
list(APPEND SCRIPT_FILES scripts/wine.sh)
endif ()
if (WIN32)
list(APPEND CMAKE_TEMPLATE_FILES cmake/templates/windows.rc.in cmake/templates/windows-cli-wrapper.rc.in
cmake/templates/cli-wrapper.cpp)
@ -121,7 +117,7 @@ set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}")
set(META_APP_DESCRIPTION "Useful C++ classes and routines such as argument parser, IO and conversion utilities")
set(META_VERSION_MAJOR 5)
set(META_VERSION_MINOR 24)
set(META_VERSION_PATCH 4)
set(META_VERSION_PATCH 8)
# find required 3rd party libraries
include(3rdParty)

View File

@ -106,6 +106,16 @@
"NO_FILE_ITEM_ACTION_PLUGIN": {"type": "BOOL", "value": "ON"}
}
},
{
"name": "devel-unity",
"inherits": ["devel-qt6"],
"displayName": "Development config creating a unity build using Qt 6",
"description": "Same as devel-qt6 but configures makes a unity build",
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/devel-unity",
"cacheVariables": {
"CMAKE_UNITY_BUILD": {"type": "BOOL", "value": "ON"}
}
},
{
"name": "devel-libc++-qt6",
"inherits": ["qt6", "devel-libc++"],
@ -153,8 +163,41 @@
}
},
{
"name": "arch-x86_64-w64-mingw32",
"name": "arch-*-w64-mingw32",
"inherits": ["no-webview", "no-kde"],
"environment": {
"CPPFLAGS": "-D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS",
"CFLAGS": "$env{CPPFLAGS} -O2 -pipe -fno-plt -fexceptions --param=ssp-buffer-size=4 -Wformat -Werror=format-security -fcf-protection",
"CXXFLAGS": "$env{CPPFLAGS} -O2 -pipe -fno-plt -fexceptions --param=ssp-buffer-size=4 -Wformat -Werror=format-security -fcf-protection",
"LDFLAGS": "-Wl,-O1,--sort-common,--as-needed -fstack-protector"
},
"cacheVariables": {
"BUILD_SHARED_LIBS": {"type": "BOOL", "value": "ON"},
"VERSIONED_MINGW_LIBRARIES": {"type": "BOOL", "value": "ON"},
"ENABLE_TARGETS_FOR_MINGW_CROSS_PACKAGING": {"type": "BOOL", "value": "ON"}
}
},
{
"name": "arch-i686-w64-mingw32",
"inherits": "arch-*-w64-mingw32",
"displayName": "Target i686-w64-mingw32 using Arch Linux's mingw-w64 packaging",
"description": "Build targeting i686-w64-mingw32, paths and flags are specific to Arch Linux's mingw-w64 packaging",
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-i686-w64-mingw32",
"toolchainFile": "/usr/share/mingw/toolchain-i686-w64-mingw32.cmake",
"environment": {
"CROSS_TOOL_PREFIX": "i686-w64-mingw32-",
"CROSS_INSTALL_PREFIX": "/usr/i686-w64-mingw32",
"PATH": "$env{CROSS_INSTALL_PREFIX}/bin:$penv{PATH}"
},
"cacheVariables": {
"CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES": {"type": "PATH", "value": "$env{CROSS_INSTALL_PREFIX}/include"},
"CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES": {"type": "PATH", "value": "$env{CROSS_INSTALL_PREFIX}/include"},
"CMAKE_CROSSCOMPILING_EMULATOR": {"type": "PATH", "value": "/usr/bin/i686-w64-mingw32-wine"}
}
},
{
"name": "arch-x86_64-w64-mingw32",
"inherits": "arch-*-w64-mingw32",
"displayName": "Target x86_64-w64-mingw32 using Arch Linux's mingw-w64 packaging",
"description": "Build targeting x86_64-w64-mingw32, paths and flags are specific to Arch Linux's mingw-w64 packaging",
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-x86_64-w64-mingw32",
@ -163,19 +206,28 @@
"CROSS_TOOL_PREFIX": "x86_64-w64-mingw32-",
"CROSS_INSTALL_PREFIX": "/usr/x86_64-w64-mingw32",
"CPPFLAGS": "-D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS",
"CFLAGS": "$env{CPPFLAGS} -O2 -pipe -fno-plt -fexceptions --param=ssp-buffer-size=4 -Wformat -Werror=format-security -fcf-protection",
"CXXFLAGS": "$env{CPPFLAGS} -O2 -pipe -fno-plt -fexceptions --param=ssp-buffer-size=4 -Wformat -Werror=format-security -fcf-protection",
"LDFLAGS": "-Wl,-O1,--sort-common,--as-needed -fstack-protector",
"PATH": "$env{CROSS_INSTALL_PREFIX}/bin:$penv{PATH}"
},
"cacheVariables": {
"BUILD_SHARED_LIBS": {"type": "BOOL", "value": "ON"},
"VERSIONED_MINGW_LIBRARIES": {"type": "BOOL", "value": "ON"},
"CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES": {"type": "PATH", "value": "$env{CROSS_INSTALL_PREFIX}/include"},
"CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES": {"type": "PATH", "value": "$env{CROSS_INSTALL_PREFIX}/include"},
"CMAKE_CROSSCOMPILING_EMULATOR": {"type": "PATH", "value": "/usr/bin/x86_64-w64-mingw32-wine"}
}
},
{
"name": "arch-i686-w64-mingw32-static",
"inherits": "arch-i686-w64-mingw32",
"displayName": "Target i686-w64-mingw32 using Arch Linux's mingw-w64 packaging (static)",
"description": "Build targeting i686-w64-mingw32, paths and flags are specific to Arch Linux's mingw-w64 packaging",
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-i686-w64-mingw32-static",
"toolchainFile": "/usr/share/mingw/toolchain-i686-w64-mingw32-static.cmake",
"cacheVariables": {
"BUILD_SHARED_LIBS": {"type": "BOOL", "value": "OFF"},
"CMAKE_FIND_LIBRARY_SUFFIXES": {"type": "STRING", "value": ".a;.lib"},
"STATIC_LIBRARY_LINKAGE": {"type": "BOOL", "value": "ON"},
"STATIC_LINKAGE": {"type": "BOOL", "value": "ON"}
}
},
{
"name": "arch-x86_64-w64-mingw32-static",
"inherits": "arch-x86_64-w64-mingw32",
@ -184,9 +236,19 @@
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-x86_64-w64-mingw32-static",
"toolchainFile": "/usr/share/mingw/toolchain-x86_64-w64-mingw32-static.cmake",
"cacheVariables": {
"BUILD_SHARED_LIBS": {"type": "BOOL", "value": "OFF"}
"BUILD_SHARED_LIBS": {"type": "BOOL", "value": "OFF"},
"CMAKE_FIND_LIBRARY_SUFFIXES": {"type": "STRING", "value": ".a;.lib"},
"STATIC_LIBRARY_LINKAGE": {"type": "BOOL", "value": "ON"},
"STATIC_LINKAGE": {"type": "BOOL", "value": "ON"}
}
},
{
"name": "arch-i686-w64-mingw32-qt6",
"inherits": ["qt6", "arch-i686-w64-mingw32"],
"displayName": "Combination of qt6 and arch-i686-w64-mingw32",
"description": "See description of qt6 and arch-i686-w64-mingw32",
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-i686-w64-mingw32-qt6"
},
{
"name": "arch-x86_64-w64-mingw32-qt6",
"inherits": ["qt6", "arch-x86_64-w64-mingw32"],
@ -194,6 +256,13 @@
"description": "See description of qt6 and arch-x86_64-w64-mingw32",
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-x86_64-w64-mingw32-qt6"
},
{
"name": "arch-i686-w64-mingw32-static-qt6",
"inherits": ["qt6", "arch-i686-w64-mingw32-static"],
"displayName": "Combination of qt6 and arch-i686-w64-mingw32-static",
"description": "See description of qt6 and arch-i686-w64-mingw32-static",
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-i686-w64-mingw32-static-qt6"
},
{
"name": "arch-x86_64-w64-mingw32-static-qt6",
"inherits": ["qt6", "arch-x86_64-w64-mingw32-static"],
@ -201,6 +270,13 @@
"description": "See description of qt6 and arch-x86_64-w64-mingw32-static",
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-x86_64-w64-mingw32-static-qt6"
},
{
"name": "arch-i686-w64-mingw32-devel",
"inherits": ["devel", "arch-i686-w64-mingw32"],
"displayName": "Combination of devel and arch-i686-w64-mingw32",
"description": "See descriptions of devel and arch-i686-w64-mingw32",
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-i686-w64-mingw32-devel"
},
{
"name": "arch-x86_64-w64-mingw32-devel",
"inherits": ["devel", "arch-x86_64-w64-mingw32"],
@ -208,6 +284,34 @@
"description": "See descriptions of devel and arch-x86_64-w64-mingw32",
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-x86_64-w64-mingw32-devel"
},
{
"name": "arch-i686-w64-mingw32-devel-qt6",
"inherits": ["qt6", "devel", "arch-i686-w64-mingw32"],
"displayName": "Combination of qt6, devel and arch-i686-w64-mingw32",
"description": "See descriptions of devel and arch-i686-w64-mingw32",
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-i686-w64-mingw32-devel"
},
{
"name": "arch-x86_64-w64-mingw32-devel-qt6",
"inherits": ["qt6", "devel", "arch-x86_64-w64-mingw32"],
"displayName": "Combination of qt6, devel and arch-x86_64-w64-mingw32",
"description": "See descriptions of devel and arch-x86_64-w64-mingw32",
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-x86_64-w64-mingw32-devel"
},
{
"name": "arch-i686-w64-mingw32-static-devel-qt6",
"inherits": ["qt6", "devel", "arch-i686-w64-mingw32-static"],
"displayName": "Combination of qt6, devel and arch-i686-w64-mingw32-static",
"description": "See descriptions of devel and arch-i686-w64-mingw32-static",
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-i686-w64-mingw32-devel"
},
{
"name": "arch-x86_64-w64-mingw32-static-devel-qt6",
"inherits": ["qt6", "devel", "arch-x86_64-w64-mingw32-static"],
"displayName": "Combination of qt6, devel and arch-x86_64-w64-mingw32-static",
"description": "See descriptions of devel and arch-x86_64-w64-mingw32-static",
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-x86_64-w64-mingw32-devel"
},
{
"name": "arch-static-compat",
"inherits": ["no-webview", "no-kde", "qt6"],
@ -256,9 +360,10 @@
"description": "Build on Windows targeting x64-windows-static using MSVC, Qt 6 (for Qt libs and CMake/Ninja), vcpkg (for other dependencies) and MSYS2 (for Perl, Go, ffmpeg and other tools)",
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/win-x64-msvc-static",
"environment": {
"INCLUDE": "$env{MSVC_ROOT}/include;$env{MSVC_ROOT}/ATLMFC/include;$env{WIN_KITS_ROOT}/include/10.0.22000.0/ucrt;$env{WIN_KITS_ROOT}//include/10.0.22000.0//um;$env{WIN_KITS_ROOT}//include/10.0.22000.0//shared;$env{WIN_KITS_ROOT}/include/10.0.22000.0//winrt;$env{WIN_KITS_ROOT}/include/10.0.22000.0//cppwinrt",
"LIB": "$env{MSVC_ROOT}/ATLMFC/lib/x64;$env{MSVC_ROOT}/lib/x64;$env{WIN_KITS_ROOT}/lib/10.0.22000.0/ucrt/x64;$env{WIN_KITS_ROOT}/lib/10.0.22000.0//um/x64",
"LIBPATH": "$env{MSVC_ROOT}/ATLMFC/lib/x64;$env{MSVC_ROOT}/lib/x64;$env{WIN_KITS_ROOT}/lib/10.0.22000.0/ucrt/x64;$env{WIN_KITS_ROOT}/lib/10.0.22000.0/um/x64"
"INCLUDE": "$env{MSVC_ROOT}/include;$env{MSVC_ROOT}/ATLMFC/include;$env{WIN_KITS_ROOT}/include/$env{WIN_KITS_VERSION}/ucrt;$env{WIN_KITS_ROOT}//include/$env{WIN_KITS_VERSION}//um;$env{WIN_KITS_ROOT}//include/$env{WIN_KITS_VERSION}//shared;$env{WIN_KITS_ROOT}/include/$env{WIN_KITS_VERSION}//winrt;$env{WIN_KITS_ROOT}/include/$env{WIN_KITS_VERSION}//cppwinrt",
"LIB": "$env{MSVC_ROOT}/ATLMFC/lib/x64;$env{MSVC_ROOT}/lib/x64;$env{WIN_KITS_ROOT}/lib/$env{WIN_KITS_VERSION}/ucrt/x64;$env{WIN_KITS_ROOT}/lib/$env{WIN_KITS_VERSION}//um/x64",
"LIBPATH": "$env{MSVC_ROOT}/ATLMFC/lib/x64;$env{MSVC_ROOT}/lib/x64;$env{WIN_KITS_ROOT}/lib/$env{WIN_KITS_VERSION}/ucrt/x64;$env{WIN_KITS_ROOT}/lib/$env{WIN_KITS_VERSION}/um/x64",
"GOROOT": "$env{MSYS2_ROOT}/mingw64/lib/go"
},
"cacheVariables": {
"BUILD_SHARED_LIBS": {"type": "BOOL", "value": "OFF"},
@ -270,9 +375,9 @@
"CMAKE_AR_COMPILER": {"type": "FILEPATH", "value": "$env{MSVC_ROOT}/bin/Hostx64/x64/lib.exe"},
"CMAKE_C_COMPILER": {"type": "FILEPATH", "value": "$env{MSVC_ROOT}/bin/HostX64/x64/cl.exe"},
"CMAKE_CXX_COMPILER": {"type": "FILEPATH", "value": "$env{MSVC_ROOT}/bin/HostX64/x64/cl.exe"},
"CMAKE_RC_COMPILER": {"type": "FILEPATH", "value": "$env{WIN_KITS_ROOT}/bin/10.0.22000.0/x64/rc.exe"},
"CMAKE_RC_COMPILER": {"type": "FILEPATH", "value": "$env{WIN_KITS_ROOT}/bin/$env{WIN_KITS_VERSION}/x64/rc.exe"},
"CMAKE_LINKER": {"type": "FILEPATH", "value": "$env{MSVC_ROOT}/bin/Hostx64/x64/link.exe"},
"CMAKE_MT": {"type": "FILEPATH", "value": "$env{WIN_KITS_ROOT}/bin/10.0.22000.0/x64/mt.exe"},
"CMAKE_MT": {"type": "FILEPATH", "value": "$env{WIN_KITS_ROOT}/bin/$env{WIN_KITS_VERSION}/x64/mt.exe"},
"CMAKE_MSVC_RUNTIME_LIBRARY": {"type": "STRING", "value": "MultiThreaded$<$<CONFIG:Debug>:Debug>"},
"CMAKE_CXX_FLAGS_DEBUG": {"type": "STRING", "value": "/MTd /Zi /Ob0 /Od /RTC1"},
"CMAKE_CXX_FLAGS_RELEASE": {"type": "STRING", "value": "/MT /O2 /Ob2 /DNDEBUG"},
@ -324,16 +429,26 @@
{"name": "devel", "configurePreset": "devel"},
{"name": "devel-libc++", "configurePreset": "devel-libc++"},
{"name": "devel-qt6", "configurePreset": "devel-qt6"},
{"name": "devel-unity", "configurePreset": "devel-unity"},
{"name": "devel-libc++-qt6", "configurePreset": "devel-libc++-qt6"},
{"name": "debug", "configurePreset": "debug"},
{"name": "debug-qt6", "configurePreset": "debug-qt6"},
{"name": "debug-kde", "configurePreset": "debug-kde"},
{"name": "debug-kde-custom", "configurePreset": "debug-kde-custom"},
{"name": "arch-i686-w64-mingw32", "configurePreset": "arch-i686-w64-mingw32"},
{"name": "arch-x86_64-w64-mingw32", "configurePreset": "arch-x86_64-w64-mingw32"},
{"name": "arch-i686-w64-mingw32-static", "configurePreset": "arch-i686-w64-mingw32-static"},
{"name": "arch-x86_64-w64-mingw32-static", "configurePreset": "arch-x86_64-w64-mingw32-static"},
{"name": "arch-i686-w64-mingw32-qt6", "configurePreset": "arch-i686-w64-mingw32-qt6"},
{"name": "arch-x86_64-w64-mingw32-qt6", "configurePreset": "arch-x86_64-w64-mingw32-qt6"},
{"name": "arch-i686-w64-mingw32-static-qt6", "configurePreset": "arch-i686-w64-mingw32-static-qt6"},
{"name": "arch-x86_64-w64-mingw32-static-qt6", "configurePreset": "arch-x86_64-w64-mingw32-static-qt6"},
{"name": "arch-i686-w64-mingw32-devel", "configurePreset": "arch-i686-w64-mingw32-devel"},
{"name": "arch-x86_64-w64-mingw32-devel", "configurePreset": "arch-x86_64-w64-mingw32-devel"},
{"name": "arch-i686-w64-mingw32-devel-qt6", "configurePreset": "arch-i686-w64-mingw32-devel-qt6"},
{"name": "arch-x86_64-w64-mingw32-devel-qt6", "configurePreset": "arch-x86_64-w64-mingw32-devel-qt6"},
{"name": "arch-i686-w64-mingw32-static-devel-qt6", "configurePreset": "arch-i686-w64-mingw32-static-devel-qt6"},
{"name": "arch-x86_64-w64-mingw32-static-devel-qt6", "configurePreset": "arch-x86_64-w64-mingw32-static-devel-qt6"},
{"name": "arch-static-compat", "configurePreset": "arch-static-compat"},
{"name": "arch-static-compat-devel", "configurePreset": "arch-static-compat-devel"},
{"name": "win-x64-msvc-static", "configurePreset": "win-x64-msvc-static"},

View File

@ -125,7 +125,7 @@ building on Windows.
`BUILTIN_ICON_THEMES=breeze;breeze-dark`.
* This variable must be set when building the application (not when building any of the libraries).
* The specified icon themes need to be installed in the usual location. Otherwise, use e.g.
`DBUILTIN_ICON_THEMES_SEARCH_PATH=D:/programming/misc/breeze-icons/usr/share/icons` to specify the
`BUILTIN_ICON_THEMES_SEARCH_PATH=D:/programming/misc/breeze-icons/usr/share/icons` to specify the
search path.
* For more detailed documentation, see the documentation about build variables (in
[directory doc](https://github.com/Martchus/cpp-utilities/blob/master/doc/buildvariables.md) and
@ -238,18 +238,20 @@ cmake --build "$BUILD_DIR/tagparser/devel-qt6" --target install -- -v
```
Note that:
* not all those dependencies are required by all my projects and some are just optional.
* Not all those dependencies are required by all my projects and some are just optional.
* The second example to just build `c++utilities` and `tagparser` already shows a stripped-down list
of dependencies.
* Especially `mingw-w64-x86_64-go` is only required when building Syncthing Tray with built-in
Syncthing-library enabled.
Syncthing-library enabled. To build in an MSYS2 shell one needs to invoke `export GOROOT=/mingw64/lib/go`
so Go can find its root.
* All Qt-related dependencies are generally only required for building with Qt GUI, e.g. Tag Editor
and Password Manager can be built without Qt GUI. The libraries `c++utilities` and `tagparser` don't
require Qt at all.
* you can also easily install Qt Creator via MSYS2 using `pacman -S mingw-w64-x86_64-qt-creator`.
* you must *not* use the presets containing `mingw-w64` in their name as those are only intended for cross-compilation
* You can also easily install Qt Creator via MSYS2 using `pacman -S mingw-w64-x86_64-qt-creator`.
* You must *not* use the presets containing `mingw-w64` in their name as those are only intended for cross-compilation
on Arch Linux.
###### Building with MSVC
To build with MSVC you can use the `win-x64-msvc-static` preset. This preset (and all presets inheriting from it) need
various additional environment variables to be set and you need to install dependencies from various sources:
* `MSYS2_ROOT`: for Perl (only used by `qtforkawesome` so far), `clang-format`, Doxygen, FFmpeg and Go (only
@ -261,6 +263,7 @@ various additional environment variables to be set and you need to install depen
`C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.34.31933`
* `WIN_KITS_ROOT`: for Windows platform headers/libraries usually installed as part of Visual Studio setup,
e.g. `C:/Program Files (x86)/Windows Kits/10`
* `WIN_KITS_VERSION`: the relevant subdirectory within `WIN_KITS_ROOT`, usually a version number like `10.0.22621.0`
* `QT_ROOT`: for Qt libraries provided by the official Qt installer, e.g. `D:/programming/qt/6.5.0/msvc2019_64`
* `QT_TOOLS`: for additional build tools provided by the official Qt installer, e.g. `D:/programming/qt/Tools`
* `VCPKG_ROOT`: directory of VCPKG checkout used for other dependencies; install the following packages:
@ -269,7 +272,22 @@ various additional environment variables to be set and you need to install depen
```
When building with MSVC, do *not* use any of the MSYS2 shells. The environment of those shells leads to
build problems.
build problems. You can however use CMake and Ninja from MSYS2's mingw-w64 packaging (instead of the CMake
version from Qt's installer). Then you need to specify the Ninja executable manually so the CMake invocation
would become something like this:
```
`& "$Env:MSYS2_ROOT\mingw64\bin\cmake.exe" --preset win-x64-msvc-static -DCMAKE_MAKE_PROGRAM="$Env:MSYS2_ROOT\mingw64\bin\ninja.exe" .
```
To run the resulting binaries, you'll need to make sure the Qt libraries are in the search path, e.g. using
`$Env:PATH = "$Env:QT_ROOT\bin"`.
Note that you don't need to install all Visual Studio has to offer. A customized installation with just
C++ core features, MSVC x86/x64 build tools, Windows SDK and vpkg should be enough. In Qt's online installer
you can also uncheck everything except the MSVC build of Qt itself.
If the compilation of the resource file doesn't work you can use `-DWINDOWS_RC_FILE=OFF` to continue the
build regardless.
##### Remarks about special presets
The presets starting with `arch-` are for use under Arch Linux. Do *not* use them unless you know what you
@ -303,6 +321,6 @@ Checkout [Case_Of's overlay](https://codeberg.org/Case_Of/gentoo-overlay)
or [perfect7gentleman's overlay](https://gitlab.com/Perfect_Gentleman/PG_Overlay).
## Copyright notice and license
Copyright © 2015-2023 Marius Kittler
Copyright © 2015-2024 Marius Kittler
All code is licensed under [GPL-2-or-later](LICENSE).

View File

@ -1323,6 +1323,25 @@ string ArgumentParser::findSuggestions(int argc, const char *const *argv, unsign
return suggestionStr;
}
/*!
* \brief Returns a copy of \a escaped with escaping characters removed.
*/
static std::string unescape(std::string_view escaped)
{
auto unescaped = std::string();
auto onEscaping = false;
unescaped.reserve(escaped.size());
for (const auto c : escaped) {
if (!onEscaping && c == '\\') {
onEscaping = true;
} else {
unescaped += c;
onEscaping = false;
}
}
return unescaped;
}
/*!
* \brief Prints the bash completion for the specified arguments and the specified \a lastPath.
* \remarks Arguments must have been parsed before with readSpecifiedArgs(). When calling this method, completionMode must
@ -1508,23 +1527,13 @@ void ArgumentParser::printBashCompletion(int argc, const char *const *argv, unsi
}
// -> completions for files and dirs
// -> if there's already an "opening", determine the dir part and the file part
string actualDir, actualFile;
bool haveFileOrDirCompletions = false;
auto actualDir = std::string(), actualFile = std::string();
auto haveFileOrDirCompletions = false;
if (argc && currentWordIndex == completionInfo.lastSpecifiedArgIndex && opening) {
// the "opening" might contain escaped characters which need to be unescaped first (let's hope this covers all possible escapings)
string unescapedOpening(opening);
findAndReplace<string>(unescapedOpening, "\\ ", " ");
findAndReplace<string>(unescapedOpening, "\\,", ",");
findAndReplace<string>(unescapedOpening, "\\[", "[");
findAndReplace<string>(unescapedOpening, "\\]", "]");
findAndReplace<string>(unescapedOpening, "\\!", "!");
findAndReplace<string>(unescapedOpening, "\\#", "#");
findAndReplace<string>(unescapedOpening, "\\$", "$");
findAndReplace<string>(unescapedOpening, "\\'", "'");
findAndReplace<string>(unescapedOpening, "\\\"", "\"");
findAndReplace<string>(unescapedOpening, "\\\\", "\\");
// the "opening" might contain escaped characters which need to be unescaped first
const auto unescapedOpening = unescape(opening);
// determine the "directory" part
string dir = directory(unescapedOpening);
auto dir = directory(unescapedOpening);
if (dir.empty()) {
actualDir = ".";
} else {
@ -1537,7 +1546,7 @@ void ArgumentParser::printBashCompletion(int argc, const char *const *argv, unsi
actualDir = std::move(dir);
}
// determine the "file" part
string file = fileName(unescapedOpening);
auto file = fileName(unescapedOpening);
if (file[0] == '\"' || file[0] == '\'') {
file.erase(0, 1);
}
@ -1790,7 +1799,7 @@ void ValueConversion::Helper::ArgumentValueConversionError::throwFailure(const s
throw ParseError(argumentPath.empty()
? argsToString("Conversion of top-level value \"", valueToConvert, "\" to type \"", targetTypeName, "\" failed: ", errorMessage)
: argsToString("Conversion of value \"", valueToConvert, "\" (for argument --", argumentPath.back()->name(), ") to type \"",
targetTypeName, "\" failed: ", errorMessage));
targetTypeName, "\" failed: ", errorMessage));
}
/*!
@ -1801,7 +1810,7 @@ void ArgumentOccurrence::throwNumberOfValuesNotSufficient(unsigned long valuesTo
throw ParseError(path.empty()
? argsToString("Expected ", valuesToConvert, " top-level values to be present but only ", values.size(), " have been specified.")
: argsToString("Expected ", valuesToConvert, " values for argument --", path.back()->name(), " to be present but only ", values.size(),
" have been specified."));
" have been specified."));
}
} // namespace CppUtilities

View File

@ -881,7 +881,7 @@ inline void Argument::setFlags(Argument::Flags flags, bool add)
{
m_flags = add ? (m_flags | flags)
: static_cast<Argument::Flags>(static_cast<std::underlying_type<Argument::Flags>::type>(m_flags)
& ~static_cast<std::underlying_type<Argument::Flags>::type>(flags));
& ~static_cast<std::underlying_type<Argument::Flags>::type>(flags));
}
/*!

View File

@ -14,7 +14,7 @@ namespace CppUtilities {
*/
FakeQtConfigArguments::FakeQtConfigArguments()
: m_qtWidgetsGuiArg(
"qt-widgets-gui", 'g', "shows a Qt widgets based graphical user interface (the application has not been built with Qt widgets support)")
"qt-widgets-gui", 'g', "shows a Qt widgets based graphical user interface (the application has not been built with Qt widgets support)")
, m_qtQuickGuiArg(
"qt-quick-gui", 'q', "shows a Qt quick based graphical user interface (the application has not been built with Qt quick support)")
{

View File

@ -21,16 +21,9 @@ function (add_custom_desktop_file)
endif ()
# parse arguments
set(ONE_VALUE_ARGS
FILE_NAME
DESKTOP_FILE_APP_NAME
DESKTOP_FILE_GENERIC_NAME
DESKTOP_FILE_DESCRIPTION
DESKTOP_FILE_CATEGORIES
DESKTOP_FILE_CMD
DESKTOP_FILE_ICON
DESKTOP_FILE_ADDITIONAL_ENTRIES)
set(MULTI_VALUE_ARGS)
set(ONE_VALUE_ARGS FILE_NAME DESKTOP_FILE_APP_NAME DESKTOP_FILE_GENERIC_NAME DESKTOP_FILE_DESCRIPTION DESKTOP_FILE_CMD
DESKTOP_FILE_ICON)
set(MULTI_VALUE_ARGS DESKTOP_FILE_CATEGORIES DESKTOP_FILE_ADDITIONAL_ENTRIES)
set(OPTIONAL_ARGS)
cmake_parse_arguments(ARGS "${OPTIONAL_ARGS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGN})
if (NOT ARGS_FILE_NAME
@ -105,7 +98,6 @@ function (add_desktop_file)
endif ()
# compose actions
set(DESKTOP_FILE_ADDITIONAL_ENTRIES "")
foreach (ACTION_VAR ${META_APP_ACTIONS})
list(GET META_APP_ACTION_${ACTION_VAR} 0 ACTION_ID)
list(GET META_APP_ACTION_${ACTION_VAR} 1 ACTION_NAME)

View File

@ -613,7 +613,7 @@ if (NOT META_NO_INSTALL_TARGETS AND ENABLE_INSTALL_TARGETS)
endif ()
# determine library directory suffix - Applications might be built as libraries under some platforms (eg. Android). Hence
# this is part of BasicConfig and not LibraryConfig.
# this is part of BasicConfig and not LibraryTarget.
set(LIB_SUFFIX
""
CACHE STRING "specifies the general suffix for the library directory")

View File

@ -53,7 +53,7 @@ endif ()
# add global library-specific header
find_template_file("global.h" CPP_UTILITIES GLOBAL_H_TEMPLATE_FILE)
if ("${META_PROJECT_NAME}" STREQUAL "c++utilities")
set(GENERAL_GLOBAL_H_INCLUDE_PATH "\"./application/global.h\"")
set(GENERAL_GLOBAL_H_INCLUDE_PATH "\"application/global.h\"")
else ()
set(GENERAL_GLOBAL_H_INCLUDE_PATH "<c++utilities/application/global.h>")
endif ()
@ -121,14 +121,37 @@ endif ()
# add custom libraries
append_user_defined_additional_libraries()
# allow writing public compile definitions to a header file instead of just relying on CMake/pkg-config
option(USE_HEADER_FOR_PUBLIC_COMPILE_DEFINITIONS "writes public compile definitions to a header file" ON)
set(DEFS_FOR_HEADER "")
if (USE_HEADER_FOR_PUBLIC_COMPILE_DEFINITIONS)
foreach (DEF ${META_PUBLIC_COMPILE_DEFINITIONS})
if (DEF MATCHES "([A-Za-z0-9_]+)=([A-Za-z0-9_ ]+)")
set(DEF_NAME "${CMAKE_MATCH_1}")
set(DEF_VALUE " ${CMAKE_MATCH_2}")
elseif (DEF MATCHES "([A-Za-z0-9_]+)")
set(DEF_NAME "${CMAKE_MATCH_1}")
set(DEF_VALUE "")
endif ()
if (DEF_NAME)
set(DEFS_FOR_HEADER "${DEFS_FOR_HEADER}#ifndef ${DEF_NAME}\n#define ${DEF_NAME}${DEF_VALUE}\n#endif\n")
endif ()
endforeach ()
endif ()
set(TARGET_GENERATED_INCLUDE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include")
set(TARGET_DEFINITIONS_HEADER "${TARGET_GENERATED_INCLUDE_DIRECTORY}/${META_PROJECT_NAME}-definitions.h")
file(WRITE "${TARGET_DEFINITIONS_HEADER}" "${DEFS_FOR_HEADER}")
# add library to be created, set libs to link against, set version and C++ standard
if (META_HEADER_ONLY_LIB)
add_library(${META_TARGET_NAME} INTERFACE)
target_link_libraries(${META_TARGET_NAME} INTERFACE ${META_ADDITIONAL_LINK_FLAGS} "${PUBLIC_LIBRARIES}"
"${PRIVATE_LIBRARIES}")
target_include_directories(
${META_TARGET_NAME} INTERFACE $<BUILD_INTERFACE:${TARGET_INCLUDE_DIRECTORY_BUILD_INTERFACE}>
$<INSTALL_INTERFACE:${HEADER_INSTALL_DESTINATION}> ${PUBLIC_INCLUDE_DIRS})
${META_TARGET_NAME}
INTERFACE $<BUILD_INTERFACE:${TARGET_INCLUDE_DIRECTORY_BUILD_INTERFACE}>
$<BUILD_INTERFACE:${TARGET_GENERATED_INCLUDE_DIRECTORY}>
$<INSTALL_INTERFACE:${HEADER_INSTALL_DESTINATION}> ${PUBLIC_INCLUDE_DIRS})
target_compile_definitions(${META_TARGET_NAME} INTERFACE "${META_PUBLIC_COMPILE_DEFINITIONS}"
"${META_PRIVATE_COMPILE_DEFINITIONS}")
target_compile_options(${META_TARGET_NAME} INTERFACE "${META_PUBLIC_COMPILE_OPTIONS}" "${META_PRIVATE_COMPILE_OPTIONS}")
@ -139,12 +162,14 @@ else ()
PUBLIC ${META_ADDITIONAL_LINK_FLAGS} "${PUBLIC_LIBRARIES}"
PRIVATE "${PRIVATE_LIBRARIES}")
if (META_IS_PLUGIN)
target_include_directories(${META_TARGET_NAME} PRIVATE $<BUILD_INTERFACE:${TARGET_INCLUDE_DIRECTORY_BUILD_INTERFACE}>
"${PRIVATE_INCLUDE_DIRS}")
target_include_directories(
${META_TARGET_NAME} PRIVATE $<BUILD_INTERFACE:${TARGET_INCLUDE_DIRECTORY_BUILD_INTERFACE}>
$<BUILD_INTERFACE:${TARGET_GENERATED_INCLUDE_DIRECTORY}> "${PRIVATE_INCLUDE_DIRS}")
else ()
target_include_directories(
${META_TARGET_NAME}
PUBLIC $<BUILD_INTERFACE:${TARGET_INCLUDE_DIRECTORY_BUILD_INTERFACE}>
$<BUILD_INTERFACE:${TARGET_GENERATED_INCLUDE_DIRECTORY}>
$<INSTALL_INTERFACE:${HEADER_INSTALL_DESTINATION}> ${PUBLIC_INCLUDE_DIRS}
PRIVATE "${PRIVATE_INCLUDE_DIRS}")
endif ()
@ -195,8 +220,10 @@ else ()
if (NOT META_PLUGIN_CATEGORY)
add_library(${META_TARGET_NAME}-headers INTERFACE)
target_include_directories(
${META_TARGET_NAME}-headers INTERFACE $<BUILD_INTERFACE:${TARGET_INCLUDE_DIRECTORY_BUILD_INTERFACE}>
$<INSTALL_INTERFACE:${HEADER_INSTALL_DESTINATION}> ${PUBLIC_INCLUDE_DIRS})
${META_TARGET_NAME}-headers
INTERFACE $<BUILD_INTERFACE:${TARGET_INCLUDE_DIRECTORY_BUILD_INTERFACE}>
$<BUILD_INTERFACE:${TARGET_GENERATED_INCLUDE_DIRECTORY}>
$<INSTALL_INTERFACE:${HEADER_INSTALL_DESTINATION}> ${PUBLIC_INCLUDE_DIRS})
target_compile_definitions(${META_TARGET_NAME}-headers INTERFACE "${META_PUBLIC_COMPILE_DEFINITIONS}"
"${META_PRIVATE_COMPILE_DEFINITIONS}")
target_compile_options(${META_TARGET_NAME}-headers INTERFACE "${META_PUBLIC_COMPILE_OPTIONS}"
@ -557,6 +584,10 @@ if (NOT META_NO_INSTALL_TARGETS AND ENABLE_INSTALL_TARGETS)
FILES "${VERSION_HEADER_FILE}"
DESTINATION "${INCLUDE_SUBDIR}/${META_PROJECT_NAME}"
COMPONENT header)
install(
FILES "${TARGET_DEFINITIONS_HEADER}"
DESTINATION "${INCLUDE_SUBDIR}/${META_PROJECT_NAME}"
COMPONENT header)
if (NOT TARGET install-header)
add_custom_target(install-header COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=header -P
"${CMAKE_BINARY_DIR}/cmake_install.cmake")

View File

@ -52,9 +52,10 @@ function (configure_test_target)
PRIVATE "${ARGS_LIBRARIES}" "${PRIVATE_LIBRARIES}")
target_include_directories(
"${TEST_TARGET_NAME}"
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> $<INSTALL_INTERFACE:${HEADER_INSTALL_DESTINATION}>
PUBLIC $<BUILD_INTERFACE:${TARGET_INCLUDE_DIRECTORY_BUILD_INTERFACE}>
$<BUILD_INTERFACE:${TARGET_GENERATED_INCLUDE_DIRECTORY}> $<INSTALL_INTERFACE:${HEADER_INSTALL_DESTINATION}>
${PUBLIC_INCLUDE_DIRS}
PRIVATE ${TEST_INCLUDE_DIRS} "${PRIVATE_INCLUDE_DIRS}")
PRIVATE ${TEST_INCLUDE_DIRS} ${PRIVATE_INCLUDE_DIRS})
target_compile_definitions(
"${TEST_TARGET_NAME}"
PUBLIC "${META_PUBLIC_COMPILE_DEFINITIONS}"

View File

@ -13,6 +13,7 @@
#define PROJECT_CONFIG_SUFFIX "@META_CONFIG_SUFFIX@"
#define PROJECT_CONFIG_TARGET_SUFFIX "@TARGET_SUFFIX@"
#define APP_NAME "@META_APP_NAME@"
#define APP_ID "@META_ID@"
#define APP_VERSION "@META_APP_VERSION@"
#define APP_VERSION_MAJOR @META_VERSION_MAJOR@
#define APP_VERSION_MINOR @META_VERSION_MINOR@

View File

@ -4,6 +4,7 @@
#ifndef @META_PROJECT_VARNAME_UPPER@_GLOBAL
#define @META_PROJECT_VARNAME_UPPER@_GLOBAL
#include "@META_PROJECT_NAME@-definitions.h"
#include @GENERAL_GLOBAL_H_INCLUDE_PATH@
#ifdef @META_PROJECT_VARNAME_UPPER@_STATIC

View File

@ -16,16 +16,16 @@ template <class StringType, class ViewType> using IsStringViewType = std::is_sam
template <class StringType, class CharType> using IsCharType = std::is_same<typename StringType::value_type, CharType>;
namespace Detail {
template <typename StringType, typename T>
auto IsStringType(int)
-> decltype(std::declval<StringType &>().append(std::declval<const T &>()), std::declval<const T &>().size(), Traits::Bool<true>{});
auto IsStringType(
int) -> decltype(std::declval<StringType &>().append(std::declval<const T &>()), std::declval<const T &>().size(), Traits::Bool<true>{});
template <typename StringType, typename T> Traits::Bool<false> IsStringType(...);
template <typename StringType> void functionTakingConstStringRef(const StringType &str);
template <typename StringType, typename T>
auto IsConvertibleToConstStringRef(int) -> decltype(functionTakingConstStringRef<StringType>(std::declval<const T &>()), Traits::Bool<true>{});
template <typename StringType, typename T> Traits::Bool<false> IsConvertibleToConstStringRef(...);
template <typename StringType, typename T>
auto IsConvertibleToConstStringRefViaNative(int)
-> decltype(functionTakingConstStringRef<StringType>(std::declval<const T &>().native()), Traits::Bool<true>{});
auto IsConvertibleToConstStringRefViaNative(
int) -> decltype(functionTakingConstStringRef<StringType>(std::declval<const T &>().native()), Traits::Bool<true>{});
template <typename StringType, typename T> Traits::Bool<false> IsConvertibleToConstStringRefViaNative(...);
} // namespace Detail
template <typename StringType, typename StringType2>

View File

@ -421,13 +421,16 @@ template <typename IntegralType, class StringType = std::string, typename BaseTy
CppUtilities::Traits::EnableIf<std::is_integral<IntegralType>, std::is_unsigned<IntegralType>> * = nullptr>
StringType numberToString(IntegralType number, BaseType base = 10)
{
std::size_t resSize = 0;
for (auto n = number; n; n /= static_cast<IntegralType>(base), ++resSize)
;
StringType res;
res.reserve(resSize);
auto resSize = std::size_t();
auto n = number;
do {
res.insert(res.begin(), digitToChar<typename StringType::value_type>(static_cast<typename StringType::value_type>(number % base)));
n /= static_cast<IntegralType>(base), ++resSize;
} while (n);
auto res = StringType(resSize, typename StringType::value_type());
auto resIter = res.end();
do {
*(--resIter)
= digitToChar<typename StringType::value_type>(static_cast<typename StringType::value_type>(number % static_cast<IntegralType>(base)));
number /= static_cast<IntegralType>(base);
} while (number);
return res;
@ -443,24 +446,24 @@ template <typename IntegralType, class StringType = std::string, typename BaseTy
Traits::EnableIf<std::is_integral<IntegralType>, std::is_signed<IntegralType>> * = nullptr>
StringType numberToString(IntegralType number, BaseType base = 10)
{
const bool negative = number < 0;
std::size_t resSize;
const auto negative = number < 0;
auto resSize = std::size_t();
if (negative) {
number = -number, resSize = 1;
} else {
resSize = 0;
}
for (auto n = number; n; n /= static_cast<IntegralType>(base), ++resSize)
;
StringType res;
res.reserve(resSize);
auto n = number;
do {
res.insert(res.begin(),
digitToChar<typename StringType::value_type>(static_cast<typename StringType::value_type>(number % static_cast<IntegralType>(base))));
n /= static_cast<IntegralType>(base), ++resSize;
} while (n);
auto res = StringType(resSize, typename StringType::value_type());
auto resIter = res.end();
do {
*(--resIter)
= digitToChar<typename StringType::value_type>(static_cast<typename StringType::value_type>(number % static_cast<IntegralType>(base)));
number /= static_cast<IntegralType>(base);
} while (number);
if (negative) {
res.insert(res.begin(), '-');
*(--resIter) = '-';
}
return res;
}
@ -487,7 +490,7 @@ StringType numberToString(FloatingType number, int base = 10)
*/
template <typename CharType> CharType charToDigit(CharType character, CharType base)
{
CharType res = base;
auto res = base;
if (character >= '0' && character <= '9') {
res = character - '0';
} else if (character >= 'a' && character <= 'z') {
@ -498,11 +501,13 @@ template <typename CharType> CharType charToDigit(CharType character, CharType b
if (res < base) {
return res;
}
std::string errorMsg;
errorMsg.reserve(36);
errorMsg += "The character \"";
constexpr auto msgBegin = std::string_view("The character \"");
constexpr auto msgEnd = std::string_view("\" is no valid digit.");
auto errorMsg = std::string();
errorMsg.reserve(msgBegin.size() + msgEnd.size() + 2);
errorMsg += msgBegin;
errorMsg += character >= ' ' && character <= '~' ? static_cast<std::string::value_type>(character) : '?';
errorMsg += "\" is no valid digit.";
errorMsg += msgEnd;
throw ConversionException(std::move(errorMsg));
}

View File

@ -4,7 +4,8 @@
#ifndef CPP_UTILITIES_GLOBAL
#define CPP_UTILITIES_GLOBAL
#include "./application/global.h"
#include "c++utilities-definitions.h"
#include "application/global.h"
#ifdef CPP_UTILITIES_STATIC
#define CPP_UTILITIES_EXPORT

View File

@ -190,7 +190,7 @@ void ArgumentParserTests::testParsing()
CPPUNIT_ASSERT_EQUAL("album"sv, std::string_view(fieldsArg.values().at(0)));
CPPUNIT_ASSERT_EQUAL("title"sv, std::string_view(fieldsArg.values().at(1)));
CPPUNIT_ASSERT_EQUAL("diskpos"sv, std::string_view(fieldsArg.values().at(2)));
CPPUNIT_ASSERT_THROW(displayTagInfoArg.values().at(3), std::out_of_range);
CPPUNIT_ASSERT_EQUAL(3_st, fieldsArg.values().size());
CPPUNIT_ASSERT_EQUAL(&displayTagInfoArg, parser.specifiedOperation());
// skip empty args
@ -208,7 +208,7 @@ void ArgumentParserTests::testParsing()
CPPUNIT_ASSERT_EQUAL("title"sv, std::string_view(fieldsArg.values().at(1)));
CPPUNIT_ASSERT_EQUAL("diskpos"sv, std::string_view(fieldsArg.values().at(2)));
CPPUNIT_ASSERT_EQUAL(""sv, std::string_view(fieldsArg.values().at(3)));
CPPUNIT_ASSERT_THROW(fieldsArg.values().at(4), std::out_of_range);
CPPUNIT_ASSERT_EQUAL(4_st, fieldsArg.values().size());
CPPUNIT_ASSERT(filesArg.isPresent());
CPPUNIT_ASSERT_EQUAL("somefile"sv, std::string_view(filesArg.values().at(0)));
@ -267,7 +267,7 @@ void ArgumentParserTests::testParsing()
CPPUNIT_ASSERT(!filesArg.isPresent());
CPPUNIT_ASSERT(fileArg.isPresent());
CPPUNIT_ASSERT_EQUAL("test"sv, std::string_view(fileArg.values().at(0)));
CPPUNIT_ASSERT_THROW(fileArg.values().at(1), std::out_of_range);
CPPUNIT_ASSERT_EQUAL(1_st, fileArg.values().size());
// constraint checking: no multiple occurrences (not resetting verboseArg on purpose)
displayFileInfoArg.reset();
@ -405,7 +405,7 @@ void ArgumentParserTests::testParsing()
CPPUNIT_ASSERT_EQUAL("album=test"sv, std::string_view(fieldsArg.values().at(0)));
CPPUNIT_ASSERT_EQUAL("title"sv, std::string_view(fieldsArg.values().at(1)));
CPPUNIT_ASSERT_EQUAL("diskpos"sv, std::string_view(fieldsArg.values().at(2)));
CPPUNIT_ASSERT_THROW(fieldsArg.values().at(3), out_of_range);
CPPUNIT_ASSERT_EQUAL(3_st, fieldsArg.values().size());
CPPUNIT_ASSERT(filesArg.isPresent());
CPPUNIT_ASSERT_EQUAL("somefile"sv, std::string_view(filesArg.values().at(0)));
CPPUNIT_ASSERT(!notAlbumArg.isPresent());
@ -473,7 +473,7 @@ void ArgumentParserTests::testParsing()
CPPUNIT_ASSERT_EQUAL("foo"sv, std::string_view(fieldsArg.values().at(0)));
CPPUNIT_ASSERT_EQUAL("bar"sv, std::string_view(fieldsArg.values().at(1)));
CPPUNIT_ASSERT_EQUAL("--help"sv, std::string_view(fieldsArg.values().at(2)));
CPPUNIT_ASSERT_THROW(fieldsArg.values().at(3), std::out_of_range);
CPPUNIT_ASSERT_EQUAL(3_st, fieldsArg.values().size());
}
/*!

View File

@ -542,6 +542,7 @@ static int execAppInternal(const char *appPath, const char *const *args, std::st
// get return code
int childReturnCode;
waitpid(child, &childReturnCode, 0);
waitpid(-child, nullptr, 0);
return childReturnCode;
} else {
// child process
@ -553,6 +554,12 @@ static int execAppInternal(const char *appPath, const char *const *args, std::st
close(readCerrPipe);
close(writeCerrPipe);
// -> create process group
if (setpgid(0, 0)) {
cerr << Phrases::Error << "Unable create process group: " << std::strerror(errno) << Phrases::EndFlush;
exit(EXIT_FAILURE);
}
// -> modify environment variable LLVM_PROFILE_FILE to apply new path for profiling output
if (!newProfilingPath.empty()) {
setenv("LLVM_PROFILE_FILE", newProfilingPath.data(), true);
@ -561,12 +568,11 @@ static int execAppInternal(const char *appPath, const char *const *args, std::st
// -> execute application
if (enableSearchPath) {
execvp(appPath, const_cast<char *const *>(args));
} else {
execv(appPath, const_cast<char *const *>(args));
}
cerr << Phrases::Error << "Unable to execute \"" << appPath << "\": execv() failed" << Phrases::EndFlush;
exit(-101);
cerr << Phrases::Error << "Unable to execute \"" << appPath << "\": " << std::strerror(errno) << Phrases::EndFlush;
exit(EXIT_FAILURE);
}
#else
@ -580,7 +586,6 @@ static int execAppInternal(const char *appPath, const char *const *args, std::st
* \throws Throws std::runtime_error when the application can not be executed.
* \remarks
* - The specified \a args must be 0 terminated. The first argument is the application name.
* - Currently only supported under UNIX.
* - \a stdout and \a stderr are cleared before.
*/
int TestApplication::execApp(const char *const *args, string &output, string &errors, bool suppressLogging, int timeout) const
@ -640,7 +645,6 @@ int TestApplication::execApp(const char *const *args, string &output, string &er
* \remarks
* - Intended to invoke helper applications (eg. to setup test files). Use execApp() and TestApplication::execApp() to
* invoke the application to be tested itself.
* - Currently only supported under UNIX.
*/
int execHelperApp(const char *appPath, const char *const *args, std::string &output, std::string &errors, bool suppressLogging, int timeout)
{
@ -655,7 +659,6 @@ int execHelperApp(const char *appPath, const char *const *args, std::string &out
* \remarks
* - Intended to invoke helper applications (eg. to setup test files). Use execApp() and TestApplication::execApp() to
* invoke the application to be tested itself.
* - Currently only supported under UNIX.
*/
int execHelperAppInSearchPath(
const char *appName, const char *const *args, std::string &output, std::string &errors, bool suppressLogging, int timeout)

View File

@ -2,6 +2,7 @@
#define TESTUTILS_H
#include "../application/argumentparser.h"
#include "../chrono/format.h"
#include "../misc/traits.h"
#include <iomanip>
@ -13,6 +14,12 @@
#define CPP_UTILITIES_HAS_EXEC_APP
#endif
// ensure CppUnit's macros produce unique variable names when doing unity builds
#if defined(__COUNTER__)
#undef CPPUNIT_UNIQUE_COUNTER
#define CPPUNIT_UNIQUE_COUNTER __COUNTER__
#endif
namespace CppUtilities {
/*!