

La bibliothèque d'assertion C ++ la plus sur-conçue
Philosophie de la bibliothèque: Fournissez les informations de diagnostic aussi utiles que possible.
Certaines des choses impressionnantes que fait la bibliothèque:
void zoog ( const std::map<std::string, int >& map) {
DEBUG_ASSERT (map. contains ( " foo " ), " expected key not found " , map);
}
ASSERT (vec.size() > min_items(), "vector doesn't have enough items", vec);
std::optional< float > get_param ();
float f = * ASSERT_VAL (get_param());
Types d'affirmations:
Affirmations conditionnelles:
DEBUG_ASSERT : Vérifiez le débogage mais ne fait rien dans la version (analogue à assert de la bibliothèque standard)ASSERT : enregistrer à la fois le débogage et la libérationASSUME : vérifié en débogage et sert un indice d'optimisation dans la libérationAffirmations inconditionnelles:
PANIC : déclenche à la fois dans le débogage et la libérationUNREACHABLE : déclenche dans le débogage, marqué comme inaccessible en libération Vous préférez assert les faibles intérêts?
Vous pouvez activer le minuscule debug_assert et assert des alias avec -DLIBASSERT_LOWERCASE .
Résumé des fonctionnalités:
ASSERT_EQ , etc.DEBUG_ASSERT_VAL et ASSERT_VAL qui renvoient une valeur afin qu'ils puissent être intégrés de manière transparente dans le code, par exemple FILE* f = ASSERT_VAL(fopen(path, "r") != nullptr) include (FetchContent)
FetchContent_Declare(
libassert
GIT_REPOSITORY https://github.com/jeremy-rifkin/libassert.git
GIT_TAG v2.1.2 # <HASH or TAG>
)
FetchContent_MakeAvailable(libassert)
target_link_libraries (your_target libassert::assert)
# On windows copy libassert.dll to the same directory as the executable for your_target
if ( WIN32 )
add_custom_command (
TARGET your_target POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:libassert::assert>
$<TARGET_FILE_DIR:your_target>
)
endif () Assurez-vous de configurer avec -DCMAKE_BUILD_TYPE=Debug ou -DDCMAKE_BUILD_TYPE=RelWithDebInfo pour les symboles et les informations de ligne.
Sur macOS, il est recommandé de générer un fichier .DSym, voir la logistique de la plate-forme ci-dessous.
Pour d'autres moyens d'utiliser la bibliothèque, par exemple via des gestionnaires de packages ou une installation à l'échelle du système, voir l'utilisation ci-dessous.
Fondamentalement, le rôle des affirmations consiste à vérifier les hypothèses faites dans les logiciels et à identifier les violations proches de leurs sources. L'outil d'affirmation devrait prioriser la fourniture autant que possible d'informations et de contexte au développeur pour permettre un triage rapide. Malheureusement, l'outillage existant de la langue et des bibliothèques fournit des informations de triage très limitées.
Par exemple, avec des affirmations stdlib, une affirmation telle que assert(n <= 12); ne fournit aucune information sur l'échec sur la raison pour laquelle il a échoué ou ce qui a conduit à son échec. Fournir une trace de pile et la valeur de n Greatley améliore le triage et le débogage. Idéalement, une défaillance d'affirmation devrait fournir suffisamment d'informations de diagnostic que le programmeur n'a pas à relancer un débogueur pour identifier le problème.
La version 1 de cette bibliothèque était une exploration en examinant la quantité d'informations et fonctionnalités utiles qui pouvaient être intégrées dans des affirmations tout en offrant une interface rapide et facile pour le développeur.
La version 2 de cette bibliothèque prend les leçons apprises de la version 1 pour créer un outil que j'ai personnellement trouvé indispensable dans le développement.
La caractéristique la plus importante que cette bibliothèque prend en charge est la décomposition de l'expression automatique. Pas besoin de ASSERT_LT ou d'autres tracas de ces tels, assert(vec.size() > 10); est automatiquement compris, comme indiqué ci-dessus.
Les valeurs impliquées dans les expressions d'affirmation sont affichées. Les diagnostics redondants comme 2 => 2 sont évités.
DEBUG_ASSERT (map.count( 1 ) == 2);
Seule l'expression complète de l'affirmation peut être extraite d'un appel macro. Montrant quelles parties de l'expression correspondent à quelles valeurs nécessitent une analyse d'expression de base. La grammaire C ++ est ambigu, mais la plupart des expressions peuvent être désambigées.
Toutes les affirmations de cette bibliothèque prennent en charge les messages de diagnostic facultatifs ainsi que les autres messages de diagnostic arbitraires.
FILE* f = ASSERT_VAL(fopen(path, " r " ) != nullptr , " Internal error with foobars " , errno, path); Une manipulation spéciale est fournie pour errno et Strerror est automatiquement appelé.
Remarque: les diagnostics supplémentaires sont évalués uniquement dans le chemin de défaillance d'une affirmation.

