// Copyright (C) 2008 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_STACK_TRACe_ #define DLIB_STACK_TRACe_ /*! This file defines 3 things. Two of them are preprocessor macros that enable you to tag functions with the dlib stack trace watcher. The third thing is a function named get_stack_trace() which returns the current stack trace in std::string form. To enable the stack trace you must #define DLIB_ENABLE_STACK_TRACE. When this #define isn't set then the 3 things described above still exist but they don't do anything. Also note that when the stack trace is enabled it changes the DLIB_ASSERT and DLIB_CASSERT macros so that they print stack traces when an assert fails. See the following example program for details: #include <iostream> #include <dlib/stack_trace.h> void funct2() { // put this macro at the top of each function you would // like to appear in stack traces DLIB_STACK_TRACE; // you may print the current stack trace as follows. std::cout << dlib::get_stack_trace() << endl; } void funct() { // This alternate form of DLIB_STACK_TRACE allows you to specify // the string used to name the current function. The other form // will usually output an appropriate function name automatically // so this may not be needed. DLIB_STACK_TRACE_NAMED("funct"); funct2(); } int main() { funct(); } !*/ #include <string> #include "assert.h" // only setup the stack trace stuff if the asserts are enabled (which happens in debug mode // basically). Also, this stuff doesn't work if you use NO_MAKEFILE #if defined(DLIB_ENABLE_STACK_TRACE) #ifdef NO_MAKEFILE #error "You can't use the dlib stack trace stuff and NO_MAKEFILE at the same time" #endif namespace dlib { const std::string get_stack_trace(); } // redefine the DLIB_CASSERT macro to include the stack trace #undef DLIB_CASSERT #define DLIB_CASSERT(_exp,_message) \ {if ( !(_exp) ) \ { \ std::ostringstream dlib_o_out; \ dlib_o_out << "\n\nError occurred at line " << __LINE__ << ".\n"; \ dlib_o_out << "Error occurred in file " << __FILE__ << ".\n"; \ dlib_o_out << "Error occurred in function " << DLIB_FUNCTION_NAME << ".\n\n"; \ dlib_o_out << "Failing expression was " << #_exp << ".\n"; \ dlib_o_out << _message << "\n\n"; \ dlib_o_out << "Stack Trace: \n" << dlib::get_stack_trace() << "\n"; \ dlib_assert_breakpoint(); \ throw dlib::fatal_error(dlib::EBROKEN_ASSERT,dlib_o_out.str()); \ }} namespace dlib { class stack_tracer { public: stack_tracer ( const char* funct_name, const char* file_name, const int line_number ); ~stack_tracer(); }; } #define DLIB_STACK_TRACE_NAMED(x) dlib::stack_tracer dlib_stack_tracer_object(x,__FILE__,__LINE__) #define DLIB_STACK_TRACE dlib::stack_tracer dlib_stack_tracer_object(DLIB_FUNCTION_NAME,__FILE__,__LINE__) #else // don't do anything if ENABLE_ASSERTS isn't defined #define DLIB_STACK_TRACE_NAMED(x) #define DLIB_STACK_TRACE namespace dlib { inline const std::string get_stack_trace() { return std::string("stack trace not enabled");} } #endif #endif // DLIB_STACK_TRACe_