msvc编译相关问题

编译环境:使用gn构建工具,msvc编译器对源码编译

一、无法解析的外部符号

1、未实现相关方法

有些方法因宏定义等原因未实现,这种情况直接定义出现问题的函数,分析是否有相关的宏配置,使用#paragma message(“xxxx”)打印,判断相关的宏配置是否正确。

2、错误使用dllimport

1、错误使用dllimport。
本该使用dllexport导出的函数因内部的宏定义被声明成了dllimport,导致出现无法解析的外部符号,这种情况可以直接从错误信息里的关键字__declspec(dllimport)看出。
解决方案:修改宏定义,将dllimport修改成dllexport即可

shared_icui18n.number_modifiers.obj : error LNK2019: 无法解析的外部符号 "__declspec(dllimport) public: void __cdecl icu_69::UnicodeSet::setToBogus(void)" (__imp_?setToBogus@UnicodeSet@icu_69@@QEAAXXZ), 
函数 "public: __cdecl icu_69::number::impl::CurrencySpacingEnabledModifier::CurrencySpacingEnabledModifier(class icu_69::FormattedStringBuilder const &,class icu_69::FormattedStringBuilder const &,bool,bool,class icu_69::DecimalFormatSymbols const &,enum UErrorCode &)" (??0CurrencySpacingEnabledModifier@impl@number@icu_69@@QEAA@AEBVFormattedStringBuilder@3@0_N1AEBVDecimalFormatSymbols@3@AEAW4UErrorCode@@@Z) 中引用了该符号

2、dllexport被定义成dllimport

C:\Users\client\Documents\arkui\third_party\flutter\engine\flutter\shell\platform\glfw\flutter_glfw.cc(562): error C2491: “FlutterDesktopSetClipboardData”: 
不允许 dllimport 函数 的定义
C:\Users\client\Documents\arkui\third_party\flutter\engine\flutter\shell\platform\glfw\flutter_glfw.cc(568): error C2491: “FlutterDesktopGetClipboardData”: 
不允许 dllimport 函数 的定义
#ifdef _WIN32
#define FLUTTER_EXPORT __declspec(dllimport)
#else
#define FLUTTER_EXPORT
#endif

3、dll 链接不一致(定义不统一)
因宏定义问题,有些地方定义成dllexport,而有些地方被定义成dllimport
解决方案:统一成dllexport即可

C:\Users\client\Documents\arkui\third_party\flutter\skia\src\ports\SkFontMgr_config_parser.cpp(21): warning C4273: “containerFontPath”: dll 链接不一致
C:\Users\client\Documents\arkui\third_party\flutter\skia\include\core\SkFontMgr.h(49): note: 参见“public: static std::basic_string<char,std::char_traits<char>,std::allocator<char> > SkFontMgr::containerFontPath”的前一个定义
C:\Users\client\Documents\arkui\third_party\flutter\skia\src\ports\SkFontMgr_config_parser.cpp(21): error C2491: “SkFontMgr::containerFontPath”: 不允许 dllimport 静态数据成员 的定义
#if !defined(SK_API)
    #if defined(SKIA_DLL)
        #if defined(_MSC_VER)
            #if SKIA_IMPLEMENTATION
                #define SK_API __declspec(dllexport)
            #else
                #define SK_API __declspec(dllimport)
            #endif
        #else
            #define SK_API __attribute__((visibility("default")))
        #endif
    #else
        #define SK_API
    #endif
#endif

3、未使用dllexport

一个dll库的api想暴露给其他模块使用,相关的API必须使用dllexport暴露出来,否则就会出现“无法解析的外部符号”异常。通常将dllexport声明到类名、方法名上,在类上声明时一定要处于class与类名之间,否则也会提示这个异常;另外一个class使用dllexport声明后,其所有的方法外部是可以调用的,但其内部类需要再重新使用dllexport声明后才能供外部使用。

class SK_API SkVertices : public SkNVRefCnt<SkVertices> {
public:   
    class Builder {
    public:
        sk_sp<SkVertices> detach();
    };
}

以上代码就会报如下错误,解决方法就是将内部类Builder添加dllexport声明。

