分类 软件 下的文章

(碎碎念环节之 诈尸 ) 之前在读书的时候,就好奇有些巨佬的博客,怎么写着写着过几年就不更新了,还挺可惜的。直到自己上班才发现,这b班上的是真忙。本来空闲时间就不多,下班的时间还都拿来休息回血了,最多也就抽空临幸下老爱好或者填坑了,谁还有时间跟闲着没事一样一周写两份周报啊。再加上坚持写博客的人大多是有追求有讲究的,总不能内容越写越烂,于是为了精品内容就变成了经典爷爷up主,隔几个月甚至几年才突然诈尸一次,而某些精品博客可能就在这个过程中逐渐消亡了。虽然伤感但是非常现实,人总是要先吃饱饭的,哪里有其他精力空出来搞这些花里胡哨的事情。


最近在研究あいミス的解包汉化,好不容易花了一个星期把加密逻辑梳理走通了,然后开始看文本怎么提取、翻译、重新打包。(此处不得不提某个头铁憨憨,放着Android+IL2CppDumper不用,头铁用f12去看wasm汇编,折磨了小一个星期差点弃坑。)留个坑吧,有空考虑要不要写篇文章,记录下分析拆包是怎么做的。

看了半天发现,发现很多解包工具都不更新了,比如经典的AssetStudioUABE,想着靠谱起见,至少找一个在更新的工具吧。找了半天发现还得是LLM,ChatGPT马上就提供了有效信息,有个叫UnityPy的工具还在更新。一看,是个python程序库而不是界面软件,正好拿来给我批量处理当API调用,免得自己还要去改源程序当库用了。

然后天就塌了。由于不想装VSCode,就在linux上部署了code-server开发。装了python插件之后发现,代码高亮没了,怎么按快捷键都提示没有补全项可用。看了下控制台输出,发现pylance没有调用日志,以为是python插件的版本问题,就去折腾怎么降级python插件版本。一路从2025年试到2022年都没用,实在没辙了,就去问ChatGPT。好嘛,不问不知道,原来微软这鸡贼小子在pylance插件了加了史,只有微软自家发布的VSCode可以正常调用pylance插件,其他基于开源VSCodium方案的发行版会调用失败。我拿2024年的pylance插件试了下,服务确实可以启动起来,但是会输出一大堆车轱辘话。一开始没在意,以为是什么EULA一类的,后面看了社区讨论才知道,这是暗戳戳在内涵用户不是在官方环境下安装的插件来着。

想着几年前,最开始接触code-server的时候,安装python全家桶插件是使用正常的,于是决定回溯看是哪个版本加的史。二分找了一下,最后可用的版本大约在2023.6.30这里,高于这个版本的pylance插件就会开始bb并拒绝工作了。

后续是搜了一下,发现推荐的用法是,用开源的basedpyright代替pylance,其他插件正常安装就行,与vscode默认配置功能基本一致。唯一比较明显的是,由于缺少了巨硬魔法的加持,生成代码补全的速度略慢了一些,能够感受到从输入到出现提示的明显延迟,要是补全的tab或者回车敲得稍微快一些,能直接打断LSP施法。

啊?这玩意还能有第三期?

起因是想玩玩ChatGLM3,然后发现这个库用的pytorch版本特别新(说是要求2.0以上,实测1.12也行),于是就打算自己编一个新版本玩玩。然后人就傻眼了:编了几天,编译过程是挺顺利的,结果编出来的whl用不了,一import就报OSError 1114,说是某个DLL的初始化函数出了问题,一开始以为是编译器坏了(因为就在当天一次重启把我CUDNN炸了,也不知道是不是SSD的问题 汰渍全责!),前后更换配置(Python版本/MSVC版本/是否启用CUDA,甚至换了电脑)编了几天,SSD都写了快1TB了,还是没有任何进展。

