Avalonia采用AOT编译后无法运行解决办法

近日在制作Avalonia程序过程中,发现调试时很正常,发布后却无法运行,感觉很奇怪,我的发布配置有以下两条:

1
2
<PublishTrimmed>True</PublishTrimmed>
<PublishAot Condition="'$(Configuration)' != 'Debug'">true</PublishAot>

第一条启用了裁剪,第二条启用了AOT编译(但是在开发时没开启,因为预览窗口不支持AOT)

经过一番排查,发现这两个都有问题:

  1. 反射对AOT不友好,我的ViewLocator.cs使用了反射来创建对象
  2. 有的库对剪裁支持不好,因此要对其关闭剪裁

解决方案

问题1: 消除反射

原代码使用反射创建对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
public Control? Build(object? param)
{
if (param != null && param is ViewModelBase)
{
var viewModelType = param.GetType();
if (_viewModelViewMappings.TryGetValue(viewModelType, out var viewType))
{
return (Control)Activator.CreateInstance(viewType)!; // 这里使用了反射
}
return new TextBlock { Text = "Not Found: " + viewModelType.FullName };
}
return null;
}

修改后使用工厂方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public Control? Build(object? param)
{
if (param != null && param is ViewModelBase)
{
var viewModelType = param.GetType();
if (_viewModelViewMappings.TryGetValue(viewModelType, out var viewFactory))
{
return viewFactory(); // 使用了工厂方法
}
return new TextBlock { Text = "Not Found: " + viewModelType.FullName };
}
return null;
}

这样就可以消除反射了

问题2: 关闭特定库的剪裁

发布时我注意到很多这样的剪裁警告

1
2
3
4
5
2>Assembly 'Serilog' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
2>Assembly 'ReactiveUI' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
2>Assembly 'SukiUI' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
2>Assembly 'Avalonia.Controls.DataGrid' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
2>Assembly 'Avalonia.Controls.DataGrid' produced AOT analysis warnings.

因此我修改项目的sln文件,增加以下片段,通过外部的xml文件来限制剪裁

1
2
3
<ItemGroup>
<TrimmerRootDescriptor Include="TrimmerRoots.xml" />
</ItemGroup>

下面是TrimmerRoots.xml的内容

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8" ?>
<linker>
<assembly fullname="Serilog" />
<assembly fullname="Serilog.Sinks.Console" />
<assembly fullname="Serilog.Sinks.File" />
<assembly fullname="ReactiveUI" />
<assembly fullname="SukiUI" />
<assembly fullname="Serilog.Sinks.File" />
</linker>

我将所有报警告的项目都加入了进去,虽然后面的编译依旧有新的警告,但是程序可以正常运行了。至此,所有问题解决。

Avalonia Unable to resolve property or method of name 'xxx' on type 'XamlX.TypeSystem.XamlPseudoType'解决办法

近期我在使用Avalonia编写桌面程序时,用到了ItemRepeater组件,写出来大概是这样

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
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:vm="clr-namespace:CooingOwl.ViewModels"
xmlns:suki="clr-namespace:SukiUI.Controls;assembly=SukiUI"
x:DataType="vm:ExploreViewModel"
x:Class="CooingOwl.Views.ExploreView">

<ScrollViewer HorizontalScrollBarVisibility="Auto">
<ItemsRepeater ItemsSource="{Binding B}" Margin="16">
<ItemsRepeater.Layout>
<StackLayout Spacing="20"
Orientation="Vertical" />
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<DataTemplate>
<suki:GlassCard>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Name}"/>
<TextBlock Margin="4 0" FontWeight="Bold"
Text="{Binding Id}"/>
</StackPanel>
</suki:GlassCard>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ScrollViewer>

</UserControl>

其中<TextBlock Text="{Binding Name}"/>Text="{Binding Id}"/>产生了报错AVLN2000 Unable to resolve property or method of name 'Id' on type 'XamlX.TypeSystem.XamlPseudoType'.,查看类型ExploreViewModel,定义大概如下

