如何为 gtkmm 应用程序创建 CMakeLists.txt?

How to create a CMakeLists.txt for a gtkmm application?

我的应用树如下:

├── build
├── CMakeLists.txt
├── example
│   ├── applicationwindow.cpp
│   ├── applicationwindow.h
│   └── Application.glade
└── main.cpp

2 directories, 5 files

而我创建的CMakeLists.txt文件如下:

cmake_minimum_required(VERSION 3.1.0)
project(Example_App)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

find_package(PkgConfig)
pkg_check_modules(GTKMM gtkmm-3.0)

include_directories(${GTKMM_INCLUDE_DIRS})
link_directories(${GTKMM_LIBRARY_DIRS})

set(SOURCE_FILES main.cpp)
add_executable(${CMAKE_PROJECT_NAME} ${SOURCE_FILES} example/applicationwindow.cpp)
target_link_libraries(${CMAKE_PROJECT_NAME} ${GTKMM_LIBRARIES})

在成功 cmake ..make 之后,当我执行应用程序时出现以下错误:

terminate called after throwing an instance of 'Glib::FileError'
Aborted (core dumped)

我试过用 Makefile 构建它,但这似乎没有任何问题。我也尝试调查 Glib::FileError 但是,我无法提取问题的确切原因。在像这里表示的这个例子这样的更简单的实例上尝试类似的 CMakeLists:Gtkmm Example of a Application Window

然而它似乎有效。这里的确切问题可能是什么?

当你想在你的程序中有一个名为 file.glade 的文件(这个文件可以是 file.png 等任何东西),它位于资源目​​录中,你必须首先在程序构建目录中输入它,然后将以下代码添加到您的 CMakeList.txt:

file(COPY resource DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

resource 是包含 file.glade 的目录,其名称可以是您想要的任何名称。在您的代码中:

auto builder = Gtk::Builder::create_from_file("resource/file.glade");

由于您似乎是 CMake 的新手,我将围绕 mohamadp91 提供的答案添加一些代码。

你的问题是,当你 运行 正在 cmake .. 时,Application.glade 文件永远不会复制到 build 目录,当你 运行 make 并执行您的软件。此时,应用程序尝试加载 build/example/Application.glade 文件,但未找到任何文件,您收到错误消息。

使用纯 Makefile 时不会发生这种情况,因为您没有在 build 中构建目录,而是直接在 example 目录旁边。然后应用程序可以找到 Glade 文件。

我做了一个小例子来重现你的问题。它具有相同的目录结构:

├── build
├── CMakeLists.txt
├── example
│   ├── CMakeLists.txt
│   └── Application.glade
└── main.cpp

它只有一个 main.cpp 文件,它试图在 example 下加载资源(在本例中为 Glade 文件,就像你一样)。这是 C++ 代码:

#include <iostream>
#include <gtkmm.h>

constexpr int FILE_ERROR    = 1;
constexpr int MARKUP_ERROR  = 2;
constexpr int BUILDER_ERROR = 3;

Gtk::ApplicationWindow* window = nullptr;

int main(int argc, char **argv)
{
    auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example");
    auto builder = Gtk::Builder::create();

    try
    {
        // Try to use Application.glade:
        builder->add_from_file("example/Application.glade");
    }
    catch(const Glib::FileError& ex)
    {
      // This was your case, because the Application.glade file could
      // not be located:
      std::cout << "File error :" << ex.what() << std::endl;
      return FILE_ERROR;
    }
    catch(const Glib::MarkupError& ex)
    {
      std::cout << "Markup error :" << ex.what() << std::endl;
      return MARKUP_ERROR;
    }
    catch(const Gtk::BuilderError& ex)
    {
      std::cout << "Builder error :" << ex.what() << std::endl;
      return BUILDER_ERROR;
    }

    //Get the GtkBuilder-instantiated Dialog:
    builder->get_widget("MainWindow", window);

    if(window)
    {
        app->run(*window);
    }

    delete window;

    return 0;
}

该示例显示了如何捕获 Glib::FileError 异常并避免段错误。 Glade 文件很简单,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.2 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkApplicationWindow" id="MainWindow">
    <property name="can_focus">False</property>
    <child type="titlebar">
      <placeholder/>
    </child>
    <child>
      <object class="GtkButton" id="MainButton">
        <property name="label" translatable="yes">Hello World</property>
        <property name="visible">True</property>
        <property name="can_focus">True</property>
        <property name="receives_default">True</property>
      </object>
    </child>
  </object>
</interface>

在顶级目录中,我使用 add_subdirectory 命令告诉 CMake 进入 example 子目录并处理位于那里的 CMakeLists.txt 文件:

cmake_minimum_required(VERSION 3.1.0)
project(Example_App)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

find_package(PkgConfig)
pkg_check_modules(GTKMM gtkmm-3.0)

include_directories(${GTKMM_INCLUDE_DIRS})
link_directories(${GTKMM_LIBRARY_DIRS})

set(SOURCE_FILES main.cpp)
add_executable(${CMAKE_PROJECT_NAME} ${SOURCE_FILES} main.cpp)
target_link_libraries(${CMAKE_PROJECT_NAME} ${GTKMM_LIBRARIES})

# CMake is gonna read the 'CMakeLists.txt' file located under 'example':
add_subdirectory(example)

在该文件中,我只是将构建目录中example下的Application.glade文件复制:

file(COPY Application.glade DESTINATION ${CMAKE_CURRENT_BINARY_DIR})