Sambatyon
Sambatyon

Reputation: 3374

Qt + CMake + VC++ produce a command prompt

I am using the combination mentioned in the title while trying to run the window layout example from the qt tutorials. The main looks like this:

#include <QtGui>

int main(int argc, char **argv) {
  QApplication app(argc, argv);
  QWidget window;
  QLabel *label = new QLabel(QApplication::translate("windowlayout", "Name:"));
  QLineEdit *lineEdit = new QLineEdit();

  QHBoxLayout *layout = new QHBoxLayout();
  layout->addWidget(label);
  layout->addWidget(lineEdit);
  window.setLayout(layout);
  window.setWindowTitle(
      QApplication::translate("windowlayout", "Window layout"));
  window.show();
  return app.exec();
}

And the CMakeLists.txt like this:

PROJECT(test)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0)

FIND_PACKAGE(Qt4 REQUIRED)
INCLUDE_DIRECTORIES(${QT_INCLUDE_DIR} ${QT_QTCORE_INCLUDE_DIR} ${QT_QTGUI_INCLUDE_DIR})

SET(test_SRCS main.cc)

QT4_AUTOMOC(${test_SRCS})

ADD_EXECUTABLE(test ${test_SRCS})

TARGET_LINK_LIBRARIES(test ${QT_QTGUI_LIBRARIES} ${QT_QTCORE_LIBRARIES})

The building and compilation work properly but when I run the application, it always show a command prompt. How do I avoid that?

Upvotes: 1

Views: 5038

Answers (4)

SHERIF OMRAN
SHERIF OMRAN

Reputation: 167

in the pro file, remove the following console definition and it will go

CONFIG += console

Upvotes: -1

Antwane
Antwane

Reputation: 22608

In your CMakeFile with Qt4, you don't need to change your CPP code or to add flags at compile time. Simply use

set(QT_USE_QTMAIN TRUE)

It will automatically link qtmain.lib with your executable. This library defines other common main() signatures, including WinMain().

With this trick, your app can compile with MSVC under Windows, without mofiying your original main() function and without displaying a console when you run your app outside of your IDE (QtCreator for example).

Final resulting CMakeLists.txt can be :

PROJECT(test)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0)

FIND_PACKAGE(Qt4 REQUIRED)
if(WIN32)
    SET(QT_USE_QTMAIN TRUE)
endif(WIN32)

INCLUDE(${QT_USE_FILE})

SET(test_SRCS main.cc)

QT4_AUTOMOC(${test_SRCS})

ADD_EXECUTABLE(test ${test_SRCS})

TARGET_LINK_LIBRARIES(test ${QT_LIBRARIES})

Additionnaly, you don't need to include QtCore and QtGui, they are included by default with QT_USE_FILE (for include folders) and QT_LIBRARIES (for libraries).

You only have to set what modules you use, or you don't use (for Gui) :

# Use Network and Sql modules
set(QT_USE_QTNETWORK TRUE)
set(QT_USE_QTSQL TRUE)
# Do not use Gui module
set(QT_DONT_USE_QTGUI TRUE)

Upvotes: 4

FuNkDaDdY
FuNkDaDdY

Reputation: 71

I wanted a release build to hide the console but all other builds to show it. To do that use:

if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
    SET_TARGET_PROPERTIES(MyApp PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
    SET_TARGET_PROPERTIES(MyApp PROPERTIES RELWITHDEBINFO "/SUBSYSTEM:CONSOLE")
    SET_TARGET_PROPERTIES(MyApp PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
    SET_TARGET_PROPERTIES(MyApp PROPERTIES MINSIZEREL "/SUBSYSTEM:WINDOWS")
endif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")

This will introduce the following linker error: error LNK2019: unresolved external symbol _WinMain@16 referenced in function ___tmainCRTStartup

to fix it link with QT_QTMAIN_LIBRARY in your CMakeLists.txt file

TARGET_LINK_LIBRARIES(MyApp ${QT_LIBRARIES} ${QT_QTMAIN_LIBRARY} ${OTHER_STUFF_TO_LINK})

Now you don't even have to change your sources as was done in the previous solution.

Upvotes: 6

ComicSansMS
ComicSansMS

Reputation: 54589

You need to tell CMake that you want a GUI application:

 # GUI Type
 if(WIN32)
   set(GUI_TYPE WIN32)
 endif(WIN32)
 if(APPLE)
   set(GUI_TYPE MACOSX_BUNDLE)
 endif(APPLE)

 ADD_EXECUTABLE(test ${GUI_TYPE} ${test_SRCS})

Note that when you are compiling on Windows, this will change the program entry from main() to WinMain(), so you will need to modify your sources as well. Here's what I usually do:

#ifdef _WIN32
class Win32CommandLineConverter;

int CALLBACK WinMain(HINSTANCE /* hInstance */, HINSTANCE /* hPrevInstance */, LPSTR /* lpCmdLine */, int /* nCmdShow */)
{
    Win32CommandLineConverter cmd_line;
    return main(cmd_line.argc(), cmd_line.argv());
}


class Win32CommandLineConverter {
private:
    std::unique_ptr<char*[]> argv_;
    std::vector<std::unique_ptr<char[]>> storage_;
public:
    Win32CommandLineConverter()
    {
        LPWSTR cmd_line = GetCommandLineW();
        int argc;
        LPWSTR* w_argv = CommandLineToArgvW(cmd_line, &argc);
        argv_ = std::unique_ptr<char*[]>(new char*[argc]);
        storage_.reserve(argc);
        for(int i=0; i<argc; ++i) {
            storage_.push_back(ConvertWArg(w_argv[i]));
            argv_[i] = storage_.back().get();
        }
        LocalFree(w_argv);
    }
    int argc() const
    {
        return static_cast<int>(storage_.size());
    }
    char** argv() const
    {
        return argv_.get();
    }
    static std::unique_ptr<char[]> ConvertWArg(LPWSTR w_arg)
    {
        int size = WideCharToMultiByte(CP_UTF8, 0, w_arg, -1, nullptr, 0, nullptr, nullptr);
        std::unique_ptr<char[]> ret(new char[size]);
        WideCharToMultiByte(CP_UTF8, 0, w_arg, -1, ret.get(), size, nullptr, nullptr);
        return ret;
    }
};
#endif

Upvotes: 8

Related Questions