在 Xcode 8 中创建 wxWidgets 的工程

wxWidgets 的文档太老了,相应的指引根本无法使用。经过一番摸索,终于找到了在 Xcode 中创建 wxWidgets 的工程。

前提条件

Homebrew

1
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

wxWidgets

1
$ brew install wxwidgets

开始创建工程

  1. 打开 Xcode -> “Create a new Xcode project”
    Create a new Xcode project

    注意要选择 “Cocoa Application”。我一开始选了 “Command Line Tool” ,虽然也能正常跑出来界面,但生成的只是一个可执行文件,而不是 Application Bundle 。这样一来就无法定制程序的图标和一些其它的行为。

  2. 语言选 Objective C ,其它的勾全部清空。
    Set up project

  1. Build Settings -> Other Linker Flags

    打开 Terminal 输入

    1
    wx-config --libs

    将输出的内容添加到:
    Other Linker Flags

  2. Build Settings -> Other C++ Flags

    打开 Terminal 输入

    1
    wx-config --cxxflags

    将输出的内容添加到 “Ohter C++ Flags”

  3. 把没用的文件删除:
    Delete useless files
    其中 Assets.xcassets 是用来放图标的,要留着。MainMenu.xib 是程序菜单,不需要可以删除掉。

  4. wxWidgets 的 Hello world 测试一下。
    new file
    新建一个 main.cpp ,粘贴:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    // wxWidgets "Hello world" Program
    // For compilers that support precompilation, includes "wx/wx.h".
    #include <wx/wxprec.h>
    #ifndef WX_PRECOMP
    #include <wx/wx.h>
    #endif
    class MyApp: public wxApp
    {
    public:
    virtual bool OnInit();
    };
    class MyFrame: public wxFrame
    {
    public:
    MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
    private:
    void OnHello(wxCommandEvent& event);
    void OnExit(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);
    wxDECLARE_EVENT_TABLE();
    };
    enum
    {
    ID_Hello = 1
    };
    wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(ID_Hello, MyFrame::OnHello)
    EVT_MENU(wxID_EXIT, MyFrame::OnExit)
    EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
    wxEND_EVENT_TABLE()
    wxIMPLEMENT_APP(MyApp);
    bool MyApp::OnInit()
    {
    MyFrame *frame = new MyFrame( "Hello World", wxPoint(50, 50), wxSize(450, 340) );
    frame->Show( true );
    return true;
    }
    MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
    : wxFrame(NULL, wxID_ANY, title, pos, size)
    {
    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!" );
    }
    void MyFrame::OnExit(wxCommandEvent& event)
    {
    Close( true );
    }
    void MyFrame::OnAbout(wxCommandEvent& event)
    {
    wxMessageBox( "This is a wxWidgets' Hello world sample",
    "About Hello World", wxOK | wxICON_INFORMATION );
    }
    void MyFrame::OnHello(wxCommandEvent& event)
    {
    wxLogMessage("Hello world from wxWidgets!");
    }

    7, 点击运行,一切 OK 就可以开始愉快地编程了。

Ubuntu 下配置基于 Nginx/Openresty 自动化 Let's encrypt 证书申请、更新

简述

趁着年底有点时间,把自己的服务器操作系统升级到了 16.04 。Let’s Encrypt 是早就听说过,只是一直没时间搞。前两天听朋友讲到在 nginx/openresty 下有自动化的 lua 脚本可以实现自动化的申请和证书更新,感觉非常有意思,顺便折腾了一把。

过程

Openresty

Openresty 是在 nginx core 的基础上集成了 LuaJIT 和许多第三方的 nginx 模块。除了 nginx 本身具备的功能外,还可以用来做 web application,web service。利用 lua 可以直接在 Openresty 里面构建动态服务。目前官方只提供 RPM 的预编译包,其它操作系统需要自行编译。 官方的安装说明 简明易懂,直接照猫画虎即可。

接下来要配置 systemd ,让 Openresty 可以自动启动。

1
$ sudo vim /etc/systemd/system/nginx.service

nginx.service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Unit]
Description=The nginx HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/usr/local/openresty/nginx/logs/nginx.pid
ExecStartPre=/usr/local/openresty/nginx/sbin/nginx -t
ExecStart=/usr/local/openresty/nginx/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

启用:

1
2
$ sudo systemctl enable nginx
$ sudo systemctl start nginx

