Unreal插件 pragma optimize编译错误问题的排查与解决
Unreal各种编译模式与宏的对应关系
UE文档: https://docs.unrealengine.com/en-US/Programming/Development/BuildConfigurations
对应关系,仔细看下面这个函数就一目了然:
EBuildConfigurations::Type FApp::GetBuildConfiguration()
{
#if UE_BUILD_DEBUG
return EBuildConfigurations::Debug;
#elif UE_BUILD_DEVELOPMENT
return bIsDebugGame ? EBuildConfigurations::DebugGame : EBuildConfigurations::Development;
#elif UE_BUILD_SHIPPING
return EBuildConfigurations::Shipping;
#elif UE_BUILD_TEST
return EBuildConfigurations::Test;
#else
return EBuildConfigurations::Unknown;
#endif
}
特别注意的是, Development模式和DebugGame模式对应的宏都是: UE_BUILD_DEVELOPMENT
每种编译模式都可以和Editor模式组合,区分Editor模式的宏是: WITH_EDITOR
例如,判断当前是否Development模式的唯一正确方法:
#include "Misc/App.h"
FApp::GetBuildConfiguration() == EBuildConfigurations::Development
pragma optimize编译错误问题背景
需要发布一版最新插件,因为要部署给用户用,编译模式必须是: Development Editor
然而发布的过程中,使用Debug模式可以编译出来,但是切换为Development Editor模式却有编译错误:
xxxxx.cpp: error C4426: optimization flags changed after including header, may be due to #pragma optimize()
听取同事的建议,将#pragma optimize("", on)切换为#pragma optimize("", off),也还是不能跳过这个编译错误
我把项目里的所有#pragma optimize都注释掉,也还是一样的错误。
排查过程
因为迫切需要发布最新插件,所以我下定决心排查下到底是什么问题。
我就开始排除大法,
- 首先,根据错误提示,问题肯定出在xxxxx.cpp里
- 我先怀疑是xxxxx.cpp里include不该include的头文件,所以先把所有include都干掉;结果还是有这个错误
- 继续缩小范围,xxxxx.cpp里所有的函数实现都注释掉,所有函数体直接return,结果还是有这个错误
- 最后一看,这个文件里除了空函数,就剩下了如下的宏:
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
然后我就开始跟这个宏定义BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION,代码摘抄如下:
// SlateOptMacros.h
#define BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION BEGIN_FUNCTION_BUILD_OPTIMIZATION
#define END_SLATE_FUNCTION_BUILD_OPTIMIZATION END_FUNCTION_BUILD_OPTIMIZATION
//Platform.h
#define BEGIN_FUNCTION_BUILD_OPTIMIZATION PRAGMA_DISABLE_OPTIMIZATION
//CoreMiscDefines.h
#define PRAGMA_DISABLE_OPTIMIZATION PRAGMA_DISABLE_OPTIMIZATION_ACTUAL
#if UE_BUILD_DEBUG
#define PRAGMA_ENABLE_OPTIMIZATION PRAGMA_DISABLE_OPTIMIZATION_ACTUAL
#else
#define PRAGMA_ENABLE_OPTIMIZATION PRAGMA_ENABLE_OPTIMIZATION_ACTUAL
#endif
//WindowsPlatform.h
#if !defined(__clang__)
#define PRAGMA_DISABLE_OPTIMIZATION_ACTUAL __pragma(optimize("",off))
#define PRAGMA_ENABLE_OPTIMIZATION_ACTUAL __pragma(optimize("",on))
#elif defined(_MSC_VER) // Clang only supports __pragma with -fms-extensions
#define PRAGMA_DISABLE_OPTIMIZATION_ACTUAL __pragma(clang optimize off)
#define PRAGMA_ENABLE_OPTIMIZATION_ACTUAL __pragma(clang optimize on)
#endif
阅读代码,发现BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION, 其实就相当于执行了一次#pragma optimize
当前编译用的是Development Editor模式,所以执行的是#pragma optimize("", on)
临时方案
由于背景中编译错误的意思就是: 在文件中xxxxx.cpp改变了#pragma optimize的值导致
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION会把#pragma optimize打开,所以我就在xxxxx.cpp的结尾加了行是#pragma optimize("", off),结果就可以编译通过了。
我接着仔细分析这个宏,因为BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION具体执行的on或off,取决于当前的编译模式。
因此,当编译模式改为Debug模式后,我加的这行又会造成编译错误;所以这不是最终方案
最终方案
-
在整个工程中搜索BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION,看其他地方是怎么用BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION的。
-
发现其他地方,只要写了BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION,都会有END_SLATE_FUNCTION_BUILD_OPTIMIZATION
-
于是我把#pragma optimize("", off)替换为END_SLATE_FUNCTION_BUILD_OPTIMIZATION,也是可以编译通过了。
-
跟了一下END_SLATE_FUNCTION_BUILD_OPTIMIZATION,发现他的逻辑和BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION是完全对称的
-
把插件中的其他#pragma optimize语句全部干掉,结果也是ok的
经验与反思
主要3条经验
-
解决C++编译问题,束手无策的时候可以试试排除大法
-
不要在工程里手写任何类似#pragma optimize的语句,因为这样写的话,切换UE的编译模式一定会有编译错误
-
一个文件里,加了BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION,千万别忘了加END_SLATE_FUNCTION_BUILD_OPTIMIZATION
Q: 之前同事的建议,将xxxxx.cpp的#pragma optimize("", on)切换为#pragma optimize("", off),也还是不能跳过这个编译错误的原因是什么?
A: 因为xxxxx.cpp里的#pragma optimize写在的文件的头部, 改完之后,先执行的为#pragma optimize("", off), 后执行的BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION,所以等于没改。
浙公网安备 33010602011771号