创建一个CMake+GTK的项目,并配置vscode+GDB调试
概述
通过一步步创建一个基于C语言和CMake的GTK项目,来熟悉一个C语言项目的创建过程和最基本的项目结构。 之后会配置一套基于GDB和vscode的调试环境,并简单讲一下如何在这种调试环境下调试代码
编写CMakeLists.txt
指定cmake的最小版本,我本地安装的是3.26的版本,所以这边就设置为3.10了,像3.10往上的版本都不会有什么问题
scss
cmake_minimum_required(VERSION 3.10)
配置项目名称
scss
project(GTKCTest)
project命令中除了可以配置项目的名称,还可以配置项目的语言环境、版本、说明信息以及官方首页地址
配置C语言标准版本以及cmake执行时的调试参数
swift
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_FLAGS "-Wall -g -O0")
set函数是在配置本次运行时的环境变量 这里配置了CMAKE_C_STANDARD和CMAKE_C_FLAGS两个环境变量 CMAKE_C_STANDARD是使用C编译时,使用的C的标准版本,这里指定了这个项目所使用的C语言的标准版本为99 CMAKE_C_FLAGS是使用C编译时,使用的编译器选项, -Wall是指编译C语言代码时启用所有的警告, -g告诉C语言编译器在编译时生成调试信息, -O0是在告诉C语言编译器在编译时不要做优化处理,禁止编译器进行编译过程中的优化,是为了能在调试时看到更清晰的代码
接下来是配置包管理器和依赖包
scss
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
这里我们先声明了包管理器PkgConfig是必要的依赖 然后我们用PkgConfig去检查本地开发环境时是否有安装3.0版本的gtk+依赖包
接下来配置依赖包头文件、连接库和依赖包需要的编译器选项
scss
include_directories(${GTK3_INCLUDE_DIRS})
link_directories(${GTK3_LIBRARY_DIRS})
add_definitions(${GTK3_CFLAGS_OTHER})
这里我们配置了GTK3的头文件地址、连接库地址、和编译器选项 除了依赖包的头文件地址需要配置,我们项目中的依赖库地址也要配置 比如我们在项目中创建一个src/include路径,在这个路径下放我们所有的依赖包 就可以这样配置一下
scss
include_directories(src/include)
接下来我们使用file方法,将src目录下的所有c文件,都添加到一个变量中 并且我们要用GLOB_RECURSE参数,来指定使用递归方式来进行文件匹配
erlang
file(GLOB_RECURSE SOURCES "src/*.c" "src/**/*.c")
这样我们就把src下所有的c文件都写入了SOURCES变量,之后我们就可以使用SOURCES变量来编译
scss
add_executable(GTKCTest ${SOURCES})
这里的GTKCTest是我们编译出来的可执行文件的名称
最后,我们把GTK3的库链接到编译产物身上
scss
target_link_libraries(GTKCTest ${GTK3_LIBRARIES})
到这我们的CMakeLists.txt文件就差不多了, 然后接下来我们就可以开始写代码
编写main.c和main.h
我们在src目录下创建了main.c并在src/include目录下创建了main.h文件
首先我们先在main.h中创建头文件保护,并引入gtk
arduino
#ifndef MAIN_H
#define MAIN_H
#include <gtk/gtk.h>
#endif
MAIN_H是我们创建的一个全局变量,他用来保护这个头文件中的声明不被多次执行,避免造成内存上的浪费
接下来我们开始编写main.c文件,在main.c文件中,我们先引入main.h 接着创建一个主函数,并在主函数中创建GTK窗口,在窗口关闭之后退出程序
scss
#include "main.h"
static void on_window_closed(GtkWidget* widget, gpointer data)
{
g_print("Window is closed\n");
gtk_main_quit();
}
int main(int args, char** argv)
{
gtk_init(&args, &argv);
GtkWidget* main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(main_window), "Hello World!");
gtk_window_set_default_size(GTK_WINDOW(main_window), 800, 600);
g_signal_connect(G_OBJECT(main_window), "delete_event", G_CALLBACK(on_window_closed), NULL);
gtk_widget_show(GTK_WIDGET(main_window));
gtk_main();
return 0;
}
然后我们在项目目录下创建build目录,cd到build下,执行cmake..,再执行make 我们就可以在build目录下找到编译生成的GTKCTest可执行文件了,运行他就可以看到我们创建的窗口了,并且在窗口关闭之后可以看到程序进程也退出了 接下来我们可以把一些变量放在头文件中声明以及定义,然后在c文件中使用,比如像窗口的标题、尺寸以及窗口本身,我们都可以放在h文件中声明,标题和尺寸则可以直接在h文件中定义赋值。
ini
char *MAIN_WINDOW_TITLE = "Hello World!";
int MAIN_WINDOW_WIDTH = 800;
int MAIN_WINDOW_HEIGHT = 600;
GtkWidget* MAIN_WINDOW;
scss
MAIN_WINDOW = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(MAIN_WINDOW), MAIN_WINDOW_TITLE);
gtk_window_set_default_size(GTK_WINDOW(MAIN_WINDOW), MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT);
g_signal_connect(G_OBJECT(MAIN_WINDOW), "delete_event", G_CALLBACK(on_window_closed), NULL);
gtk_widget_show(GTK_WIDGET(MAIN_WINDOW));
这样做的好处呢,就是我们以后如果要在其他的c文件中去写一些需要用到窗口属性,或者需要控制窗口的逻辑时,我们就可以直接把这些变量引入进来,直接去使用或者重新赋值。
配置vscode gdb调试环境
如果我们每次都从命令行中执行编译、启动命令,就感觉有点繁琐,那我们可以利用vscode的launch,来做一些自动化的配置 首先我们先在项目的根目录下创建一个.vsocde文件夹,并在文件夹下创建launch.json和tasks.json两个文件 首先我们先在tasks.json文件中配置cmake和make的任务
bash
{
"version": "2.0.0",
"tasks": [
{
"label": "cmake",
"options": {
"cwd": "${workspaceFolder}/build"
},
"type": "shell",
"command": "cmake .."
},
{
"label": "make",
"options": {
"cwd": "${workspaceFolder}/build"
},
"type": "shell",
"command": "make",
"dependsOn": ["cmake"]
}
]
}
这里我们用了dependsOn属性,让make执行时,先去执行cmake 接着我们来编写launch.json文件,我们先写一个RUN的launch,确保我们的task和程序都可以正常运行
bash
{
"version": "0.2.0",
"configurations": [
{
"name": "RUN",
"type": "cppdbg",
"request": "launch",
"cwd": "${workspaceFolder}/build",
"program": "${workspaceFolder}/build/GTKCTest",
"preLaunchTask": "make"
}
]
}
这里我们用preLaunchTask告诉vscode,执行这个launch之前,先执行make的任务,这样就可以把cmake、make、run连成一条线 接着我们在vscode的Run and Debug中找到刚才编写的Run Launch 然后运行一下 程序可以正常运行 接着我们在写一个GDB的Launch
bash
{
"name": "GDB",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/GTKCTest",
"args": [],
"stopAtEntry": true,
"cwd": "${workspaceFolder}/build",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb",
"preLaunchTask": "make"
}
这里同样指定了preLaunchTask为make 同时也是用了MIMode和miDebuggerPath,指定了gdb作为我们的调试工具 之后我们就可以使用vscode来调试我们的Gtk项目了