使用 Ninja 使用 CMake 构建的 Unicode MFC 应用程序中未解决的 WinMain 错误

Posted

技术标签:

【中文标题】使用 Ninja 使用 CMake 构建的 Unicode MFC 应用程序中未解决的 WinMain 错误【英文标题】:Unresolved WinMain error in Unicode MFC application built with CMake using Ninja 【发布时间】:2020-09-16 16:24:48 【问题描述】:

这是一个显示此问题的最小项目。它由两个文件组成:CMakeLists.txt 和 hellomfc.cpp。

CMakeLists.txt

cmake_minimum_required(VERSION 3.18)
project(HelloMFC)
set(CMAKE_MFC_FLAG 2)
add_executable(HelloMFC WIN32 hellomfc.cpp)
target_compile_definitions(HelloMFC PRIVATE _AFXDLL _UNICODE UNICODE)

hellomfc.cpp

#include <afxwin.h>

class CMainFrame : public CFrameWnd 
public:
  CMainFrame()  Create(NULL, _T("Windows App")); 
;
class CApp : public CWinApp 
  CMainFrame *Frame;
  BOOL InitInstance() 
    Frame = new CMainFrame();
    m_pMainWnd = Frame;

    Frame->ShowWindow(SW_SHOW);
    Frame->UpdateWindow();

    return TRUE;
  
;

CApp theApp;

对于此示例,我从 Visual Studio 2019 的开发人员命令提示符运行 CMake。

使用 Visual Studio 2019 生成器构建它没有问题:

C:\Users\rdeterre\Documents\hello-mfc\build-vs>cmake ..
-- Building for: Visual Studio 16 2019
-- The C compiler identification is MSVC 19.27.29111.0
-- The CXX compiler identification is MSVC 19.27.29111.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/14.27.29110/bin/Hostx64/x64/cl.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/14.27.29110/bin/Hostx64/x64/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: C:/Users/rdeterre/Documents/hello-mfc/build-vs

C:\Users\rdeterre\Documents\hello-mfc\build-vs>cmake --build .
Microsoft (R) Build Engine version 16.7.0+b89cb5fde for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.

  Checking Build System
  Building Custom Rule C:/Users/rdeterre/Documents/hello-mfc/CMakeLists.txt
  hellomfc.cpp
  _WIN32_WINNT not defined. Defaulting to _WIN32_WINNT_MAXVER (see WinSDKVer.h)
  HelloMFC.vcxproj -> C:\Users\rdeterre\Documents\hello-mfc\build-vs\Debug\HelloMFC.exe
  Building Custom Rule C:/Users/rdeterre/Documents/hello-mfc/CMakeLists.txt

但使用 ninja 生成器失败并出现“未解析符号 _WinMain@16”错误:

C:\Users\rdeterre\Documents\hello-mfc\build-ninja>cmake .. -GNinja
-- The C compiler identification is MSVC 19.27.29111.0
-- The CXX compiler identification is MSVC 19.27.29111.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/14.27.29110/bin/Hostx86/x86/cl.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/14.27.29110/bin/Hostx86/x86/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: C:/Users/rdeterre/Documents/hello-mfc/build-ninja

C:\Users\rdeterre\Documents\hello-mfc\build-ninja>cmake --build .
[1/2] Building CXX object CMakeFiles\HelloMFC.dir\hellomfc.cpp.obj
_WIN32_WINNT not defined. Defaulting to _WIN32_WINNT_MAXVER (see WinSDKVer.h)
[2/2] Linking CXX executable HelloMFC.exe
FAILED: HelloMFC.exe
cmd.exe /C "cd . && C:\Users\rdeterre\scoop\apps\cmake\3.18.1\bin\cmake.exe -E vs_link_exe --intdir=CMakeFiles\HelloMFC.dir --rc=C:\PROGRA~2\WI3CF2~1\10\bin\100190~1.0\x86\rc.exe --mt=C:\PROGRA~2\WI3CF2~1\10\bin\100190~1.0\x86\mt.exe --manifests  -- C:\PROGRA~2\MICROS~1\2019\PROFES~1\VC\Tools\MSVC\1427~1.291\bin\Hostx86\x86\link.exe /nologo CMakeFiles\HelloMFC.dir\hellomfc.cpp.obj  /out:HelloMFC.exe /implib:HelloMFC.lib /pdb:HelloMFC.pdb /version:0.0 /machine:X86 /debug /INCREMENTAL /subsystem:windows  kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib && cd ."
LINK Pass 1: command "C:\PROGRA~2\MICROS~1\2019\PROFES~1\VC\Tools\MSVC\1427~1.291\bin\Hostx86\x86\link.exe /nologo CMakeFiles\HelloMFC.dir\hellomfc.cpp.obj /out:HelloMFC.exe /implib:HelloMFC.lib /pdb:HelloMFC.pdb /version:0.0 /machine:X86 /debug /INCREMENTAL /subsystem:windows kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST /MANIFESTFILE:CMakeFiles\HelloMFC.dir/intermediate.manifest CMakeFiles\HelloMFC.dir/manifest.res" failed (exit code 1120) with the following output:
msvcrtd.lib(exe_winmain.obj) : error LNK2019: unresolved external symbol _WinMain@16 referenced in function "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ)
HelloMFC.exe : fatal error LNK1120: 1 unresolved externals
ninja: build stopped: subcommand failed.

请注意,在取出 _UNICODE UNICODE 编译定义时,构建对两个生成器都有效。但是,此特定项目需要 unicode 构建。

【问题讨论】:

你为什么在这里发帖?你没有问过问题。如果你觉得 CMake 有错误,你不应该在gitlab.kitware.com/cmake/cmake/-/issues 报告它吗? 仅供参考,CMAKE_MFC_FLAG 文档状态 Enables the use of the Microsoft Foundation Classes (MFC). It should be set to 1 for the static MFC library, and 2 for the shared MFC library. This is used in Visual Studio project files. 谢谢,我会在 CMake 问题跟踪器上报告这个。我想问题应该是“是否可以使用 ninja 生成器构建 unicode MFC 应用程序?”。关于CMAKE_MFC_FLAG,令人惊讶的是,鉴于文档所说,它可以在非 unicode 版本中与 Ninja 一起使用。 这里是 CMake 问题的链接供参考:gitlab.kitware.com/cmake/cmake/-/issues/21202 【参考方案1】:

可能是CMake的一个bug,但是你可以显式指定应用入口点:

# CMakeLists.txt

...

target_link_options($PROJECT_NAME PRIVATE "/entry:wWinMainCRTStartup")

所以,它应该可以解决您的错误。

【讨论】:

以上是关于使用 Ninja 使用 CMake 构建的 Unicode MFC 应用程序中未解决的 WinMain 错误的主要内容,如果未能解决你的问题,请参考以下文章

在 macOS 上使用 Ninja 进行 CMake GUI

当我使用 CMake 和 ninja 构建时,clang++ 会忽略 -MD 标志

使用 Ninja 使用 CMake 构建的 Unicode MFC 应用程序中未解决的 WinMain 错误

CMake / Ninja:当内容未知时递归“清理”输出目录......?

CMake 找不到 Ninja

使用 CMake + Ninja 使用 GIT 下载依赖项