Andrew Moa Blog Site

Msys2工具链静态编译方法

静态编译的好处是发布的时候不用带上一堆动态链接库。Msys2工具链理论上是支持静态编译的,但实际使用的时候即使直接加上-static开关,链接生成的可执行文件最后运行时还是会提示缺失动态链接库,尤其是Mingw工具链依赖的libwinpthread-1.dlllibstdc++-6.dlllibgcc_s_seh-1.dll这"三大件"。而对于clang编译器,运行时依赖又变成了libc++.dll。本文探讨一种简便的办法,方便针对不同编译器的静态链接编译管理。

1. FLTK项目静态编译

这里用FLTK实现一个简单的窗口应用,FLTK的LICENSE支持发布静态链接版本的程序,而且生成的程序体积非常小,用来编写和发布小工具十分方便。

// --- mian.cpp ---

#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
#include <FL/fl_ask.H>

class SimpleWindow : public Fl_Window
{
private:
    Fl_Button *button;

public:
    SimpleWindow(int w, int h, const char *title) : Fl_Window(w, h, title)
    {
        color(FL_WHITE);
        button = new Fl_Button(w / 2 - 50, h / 2 - 20, 100, 40, "Click Me!");
        button->color(FL_BLUE);
        button->labelcolor(FL_WHITE);
        button->callback([](Fl_Widget *w, void *data)
                         { 
                            fl_message_title("Click Me!");
                            fl_message("You clicked the button!"); }, NULL);
        end();
    }
};
int main(int argc, char **argv)
{
    SimpleWindow window(400, 300, "FLTK Simple Window");
    window.show(argc, argv);
    return Fl::run();
}

msys2安装的FLTK提供了fltk-config工具用于配置和编译FLTK项目源码,使用该工具可以很方便地将FLTK项目的cpp源码编译成可执行文件。

fltk-config --compile main.cpp --link -static

--link -static表示链接静态库,运行效果如下图所示。

5f13ec9d82726c88e3d8f6fbc4cf90c6.png

阅读时长2分钟
Andrew Moa

Lambda表达式处理事件回调函数

C++11开始支持Lambda表达式,Lambda表达式除了可以作为匿名函数使用,还可以通过捕获列表访问环境中的变量。在UI编程中使用Lambda表达式替代传统的函数指针处理回调函数,不仅可以简化代码提高可读性,还可以减少参数传递提高灵活性。下面针对常用的C++ UI库尝试实现相关操作。

1. wxWidgets事件绑定

1.1 wxWidgets事件机制

wxWidgets有两套事件机制,一套是静态的事件表1,另一套是动态事件机制2。动态事件提供了两套API,分别是Connect()Bind()3,后者较新,前者已经淘汰。

实际上Bind()是原生支持Lambda表达式的,我们可以将官方文档的示例代码4改写如下。

// --- main.cpp ---

#include <wx/wx.h>

enum
{
    ID_Hello = 1
};

class MyFrame : public wxFrame
{
public:
    MyFrame()
        : wxFrame(nullptr, wxID_ANY, "Hello World")
    {
        wxMenu *menuFile = new wxMenu;
        menuFile->Append(ID_Hello, "&Hello...\tCtrl-H",
                         "Help string shown in status bar for this menu item");
        menuFile->AppendSeparator();
        menuFile->Append(wxID_EXIT);

        wxMenu *menuHelp = new wxMenu;
        menuHelp->Append(wxID_ABOUT);

        wxMenuBar *menuBar = new wxMenuBar;
        menuBar->Append(menuFile, "&File");
        menuBar->Append(menuHelp, "&Help");

        SetMenuBar(menuBar);

        CreateStatusBar();
        SetStatusText("Welcome to wxWidgets!");

        Bind(wxEVT_MENU, [](wxCommandEvent &event)
             { wxLogMessage("Hello world from wxWidgets!"); }, ID_Hello);
        Bind(wxEVT_MENU, [](wxCommandEvent &event)
             { wxMessageBox("This is a wxWidgets Hello World example",
                            "About Hello World", wxOK | wxICON_INFORMATION); }, wxID_ABOUT);
        Bind(wxEVT_MENU, [this](wxCommandEvent &event)
             { this->Close(true); }, wxID_EXIT);
    }
};

class MyApp : public wxApp
{
public:
    bool OnInit() override
    {
        MyFrame *frame = new MyFrame();
        frame->Show(true);
        return true;
    }
};

wxIMPLEMENT_APP(MyApp);

注意Bind()函数传入的参数个数,这里不再需要传入this指针。使用Lambda表达式改写之后窗口类的成员函数基本不需要定义,需要调用对象自身的方法执行特定操作时(比如执行关闭窗口操作),可以通过捕获列表获取对象的this指针。

阅读时长11分钟
Andrew Moa