lib_ui.vertices.obj : error LNK2019: 无法解析的外部符号 "public: class sk_sp<class SkVertices> __cdecl SkVertices::Builder::detach(void)" (?detach@Builder@SkVertices@@QEAA?AV?$sk_sp@VSkVertices@@@@XZ),函数 "public: bool __cdecl flutter::Vertices::init(enum SkVertices::VertexMode,class std::vector<float,class std::allocator<float> > const &,class std::vector<float,class std::allocator<float> > const &,class std::vector<int,class std::allocator<int> > const &,class std::vector<unsigned short,class std::allocator<unsigned short> > const &)" (?init@Vertices@flutter@@QEAA_NW4VertexMode@SkVertices@@AEBV?$vector@MV?$allocator@M@std@@@std@@1AEBV?$vector@HV?$allocator@H@std@@@6@AEBV?$vector@GV?$allocator@G@std@@@6@@Z) 中引用了该符号  

4、其他问题

1、在头文件实现其方法引起(原因尚不清楚
解决方法:将方法实现从头文件移到.cpp文件。

  • 在头文件声明静态变量、方法,在.cpp文件赋值、实现,在.h文件的方法里引用。
  • 在头文件声明的全局函数,在cpp中实现,然后在头文件中引用。
    /**
     * 头文件定义
     */
    typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y, SkPoint* result);

    static MapXYProc GetMapXYProc(TypeMask mask) {
        SkASSERT((mask & ~kAllMasks) == 0);
        return gMapXYProcs[mask & kAllMasks];
    }
test222.test.obj : error LNK2019: 无法解析的外部符号 "private: static void (__cdecl*const * const SkMatrix::gMapXYProcs)(class SkMatrix const &,float,float,struct SkPoint *)" (?gMapXYProcs@SkMatrix@@0QBQ6AXAEBV1@MMPEAUSkPoint@@@ZB),函数 "private: static void (__cdecl*__cdecl SkMatrix::GetMapXYProc(enum SkMatrix::TypeMask))(class SkMatrix const &,float,float,struct 
SkPoint *)" (?GetMapXYProc@SkMatrix@@CAP6AXAEBV1@MMPEAUSkPoint@@@ZW4TypeMask@1@@Z) 中引用了该符号

SkStrEndsWith在SkString.h中定义,为全局函数,在SkString.cpp中实现。在SkString类的头文件中调用

bool SkStrEndsWith(const char string[], const char suffixStr[]);
bool SkStrEndsWith(const char string[], const char suffixChar);

class SK_API SkString {
public:
    bool endsWith(const char suffixStr[]) const {
        return SkStrEndsWith(fRec->data(), suffixStr);
    }
    bool endsWith(const char suffixChar) const {
        return SkStrEndsWith(fRec->data(), suffixChar);
    }
}    
test222.test.obj : error LNK2019: 无法解析的外部符号 "bool __cdecl SkStrEndsWith(char const * const,char const * const)" (?SkStrEndsWith2@@YA_NQEBD0@Z),函数 "public: bool __cdecl SkString::endsWith(char const * const)const " (?endsWith@SkString@@QEBA_NQEBD@Z) 中引用了该符号
test222.test.obj : error LNK2019: 无法解析的外部符号 "bool __cdecl SkStrEndsWith(char const * const,char)" (?SkStrEndsWith2@@YA_NQEBDD@Z),函数 "public: bool __cdecl SkString::endsWith(char)const " (?endsWith@SkString@@QEBA_ND@Z) 中引用了该符号

2、修改相关的方法,让其重新编译解决

test222.test.obj : error LNK2019: 无法解析的外部符号 "public: __cdecl SkPathRef::~SkPathRef(void)" (??1SkPathRef@@QEAA@XZ),函数 "public: void * __cdecl SkPathRef::`scalar deleting destructor'(unsigned int)" (??_GSkPathRef@@QEAAPEAXI@Z) 中引用了该符号
test222.test.obj : error LNK2019: 无法解析的外部符号 "public: bool __cdecl SkPathRef::isValid(void)const " (?isValid@SkPathRef@@QEBA_NXZ),函数 "public: bool __cdecl SkPath::isValid(void)const " (?isValid@SkPath@@QEBA_NXZ) 中引用了该符号

3、可能是与系统方法冲突?
Windows系统有一个CreateDirectory方法

  if (cache_base_dir.is_valid()) {
    return std::make_shared<fml::UniqueFD>(fml::CreateDirectory(
        cache_base_dir,
        {"flutter_engine", GetFlutterEngineVersion(), "skia", GetSkiaVersion()},
        read_only ? fml::FilePermission::kRead
                  : fml::FilePermission::kReadWrite));
  } else {
    return std::make_shared<fml::UniqueFD>();
  }

将file.h头文件中的CreateDirectory方法名修改成CreateDirectory2,并同步修改此处代码解决此问题

