存档

‘日常’ 分类的存档

UWP中为 WinRT 组件创建 NuGet 包

2026年9月6日 没有评论

这篇文章可以说是迟到了 N 多年的分享了,一直放在草稿箱里但是没有发布,今天赶紧地整理。

先搞清楚:WinRT 组件里到底有什么

假设我们有一个 WinRT 组件:Demo.winmd、Demo.dll。这两个文件虽然经常一起出现,但职责完全不同。.winmdWindows Metadata 文件,它描述的是这个 WinRT 组件对外暴露的类型信息,比如:

namespace
class
interface
method
property
enum

WinRT 的语言投影也依赖这些 metadata。比如 C++/WinRT 会根据 WinRT metadata 生成对应的 C++ 投影代码。所以可以简单理解成:Demo.winmd 告诉编译器“这个组件长什么样”,它本身并不是业务代码的实现。.dll 才是实际的 native implementation。也就是说:Demo.dll 真正执行代码。对于一个典型的 WinRT Component,这两个文件是配套的。

Visual Studio 在构建 Windows Runtime Component 时,会生成 WinRT metadata;对于 C++/WinRT 项目,工具链也是先处理 IDL 生成 .winmd,再基于 metadata 生成相应的投影代码。

不要把 .winmd 理解成普通 .NET 程序集,也不要把它和 DLL 当成两个可以随便替换的文件。它们共同描述并实现了一个 WinRT 组件。

NuGet 包里应该放什么?

对于这个例子,一个最基本的 NuGet 包可以长这样:

com.xx.demo.nupkg
│
├─ lib
│  └─ uap10.0
│     └─ Demo.winmd
├─ runtimes
│  ├─ win10-x86
│  │  └─ native
│  │     └─ Demo.dll
│  └─ win10-x64
│     └─ native
│        └─ Demo.dll
└─ build
   └─ native
      └─ com.xx.demo.targets

这里其实就是整个事情最关键的部分,.nuspec 本身反而没什么好讲的——如果你平时用 NuGet,知道怎么写一个基本的 .nuspec 就够了。

为什么 .winmd.dll 要放在不同目录?

这是很多第一次做 native NuGet 包的人容易疑惑的地方。.winmd 是给编译阶段使用的,所以我们把它放到 lib/uap10.0/,而 DLL 属于 native runtime binary,因此放到:runtimes/win10-x64/native/、runtimes/win10-x86/native/。

这样做的一个直接好处就是:同一个 NuGet 包可以同时支持多个 CPU 架构。微软的 UWP NuGet 示例也是把 WinMD 放到 lib\uap10.0,native DLL 放到 runtimes 对应的架构目录。 Microsoft Learn+1

C++ 项目为什么还需要 .targets

NuGet 对 native C++ 包的处理方式,本身就和 .NET 程序集不太一样。微软的 native NuGet 文档也明确提到,native 包通常通过 buildcontenttools 等目录以及 MSBuild 的 .props/.targets 来完成项目集成,而不是依赖 lib 直接添加 C++ Reference。 所以我们通常需要提供一个:com.xx.demo.targets。它的作用可以简单理解成:告诉 MSBuild:这个 NuGet 包里的 WinMD 和 DLL 怎么添加到当前项目。

一个简化后的思路大概是:

<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'UAP'">
    <Reference Include="
        $(MSBuildThisFileDirectory)
        ..\..\lib\uap10.0\Demo.winmd">

        <Implementation>Demo.dll</Implementation>
    </Reference>
    <ReferenceCopyLocalPaths Include="
        $(MSBuildThisFileDirectory)
        ..\..\runtimes\win10-$(Platform)\native\Demo.dll" />
</ItemGroup>

.nuspec 不需要写得很复杂

如果已经熟悉 NuGet,可以把它理解成一个文件映射:

<files>
    <file
        src=".\Demo.winmd"
        target="lib\uap10.0" />
    <file
        src=".\Demo.dll"
        target="runtimes\win10-x64\native" />
    <file
        src=".\com.xx.demo.targets"
        target="build\native" />
</files>

如果还要支持 x86,就再放一个对应的 DLL:runtimes/win10-x86/native/Demo.dll。

