Compare commits

...

31 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
18 changed files with 231 additions and 80 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 5)
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,10 +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/$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"
"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"},
@ -284,7 +388,6 @@
"DOXYGEN_BIN": {"type": "FILEPATH", "value": "$env{MSYS2_ROOT}/mingw64/bin/doxygen.exe"},
"CLANG_FORMAT_BIN": {"type": "FILEPATH", "value": "$env{MSYS2_ROOT}/mingw64/bin/clang-format.exe"},
"GO_BIN": {"type": "FILEPATH", "value": "$env{MSYS2_ROOT}/mingw64/bin/go.exe"},
"GOROOT": {"type": "PATH", "value": "$env{MSYS2_ROOT}/mingw64/lib/go"},
"FFMPEG_BIN": {"type": "FILEPATH", "value": "$env{MSYS2_ROOT}/mingw64/bin/ffmpeg.exe"},
"REALPATH_BIN": {"type": "FILEPATH", "value": "$env{MSYS2_ROOT}/usr/bin/realpath.exe"},
"FORCE_EXTERNAL_ICONV": {"type": "BOOL", "value": "ON"},
@ -326,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
@ -321,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

@ -1799,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));
}
/*!
@ -1810,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 {
/*!