shell.persistent_cache.obj : error LNK2019: 无法解析的外部符号 "class fml::UniqueObject<void *,struct fml::internal::os_win::UniqueFDTraits> __cdecl fml::CreateDirectoryA(class fml::UniqueObject<void *,struct fml::internal::os_win::UniqueFDTraits> const &,class std::vector<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class 
std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > > const &,enum fml::FilePermission)" (?CreateDirectoryA@fml@@YA?AV?$UniqueObject@PEAXUUniqueFDTraits@os_win@internal@fml@@@1@AEBV21@AEBV?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@std@@W4FilePermission@1@@Z),函数 "class std::shared_ptr<class fml::UniqueObject<void *,struct fml::internal::os_win::UniqueFDTraits> > __cdecl flutter::`anonymous namespace'::MakeCacheDirectory(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,bool)" (?MakeCacheDirectory@?A0xaa3946e9@flutter@@YA?AV?$shared_ptr@V?$UniqueObject@PEAXUUniqueFDTraits@os_win@internal@fml@@@fml@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@4@_N@Z) 中引用了该符号

在fml模块添加rpcrt库即可 libs = [ "Rpcrt4.lib" ]

fml.file_win.obj : error LNK2019: 无法解析的外部符号 __imp_RpcStringFreeW,函数 "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl fml::CreateTemporaryDirectory(void)" (?CreateTemporaryDirectory@fml@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ) 中引用了该符号
fml.file_win.obj : error LNK2019: 无法解析的外部符号 __imp_UuidCreateSequential,函数 "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl fml::CreateTemporaryDirectory(void)" (?CreateTemporaryDirectory@fml@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ) 中引用了该符号
fml.file_win.obj : error LNK2019: 无法解析的外部符号 __imp_UuidToStringW,函数 "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl fml::CreateTemporaryDirectory(void)" (?CreateTemporaryDirectory@fml@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ) 中引用了该符号
.\txt.dll : fatal error LNK1120: 3 个无法解析的外部命令

1、默认字符集错误
默认为窄字符,如果使用宽字符,可通过 cflags = [ "-DUNICODE", "-D_UNICODE", ]

C:\Users\client\Documents\arkui\third_party\flutter\engine\flutter\fml\platform\win\file_win.cc(57): error C2664: “DWORD GetTempPathA(DWORD,LPSTR)”: 无法将参数 2 从“wchar_t [260]”转换为“LPSTR”

2、多个模块引用同一个静态库导致此问题出现

skia.lib(skia.SkString.obj) : error LNK2005: "public: void __cdecl SkString::insertScalar(unsigned __int64,float)" (?insertScalar@SkString@@QEAAX_KM@Z) 已经在 txt.dll.lib(txt.dll) 中定义  
skia.lib(skia.SkString.obj) : error LNK2005: "public: void __cdecl SkString::printf(char const * const,...)" (?printf@SkString@@QEAAXQEBDZZ) 已经在 txt.dll.lib(txt.dll) 中定义
skia.lib(skia.SkString.obj) : error LNK2005: "public: void __cdecl SkString::appendf(char const * const,...)" (?appendf@SkString@@QEAAXQEBDZZ) 已经在 txt.dll.lib(txt.dll) 中定义
skia.lib(skia.SkString.obj) : error LNK2005: "public: void __cdecl SkString::appendVAList(char const * const,char *)" (?appendVAList@SkString@@QEAAXQEBDPEAD@Z) 已经在 txt.dll.lib(txt.dll) 
中定义

3、error C2027: 使用了未定义类型“SkSVGNode“
在SkSVGDOM.h内使用class SkSVGNode; 方式引入SkSVGNode类,将此注释掉直接使用include方式引入头文件解决

#include "SkSVGNode.h"
// class SkSVGNode;

4、编译动态库时直接依赖了动态库,出现“无法解析的外部符号 _DllMainCRTStartup”
解决方法:使用sources引入源码文件即可。

static_library("cjson_static") {
    sources = [ "cJSON.c" ]
    public_configs = [ ":cJSON_config" ]
}

shared_library("cjson") {
    deps = [ ":cjson_static" ]
    public_configs = [ ":cJSON_config" ]
    
}

相关报错信息如下

LINK : error LNK2001: 无法解析的外部符号 _DllMainCRTStartup

二、其他编译相关问题

1、在Windows上修改头文件不会引起文件重新编译
可能跟gn配置有关,没有删除相关stamp文件

2、修一个类中的方法名,此方法只在本类中使用,也会引起大量的“无法解析的外部符号错误”
编译缓存问题,需要清除编译缓存,重新编译一下即可

3、不支持“使用指定的初始值设定项”
此语法特性在C++11已经实现,但msvc在C++20才实现。

union ColorParam {
    struct {
        uint8_t blue;
        uint8_t green;
        uint8_t red;
        uint8_t alpha;
    } argb;
    uint32_t value;
};
ColorParam colorValue_ { .value = 0xff000000 };
C:\Users\client\Documents\arkui\src\main.cpp(15): error C7555: 使用指定的初始值设定项至少需要“/std:c++20”

https://blog.csdn.net/u010798503/article/details/119744710

4、没有引入相关头文件
#include<algorithm>

error C2039: “clamp”: 不是 “std” 的成员

5、不能生成导入库
能正常生成dll文件,但不能生成dll.lib导入库文件。
根因:没有使用dllexport导出,导致没有相关信息来生成dll.lib文件

三、理解不了的疑问

1、定义的空宏被执行
空宏定义中的方法调用是否会被调用?

    #define SkDEBUGCODE(...)
    
    struct StencilPathArgs {
        SkDEBUGCODE(StencilPathArgs() { memset(this, 0, sizeof(*this)); }) // For validation.
        SkDEBUGCODE(void validate() const);
    };

    void stencilPath(const StencilPathArgs& args) {
        SkDEBUGCODE(args.validate();) //此行代码中的validate()方法是否会被调用???        
    }

2、宏参数传递异常
#define DECLARE_ACE_TYPE(…) DECLARE_RELATIONSHIP_OF_CLASSES(VA_ARGS)展开异常

#define DECLARE_ACE_TYPE(...) DECLARE_RELATIONSHIP_OF_CLASSES(__VA_ARGS__)

#define DECLARE_CLASS_TYPE_INFO(classname)                                              \
public:                                                                                 \
    static const char* TypeName()                                                       \
    {                                                                                   \
        return #classname;                                                              \
    }                                                                                   \
    static TypeInfoBase::IdType TypeId()                                                \
    {                                                                                   \
        static TypeInfoBase::IdType myTypeId = std::hash<std::string> {}(TypeName());   \
        return myTypeId;                                                                \
    }                                                                                   \
    DECLARE_CLASS_TYPE_SIZE(classname)

// Integrate it into class declaration to support 'DynamicCast'.
#define DECLARE_ACE_TYPE(classname, ...) DECLARE_CLASS_TYPE_INFO(classname)            \
protected:                                                                                            \
    template<class __T, class __O, class... __V>                                                      \
    uintptr_t TrySafeCastById(TypeInfoBase::IdType id) const                                          \
    {                                                                                                 \
        VERIFY_DECLARED_CLASS(__T);                                                                   \
        uintptr_t ptr = __T::SafeCastById(id);                                                        \
        return ptr != 0 ? ptr : TrySafeCastById<__O, __V...>(id);                                     \
    }                                                                                                 \
    template<class __T>                                                                               \
    uintptr_t TrySafeCastById(TypeInfoBase::IdType id) const                                          \
    {                                                                                                 \
        VERIFY_DECLARED_CLASS(__T);                                                                   \
        return __T::SafeCastById(id);                                                                 \
    }                                                                                                 \
    uintptr_t SafeCastById(TypeInfoBase::IdType id) const override                                    \
    {                                                                                                 \
        return id == TypeId() ? reinterpret_cast<uintptr_t>(this) : TrySafeCastById<__VA_ARGS__>(id); \
    }                                                                                                 \
    TypeInfoBase::IdType GetTypeId() const override                                                   \
    {                                                                                                 \
        return TypeId();                                                                              \
    }                                                                                                 \
    const char* GetTypeName() const override                                                          \
    {                                                                                                 \
        return TypeName();                                                                            \
    }                                                                                                 \
    DECLARE_CLASS_GET_TYPE_SIZE(classname)

3、以下是做什么用的?

bool ACE_EXPORT AceTraceBeginWithArgs(const char* format, ...) __attribute__((__format__(printf, 1, 2)));

四、相关工具使用

1、查看导出函数
使用vstudio的命令行,执行以下命令即可

dumpbin /exports C:\Users\client\Documents\arkui\out\skia.dll.lib

2、查看引用函数
使用vstudio的命令行,执行以下命令即可

dumpbin /imports C:\Users\client\Documents\arkui\out\skia.dll.lib
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值