这里最重要的不是 XML 本身,而是记住:

WinMD
    → lib/uap10.0
Native DLL
    → runtimes/<RID>/native
MSBuild 集成
    → build/native

XML 文档要不要一起打包?

如果组件是给别人使用的,比较建议加上。里面保存 C++/C# 的 API 文档注释,这样 IDE 可以显示对应的 API 注释。这个东西不影响组件运行,但对 SDK 类组件来说体验差别还是挺大的。

分类: 日常 标签: ,

如何找到适合自己的 llama.cpp 配置

2026年8月28日 没有评论

众所周知,llama.cpp 是一个使用 C++ 来实现的一个大模型推理工具,不依赖 python, pytorch,而且性能也很好,支持自定义的参数调整。Ollama 底层也是封装了这个库,提供给普通用户。

Ollama 的设置对于 AI生成代码这样的专业场景下,不一定可以发挥硬件的最大性能,所以有的场景,还是会有人直接使用 llama.cpp 来加载模型。

对于 Windows 平台,最直接的方式就是使用 winget 来安装:

winget install llama.cpp

今天的这边文章,要和大家分享的是普通的开发人员,如何简单快速地在本地使用 llama.cpp 搭建起本地模型。当然,不可否认,Ollama 依然是很优秀的工具,它们是相互补充而不是替代其中的某一个。

第一步从 HF 上下载 GGUF 模型文件,一般而言大家可以下载 Q4_K_M 格式的文件。

第二步,运行最基础的命令:llama-server.exe -m .\Qwen3.8-27B-UD-Q4_K_M.gguf -ngl 0 -fa off –spec-type none -c 1024,记得模型名称换成你本地实际的模型,先保证你机器可以跑起来,如果你模型不适用你电脑,那么初始化就会报错。

第三步,当可以运行后,你就可以访问 localhost:8080 访问 llama.cpp 提供的简单网页版聊天工具,随便说点什么,在里面你会看到生成的 token 速度,Qwen3.8 在我机器上只有 2t/s,够慢的了。

第四步,结束并运行新的命令:llama-server.exe -m .\Qwen3.8-27B-UD-Q4_K_M.gguf -ngl 10 -fa off –spec-type none -c 1024,可以看到变化是 ngl 从 0 变到了 10,你就可以观察内存和显存的占用情况,如果允许没有问题,就以步长 10,逐步添加,同时也增加 -c 上下文长度。

第五步,打开 mtp,执行下面的命令 llama-server.exe -m .\Qwen3.8-27B-UD-Q4_K_M.gguf -ngl 20 -fa on –spec-type draft-mtp -c 1024, 可以看开启 mtp 后,是否可以初始化成功,一般而言启用了 mtp ,生成 token 的速度会增加,如果你发现没有效果,应该及时关闭,否则得不偿失。

对于我的机器,最后停留在 llama-server.exe -m .\Qwen3.8-27B-UD-Q4_K_M.gguf -ngl 10 -fa on –spec-type draft-mtp -c 32768 这个参数上面。

大家可以自己试一试,没有最好的,只有合适的。

分类: AI, 工具, 日常 标签:

OpenCode 介绍

2026年7月19日 没有评论

OpenCode 是什么?

一句话来说:一个开源的 AI Coding Agent,可以运行在 Terminal、Desktop、IDE 中,并支持几乎所有主流的大模型。相比很多只能调用固定模型的工具,OpenCode 最大的特点就是Provider 无关

基本可以理解成:只要模型提供 OpenAI Compatible API,大概率都能接。

官网地址是 https://opencode.ai,官方也提供桌面版应用,非常适合我这样无法接受命令行的小白。

为什么很多人开始用 OpenCode?如果只看能力,其实现在 AI Coding Agent 都差不多:

  • 修改代码
  • 自动搜索项目
  • 调用终端
  • Git 操作
  • 修 Bug
  • 写测试

这些大家都会。OpenCode 真正吸引人的地方主要有几个:

1. 开源。这是很多人首先关注的一点。整个 Agent 都是开源的,很多时候你甚至可以直接看看它到底是怎么组织 Prompt、怎么管理 Context、怎么调 Tool 的。对于喜欢研究 Agent Workflow 的人,这一点很有价值。

2. 不绑定任何模型。这一点比想象中重要。如果工具绑定 Provider,你只能等官方适配,OpenCode 基本没有这个问题,换模型基本就是改配置。

3. 真正以 Terminal 为中心。很多 IDE 插件,本质还是聊天窗口。OpenCode 更像一个真正工作的 Agent。

例如:修复所有 eslint 错误。它可能会:

  • 搜索项目
  • 分析错误
  • 修改多个文件
  • 执行 npm run lint
  • 再继续修改
  • 最终提交修改

整个过程基本不用你手动介入。这种体验和 Cursor 的 Agent Mode 很接近。

4. LSP 支持。很多 Agent 修改代码其实都是:全文件读取 → LLM 自己猜。OpenCode 会利用 Language Server 获取:

  • Definition
  • Reference
  • Symbol
  • 类型信息

因此:跨文件修改准确率会高不少,尤其大型项目比较明显。

配置建议

项目级 Prompt

很多人一直在聊天。其实更推荐写:AGENTS.md 或者项目 Prompt。

告诉 Agent:项目规范、命名规则、Commit 风格、是否允许执行命令、是否自动运行测试,效果会明显好很多。

自定义命令

OpenCode 支持自定义 Command。

例如:/review,实际上就是:

Review 当前改动,只关注:
- Bug
- 性能
- 安全

以后一句:/review,不用重复输入 Prompt。长期下来效率提升非常明显。

AI 编程工具最大的变化,不是模型越来越强,而是 Agent 越来越成熟。OpenCode 代表的是另一种思路:不是把 AI 塞进 IDE,而是把 AI 放到开发流程本身。它知道你的项目、能调用工具、能执行命令、能管理上下文,也能完成完整的开发任务。

如果你平时就是终端重度用户,或者已经习惯 Claude Code、Aider、Codex CLI 这一类工具,那么 OpenCode 值得体验一下。它未必会成为你的唯一工具,但很可能会成为工具箱里长期保留的那一个。

分类: AI, 日常 标签:

解决 Supabase IPv4 连接问题

2026年3月3日 没有评论

其实在上个月的时候就发现,办公网络环境下,无法连接到我的 Supabase 数据库实例上,当然在家里的网络就没有这个问题,一直以为是 IT 给屏蔽了,但是心里总是不明白 IT 为啥要这么做。

今天无意间ping 了下分配的域名,发现只能解析到 IPV6 地址,才意识到这是典型的IPv4/IPv6网络兼容性问题。

经过检索,这篇帖子提供了线索,到 Supabase 的官网上一看,果然人家说的很清楚,当时自己没有留意。

迅速从默认的 Direct 连接切换到 Transaction pooler,就没有问题了。虽然牺牲了一些性能,但是好歹是可以使用了。

最后提醒一下,这两种连接方式,需要用到的用户名是不一样的,密码是一样的。

分类: 日常 标签:

ubuntu 18.04 升级gcc

2026年2月10日 没有评论

要在Ubuntu 18.04 上升级g++到版本10,可以按照以下步骤进行操作:

  1. 打开终端。
  2. 更新系统软件包列表,使用命令sudo apt update
  3. 安装必需的依赖项,使用命令sudo apt install build-essential。这将确保所有构建工具都已正确安装。
  4. 添加PPA(Personal Package Archive)存储库来获取最新的GCC编译器版本。运行以下命令:sudo add-apt-repository ppa:ubuntu-toolchain-r/testsudo apt update
  5. 安装GCC 10及其相关组件,使用命令sudo apt install gcc-10 g++-10
  6. 设置默认的C++编译器为GCC 10,使用命令sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 100sudo update-alternatives --set gcc /usr/bin/gcc-10。同样地,也可以通过类似的方式设置默认的C编译器。
  7. 现在,您应该能够使用GCC 10进行编程了。

注意:由于Ubuntu 18.04不支持直接从官方源中提供GCC 10,因此我们使用第三方PPA存储库来获得最新版本。