1
2
3
4
5
6
7
8
9
public class ExploreViewModel : ViewModelBase
{
public A[] B { get; set; } = new A[] { ... };
}

public class A{
int Id,
string Name
}

造成该问题的原因是我需要使用的属性B是一个原始的数组,这里应该使用ObservableCollection因此解决方案是做出如下修改

1
2
3
4
public class ExploreViewModel : ViewModelBase
{
public ObservableCollection<Assistant> Assistants { get; set; } = new (new List<Assistant>{...});
}

至此能够成功编译运行

Scoop意外卸载的处理办法

这几天发现电脑上的Scoop莫名其妙消失了,我觉得可能是UniGetUI的问题,总之我的Scoop被卸载了,使用Scoop安装的软件的环境变量也失效了,这导致我写代码的相关环境无法使用。
在重新安装Scoop后,环境变量没有恢复,而我发现路径C:\Users\用户名\scoop没有丢失,那么说明软件文件和持久化数据应该没有丢失,寻找一些资料后,我在一篇Github Issue中找到了解决办法,如果你遇到了相同的问题,可以尝试按照以下步骤解决:

1
2
cd C:\Users\用户名\scoop\apps
scoop reset *

我在重新安装Scoop并且进行了该操作后,成功恢复了大多数软件对应的环境,除了一些我已经打开的一些软件没有恢复,不过后面也可以手动scoop reset 软件名来单独进行恢复

Nuxt.js content使用项目组件报错

问题描述

最近使用 Nuxt.js 的 Content 模块时,发现其支持项目中写好的 Vue 组件,相关文档可以参考 这里
我在页面中尝试添加如下组件,该组件位于~/components/XXX/VideoArea.vue

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
<script setup lang="ts">
import ArtPlayer from "artplayer"

const art_ref = ref<HTMLInputElement | null>(null)
const art_instance = ref<Artplayer | null>(null);

const props = defineProps<{ url: string }>()

onMounted(() => {
if (!art_ref.value) return
// 文档参考: https://artplayer.org/document/start/option.html
art_instance.value = new ArtPlayer({
// 指定播放器的容器元素
container: art_ref.value,
// 设置视频的 URL
url: props.url,
// 启用自动迷你模式
autoMini: true,
// 启用自动调整大小
autoSize: true,
// 启用全屏模式
fullscreen: true,
// 使用服务器端渲染
// useSSR: true,
// 启用快进功能
fastForward: true,
// 锁定播放器界面
lock: true
})
})
</script>

<template>
<div ref="art_ref" class="h-96 mr-auto">
<slot></slot>
</div>
</template>

对应 Content

1
2
3
4
5
6
7
---
title: '标题'
description: '简述'
---
::xxx-video-area{url="视频链接"}
视频描述
::

发现启动后报错 If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.,后来发现可能是没有设定全局组件,文档中有提到:

Components that are used in Markdown has to be marked as global in your Nuxt app if you don’t use the components/content/ directory, visit Nuxt 3 docs to learn more about it.
如果在Nuxt应用中使用的组件未放置在components/content/目录下,则需将其标记为全局组件。

对比一下,我的组件在~/components/XXX/下,而不是在~/components/content/下,因此无法访问到该组件。

解决方案

方案一:将组件移动到~/components/content/目录下

假设你的组件仅用于内容页面,可以将其移动到~/components/content/目录下,这样 Nuxt Content 模块会自动识别并加载这些组件。

方案二:将组件名称改为VideoArea.global.vue

参考官方文档,我们修改文件后缀名也可以达到全局化的效果

方案三:将所有组件默认设为全局

nuxt.config.ts中,我们需要增加组件选项,设为全局即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
export default defineNuxtConfig({
compatibilityDate: '2024-04-03',
devtools: { enabled: true },
css: ['~/assets/css/main.css'],

postcss: {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
},

modules: ['@nuxt/content'],

// 为了适配 Nuxt content 必须全局注册
// 注意下面这块,上面的如果你和我不同不需要改动
components: {
global: true,
dirs: ['~/components']
},
})