然后也是因为各种配置问题没文档,编不出Debug版的wheel来,就着RelWithDebInfo版用regsvr32看了半天,发现好像是因为某个全局静态变量没有初始化还是咋的,导致DLL加载过程中抛出了c10库的异常,没给任何有用信息就直接把主程序炸了;然而由于该方法只是简单地加载了一个DLL,并不一定遵循PyTorch应有的初始化逻辑,所以也不知道有没有参考价值。

最后实在想不通了,为什么官方编出来的装了可以直接用,于是决定去偷学官方ci的编译脚本,看看编译流程上和自己的到底有啥区别,结果最后发现,好像最大的差别是他用的是Ninja生成,而我用的是MSBuild。虽然认为本质上应该没啥区别,但是抱着死马当活马医的心态,装了VS自带的CMake工具(对,这玩意其实也自带Ninja的),然后有样学样,用Ninja来编译PyTorch。虽然不是很想用咕果家的东西,但是不得不承认的是,Ninja的TUI还是做得比MSBuild好的,至少可以大致了解到编译流程进行了多少= =

这里贴一下中间需要设置的变量:

  1. set CMAKE_GENERATOR=Visual Studio 16 2019(因为我没把Ninja加到PATH,以及VS2017编译会有报错);
  2. set DISTUTILS_USE_SDK=1,不然CUDA配置那里可能报一些奇奇怪怪的错误;
  3. python setup.py bdist_wheel,然后理论上他configure完会出现异常终止,因为MSBuild内部调的Ninja和我们设置的环境变量不符合;
  4. set CMAKE_GENERATOR=,取消generator的设置;
  5. 重新执行3,理论上应该不出现任何问题,直到编译完成。

然后就是经典环节了。pip安装编完的whl,import,没有报错,直接成功了,是的,成功了。

很喜欢计算机人的一句话:啊?

只能说是在摸清问题之前解决了问题了罢。咱又不开发AI框架,既然问题解决了,那探究先到此为止吧。

鉴于某些众所周知的原因,GitHub传输速度太拉,gitee又半死不活的,于是决定给自己搭个本地git仓库用,一方面解决了公私有代码的问题 反正都是私有了,另一方面上传下载快的1p,还可以选择自己喜欢的管理风格。然后简单整理了一下现有的开源git服务器。只能说这玩意一团散沙,不靠友商对比都不知道有哪些,在这里简单列一下。

  1. ruby系:GitLab。这个没什么好说的,说到私有git服务器第一反应必然是这个,似乎也是目前已知的开源git服务器中体量最大的,功能齐全,界面美观。问题在于自己编linux包麻烦,我omnibus-gitlab整了几天都没编出来= =

  2. golang系:Gogsgiteaforgejo。这仨一脉相传,我是先用的forgejo,然后又回头试用了下gogs,发现两者的html模板几乎都长得一模一样,后知后觉地搜了下才发现的。简单概括来说,就是先有的gogs,然后一群贡献者嫌gogs更新慢、不加新功能,然后fork出了gitea;然后gitea搞了几年之后开公司了,codeberg担心gitea搞收费,就又从gitea代码fork出了一个forgejo自己开发(贵圈真乱.jpg)。但是不得不提的是,gogs的确老了,甚至不支持统计展示当前仓库各个语言的代码量。。

  3. Java系:gitbucketGitBlitOneDev。这三家都是个搞个的,其中OneDev比较新,界面做的也比较现代化。

出于兼容性考虑,还是编译一份32位版的,哪都能用。

装包:

pacman -S mingw-w64-i686-gtk3 pkg-config mingw-w64-i686-amtk mingw-w64-i686-tepl mingw-w64-i686-libpeas mingw-w64-i686-gobject-introspection mingw-w64-i686-gspell mingw-w64-i686-vala mingw-w64-i686-itstool mingw-w64-i686-desktop-file-utils

其中有几个地方要修改一下:

  1. 复制一份pkgconfig的tepl-6.pctepl-5.pc,msys2没有这个包;
  2. meson改了API导致语法不兼容,可以选择装meson的时候指定版本为0.59(参见meson.build),或者把data/meson.build文件第七行删掉。

配置:

git checkout gnome-3-38-fix-build
MSYS2_ENV_CONV_EXCL='PKG_CONFIG_PATH' meson

其中MSYS2_ENV_CONV_EXCL是针对MSYS2会自动改变环境变量的分隔符而加的。MSYS2装的pkgconfig只认冒号分隔符,但是MSYS2会自动转成分号,这样pkgconfig就只认PKG_CONFIG_DIR中的最后一个,导致pc文件找不到。

编译完成之后,在MSYS里设置好XDG_DATA_DIRS就可以使用了。界面和Linux下完全一样,win的标题栏都没了。然而非常诡异的一点是,如果试图把dll文件复制到gedit一起打包的话,会发现根本启动不起来,两者只能单独分开,然后通过PATH联系起来,就tm离谱。在3.36版本之前是有win32打包脚本的,不过之后被移除了,可以去git历史里面去看,然而我执行又是各种报错= =

===

第二天更新

又看了眼,发现相比于把dll复制到install目标文件夹里,官方脚本里的配置方式是把gedit install到现有的mingw环境中。那么一种可行的方式是,先用pacman装好需要的库,然后把编译好的gedit install到这个chroot环境中。假设安装到E:\gedit\mingw32目录,那么根据make-gedit-installer脚本,可以有如下操作:

pushd /e/gedit
mkdir -p var/lib/pacman
mkdir -p var/log
mkdir -p tmp
pacman -Syu --root `pwd`
pacman -S mingw-w64-i686-gtk3 ...  # 后面的库略

这个地方的mingw32文件夹是不可少的,主要是因为msys2为了做环境隔离,设立了多个子文件夹。后续可以把这个mingw32文件夹单独提出来,重命名后自由使用。

还有一种偷懒的方法是,先直接用pacman装gedit,再卸掉这个包,剩下来的就是依赖环境了

然后再用meson去reconfigure gedit,指定prefix为E:\\gedit\\mingw32,重新执行ninjaninja install即可完成安装。安装完大小接近1个G,如果需要精简空间,可以参考remove_useless_stuff函数,改改路径前缀执行,最终能把大小控制在400MB以内。(经典的gedit 2.30展开安装也才80MB左右,通货膨胀严重啊)

因为这里不打算发行,就不按照原始脚本用wix进行后续打包工作了。

看到MSYS和winlibs两个网站上的gcc都区分了MSVCRT和UCRT版本,这里简单记录一下。

再简单提一下C/C++运行库(C Runtime,CRT)的概念吧,因为所有符合C/C++标准的程序采用的绝大部分基本函数都具有相同的功能(最典型的就是stdio.hmemory.hiostream了),因而将这些常见函数抽象出来做成单独的程序库能够有效节省编译时间,并且对闭源编译器还有隐藏实现的功能等。

然后这里MSVCRT指的是当年Visual C++系列随编译器附带的运行库,也就是说发布一版VC++就会发布一版MSVCRT,那么在动态链接的情况下,目标机器就必须安装对应的运行库。比如说原来最为常见的找不到MSVCP80.dll这类信息,就是因为这种情况产生的,也就是俗称的缺库。

那么UCRT就是微软为了解决这一问题提出的新方案。程序不再链接到某一具体版本的CRT,而是链接到一系列中间dll上,形如api-ms-win-xxxx.dll,想必在某些地方见过。这些dll文件非常小,它们并不包含具体函数的实现,而是作为一个中间层,将对应的函数请求转发到当前系统所支持的CRT中。没有什么是加抽象层解决不了的问题

然后这里区分两种CRT的话,实际上并不只是区分编译出来的程序最终默认链接到哪种CRT,这些gcc本身也会被链接到对应的库。比如说,UCRT版本的gcc会链接到ucrtbase.dll,而MSVCRT版本的会链接到mscvrt.dll

PS1. UCRT版本的gcc包含有MSVCRT的库,但是反过来没有验证是否同样支持; PS2. 在gcc的C支持库中,可以通过传递--with-default-msvcrt=ucrt参数来让MinGW使用UCRT作为其支撑运行库。