Unresolved WinMain error in Unicode MFC application built with CMake using Ninja generator
I had originally asked this question on Stack Overflow but got told that it may be a bug with CMake. The problem is a linking error that appears when building a Unicode MFC application using the Ninja generator. Here is a minimal project that shows this issue. It consists of two files: CMakeLists.txt and 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;
For this example, I'm running CMake from a developer command prompt for Visual Studio 2019. Building this using the visual studio 2019 generator works no problem:
Build log with Visual Studio 2019 generator
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
But using the ninja generator fails with an "unresolved symbol _WinMain@16" error:
Build log with Ninja generator
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:\PROGRA2\WI3CF21\10\bin\1001901.0\x86\rc.exe --mt=C:\PROGRA2\WI3CF21\10\bin\1001901.0\x86\mt.exe --manifests -- C:\PROGRA2\MICROS1\2019\PROFES1\VC\Tools\MSVC\14271.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:\PROGRA2\MICROS1\2019\PROFES1\VC\Tools\MSVC\14271.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.
Note that building works with both generators when taking out the _UNICODE UNICODE
compile definitions.
In addition, adding target_link_options(${PROJECT_NAME} PRIVATE "/entry:wWinMainCRTStartup")
to the CMakeLists.txt file solves the issue.