在Win下编译适用于Linux的Rust程序

最近在尝试在 Windows11 下编译 Linux 可用的程序时遇到了不少问题,我这里总结一个简单的编译方法供大家参考(不过现在都有WSL了,是不是直接在上面编译更好?)

具体方法

安装工具链

rustup target add x86_64-unknown-linux-musl 使用 musl 进行静态连接工具链
你可以使用rustup target list指令来检查自己是否装好了工具链
检查工具链

修改 Cargo 配置

在 ~/.cargo/config.toml (如果没有请自己创建) 内加上

1
2
[target.x86_64-unknown-linux-musl]
linker = "rust-lld"

Cargo配置

进行编译和测试

使用cargo build --target=x86_64-unknown-linux-musl就可以进行编译你的项目了,或者也可以用cargo build --target x86_64-unknown-linux-musl --release来构建 release 模式的
进行编译
可见,很快就编译好了,下面我使用 WSL2 运行该程序测试正确性,代码如下(虽然这个不重要)
程序代码
运行结果如下
运行结果
可见,一切顺利,结束!

Rust萌新之路-变量、函数和判断

我推荐的布局介绍

我推荐使用 Vscode 再安装 Rust-Analyzer 插件进行刷题,记得在开刷之前先执行 rustlings lsp 来启用语法提示,下面给大家看看各个布局窗口的作用
在命令行运行rustlings指令
1号区域是终端,我在里面启动了 rustlings watch 来检查进度,2号区域是各个题目(所有的题目都在 exercises 文件夹内),3号区域就是代码编辑框了,这样简简单单就可以开始了

Intro 和 Variables

Intro 部分其实没什么好看的,主要是教你如何使用 Rustlings ,在终端中提示通过编译后,你把注释中的 // I AM NOT DONE 删掉就可以了

Variables 里面的东西也比较简单,主要就是考变量的初始化语法、未初始化不能使用、如何创建可变变量、重新申明变量、常量必须指明类型这些,基本上没有什么问题,就不赘述了。

Functions 和 If

Functions 内的内容也比较基础,主要考察了函数的创建、参数的定义和传入、返回值的定义方式、通过去掉分号来返回一个值
很轻松就能解决这一块,我也认为这一块不会出现什么问题,也不多讲了。

If 的第一题体现了我很喜欢的一点,就是 Rust 中的 if 语句是有返回值的,同样可以用去掉分号来表示返回,整体也可以作为函数的返回值,因此这题我的答案是这样的

1
2
3
4
5
6
7
pub fn bigger(a: i32, b: i32) -> i32 {
if a>b {
a
}else {
b
}
}

第二题也类似,答案如下

1
2
3
4
5
6
7
8
9
pub fn foo_if_fizz(fizzish: &str) -> &str {
if fizzish == "fizz" {
"foo"
} else if fizzish == "fuzz" {
"bar"
}else {
"baz"
}
}

不过这里其实有一个比较有意思的地方,返回值是一个&str,新手可能会忘记为什么这里不需要标注生命周期,请让我来解释一下,这是因为这个函数满足了生命周期省略规则,我认为这里满足的是“如果只有一个输入生命周期参数,那么它被赋予所有输出生命周期参数”,所以我觉得函数签名应该等价于 pub fn foo_if_fizz<'a>(fizzish: &'a str) -> &'a str ,不过考虑到字符串字面量的生命周期是 'static ,我认为这里也可以是 pub fn foo_if_fizz(fizzish: &str) -> &'static str,具体是什么样希望能有大神指出。

Quiz1

终于到了第一个小测验了,这也会是第一篇的最后一题,这是关于上面的 Variables、Functions 和 If 的测验。
对于写完前面的你应该算是简简单单

1
2
3
4
5
6
7
fn calculate_price_of_apples(num:i32)->i32{
if num>40{
num
}else{
num*2
}
}

