In my project I have very many files and I want to manage debug with C++ macros. For every file, I want to use its own switch for enable or disable debug and adjust debug level. So basically there is shared file with settings:
This is how shared file debug.h looks:
#define DEBUG_LEVEL_LOG -1
#define DEBUG_LEVEL_NONE 0
#define DEBUG_LEVEL_ERROR 1
#define DEBUG_LEVEL_WARNING 2
#define DEBUG_LEVEL_INFO 3
#define DEBUG_LEVEL_DEBUG 4
#define DEBUG_LEVEL_TRACE 5
#ifndef ON
#define ON 1
#endif
#ifndef OFF
#define OFF 0
#endif
// setings for component "wireless"
#define WIRELESS_DEBUGGING ON
#define WIRELESS_DEBUGGING_LEVEL DEBUG_LEVEL_ERROR
// settings for another components
...
In every file I want to debug with this settings I need to define another bunch of macros. For example file "wireless.h"
#ifndef WIRELESS_DEBUGGING
#define WIRELESS_DEBUGGING_LEVEL DEBUG_LEVEL_NONE
#endif
#if WIRELESS_DEBUGGING
#if WIRELESS_DEBUGGING_LEVEL >= DEBUG_LEVEL_LOG
#define WIRELESS_LOG(...); Logger::log(__VA_ARGS__);
#else
#define WIRELESS_LOG(...); {}
#endif
#if WIRELESS_DEBUGGING_LEVEL >= DEBUG_LEVEL_ERROR
#define WIRELESS_ERROR(...); Logger::error(__VA_ARGS__);
#else
#define WIRELESS_ERROR(...); {}
#endif
#if WIRELESS_DEBUGGING_LEVEL >= DEBUG_LEVEL_WARNING
#define WIRELESS_WARNING(...); Logger::warning(__VA_ARGS__);
#else
#define WIRELESS_WARNING(...); {}
#endif
#if WIRELESS_DEBUGGING_LEVEL >= DEBUG_LEVEL_INFO
#define WIRELESS_INFO(...); Logger::info(__VA_ARGS__);
#else
#define WIRELESS_INFO(...); {}
#endif
#if WIRELESS_DEBUGGING_LEVEL >= DEBUG_LEVEL_DEBUG
#define WIRELESS_DEBUG(...); Logger::debug(__VA_ARGS__);
#else
#define WIRELESS_DEBUG(...); {}
#endif
#if WIRELESS_DEBUGGING_LEVEL >= DEBUG_LEVEL_TRACE
#define WIRELESS_TRACE(...); Logger::trace(__VA_ARGS__);
#else
#define WIRELESS_TRACE(...); {}
#endif
#else
#define WIRELESS_LOG(...); {}
#define WIRELESS_ERROR(...); {}
#define WIRELESS_WARNING(...); {}
#define WIRELESS_INFO(...); {}
#define WIRELESS_DEBUG(...); {}
#define WIRELESS_TRACE(...); {}
#endif
When I want to debug given component, I simply use something like this (in wireless.cpp)
WIRELESS_TRACE("wireless: hello world\n");
... etc ...
So far it's working. And here is the question: I don't want to use "local" bunch of definitions similar to definitions in file "wireless.h" in every component I'm using only with different prefix. Instead of this I want to have some "super macro" which will look similar to this
REGISTER_DEBUG(WIRELESS);
Is there a way how to achieve this using some concatenation and multi-line macro? I have found that using #define inside #define is forbidden.
I'm not completely sure what you want, so if this doesn't fit let me know and I'll delete.
There is the possibility of concatenating tokens in the preprocessor using ##. See, for example, https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html
This is somewhat clumsy, but should do the trick:
#define DEBUG_LEVEL_LOG -1
#define DEBUG_LEVEL_NONE 0
#define DEBUG_LEVEL_ERROR 1
#define DEBUG_LEVEL_WARNING 2
#define DEBUG_LEVEL_INFO 3
#define DEBUG_LEVEL_DEBUG 4
#define DEBUG_LEVEL_TRACE 5
#define TRACE(a,...) _TRACE(a,__VA_ARGS__)
#define _TRACE(a,...) __TRACE_##a(__VA_ARGS__)
#define __TRACE_5(...) do{Logger::trace(__VA_ARGS__);}while(0)
Here is the clumsiness: you also need to define __TRACE_4, __TRACE_3 and so on to be empty. And then you need to define the same thing for Debug:
#define __DEBUG_4(...) do{Logger::debug(__VA_ARGS__);}while(0)
But in the end, after you defined your Wireless log level:
#define WIRELESS_LEVEL 5
you can just call the macro just like this:
TRACE(WIRELESS_LEVEL,"wireless: hello world\n");
Edit
Alternatively (this might be cleaner):
#define __PRINT_55(...) do{Logger::trace(__VA_ARGS__);}while(0)
#define __PRINT_44(...) do{Logger::debug(__VA_ARGS__);}while(0)
// etc...
// Also need to define what you need to be not printed:
#define __PRINT_01(...)
// etc...
#define PRINT(a,b,...) _PRINT(a,b,__VA_ARGS__)
#define _PRINT(a,b,...) __PRINT_##a##b(__VA_ARGS__)
Now you can call your function like this:
PRINT(DEBUG_LEVEL_TRACE, WIRELESS_LEVEL, "Hello world\n");
You can get there by switching from macros to inline functions. Something like this:
// debug.h
enum DebugLevel {
DEBUG_LEVEL_LOG = -1,
DEBUG_LEVEL_NONE = 0,
DEBUG_LEVEL_ERROR = 1,
DEBUG_LEVEL_WARNING = 2,
DEBUG_LEVEL_INFO = 3,
DEBUG_LEVEL_DEBUG = 4,
DEBUG_LEVEL_TRACE = 5
};
// settings for component "wireless"
constexpr bool WIRELESS_DEBUGGING = true;
constexpr DebugLevel WIRELESS_DEBUGGING_LEVEL = DEBUG_LEVEL_ERROR;
#define REGISTER_DEBUG_FUNC(topic, level, func) \
template <typename... Args> \
inline void topic##_##level(Args&& ... args) { \
if ( topic##_DEBUGGING && topic##_DEBUGGING_LEVEL >= DEBUG_LEVEL_##level ) \
Logger::func(std::forward<Args>(args)...); \
}
#define REGISTER_DEBUG(topic) \
REGISTER_DEBUG_FUNC(topic, LOG, log) \
REGISTER_DEBUG_FUNC(topic, ERROR, error) \
REGISTER_DEBUG_FUNC(topic, WARNING, warning) \
REGISTER_DEBUG_FUNC(topic, INFO, info) \
REGISTER_DEBUG_FUNC(topic, DEBUG, debug) \
REGISTER_DEBUG_FUNC(topic, TRACE, trace)
// wireless.h
REGISTER_DEBUG(WIRELESS)
Related
I only found this related question, which isn't quite what I am looking for.
I used to have macros defined inside an #ifdef statement:
#ifdef DEBUG
# define PRINT_IF_DEBUGGING(format) printf(format);
# define PRINTF_IF_DEBUGGING(format, ...) printf(format, __VA_ARGS__);
#else
# define PRINT_IF_DEBUGGING(...)
# define PRINTF_IF_DEBUGGING(...)
#endif
Now, I want to do the inverse, to have the #ifdef statements inside the macros. Something like this:
#define PRINT_IF_DEBUGGING(format, ...) \
#if defined(DEBUG) print(format); #endif
#define PRINTF_IF_DEBUGGING(format, ...) \
#if defined(DEBUG) printf(format, __VA_ARGS__); #endif
However, I am having an issue using __VA_ARGS__ inside the #ifdef defined.
error: '#' is not followed by a macro parameter
#define PRINT_IF_DEBUGGING(format, ...)
error: '#' is not followed by a macro parameter
#define PRINTF_IF_DEBUGGING(format, ...)
warning: __VA_ARGS__ can only appear in the expansion of a C++11 variadic macro
#if defined(DEBUG) printf(format, __VA_ARGS__); #endif
Is this possible?
This should really be a comment, but I can't format that in a way that will allow me to say what I want to say, so I'm answering instead.
Anyway, just change this:
#if defined(DEBUG) print(format); #endif
to this:
#if defined(DEBUG)
print(format);
#endif
and so on, and that should fix it.
You can't use #ifdef inside of #define , so no, this is not possible. The first code you showed is the correct solution.
Using #ifdef inside of #define is not possible. But there are still ways you can detect wether or not a macro has been defined within a macro definition.
1. Solution
godbolt
#define CAT(a, b) CAT_IMPL(a, b)
#define CAT_IMPL(a, b) a ## b
#define IS_DEBUG_DEFINED() CHECK((CAT(CHECK_,DEBUG), 0, 1))
#define CHECK_DEBUG ~,~
#define CHECK(tup) CHECK_IMPL tup
#define CHECK_IMPL(a, b, c, ...) c
#define IIF(condition, true_value, false_value) CAT(IIF_,condition)(true_value, false_value)
#define IIF_0(true_value, false_value) false_value
#define IIF_1(true_value, false_value) true_value
#define PRINT_IF_DEBUGGING(format) IIF(IS_DEBUG_DEFINED(), PRINT_DEBUGGING, PRINT_NOT_DEBUGGING)(format)
// this will be used if DEBUG is defined:
#define PRINT_DEBUGGING(format) debugPrint(format)
// this will be used if DEBUG is NOT defined:
#define PRINT_NOT_DEBUGGING(format) print(format)
PRINT_IF_DEBUGGING(foo) will expand to:
if DEBUG is defined: debugPrint(foo)
if DEBUG is not defined: print(foo)
Example:
PRINT_IF_DEBUGGING("test1");
#define DEBUG
PRINT_IF_DEBUGGING("test2");
#undef DEBUG
PRINT_IF_DEBUGGING("test3");
would result in:
print("test1");
debugPrint("test2");
print("test3");
2. How IS_DEBUG_DEFINED() works
The fundamental trick behind this is to use concatenation - if the macro was defined it will be expanded, otherwise the token will be left unmodified by the preprocessor:
godbolt
#define CAT(a, b) CAT_IMPL(a, b)
#define CAT_IMPL(a, b) a ## b
// DEBUG NOT DEFINED:
CAT(CHECK_,DEBUG) // will expand to CHECK_DEBUG
// DEBUG DEFINED:
#define DEBUG 1234
CAT(CHECK_,DEBUG) // will expand to CHECK_1234
The first CAT will expand to CHECK_DEBUG, because DEBUG was not defined.
The second CAT however will expand to CHECK_1234, because DEBUG was defined and expanded to 1234 before the concatenation with CHECK_.
By defining a macro named CHECK_DEBUG we can change the result if the macro was not defined, e.g.:
godbolt
#define TEST CAT(CHECK_,DEBUG), 0, 1
#define CHECK_DEBUG ~,~
If DEBUG is not defined the result will be ~, ~, 0, 1 (4 comma-separated tokens)
If DEBUG is defined the result will be CHECK_, 0, 1 (3 comma-separated tokens)
Notice how we got 4 tokens in the first case, but only 3 tokens in the second.
Now all we need to do is take the 3rd token from that sequence (which will be 0 if DEBUG is not defined and 1 otherwise), for example with a simple macro that always returns the 3rd argument:
#define CHECK(a, b, c, ...) c
Putting it all together, this is what a full IS_DEBUG_DEFINED() could look like:
godbolt
#define CAT(a, b) CAT_IMPL(a, b)
#define CAT_IMPL(a, b) a ## b
#define IS_DEBUG_DEFINED() CHECK((CAT(CHECK_,DEBUG), 0, 1))
#define CHECK_DEBUG ~,~
#define CHECK(tup) CHECK_IMPL tup
#define CHECK_IMPL(a, b, c, ...) c
IS_DEBUG_DEFINED() will expand to 0 if DEBUG is not defined, and 1 if it is, e.g.:
IS_DEBUG_DEFINED() // -> 0
#define DEBUG
IS_DEBUG_DEFINED() // -> 1
#undef DEBUG
IS_DEBUG_DEFINED() // -> 0
With IS_DEBUG_DEFINED() you can then use a standard preprocessor IIF to change the behaviour of your macro depending on wether DEBUG is defined or not.
Example: godbolt
#define IIF(condition, true_value, false_value) CAT(IIF_,condition)(true_value, false_value)
#define IIF_0(true_value, false_value) false_value
#define IIF_1(true_value, false_value) true_value
#define PRINT_IF_DEBUGGING(format) IIF(IS_DEBUG_DEFINED(), PRINT_DEBUGGING, PRINT_NOT_DEBUGGING)(format)
// this will be used if DEBUG is defined:
#define PRINT_DEBUGGING(format) debugPrint(format)
// this will be used if DEBUG is NOT defined:
#define PRINT_NOT_DEBUGGING(format) print(format)
PRINT_IF_DEBUGGING("test"); // -> print("test");
#define DEBUG
PRINT_IF_DEBUGGING("test"); // -> debugPrint("test");
#undef DEBUG
PRINT_IF_DEBUGGING("test"); // -> print("test");
3. Caveats
One small caveat with this is that if DEBUG is defined it must expand to a valid preprocessing token (so it must only contain letters, digits and underscores) - otherwise the concatenation will result in an error.
So this would not work:
#define DEBUG ()
#define DEBUG +
I have the following problem:
#define CONCAT_(A,B) A ## B
#define CONCAT(A,B) CONCAT_(A,B)
#define CREATE_NAME(N) CONCAT(N, __COUNTER__)
If I wanted to retrieve a specific variable##__COUNTER__ later in the code how can I achieve this? I only need to get the previous one, something like:
#define CONCAT_(A,B) A ## B
#define CONCAT(A,B) CONCAT_(A,B)
#define CREATE_NAME(N) CONCAT(N, __COUNTER__)
#define GET_NAME_PREV(N, VAL) CONCAT(N, VAL)
auto CREATE_NAME(v);
auto test_current_counter_value = GET_NAME_PREV(v, __COUNTER__ -1);
Thank you.
BOOST_PP_SUB macro from boost library can be evaluated and expanded to an identifier.
#include <boost/preprocessor/arithmetic/sub.hpp>
#define CONCAT_(A,B) A ## B
#define CONCAT(A,B) CONCAT_(A,B)
#define CREATE_NAME(N) CONCAT(N, __COUNTER__)
#define GET_NAME_PREV(N) CONCAT(N, BOOST_PP_SUB(__COUNTER__, 1))
auto CREATE_NAME(v) = true;
auto test_current_counter_value = GET_NAME_PREV(v);
Try it on Compiler Explorer.
So i have been trying to learn unrealengine4 and wanted to use vim as my editor.
As an autocompletion engine i wanted to use CoC with clangd.
After some fiddling around to get my compile_commands.json almost everything works as expected.
But i get the following two errors in every document i open.
(Just for clarification, when i use VSCode i also get the same errors if i use the clangd completion engine)
In included file: Exactly one of [UE_BUILD_DEBUG UE_BUILD_DEVELOPMENT UE_BUILD_TEST UE_BUILD_SHIPPING] should be defined to be 1[clang: pp_hash_error]
Incomplete type 'UOpenDoor' named in nested name specifier[clang: incomplete_nested_name_spec] ( assuming i open a module named OpenDoor.cpp)
The first error i was able to trace back to the Unrealengine Build Tool, as the file that contains the definition of this error is located in UnrealEngine/Engine/Source/Runtime/Core/Public/Misc/Build.h
The file is as follows:
#pragma once
/*--------------------------------------------------------------------------------
Build configuration coming from UBT, do not modify
--------------------------------------------------------------------------------*/
// Set any configuration not defined by UBT to zero
#ifndef UE_BUILD_DEBUG
#define UE_BUILD_DEBUG 0
#endif
#ifndef UE_BUILD_DEVELOPMENT
#define UE_BUILD_DEVELOPMENT 0
#endif
#ifndef UE_BUILD_TEST
#define UE_BUILD_TEST 0
#endif
#ifndef UE_BUILD_SHIPPING
#define UE_BUILD_SHIPPING 0
#endif
#ifndef UE_GAME
#define UE_GAME 0
#endif
#ifndef UE_EDITOR
#define UE_EDITOR 0
#endif
#ifndef UE_BUILD_SHIPPING_WITH_EDITOR
#define UE_BUILD_SHIPPING_WITH_EDITOR 0
#endif
#ifndef UE_BUILD_DOCS
#define UE_BUILD_DOCS 0
#endif
/**
* Whether compiling for dedicated server or not.
*/
#ifndef UE_SERVER
#define UE_SERVER 0
#endif
// Ensure that we have one, and only one build config coming from UBT
#if UE_BUILD_DEBUG + UE_BUILD_DEVELOPMENT + UE_BUILD_TEST + UE_BUILD_SHIPPING != 1
#error Exactly one of [UE_BUILD_DEBUG UE_BUILD_DEVELOPMENT UE_BUILD_TEST UE_BUILD_SHIPPING] should be defined to be 1
#endif
/*--------------------------------------------------------------------------------
Legacy defined we want to make sure don't compile if they came in a merge.
--------------------------------------------------------------------------------*/
#define FINAL_RELEASE_DEBUGCONSOLE (#)
#define FINAL_RELEASE (#)
#define SHIPPING_PC_GAME (#)
#define UE_BUILD_FINAL_RELEASE (#)
/*----------------------------------------------------------------------------
Mandatory bridge options coming from UBT, do not modify directly!
----------------------------------------------------------------------------*/
/**
* Whether we are compiling with the editor; must be defined by UBT
*/
#ifndef WITH_EDITOR
#define WITH_EDITOR 0 // for auto-complete
#error UBT should always define WITH_EDITOR to be 0 or 1
#endif
/**
* Whether we are compiling with the engine; must be defined by UBT
*/
#ifndef WITH_ENGINE
#define WITH_ENGINE 0 // for auto-complete
#error UBT should always define WITH_ENGINE to be 0 or 1
#endif
/**
* Whether we are compiling with developer tools; must be defined by UBT
*/
#ifndef WITH_UNREAL_DEVELOPER_TOOLS
#define WITH_UNREAL_DEVELOPER_TOOLS 0 // for auto-complete
#error UBT should always define WITH_UNREAL_DEVELOPER_TOOLS to be 0 or 1
#endif
/**
* Whether we are compiling with plugin support; must be defined by UBT
*/
#ifndef WITH_PLUGIN_SUPPORT
#define WITH_PLUGIN_SUPPORT 0 // for auto-complete
#error UBT should always define WITH_PLUGIN_SUPPORT to be 0 or 1
#endif
/**
* Whether we are compiling with Slate accessibility and automation support
*/
#ifndef WITH_ACCESSIBILITY
#define WITH_ACCESSIBILITY 1
#endif
/** Enable perf counters */
#ifndef WITH_PERFCOUNTERS
#define WITH_PERFCOUNTERS 0
#endif
/**
* Whether we are compiling a PGO instrumented build.
*/
#ifndef ENABLE_PGO_PROFILE
#define ENABLE_PGO_PROFILE 0
#endif
/**
* Unreal Header Tool requires extra data stored in the structure of a few core files. This enables some ifdef hacks to make this work.
* Set via UBT, do not modify directly
*/
#ifndef HACK_HEADER_GENERATOR
#define HACK_HEADER_GENERATOR 0
#endif
/** Whether we are compiling with automation worker functionality. Note that automation worker defaults to enabled in
UE_BUILD_TEST configuration, so that it can be used for performance testing on devices */
#ifndef WITH_AUTOMATION_WORKER
#define WITH_AUTOMATION_WORKER !(UE_BUILD_SHIPPING || HACK_HEADER_GENERATOR)
#endif
/**
* Whether we want a monolithic build (no DLLs); must be defined by UBT
*/
#ifndef IS_MONOLITHIC
#define IS_MONOLITHIC 0 // for auto-complete
#error UBT should always define IS_MONOLITHIC to be 0 or 1
#endif
/**
* Whether we want a program (shadercompilerworker, fileserver) or a game; must be defined by UBT
*/
#ifndef IS_PROGRAM
#define IS_PROGRAM 0 // for autocomplete
#error UBT should always define IS_PROGRAM to be 0 or 1
#endif
/**
* Whether we support hot-reload. Currently requires a non-monolithic build and non-shipping configuration.
*/
#ifndef WITH_HOT_RELOAD
#define WITH_HOT_RELOAD (!IS_MONOLITHIC && !UE_BUILD_SHIPPING && !UE_BUILD_TEST && !UE_GAME && !UE_SERVER)
#endif
/**
* Whether we include support for text archive formats. Disabling support allows de-virtualizing archive calls
* and eliminating string constants for field names.
*/
#ifndef WITH_TEXT_ARCHIVE_SUPPORT
#define WITH_TEXT_ARCHIVE_SUPPORT WITH_EDITORONLY_DATA
#endif
/*----------------------------------------------------------------------------
Optional bridge options coming from UBT, do not modify directly!
If UBT doesn't set the value, it is assumed to be 0, and we set that here.
----------------------------------------------------------------------------*/
/**
* Checks to see if pure virtual has actually been implemented, this is normally run as a CIS process and is set (indirectly) by UBT
*
* #see Core.h
* #see ObjectMacros.h
**/
#ifndef CHECK_PUREVIRTUALS
#define CHECK_PUREVIRTUALS 0
#endif
/** Whether to use the null RHI. */
#ifndef USE_NULL_RHI
#define USE_NULL_RHI 0
#endif
/** If not specified, disable logging in shipping */
#ifndef USE_LOGGING_IN_SHIPPING
#define USE_LOGGING_IN_SHIPPING 0
#endif
#ifndef USE_CHECKS_IN_SHIPPING
#define USE_CHECKS_IN_SHIPPING 0
#endif
/** If not defined follow the CHECK behavior since previously ensures were compiled in with checks */
#ifndef USE_ENSURES_IN_SHIPPING
#define USE_ENSURES_IN_SHIPPING USE_CHECKS_IN_SHIPPING
#endif
#ifndef ALLOW_CONSOLE_IN_SHIPPING
#define ALLOW_CONSOLE_IN_SHIPPING 0
#endif
/** Compile flag to force stats to be compiled */
#ifndef FORCE_USE_STATS
#define FORCE_USE_STATS 0
#endif
/**
* Optionally enable support for named events from the stat macros without the stat system overhead
* This will attempt to disable regular stats system and use named events instead
*/
#ifndef ENABLE_STATNAMEDEVENTS
#define ENABLE_STATNAMEDEVENTS 0
#endif
#ifndef ENABLE_STATNAMEDEVENTS_UOBJECT
#define ENABLE_STATNAMEDEVENTS_UOBJECT 0
#endif
/*--------------------------------------------------------------------------------
Basic options that by default depend on the build configuration and platform
DO_GUARD_SLOW If true, then checkSlow, checkfSlow and verifySlow are compiled into the executable.
DO_CHECK If true, then checkCode, checkf, verify, check, checkNoEntry, checkNoReentry, checkNoRecursion, verifyf, checkf are compiled into the executables
DO_ENSURE If true, then ensure, ensureAlways, ensureMsgf and ensureAlwaysMsgf are compiled into the executables
STATS If true, then the stats system is compiled into the executable.
ALLOW_DEBUG_FILES If true, then debug files like screen shots and profiles can be saved from the executable.
NO_LOGGING If true, then no logs or text output will be produced
--------------------------------------------------------------------------------*/
#if UE_BUILD_DEBUG
#ifndef DO_GUARD_SLOW
#define DO_GUARD_SLOW 1
#endif
#ifndef DO_CHECK
#define DO_CHECK 1
#endif
#ifndef DO_ENSURE
#define DO_ENSURE 1
#endif
#ifndef STATS
#define STATS ((WITH_UNREAL_DEVELOPER_TOOLS || !WITH_EDITORONLY_DATA || USE_STATS_WITHOUT_ENGINE || USE_MALLOC_PROFILER || FORCE_USE_STATS) && !ENABLE_STATNAMEDEVENTS)
#endif
#ifndef ALLOW_DEBUG_FILES
#define ALLOW_DEBUG_FILES 1
#endif
#ifndef ALLOW_CONSOLE
#define ALLOW_CONSOLE 1
#endif
#ifndef NO_LOGGING
#define NO_LOGGING 0
#endif
#elif UE_BUILD_DEVELOPMENT
#ifndef DO_GUARD_SLOW
#define DO_GUARD_SLOW 0
#endif
#ifndef DO_CHECK
#define DO_CHECK 1
#endif
#ifndef DO_ENSURE
#define DO_ENSURE 1
#endif
#ifndef STATS
#define STATS ((WITH_UNREAL_DEVELOPER_TOOLS || !WITH_EDITORONLY_DATA || USE_STATS_WITHOUT_ENGINE || USE_MALLOC_PROFILER || FORCE_USE_STATS) && !ENABLE_STATNAMEDEVENTS)
#endif
#ifndef ALLOW_DEBUG_FILES
#define ALLOW_DEBUG_FILES 1
#endif
#ifndef ALLOW_CONSOLE
#define ALLOW_CONSOLE 1
#endif
#ifndef NO_LOGGING
#define NO_LOGGING 0
#endif
#elif UE_BUILD_TEST
#ifndef DO_GUARD_SLOW
#define DO_GUARD_SLOW 0
#endif
#ifndef DO_CHECK
#define DO_CHECK USE_CHECKS_IN_SHIPPING
#endif
#ifndef DO_ENSURE
#define DO_ENSURE USE_ENSURES_IN_SHIPPING
#endif
#ifndef STATS
#define STATS ((USE_MALLOC_PROFILER || FORCE_USE_STATS) && !ENABLE_STATNAMEDEVENTS)
#endif
#ifndef ALLOW_DEBUG_FILES
#define ALLOW_DEBUG_FILES 1
#endif
#ifndef ALLOW_CONSOLE
#define ALLOW_CONSOLE 1
#endif
#ifndef NO_LOGGING
#define NO_LOGGING !USE_LOGGING_IN_SHIPPING
#endif
#elif UE_BUILD_SHIPPING
#if WITH_EDITOR
#ifndef DO_GUARD_SLOW
#define DO_GUARD_SLOW 0
#endif
#ifndef DO_CHECK
#define DO_CHECK 1
#endif
#ifndef DO_ENSURE
#define DO_ENSURE 1
#endif
#ifndef STATS
#define STATS 1
#endif
#ifndef ALLOW_DEBUG_FILES
#define ALLOW_DEBUG_FILES 1
#endif
#ifndef ALLOW_CONSOLE
#define ALLOW_CONSOLE 0
#endif
#ifndef NO_LOGGING
#define NO_LOGGING 0
#endif
#else
#ifndef DO_GUARD_SLOW
#define DO_GUARD_SLOW 0
#endif
#ifndef DO_CHECK
#define DO_CHECK USE_CHECKS_IN_SHIPPING
#endif
#ifndef DO_ENSURE
#define DO_ENSURE USE_ENSURES_IN_SHIPPING
#endif
#ifndef STATS
#define STATS (FORCE_USE_STATS && !ENABLE_STATNAMEDEVENTS)
#endif
#ifndef ALLOW_DEBUG_FILES
#define ALLOW_DEBUG_FILES 0
#endif
#ifndef ALLOW_CONSOLE
#define ALLOW_CONSOLE ALLOW_CONSOLE_IN_SHIPPING
#endif
#ifndef NO_LOGGING
#define NO_LOGGING !USE_LOGGING_IN_SHIPPING
#endif
#endif
#else
#error Exactly one of [UE_BUILD_DEBUG UE_BUILD_DEVELOPMENT UE_BUILD_TEST UE_BUILD_SHIPPING] should be defined to be 1
#endif
/**
* This is a global setting which will turn on logging / checks for things which are
* considered especially bad for consoles. Some of the checks are probably useful for PCs also.
*
* Throughout the code base there are specific things which dramatically affect performance and/or
* are good indicators that something is wrong with the content. These have PERF_ISSUE_FINDER in the
* comment near the define to turn the individual checks on.
*
* e.g. #if defined(PERF_LOG_DYNAMIC_LOAD_OBJECT) || LOOKING_FOR_PERF_ISSUES
*
* If one only cares about DLO, then one can enable the PERF_LOG_DYNAMIC_LOAD_OBJECT define. Or one can
* globally turn on all PERF_ISSUE_FINDERS :-)
*
**/
#ifndef LOOKING_FOR_PERF_ISSUES
#define LOOKING_FOR_PERF_ISSUES (0 && !(UE_BUILD_SHIPPING))
#endif
/** Enable the use of the network profiler as long as we are not a Shipping or Test build */
#ifndef USE_NETWORK_PROFILER
#define USE_NETWORK_PROFILER !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
#endif
/** Enable UberGraphPersistentFrame feature. It can speed up BP compilation (re-instancing) in editor, but introduce an unnecessary overhead in runtime. */
#define USE_UBER_GRAPH_PERSISTENT_FRAME 1
/** Enable validation of the Uber Graph's persistent frame's layout, this is useful to detect uber graph frame related corruption */
#define VALIDATE_UBER_GRAPH_PERSISTENT_FRAME (!(UE_BUILD_SHIPPING || UE_BUILD_TEST)) && USE_UBER_GRAPH_PERSISTENT_FRAME
/** Enable fast calls for event thunks into an event graph that have no parameters */
#define UE_BLUEPRINT_EVENTGRAPH_FASTCALLS 1
/** Enable perf counters on dedicated servers */
#define USE_SERVER_PERF_COUNTERS ((UE_SERVER || UE_EDITOR) && WITH_PERFCOUNTERS)
#define USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING 1
#define USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS (USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING && 0)
// 0 (default), set this to 1 to get draw events with "TOGGLEDRAWEVENTS" "r.ShowMaterialDrawEvents" and the "ProfileGPU" command working in test
#ifndef ALLOW_PROFILEGPU_IN_TEST
#define ALLOW_PROFILEGPU_IN_TEST 0
#endif
#ifndef ALLOW_PROFILEGPU_IN_SHIPPING
#define ALLOW_PROFILEGPU_IN_SHIPPING 0
#endif
// draw events with "TOGGLEDRAWEVENTS" "r.ShowMaterialDrawEvents" (for ProfileGPU, Pix, Razor, RenderDoc, ...) and the "ProfileGPU" command are normally compiled out for TEST and SHIPPING
#define WITH_PROFILEGPU (!(UE_BUILD_SHIPPING || UE_BUILD_TEST) || (UE_BUILD_TEST && ALLOW_PROFILEGPU_IN_TEST) || (UE_BUILD_SHIPPING && ALLOW_PROFILEGPU_IN_SHIPPING))
#ifndef ALLOW_CHEAT_CVARS_IN_TEST
#define ALLOW_CHEAT_CVARS_IN_TEST 1
#endif
#define DISABLE_CHEAT_CVARS (UE_BUILD_SHIPPING || (UE_BUILD_TEST && !ALLOW_CHEAT_CVARS_IN_TEST))
// Controls the creation of a thread for detecting hangs (FThreadHeartBeat). This is subject to other criteria, USE_HANG_DETECTION
#ifndef ALLOW_HANG_DETECTION
#define ALLOW_HANG_DETECTION 1
#endif
#define USE_HANG_DETECTION (ALLOW_HANG_DETECTION && !WITH_EDITORONLY_DATA && !IS_PROGRAM && !UE_BUILD_DEBUG && !ENABLE_PGO_PROFILE)
// Controls the creation of a thread for detecting hitches (FGameThreadHitchHeartBeat). This is subject to other criteria, USE_HITCH_DETECTION
#ifndef ALLOW_HITCH_DETECTION
#define ALLOW_HITCH_DETECTION 0
#endif
// Adjust a few things with the slack policy and MallocBinned2 to minimize memory usage (at some performance cost)
#ifndef AGGRESSIVE_MEMORY_SAVING
#define AGGRESSIVE_MEMORY_SAVING 0
#endif
// Controls if UObjects are initialized as soon as they are available or only after the module is "loaded". This only applies to monolithic builds; if there are DLLs, this is how it works anyway and this should not be turned on
#ifndef USE_PER_MODULE_UOBJECT_BOOTSTRAP
#define USE_PER_MODULE_UOBJECT_BOOTSTRAP 0
#endif
#define USE_HITCH_DETECTION (ALLOW_HITCH_DETECTION && !WITH_EDITORONLY_DATA && !IS_PROGRAM && !UE_BUILD_DEBUG)
// Controls whether shipping builds create backups of the most recent log file.
// All other configurations always create backups.
#ifndef PRESERVE_LOG_BACKUPS_IN_SHIPPING
#define PRESERVE_LOG_BACKUPS_IN_SHIPPING 1
#endif
#ifndef ENABLE_RHI_VALIDATION
#define ENABLE_RHI_VALIDATION (UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT)
#endif
// Controls whether FPlatformMisc::GetDeviceId() is available to be called.
// When set to 1, calls to this API will be hardcoded to return an empty string
// to avoid running afoul of calling device APIs that platform owners may restrict
// access to without waivers or special steps. Code that uses GetDeviceId() should
// expect to receive empty strings in these cases and response appropriately with
// fallback logic.
#ifndef GET_DEVICE_ID_UNAVAILABLE
#define GET_DEVICE_ID_UNAVAILABLE 0
#endif
When i manually change the option UE_BUILD_DEVELOPMENT to 1 then the first error just gets replaced by all other errorsdefined later. e.g.In included file: UBT should always define WITH_EDITOR to be 0 or 1
I suspect the problem is, that i am using the UBT wrong, but i have no idea, how to use it correctly.
For the second error when i look into the header file at the definition of UOpenDoor which is :
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class BUILDINGESCAPE_API UOpenDoor : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UOpenDoor();
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
//Door Opening Function
virtual void OpenDoor(float DeltaTime);
//Door Closing Function
virtual void CloseDoor(float DeltaTime);
private:
//Member Variable definition
FRotator StartingRotation;
FRotator TargetRotation;
float DoorLastOpened = 0.f;
//Exposed parameters
UPROPERTY(EditAnywhere)
float OpenAngle = 90.f;
UPROPERTY(EditAnywhere)
float DoorDelay = 2.f;
UPROPERTY(EditAnywhere)
float OpenVelocity = 2.f;
UPROPERTY(EditAnywhere)
float CloseVelocity = 2.f;
UPROPERTY(EditAnywhere)
ATriggerVolume* Trigger;
UPROPERTY(EditAnywhere)
AActor* TriggerActor;
};
I get the error Variable has incomplete type 'class BUILDINGESCAPE_API'
Since i am quite new to c++ i have no idea where to go from there.
Any help would be greatly appreciated, as this problem has beeen driving me insane for weeks now...
Thanks a lot in Advance!
There is a nice write-up on github targeted at QtCreator, but it could be abstracted to any tool.
In a nut shell:
Generate some intermediate files:
cd <project-dir>
make UE4Editor
Find the needed defines in Intermediate/Build/Linux/<build-id>/UE4Editor/Development/<project-name>/Definitions.<project-name>.h
Additionally will you need these:
#define UE_BUILD_DEVELOPMENT 1
#define WITH_EDITOR 1
#define WITH_UNREAL_DEVELOPER_TOOLS 1
#define WITH_PLUGIN_SUPPORT 1
#define IS_MONOLITHIC 1
#define IS_PROGRAM 0
#define UE_EDITOR 1
#define CORE_API
#define COREUOBJECT_API
#define ENGINE_API
#define SLATE_API
#define INPUTCORE_API
#define SLATECORE_API
#define MESSAGING_API
#define RENDERCORE_API
#define RHI_API
#define SHADERCORE_API
#define ASSETREGISTRY_API
#define ENGINEMESSAGES_API
#define ENGINESETTINGS_API
#define SYNTHBENCHMARK_API
#define RENDERER_API
#define GITSOURCECONTROL_API
#define EDITORSTYLE_API
#define SOURCECONTROL_API
#define CHAOS_API
#define PHYSICSCORE_API
#define APPLICATIONCORE_API
#define DEVELOPERSETTINGS_API
I also need #define UE_TRACE_ENABLED 0 on UE 4.26
In the linked gist, a Python script was used to parse the Definitions.<project-name>.h file and generate an output, that can be used by QtCreator. I have no knowledge of vim+clangd, but with the above information one should be able to find a similar solution.
What is the difference between the C++ macro VERIFY() and ATLVERIFY() ? And which one is better to use for COM objects?
There is some difference in how the errors are reported. ATLVERIFY is defined as
#ifndef ATLVERIFY
#ifdef _DEBUG
#define ATLVERIFY(expr) ATLASSERT(expr)
#else
#define ATLVERIFY(expr) (expr)
#endif // DEBUG
#endif // ATLVERIFY
And ATLASSERT is
#ifndef ATLASSERT
#define ATLASSERT(expr) _ASSERTE(expr)
#endif // ATLASSERT
So it ends up in _ASSERTE (see https://msdn.microsoft.com/en-us/library/ezb1wyez.aspx )
While VERIFY is
#ifdef _DEBUG
#define VERIFY(f) ASSERT(f)
#else // _DEBUG
#define VERIFY(f) ((void)(f))
#endif // !_DEBUG
So it ends up in ASSERT (see https://msdn.microsoft.com/en-us/library/aa297139(v=vs.60).aspx )
I have a problem where I can't seem to get conditional #define preprocessors to work correctly. For example:
#define WIN32_BUILD
#ifdef WIN32_BUILD
#define PCH "stdafx.h"
#else
#define PCH "xyz.h"
#endif
#include PCH
If I use this form, the compiler tells me that it can't find 'stdafx.h'. OK, that seems odd, so if I change the code to....
#define WIN32_BUILD
#ifdef WIN32_BUILD
#define PCH "xyz.h"
#else
#define PCH "stdafx.h"
#endif
#include PCH
Then the file defined in PCH gets picked up and everything compiles fine. This seems odd to me, almost like the preprocessor is ignoring the #if directives and just using all the #defines that it encounters.
Obviously I am doing something wrong, and I was hoping that someone could help me understand this.
When a project has the precompiled header feature turned on the preprocessor ignores everything that comes before #include "stdafx.h"
So your #define statements are ignored.
TL:DR; #define defines the symbol, #ifdef tests if the symbol is defined not whether it has a value.
#define WIN32_BUILD
This defines a pre-processor token, WIN32_BUILD. The token has no value. Anywhere you use the token 'WIN32_BUILD' the pre-processor will substitute the empty string, i.e. nothing.
#ifdef WIN32_BUILD
This checks if the pre-processor token WIN32_BUILD is defined. It is, you just defined it.
#ifdef WIN32_BUILD
// true - this code is included.
#define PCH "stdafx.h"
This defines the pre-processor token, PCH, and assigns it the value "stdafx.h"
#else
#define PCH "xyz.h"
#endif
This code is ignored, because WIN32_BUILD was defined.
It looks as though you were expecting 'ifdef' to only evaluate to true if the expression was not defined /to/ something.
#define a
#define b SOMETHING
#ifdef a
// you are expecting this to be ignored
#endif
#ifdef b
// and expecting this not to be ignored
#endif
#ifdef and #if defined(...) do the same thing.
#define a
#define b SOMETHING
#if defined(a) && defined(b)
// this code will be evaluated, both tokens are defined.
#endif
This feature of pre-processor tokens is often used to support conditional functionality:
#if HAVE_CPP11_OVERRIDE_KEYWORD
#define OVERRIDE_FN override
#else
#define OVERRIDE_FN
#endif
struct A {
virtual void foo() {}
};
struct B : public A {
void foo() OVERRIDE_FN {}
};
In the above code, the override keyword is only added if the system supports it (determined outside of the code).
So a compiler with override sees
struct B : public A {
void foo() override {}
};
a compiler without it sees
struct B : public A {
void foo() {}
};
Note: The opposite of "ifdef" is "ifndef":
#define a
#define b SOMETHING
#undef c
//#define d // << we didn't define it.
int main() {
#ifdef a
#pramga message("a is defined")
#else
#pramga message("a is UNdefined")
#endif
#ifdef b
#pragma message("b is defined")
#else
#pramga message("b is UNdefined")
#endif
#ifdef c
#pramga message("c is defined")
#endif
#else
#pramga message("c is UNdefined")
#endif
#ifdef d
#pramga message("d is defined")
#endif
#else
#pramga message("d is UNdefined")
#endif
#ifndef d
#pragma message("d is not defined")
#endif
#ifndef a
#pragma message("a is not defined")
#endif
return 0;
}
You can assign a pre-processor token numeric values and test them with #if
#if _MSC_VER
#define WIN32_BUILD 1
#else
#define WIN32_BUILD 0
#endif
#if WIN32_BUILD
#include <Windows.h>
#endif
But, especially when doing cross-platform programming, people tend to use ifdef variants rather than numeric checks, because the value checks require you to explicitly ensure all of the tokens are defined with a value. It's a lot easier just to only define them when you need them.