编程开发与计算机科学

通过 GitHub Actions 编译 Lazarus 项目

理论上 Lazarus 是支持交叉编译的,但官方发行的默认版本并没有打包不同平台所依赖的各组件。比如在 Windows 平台上将编译目标设为 Linux 时,编译器会报错:Can’t find unit system used by fcllaz ——缺少 Linux 平台上的预编译文件。

虽然可以使用 fpcupdeluxe (GitHub) 项目安装支持交叉编译的 Lazarus 工具链,不过这个工具似乎不支持命令行环境下的配置和安装。

……

Lazarus 项目支持多语言国际化(进阶篇)

在之前的一篇文章中简单介绍了如何在 Lazarus 项目中启用多语言国际化。不过使用 DefaultTranslatorSetDefaultLang() 无法实现运行时动态切换 GUI 的语言。更准确地说,在程序中首次调用 LCLTranslator.SetDefaultLang(),并将参数 ForceUpdate 设为 True,是能够在运行时修改 GUI 语言的,但若再次调用便无效了。

查看 SetDefaultLang() 源代码:

pascalfunction SetDefaultLang(Lang: string; Dir: string = ''; LocaleFileName: string = ''; ForceUpdate: boolean = true): string;
{ Arguments:
  Lang - language (e.g. 'ru', 'de', 'zh_CN'); empty argument is default language.
  Dir - custom translation files subdirectory (e.g. 'mylng'); empty argument means searching only in predefined subdirectories.
  LocaleFileName - custom translation file name; empty argument means that the name is the same as the one of executable.
  ForceUpdate - true means forcing immediate interface update. Only should be set to false when the procedure is
    called from unit Initialization section. User code normally should not specify it.
}
var
  lcfn: string;
  LocalTranslator: TUpdateTranslator;
  i: integer;

begin
  Result := '';
  LocalTranslator := nil;
  // search first po translation resources
  try
    lcfn := FindLocaleFileName('.po', Lang, Dir, LocaleFileName, Result);
    if lcfn <> '' then
    begin
      Translations.TranslateResourceStrings(lcfn);
      LocalTranslator := TPOTranslator.Create(lcfn);
    end
    else
    begin
      // try now with MO translation resources
      lcfn := FindLocaleFileName('.mo', Lang, Dir, LocaleFileName, Result);
      if lcfn <> '' then
      begin
        GetText.TranslateResourceStrings(UTF8ToSys(lcfn));
        LocalTranslator := TDefaultTranslator.Create(lcfn);
      end;
    end;
  except
    Result := '';
    lcfn := '';
  end;

  if lcfn<>'' then
    TranslateLCLResourceStrings(Lang, lcfn);

  if LocalTranslator<>nil then
  begin
    if Assigned(LRSTranslator) then
      LRSTranslator.Free;
    LRSTranslator := LocalTranslator;

    // Do not update the translations when this function is called from within
    // the unit initialization.
    if ForceUpdate=true then
    begin
      for i := 0 to Screen.CustomFormCount-1 do
        LocalTranslator.UpdateTranslation(Screen.CustomForms[i]);
      for i := 0 to Screen.DataModuleCount-1 do
        LocalTranslator.UpdateTranslation(Screen.DataModules[i]);
    end;
  end;
end;
lcltranslator.pas

该函数首先查找本地的 .po.mo 翻译文件;然后,将程序的资源字符串翻译成本地语言;接下来,创建一个新的 TUpdateTranslator 对象替代全局对象。

……

Free Pascal Hack 之访问对象的 protected 成员

默认情况下,Free Pascal 类中 protected 成员只能被当前类、子类以及同一个 Unit 中的代码访问。然而在实践中,往往会碰到访问其他 Unit 中定义的类实例对象的 protected 成员的需求。通常我们会通过类继承以及修改原始类成员的代码来暴露 protected 成员,然而当该对象来自第三方库,甚至 FCL 和 LCL 时,情况就会比较棘手。有一种 Hack 方法可以实现这个需求,且不用修改原始 Unit 的代码,没有额外副作用。

