13

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?

Gtker
  • 2,237
  • 9
  • 29
  • 37

6 Answers6

7

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.

Bill Hoffman
  • 1,742
  • 11
  • 12
3

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.

Community
  • 1
  • 1
Matt Eckert
  • 1,946
  • 14
  • 16
  • This method of specifying the entry point (can't say anything about the subsystem) didn't work for me, but `target_link_options` one suggested in https://stackoverflow.com/a/58079971/132042 did. When I looked at the flags as passed in to the linker, `/ENTRY` wasn't in there. – Tatiana Racheva Feb 20 '21 at 21:24
3

For CMake 3.13 and newer you can use

target_link_options(target PRIVATE "/SUBSYSTEM:WINDOWS" "/ENTRY:mainCRTStartup")
eyelash
  • 3,197
  • 25
  • 33
2

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.

Blindy
  • 65,249
  • 10
  • 91
  • 131
  • But I can use gcc to build a window programe with `main`,why can't `cmake`? BTW,can you elaborate what's a propper `WinMain` function? I've tried to change `main` to `WinMain` but still not working. – Gtker May 02 '10 at 08:06
  • `int main(int, char **)` is the console version of the entry point. `int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)` is the windowed version of the entry point. – Blindy May 02 '10 at 08:12
  • About your first question, cmake does exactly what you tell it to do. You shouldn't ask "why can't cmake?", you should ask "why can't I tell cmake to ...?". – Blindy May 02 '10 at 08:14
2

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.

legends2k
  • 31,634
  • 25
  • 118
  • 222
1

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})
Michael Aaron Safyan
  • 93,612
  • 16
  • 138
  • 200
  • Thanks.I've tried your 2 solutions,but none work.The first still generates a console,and the second reports: `cl : Command line warning D9002 : ignoring unknown option '-mwindows'` – Gtker May 02 '10 at 08:11
  • @Michael Aaron Safyan, I've pasted the code above,can you take a look? – Gtker May 02 '10 at 08:23
  • @Runner, sorry, but I don't have a copy of Windows on which to test... I am familiar with CMake, but not so much with Windows. Perhaps if you could show me documentation for the "-mwindows" flag, though, I might be able to figure out the CMake equivalent. – Michael Aaron Safyan May 02 '10 at 16:02
  • I'm not familiar with that flag too,but someone gives this link: http://msdn.microsoft.com/en-us/library/fcc1zstk%28VS.71%29.aspx – Gtker May 02 '10 at 16:08