附上几个调试技巧:

  • 通过 systemctl status nginx 可以看到 nginx 是不是正常启动了。若是失败这里也会输出用的日志信息,可以按左右键对界面进行横向滚动
  • 需要看到更多日志可以使用 journalctl -b _PID=上一步中输出的PID 查看更多的信息。
  • 通过 curl http://localhost 确认 nginx 已经可以正常工作。

LuaRocks

这个 lua 的包管理器,相当于 node.js 的 npm 。安装的方法 点这里 。 上面推荐安装的版本是 2.0.13 。但我装的是当时最新的 2.4.2 ,也许是这个原因导致我后面配置 lua-resty-auto-ssl 的时候踩了坑?

lua-resty-auto-ssl

装完 LuaRocks 之后,首先要配置一下 PATH,在 ~/.profile 中加入:

1
export PATH=/usr/local/openresty/luajit/bin:/usr/local/openresty/bin:/usr/local/openresty/nginx/sbin:$PATH


1
source ~/.profile

然后就可以使用它来安装 lua-resty-auto-ssl 了:

1
2
3
4
5
6
$ sudo luarocks install lua-resty-auto-ssl

# Create /etc/resty-auto-ssl and make sure it's writable by whichever user your
# nginx workers run as (in this example, "www-data").
$ sudo mkdir /etc/resty-auto-ssl
$ sudo chown www-data /etc/resty-auto-ssl

修正 lua-resty-auto-ssl 的脚本权限问题

1
2
$ sudo chmod +x /usr/local/openresty/luajit/share/lua/5.1/resty/auto-ssl/shell/*
$ sudo chmod +x /usr/local/openresty/luajit/share/lua/5.1/resty/auto-ssl/vendor/*

这就是上面我提到的坑,也许是 LuaRocks 的问题,也许不是。如果你找到了原因,欢迎 comment 给我,谢谢哈。

在 Openresty 中配置 lua-resty-auto-ssl

nginx 的 ssl 站点需要先指定一个静态的 ssl_certificate, 否则会报错,因此需要生成一个自签的证书,骗过 nginx 让它顺利启动之后,再由 lua-resty-auto-ssl 返回动态的证书。

1
2
3
4
$ sudo openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 \
-subj '/CN=sni-support-required-for-valid-ssl' \
-keyout /etc/ssl/resty-auto-ssl-fallback.key \
-out /etc/ssl/resty-auto-ssl-fallback.crt

我习惯于将全局配置就放到 nginx.conf 里面,每个虚拟主机、网站或说应用独立一个配置文件 example.com.vh.conf 这样。

nginx 的全局配置 /usr/local/openresty/nginx/conf/nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
http {
# 配置 lua-resty-auto-ssl 的全局选项,并启动服务
lua_shared_dict auto_ssl 1m;
resolver 8.8.8.8;

init_by_lua_block {
auto_ssl = (require "resty.auto-ssl").new()

# 这里你可以限定只给那些域名启用 auto ssl
auto_ssl:set("allow_domain", function(domain)
return true
end)

auto_ssl:init()
}

init_worker_by_lua_block {
auto_ssl:init_worker()
}

server {
listen 127.0.0.1:8999;
location / {
content_by_lua_block {
auto_ssl:hook_server()
}
}
}

include /path/to/example.com.vh.conf;
}

example.com.vh.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
server {
listen 80;
server_name example.com;

# Let's Encrypt 需要验证你对域名的控制权,这个就是用来应答的.
location /.well-known/acme-challenge/ {
content_by_lua_block {
auto_ssl:challenge_server()
}
}
}

server {
listen 443 ssl;
server_name example.com;

# lua-resty-auto-ssl 的精华部份,若当前还没有证书或已过期则自动申请,然后返回,证书有效就直接返回
ssl_certificate_by_lua_block {
auto_ssl:ssl_certificate()
}

# 这里配上之前我们生成的自签名证书,否则会报错
ssl_certificate /etc/ssl/resty-auto-ssl-fallback.crt;
ssl_certificate_key /etc/ssl/resty-auto-ssl-fallback.key;
}

我主要是演示这些配置放在哪些地方,参数的意义可以在 lua-resty-auto-ssl 主页上查询。

以上配置完成重启 nginx ,接着就可以看看 auto ssl 是否能正常工作了:

1
2
$ sudo systemctl restart nginx
$ curl https://example.com

若有错误,可以查看 nginx 的 error log, lua-resty-auto-ssl 会将错误信息输出到这上面。

总结

虽然早有 CertBot 这样的自动化工具,但 lua-resty-auto-ssl 显然是更加地方便,在新建站点的时候多加几行即可实现全自动化的 https 。