本章到此就结束了

有用的其他参考

Rust萌新之路-Rustlings的安装

专栏简介

我学习 Rust 已经有一小段时间了,Rustling 这个项目我认为是新手学完Rust基本语法,或者在看完 The Book (中文版) 后,一个很适合的练习题组,这个项目提供了75道 Rust 语言的小题目,提供了方方面面的考验,对于绝大多数题目也都有足够的提示,但是鉴于我没有找到使用中文介绍这些题目的文章,便打算自己开一篇介绍和讲解,本人有的实现可能不够好,或者讲解有谬误,希望各位斧正。

安装 Rustlings

既然你已经开始想要写 Rust 练习题,那么你应该已经安装过Rust了,就不做多的介绍了,如果你还没有安装,请参考官方的这个页面,可以先安装Visual Studio最新版后,勾选适用于桌面的C++开发,然后安装 Rustup 等工具。

接下来,打开 Rustlings 官方仓库 ,里面介绍了安装的方式,在 Mac OS 或者 Linux 操作系统上,安装 Rustlings 是很简单的

1
curl -L https://raw.githubusercontent.com/rust-lang/rustlings/main/install.sh | bash

使用这个命令就可以把它安装到你的电脑上,之后就可以使用 Rustlings 指令了。至于 Windows 下稍微复杂一点,你需要先激活 Powershell 的脚本运行权限,然后就可以运行安装指令了

1
2
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Start-BitsTransfer -Source https://raw.githubusercontent.com/rust-lang/rustlings/main/install.ps1 -Destination $env:TMP/install_rustlings.ps1; Unblock-File $env:TMP/install_rustlings.ps1; Invoke-Expression $env:TMP/install_rustlings.ps1

如果你不喜欢上面的安装方式,也可以手动安装,也没多麻烦,先下载这个 git 仓库,然后在里面运行 cargo install –path . 就行了,我使用 git clone 进行下载,指令可以参考如下(可以把5.2.1替换成最新版本)

1
2
3
git clone -b 5.2.1 --depth 1 https://github.com/rust-lang/rustlings
cd rustlings
cargo install --force --path .

这样,你就完成了 rustlings 的安装,尝试在命令行运行 rustlings ,它会给你反应

在命令行运行 rustlings 指令

基础使用

其实需要做的操作很少,你如果只是做题的话在 rustlings 目录下使用 rustlings watch 就够了,以下内容主要是我对官方操作解释的翻译(注意,你的指令一定要在 rustlings 目录下运行,不要到上级或者子目录)

你要做的所有题目都在 rustlings/exercises/ 文件夹里,当你想以官方推荐的顺序来做的话,运行

1
rustlings watch

它会持续按顺序检查题目,并且给出错误(每当你编辑过之后),你需要修好错误或者使代码通过编译,它就会进入下一个题目,直到所有题目完成,或者你关闭了它,如果你只想运行一次而非持续运行,你可以允许下一条指令

1
rustlings verify

如果你想手动指定它检查的题目,你可以用 run 指令

1
rustlings run 测试名

或者使用 run next 来检查下一个的

1
rustlings run next

当你遇到了不会的题目,需要一定帮助时,可以使用 hint 指令,它的用法和 run 差不多,可以指定名字或者使用 next 来查找下一个

1
2
rustlings hint myExercise1
rustlings hint next

list 指令可以用于检查你的进度

1
rustlings list

例如我的输出就是都做完了

我运行 rustlings list 的结果

另外有一个非常重要的,就是你会发现你在编辑时无法使用 Rust-Analyzer ,这怎么行?启用的方法官方仓库也有给出,就是运行

1
rustlings lsp

另外,卸载的方法如下:

  1. 先删除 rustlings 所在的文件夹
  2. 运行 cargo uninstall rustlings

有用的其他参考

Hello World

欢迎来到 Sworld 的博客主页!
本站正在建设,请往下翻以查看更多文章!