sudo update-alternatives –install /usr/bin/g++ g++ /usr/bin/g++-8 100

为什么在现在还在说一个版本这么旧的话题?是因为一些 armv7 的设备,还运行的是老版本,而且由于华强北自定义的镜像,只能停留在那个版本的系统。有时候感觉就很可惜。
分类: 日常 标签:

代码行数统计工具

2026年1月19日 没有评论

每当一段时间过,就会有触发需求,统计大家的代码量、UT 覆盖率之类的。经过一番搜索,找到了 cloc 这个今天想要推荐的工具,其开源地址为:https://github.com/AlDanial/cloc

这个工具可以按语言类型、单文件或文件夹、空白行数之类的来过滤,使用也很简单,下载到本地后就是一个单绿色程序,对于 Linux 和 Mac 系统也支持。

随着现在 CI/CD 的集成,代码统计在云端也都有了,但是本地放一个,某些场景下就会派上用处。兄弟,你信我没错的。

大家可以基于我的模板来改吧改吧。

cloc.exe c:\code\project\ --include-lang="C,C++,C/C++ Header,CSS,HTML,Java,JavaScript,JSX,Kotlin,Objective-C,Objective-C++,Swift,TypeScript,JSON,Markdown"

最后,祝大家好运。

分类: 一句话, 日常 标签:

驱动快速备份和还原

2025年12月5日 没有评论

最近在写 PPT 时电脑挂了,虽然马上就换了个备用机器,但是发现了一个问题就是缺少打印机驱动。

以前的硬盘虽然可以作为移动硬盘使用,但是很显然,驱动是无法直接拷贝的。

那个打印机驱动实在是过于久远,系统无法识别出来,默认的驱动包而且还会安装额外的应用,对于有洁癖的人来说,有点不能忍受。

经过一番检索,一个合适的步骤如下:

1,网上搜索打印机对应的驱动安装包,在测试机器上安装。
2,测试机查看打印机设备的驱动,记住它的驱动文件名名称,例如 printxxx.inf
3,测试机上导出驱动,
dism /online /export-driver /destination:”C:\Users\xxx\Desktop\backup”
4,进入这个文件夹,里面会有很多子文件夹。根据第二步里的文件名,搜索相关的子文件夹
5,这个子文件夹,就是驱动实际会用到的最小集合。拷贝到目标机器上。
6,目标机器上,选择添加打印机,然后手动浏览驱动,选择刚才拷贝的子文件夹
7,无脑下一步,就会发现打印机被添加上了
8,备份这个驱动文件夹。以后再添加打印机时,就可以跳过前面5步,直接开始手动添加驱动了

上面的方式,可以满足基本的打印需求。如果是要支持扫描之类的功能,那还是安装默认的全家桶吧。

理论上,也支持其他类型的驱动。

分类: Windows, 日常 标签:

群晖 SHR 无损改为Basic方式

2025年11月14日 没有评论

群晖在用了几年后,当初买的一块4T空间的硬盘看起来不太够用了,于是就加了一块 8T 硬盘,毕竟 12T 的太贵了。

对于小姐姐来说足够了。

一插入就识别出来了,确认很方便,初始化的时候想着是不是搞个raid,将来也起码有个备份的。因为就2个硬盘,于是选择了 SHR 的方式,可是万万没有想到,这样一来,2个磁盘都成了 3T 大小的了,那我的 8T 岂不是白买了。

但是后悔药岂是那么好吃的?网上一顿搜索,简直不要太麻烦,备份导出,大概思路就是使用第三块硬盘来中转下。我去哪里再找这么大容量的硬盘~

官网的 KB里也没有发现好的解决方法,最后快要放弃的时候,无意间在贴吧里发现了线索,顺便展开搜索,最终解决了。

其实还是承担了数据丢失的风险。

首先,在群晖上临时打开 ssh开关,然后使用工具远程连接。 输入 ssh xxxx@192.168.x.xxx,然后再输入 sudo -i,再次输入密码,即可进入 root 状态。

