How do I compile a Window API program using cl? - c

I am trying to compile a simple C Windows API program using the Windows SDK Command Prompt.
Here an excerpt from the program:
#include <Windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
[...]
RegisterClass(&wc);
hwnd = CreateWindow("test", NULL, 0, 0, 0, 0, 0, NULL, NULL, hInstance, NULL);
[...]
When I compile it using
cl test.c
in the Windows SDK Command Promt, it gives me a lot of linker errors like these:
test.obj : error LNK2019: unresolved external symbol __imp_CreateWindowExA referenced in function WinMain
test.obj : error LNK2019: unresolved external symbol __imp_RegisterClassA referenced in function WinMain

There are at least two problems.
The linker is telling you that there is an "unresolved external symbol". That means it can't find a definition for the function(s) that you tried to call. In this case, there are two such undefined functions: CreateWindowExA and RegisterClassA.
Obviously the definition for those functions is not to be found in your code, but rather in the Windows API libraries, so you'll need to inform the linker of where it can find those definitions.
The SDK comes with stubs (*.lib) files, which contain information used by the linker so that it can find the proper function definitions in the Windows DLLs at runtime. You need to instruct the linker where it can find those *.lib files.
There are a couple of different strategies for doing so:
The simple (albeit non-portable) way is to insert a #pragma statement into your source file that instructs the compiler to leave a comment recognized by the linker. For example,
#pragma comment(lib, "user32")
automatically links to user32.lib, which is the stub file for user32.dll.
Alternatively, you can pass the parameters on the command line to cl.exe. This gets awfully complicated in a hurry, though, if you're not using MSBuild or some kind of make file. In this case, you would need to modify your command line to (at minimum):
cl test.c user32.lib
Both of these options naturally assumes that your Windows SDK directory was added to the path. I'm pretty sure the installer does that for you automatically, but I'm not positive. If it doesn't, or you've removed these files from your path, you'll need to use fully-qualified paths to the *.lib files on the command line.
Reading the documentation for the possible compiler options is a good place to start. Or better yet, if you're unfamiliar with Windows programming, using an environment like Visual Studio that puts all of this stuff together for you automatically. Once you understand what's going on, look to see what the command line that Visual Studio runs is, and dissect it bit-by-bit.
Next problem is that you're compiling without Unicode defined, and because ANSI is the default, all of the macros inside the Windows header files are resolving to call the A suffixed versions of all the SDK functions. This is probably not what you want. Windows has been fully Unicode now for over a decade, and all new applications should be built as Unicode. The Unicode versions have a W suffix appended to their name.
Again, you can instruct the compiler to build with Unicode explicitly by either adding lines to your source file, or adding parameters to your command line.
In this case, the simplest way is probably just to add
#define UNICODE
to the top of your source file before #include <windows.h>. Just as we saw above, from the Visual Studio environment, UNICODE is automatically defined for you unless you explicitly change your project settings to target something else.

Those functions live in user32.lib. You need to supply that to the cl tool.
cl test.c ""C:\Program Files\Microsoft SDKs\Windows\v6.0A\Lib\user32.lib"
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.307
Copyright (C) Microsoft Corporation. All rights reserved.
test.c
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.
/out:test.exe
test.obj
"C:\Program Files\Microsoft SDKs\Windows\v6.0A\Lib\user32.lib"

Related

C - error: conflicting types for 'SDL_main' [duplicate]

I want to make a game using SDL2, but I'm unable to compile and/or run my code, please help!
SDL2 is notoriously hard to set up, and it's often the first library aspiring game developers try to use.
This post is intended as a canonical duplicate for common problems with setting up SDL2.
This answer is about MinGW / GCC, and not Visual Studio.
This answer only applies to Windows.
Common errors
The common errors are:
SDL.h: No such file or directory (when compiling)
Various SDL_main problems: "undefined reference to SDL_main", "conflicting types for SDL_main" or "number of arguments doesn't match prototype", etc. (when compiling or linking)
undefined reference to other functions (when linking)
DLL problems: (when running your program)
'??.dll' was not found
procedure entry point ... could not be located in ..., and other mysterious DLL-related errors
The program seemingly doing nothing when launched
This list is sorted from bad to good. If you change something and get a different error, use this list to tell if you made things better or worse.
The preamble
0. Don't follow bad advice.
Some resources will suggest you to do #define SDL_MAIN_HANDLED or #undef main. Don't blindly follow that advice, it's not how SDL2 is intended to be used.
If you do everything correcty, it will never be necessary. Learn the intended approach first. Then you can research what exactly that does, and make an educated decision.
1. Figure out how to compile directly from the console, you can start using an IDE and/or build system later.
If you're using an IDE, I suggest to first make sure you're able to compile your program directly from the console, to rule out any IDE configuration problems. After you figure that out, you can use the same compiler options in your IDE.
The same applies to build systems, such as CMake.
2. Download the right SDL2 files. Make sure you have the right files. You need the archive called SDL2-devel-2.0.x-mingw.tar.gz from here.
Extract it to any directory, preferably somewhere near your source code. Extracting into the compiler installation directory is often considered a bad practice (and so is copying them to C:\Windows, which is a horrible idea).
3. Know the difference between compiler flags and linker flags. A "flag" is an option you specify in the command line when building your program. When you use a single command, e.g. g++ foo.cpp -o foo.exe, all your flags are added to the same place (to this single command).
But when you build your program in two steps, e.g.:
g++ foo.cpp -c -o foo.o (compiling)
g++ foo.o -o foo.exe (linking)
you have to know which of the two commands to add a flag to. Those are "compiler flags" and "linker flags" respectively.
Most IDEs will require you to specify compiler and linker flags separately, so even if you use a single command now, it's good to know which flag goes where.
Unless specified otherwise, the order of the flags doesn't matter.
SDL.h: No such file or directory
Or any similar error related to including SDL.h or SDL2/SDL.h.
You need to tell your compiler where to look for SDL.h. It's in the SDL files you've downloaded (see preamble).
Add -Ipath to your compiler flags, where path is the directory where SDL.h is located.
Example: -IC:/Users/HolyBlackCat/Downloads/SDL2-2.0.12/x86_64-w64-mingw32/include/SDL2. Relative paths work too, e.g. -ISDL2-2.0.12/x86_64-w64-mingw32/include/SDL2.
Note that the path will be different depending on how you write the #include:
If you do #include <SDL.h>, then the path should end with .../include/SDL2 (like above). This is the recommended way.
If you do #include <SDL2/SDL.h>, then the path should end with .../include.
Various SDL_main problems
You can get several different errors mentioning SDL_main, such as undefined reference to SDL_main, or conflicting types for 'SDL_main', or number of arguments doesn't match prototype, etc.
You need to have a main function. Your main function must look like int main(int, char **). NOT int main() and NOT void main(). This is a quirk of SDL2, related to it doing #define main SDL_main.
Adding parameter names is allowed (and is mandatory in C), e.g. int main(int argc, char **argv). Also the second parameter can be written as char *[] or with a name: char *argv[]. No other changes are allowed.
If your project has multiple source files, make sure to include SDL.h in the file that defines the main function, even if it doesn't otherwise use SDL directly.
Try to avoid #define SDL_MAIN_HANDLED or #undef main when solving this issue, see preamble for explanation.
undefined reference to various functions
• undefined reference to SDL_...
The error message will mention various SDL_... functions, and/or WinMain. If it mentions SDL_main, consult the section "Various SDL_main problems" above. If the function names don't start with SDL_, consult the section "undefined reference to other functions" below.
You need to add following linker flags: -lmingw32 -lSDL2main -lSDL2 -Lpath, where path is the directory where libSDL2.dll.a and libSDL2main.a (which you've downloaded) are located. The order of the -l... flags matters. They must appear AFTER any .c/.cpp/.o files.
Example: -LC:/Users/HolyBlackCat/Desktop/SDL2-2.0.12/x86_64-w64-mingw32/lib. Relative paths work too, e.g. -LSDL2-2.0.12/x86_64-w64-mingw32/lib.
When you use -l???, the linker will look for a file called lib???.dll.a or lib???.a (and some other variants), which is why we need to pass the location of those files. libmingw32.a (corresponding to -lmingw32) is shipped with your compiler, so it already knows where to find it.
I added all those flags and nothing changed, or I'm getting skipping incompatible X when searching for Y:
You probably use the wrong SDL .a files. The archive you downloaded contains two sets of files: i686-w64-mingw32 (32-bit) and x86_64-w64-mingw32 (64-bit). You must use the files matching your compiler, which can also be either 32-bit or 64-bit.
Print (8*sizeof(void*)) to see if your compiler is 32-bit or 64-bit.
Even if you think you use the right files, try the other ones to be sure.
Some MinGW versions can be switched between 32-bit and 64-bit modes using -m32 and -m64 flags (add them to both compiler and linker flags).
I get undefined reference to a specific function:
• undefined reference to WinMain only
There are several possibilities, all of which were covered in the previous section:
You forgot -lmingw32 and/or -lSDL2main linker flags.
You must use following linker flags, in this exact order, after
any .c/.cpp/.o files: -lmingw32 -lSDL2main -lSDL2
The libSDL2main.a file you use doesn't match your compiler (32-bit file with a 64-bit compiler, or vice versa).
Try to avoid #define SDL_MAIN_HANDLED or #undef main when solving this issue, see preamble for explanation.
• undefined reference to SDL_main only
See the section "Various SDL_main problems" above.
• undefined reference to other functions
Your linker found and used libSDL2.a, but it should be finding and using libSDL2.dll.a. When both are available, it prefers the latter by default, meaning you didn't copy the latter to the directory you passed to -L.
If you intended to perform static linking, see the section called "How do I distribute my app to others?" below.
Nothing happens when I try run my app
Let's say you try to run your app, and nothing happens. Even if you try to print something at the beginning of main(), it's not printed.
Windows has a nasty habit of not showing some DLL-related errors when the program is started from the console.
If you were running your app from the console (or from an IDE), instead try double-clicking the EXE in the explorer. Most probably you'll now see some DLL-related error; then consult one of the next sections.
??.dll was not found
Copy the .dll mentioned in the error message, and place it next to your .exe.
If the DLL is called SDL2.dll, then it's in the SDL files you've downloaded (see preamble). Be aware that there are two different SDL2.dlls: a 32-bit one (in the i686-w64-mingw32 directory), and a 64-bit one (in x86_64-w64-mingw32). Get the right one, if necessary try both.
Any other DLLs will be in your compiler's bin directory (the directory where gcc.exe is located).
You might need to repeat this process 3-4 times, this is normal.
For an automatic way of determining the needed DLLs, see the next section.
procedure entry point ... could not be located in ... and other cryptic DLL errors
Your program needs several .dlls to run, and it found a wrong version of one, left over from some other program you have installed.
It looks for DLLs in several different places, but the directory with the .exe has the most priority.
You should copy all DLLs your program uses (except the system ones) into the directory where your .exe is located.
A reliable way to get a list of needed DLLs is to blindly copy a bunch of DLLs, and then remove the ones that turn out to be unnecessary:
Copy SDL2.dll. It's in the SDL files you've downloaded (see preamble). Be aware that there are two different SDL2.dlls: a 32-bit one (in the i686-w64-mingw32 directory), and a 64-bit one (in x86_64-w64-mingw32). Get the right one, if necessary try both.
Copy all DLLs from your compiler's bin directory (the directory where gcc.exe is located).
Now your program should run, but we're not done yet.
Download NTLDD (or some other program that displays a list of used DLLs). Run ntldd -R your_program.exe.
Any DLL not mentioned in its output should be removed from the current directory. Your program uses everything that remains.
I ended up with following DLLs, expect something similar: SDL2.dll, libgcc_s_seh-1.dll, libstdc++-6.dll (C++ only), libwinpthread-1.dll.
Can I determine the needed DLLs without copying excessive ones?
Yes, but it's less reliable.
Your program searches for DLLs in following locations, in this order:
The directory where your .exe is located.
C:\Windows, including some of its subdirectories.
The directories listed in PATH.
Assuming you (or some jank installer) didn't put any custom DLLs into C:\Windows, adding your compiler's bin directory to the PATH (preferably as the first entry) and either putting SDL2.dll in the same directory as the .exe or into some directory in the PATH should be enough for your program to work.
If this works, you can then run ntldd without copying any DLLs beforehand, and copy only the necessary ones. The reason why you'd want to copy them at all at this point (since your app already works) is to be able to distribute it to others, without them having to install the compiler for its DLLs. Skip any DLLs located outside of your compiler's bin directory (except for SDL2.dll).
Note that the possibility of having weird DLLs in C:\Windows is real. E.g. Wine tends to put OpenAL32.dll into C:\Windows, so if you try this process with OpenAL on Wine, it will fail. If you're making a sciprt that runs ntldd automatically, prefer copying the DLLs (or at least symlinking them - I heard MSYS2 can emulate symlinks on Windows?).
Can I make an EXE that doesn't depend on any DLLs?
It's possible to make an .exe that doesn't depend on any (non-system) .dlls by using the -static linker flag, this is called "static linking". This is rarely done, and you shouldn't need to do this if you did the above steps correctly. This requires some additional linker flags; they are listed in file ??-w64-mingw32/lib/pkgconfig/sdl2.pc shipped with SDL, in the Libs.private section. Notice that there are two files, for x32 and x64 respectively.
How do I distribute my app to others?
Follow the steps in the previous section, titled procedure entry point ... could not be located in ....
A saner alternative?
There is MSYS2.
It has a package manager that lets you download prebuilt libraries, and, as a bonus, a fresh version of the compiler.
Install SDL2 from its package manager. Use a tool called pkg-config (also from the package manager) to automatically determine all necessary flags (pkg-config --cflags SDL2 for compiler flags, pkg-config --libs SDL2 for linker flags).
This is the same experience as you would have on Linux (maybe except for some DLL management hassle).
Bonus - Other problems
Q: My program always opens a console window when I run it, how do I hide it?
A: Add -mwindows to the linker flags.
Q: I get error 'SDL_VideoMode' wasn't declared in this scope.
A: SDL_VideoMode is from SDL1.2, it's not a part of the newer SDL2. Your code was written for the outdated version of SDL. Find a better tutorial that deals specifically with SDL2.
Q: My program has the default file icon, but I want a custom one.
A: Your icon must be in the .ico format. If your graphics editor doesn't support it, make a series of .pngs of common sizes (e.g. 16x16, 32x32, 48x48, 64x64), then convert them to a single .ico using ImageMagick: magick *.png result.ico (or with convert instead of magick).
Create a file with the .rc extension (say, icon.rc), with following contents MyIconName ICON "icon.ico" (where MyIconName is an arbitrary name, and "icon.ico" is the path to the icon). Convert the file to an .o using windres -O res -i icon.rc -o icon.o (the windres program is shipped with your compiler). Specify the resulting .o file when linking, e.g. g++ foo.cpp icon.o -o foo.exe.
Recent versions of SDL2 have a nice property of using the same icon as the window icon, so you don't have to use SDL_SetWindowIcon.
A solution for Visual Studio:
Why not use a package manager? I use vcpkg, and it makes super easy to consume 3rd party libraries. Grab the vcpkg source, and extract it to a safe place, like C:/, then run its bootstrap script bootstrap-vcpkg.bat, this will generate vcpkg executable. Then run vcpkg integrate install to make libraries installed with vcpkg available in Visual Studio.
Search for the library you need:
vcpkg search sdl
imgui[sdl2-binding] Make available SDL2 binding
libwebp[vwebp-sdl] Build the vwebp viewer tool.
magnum[sdl2application] Sdl2Application library
sdl1 1.2.15#12 Simple DirectMedia Layer is a cross-platform development library designed to p...
sdl1-net 1.2.8-3 Networking library for SDL
sdl2 2.0.12-1 Simple DirectMedia Layer is a cross-platform
...
Install it with: vcpkg install sdl2.
Now you just need include SDL2 headers, and everything will work out of the box. The library will be linked automatically.
You can learn more about vcpkg here.
On Mac this is what I follow for XCode (must install g++):
sdl linking:
g++ main.cpp -o main $(sdl2-config --cflags --libs)
XCODE project steps:
open terminal app (macOS)
BUILD SETTINGS (select 'all' and 'combined' search bar enter: "search")
click on "header search paths(way right side click)
add: /usr/local/include
BUILD PHASES --> LINK BINARY LIBRARIES (click plus)
type in SDL --> click "add other"
press: command+SHIFT+g (to bring search bar)
type in: usr/local/Cellar
navigate to: SDL2 -->2.0.8 -->lib --> libSDL2-2.2.0.dylib (make sure not shortcut)

Microsoft linker spontaneously creating library

I'm trying to compile a C program (specifically, the Python interpreter) as a plain statically linked 64-bit Windows binary. My command line looks like this:
cl /DPy_BUILD_CORE ... /link Advapi32.lib Shell32.lib User32.lib
where ... is the long list of source files and include directory specifications, and the library specifications I added as necessary to fix unresolved symbol errors. I'm getting linker output that looks like (after the C compiler has finished running):
Microsoft (R) Incremental Linker Version 12.00.21005.1
Copyright (C) Microsoft Corporation. All rights reserved.
/out:getbuildinfo.exe
Advapi32.lib
Shell32.lib
User32.lib
getbuildinfo.obj
(lots more .obj's)
Creating library getbuildinfo.lib and object getbuildinfo.exp
... and then a weird error that I'm still trying to figure out, but maybe I might have a better chance if I understand another aspect of the behavior of the linker here.
Why is it creating a library? I didn't tell it to do that. It's only supposed to be creating a .exe.
In particular, I tried a small test case with just a couple of trivial C source files and otherwise the exact same command line, and it behaved as expected, creating only the .exe and not trying anything with libraries. The only differences are in the number and contents of the C source files, but I wouldn't have thought the contents of a C source file could change the behavior of the linker.
What am I missing?

LNK2001, again

I looked for similar problems, but the only topic might be the one on the use of a library, which I would avoid... here is my issue, I get this error:
1>Signal generator.obj : error LNK2001: unresolved external symbol "double __cdecl findMaxModulus(double *,int)" (?findMaxModulus##YANPANH#Z)
I am using visual studio professional 2008 to develop a c program. I have a main file and another file with all the functions I wrote, myFunctions.h/c. The problem is that these errors do not come out when I include "myFunctions.c", while they come out when I include "myFunctions.h".
i am doing what i remember from university (i am much more into matlab now), which is
/* Home-made includes */
#include "myType.h"
#include "myFunctions.h"
just after the inclusion of the othe headers (stdlib, math, etc...)
any guess? thank you
The error means the linker could not find the function. This most likely means that you aren't compiling your myFunctions.c file at all. Make sure it's added as a "source file" to the project in Visual Studio.
If you want to try on gcc try to compile both .c files same like this below:
gcc -Wall main.c myfunction.c -o final.out
You are missing the other .c file.So in the linking phase linker could not resolve the external symbol (which is your function). Try as I said.
For Visual Studio: You need to check whether all the source files are checked to make a build. there is an option to include number of files from the several source files.

How do I install pthread_win32 (Windows pthread / posix thread library) for Visual Studio 2005?

Just to be clear - I have searched the depths of the internet and back for information on how to do this
I'm looking for assistance setting up pthread_Win32 to work with Visual Studio 2005. I'm programming in C, and I have a number of multithreaded assignments to write using pthread.h. However, since pthread is native to unix, I have to write all of my code, ftp it, and then ssh to my class' remote unix system to run it. It makes development take so much longer, and it's incredibly inefficient. I'd love (more than anything) to be able to get this working on my win32 machine, so I can develop in visual studio as I've been doing for quite some time.
I've installed the pthread.lib file and pthread.h file into the respective lib/header directories, where all of the other files are. The DLL on the other hand (the actual library), I've placed in c:\windows\system32. I've tried to add the DLL as a dependency (right click project -> references -> Add new reference), but as others have stated, all I get is a blank dialogue box with no option to add any DLL files or anything. It seems to recognize the header file, but I get these errors when I compile:
1>Linking...
1>main.obj : error LNK2019: unresolved external symbol _imp_pthread_join referenced in function _main
1>main.obj : error LNK2019: unresolved external symbol _imp_pthread_create referenced in function _main
1>main.obj : error LNK2019: unresolved external symbol _imp_pthread_exit referenced in function _fcount
From my research, I've determined that this is a problem with the DLL, and I'm assuming it can't find the definitions of the functions I've referenced in my code. I've searched high and low and I can't seem to figure out any way to overcome this problem. I've added the directories of the lib/header files to my linker, just in-case, but that didn't solve the issue. I need to do something, in visual studio, to specify that I need pthreadVC2.dll as a project dependency - and it seems to be impossible (and extremely frustrating) at this point.
Any words of wisdom?
Thank you very much
I have been through this problem recently.
It appears that the __imp__ prefix is prepended to the function name in case pthread.h is included in dynamic linking mode.
Simply add the PTW32_STATIC_LIB define to your project or your source code before including pthread.h should solve the issue.
#define PTW32_STATIC_LIB
#include <pthread.h>
Although, I am not completely over as Visual Studio now trys to link with the _[FuncName] instead of [FuncName]
In visual studio, function seems to be declared differently wether you are going to link them statically (.lib) or dynamically (.dll).
To define a function you will link dynamically :
__declspec (dllimport) int myFunc(int myArgs) ;
To define function you are exporting for dynamic linking :
__declspec (dllexport) int myFunc(int myArgs) ;
And the simpliest, to define a function you will link statically:
int myFunc(int myArgs) ;
[EDIT]
I am going on my investigations and went through this on MS help center.
It seems that to avoid the _[FuncName] effect it is required to define a static linked library function by the following:
int __cdecl myFunc(int MyArgs) ;
Have you added pthreadVC.lib (or whichever particular lib you need) to the project property:
Linker/Input/Additional Dependencies
It's not enough to just have the lib file in a particular directory, the linker needs to be told to use it as an input.
Just adding pthreadVC2.lib to linker list is not suffiecient.
You also have to add addtional lib like pthreadVCE2.lib and pthreadVSE2.lib.
I am facing same issue but then I resolved it through adding these files.

What's the equivalent of gcc's -mwindows option in cmake?

I'm following the tuto:
http://zetcode.com/tutorials/gtktutorial/firstprograms/
It works but each time I double click on the executable,there is a console which I don't want it there.
How do I get rid of that console?
I tried this:
add_executable(Cmd WIN32 cmd.c)
But got this fatal error:
MSVCRTD.lib(crtexew.obj) : error LNK2019: unresolved external symbol _WinMain#16 referenced in function ___tmainCRTStartup
Cmd.exe : fatal error LNK1120: 1 unresolved externals
While using gcc directly works:
gcc -o Cmd cmd.c -mwindows ..
I'm guessing it has something to do with the entry function: int main( int argc, char *argv[]),but why gcc works?
How can I make it work with cmake?
UPDATE
Let me paste the source code here for convenience:
#include <gtk/gtk.h>
int main( int argc, char *argv[])
{
GtkWidget *window;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_show(window);
gtk_main();
return 0;
}
UPDATE2
Why gcc -mwindows works but add_executable(Cmd WIN32 cmd.c) not?
Maybe that's not the equivalent for -mwindows in cmake?
add_executable(Cmd WIN32 cmd.c)
Tells CMake this is a Windows program, and it looks for WinMain instead of main. If you want to see the flags being used you can run make VERBOSE=1. The question might be how do you define WinMain for gtk apps? I know with Qt, you link in a library that defines it for you.
You can set these linker flags to have a main() entry point and no console:
SET(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} /subsystem:windows /ENTRY:mainCRTStartup")
For more info, see this answer for the linker flags, and this answer for how to set flags in cmake.
For CMake 3.13 and newer you can use
target_link_options(target PRIVATE "/SUBSYSTEM:WINDOWS" "/ENTRY:mainCRTStartup")
If you want your program to run in console mode (ie a main function), you have to specify it in your project's properties in MSVC. What you're using right now is a project in windowed mode (ie a WinMain function, which you don't have, hence the error).
But if you don't want to get the ugly console window, you want to use the windowed mode (ie transform your main function into a propper WinMain function). This way your normal window is all that will show.
edit: As an aside, you really shouldn't name your program "cmd", that's the name of Windows' command interpreter.
According to the CMake documentation for using the WIN32 flag with ADD_EXECUTABLE:
When this property is set to true the executable when linked on Windows will be created with a WinMain() entry point instead of of just main().This makes it a GUI executable instead of a console application. See the CMAKE_MFC_FLAG variable documentation to configure use of MFC for WinMain executables.
However, your program's entry point is main() and not WinMain(). What you should do, instead, is omit the WIN32 flag, but you need to link against libgtk. So, you would use TARGET_LINK_LIBRARIES:
FIND_PACKAGE(GTK2 2.6 REQUIRED gtk)
INCLUDE_DIRECTORIES(${GTK2_INCLUDE_DIRS})
LINK_DIRECTORIES(${GTK2_LIBRARIES})
ADD_EXECUTABLE(myprogramname source1 source2 ... sourceN)
TARGET_LINK_LIBRARIES(myprogramname ${GTK2_LIBRARIES})
While the accepted answer works for MinGW, it won't work for MSVC when you don't define a WinMain. No answer is cross-toolchain compatible IMHO.
Fix Subsystem
add_executable(my_exe WIN32 main.c)
basically passes -mwindows if MinGW compiler is used or /SUBSYSTEM:WINDOWS if MSVC. This sets the subsystem field in PE header of the generated executable to 2 i.e. IMAGE_SUBSYSTEM_WINDOWS_GUI. This instructs Windows to not provide a separate console window for this executable.
Fix Entry Point on MSVC
When MSVC receives /SUBSYSTEM:WINDOWS, its runtime expects1 a WinMain, not main, to be defined unlike MinGW's (which works with any one defined). If you want to continue to use main, fix the entry point:
target_link_options(my_exe PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/ENTRY:mainCRTStartup>
)
1: Yes, OS first calls C runtime and it's the C runtime which calls your executable's entry point
Fix Subsystem Per-config
add_executable(my_exe WIN32 ... internally sets the executable's WIN32_EXECUTABLE property. This gives another, more useful way to do it:
add_executable(my_exe main.c) # look ma, no WIN32!
set_target_properties(my_exe PROPERTIES WIN32_EXECUTABLE 1)
This is useful when you want to do it only for some configurations. I personally enable this only on Release builds, while having a console window on Debug builds is useful.
# No console window for non-debug builds
set_target_properties(my_exe PROPERTIES WIN32_EXECUTABLE
$<AND:$<PLATFORM_ID:Windows>,$<NOT:$<CONFIG:Debug,RelWithDebInfo>>>
)
Verify
# Generate Ninja files for GCC
cmake -B build_g -G "Ninja Multi-Config"
# Generate Visual Studio project and solution for MSVC
cmake -B build_v -G "Visual Studio 17 2022"
# Build with verbosity
cmake --build build_g --config Release -v
This should show the actual build commands with parameters in full verbosity. Useful to verify if -mwindows or /SUBSYSTEM:WINDOWS is passed for the right build configurations.

Resources