Beaucoup de travail a été consacré à générer de jolies traces de pile et à les formater aussi bien que possible. CPPTrace est utilisé comme une solution portable et autonome pour Stacktraces pré-C ++ 23. Des configurations facultatives peuvent être trouvées dans la documentation de la bibliothèque.
Une fonctionnalité à noter est qu'au lieu d'imprimer toujours des chemins complets, seul le nombre minimum de répertoires nécessaires pour différencier les chemins est imprimé.

Une autre fonctionnalité qui mérite d'être soulignée est que les traces de pile replient les traces avec une récursion profonde:

Le gestionnaire d'affirmation applique une syntaxe qui met en évidence le cas échéant, comme on le voit dans toutes les captures d'écran ci-dessus. C'est pour aider à améliorer la lisibilité.
Libassert prend en charge les gestionnaires de défaillance d'assertion personnalisés:
void handler (assert_type type, const assertion_info& assertion) {
throw std::runtime_error ( " Assertion failed: n " + assertion. to_string ());
}
int main () {
libassert::set_failure_handler (handler);
} Beaucoup de soins sont donnés à la production de stringifications de débogage des valeurs aussi efficacement que possible: les chaînes, les caractères, les nombres doivent tous être imprimés comme vous vous en doutez. De plus, les conteneurs, les tuples, STD :: Facultatif, les pointeurs intelligents, etc. sont tous chaînés pour afficher autant d'informations que possible. Si un utilisateur a défini un type de surcharge operator<<(std::ostream& o, const S& s) , cette surcharge sera appelée. Sinon, un message par défaut sera imprimé. De plus, un point de personnalité de strification est fourni:
template <> struct libassert ::stringifier<MyObject> {
std::string stringify ( const MyObject& type) {
return ...;
}
};

Les valeurs d'affirmation sont imprimées en hexadécimal ou en décimal si Hex / Binary sont utilisés de chaque côté d'une expression d'affirmation:
ASSERT (get_mask() == 0b00001101);
Étant donné que les expressions sont déjà en cours de décomposition automatiquement, vous pouvez opter pour avoir des comparaisons non signées signées faites automatiquement avec la sécurité des signes avec -DLIBASSERT_SAFE_COMPARISONS :
ASSERT ( 18446744073709551606ULL == - 10 );
Libassert fournit deux en-têtes <libassert/assert-catch2.hpp> et <libassert/assert-gtest.hpp> pour une utilisation avec Catch2 et Googlest.
Exemple de sortie de gtest:

Plus d'informations ci-dessous.
Libassert fournit trois types d'affirmations, chacun variant légèrement selon le moment où il doit être vérifié et comment il doit être interprété:
| Nom | Effet |
|---|---|
DEBUG_ASSERT | Vérifié dans le débogage, pas de CodeGen dans la version |
ASSERT | Vérifié à la fois les versions de débogage et de libération |
ASSUME | Vérifié dans le débogage, if(!(expr)) { __builtin_unreachable(); } en version |
Affirmations inconditionnelles
| Nom | Effet |
|---|---|
PANIC | Déclenche à la fois en débogage et en libération |
UNREACHABLE | Déclenché dans le débogage, marqué comme inaccessible en libération. |
Un avantage pour PANIC et UNREACHABLE sur ASSERT(false, ...) est que le compilateur obtient des informations [[noreturn]] .
ASSUME que le chemin de défaillance soit inaccessible dans la libération, fournissant potentiellement des informations utiles à l'optimiseur. Ce n'est pas le comportement par défaut pour toutes les affirmations, car la conséquence immédiate de cela est que l'échec de l'affirmation dans -DNDEBUG peut conduire à UB et il est préférable de rendre cela très explicite.
Variantes d'assistance qui peuvent être utilisées en ligne dans une expression, telles que FILE* file = ASSERT_VAL(fopen(path, "r"), "Failed to open file"); , sont également disponibles:
| Nom | Effet |
|---|---|
DEBUG_ASSERT_VAL | Enregistré dans le débogage, doit être évalué à la fois dans le débogage et la libération |
ASSERT_VAl | Vérifié à la fois les versions de débogage et de libération |
ASSUME_VAL | Vérifié dans le débogage, if(!(expr)) { __builtin_unreachable(); } en version |
Remarque: Même dans la version, la version construit l'expression de DEBUG_ASSERT_VAL doit toujours être évaluée, contrairement à DEBUG_ASSERT . Bien sûr, si le résultat n'est pas utilisé et ne produit aucun effet secondaire, il sera optimisé.
Performances: En ce qui concerne les performances d'exécution, l'impact sur Calsites est très minime sous -Og ou plus. Le chemin rapide dans le code (c'est-à-dire où l'affirmation n'échoue pas), sera rapide. Beaucoup de travail est nécessaire pour traiter les défaillances de l'affirmation une fois qu'ils se sont produits. Cependant, comme les échecs devraient être rares, cela ne devrait pas avoir d'importance.
Vitesses de compilation:, il y a un coût de compilation à temps associé à toutes les instanciations de modèle requises pour la magie de cette bibliothèque.
Autre:
Note
En raison de la décomposition de l'expression, ASSERT(1 = 2); Compiles.
Toutes les fonctions d'assurance sont des macros. Voici quelques pseudo-déparations pour interfacer avec eux:
void DEBUG_ASSERT (expression, [optional message], [optional extra diagnostics, ...]);
void ASSERT (expression, [optional message], [optional extra diagnostics, ...]);
void ASSUME (expression, [optional message], [optional extra diagnostics, ...]);
decltype ( auto ) DEBUG_ASSERT_VAL(expression, [optional message], [optional extra diagnostics, ...]);
decltype ( auto ) ASSERT_VAL (expression, [optional message], [optional extra diagnostics, ...]);
decltype ( auto ) ASSUME_VAL (expression, [optional message], [optional extra diagnostics, ...]);
void PANIC ([optional message], [optional extra diagnostics, ...]);
void UNREACHABLE ([optional message], [optional extra diagnostics, ...]); -DLIBASSERT_PREFIX_ASSERTIONS peut être utilisé pour préfixer ces macros avec LIBASSERT_ . Ceci est utile pour envelopper les assertions Libassert.
-DLIBASSERT_LOWERCASE peut être utilisé pour activer le debug_assert et assert des alias pour DEBUG_ASSERT et ASSERT . Voir: Remplacement <cassert>.
expression L' expression est automatiquement décomposée afin que des informations de diagnostic peuvent être fournies. Le type résultant doit être convertible en booléen.
L'opération entre les côtés gauche et droite du fonctionnement de niveau supérieur dans l'arborescence d'expression est évalué par un objet de fonction.
Remarque: les opérateurs logiques booléens ( && et || ) ne sont pas décomposés par défaut en raison du court-circuit.
assertion message Un message d'affirmation facultatif peut être fourni. Si le premier argument qui suit l'expression d'affirmation, ou le premier argument en panique / inaccessible, est un type de chaîne, il sera utilisé comme message (si vous voulez que le premier paramètre, qui se trouve être une chaîne, soit une valeur de diagnostic supplémentaire au lieu de passer simplement une chaîne vide d'abord, c'est-à-dire ASSERT(foo, "", str); ).
Remarque: L'expression du message d'assertion n'est évaluée que dans le chemin de défaillance de l'affirmation.
extra diagnosticsUn nombre arbitraire de valeurs de diagnostic supplémentaires peut être fournie. Ceux-ci sont affichés ci-dessous les diagnostics d'expression si un chèque échoue.
Remarque: les diagnostics supplémentaires sont évalués uniquement dans le chemin de défaillance de l'affirmation.
Il y a une manipulation spéciale lorsque errno est fourni: la valeur de strerror s'affiche automatiquement.
Pour faciliter la facilité d'intégration dans le code _VAL des variantes sont fournies qui renvoient une valeur de l'expression de l'affirmation. La valeur renvoyée est déterminée comme suit:
ASSERT_VAL(foo()); ou ASSERT_VAL(false); ) Dans l'expression de l'affirmation, la valeur de l'expression est simplement renvoyée.== , != , < , <= , > , >= , && , || ou ou toute affectation ou affectation composée puis la valeur de l' opérande de gauche est renvoyée.& , | , ^ , << , >> , ou tout opérateur binaire avec priorité au-dessus de bithift, alors la valeur de l'expression entière est renvoyée. C'est-à-dire, ASSERT_VAL(foo() > 2); Renvoie le résultat calculé de foo() et ASSERT_VAL(x & y); Renvoie le résultat calculé de x & y ;
Si la valeur de l'expression d'affirmation sélectionnée à retourner est un LVALUE, le type de l'appel d'assistance sera une référence LVALUE. Si la valeur de l'expression d'affirmation est un RValue, le type de l'appel sera un RValue.
namespace libassert {
[[nodiscard]] std::string stacktrace (
int width = 0 ,
const color_scheme& scheme = get_color_scheme(),
std::size_t skip = 0
);
template < typename T> [[nodiscard]] std::string_view type_name () noexcept ;
template < typename T> [[nodiscard]] std::string pretty_type_name () noexcept ;
template < typename T> [[nodiscard]] std::string stringify ( const T& value);
}stacktrace : génère une trace de pile, formats à la largeur donnée (0 pour aucune formatage de largeur)type_name : renvoie le nom de type de tpretty_type_name : renvoie le nom de type Prettified pour tstringify : produit un débogage stringification d'une valeur namespace libassert {
void enable_virtual_terminal_processing_if_needed ();
inline constexpr int stdin_fileno = 0 ;
inline constexpr int stdout_fileno = 1 ;
inline constexpr int stderr_fileno = 2 ;
bool isatty ( int fd);
[[nodiscard]] int terminal_width ( int fd);
}enable_virtual_terminal_processing_if_needed : Activer les séquences d'échappement ANSI pour les terminaux sur Windows, nécessaires pour la sortie de la couleur.isatty : renvoie true si le descripteur de fichier correspond à un terminalterminal_width : renvoie la largeur du terminal représenté par FD ou 0 sur l'erreur namespace libassert {
// NOTE: string view underlying data should have static storage duration, or otherwise live as
// long as the scheme is in use
struct color_scheme {
std::string_view string, escape, keyword, named_literal, number, punctuation, operator_token,
call_identifier, scope_resolution_identifier, identifier, accent, unknown, reset;
static const color_scheme ansi_basic;
static const color_scheme ansi_rgb;
static const color_scheme blank;
};
void set_color_scheme ( const color_scheme&);
const color_scheme& get_color_scheme ();
} Par défaut color_scheme::ansi_rgb est utilisé. Pour désactiver les couleurs, utilisez color_scheme::blank .
set_color_scheme : définit le schéma de couleurs pour le gestionnaire d'assertion par défaut lorsque Stderr est un terminal namespace libassert {
void set_separator (std::string_view separator);
}set_separator : définit le séparateur entre l'expression et la valeur dans la sortie de diagnostic d'affirmation. Par défaut: => . Remarque: Pas de file d'infirme. namespace libassert {
enum class literal_format_mode {
infer, // infer literal formats based on the assertion condition
no_variations, // don't do any literal format variations, just default
fixed_variations // always use a fixed set of formats (in addition to the default format)
};
void set_literal_format_mode (literal_format_mode);
enum class literal_format : unsigned {
// integers and floats are decimal by default, chars are of course chars, and everything
// else only has one format that makes sense
default_format = 0 ,
integer_hex = 1 ,
integer_octal = 2 ,
integer_binary = 4 ,
integer_character = 8 , // format integers as characters and characters as integers
float_hex = 16 ,
};
[[nodiscard]] constexpr literal_format operator |(literal_format a, literal_format b);
void set_fixed_literal_format (literal_format);
}set_literal_format_mode : Définit si la bibliothèque doit afficher des variations littérales ou les déduireset_fixed_literal_format : définir une configuration de format littéral fixe, modifie automatiquement le lital_format_mode; Notez que le format par défaut sera toujours utilisé avec d'autres namespace libassert {
enum class path_mode {
full, // full path is used
disambiguated, // only enough folders needed to disambiguate are provided
basename, // only the file name is used
};
LIBASSERT_EXPORT void set_path_mode (path_mode mode);
}set_path_mode : définit le mode de raccourcissement du chemin pour la sortie d'assurance. Par défaut: path_mode::disambiguated . namespace libassert {
enum class assert_type {
debug_assertion,
assertion,
assumption,
panic,
unreachable
};
struct LIBASSERT_EXPORT binary_diagnostics_descriptor {
std::string left_expression;
std::string right_expression;
std::string left_stringification;
std::string right_stringification;
};
struct extra_diagnostic {
std::string_view expression;
std::string stringification;
};
struct LIBASSERT_EXPORT assertion_info {
std::string_view macro_name;
assert_type type;
std::string_view expression_string;
std::string_view file_name;
std:: uint32_t line;
std::string_view function;
std::optional<std::string> message;
std::optional<binary_diagnostics_descriptor> binary_diagnostics;
std::vector<extra_diagnostic> extra_diagnostics;
size_t n_args;
std::string_view action () const ;
const cpptrace::raw_trace& get_raw_trace () const ;
const cpptrace::stacktrace& get_stacktrace () const ;
[[nodiscard]] std::string header ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string tagline ( const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string location () const ;
[[nodiscard]] std::string statement ( const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string print_binary_diagnostics ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string print_extra_diagnostics ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string print_stacktrace ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string to_string ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
};
} Debug Assertion failed at demo.cpp:194: void foo::baz(): Internal error with foobars
debug_assert(open(path, 0) >= 0, ...);
Where:
open(path, 0) => -1
Extra diagnostics:
errno => 2 "No such file or directory"
path => "/home/foobar/baz"
Stack trace:
#1 demo.cpp:194 foo::baz()
#2 demo.cpp:172 void foo::bar<int>(std::pair<int, int>)
#3 demo.cpp:396 main
Debug Assertion failed : assertion_info.action()demo.cpp:194 : assertion_info.file_name et assertion_info.linevoid foo::baz() : assertion_info.pretty_functionInternal error with foobars : assertion_info.messagedebug_assert : assertion_info.macro_nameopen(path, 0) >= 0 : assertion_info.expression_string... : déterminé par assertion_info.n_args qui a le nombre total d'arguments transmis à la macro de l'affirmationopen(path, 0) : assertion_info.binary_diagnostics.left_expression-1 : assertion_info.binary_diagnostics.left_stringification0 => 0 n'est pas utile)errno : assertion_info.extra_diagnostics[0].expression2 "No such file or directory" : assertion_info.extra_diagnostics[0].stringificationassertion_info.get_stacktrace() , ou assertion_info.get_raw_trace() pour obtenir la trace sans la résoudreAiders:
assertion_info.header() :
Debug Assertion failed at demo.cpp:194: void foo::baz(): Internal error with foobars
debug_assert(open(path, 0) >= 0, ...);
Where:
open(path, 0) => -1
Extra diagnostics:
errno => 2 "No such file or directory"
path => "/home/foobar/baz"
assertion_info.tagline() :
Debug Assertion failed at demo.cpp:194: void foo::baz(): Internal error with foobars
assertion_info.location() :
Note
Le traitement du chemin sera effectué en fonction du mode de chemin
demo.cpp:194
assertion_info.statement() :
debug_assert(open(path, 0) >= 0, ...);
assertion_info.print_binary_diagnostics() :
Where:
open(path, 0) => -1
assertion_info.print_extra_diagnostics() :
Extra diagnostics:
errno => 2 "No such file or directory"
path => "/home/foobar/baz"
assertion_info.print_stacktrace() :
Stack trace:
#1 demo.cpp:194 foo::baz()
#2 demo.cpp:172 void foo::bar<int>(std::pair<int, int>)
#3 demo.cpp:396 main
Libassert fournit un point de personnalisation pour les types définis par l'utilisateur:
template <> struct libassert ::stringifier<MyObject> {
std::string stringify ( const MyObject& type) {
return ...;
}
};Par défaut, tous les types définis par l'utilisateur de type conteneur seront automatiquement stringifiables.
De plus, LIBASSERT_USE_FMT peut être utilisé pour permettre à libassert d'utiliser fmt::formatter s.
Enfin, tous les types avec un operator<< La surcharge peut être chaîné.
namespace libassert {
void set_failure_handler ( void (*handler)( const assertion_info&));
}set_failure_handler : définit le gestionnaire d'assertion du programme.Un exemple de gestionnaire d'assurance similaire au gestionnaire par défaut:
void libassert_default_failure_handler ( const assertion_info& info) {
libassert::enable_virtual_terminal_processing_if_needed (); // for terminal colors on windows
std::string message = info. to_string (
libassert::terminal_width (libassert::stderr_fileno),
libassert::isatty (libassert::stderr_fileno)
? libassert::get_color_scheme ()
: libassert::color_scheme::blank
);
std::cerr << message << std::endl;
switch (info. type ) {
case libassert::assert_type::assertion:
case libassert::assert_type::debug_assertion:
case libassert::assert_type::assumption:
case libassert::assert_type::panic:
case libassert::assert_type::unreachable:
( void ) fflush (stderr);
std::abort ();
// Breaking here as debug CRT allows aborts to be ignored, if someone wants to make a
// debug build of this library
break ;
default :
std::cerr << " Critical error: Unknown libassert::assert_type " << std::endl;
std::abort ( 1 );
}
}Par défaut, Libassert abandonne tous les types d'affirmation. Cependant, il peut être souhaitable de lancer une exception à partir de certains ou de tous les types d'assertion au lieu de l'avorter.
Important
Les gestionnaires de défaillance ne doivent pas revenir pour assert_type::panic et assert_type::unreachable .
Libassert soutient les points de rupture programmatiques sur l'échec de l'affirmation pour rendre les affirmations plus adaptées au débogueur en ramenant la ligne d'affirmation par opposition à plusieurs couches au plus profond d'une CallStack:

Cette fonctionnalité est actuellement opt-in et peut être activée en définissant LIBASSERT_BREAK_ON_FAIL . Il est préférable de faire en tant que drapeau du compilateur: -DLIBASSERT_BREAK_ON_FAIL ou /DLIBASSERT_BREAK_ON_FAIL .
En interne, la bibliothèque vérifie la préparation d'un débogueur avant d'exécuter une instruction pour interrompre le débogueur. Par défaut, le chèque n'est effectué qu'une seule fois lors du premier échec d'affirmation. Dans certains scénarios, il peut être souhaitable de configurer ce chèque pour toujours être effectué, par exemple si vous utilisez un gestionnaire d'assistance personnalisé qui lance une exception au lieu de l'avorter et que vous pouvez vous remettre d'un échec d'affirmation permettant des échecs supplémentaires plus tard et vous ne joignez qu'un débogueur à mi-chemin de la durée de votre programme. Vous pouvez utiliser libassert::set_debugger_check_mode pour contrôler la façon dont cette vérification est effectuée:
namespace libassert {
enum class debugger_check_mode {
check_once,
check_every_time,
};
void set_debugger_check_mode (debugger_check_mode mode) noexcept ;
}La bibliothèque expose également ses utilitaires internes pour définir les points d'arrêt et vérifier si le programme est en cours de débogage:
namespace libassert {
bool is_debugger_present () noexcept ;
}
# define LIBASSERT_BREAKPOINT () <...internals...>
# define LIBASSERT_BREAKPOINT_IF_DEBUGGING () <...internals...>Cette API imite l'API de P2514, qui a été acceptée au C ++ 26.
Une note sur constexpr : pour Clang et MSVC Libassert peut utiliser l'intrinssique du compilateur, cependant, pour l'assemblage en ligne GCC est requis. L'assemblage en ligne n'est pas autorisé dans les fonctions constexpr pré-C ++ 20, cependant, GCC le prend en charge avec un avertissement après GCC 10 et la bibliothèque peut surprendre cet avertissement pour GCC 12.
Définit:
LIBASSERT_USE_MAGIC_ENUM : utilisez l'énumération magique pour corriger les valeurs d'énumérationLIBASSERT_DECOMPOSE_BINARY_LOGICAL : décomposer && et ||LIBASSERT_SAFE_COMPARISONS : activer des comparaisons signées en toute sécurité pour les expressions décomposéesLIBASSERT_PREFIX_ASSERTIONS : préfixe toutes les macros d'assertion avec LIBASSERT_LIBASSERT_USE_FMT : permet l'intégration libfmtLIBASSERT_NO_STRINGIFY_SMART_POINTER_OBJECTS : désactive le strification du contenu du pointeur intelligentCMake:
LIBASSERT_USE_EXTERNAL_CPPTRACE : utilisez un externam cpptrace au lieu d'équilibrer la bibliothèque avec fetchContentLIBASSERT_USE_EXTERNAL_MAGIC_ENUM : utilisez une énumération magique externamNote
En raison du préprocesseur non conformément de MSVC, il n'y a pas de moyen facile de fournir des emballages d'affirmation. Afin d'utiliser des intégrations de bibliothèque de tests /Zc:preprocessor est requis.
Libassert fournit une intégration Catch2 dans libassert/assert-catch2.hpp :
# include < libassert/assert-catch2.hpp >
TEST_CASE ( " 1 + 1 is 2 " ) {
ASSERT ( 1 + 1 == 3 );
}
Actuellement, la seule macro fournie est ASSERT , qui remplira un REQUIRE en interne.
Remarque: Avant V3.6.0, les codes de couleur ANSI interfèrent avec l'emballage de la ligne de Catch2 afin que la couleur soit désactivée sur les anciennes versions.
Libassert fournit une intégration GTEST dans libassert/assert-gtest.hpp :
# include < libassert/assert-gtest.hpp >
TEST (Addition, Arithmetic) {
ASSERT ( 1 + 1 == 3 );
}
Actuellement, Libassert fournit ASSERT et EXPECT des macros pour GTEST.
Ce n'est pas aussi joli que je le souhaite, cependant, cela fait le travail.
Cette bibliothèque cible> = C ++ 17 et prend en charge tous les principaux compilateurs et toutes les principales plates-formes (Linux, MacOS, Windows et Mingw).
Remarque: La bibliothèque s'appuie sur certaines extensions du compilateur et des fonctionnalités spécifiques du compilateur, de sorte qu'elle n'est pas compatible avec -pedantic .
Avec cmake fetchContent:
include (FetchContent)
FetchContent_Declare(
libassert
GIT_REPOSITORY https://github.com/jeremy-rifkin/libassert.git
GIT_TAG v2.1.2 # <HASH or TAG>
)
FetchContent_MakeAvailable(libassert)
target_link_libraries (your_target libassert::assert)Remarque: Sur Windows et MacOS, un travail supplémentaire est recommandé, voir la logistique de la plate-forme ci-dessous.
Assurez-vous de configurer avec -DCMAKE_BUILD_TYPE=Debug ou -DDCMAKE_BUILD_TYPE=RelWithDebInfo pour les symboles et les informations de ligne.
git clone https://github.com/jeremy-rifkin/libassert.git
git checkout v2.1.2
mkdir libassert/build
cd libassert/build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j
sudo make installUtilisation via Cmake:
find_package (libassert REQUIRED)
target_link_libraries (<your target > libassert::assert) Assurez-vous de configurer avec -DCMAKE_BUILD_TYPE=Debug ou -DDCMAKE_BUILD_TYPE=RelWithDebInfo pour les symboles et les informations de ligne.
Ou compiler avec -lassert :
g++ main.cpp -o main -g -Wall -lassert
./mainSi vous obtenez une erreur dans le sens de
error while loading shared libraries: libassert.so: cannot open shared object file: No such file or directory
Vous devrez peut-être exécuter sudo /sbin/ldconfig pour créer tous les liens nécessaires et mettre à jour les caches afin que le système puisse trouver libcpptrace.so (j'ai dû le faire sur Ubuntu). Uniquement lors de l'installation à l'échelle du système. Habituellement, votre manger de colis le fait pour vous lors de l'installation de nouvelles bibliothèques.
git clone https: // github.com / jeremy - rifkin / libassert.git
git checkout v2. 1.2
mkdir libassert / build
cd libassert / build
cmake . . - DCMAKE_BUILD_TYPE = Release
msbuild libassert.sln
msbuild INSTALL.vcxprojRemarque: vous devrez s'exécuter en tant qu'administrateur dans un développeur PowerShell, ou utiliser vcvarsall.bat distribué avec Visual Studio pour obtenir l'ensemble des variables d'environnement correctes.
Pour installer uniquement pour l'utilisateur local (ou tout préfixe personnalisé):
git clone https://github.com/jeremy-rifkin/libassert.git
git checkout v2.1.2
mkdir libassert/build
cd libassert/build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX= $HOME /wherever
make -j
sudo make installUtilisation via Cmake:
find_package (libassert REQUIRED PATHS $ENV{HOME} /wherever)
target_link_libraries (<your target > libassert::assert)En utilisant manuellement:
g++ main.cpp -o main -g -Wall -I$HOME/wherever/include -L$HOME/wherever/lib -lassert
Pour utiliser la bibliothèque sans CMake, suivez d'abord les instructions d'installation lors de l'installation à l'échelle du système, de l'installation d'utilisateurs locaux ou des gestionnaires de packages.
Utilisez les arguments suivants pour compiler avec Libassert:
| Compilateur | Plate-forme | Dépendances |
|---|---|---|
| GCC, Clang, Intel, etc. | Linux / macOS / Unix | -libassert -I[path] [cpptrace args] |
| mingw | Fenêtre | -libassert -I[path] [cpptrace args] |
| msvc | Fenêtre | assert.lib /I[path] [cpptrace args] |
| bruit | Fenêtre | -libassert -I[path] [cpptrace args] |
Pour l'espace réservé [path] dans -I[path] et /I[path] , spécifiez le chemin du dossier dans le dossier incluant contenant libassert/assert.hpp .
Si vous liez statiquement, vous devrez en outre spécifier -DLIBASSERT_STATIC_DEFINE .
Pour l'espace réservé [cpptrace args] reportez-vous à la documentation CPPTrace.
Libassert est disponible via Conan à https://conan.io/center/recipes/libassert.
[requires]
libassert/2.1.2
[generators]
CMakeDeps
CMakeToolchain
[layout]
cmake_layout
# ...
find_package (libassert REQUIRED)
# ...
target_link_libraries (YOUR_TARGET libassert::assert) vcpkg install libassert
find_package (libassert CONFIG REQUIRED)
target_link_libraries (YOUR_TARGET PRIVATE libassert::assert)Les fenêtres et les macos nécessitent un peu de travail supplémentaire pour tout obtenir au bon endroit
Copie de la bibliothèque .dll sur Windows:
# Copy the assert.dll on windows to the same directory as the executable for your_target.
# Not required if static linking.
if ( WIN32 )
add_custom_command (
TARGET your_target POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:libassert::assert>
$<TARGET_FILE_DIR:your_target>
)
endif ()Sur macOS, il est recommandé de générer un fichier DSYM contenant des informations de débogage pour votre programme:
Dans xcode cmake, cela peut être fait avec
set_target_properties (your_target PROPERTIES XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym" ) Et en dehors de Xcode, cela peut être fait avec dsymutil yourbinary :
# Create a .dSYM file on macos. Currently required, but hopefully not for long
if ( APPLE )
add_custom_command (
TARGET your_target
POST_BUILD
COMMAND dsymutil $<TARGET_FILE:your_target>
)
endif () Cette bibliothèque ne remplace pas <cassert> . -DLIBASSERT_LOWERCASE peut être utilisé pour créer des alias minuscules pour les macros d'assertion, mais sachez que ASSERT de Libassert est toujours vérifiée dans la version. Pour remplacer <cassert> Utilisez par Libassert, remplacez assert par DEBUG_ASSERT ou créez un alias dans les lignes suivantes:
# define assert (...) DEBUG_ASSERT(__VA_ARGS__) Une chose à savoir: la remplacement assert de Cassert n'est techniquement pas autorisée par la norme, mais cela ne devrait pas être un problème pour un compilateur sain d'esprit.
Non, pas encore.
cpp-sort de Morwenn Même avec des constructions comme assert_eq , les diagnostics d'affirmation font souvent défaut. Par exemple, dans la rouille, les valeurs gauche et droite sont affichées mais pas les expressions elles-mêmes:
fn main ( ) {
let count = 4 ;
assert_eq ! ( count , 2 ) ;
} thread 'main' panicked at 'assertion failed: `(left == right)`
left: `4`,
right: `2`', /app/example.rs:3:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Ce n'est pas aussi utile que possible.
Fonctionnalité d'autres langues / leurs bibliothèques standard fournissent:
| C / C ++ | Rouiller | C # | Java | Python | Javascrip | Libassert | |
|---|---|---|---|---|---|---|---|
| Chaîne d'expression | ✔️ | ✔️ | |||||
| Emplacement | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| Trace de pile | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | |
| Message d'assistance | ** | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| Diagnostics supplémentaires | * | * | * | * | ✔️ | ||
| Spécialisations binaires | ✔️ | ✔️ | ✔️ | ||||
| Décomposition d'expression automatique | ✔️ | ||||||
| Chaînes de sous-expression | ✔️ |
* : Possible grâce à la formatage des chaînes, mais c'est l'idéal sous.
** : assert(expression && "message") est couramment utilisé mais cela est sous-idéal et ne permet que des messages littéraux de chaîne.
Extras:
| C / C ++ | Rouiller | C # | Java | Python | Javascrip | Libassert | |
|---|---|---|---|---|---|---|---|
| Syntaxe mise en évidence | ? | ✔️ | |||||
| Cohérence de formatage littéral | ✔️ | ||||||
| Chaînes d'expression et valeurs d'expression partout | ✔️ | ||||||
| Les valeurs de retour de l'affirmation pour permettre aux affirmations d'être intégrées dans les expressions en ligne | ✔️ |