JoshWindsor 发表于 2021-3-24 19:09

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::Developmentpragma 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_OPTIMIZATIONPRAGMA_DISABLE_OPTIMIZATION_ACTUAL#else    #define PRAGMA_ENABLE_OPTIMIZATIONPRAGMA_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,所以等于没改。
页: [1]
查看完整版本: Unreal插件 pragma optimize编译错误问题的排查与解决