使用Module::Build构建发行版时如何实现安装卸载阶段缓存清理
安装阶段清理残留缓存
Module::Build默认不会操作用户主目录下的任何内容,要保证安装时无旧缓存残留,直接在Build.PL中重写ACTION_install钩子,在执行原生安装逻辑前先清理对应路径的缓存即可:
use Module::Build; use File::Spec; my $build = Module::Build->new( # 此处保留你原有的模块配置,比如module_name、license、依赖声明等 module_name => 'My::Module', license => 'perl', # ... 其他原有配置项 ); sub ACTION_install { my $self = shift; # 匹配所有符合命名规则的缓存文件 my @old_caches = glob File::Spec->catfile( $ENV{HOME}, '.cache', 'my_*.cache' ); # 静默删除旧缓存,无文件/无权限时不中断安装流程 unlink @old_caches; # 执行原有安装流程 $self->SUPER::ACTION_install(@_); } $build->create_build_script;
注意:安装流程的执行权限和运行安装命令的用户一致,如果用root执行全局安装,仅会清理root用户家目录下的缓存,不要强行遍历所有用户家目录做清理,会在多用户系统上触发权限错误和安全问题。
卸载阶段自动清理缓存
Module::Build默认没有内置卸载动作,你可以自行在Build.PL中定义ACTION_uninstall实现卸载+缓存清理的逻辑,把下面的代码追加到上面的Build.PL中即可:
sub ACTION_uninstall { my $self = shift; # 先执行标准卸载逻辑,移除所有已安装的模块文件、文档、可执行脚本 require ExtUtils::Install; ExtUtils::Install::uninstall( $self->install_map, 1, # 设为0可关闭卸载过程的详细输出 0, # 设为1可跳过删除确认提示 ); # 卸载完成后清理当前操作用户的缓存 my @user_caches = glob File::Spec->catfile( $ENV{HOME}, '.cache', 'my_*.cache' ); unlink @user_caches; print "已清理用户缓存文件\n" if @user_caches; }
定义完成后,用户在源码目录执行perl Build.PL && ./Build && ./Build uninstall即可完成完整卸载。同样的,这个逻辑仅会清理执行卸载命令的用户家目录下的缓存,符合多用户系统的权限规范。
兜底兼容方案
如果用户通过cpanm等包管理器直接安装,不会手动执行uninstall命令,最稳妥的兜底方案是在模块自身的初始化逻辑中加版本校验:每次模块启动时检查缓存对应的版本标记,如果当前模块版本和缓存生成的版本不匹配,自动清理所有旧缓存,这个逻辑不依赖安装/卸载流程,兼容性最好。
核心实现参考:
# 放在模块初始化入口处 use File::Spec; our $VERSION = '0.01'; # 你的模块版本号 my $cache_dir = File::Spec->catfile($ENV{HOME}, '.cache'); my $version_mark = File::Spec->catfile($cache_dir, '.my_module_cache_ver'); my $cache_ver = ''; if (-f $version_mark) { open my $in, '<', $version_mark; $cache_ver = <$in>; chomp $cache_ver; close $in; } # 版本不匹配时清理所有旧缓存 if ($cache_ver ne $VERSION) { unlink glob File::Spec->catfile($cache_dir, 'my_*.cache'); # 写入新版本标记 open my $out, '>', $version_mark; print $out $VERSION; close $out; }
提示:如果你的模块会被打包成deb、rpm等系统发行版包,不要把用户目录的缓存清理逻辑写在系统包的卸载脚本里——系统包卸载时以root身份运行,仅能清理root的缓存,普通用户的缓存通过上述模块内的版本校验逻辑处理即可,这是桌面类软件通用的缓存处理规则。
内容的提问来源于stack exchange,提问作者Tim Potapov