第二步,查看系统分区。输入命令 cat /proc/mdstat , 一般md2是你的第一张盘,是按照顺序来的,也可以通过下面显示的空间大小来判断。我的硬盘分别是 4T 和 8T,比较好区分。

第三步,输入命令:

mdadm --grow --raid-devices=1 --force /dev/md2

之后 SHR 方式就变成了 basic方式。

第四步,稳妥起见,重启群晖。大风大浪都见过,不差这最后一步,万一哪里出问题了,不划算。

按照这个意思来分析,估计群晖是不是只在磁盘特定的分区位置加了标记,所以使用上面强制更新的命令,避免了中转的烦恼。这也是我前面提及会有风险的原因。

比较取巧的是,我把新硬盘的内容给清空不要了,所以需要考虑的因素就少了。

但是,但是磁盘数据备份,甚至是异地备份的事情,一定要落实,毕竟数据和回忆无价。

分类: NAS, 日常 标签:

路先行 CarPlay 盒子升级

2025年10月15日 没有评论

在大约8+个月前,我买了个CarPlay 的有线到无线的转换器,寻思多年未使用的功能终于可以派上用处了。

这东西不太放心,怕影响了现有的车机系统,并没有开放使用。操作起来主观感觉还将就,可以感知到延迟,但还在可以接受的范围里。

主要是手机支架是面向我的,看导航信息很是方便,用了这个后看导航要偏头看屏幕,不是很习惯,而且地图的导航界面和手机的布局不太一样,一时之间并不适应。

所以这个设备就放这里了,希望以后有机会可以体验原生的车机系统。

对于盒子的升级,问了下客服,整理步骤如下:

  1. 先将盒子插入到电脑的 U盘口,或者手机的充电器上。
  2. 手机搜索 wifi 热点,会发现一个类似 smartBox-43AB 格式的热点。
  3. 手机接入这个热点后,会发现“无互联网连接”的提示,这是符合预期的,毕竟它不是一个可以上网的路由器。
  4. 手机浏览器访问 192.168.1.101,就会在页面里发现盒子的各种参数信息。滑动到页面底部,会发现一个区域是关于升级的。如果有新版本,点击更新就好了。
  5. 升级完成后,插入到车上,重新连接。如果需要密码,那就是 88888888

对了,这个盒子牌子叫做“路先行”,某宝上另外一个常见的牌子是君用。对于君用的那个盒子,一个是价格原因,另外有人反馈延迟较高,就没有买。

我买的这个,插入到扶手箱里的 USB 接口上,运行一段时间后,可以感觉到发热,但也不至于不能碰。

其实到现在,我发现了一个使用这个盒子的场景了。我有一个专门的手机壳,磁吸的方式放到中控台上。如果是别人要用导航的话,就可以连接到这个盒子上,毕竟别人的手机壳可不是磁吸的,尽管我也留有备份的磁吸片。

对了,一般而言,CarPlay 盒子都区分苹果和安卓的,大家在购买时需要确认下是否和自己的手机适配。不过,衣服自己洗这里还是希望大家的小车车都自带这样的功能,毕竟时代在进步是不是。

分类: 日常 标签:

磁盘取消 BitLocker 加密

2025年9月11日 没有评论

BitLocker 这个东西吧,好也不好,一言难尽。反正衣服自己洗是倾向于给关闭了的。

打开控制面板->系统和安全->BitLocker 驱动器加密,这个时候弹出的界面上就会显示加密状态。对于多个分区,可以分别关闭。

但是发现磁盘上还是有个感叹号图标,奇怪的很。

继续检索,又有一个思路,Windows 设置中,搜索“加密”,打开“设备加密设置”,把右边的开关给关掉。

悲催的是,系统弹窗说无法关闭,即使重启系统后,也不行。

继续检索,又看到方法,命令行输入:

manage-bde -status

输出结果里可以看到,显示加密暂停。

继续执行指令:

manage-bde -pause C:

注意,修改这里的盘符为实际的值哈。

输入命令后,不要着急,耐心等待几分钟,之后使用 manage-bde -status 来查询状态。如果显示结束了,那么再回到刚才的设置窗口里,把开关给关闭。

之后再重启一次电脑就可以了。

分类: 日常 标签: