全部文章

<p>最近在 QQ 群里看到一个问题:</p> <p><img src="/uploads/qq-node-chart.png" alt="" /></p> <p>这个问题我之前也想过,但是实际的项目没有用到就搁置了。趁今天有时间,就好好研究一下。</p> <h1>选型</h1> <h2>Node.js 如何实现画布?</h2> <p>Node.js 有 npm 包 <a href="https://www.npmjs.com/package/canvas">node-canvas</a></p> <h2>Node.js 如何实现图表?</h2> <ul> <li>用 <a href="https://f2-v3.antv.vision/zh/docs/tutorial/node-env">F2</a>,建议用 v3 版本,因为 v4 之后用 jsx 描述图表,需要配置 babel 转译一下 jsx,有点麻烦。</li> <li>用 <a href="https://g2.antv.antgroup.com/manual/extra-topics/ssr">G2</a></li> </ul> <h1>实现</h1> <p>图表的实现,我选用的是 <code>F2</code>。</p> <p>按照<a href="https://f2-v3.antv.vision/zh/docs/tutorial/node-env">文档</a>一步一步实现。</p> <p>我遇到的问题是: 1、渲染出的 jpg 图片背景色是黑色的,而我需要的是白色背景。</p> <p><img src="/uploads/pie-dark.jpg" alt="" /></p> <p>阅读 F2 的 API 文档,发现可以通过添加一个组来实现,然后把组的 <code>zIndex</code> 设为 <code>-1</code>,然后在组添加一个和画布一样大小的白色的矩形充当白色背景。</p> <p>我把它抽取成一个方法,如下:</p> <pre><code class="language-js">// chart 是一个图表实例 const addBg = (chart) => { const canvas = chart.get("canvas"); const bgGroup = canvas.addGroup({ zIndex: -1, }); const bg = new F2.G.Shape.Rect({ attrs: { x: 0, y: 0, height: canvas.getWidth(), width: canvas.getHeight(), lineWidth: 0, fill: "#fff", strokeStyle: "#000", radius: 0, }, }); bgGroup.add(bg); };</code></pre> <p>调用代码:</p> <pre><code class="language-js">// 省略了一些代码,可以参考官方示例 const chart = new F2.Chart({ context: canvas.getContext("2d"), width, height, animate: false, pixelRatio, }); addBg(chart);</code></pre> <p>最终效果:</p> <p><img src="/uploads/pie-white.jpg" alt="" /></p>
详情
<h1>encodeURI</h1> <p>对统一资源标识符(URI)进行编码。</p> <p>以下字符不会被编码:</p> <table> <thead> <tr> <th>类型</th> <th>包含</th> </tr> </thead> <tbody> <tr> <td>保留字符</td> <td>; , / ? : @ & = + $</td> </tr> <tr> <td>非转义的字符</td> <td>字母 数字 - _ . ! ~ * ' ( )</td> </tr> <tr> <td>数字</td> <td>#</td> </tr> </tbody> </table> <h2>例子</h2> <pre><code class="language-js">const uri = "http://username:password@www.example.com:80/path/to/file.php?foo=316&bar=this+has+spaces#anchor" const encodedUri = encodeURI(uri);</code></pre> <h1>参考</h1> <p><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/encodeURI">encodeURI()</a></p>
详情
<h1>不可变引用</h1> <p>引用 (Reference) – 引用其他数据的不可变指针。</p> <p>当引用指向某个值,我们称为“借用”这个值,因为是被不可变的借用,所以不能被修改,也不能移动。</p> <p>借用一直持续到生命周期结束,即离开作用域。</p> <pre><code class="language-rust">fn main() { let mut a = 4; // 定义变量 a 并赋值为 4 let ref_a: &i32 = &a; // ref_a 借用了 a,ref_a 指向 a。 println!("{}", a); // `a` 还可以继续使用(可读) println!("{}", *ref_a); // 解引用(获取值) a = 3; // 编译报错,因为 a 已被 ref_a 借走了(不可写) *ref_a = 6; // 编译报错,因为 ref_a 是不可变引用 }</code></pre> <h1>可变引用</h1> <p>可变引用 (Mutable reference)。</p> <p>当一个变量被可变地借用时,也不可使用。</p> <pre><code class="language-rust">fn main() { let mut a = 4; // 定义变量 a 并赋值为 4 let ref_a: &mut i32 = &mut a; // ref_a 借用了 a,ref_a 指向 a。之后 a 不可用 println!("{}", a); // 编译报错,a 被可变借用。 println!("{}", *ref_a); // 解引用(获取值) a = 3; // 编译报错,因为 a 已被 ref_a 可变借走了 *ref_a = 6; // 解引用并重新赋值 println!("{}", *ref_a); // 解引用(获取值) }</code></pre> <h1>参考</h1> <p><a href="https://learnxinyminutes.com/docs/zh-cn/rust-cn/">Y分钟速成X其中 X=Rust</a></p>
详情
<p>接上一篇<a href="/web-print-requirement.html">Web 打印服务之需求篇</a>,这篇主要关注实现过程。</p> <h1>1、用最熟悉的技术栈 Electron 初探</h1> <p>一开始是用 Electron 来做,做完之后发现有几个问题:</p> <ul> <li>安装包太大</li> <li>很容易被抄袭(源码无法保护)</li> </ul> <h1>2、追求安装包最小 Slint</h1> <p>后来尝试用 slint(Slint is a declarative GUI toolkit to build native user interfaces for Rust, C++, or JavaScript apps.)</p> <p>遇到的问题:</p> <ul> <li>界面是写出来了,但是无法实现需求:“应用关闭时不时退出,而是最小化到托盘。”</li> <li>无法实现需求:“实现启动、关闭 WebSocket 服务”</li> </ul> <h1>3、试试 Tauri</h1> <p>后来尝试用 Tauri,遇到的问题:</p> <ul> <li>由于 Rust 不熟,靠 ChatGPT 东拼西凑没能实现启动、关闭 WebSocket 服务,卡在这里两个多星期。</li> <li>在 Windows 系统,Tauri 运行占用的内存比 Electron 还高,诧异之余,也不明所以。</li> </ul> <h1>总结</h1> <p>最后在谷歌和 ChatGPT 的帮助下,用 Tauri 实现了一个应用。</p> <h2>成果</h2> <ul> <li>MacOS 10.15.7 打包出的 dmg 只有 3.1MB</li> </ul>
详情
<p>最近想做一个应用用来替代 C-Lodop,功能比 C-Lodop 更少一些,因为只针对热敏打印机。简单点就是提供一个 WebSocket 服务,这个服务提供:</p> <ul> <li>获取打印机列表</li> <li>预览</li> <li>编辑</li> <li>打印</li> </ul> <p>要求:</p> <ul> <li>支持 Windows 系统(32位、64位)Windows 7 以上版本。</li> <li>支持 MacOS 系统</li> <li>支持主流 Linux 系统。如 Ubuntu。</li> <li>支持国产操作系统。如:统信、麒麟。</li> <li>应用关闭时不是退出,而是最小化到托盘。</li> <li>能自定义 WebSocket 服务监听的端口。</li> <li>能启动 WebSocket 服务。</li> <li>能关闭 WebScoket 服务。</li> </ul> <p><img src="/uploads/web-print-arch.png" alt="" /></p>
详情
<p>前段时间工作中遇到一个需求,node.js 需要调用 dll 提供的一些方法来实现业务需求。</p> <p>一开始,调研了现有的一些 node.js 库,如:<code>ffi-napi</code>、<code>koffi</code>,最终发现调用方写的代码太痛苦了。 如使用 koffi,举个例子:</p> <pre><code class="language-js">const koffi = require("koffi"); // Load the shared library const lib = koffi.load("user32.dll"); // Declare constants const MB_OK = 0x0; const MB_YESNO = 0x4; const MB_ICONQUESTION = 0x20; const MB_ICONINFORMATION = 0x40; const IDOK = 1; const IDYES = 6; const IDNO = 7; // Find functions const MessageBoxA = lib.func("__stdcall", "MessageBoxA", "int", [ "void *", "str", "str", "uint", ]); const MessageBoxW = lib.func("__stdcall", "MessageBoxW", "int", [ "void *", "str16", "str16", "uint", ]); let ret = MessageBoxA( null, "Do you want another message box?", "Koffi", MB_YESNO | MB_ICONQUESTION ); if (ret == IDYES) { MessageBoxW(null, "Hello World!", "Koffi", MB_ICONINFORMATION); } </code></pre> <p>对于前端开发,压根不懂 <code>__stdcall, void *, str16, unit</code> 这些。</p> <p>理想的(期望)调用方式如下:</p> <pre><code class="language-js">const addon = require("addon"); let ret = addon.MessageBoxA(null, "Do you want another message box?", "Koffi", MB_YESNO | MB_ICONQUESTION );</code></pre> <p>为了实现理想的调用方式,那就不能用通用的解决方案(<code>ffi-napi</code>、<code>koffi</code>),需要基于<a href="https://nodejs.org/docs/latest-v16.x/api/n-api.html">C/C++ addons with Node-API</a>,但这个方案也有缺点,就是你需要会 C/C++,如果你不会或者你团队没有会 C/C++ 的,那我建议你还是 <code>koffi</code> 这种通用的解决方案。</p> <p>那就上一张图吧,具体的代码就不放上来,在这里只希望给遇到同样问题的人提供一个思路,具体的代码需要自己去探索。</p> <p><img src="/uploads/%E6%97%A0%E6%A0%87%E9%A2%98-2024-02-05-0935.png" alt="" /></p>
详情
<p>最近在做一个 Electron 项目,遇到了 Error: A dynamic link library (DLL) initialization routine failed.</p> <p><img src="/uploads/2024-06-07_14-53-27.jpg" alt="" /></p> <p>折腾了两天,趁今天有时间,记录一下。 先说解决方案:</p> <pre><code>// binding.gyp // 删除 "msbuild_settings": { "ClCompile": { "ExceptionHandling": "Async" } }</code></pre> <p>网上找的资料,大多说的是 node.js 的版本和 electron 自带的版本不匹配,而我遇到的这种情况很特殊。</p> <h1>背景</h1> <p>我的 C++ addon 是基于 node-addon-api 写的,依赖了 setupapi.lib。</p> <p>本地环境:</p> <ul> <li>node: v16.14.2</li> <li>node-gyp: v10.1.0</li> <li>Pyhton: 3.11.3</li> <li>VS2022: 17.8.34330.188</li> </ul> <p>electron 版本信息:</p> <pre><code>{ node: '16.16.0', v8: '10.6.194.27-electron.0', uv: '1.43.0', zlib: '1.2.12.1-motley', brotli: '1.0.9', ares: '1.18.1', modules: '109', nghttp2: '1.47.0', napi: '8', llhttp: '6.0.7', openssl: '1.1.1', cldr: '41.0', icu: '71.1', tz: '2022e', unicode: '14.0', electron: '21.4.4', chrome: '106.0.5249.199' }</code></pre> <h1>现象</h1> <ol> <li>本机 node 执行 <code>node app.js</code>,正常。</li> <li>Electron 执行 <code>npm run start</code> -> <code>electron main.js --enable-logging</code>,则报错。</li> </ol>
详情
<p>用 C++ 写一个 nodejs addon。</p> <p>我的系统是 MacOS 10.15.7。</p> <h1>一、安装 node-gyp</h1> <p>我是全局安装。</p> <pre><code>npm i node-gyp -g</code></pre> <p>注意:node-gyp 依赖 <code>Python</code> 和 <code>Xcode Command Line Tools</code>,详细信息请参考:<a href="https://github.com/nodejs/node-gyp">https://github.com/nodejs/node-gyp</a></p> <h1>二、写 bindding.gyp</h1> <pre><code>{ "targets": [ { "target_name": "addon", "sources": [ "hello.cc" ] } ] }</code></pre> <h1>三、编写 hello.cc</h1> <pre><code class="language-c++">#include <node.h> namespace demo { using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; using v8::Object; using v8::String; using v8::Value; void Method(const FunctionCallbackInfo<Value> &args) { Isolate *isolate = args.GetIsolate(); // 返回一个字符串 world args.GetReturnValue().Set(String::NewFromUtf8( isolate, "world") .ToLocalChecked()); } // 初始化,接收一个 exports 对象 void Initialize(Local<Object> exports) { // 在 exports 上导出一个方法,方法名是 hello,方法的实现是 Method NODE_SET_METHOD(exports, "hello", Method); } // NODE_MODULE 是宏。用来初始化一个 nodejs 模块 NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize) }</code></pre> <h1>四、配置和编译</h1> <h2>配置</h2> <pre><code class="language-bash">node-gyp configure</code></pre> <h2>编译</h2> <p>// 默认编译输出的目录是 <code>build/Release</code></p> <pre><code class="language-bash">node-gyp build // 如果遇到错误,可以尝试 node-gyp rebuild</code></pre> <h1>五、nodejs 调用 .node</h1> <pre><code class="language-js">// demo.js const addon = require("./build/Release/addon"); console.log(addon.hello()); // 输出 world</code></pre> <h1>参考</h1> <p><a href="https://nodejs.org/docs/latest-v16.x/api/addons.html">https://nodejs.org/docs/latest-v16.x/api/addons.html</a></p> <p><a href="https://github.com/nodejs/node-gyp">https://github.com/nodejs/node-gyp</a></p>
详情
<p>最近在研究替换 C-Lodop 的方案。</p> <h1>方案一:C++ addon</h1> <p>C++ addon 是用 C++ 编写的动态链接的共享对象。require() 函数可以将插件加载为普通的Node.js 模块。插件提供了 JavaScript 和 C/C++ 库之间的接口。</p> <p>实现插件的三种方式:</p> <table> <thead> <tr> <th>实现插件的方式</th> <th>优点</th> <th>缺点</th> </tr> </thead> <tbody> <tr> <td>Node-API</td> <td>可移植、可跨不同 Node.js 版本</td> <td></td> </tr> <tr> <td>nan</td> <td>不用考虑 node.js 版本</td> <td></td> </tr> <tr> <td>直接使用内部 V8、libuv 和 Node.js 库</td> <td></td> <td>实现复杂</td> </tr> </tbody> </table> <p>Node-API(以前的 N-API)是一种用于构建本机插件的 API。</p> <h1>方案二:ffi-napi</h1> <p>ffi-napi 是一个 Node.js 模块,它提供了一个简单的方式来调用外部(本地)的 C/C++ 函数,而无需编写 C++ 插件。它使用了 Node.js 的 N-API 来实现跨版本的稳定性,并且具有良好的跨平台兼容性。</p> <p>优点:不用编写 C++ 代码或者构建 C++ 插件。</p> <p>缺点:安装 ffi-napi 需要 node-gyp 构建、Python、msvs。项目已不再更新,最后一次更新 2021-03-18</p> <p><a href="https://github.com/node-ffi-napi/node-ffi-napi">https://github.com/node-ffi-napi/node-ffi-napi</a></p> <h1>方案三:koffi</h1> <p>Koffi 是 Node.js 的一个快速且易用的 C FFI 模块。</p> <p>特性:</p> <p>1、低开销,高性能。</p> <p>2、通过引用(指针)和值支持基元和聚合数据类型(结构和固定大小的数组)。</p> <p>3、Javascript函数可以用作C回调(自1.2.0起)。</p> <p><a href="https://koffi.dev/">https://koffi.dev/</a></p> <p><a href="https://github.com/Koromix/rygel/">https://github.com/Koromix/rygel/</a></p> <h1>名词解释:</h1> <p>FFI: Foreign Function Interface</p> <p>NAN: Native Abstractions for Node.js</p> <h1>参考</h1> <ul> <li><a href="https://zhuanlan.zhihu.com/p/687513603">https://zhuanlan.zhihu.com/p/687513603</a></li> <li><a href="https://nodejs.org/docs/latest-v16.x/api/addons.html#node-api">https://nodejs.org/docs/latest-v16.x/api/addons.html#node-api</a></li> <li><a href="https://github.com/nodejs/node-gyp#installation">https://github.com/nodejs/node-gyp#installation</a></li> </ul>
详情
<h1>CMake 是什么?</h1> <p>一个强大的软件构建系统。典型用途是用来构建 C/C++ 编写的项目。</p> <h1>1安装</h1> <h2>1.1 安装 CMake</h2> <p>我安装的是 3.25.3 版本 <a href="https://github.com/Kitware/CMake/releases/download/v3.25.3/cmake-3.25.3-windows-x86_64.msi"> cmake-3.25.3-windows-x86_64.msi</a></p> <p>如果想下载其它版本,进入 <a href="https://cmake.org/download/">https://cmake.org/download/</a> 找到需要的版本。</p> <h2>1.2 安装 Visual Studio Code 插件</h2> <h3>1.2.1 CMake</h3> <p><a href="https://marketplace.visualstudio.com/items?itemName=twxs.cmake">Cmake</a> 高亮显示 CMakeLists.txt 语法。</p> <h3>1.2.2 CMake Tools</h3> <p><a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools">CMake Tools</a> 用来配置和执行 cmake 命令。</p> <h1>2新建项目</h1> <h2>2.1 新建目录</h2> <p>cmake-demo</p> <h2>2.2 新建 CMakeLists.txt</h2> <pre><code class="language-txt">cmake_minimum_required(VERSION 3.10) project(demo) # set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "-m32") set(CMAKE_VERBOSE_MAKEFILE on) # include_directories(${OPENGL_INCLUDE_DIR} ${GLEW_INCLUDE_DIRS}) add_executable(demo demo.cc)</code></pre> <h2>2.3 新建 demo.cc</h2> <pre><code class="language-c++">#include <stdio.h> int main() { printf("Hello CMake\n"); return 0; }</code></pre> <h2>2.4 选则编译工具</h2> <p>我选择的是 <code>Visual Studio 生成工具 2019 Release - x86</code></p> <p><img src="/uploads/Snipaste_2024-09-11_10-13-37.png" alt="" /></p> <h2>2.5 运行</h2> <p>如果编译通过的话,会自动运行,控制台会输出 <code>Hello CMake</code></p> <p><img src="/uploads/Snipaste_2024-09-11_10-18-10.png" alt="" /></p> <h1>参考</h1> <p><a href="https://cmake.org/cmake/help/latest/guide/tutorial/index.html">https://cmake.org/cmake/help/latest/guide/tutorial/index.html</a></p> <p><a href="https://zhuanlan.zhihu.com/p/653282782">https://zhuanlan.zhihu.com/p/653282782</a></p>
详情
<p>由于 jsbarcode 不支持 Code93 条码,所以只能自己动手。</p> <p>之前有想过用 <code>bwip-js</code> 替换 <code>jsbarcode</code>,但由于需求要支持更改条码内文字的字体,<code>bwip-js</code> 虽然也能<a href="https://juejin.cn/post/7297024168604549156">修改字体</a>,但是还要加载字体文件,这个方案需要修改的文件太多,也怕引入其它 bug,最终没有采取这个方案。</p> <p>首先,需要了解一下 Code 93</p> <h1>Code 93</h1> <p>1982 年 Intermec 公司设计;主要被加拿大邮政使用。<a href="https://en.wikipedia.org/wiki/Code_93">参考</a></p> <h2>允许的字符</h2> <p><code>0-9</code>、<code>A-Z</code>、<code>-</code>、<code>.</code>、<code>$</code>、<code>/</code>、<code>+</code>、<code>%</code>、<code>空格</code></p> <h2>结构</h2> <p><img src="/uploads/code93-structure.jpg" alt="" /></p> <h1>实战</h1> <h2>1 克隆 github 仓库</h2> <pre><code>git clone https://github.com/lindell/JsBarcode.git</code></pre> <h2>2 添加 Code93 代码,参考<a href="https://github.com/elysiumphase/bitgener/blob/master/src/Barcode/Code93.js">Code 93</a></h2> <p><code>src/barcodes</code> 下新建 <code>CODE93</code> 目录,新建 <code>index.js</code> 文件</p> <pre><code class="language-js">// index.js // Encoding documentation: // https://en.wikipedia.org/wiki/Code_93#Encoding import Barcode from "../Barcode.js"; const encoding = [ "100010100", ... ]; class CODE93 extends Barcode { constructor(data, options) { data = data.toUpperCase(); super(data, options); } encode() { const data = this.data; const table = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%____*"; // _ => ($), (%), (/) et (+) const dataToEncode = data.toUpperCase(); const dataToEncodeLength = dataToEncode.length; let digit = ""; // start : * digit += encoding[47]; // digits for (let i = 0; i < dataToEncodeLength; i += 1) { digit += encoding[table.indexOf(dataToEncode.charAt(i))]; } // checksum let weightC = 0; let weightSumC = 0; let weightK = 1; // start at 1 because the right-most character is 'C' checksum let weightSumK = 0; for (let i = dataToEncodeLength - 1; i >= 0; i -= 1) { weightC = weightC === 20 ? 1 : weightC + 1; weightK = weightK === 15 ? 1 : weightK + 1; const index = table.indexOf(dataToEncode.charAt(i)); weightSumC += weightC * index; weightSumK += weightK * index; } const c = weightSumC % 47; weightSumK += c; const k = weightSumK % 47; digit += encoding[c]; digit += encoding[k]; // stop : * digit += encoding[47]; // terminaison bar digit += "1"; const encodedData = { data: digit, text: dataToEncode, }; return encodedData; } valid() { return /^[0-9a-zA-Z-. $/+%]+$/.test(this.data); } } export { CODE93 }; </code></pre> <h2>3 编译打包</h2> <p>在 <code>jsbarcode</code> 仓库根目录执行 <code>npm run build</code></p> <h2>4 本地调试</h2> <ol> <li>在 <code>jsbarcode</code> 仓库根目录执行 <code>npm link</code></li> <li>在使用 <code>jsbarcode</code> 的仓库执行 <code>npm link jsbarcode</code></li> <li>使用 <pre><code class="language-javascript">JsBarcode("#barcode", "1234", { format: "CODE93", width: 4, height: 40, displayValue: false, });</code></pre></li> <li>显示结果</li> </ol> <p><img src="/uploads/code93.jpg" alt="" /></p> <h1>参考</h1> <p><a href="https://en.wikipedia.org/wiki/Code_93">维基百科 Code 93</a></p> <p><a href="https://github.com/elysiumphase/bitgener/blob/master/src/Barcode/Code93.js">Code 93</a></p>
详情
<p>继上一篇文章<a href="http://pcdeng.com/rust-libusb-gnu.html">《Windows 11 搭建 Rust USB 开发环境之 GNU 版》</a>,这篇主要总结一下安装 <code>msvc</code> 工具链的要点。</p> <h1>前置</h1> <ol> <li>Windows 11 系统</li> <li><a href="https://visualstudio.microsoft.com/zh-hans/visual-cpp-build-tools/">Microsoft C++ 生成工具</a>,我装的是 2022 版,还有一些依赖,如 <code>Windows 11 SDK</code>,参考 <a href="https://zhuanlan.zhihu.com/p/507532813">Windows上Rust所依赖的msvc到底怎么装?</a></li> <li>rust 及其相关工具,如 <code>cargo</code>、<code>rustup</code>、<code>rustc</code>。一般安装好 rust,这些工具都会包含在内。</li> <li>下载 <code>libusb</code> 编译好的库,我下载的是 <a href="https://github.com/libusb/libusb/releases/download/v1.0.26/libusb-1.0.26-binaries.7z">libusb-1.0.26</a></li> </ol> <h1>实战</h1> <p>项目根目录假定是 <code>D:\projects\rust\libusb-demo</code></p> <h2>创建一个 rust 项目</h2> <p>打开一个<code>命令提示符</code>后,执行以下命令</p> <pre><code class="language-cmd">cargo new libusb-demo cd libusb-demo cargo add libusb code .</code></pre> <h2>写调用 <code>libusb</code> 的测试代码</h2> <p>在 Visual Studio Code 编辑器中编辑 <code>src/main.rs</code></p> <pre><code class="language-rs">extern crate libusb; fn main() { let context = libusb::Context::new().unwrap(); for device in context.devices().unwrap().iter() { let device_desc = device.device_descriptor().unwrap(); println!("Bus {:03} Device {:03} ID {:04x}:{:04x}", device.bus_number(), device.address(), device_desc.vendor_id(), device_desc.product_id()); } }</code></pre> <h2>配置</h2> <ol> <li>解压 <code>libusb-1.0.26-binaries.7z</code> 得到 <code>libusb-1.0.26-binaries</code>。</li> <li>把 <code>libusb-1.0.26-binaries</code> 下的 <code>VS2015-x64</code> 复制到 <code>D:\projects\rust\libusb-demo</code> 下,并改名为 <code>libusb-x64</code></li> <li>在 <code>libusb-demo</code> 下新建 <code>.cargo/config.toml</code> <pre><code class="language-toml">// .cargo/config.toml [target.x86_64-pc-windows-msvc.'usb-1.0'] # rustc-link-search = ['D:\projects\rust\libusb-demo\libusb-x64\dll'] # 这种是动态链接方式 rustc-link-search = ['D:\projects\rust\libusb-demo\libusb-x64\lib'] # 这种是静态链接方式 rustc-link-lib = ['libusb-1.0']</code></pre></li> </ol> <h2>编译正式版</h2> <pre><code class="language-cmd">cargo build --release</code></pre> <h2>验证</h2> <h3>静态链接版</h3> <p>复制 <code>target\release\libusb-demo.exe</code> 到虚拟机里或另一台装有 Windows 的系统运行。 打开 <code>命令提示符</code>,进入 <code>C:\Users\Payton\Desktop</code></p> <pre><code class="language-cmd">C:\Users\Payton\Desktop>libusb-demo.exe Bus 003 Device 001 ID 0e0f:0003 Bus 001 Device 002 ID 0e0f:0002 Bus 003 Device 000 ID 15ad:0779 Bus 002 Device 000 ID 15ad:0770 Bus 003 Device 002 ID 0e0f:0002 Bus 003 Device 003 ID 0e0f:0002 Bus 001 Device 000 ID 15ad:0774</code></pre> <h3>动态链接版</h3> <p>复制 <code>target\release\libusb-demo.exe</code> 和 <code>libusb-x64\dll\libusb-1.0.dll</code> 到虚拟机里或另一台装有 Windows 的系统运行。 打开 <code>命令提示符</code>,进入 <code>C:\Users\Payton\Desktop</code>,</p> <ul> <li>如果没有复制 <code>libusb-1.0.dll</code></li> </ul> <pre><code class="language-cmd">C:\Users\Payton\Desktop>libusb-demo.exe</code></pre> <p>提示 <img src="//www.pcdeng.com/uploads/libusb-1.0.dll-not-found.jpg" alt="" /></p> <ul> <li>复制 <code>libusb-1.0.dll</code> <pre><code class="language-cmd">C:\Users\Payton\Desktop>libusb-demo.exe Bus 003 Device 001 ID 0e0f:0003 Bus 001 Device 002 ID 0e0f:0002 Bus 003 Device 000 ID 15ad:0779 Bus 002 Device 000 ID 15ad:0770 Bus 003 Device 002 ID 0e0f:0002 Bus 003 Device 003 ID 0e0f:0002 Bus 001 Device 000 ID 15ad:0774</code></pre></li> </ul> <h1>参考</h1> <p><a href="https://zhuanlan.zhihu.com/p/507532813">Windows上Rust所依赖的msvc到底怎么装?</a></p> <p><a href="https://github.com/dcuddeback/libusb-rs/issues/20">Linking on Windows #20</a></p> <h1>附</h1> <ol> <li>项目目录 <img src="//www.pcdeng.com/uploads/rust-libusb-demo.jpg" alt="" /></li> </ol>
详情