nextpnr 权限被拒:Permission denied 速查
更新时间:2026-10-23。FAQ 速查页,面向在 Linux 服务器、WSL、Docker 容器里跑开源 FPGA 链路(Yosys + nextpnr + iceprog/openFPGALoader)的同学。nextpnr 本身只是个命令行工具,但布局布线要写
.asc/.bit产物、读 chipdb、走临时目录,烧录环节还要直接打开 USB 设备——任何一级路径或设备节点不可写、不可访问,操作系统就甩回一句Permission denied。这句话来自内核,不是设计有错,也不是工具装坏了。同语义在 Yosys 侧的姊妹篇见 Yosys 权限被拒速查,商业工具侧对照见 Quartus 权限被拒速查。
本文要回答的问题
- 报错里的
open: Permission denied与failed to open file分别落在哪个阶段,怎么读原文? - 以前用 sudo 跑过一次 make 之后普通用户再也编不动,怎么救?
- chipdb 装在
/usr/share这类只读区,nextpnr 到底会不会往里写? - Docker 里
-v挂载的工程目录属主对不上,报权限错怎么修? - 烧录时 iceprog / openFPGALoader 报 libusb 权限错,udev 规则怎么配?
一、报错原文与典型现象
权限类报错分散在布局布线、产物写盘、烧录三个阶段,先认出五种典型形态(工程路径以 /proj/demo 占位):
ERROR: failed to open output file '/proj/demo/build/top.asc': Permission denied
ERROR: failed to open file '/proj/demo/build/top.json' for reading: Permission denied$ make
nextpnr-ice40 --hx8k --package ct256 --json build/top.json --asc build/top.asc
make: *** [Makefile:12: build/top.asc] Error 1
/bin/sh: 1: cannot create build/top.asc: Permission denied烧录阶段报在 USB 设备上,与工程文件无关,这是开源链路里最高频的一枝:
$ iceprog build/top.bin
init..
Can't find iCE FTDI USB device (vendor_id 0x0403, device_id 0x6010 or 0x6014).
ABORT.
$ openFPGALoader -b ice40_generic build/top.bin
Error: failed to open device: LIBUSB_ERROR_ACCESS
libusb: error [_get_usbfs_fd] libusb couldn't open USB device /dev/bus/usb/001/005: Permission denied读报错的关键是盯住路径落在哪一枝:报在 build/、output/ 下是工程产物目录写权限问题;报在源码 .v、.json 上是读权限问题;报在 /dev/bus/usb/... 或 libusb 上是 USB 设备节点访问权问题,与前两类互不相干。/usr/share/nextpnr 这类安装目录本来就该只读,正常跑 nextpnr 不会往里写——报错路径落在安装区时,先怀疑是不是把工程建在了安装目录里。
二、病因处置速查表
| 报错现象 / 场景 | 可能原因 | 快速验证 | 处置 |
|---|---|---|---|
| 写 build/top.asc 被拒,目录属主是别人 | 工程来自压缩包/同事,保留原 uid | ls -l build/ 看属主 | chown -R <user>:<组> <工程目录> |
| sudo make 一次后普通身份全被拒 | build/、json、asc 变 root 属主 | ls -l build 出现 root | sudo chown -R <user> <工程目录>,禁 sudo 跑 make |
| 报 Read-only file system | NFS/共享文件夹以 ro 挂载 | mount | grep /proj 看 ro | 工程挪到可写分区 |
| /tmp 下临时文件报错 | TMPDIR 权限异常或指向只读区 | ls -ld /tmp;echo $TMPDIR | 修 /tmp 为 1777 或改 TMPDIR 到 HOME |
| Docker 里写挂载目录被拒 | 容器内 uid 与宿主机文件属主不匹配 | 容器里 id 对比宿主 ls -ln | --user $(id -u):$(id -g) 启动容器 |
| 读 /usr/share/nextpnr 下 chipdb 报错 | 安装时权限位错(别人 700) | ls -l /usr/share/nextpnr* | 重装或 chmod a+rX 修读位 |
| iceprog 找不到 FTDI / libusb ACCESS | 当前用户无 USB 设备节点访问权,缺 udev 规则 | lsusb 能看到设备但工具打不开 | 配 udev 规则后拔插,或把用户加 plugdev |
| 容器内烧录报权限错 | 容器默认隔离 USB 设备 | 容器里 ls /dev/bus/usb 为空 | 加 --device 或 --privileged,udev 规则仍要配 |
| 权限位全对仍被拒(服务器) | NFS root_squash / uid 映射错乱 | 两台机器各跑 id 比对 uid | 找管理员统一 uid 或调整导出选项 |
三、排查决策图
下面这张图是标准排查路线,颜色按角色区分:红是报错入口与命中的根因,蓝是排查动作,绿是通过分支,橙是修复动作,紫是防复发沉淀。
读这张图抓住两条主线:左支是文件侧——八成案例是 build/ 里混进了 root 或别人属主的产物文件,或者挂载/TMPDIR 是只读的;右支是设备侧——iceprog、openFPGALoader 要直接打开 USB 设备节点,当前用户没权限就报 libusb 错。两条支路互不相干,修文件不用动 udev,修烧录也不用 chown 工程,先用报错路径归类再走对应分支。
四、逐条排查展开
文件侧:先看产物树属主。 nextpnr 的工作目录约定是 build/(或工程里自定的输出目录)放 .json、.asc、.bit、时序报告,属主必须是跑 make 的用户。高频事故三个来源:同事打包发来的工程保留了对方 uid;用 sudo 跑过一次 make(或 root 装完工具顺手编译演示)导致整棵 build 变 root 属主;NFS 或虚拟机共享文件夹以只读或 uid 映射错乱的方式挂进来。一条命令看清现场:
whoami; id
ls -ld /proj/demo /proj/demo/build
ls -l /proj/demo/build | head
mount | grep " /proj"
ls -ld /tmp; echo "TMPDIR=$TMPDIR"属主不对就归还:sudo chown -R <user>:<组> /proj/demo。不要图省事 chmod -R 777——共享服务器上这会让别人的运行踩坏你的产物,也不符合审计要求;协作目录用公共组加 setgid 更干净:
sudo chgrp -R <协作组> /proj/demo
chmod g+s /proj/demo
umask 002mount 输出带 ro 是只读挂载,chmod 改不了,只能挪工程。/tmp 标准权限是 drwxrwxrwt(1777),如果被改坏(比如清理脚本误动),nextpnr 与 yosys 的临时文件全部失败,sudo chmod 1777 /tmp 修复;TMPDIR 若被环境变量指到只读区,改回 HOME 下目录即可。
chipdb 只读是正常设计,不是病。 nextpnr 的芯片数据库装在 /usr/share/nextpnr 或 /usr/local/share/nextpnr,普通用户只读完全正常——nextpnr 只往里读。报错路径落在 chipdb 上只有两种可能:安装时权限位搞错(目录变成 drwx------ 属 root,普通用户读不了,sudo chmod -R a+rX 修复或重装);或者你把工程目录误建在了安装区里,挪走即可。
Docker 属主错配。 容器里默认 root 跑 nextpnr,写出的 build 产物在宿主机看属主是 root,下次宿主机普通用户编就报拒;反过来容器里用非 root 用户跑,而挂载目录属主是宿主机另一个 uid,容器内写也拒。标准解法是让容器内 uid 与宿主机一致:
docker run --rm -it \
--user "$(id -u):$(id -g)" \
-v /proj/demo:/work -w /work \
<fpga镜像> make烧录还要多一步:容器默认看不到 USB 设备,加 --device=/dev/bus/usb(或具体节点),宿主机上的 udev 规则依然要配——容器隔离的是设备可见性,不是内核权限检查。
烧录侧:udev 规则是开源链路的装机必修课。 iCE40 开发板(iCEstick、iCEBreaker 等)走 FTDI 芯片,VID:PID 常见 0403:6010 / 0403:6014;lsusb 能看到板子但 iceprog 打不开、openFPGALoader 报 LIBUSB_ERROR_ACCESS,就是当前用户对 /dev/bus/usb/001/005 这类节点没有读写权。以 root 身份创建 /etc/udev/rules.d/53-ftdi-ice40.rules:
# iCE40 开发板 FTDI
SUBSYSTEM=="usb", ATTR{idVendor}=="0403", ATTR{idProduct}=="6010", MODE="0666"
SUBSYSTEM=="usb", ATTR{idVendor}=="0403", ATTR{idProduct}=="6014", MODE="0666"然后 sudo udevadm control --reload-rules && sudo udevadm trigger,拔插一次板子。更严格的环境把 MODE="0666" 换成 GROUP="plugdev" 并 sudo usermod -aG plugdev <user>,重新登录生效。修好后 openFPGALoader --detect 能列出板子就算闭环。
最小复现一锤定音。 在自己的 HOME 下新建空目录,放一个点灯级顶层(一个 always 块翻转 LED),跑完整 yosys → nextpnr → icepack 流程:能通过,说明工具安装与 chipdb 都没问题,病灶 100% 在原工程目录的权限或挂载;空工程也失败,再回头查 /tmp、TMPDIR 与安装目录读位。烧录侧用 lsusb 加 openFPGALoader --detect 复验——能探测到 JTAG 链上的器件型号就算闭环。
五、规范做法与预防
- 工程只放可写目录:个人或项目可写分区,远离安装目录与系统盘;NFS/共享文件夹先确认不是 ro。
- 绝不 sudo 跑 make:装工具归 root、编译烧录归普通用户;发现 build/ 里有 root 属主文件立刻 chown 归还。
- 产物树不进版本库:
build/整个加入忽略列表;共享的是 RTL 源、约束(.pcf/.lpf)与 Makefile。 - udev 规则装机即配:新机器装完开源链顺手写好 FTDI 规则,比每次烧录报错再查省事得多。
- Docker 启动固化
--user:把 uid 映射写进 Makefile 或 compose 文件,别靠记性。 - 报错先归类再动手:路径在工程目录查属主与挂载,路径在
/dev/bus/usb查 udev,两路别混修。
这一篇在知识体系里的位置
本篇是 FPGA 工具排错速查簇的一员:nextpnr 文件与 USB 权限问题看本篇;上游综合阶段同语义报错看 Yosys 权限被拒速查;商业工具侧的对照(jtagd、quartus_sh、Programmer)看 Quartus 权限被拒速查——三家的报错措辞不同,但「属主错乱、只读挂载、下载器设备权限」三根病因轴完全同构,ls -l、mount、lsusb 三件排查套可以互相迁移。
一句话总结
nextpnr 权限被拒先读报错路径归类:落在 build/ 产物或源码上是文件侧问题,八成是 sudo 残留 root 产物、压缩包解压的他人 uid、只读挂载或 TMPDIR 异常,用 ls -l、mount 定位后 chown 归还或挪工程,切勿一把 777;落在 /dev/bus/usb 或 libusb 上是烧录侧问题,配 FTDI 的 udev 规则重插板子即可,Docker 里还要加 --user 与 --device;工程放可写目录、不 sudo 跑 make、udev 规则装机即配,这类报错即可基本绝迹。