必须通过launchdaemon机制注册为系统级守护进程,即创建/library/launchdaemons/下plist文件,配置label、programarguments、runatload和keepalive等键,设权限644并用bootstrap加载。

如果您希望某个程序在 macOS 系统启动早期即以 root 权限自动运行并长期驻留,必须通过 LaunchDaemon 机制注册为系统级守护进程。以下是实现此目标的多种可行方法:
一、创建并加载/Library/LaunchDaemons/下的plist文件
该方法将服务注册为系统级守护进程,由 launchd 在内核初始化完成后、用户登录前即加载,以 root 身份持续运行,适用于需全局生效、高权限或无用户会话依赖的后台任务。
1、使用终端创建配置目录(如不存在):sudo mkdir -p /Library/LaunchDaemons
2、用 nano 编辑器新建 plist 文件:sudo nano /Library/LaunchDaemons/com.example.myservice.plist
3、输入符合规范的 XML 内容,确保包含 Label(全局唯一,推荐反向域名格式)、ProgramArguments(数组形式,首项为绝对路径可执行文件)、RunAtLoad(设为
4、保存退出后,修正文件权限:sudo chown root:wheel /Library/LaunchDaemons/com.example.myservice.plist
5、设置文件访问权限为 644:sudo chmod 644 /Library/LaunchDaemons/com.example.myservice.plist
6、使用新语法加载服务:sudo launchctl bootstrap system /Library/LaunchDaemons/com.example.myservice.plist
二、配合启动脚本封装复杂逻辑
当目标程序依赖环境变量、工作目录或需前置初始化时,直接调用二进制易失败;此时应编写独立 shell 启动脚本,并在 plist 中指向该脚本,从而解耦配置与执行逻辑。
1、创建可执行脚本目录:sudo mkdir -p /usr/local/bin/myservice
2、新建并编辑启动脚本:sudo nano /usr/local/bin/myservice/run.sh
3、在脚本中显式声明环境变量(如 PATH)、切换工作目录,并以 exec 方式调用主程序:exec /usr/local/bin/myservice/main --config /usr/local/bin/myservice/config.yaml
4、赋予脚本执行权限:sudo chmod 755 /usr/local/bin/myservice/run.sh
5、在 plist 的 ProgramArguments 中指定
6、同步调整脚本目录属主与权限:sudo chown -R root:wheel /usr/local/bin/myservice
7、重新加载服务配置:sudo launchctl bootout system /Library/LaunchDaemons/com.example.myservice.plist && sudo launchctl bootstrap system /Library/LaunchDaemons/com.example.myservice.plist
三、启用日志重定向便于排错
系统级守护进程默认不输出到终端,其 stdout 与 stderr 会被丢弃或混入 system.log,导致问题难以定位;通过显式指定日志路径,可将运行时输出分离存储,大幅提升调试效率。
1、预先创建日志目录并授权:sudo mkdir -p /var/log/myservice
2、赋予 root 写入权限:sudo chown root:wheel /var/log/myservice
3、在 plist 的
4、添加错误日志路径:
5、确保日志文件路径为绝对路径,且 launchd 有权限写入:sudo touch /var/log/myservice/out.log /var/log/myservice/err.log
6、重新加载配置使日志设置生效:sudo launchctl kickstart -k system/com.example.myservice
四、验证服务状态与即时调试
加载成功不等于服务正常运行;launchd 提供实时状态查询与强制干预能力,可用于确认进程是否已启动、检查退出原因或触发单次执行,避免重启系统反复测试。
1、列出所有系统域服务并过滤目标标识:sudo launchctl list | grep example
2、打印详细运行时信息(含退出码、上次启动时间):sudo launchctl print system/com.example.myservice
3、若服务未运行,手动触发一次启动:sudo launchctl kickstart -k system/com.example.myservice
4、立即停止当前实例(不卸载配置):sudo launchctl kill 9 system/com.example.myservice
5、查看控制台中该进程最近输出:log show --predicate 'process == "myservice"' --last 5m
6、若需临时禁用服务而不删除文件,执行:sudo launchctl bootout system /Library/LaunchDaemons/com.example.myservice.plist