……

GetSystemMenu() 可能损坏其他进程的窗口菜单

通过 Windows API GetSystemMenu 获取窗口系统菜单(即窗口标题栏右键菜单)句柄,可以实现自定义窗口菜单的功能。但若获取的窗口菜单句柄来自其他进程的窗口,便会引发问题。

……

有趣的编程语言 Red

Red 项目最早始于 2011 年,项目由 Nenad Rakocevic 主导。Red 语言是一种同时具有函数式、声明式、符号式特性的现代编程语言,其目标是构建成一个全栈编程语言。Red 语言受到 Rebol 语言启发,两者语法高度相似。和 Rebol 语言只能解释执行不同,Red 语言还提供了 AOT 编译(生成独立的可执行文件)功能,在未来还将支持 JIT 编译。

Red 语言的主要特性:

……

Free Pascal 链接 C/C++ 静态库

本文提供的方法仅在 Windows 中测试通过,未在 Linux 中进行过测试,但理论上也能使用。

Free Pascal 中可以用非常简单的代码链接到动态库:

pascalfunction MyAdd(x, y: Integer): Integer; external 'mylib.dll' name 'MyAdd';

另外也可以链接到静态库,这样分发程序的时候就不用带上一堆 DLL 文件了。

首先将 C 代码编译为静态库,然后在 Lazarus > 项目选项 > 编译器选项 > 路径 > 库 (-Fl) 中输入静态库存放的路径。此处以 C 编写的静态库导出 MyAdd() 函数为例,演示如何在 Free Pascal 中调用它。

……

Zig 语言:从入门到放弃

一直想用 Zig 来写一点什么。正好看到一个 Zig 的 GUI 项目 Capy,想着用它来试试手。

首先,用 scoop install zig 命令安装了 Zig,版本是 0.14.0(后续会提到)。然后,按照 Capy 的官方文档下载了项目模板,使用 zig build 命令编译。接下来,就遇到第一个扑面而来的问题:

error: unable to discover remote git server capabilities: ConnectionTimedOut

可以确信的是,命令执行环境中已经正确地配置了代理,包括 Git 全局配置、环境变量和系统代理。Zig 没能正确使用代理设置。最后只能使用虚拟网卡实现代理。

……

为什么说鼓吹零基础 AI 编程的都是骗子

前阵子在社交媒体上看到一条消息:「我完全不懂编程,N 小时内写了一个 APP,荣登 App Store 排行榜」。我可以言之凿凿地论断:这就是一个卖课的骗子,所谓的排行榜也是靠作弊刷出来的。因为软件开发的内核从来不是你能否掌握一门编程语言,而是你能否像程序一样思考。目前的 AI 本质上不过是一个玩文字接龙游戏的程序罢了,它无法代替人进行思考(所谓强人工智能)。

……

编译 libmagic.dll

libmagic 是由 file 命令提供的一个开源库,用于检测文件的类型,最新版本为 5.46,发布于 2024年 11 月。PyPI 上有一个名为 python-magic-bin 的包提供了编译好的 Windows 二进制版本,然而最后一次更新已是 8 年前。Scoop 的 main 仓库中也包含了一个由第三方编译的 file 命令,版本号为 5.45,但没有提供 libmagic 的动态链接库。此外,5.45 的 Magic 文件版本是 19,而 5.46 已经升级到 20,两者不兼容。看来是时候考虑自己编译一个 Windows 版本了。

……

如何判断一个窗口句柄是否为桌面顶层窗口

在微软官方文档中,并没有提供一个 API 用于判断一个窗口句柄是否为桌面的顶层窗口。通过类似 NULL == GetParent(hwnd) 或者 hwnd == GetAncestor(hWnd,GA_ROOT) 等简单代码都无法做出正确判断。经过测试,找到两种靠谱的解决方案。

……