使用Rust + Electron开发跨平台桌面应用 ( 一 )

前言

近段时间学习了Rust,一直想着作点什么东西深刻学习,由于是刚学习,不少地方都不熟悉,因此也就不能拿它来作编译器这些,至于web开发,实际上我并不建议拿这个来学习一门语言,大概有几个方面,一是web开发的套路无非也就那么几个,对学习一门语言并不会有多大的帮助。二是web开发大多已经被封装了不少东西,对学习语言自己其实不利,真的要深刻学习的话仍是建议从语言自己出发,尽可能不要用封装好的东西,固然,标准库除外。html

为何是Rust + Electron

缘由其实很简单,我不想作太复杂的东西,由于大部分的精力仍是要放在工做上,其次是但愿作一个我平常能用的东西,固然如今还没想好,多是个音乐播放器,也多是个天气展现的app,这样我就能够天天使用了,这也会更有动力促使我开发好它。node

Rust 和 Electron 想必就不用我多介绍了吧,至于为何是这个组合能够查看知乎的这个问题,我赞同的是的方案是python

使用 C/Cpp/Rust 开发的核心 + Electron / Qt 开发界面

本期目标

本期的目标很是简单,将Rust 和 Electron结合起来,使用Rust获取电脑cpu核数,Electron将数据绘制在界面上展现。git

初始化Electron项目

Electron项目的初始化我用的工具是electron-forge,首先咱们按照electron-forge的官网介绍来github

npm install -g electron-forge

electron-forge init my-new-project

cd my-new-project

electron-forge start

解释一下,首先咱们要安装electron-forge,这是一个脚手架工具,相似于Vue-cli。
而后咱们初始化一个项目,项目名称为my-new-project。web

须要注意的是这初始化的过程当中electron-forge会构建package.json, 而后下载依赖,我第一次下载依赖的时候卡在了electron-runtime,第二次重试的时候就行了。npm

第二个是electron-forge中的依赖会对Python版本有要求,只能要求Python2,这里要注意的一点是,我十分不建议使用pyenv来控制Python版本,会出现如下错误,个人解决方式是使用virtualenv新建一个Python2 的环境。json

Fatal Python error: PyThreadState_Get: no current thread

如今咱们来看一下项目结构app

clipboard.png

整个项目结构很是简单,src中是咱们的源文件,index.html是界面文件,index.js是界面逻辑文件,你们打开index.js就能够看到一段自动生成的代码,主要是建立了一个app,以及监听app的活动,须要注意到的是其中对mac的处理。electron

app.on('window-all-closed', () => {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

好了,如今让咱们把项目跑起来,在项目目录下执行electron-forge start命令,稍等一会咱们就能够看到界面运行起来了

clipboard.png

初始化Rust项目

在开发以前咱们要知道,JS是没法直接运行Rust的,就像JS没法直接运行C++同样。因此咱们须要将Rust打包成Node模块提供给JS进行调用。因此咱们会使用neon来作到这件事,neon的github地址在这里

首先咱们须要安装neon,注意,neon对python版本也是有要求的,若是你是mac,python版本必需要是Python2.7,不支持Python3,一样,这里也会出现上面说过的no current thread问题,因此咱们在开发时最好用virtualenv新建一个Python2的环境。

安装完neon以后咱们执行neon new thread-count,新建一个项目。看一下项目结构

clipboard.png

lib是咱们最终的导出文件,提供给electron进行调用,native下则是咱们的rust代码,注意,这里的入口文件是native/src/lib.rs,由于咱们创建的是一个库而不是一个可执行的应用程序。
让咱们先编译项目,在文件目录下执行neon build --release命令。

让咱们进入终端调用一下项目试试:

clipboard.png

成功!到如今咱们就成功的将rust写的代码封装成node库,使得JS能够进行调用了,接下来咱们回到上面说过的,将rust的功能更改成获取CPU核数,而后将它封装成一个函数并进行导出。

首先咱们要修改Cargo.toml,在[dependencies]下增长一个num_cpus = "1.4.0"的依赖项,
而后修改native/src/lib.rs文件以下

#[macro_use]
extern crate neon;

use neon::prelude::*;

fn thread_count(mut cx: FunctionContext) -> JsResult<JsNumber> {
    Ok(cx.number(num_cpus::get() as f64))
}

register_module!(mut cx, {
    cx.export_function("thread_count", thread_count)
});

修改lib/index.js以下:

var addon = require('../native');

module.exports = addon.thread_count;

而后咱们再进行编译,执行neon build --release命令,而后再进入终端调用这个函数试试

clipboard.png

成功啦,至此,咱们就成功的将rust代码封装给JS进行了调用。须要注意的是编译rust的node版本须要与运行electron的node版本一致,不然会出现没法调用的状况。好了,到此第一期就结束了,代码我会抽空整理到github,以供有须要的同窗查看。

效果

最后看一下效果图吧

clipboard.png

ps: 如今Rust的各项工具和库都不是很成熟,因此你们再实践过程当中会遇到各类问题,均可以评论到下面你们一块儿讨论。