工作环境搭建合集

工作环境搭建合集

README.org

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
基于Ubuntu 20.04.4使用Docker构建工作环境。petalinux-2018.3/2022.1采用了分阶段构建,镜像体积大幅缩小。

使用emacs导出index.org代码块,快捷方式:
#+begin_src bash
emacs index.org --batch --eval '(org-babel-tangle)'
#+end_src

代码块导出在index.org文件所在目录下,目录结构如下:
#+begin_src bash
.
├── index.org
├── petalinux-2018.3
│   ├── offline_compile
│   │   ├── Dockerfile
│   │   ├── accept-eula.sh
│   │   ├── zynq_auto.sh
│   │   └── zynqmp_auto.sh
│   └── online_compile
│       ├── Dockerfile
│       └── accept-eula.sh
├── petalinux-2022.1
│   ├── offline_compile
│   │   ├── Dockerfile
│   │   ├── accept-eula.sh
│   │   ├── zynq_auto.sh
│   │   └── zynqmp_auto.sh
│   └── online_compile
│       ├── Dockerfile
│       └── accept-eula.sh
├── petalinux2018.3_FMQLMP-Linux-SDK-Prj-20250408
│   ├── Dockerfile
│   └── accept-eula.sh
└── ubuntu16.04
    ├── Dockerfile
    └── README.md

9 directories, 17 files
#+end_src

vmware安装ubuntu 24.04.4

vmware15.x/17.x都可以安装ubuntu 24.04.4。

准备ubuntu24.04.4镜像

ubuntu历史版本:http://old.releases.ubuntu.com/

1
2
# ubuntu-24.04.4下载链接
http://old.releases.ubuntu.com/24.04/ubuntu-24.04.4-desktop-amd64.iso

下载petalinux及相关的离线编译包

下载petalinux及相关的离线编译包,如果需要仿真的话,也可以下载相关的BSP

1
2
# 访问官网下载界面,指定版本下载
https://www.amd.com/zh-cn/support/downloads/adaptive-socs-and-fpgas/embedded-software.html

ubuntu24.04.04安装docker

安装docker

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# 1. 执行以下命令,添加 Docker 软件源
sudo apt-get update
sudo apt-get install ca-certificates curl -y
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://mirrors.cloud.tencent.com/docker-ce/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo   "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://mirrors.cloud.tencent.com/docker-ce/linux/ubuntu/ \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" |   sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

# 2. 执行以下命令,安装 Docker
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 3. 执行以下命令,运行 Docker
sudo systemctl start docker

# 4. 执行以下命令,检查安装结果
sudo docker info
# 返回如下信息,即表示安装成功
<<'CONTENT'
Client: Docker Engine - Community
 Version:    29.3.0
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.31.1
    Path:     /usr/libexec/docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v5.1.0
    Path:     /usr/libexec/docker/cli-plugins/docker-compose

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 29.3.0
 Storage Driver: overlayfs
  driver-type: io.containerd.snapshotter.v1
 Logging Driver: json-file
 Cgroup Driver: systemd
 Cgroup Version: 2
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
 CDI spec directories:
  /etc/cdi
  /var/run/cdi
 Swarm: inactive
 Runtimes: runc io.containerd.runc.v2
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 301b2dac98f15c27117da5c8af12118a041a31d9
 runc version: v1.3.4-0-gd6d73eb8
 init version: de40ad0
 Security Options:
  apparmor
  seccomp
   Profile: builtin
  cgroupns
 Kernel Version: 6.8.0-71-generic
 Operating System: Ubuntu 24.04 LTS
 OSType: linux
 Architecture: x86_64
 CPUs: 2
 Total Memory: 3.637GiB
 Name: VM-4-13-ubuntu
 ID: 7ba0d015-bc67-4fdf-aa10-22fb3cef9c62
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Experimental: false
 Insecure Registries:
  ::1/128
  127.0.0.0/8
 Live Restore Enabled: false
 Firewall Backend: iptables
CONTENT

docker换源

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
sudo mkdir -p /etc/docker
# sudo tee /etc/docker/daemon.json <<EOF
# {
#     "registry-mirrors": [
#         "https://docker.m.daocloud.io"
#     ]
# }
# EOF
sudo tee /etc/docker/daemon.json <<EOF
{
  "builder": {
    "gc": {
      "defaultKeepStorage": "50GB",
      "enabled": true
    }
  },
  "experimental": false,
  "registry-mirrors": [
    "https://docker.m.daocloud.io"
  ]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

# 测试Docker pull nginx
sudo docker pull nginx

使用 Docker

Docker 的基本使用命令如下:
管理 Docker 守护进程
1
2
3
4
5
6
# 运行 Docker 守护进程:
sudo systemctl start docker
# 停止 Docker 守护进程:
sudo systemctl stop docker
# 重启 Docker 守护进程:
sudo systemctl restart docker
管理镜像。本文以 Docker Hub 的 Nginx 镜像为例
1
sudo docker pull nginx

注意: 如果 docker pull 命令报错 “Get "https://registry-1.docker.io/v2/": xxxxx (Client.Timeout exceeded while awaiting headers)” 则说明是网络问题,建议参考 使用腾讯云镜像源加速 Docker 更换源。

1
2
3
4
5
6
# 修改标签:您可以修改镜像标签以便记忆区分。
sudo docker tag docker.io/nginx:latest tencentyun/nginx:v1
# 查看已有镜像:
sudo docker images
# 强制删除镜像:
sudo docker rmi -f tencentyun/nginx:v1
管理容器
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 运行并进入容器:
sudo docker run -it ImageId /bin/bash
# 其中,ImageId 可通过执行 docker images 命令获取。直接退出当前 SSH 连接的窗口或者通过 “Ctrl+p 接 Ctrl+q” 组合按键将进入的容器放到后台。

# 在后台运行的容器里新执行一个 bash 进程:
sudo docker exec -it 容器 ID /bin/bash
# 通过执行 exit 命令退出 bash 进程。

# 查看后台容器:
sudo docker ps    # 查看运行中的容器
sudo docker ps -a # 查看所有容器

# 重新启动已退出的容器:
docker start <容器 ID>
# 已退出的容器可以用 sudo docker ps -a 命令查询到,命令输出的 STATUS 列包含 “Exited” 的就是已退出的容器。
将容器做成镜像
1
2
3
sudo docker commit <容器 ID 或容器名> [<仓库名>[:<标签>]]
# 例如:
sudo docker commit 1c23456cd7**** tencentyun/nginx:v2
docker镜像的导出和导入
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 云服务器导出完整镜像
docker save -o <导出文件名.tar> <镜像名:标签>
# 例
docker save -o cross-compiler.tar cross-compiler:latest

# 使用scp将镜像从云服务器拷贝到本地,如:
scp opencode:/root/cross-compiler.tar.gz ./
# opencode对应ssh连接目标

# 本地导入
docker load -i <导出文件名.tar>
# 例
docker load -i cross-compiler.tar.gz
删除未使用的镜像
1
2
# 示例
docker rmi nginx:latest
清理构建缓存
1
docker system prune

ubuntu16.04

Dockerfile

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
FROM ubuntu:16.04

# --- apt source switching -------------------------------------------------
# ubuntu:16.04 xenial EOL,官方源已经迁移 old?releases.ubuntu.com
# Build arg example: docker build --build-arg UBUNTU_MIRROR=http://your-mirror -t myimg .
ARG UBUNTU_MIRROR
RUN if [ -n "${UBUNTU_MIRROR}" ]; then \
      sed -i.bak "s|archive.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list && \
      sed -i    "s|security.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list; \
    fi

RUN dpkg --add-architecture i386 && apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt-get install -y \
      --no-install-recommends \
	  net-tools \
      git \
      emacs \
      vim \
      less \
      curl \
      wget \
      iputils-ping \
      tree \
      findutils \
      locales \
      software-properties-common \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# 配置 locale:ENV 保证容器环境变量生效
RUN locale-gen en_US.UTF-8
ENV LANG=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8

构建容器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 使用内网镜像源构建
# docker build --build-arg UBUNTU_MIRROR=mirrors.aliyun.com -t ubuntu16-dev .
# 或
time docker build \
     --network=host \
     --build-arg UBUNTU_MIRROR=mirrors.tuna.tsinghua.edu.cn \
     -t ubuntu16-dev:latest .

# 验证
docker run --rm ubuntu16-dev locale
# 输出应该看到 LANG=en_US.UTF-8,而不是 POSIX

README

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# ubuntu16-dev

基于 Ubuntu 16.04 (xenial) 的开发环境镜像。

## 镜像内容

- 基础镜像:`ubuntu:16.04`
- 多架构:启用 i386 (`dpkg --add-architecture i386`)
- 工具:`net-tools``git``emacs``vim``less``curl``wget``iputils-ping``tree``findutils``locales`
- Locale:`en_US.UTF-8``LANG``LC_ALL` 已设置)
- 代理环境变量:构建时通过 build-arg 传入的 `HTTP_PROXY` / `HTTPS_PROXY` 会同时写入镜像的 `ENV`,容器内可直接复用

## 构建

### 直连网络

```bash
docker build -t ubuntu16-dev:latest .
```

### 通过代理构建(需同时使用 EOL 镜像源)

Ubuntu 16.04 已于 2021 年 EOL,`archive.ubuntu.com` 不再提供 xenial 仓库,需通过仍保留 xenial 的镜像源访问(如 TUNA、Aliyun、USTC)。若同时处于代理环境:

```bash
docker build --network=host \
  --build-arg HTTP_PROXY=http://127.0.0.1:10808 \
  --build-arg HTTPS_PROXY=http://127.0.0.1:10808 \
  --build-arg UBUNTU_MIRROR=mirrors.tuna.tsinghua.edu.cn \
  -t ubuntu16-dev:latest .
```

要点:

- `--network=host` 使构建容器内的 `127.0.0.1` 指向宿主机,从而可直接命中宿主机的 `127.0.0.1:10808` 代理。
- 基础镜像 `ubuntu:16.04` 由 Docker daemon 拉取,需确保 daemon 本身能联通 registry(可通过 `/etc/systemd/system/docker.service.d/http-proxy.conf` 等方式配置)。

## 构建参数

| 参数 | 说明 |
| --- | --- |
| `HTTP_PROXY` | 构建期 HTTP 代理地址,同时写入镜像 `ENV` |
| `HTTPS_PROXY` | 构建期 HTTPS 代理地址,同时写入镜像 `ENV` |
| `UBUNTU_MIRROR` | 替换 `/etc/apt/sources.list` 中的 `archive.ubuntu.com``security.ubuntu.com`(不写协议头,例如 `mirrors.tuna.tsinghua.edu.cn/ubuntu`) |

## 使用

### 启动交互式 shell

```bash
docker run --rm -it ubuntu16-dev:latest bash
```

### 临时执行单条命令

```bash
docker run --rm ubuntu16-dev:latest <command>
```

示例:

```bash
docker run --rm ubuntu16-dev:latest git --version
docker run --rm ubuntu16-dev:latest locale
```

### 挂载工作目录

把宿主机当前目录挂到容器内的 `/work`,进入容器后即可读写宿主机文件:

```bash
docker run --rm -it -v "$PWD":/work -w /work ubuntu16-dev:latest bash
```

### 配置 SSH / Git

容器内 SSH 客户端与 git 已就绪。挂载宿主机 `.ssh` 与 git 配置即可复用:

```bash
docker run --rm -it \
  -v "$PWD":/work \
  -v "$HOME/.ssh":/root/.ssh \
  -v "$HOME/.gitconfig":/root/.gitconfig \
  -w /work \
  ubuntu16-dev:latest bash
```

### 网络与代理

镜像构建时已写入 `http_proxy` / `https_proxy` 等环境变量。若容器内需要访问外网:

- 容器默认使用 Docker bridge 网络,访问 `127.0.0.1` 指向容器自身,不会命中宿主机代理。
- 如需复用宿主机代理,请用 `--network=host`
  ```bash
  docker run --rm -it --network=host ubuntu16-dev:latest bash
  ```

- 也可在 `docker run` 时覆盖:

  ```bash
  docker run --rm -it \
    -e http_proxy=http://127.0.0.1:10808 \
    -e https_proxy=http://127.0.0.1:10808 \
    ubuntu16-dev:latest bash
  ```

### 验证

```bash
docker run --rm ubuntu16-dev:latest bash -c '
  for t in git emacs vim curl wget ping tree find xargs; do
    command -v $t >/dev/null && echo "OK: $t" || echo "MISSING: $t"
  done
  locale | head -3
'
```

## 文件

- `Dockerfile` ― 镜像构建定义
- `README.md` ― 本文档

petalinux-2018.3

online_compile

Dockerfile
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# syntax=docker/dockerfile:1.4
# =====================================================================
# PetaLinux 2018.3 — multi-stage build
#
# Stage 1 ("builder") performs the dirty work: run the Xilinx installer
# and extract the offline sstate cache. Its image is discarded.
#
# Stage 2 ("final")   is the shipped image. It starts from a fresh
# ubuntu:16.04, re-installs apt deps, and pulls only the cleaned
# artifacts from builder via `COPY --chown=vivado:vivado --from=builder`.
#
# Benefits vs the previous single-stage build:
#   * The 7.3 GB installer .run and the 32 GB sstate.tar.gz are NEVER
#     present in the shipped image (they are removed in builder and
#     builder's layers are discarded).
#   * `--chown=vivado:vivado` fixes the runtime permission issue:
#     vivado owns sstate at image build time, so petalinux-build can
#     write to downloads/ without root.
# =====================================================================


# =====================================================================
# Stage 1 — builder
# =====================================================================
FROM ubuntu:16.04 AS builder

# --- Optional Ubuntu mirror override (handy behind a firewall) -------
ARG UBUNTU_MIRROR
RUN if [ -n "${UBUNTU_MIRROR}" ]; then \
      sed -i "s|archive.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list && \
      sed -i "s|security.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list; \
    fi

# --- apt dependencies (UG1144 host requirements) ----------------------
RUN dpkg --add-architecture i386 && apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt-get install -y -q \
      autoconf automake bc bison build-essential chrpath cpio curl \
      diffstat emacs expect findutils flex g++ gawk gcc gcc-multilib \
      git gnupg gzip iproute2 iputils-ping less lib32ncurses5 \
      lib32stdc++6 lib32z1-dev libfontconfig1:i386 libglib2.0-dev \
      libgtk2.0-0 libncurses5-dev libsdl1.2-dev libselinux1 \
      libsm6:i386 libssl-dev libtool libtool-bin libx11-6:i386 \
      libxrender1:i386 locales make net-tools pax rsync screen socat \
      software-properties-common sudo tar texinfo tftpd-hpa \
      tofrodos tree unzip vim wget xterm xvfb zlib1g-dev zlib1g:i386 \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# --- Locale (the installer is en_US.UTF-8 sensitive) -----------------
RUN locale-gen en_US.UTF-8 && update-locale LANG=en_US.UTF-8

# --- /bin/sh must be bash, not dash (UG1144) -------------------------
RUN echo "dash dash/sh boolean false" | debconf-set-selections && \
  DEBIAN_FRONTEND=noninteractive dpkg-reconfigure -f noninteractive dash

# --- Non-root user required by the PetaLinux installer ---------------
RUN adduser --disabled-password --gecos '' vivado && \
    usermod -aG sudo vivado && \
    echo "vivado ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

# --- Build-time arguments --------------------------------------------
# Defaults match the filenames currently present in the build context.
# Override per build, e.g.:
#   docker build --build-arg PETA_RUN_FILE=petalinux-v2018.3-final-installer.run ...
ARG PETA_RUN_FILE=petalinux-v2018.3-final-installer.run

# --- Pull build inputs into the image --------------------------------
COPY accept-eula.sh /${PETA_RUN_FILE} /

# --- Run the installer (must be non-root) and stage the artifacts ----
# All five actions live in ONE RUN layer. Even though they appear
# sequentially here, the resulting layer contains only the FINAL state
# (tarball removed, installer removed, scripts relocated to /opt/Xilinx).
RUN chmod a+rx /${PETA_RUN_FILE} /accept-eula.sh && \
    mkdir -p /opt/Xilinx && \
    chmod 777 /tmp /opt/Xilinx && \
    cd /tmp && \
    sudo -u vivado -i /accept-eula.sh /${PETA_RUN_FILE} /opt/Xilinx/petalinux && \
    rm -f /${PETA_RUN_FILE} /accept-eula.sh


# =====================================================================
# Stage 2 — final (the image that actually ships)
# =====================================================================
FROM ubuntu:16.04

# --- Optional Ubuntu mirror override (same as builder) --------------
ARG UBUNTU_MIRROR
RUN if [ -n "${UBUNTU_MIRROR}" ]; then \
      sed -i "s|archive.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list && \
      sed -i "s|security.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list; \
    fi

# --- apt dependencies (same set as builder; runtime needs them) -------
RUN dpkg --add-architecture i386 && apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt-get install -y -q \
      autoconf automake bc bison build-essential chrpath cpio curl \
      diffstat emacs expect findutils flex g++ gawk gcc gcc-multilib \
      git gnupg gzip iproute2 iputils-ping less lib32ncurses5 \
      lib32stdc++6 lib32z1-dev libfontconfig1:i386 libglib2.0-dev \
      libgtk2.0-0 libncurses5-dev libsdl1.2-dev libselinux1 \
      libsm6:i386 libssl-dev libtool libtool-bin libx11-6:i386 \
      libxrender1:i386 locales make net-tools pax rsync screen socat \
      software-properties-common sudo tar texinfo tftpd-hpa \
      tofrodos tree unzip vim wget xterm xvfb zlib1g-dev zlib1g:i386 \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# --- Locale ----------------------------------------------------------
RUN locale-gen en_US.UTF-8 && update-locale LANG=en_US.UTF-8

# --- /bin/sh must be bash, not dash (UG1144) -------------------------
# Combined into a single RUN to save one image layer.
RUN echo "dash dash/sh boolean false" | debconf-set-selections && \
    DEBIAN_FRONTEND=noninteractive dpkg-reconfigure -f noninteractive dash

# --- Non-root user (must match the UID used at COPY --chown) ---------
RUN adduser --disabled-password --gecos '' vivado && \
    usermod -aG sudo vivado && \
    echo "vivado ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

# --- Bring in the cleaned artifacts from builder ---------------------
# --chown=vivado:vivado makes the sstate cache writable by vivado,
# so `petalinux-build` can populate downloads/ without root access.
COPY --chown=vivado:vivado --from=builder /opt/Xilinx/petalinux          /opt/Xilinx/petalinux

# --- Switch to non-root for everything below -------------------------
USER vivado
ENV HOME=/home/vivado
ENV LANG=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8
WORKDIR /home/vivado/project

# --- Source PetaLinux settings on every shell -------------------------
# .bashrc   — interactive non-login shells (docker exec bash)
# .profile  — login shells (docker exec bash -l, automated scripts)
RUN { echo; \
      echo '# PetaLinux environment'; \
      echo 'source /opt/Xilinx/petalinux/settings.sh'; \
    } >> /home/vivado/.bashrc && \
    { echo; \
      echo '# PetaLinux environment'; \
      echo 'source /opt/Xilinx/petalinux/settings.sh'; \
    } >> /home/vivado/.profile
.dockerignore
1
2
*.bsp
md5sum*
accept-eula.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/usr/bin/expect
set timeout -1
set install_dir [lindex $argv 1]
set installer [lindex $argv 0]

# PetaLinux 2018.3 installer accepts only positional INSTALL_DIR (and
# --log/--help). Earlier versions of accept-eula.sh invoked the installer
# with `-d $install_dir`, which causes the 2018.3 installer to print
# "getopt: invalid option -- 'd'" and exit immediately. Use the positional
# form so the same script works across 2018.3 and 2020.x installers.
spawn $installer $install_dir
set timeout 2
expect {
    "ERROR: Invalid options:" {spawn $installer -d $install_dir }
    timeout { }
}

set timeout 600
expect "Press Enter to display the license agreements"
send "\r"
set timeout 2

expect {
    "* >*" {send "y\r"}
    timeout { send "q"; sleep 1; exp_continue}
}
expect {
    "* >*" {send "y\r"}
    timeout { send "q"; sleep 1; exp_continue}
}
expect {
    "*Installing PetaLinux...*" {}
    "* >*" {send "y\r"}
    timeout { send "q"; sleep 1; exp_continue}
}

set timeout -1
expect "INFO: Checking PetaLinux installer integrity..."
expect "INFO: PetaLinux SDK has been installed"
#interact
基于bsp验证环境
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
bsp_name="xilinx-zc706-v2018.3-final.bsp"
zynq_arch="zynq"
prj_index=1
prj_name="prj_"

# 仅当依赖目录非普通用户权限时执行,普通用户为vivado,超级用户为root
sudo chown -R vivado:vivado ../$(basename $PWD)

# 如果不指定工程名称,会以bsp文件命名工程,根据喜好二选一,前边定义的变量也是为了方便创建工程
# # 1. 基于BSP创建工程,工程名称为BSP名称
# petalinux-create -t project -s $bsp_name
# 2. 基于BSP创建工程,根据指定名称创建工程
petalinux-create -t project -s $bsp_name -n $prj_name$prj_index

# # 不基于BSP创建工程,zynqmp或zynq根据fpga型号确定
# # petalinux-create 命令用于创建新的PetaLinux 工程:
# # 注意--template对应的zynqMP后边两个字母是大写
# petalinux-create -t project --template ${zynq_arch} -n $prj_name$prj_index

cd $prj_name$prj_index

petalinux-config --get-hw-description hardware/xilinx-zc706-2018.3/xilinx-zc706-2018.3.sdk
# 进入配置界面后验证以下配置即可,然后保存配置并退出。如果有其他功能需要的自行配置
<<'CONTENT'
→ Yocto Settings
   Add pre-mirror url   --->
   Local sstate feeds settings  --->
   [*] Enable BB NO NETWORK
CONTENT

# 增加time命令是为了查看最终编译花了多长时间
time petalinux-build

# 生成启动镜像
petalinux-package --boot --fsbl --fpga --u-boot --force

# 如果要封装预构建镜像
petalinux-package --prebuilt --fpga <FPGA bitstream>
# 例如:
petalinux-package --prebuilt --fpga images/system.bit

offline_compile

Dockerfile
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# syntax=docker/dockerfile:1.4
# =====================================================================
# PetaLinux 2018.3 — multi-stage build
#
# Stage 1 ("builder") performs the dirty work: run the Xilinx installer
# and extract the offline sstate cache. Its image is discarded.
#
# Stage 2 ("final")   is the shipped image. It starts from a fresh
# ubuntu:16.04, re-installs apt deps, and pulls only the cleaned
# artifacts from builder via `COPY --chown=vivado:vivado --from=builder`.
#
# Benefits vs the previous single-stage build:
#   * The 7.3 GB installer .run and the 32 GB sstate.tar.gz are NEVER
#     present in the shipped image (they are removed in builder and
#     builder's layers are discarded).
#   * `--chown=vivado:vivado` fixes the runtime permission issue:
#     vivado owns sstate at image build time, so petalinux-build can
#     write to downloads/ without root.
# =====================================================================


# =====================================================================
# Stage 1 — builder
# =====================================================================
FROM ubuntu:16.04 AS builder

# --- Optional Ubuntu mirror override (handy behind a firewall) -------
ARG UBUNTU_MIRROR
RUN if [ -n "${UBUNTU_MIRROR}" ]; then \
      sed -i "s|archive.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list && \
      sed -i "s|security.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list; \
    fi

# --- apt dependencies (UG1144 host requirements) ----------------------
RUN dpkg --add-architecture i386 && apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt-get install -y -q \
      autoconf automake bc bison build-essential chrpath cpio curl \
      diffstat emacs expect findutils flex g++ gawk gcc gcc-multilib \
      git gnupg gzip iproute2 iputils-ping less lib32ncurses5 \
      lib32stdc++6 lib32z1-dev libfontconfig1:i386 libglib2.0-dev \
      libgtk2.0-0 libncurses5-dev libsdl1.2-dev libselinux1 \
      libsm6:i386 libssl-dev libtool libtool-bin libx11-6:i386 \
      libxrender1:i386 locales make net-tools pax rsync screen socat \
      software-properties-common sudo tar texinfo tftpd-hpa \
      tofrodos tree unzip vim wget xterm xvfb zlib1g-dev zlib1g:i386 \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# --- Locale (the installer is en_US.UTF-8 sensitive) -----------------
RUN locale-gen en_US.UTF-8 && update-locale LANG=en_US.UTF-8

# --- /bin/sh must be bash, not dash (UG1144) -------------------------
RUN echo "dash dash/sh boolean false" | debconf-set-selections && \
  DEBIAN_FRONTEND=noninteractive dpkg-reconfigure -f noninteractive dash

# --- Non-root user required by the PetaLinux installer ---------------
RUN adduser --disabled-password --gecos '' vivado && \
    usermod -aG sudo vivado && \
    echo "vivado ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

# --- Build-time arguments --------------------------------------------
# Defaults match the filenames currently present in the build context.
# Override per build, e.g.:
#   docker build --build-arg PETA_RUN_FILE=petalinux-v2018.3-final-installer.run ...
ARG PETA_RUN_FILE=petalinux-v2018.3-final-installer.run
ARG PETA_CACHE_FILE=sstate-rel-v2018.3.tar.gz
ARG PETA_ZYNQ_AUTO_FILE=zynq_auto.sh
ARG PETA_ZYNQMP_AUTO_FILE=zynqmp_auto.sh

# --- Pull build inputs into the image --------------------------------
COPY accept-eula.sh \
     /${PETA_RUN_FILE} \
     /${PETA_CACHE_FILE} \
     /${PETA_ZYNQ_AUTO_FILE} \
     /${PETA_ZYNQMP_AUTO_FILE} \
     /

# --- Run the installer (must be non-root) and stage the artifacts ----
# All five actions live in ONE RUN layer. Even though they appear
# sequentially here, the resulting layer contains only the FINAL state
# (tarball removed, installer removed, scripts relocated to /opt/Xilinx).
RUN chmod a+rx /${PETA_RUN_FILE} /accept-eula.sh && \
    mkdir -p /opt/Xilinx && \
    chmod 777 /tmp /opt/Xilinx && \
    cd /tmp && \
    sudo -u vivado -i /accept-eula.sh /${PETA_RUN_FILE} /opt/Xilinx/petalinux && \
    rm -f /${PETA_RUN_FILE} /accept-eula.sh && \
    tar zxf /${PETA_CACHE_FILE} -C /opt/Xilinx/ && \
    rm -f /${PETA_CACHE_FILE} && \
    chmod +x /${PETA_ZYNQ_AUTO_FILE}     && mv /${PETA_ZYNQ_AUTO_FILE}     /opt/Xilinx/ && \
    chmod +x /${PETA_ZYNQMP_AUTO_FILE}   && mv /${PETA_ZYNQMP_AUTO_FILE}   /opt/Xilinx/


# =====================================================================
# Stage 2 — final (the image that actually ships)
# =====================================================================
FROM ubuntu:16.04

# --- Optional Ubuntu mirror override (same as builder) --------------
ARG UBUNTU_MIRROR
RUN if [ -n "${UBUNTU_MIRROR}" ]; then \
      sed -i "s|archive.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list && \
      sed -i "s|security.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list; \
    fi

# --- apt dependencies (same set as builder; runtime needs them) -------
RUN dpkg --add-architecture i386 && apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt-get install -y -q \
      autoconf automake bc bison build-essential chrpath cpio curl \
      diffstat emacs expect findutils flex g++ gawk gcc gcc-multilib \
      git gnupg gzip iproute2 iputils-ping less lib32ncurses5 \
      lib32stdc++6 lib32z1-dev libfontconfig1:i386 libglib2.0-dev \
      libgtk2.0-0 libncurses5-dev libsdl1.2-dev libselinux1 \
      libsm6:i386 libssl-dev libtool libtool-bin libx11-6:i386 \
      libxrender1:i386 locales make net-tools pax rsync screen socat \
      software-properties-common sudo tar texinfo tftpd-hpa \
      tofrodos tree unzip vim wget xterm xvfb zlib1g-dev zlib1g:i386 \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# --- Locale ----------------------------------------------------------
RUN locale-gen en_US.UTF-8 && update-locale LANG=en_US.UTF-8

# --- /bin/sh must be bash, not dash (UG1144) -------------------------
# Combined into a single RUN to save one image layer.
RUN echo "dash dash/sh boolean false" | debconf-set-selections && \
    DEBIAN_FRONTEND=noninteractive dpkg-reconfigure -f noninteractive dash

# --- Non-root user (must match the UID used at COPY --chown) ---------
RUN adduser --disabled-password --gecos '' vivado && \
    usermod -aG sudo vivado && \
    echo "vivado ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

# --- Bring in the cleaned artifacts from builder ---------------------
# --chown=vivado:vivado makes the sstate cache writable by vivado,
# so `petalinux-build` can populate downloads/ without root access.
COPY --chown=vivado:vivado --from=builder /opt/Xilinx/petalinux          /opt/Xilinx/petalinux
COPY --chown=vivado:vivado --from=builder /opt/Xilinx/sstate-rel-v2018.3 /opt/Xilinx/sstate-rel-v2018.3
COPY --chown=vivado:vivado --from=builder /opt/Xilinx/zynq_auto.sh       /opt/Xilinx/zynq_auto.sh
COPY --chown=vivado:vivado --from=builder /opt/Xilinx/zynqmp_auto.sh     /opt/Xilinx/zynqmp_auto.sh

# --- Switch to non-root for everything below -------------------------
USER vivado
ENV HOME=/home/vivado
ENV LANG=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8
WORKDIR /home/vivado/project

# --- Source PetaLinux settings on every shell -------------------------
# .bashrc   — interactive non-login shells (docker exec bash)
# .profile  — login shells (docker exec bash -l, automated scripts)
RUN { echo; \
      echo '# PetaLinux environment'; \
      echo 'source /opt/Xilinx/petalinux/settings.sh'; \
    } >> /home/vivado/.bashrc && \
    { echo; \
      echo '# PetaLinux environment'; \
      echo 'source /opt/Xilinx/petalinux/settings.sh'; \
    } >> /home/vivado/.profile
.dockerignore
1
2
*.bsp
md5sum*
accept-eula.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/usr/bin/expect
set timeout -1
set install_dir [lindex $argv 1]
set installer [lindex $argv 0]

# PetaLinux 2018.3 installer accepts only positional INSTALL_DIR (and
# --log/--help). Earlier versions of accept-eula.sh invoked the installer
# with `-d $install_dir`, which causes the 2018.3 installer to print
# "getopt: invalid option -- 'd'" and exit immediately. Use the positional
# form so the same script works across 2018.3 and 2020.x installers.
spawn $installer $install_dir
set timeout 2
expect {
    "ERROR: Invalid options:" {spawn $installer -d $install_dir }
    timeout { }
}

set timeout 600
expect "Press Enter to display the license agreements"
send "\r"
set timeout 2

expect {
    "* >*" {send "y\r"}
    timeout { send "q"; sleep 1; exp_continue}
}
expect {
    "* >*" {send "y\r"}
    timeout { send "q"; sleep 1; exp_continue}
}
expect {
    "*Installing PetaLinux...*" {}
    "* >*" {send "y\r"}
    timeout { send "q"; sleep 1; exp_continue}
}

set timeout -1
expect "INFO: Checking PetaLinux installer integrity..."
expect "INFO: PetaLinux SDK has been installed"
#interact
zynq_auto.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/bin/bash
## 本地仓库设置
SSTATE_LOCAL_PATH="/opt/Xilinx/sstate-rel-v2018.3"

#删除带有指定关键字的行
delete_line_with_special_word ()
{
  if [[ $# -lt 2 ]]; then
	return
  fi
  FILE=$1
  WORD=$2

  sed -i "/${WORD}/d" ${FILE}
}
#文件内容追加
append_line_into_file ()
{
  if [[ $# -lt 2 ]]; then
	return
  fi
  FILE=$1
  LINE=$2
  echo do
  echo $LINE >> $FILE
}
CONFIG="./project-spec/configs/config"
cp $CONFIG $CONFIG.old

## 本地包
delete_line_with_special_word   $CONFIG  CONFIG_YOCTO_NETWORK_SSTATE_FEEDS
append_line_into_file           $CONFIG  "# CONFIG_YOCTO_NETWORK_SSTATE_FEEDS is not set"
delete_line_with_special_word   $CONFIG  CONFIG_YOCTO_BB_NO_NETWORK
append_line_into_file           $CONFIG  "CONFIG_YOCTO_BB_NO_NETWORK=y"
delete_line_with_special_word   $CONFIG  CONFIG_PRE_MIRROR_URL
append_line_into_file           $CONFIG  "CONFIG_PRE_MIRROR_URL=\"file://${SSTATE_LOCAL_PATH}/downloads\""
delete_line_with_special_word   $CONFIG  CONFIG_YOCTO_LOCAL_SSTATE_FEEDS_URL
append_line_into_file           $CONFIG  "CONFIG_YOCTO_LOCAL_SSTATE_FEEDS_URL=\"${SSTATE_LOCAL_PATH}/arm\"" #zynq

## | 目录      | 平台        |
## | --------- | ----------- |
## | aarch64   | ZynqMP      |
## | arm       | Zynq        |
## | mb-full   | MB AXI      |
## | mb-lite   | MB AXI lite |
## | downloads | 全平台  |

## 免输入密码登陆
delete_line_with_special_word   $CONFIG  CONFIG_YOCTO_ENABLE_DEBUG_TWEAKS
append_line_into_file           $CONFIG  "CONFIG_YOCTO_ENABLE_DEBUG_TWEAKS=y"
zynqmp_auto.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/bin/bash
## 本地仓库设置
SSTATE_LOCAL_PATH="/opt/Xilinx/sstate-rel-v2018.3"

#删除带有指定关键字的行
delete_line_with_special_word ()
{
  if [[ $# -lt 2 ]]; then
	return
  fi
  FILE=$1
  WORD=$2

  sed -i "/${WORD}/d" ${FILE}
}
#文件内容追加
append_line_into_file ()
{
  if [[ $# -lt 2 ]]; then
	return
  fi
  FILE=$1
  LINE=$2
  echo do
  echo $LINE >> $FILE
}
CONFIG="./project-spec/configs/config"
cp $CONFIG $CONFIG.old

## 本地包
delete_line_with_special_word   $CONFIG  CONFIG_YOCTO_NETWORK_SSTATE_FEEDS
append_line_into_file           $CONFIG  "# CONFIG_YOCTO_NETWORK_SSTATE_FEEDS is not set"
delete_line_with_special_word   $CONFIG  CONFIG_YOCTO_BB_NO_NETWORK
append_line_into_file           $CONFIG  "CONFIG_YOCTO_BB_NO_NETWORK=y"
delete_line_with_special_word   $CONFIG  CONFIG_PRE_MIRROR_URL
append_line_into_file           $CONFIG  "CONFIG_PRE_MIRROR_URL=\"file://${SSTATE_LOCAL_PATH}/downloads\""
delete_line_with_special_word   $CONFIG  CONFIG_YOCTO_LOCAL_SSTATE_FEEDS_URL
append_line_into_file           $CONFIG  "CONFIG_YOCTO_LOCAL_SSTATE_FEEDS_URL=\"${SSTATE_LOCAL_PATH}/aarch64\"" #zynqMP

## | 目录      | 平台        |
## | --------- | ----------- |
## | aarch64   | ZynqMP      |
## | arm       | Zynq        |
## | mb-full   | MB AXI      |
## | mb-lite   | MB AXI lite |
## | downloads | 全平台  |

## 免输入密码登陆
delete_line_with_special_word   $CONFIG  CONFIG_YOCTO_ENABLE_DEBUG_TWEAKS
append_line_into_file           $CONFIG  "CONFIG_YOCTO_ENABLE_DEBUG_TWEAKS=y"
基于bsp验证环境
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
bsp_name="xilinx-zc706-v2018.3-final.bsp"
zynq_arch="zynq"
prj_index=1
prj_name="prj_"

# 仅当依赖目录非普通用户权限时执行,普通用户为vivado,超级用户为root
sudo chown -R vivado:vivado ../$(basename $PWD)

# 如果不指定工程名称,会以bsp文件命名工程,根据喜好二选一,前边定义的变量也是为了方便创建工程
# # 1. 基于BSP创建工程,工程名称为BSP名称
# petalinux-create -t project -s $bsp_name
# 2. 基于BSP创建工程,根据指定名称创建工程
petalinux-create -t project -s $bsp_name -n $prj_name$prj_index

# # 不基于BSP创建工程,zynqmp或zynq根据fpga型号确定
# # petalinux-create 命令用于创建新的PetaLinux 工程:
# # 注意--template对应的zynqMP后边两个字母是大写
# petalinux-create -t project --template ${zynq_arch} -n $prj_name$prj_index

cd $prj_name$prj_index

# 确认离线编译目录下有arm、aarch64、downloads
ls /opt/Xilinx/sstate-rel-v2018.3
# 运行离线编译脚本
/opt/Xilinx/zynq_auto.sh

petalinux-config --get-hw-description hardware/xilinx-zc706-2018.3/xilinx-zc706-2018.3.sdk
# 进入配置界面后验证以下配置即可,然后保存配置并退出。如果有其他功能需要的自行配置
<<'CONTENT'
→ Yocto Settings
   Add pre-mirror url   --->
   Local sstate feeds settings  --->
   [*] Enable BB NO NETWORK
CONTENT

# 增加time命令是为了查看最终编译花了多长时间
time petalinux-build

# 生成启动镜像
petalinux-package --boot --fsbl --fpga --u-boot --force

# 如果要封装预构建镜像
petalinux-package --prebuilt --fpga <FPGA bitstream>
# 例如:
petalinux-package --prebuilt --fpga images/system.bit

构建容器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 构建容器
time DOCKER_BUILDKIT=1 docker build \
     --network=host \
     --progress=plain \
     --build-arg UBUNTU_MIRROR=mirrors.tuna.tsinghua.edu.cn \
     -t petalinux:2018.3 .

# 清理构建缓存
docker system prune -f

# 完成构建后运行容器
# 可以在本地创建并进入工作目录后与容器工作目录完成挂载
mkdir -p /data/disk/Projects/petalinux_2018.3
cd /data/disk/Projects/petalinux_2018.3
docker run -ti --rm -e DISPLAY=$DISPLAY --net="host" -v /tmp/.X11-unix:/tmp/.X11-unix -v $HOME/.Xauthority:/home/vivado/.Xauthority -v ./:/home/vivado/project  petalinux:2018.3 /bin/bash

容器导出与导入

1
2
3
4
# 导出容器
time docker save -o petalinux_2018.3.tar petalinux:2018.3
# 导入容器
time docker load -i petalinux_2018.3.tar

petalinux2018.3_FMQLMP-Linux-SDK-Prj-20250408

Dockerfile

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# syntax=docker/dockerfile:1.4
# =====================================================================
# FMQLMP-Linux-SDK-Prj-20250408 + PetaLinux 2018.3 — multi-stage build
#
# Stage 1 ("builder") performs the dirty work: run the Xilinx installer
# and extract the FMQLMP-Linux-SDK tarball, then patches env_fmqlmp.sh
# and removes both large archives. Its image is discarded.
#
# Stage 2 ("final")   is the shipped image. It starts from a fresh
# ubuntu:16.04, re-installs apt deps, and pulls only the cleaned
# artifacts from builder via `COPY --chown=vivado:vivado --from=builder`.
#
# Benefits vs the previous single-stage build:
#   * The 7.3 GB installer .run and the FMQLMP SDK tarball are NEVER
#     present in the shipped image (they are removed in builder and
#     builder's layers are discarded).
#   * `--chown=vivado:vivado` fixes the runtime permission issue:
#     vivado owns petalinux + SDK at image build time, so subsequent
#     builds can populate downloads/ without root.
# =====================================================================


# =====================================================================
# Stage 1 — builder
# =====================================================================
FROM ubuntu:16.04 AS builder

# --- Optional Ubuntu mirror override (handy behind a firewall) -------
ARG UBUNTU_MIRROR
RUN if [ -n "${UBUNTU_MIRROR}" ]; then \
      sed -i "s|archive.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list && \
      sed -i "s|security.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list; \
    fi

# --- apt dependencies (UG1144 host requirements + this project) ------
# Merged into one RUN: includes device-tree-compiler and zlib1g:i386
# (the original Dockerfile split these into separate layers).
RUN dpkg --add-architecture i386 && apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt-get install -y -q \
      autoconf automake bc bison build-essential chrpath cpio curl \
      device-tree-compiler diffstat emacs expect findutils flex \
      g++ gawk gcc gcc-multilib git gnupg gzip iproute2 \
      iputils-ping less lib32ncurses5 lib32stdc++6 lib32z1-dev \
      libfontconfig1:i386 libglib2.0-dev libgtk2.0-0 \
      libncurses5-dev libsdl1.2-dev libselinux1 libsm6:i386 \
      libssl-dev libtool libtool-bin libx11-6:i386 libxrender1:i386 \
      locales make net-tools pax rsync screen socat \
      software-properties-common sudo tar texinfo tftpd-hpa \
      tofrodos tree unzip vim wget xterm xvfb zlib1g-dev \
      zlib1g:i386 \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# --- Locale (the installer is en_US.UTF-8 sensitive) -----------------
RUN locale-gen en_US.UTF-8 && update-locale LANG=en_US.UTF-8

# --- /bin/sh must be bash, not dash (UG1144) -------------------------
# Combined into a single RUN to save one image layer.
RUN echo "dash dash/sh boolean false" | debconf-set-selections && \
    DEBIAN_FRONTEND=noninteractive dpkg-reconfigure -f noninteractive dash

# --- Non-root user required by the PetaLinux installer ---------------
# --uid 1000 guarantees the same UID in builder and final so that
# `COPY --chown=vivado:vivado --from=builder` does not change ownership.
RUN adduser --disabled-password --gecos '' --uid 1000 vivado && \
    usermod -aG sudo vivado && \
    echo "vivado ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

# --- Build-time arguments --------------------------------------------
# Override per build, e.g.:
#   docker build --build-arg PETA_RUN_FILE=petalinux-v2018.3-final-installer.run \
#                 --build-arg FMQLMP_SDK_TAR=FMQLMP-Linux-SDK-Prj-20250408.tar.bz2 ...
ARG PETA_RUN_FILE=petalinux-v2018.3-final-installer.run
ARG FMQLMP_SDK_TAR=FMQLMP-Linux-SDK-Prj-20250408.tar.bz2
ARG FMQLMP_SDK_DIR=/opt/pkg/FMQLMP-Linux-SDK-Prj-20250408
ARG PETALINUX_PATH=/opt/Xilinx/petalinux

# --- Pull build inputs into the image --------------------------------
COPY accept-eula.sh \
     /${PETA_RUN_FILE} \
     /${FMQLMP_SDK_TAR} \
     /

# --- Run the installer AND extract the SDK in ONE RUN layer ---------
# The final state of this layer: installer gone, tarball gone, SDK
# extracted and patched, ownership transferred to vivado. Because
# builder's layers are discarded by the final stage, none of the
# large intermediate files end up in the shipped image.
RUN chmod a+rx /${PETA_RUN_FILE} /accept-eula.sh && \
    mkdir -p "$(dirname ${PETALINUX_PATH})" "$(dirname ${FMQLMP_SDK_DIR})" && \
    chmod 777 /tmp "$(dirname ${PETALINUX_PATH})" && \
    cd /tmp && \
    sudo -u vivado -i /accept-eula.sh /${PETA_RUN_FILE} ${PETALINUX_PATH} && \
    rm -f /${PETA_RUN_FILE} /accept-eula.sh && \
    tar xjf /${FMQLMP_SDK_TAR} -C "$(dirname ${FMQLMP_SDK_DIR})" && \
    git -C "${FMQLMP_SDK_DIR}" checkout -- . && \
    sed -i 's|\(^[[:space:]]*export PETALINUX=\).*|\1'"${PETALINUX_PATH}"'|g' \
        "${FMQLMP_SDK_DIR}/env_fmqlmp.sh" && \
    chown -R vivado:vivado "${PETALINUX_PATH}" "${FMQLMP_SDK_DIR}" && \
    rm -f /${FMQLMP_SDK_TAR}


# =====================================================================
# Stage 2 — final (the image that actually ships)
# =====================================================================
FROM ubuntu:16.04

# --- Optional Ubuntu mirror override (same as builder) --------------
ARG UBUNTU_MIRROR
RUN if [ -n "${UBUNTU_MIRROR}" ]; then \
      sed -i "s|archive.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list && \
      sed -i "s|security.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list; \
    fi

# --- apt dependencies (same set as builder; runtime needs them) -------
RUN dpkg --add-architecture i386 && apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt-get install -y -q \
      autoconf automake bc bison build-essential chrpath cpio curl \
      device-tree-compiler diffstat emacs expect findutils flex \
      g++ gawk gcc gcc-multilib git gnupg gzip iproute2 \
      iputils-ping less lib32ncurses5 lib32stdc++6 lib32z1-dev \
      libfontconfig1:i386 libglib2.0-dev libgtk2.0-0 \
      libncurses5-dev libsdl1.2-dev libselinux1 libsm6:i386 \
      libssl-dev libtool libtool-bin libx11-6:i386 libxrender1:i386 \
      locales make net-tools pax rsync screen socat \
      software-properties-common sudo tar texinfo tftpd-hpa \
      tofrodos tree unzip vim wget xterm xvfb zlib1g-dev \
      zlib1g:i386 \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# --- Locale ----------------------------------------------------------
RUN locale-gen en_US.UTF-8 && update-locale LANG=en_US.UTF-8

# --- /bin/sh must be bash, not dash (UG1144) -------------------------
RUN echo "dash dash/sh boolean false" | debconf-set-selections && \
    DEBIAN_FRONTEND=noninteractive dpkg-reconfigure -f noninteractive dash

# --- Non-root user (UID must match builder for --chown to align) -----
RUN adduser --disabled-password --gecos '' --uid 1000 vivado && \
    usermod -aG sudo vivado && \
    echo "vivado ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

# --- Bring in the cleaned artifacts from builder ---------------------
# --chown=vivado:vivado makes petalinux + SDK writable by vivado,
# so subsequent `petalinux-build` can populate downloads/ without root.
ARG PETALINUX_PATH=/opt/Xilinx/petalinux
ARG FMQLMP_SDK_DIR=/opt/pkg/FMQLMP-Linux-SDK-Prj-20250408

COPY --chown=vivado:vivado --from=builder ${PETALINUX_PATH} ${PETALINUX_PATH}
COPY --chown=vivado:vivado --from=builder ${FMQLMP_SDK_DIR} ${FMQLMP_SDK_DIR}

# --- Switch to non-root for everything below -------------------------
USER vivado
ENV HOME=/home/vivado
ENV LANG=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8
WORKDIR /home/vivado/project

# --- Source FMQLMP SDK env on every shell ----------------------------
# .bashrc   — interactive non-login shells (docker exec bash)
# .profile  — login shells (docker exec bash -l, automated scripts)
RUN { echo; \
      echo '# FMQLMP-Linux-SDK environment'; \
      echo "source ${FMQLMP_SDK_DIR}/env_fmqlmp.sh"; \
    } >> /home/vivado/.bashrc && \
    { echo; \
      echo '# FMQLMP-Linux-SDK environment'; \
      echo "source ${FMQLMP_SDK_DIR}/env_fmqlmp.sh"; \
    } >> /home/vivado/.profile

构建容器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 构建容器
time DOCKER_BUILDKIT=1 docker build \
     --network=host \
     --build-arg UBUNTU_MIRROR=mirrors.tuna.tsinghua.edu.cn \
     -t petalinux2018.3-fmqlmp-linux-sdk-prj-20250408 .

# 运行容器
mkdir -p /data/disk/Projects
cd /data/disk/Projects
docker run -ti \
       --rm -e DISPLAY=$DISPLAY \
       --net="host" \
       -v /tmp/.X11-unix:/tmp/.X11-unix \
       -v $HOME/.Xauthority:/home/vivado/.Xauthority \
       -v ./:/home/vivado/project \
       petalinux2018.3-fmqlmp-linux-sdk-prj-20250408 /bin/bash

accept-eula.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/usr/bin/expect
set timeout -1
set install_dir [lindex $argv 1]
set installer [lindex $argv 0]

# PetaLinux 2018.3 installer accepts only positional INSTALL_DIR (and
# --log/--help). Earlier versions of accept-eula.sh invoked the installer
# with `-d $install_dir`, which causes the 2018.3 installer to print
# "getopt: invalid option -- 'd'" and exit immediately. Use the positional
# form so the same script works across 2018.3 and 2020.x installers.
spawn $installer $install_dir
set timeout 2
expect {
    "ERROR: Invalid options:" {spawn $installer -d $install_dir }
    timeout { }
}

set timeout 600
expect "Press Enter to display the license agreements"
send "\r"
set timeout 2

expect {
    "* >*" {send "y\r"}
    timeout { send "q"; sleep 1; exp_continue}
}
expect {
    "* >*" {send "y\r"}
    timeout { send "q"; sleep 1; exp_continue}
}
expect {
    "*Installing PetaLinux...*" {}
    "* >*" {send "y\r"}
    timeout { send "q"; sleep 1; exp_continue}
}

set timeout -1
expect "INFO: Checking PetaLinux installer integrity..."
expect "INFO: PetaLinux SDK has been installed"
#interact

容器导出与导入

1
2
3
4
5
# 导出容器
time docker save -o petalinux2018.3-fmqlmp-linux-sdk-prj-20250408.tar \
     petalinux2018.3-fmqlmp-linux-sdk-prj-20250408:latest
# 导入容器
time docker load -i petalinux2018.3-fmqlmp-linux-sdk-prj-20250408.tar

petalinux-2022.1

online_compile

Dockerfile
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# syntax=docker/dockerfile:1.4
# =====================================================================
# PetaLinux 2022.1 — multi-stage build
#
# Stage 1 ("builder") runs the Xilinx installer and extracts the offline
# sstate cache. Its image is discarded.
#
# Stage 2 ("final")   is the shipped image. Starts from a fresh
# ubuntu:18.04, re-installs apt deps, then pulls only cleaned artifacts
# from builder via `COPY --chown=vivado:vivado --from=builder`.
#
# Benefits vs the previous single-stage build:
#   * The installer .run and the three sstate.tar.gz are NEVER present
#     in the shipped image (rm'd in builder; builder layers discarded).
#   * --chown=vivado:vivado fixes the runtime permission issue: vivado
#     owns sstate at image build time, so petalinux-build can write to
#     downloads/ without root.
# =====================================================================


# =====================================================================
# Stage 1 — builder
# =====================================================================
FROM ubuntu:18.04 AS builder

# --- Optional Ubuntu mirror override (handy behind a firewall) -------
ARG UBUNTU_MIRROR
RUN if [ -n "${UBUNTU_MIRROR}" ]; then \
  sed -i "s|archive.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list && \
    sed -i "s|security.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list; \
  fi

# --- apt dependencies (UG1144 host requirements) ----------------------
# Single RUN: enable i386 + one update + install all (incl. zlib1g:i386).
RUN dpkg --add-architecture i386 && \
  apt-get update && \
  DEBIAN_FRONTEND=noninteractive apt-get install -y -q \
                                 autoconf automake bc bison build-essential chrpath cpio curl \
                                 debianutils diffstat emacs expect flex g++ gawk gcc gcc-multilib \
                                 git gnupg gzip iproute2 iputils-ping kmod less lib32ncurses5 \
                                 lib32stdc++6 lib32z1-dev libegl1-mesa libfontconfig1:i386 \
                                 libglib2.0-dev libgtk2.0-0 libidn11 libncurses5-dev libsdl1.2-dev \
                                 libselinux1 libsm6:i386 libssl-dev libtinfo5 libtool libtool-bin \
                                 libx11-6:i386 libxrender1:i386 locales make net-tools pax pxelinux \
                                 python python3 python3-git python3-jinja2 python3-pexpect \
                                 python3-pip rsync screen socat sudo tar texinfo tftp-hpa \
                                 tftpd-hpa tofrodos tree unzip vim wget xterm xvfb xz-utils \
                                 zlib1g-dev zlib1g:i386 \
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/*

# --- Locale (the installer is en_US.UTF-8 sensitive) -----------------
RUN locale-gen en_US.UTF-8 && update-locale LANG=en_US.UTF-8

# --- /bin/sh must be bash, not dash (UG1144) -------------------------
RUN echo "dash dash/sh boolean false" | debconf-set-selections && \
  DEBIAN_FRONTEND=noninteractive dpkg-reconfigure -f noninteractive dash

# --- Non-root user required by the PetaLinux installer ---------------
RUN adduser --disabled-password --gecos '' vivado && \
  usermod -aG sudo vivado && \
  echo "vivado ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

# --- Build-time arguments --------------------------------------------
ARG PETA_RUN_FILE=petalinux-v2022.1-04191534-installer.run

# --- Pull build inputs into the image --------------------------------
COPY --chmod=a+rx accept-eula.sh /${PETA_RUN_FILE} /

# --- Run the installer and stage artifacts (single RUN) --------------
# Resulting layer contains only the FINAL state (tarballs removed,
# installer removed, scripts relocated, /tmp cache files removed).
RUN mkdir -p /opt/Xilinx && \
  chmod 777 /tmp /opt/Xilinx && \
  sudo -u vivado -i /accept-eula.sh /${PETA_RUN_FILE} /opt/Xilinx/petalinux && \
  rm -f /${PETA_RUN_FILE} /accept-eula.sh

# =====================================================================
# Stage 2 — final (the image that actually ships)
# =====================================================================
FROM ubuntu:18.04

# --- Optional Ubuntu mirror override (same as builder) --------------
ARG UBUNTU_MIRROR
RUN if [ -n "${UBUNTU_MIRROR}" ]; then \
  sed -i "s|archive.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list && \
    sed -i "s|security.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list; \
  fi

# --- apt dependencies (same set as builder; runtime needs them) -------
RUN dpkg --add-architecture i386 && \
  apt-get update && \
  DEBIAN_FRONTEND=noninteractive apt-get install -y -q \
                                 autoconf automake bc bison build-essential chrpath cpio curl \
                                 debianutils diffstat emacs expect flex g++ gawk gcc gcc-multilib \
                                 git gnupg gzip iproute2 iputils-ping kmod less lib32ncurses5 \
                                 lib32stdc++6 lib32z1-dev libegl1-mesa libfontconfig1:i386 \
                                 libglib2.0-dev libgtk2.0-0 libidn11 libncurses5-dev libsdl1.2-dev \
                                 libselinux1 libsm6:i386 libssl-dev libtinfo5 libtool libtool-bin \
                                 libx11-6:i386 libxrender1:i386 locales make net-tools pax pxelinux \
                                 python python3 python3-git python3-jinja2 python3-pexpect \
                                 python3-pip rsync screen socat sudo tar texinfo tftp-hpa \
                                 tftpd-hpa tofrodos tree unzip vim wget xterm xvfb xz-utils \
                                 zlib1g-dev zlib1g:i386 \
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/*

# --- Locale ----------------------------------------------------------
RUN locale-gen en_US.UTF-8 && update-locale LANG=en_US.UTF-8

# --- /bin/sh must be bash, not dash (UG1144) -------------------------
RUN echo "dash dash/sh boolean false" | debconf-set-selections && \
  DEBIAN_FRONTEND=noninteractive dpkg-reconfigure -f noninteractive dash

# --- Non-root user (must match the UID used at COPY --chown) ---------
RUN adduser --disabled-password --gecos '' vivado && \
  usermod -aG sudo vivado && \
  echo "vivado ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

# --- Bring in the cleaned artifacts from builder ---------------------
# --chown=vivado:vivado makes the sstate cache writable by vivado,
# so `petalinux-build` can populate downloads/ without root access.
COPY --chown=vivado:vivado --from=builder /opt/Xilinx/petalinux                       /opt/Xilinx/petalinux

# --- Switch to non-root for everything below -------------------------
USER vivado
ENV HOME=/home/vivado
ENV LANG=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8
WORKDIR /home/vivado/project

# --- Source PetaLinux settings on every shell -------------------------
# .bashrc   — interactive non-login shells (docker exec bash)
# .profile  — login shells (docker exec bash -l, automated scripts)
RUN { echo; \
      echo '# PetaLinux environment'; \
      echo 'source /opt/Xilinx/petalinux/settings.sh'; \
    } >> /home/vivado/.bashrc && \
  { echo; \
    echo '# PetaLinux environment'; \
    echo 'source /opt/Xilinx/petalinux/settings.sh'; \
  } >> /home/vivado/.profile
.dockerignore
1
2
*.bsp
md5sum*
accept-eula.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/usr/bin/expect
set timeout -1
set install_dir [lindex $argv 1]
set installer [lindex $argv 0]

spawn $installer -d $install_dir
set timeout 2
expect {
    "ERROR: Invalid options:" {spawn $installer -d $install_dir }
    timeout { }
}

set timeout 600
expect "Press Enter to display the license agreements"
send "\r"
set timeout 2

expect {
    "* >*" {send "y\r"}
    timeout { send "q"; sleep 1; exp_continue}
}
expect {
    "* >*" {send "y\r"}
    timeout { send "q"; sleep 1; exp_continue}
}
expect {
    "*Installing PetaLinux...*" {}
    "* >*" {send "y\r"}
    timeout { send "q"; sleep 1; exp_continue}
}

set timeout -1
expect "INFO: Checking PetaLinux installer integrity..."
expect "INFO: PetaLinux SDK has been installed"
#interact
基于bsp验证环境
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
bsp_name="xilinx-zc706-v2022.1-04191534.bsp"
zynq_arch="zynq"
prj_index=1
prj_name="prj_"

# 仅当依赖目录非普通用户权限时执行,普通用户为vivado,超级用户为root
sudo chown -R vivado:vivado ../$(basename $PWD)

# 如果不指定工程名称,会以bsp文件命名工程,根据喜好二选一,前边定义的变量也是为了方便创建工程
# # 1. 基于BSP创建工程,工程名称为BSP名称
# petalinux-create -t project -s $bsp_name
# 2. 基于BSP创建工程,根据指定名称创建工程
petalinux-create -t project -s $bsp_name -n $prj_name$prj_index

# # 不基于BSP创建工程,zynqmp或zynq根据fpga型号确定
# # petalinux-create 命令用于创建新的PetaLinux 工程:
# # 注意--template对应的zynqMP后边两个字母是大写
# petalinux-create -t project --template ${zynq_arch} -n $prj_name$prj_index

cd $prj_name$prj_index

petalinux-config --get-hw-description hardware/xilinx-zc706-2022.1/outputs/project_1.xsa
# 进入配置界面后验证以下配置即可,然后保存配置并退出。如果有其他功能需要的自行配置
<<'CONTENT'
→ Yocto Settings
   Add pre-mirror url   --->
   Local sstate feeds settings  --->
   [*] Enable BB NO NETWORK
CONTENT

# 增加time命令是为了查看最终编译花了多长时间
time petalinux-build

# 生成启动镜像
petalinux-package --boot --fsbl --fpga --u-boot --force

# 如果要封装预构建镜像
petalinux-package --prebuilt --fpga <FPGA bitstream>
# 例如:
petalinux-package --prebuilt --fpga images/system.bit

offline_compile

Dockerfile
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# syntax=docker/dockerfile:1.4
# =====================================================================
# PetaLinux 2022.1 — multi-stage build
#
# Stage 1 ("builder") runs the Xilinx installer and extracts the offline
# sstate cache. Its image is discarded.
#
# Stage 2 ("final")   is the shipped image. Starts from a fresh
# ubuntu:18.04, re-installs apt deps, then pulls only cleaned artifacts
# from builder via `COPY --chown=vivado:vivado --from=builder`.
#
# Benefits vs the previous single-stage build:
#   * The installer .run and the three sstate.tar.gz are NEVER present
#     in the shipped image (rm'd in builder; builder layers discarded).
#   * --chown=vivado:vivado fixes the runtime permission issue: vivado
#     owns sstate at image build time, so petalinux-build can write to
#     downloads/ without root.
# =====================================================================


# =====================================================================
# Stage 1 — builder
# =====================================================================
FROM ubuntu:18.04 AS builder

# --- Optional Ubuntu mirror override (handy behind a firewall) -------
ARG UBUNTU_MIRROR
RUN if [ -n "${UBUNTU_MIRROR}" ]; then \
  sed -i "s|archive.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list && \
    sed -i "s|security.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list; \
  fi

# --- apt dependencies (UG1144 host requirements) ----------------------
# Single RUN: enable i386 + one update + install all (incl. zlib1g:i386).
RUN dpkg --add-architecture i386 && \
  apt-get update && \
  DEBIAN_FRONTEND=noninteractive apt-get install -y -q \
                                 autoconf automake bc bison build-essential chrpath cpio curl \
                                 debianutils diffstat emacs expect flex g++ gawk gcc gcc-multilib \
                                 git gnupg gzip iproute2 iputils-ping kmod less lib32ncurses5 \
                                 lib32stdc++6 lib32z1-dev libegl1-mesa libfontconfig1:i386 \
                                 libglib2.0-dev libgtk2.0-0 libidn11 libncurses5-dev libsdl1.2-dev \
                                 libselinux1 libsm6:i386 libssl-dev libtinfo5 libtool libtool-bin \
                                 libx11-6:i386 libxrender1:i386 locales make net-tools pax pxelinux \
                                 python python3 python3-git python3-jinja2 python3-pexpect \
                                 python3-pip rsync screen socat sudo tar texinfo tftp-hpa \
                                 tftpd-hpa tofrodos tree unzip vim wget xterm xvfb xz-utils \
                                 zlib1g-dev zlib1g:i386 \
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/*

# --- Locale (the installer is en_US.UTF-8 sensitive) -----------------
RUN locale-gen en_US.UTF-8 && update-locale LANG=en_US.UTF-8

# --- /bin/sh must be bash, not dash (UG1144) -------------------------
RUN echo "dash dash/sh boolean false" | debconf-set-selections && \
  DEBIAN_FRONTEND=noninteractive dpkg-reconfigure -f noninteractive dash

# --- Non-root user required by the PetaLinux installer ---------------
RUN adduser --disabled-password --gecos '' vivado && \
  usermod -aG sudo vivado && \
  echo "vivado ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

# --- Build-time arguments --------------------------------------------
ARG PETA_RUN_FILE=petalinux-v2022.1-04191534-installer.run
ARG DOWNLOADS_FILE=downloads_2022.1_09151236.tar.gz
ARG ARM_CACHE_FILE=sstate_arm_2022.1_04190222.tar.gz
ARG AARCH64_CACHE_FILE=sstate_aarch64_2022.1_09151236.tar.gz
ARG PETA_ZYNQ_AUTO_FILE=zynq_auto.sh
ARG PETA_ZYNQMP_AUTO_FILE=zynqmp_auto.sh

# --- Pull build inputs into the image --------------------------------
COPY --chmod=a+rx accept-eula.sh /${PETA_RUN_FILE} /
COPY ${DOWNLOADS_FILE} \
     ${ARM_CACHE_FILE} \
     ${AARCH64_CACHE_FILE} \
     ${PETA_ZYNQ_AUTO_FILE} \
     ${PETA_ZYNQMP_AUTO_FILE} \
     /opt/Xilinx/

# --- Run the installer and stage artifacts (single RUN) --------------
# Resulting layer contains only the FINAL state (tarballs removed,
# installer removed, scripts relocated, /tmp cache files removed).
RUN mkdir -p /opt/Xilinx && \
  chmod 777 /tmp /opt/Xilinx && \
  sudo -u vivado -i /accept-eula.sh /${PETA_RUN_FILE} /opt/Xilinx/petalinux && \
  rm -f /${PETA_RUN_FILE} /accept-eula.sh && \
  tar zxf /opt/Xilinx/${DOWNLOADS_FILE}     -C /opt/Xilinx/ && rm -f /opt/Xilinx/${DOWNLOADS_FILE} && \
  tar zxf /opt/Xilinx/${ARM_CACHE_FILE}     -C /opt/Xilinx/ && rm -f /opt/Xilinx/${ARM_CACHE_FILE} && \
  tar zxf /opt/Xilinx/${AARCH64_CACHE_FILE} -C /opt/Xilinx/ && rm -f /opt/Xilinx/${AARCH64_CACHE_FILE} && \
  chmod +x /opt/Xilinx/${PETA_ZYNQ_AUTO_FILE} && \
  chmod +x /opt/Xilinx/${PETA_ZYNQMP_AUTO_FILE}


# =====================================================================
# Stage 2 — final (the image that actually ships)
# =====================================================================
FROM ubuntu:18.04

# --- Optional Ubuntu mirror override (same as builder) --------------
ARG UBUNTU_MIRROR
RUN if [ -n "${UBUNTU_MIRROR}" ]; then \
  sed -i "s|archive.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list && \
    sed -i "s|security.ubuntu.com|${UBUNTU_MIRROR}|g" /etc/apt/sources.list; \
  fi

# --- apt dependencies (same set as builder; runtime needs them) -------
RUN dpkg --add-architecture i386 && \
  apt-get update && \
  DEBIAN_FRONTEND=noninteractive apt-get install -y -q \
                                 autoconf automake bc bison build-essential chrpath cpio curl \
                                 debianutils diffstat emacs expect flex g++ gawk gcc gcc-multilib \
                                 git gnupg gzip iproute2 iputils-ping kmod less lib32ncurses5 \
                                 lib32stdc++6 lib32z1-dev libegl1-mesa libfontconfig1:i386 \
                                 libglib2.0-dev libgtk2.0-0 libidn11 libncurses5-dev libsdl1.2-dev \
                                 libselinux1 libsm6:i386 libssl-dev libtinfo5 libtool libtool-bin \
                                 libx11-6:i386 libxrender1:i386 locales make net-tools pax pxelinux \
                                 python python3 python3-git python3-jinja2 python3-pexpect \
                                 python3-pip rsync screen socat sudo tar texinfo tftp-hpa \
                                 tftpd-hpa tofrodos tree unzip vim wget xterm xvfb xz-utils \
                                 zlib1g-dev zlib1g:i386 \
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/*

# --- Locale ----------------------------------------------------------
RUN locale-gen en_US.UTF-8 && update-locale LANG=en_US.UTF-8

# --- /bin/sh must be bash, not dash (UG1144) -------------------------
RUN echo "dash dash/sh boolean false" | debconf-set-selections && \
  DEBIAN_FRONTEND=noninteractive dpkg-reconfigure -f noninteractive dash

# --- Non-root user (must match the UID used at COPY --chown) ---------
RUN adduser --disabled-password --gecos '' vivado && \
  usermod -aG sudo vivado && \
  echo "vivado ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

# --- Bring in the cleaned artifacts from builder ---------------------
# --chown=vivado:vivado makes the sstate cache writable by vivado,
# so `petalinux-build` can populate downloads/ without root access.
COPY --chown=vivado:vivado --from=builder /opt/Xilinx/petalinux                       /opt/Xilinx/petalinux
COPY --chown=vivado:vivado --from=builder /opt/Xilinx/downloads                       /opt/Xilinx/downloads
COPY --chown=vivado:vivado --from=builder /opt/Xilinx/arm                             /opt/Xilinx/arm
COPY --chown=vivado:vivado --from=builder /opt/Xilinx/aarch64                         /opt/Xilinx/aarch64
COPY --chown=vivado:vivado --from=builder /opt/Xilinx/zynq_auto.sh                    /opt/Xilinx/zynq_auto.sh
COPY --chown=vivado:vivado --from=builder /opt/Xilinx/zynqmp_auto.sh                  /opt/Xilinx/zynqmp_auto.sh

# --- Switch to non-root for everything below -------------------------
USER vivado
ENV HOME=/home/vivado
ENV LANG=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8
WORKDIR /home/vivado/project

# --- Source PetaLinux settings on every shell -------------------------
# .bashrc   — interactive non-login shells (docker exec bash)
# .profile  — login shells (docker exec bash -l, automated scripts)
RUN { echo; \
      echo '# PetaLinux environment'; \
      echo 'source /opt/Xilinx/petalinux/settings.sh'; \
    } >> /home/vivado/.bashrc && \
  { echo; \
    echo '# PetaLinux environment'; \
    echo 'source /opt/Xilinx/petalinux/settings.sh'; \
  } >> /home/vivado/.profile
.dockerignore
1
2
*.bsp
md5sum*
accept-eula.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/usr/bin/expect
set timeout -1
set install_dir [lindex $argv 1]
set installer [lindex $argv 0]

spawn $installer -d $install_dir
set timeout 2
expect {
    "ERROR: Invalid options:" {spawn $installer -d $install_dir }
    timeout { }
}

set timeout 600
expect "Press Enter to display the license agreements"
send "\r"
set timeout 2

expect {
    "* >*" {send "y\r"}
    timeout { send "q"; sleep 1; exp_continue}
}
expect {
    "* >*" {send "y\r"}
    timeout { send "q"; sleep 1; exp_continue}
}
expect {
    "*Installing PetaLinux...*" {}
    "* >*" {send "y\r"}
    timeout { send "q"; sleep 1; exp_continue}
}

set timeout -1
expect "INFO: Checking PetaLinux installer integrity..."
expect "INFO: PetaLinux SDK has been installed"
#interact
zynq_auto.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/bin/bash
## 本地仓库设置
SSTATE_LOCAL_PATH="/opt/Xilinx"

#删除带有指定关键字的行
delete_line_with_special_word ()
{
  if [[ $# -lt 2 ]]; then
	return
  fi
  FILE=$1
  WORD=$2

  sed -i "/${WORD}/d" ${FILE}
}
#文件内容追加
append_line_into_file ()
{
  if [[ $# -lt 2 ]]; then
	return
  fi
  FILE=$1
  LINE=$2
  echo do
  echo $LINE >> $FILE
}
CONFIG="./project-spec/configs/config"
cp $CONFIG $CONFIG.old

## 本地包
delete_line_with_special_word   $CONFIG  CONFIG_YOCTO_NETWORK_SSTATE_FEEDS
append_line_into_file           $CONFIG  "# CONFIG_YOCTO_NETWORK_SSTATE_FEEDS is not set"
delete_line_with_special_word   $CONFIG  CONFIG_YOCTO_BB_NO_NETWORK
append_line_into_file           $CONFIG  "CONFIG_YOCTO_BB_NO_NETWORK=y"
delete_line_with_special_word   $CONFIG  CONFIG_PRE_MIRROR_URL
append_line_into_file           $CONFIG  "CONFIG_PRE_MIRROR_URL=\"file://${SSTATE_LOCAL_PATH}/downloads\""
delete_line_with_special_word   $CONFIG  CONFIG_YOCTO_LOCAL_SSTATE_FEEDS_URL
append_line_into_file           $CONFIG  "CONFIG_YOCTO_LOCAL_SSTATE_FEEDS_URL=\"${SSTATE_LOCAL_PATH}/arm\"" #zynq

## | 目录      | 平台        |
## | --------- | ----------- |
## | aarch64   | ZynqMP      |
## | arm       | Zynq        |
## | mb-full   | MB AXI      |
## | mb-lite   | MB AXI lite |
## | downloads | 全平台  |

## 免输入密码登陆
delete_line_with_special_word   $CONFIG  CONFIG_YOCTO_ENABLE_DEBUG_TWEAKS
append_line_into_file           $CONFIG  "CONFIG_YOCTO_ENABLE_DEBUG_TWEAKS=y"
zynqmp_auto.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/bin/bash
## 本地仓库设置
SSTATE_LOCAL_PATH="/opt/Xilinx"

#删除带有指定关键字的行
delete_line_with_special_word ()
{
  if [[ $# -lt 2 ]]; then
	return
  fi
  FILE=$1
  WORD=$2

  sed -i "/${WORD}/d" ${FILE}
}
#文件内容追加
append_line_into_file ()
{
  if [[ $# -lt 2 ]]; then
	return
  fi
  FILE=$1
  LINE=$2
  echo do
  echo $LINE >> $FILE
}
CONFIG="./project-spec/configs/config"
cp $CONFIG $CONFIG.old

## 本地包
delete_line_with_special_word   $CONFIG  CONFIG_YOCTO_NETWORK_SSTATE_FEEDS
append_line_into_file           $CONFIG  "# CONFIG_YOCTO_NETWORK_SSTATE_FEEDS is not set"
delete_line_with_special_word   $CONFIG  CONFIG_YOCTO_BB_NO_NETWORK
append_line_into_file           $CONFIG  "CONFIG_YOCTO_BB_NO_NETWORK=y"
delete_line_with_special_word   $CONFIG  CONFIG_PRE_MIRROR_URL
append_line_into_file           $CONFIG  "CONFIG_PRE_MIRROR_URL=\"file://${SSTATE_LOCAL_PATH}/downloads\""
delete_line_with_special_word   $CONFIG  CONFIG_YOCTO_LOCAL_SSTATE_FEEDS_URL
append_line_into_file           $CONFIG  "CONFIG_YOCTO_LOCAL_SSTATE_FEEDS_URL=\"${SSTATE_LOCAL_PATH}/aarch64\"" #zynqMP

## | 目录      | 平台        |
## | --------- | ----------- |
## | aarch64   | ZynqMP      |
## | arm       | Zynq        |
## | mb-full   | MB AXI      |
## | mb-lite   | MB AXI lite |
## | downloads | 全平台  |

## 免输入密码登陆
delete_line_with_special_word   $CONFIG  CONFIG_YOCTO_ENABLE_DEBUG_TWEAKS
append_line_into_file           $CONFIG  "CONFIG_YOCTO_ENABLE_DEBUG_TWEAKS=y"
基于bsp验证环境
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
bsp_name="xilinx-zc706-v2022.1-04191534.bsp"
zynq_arch="zynq"
prj_index=1
prj_name="prj_"

# 仅当依赖目录非普通用户权限时执行,普通用户为vivado,超级用户为root
sudo chown -R vivado:vivado ../$(basename $PWD)

# 如果不指定工程名称,会以bsp文件命名工程,根据喜好二选一,前边定义的变量也是为了方便创建工程
# 1. 基于BSP创建工程,工程名称为BSP名称
petalinux-create -t project -s $bsp_name
# 2. 基于BSP创建工程,根据指定名称创建工程
petalinux-create -t project -s $bsp_name -n $prj_name$prj_index

# 不基于BSP创建工程,zynqmp或zynq根据fpga型号确定
# petalinux-create 命令用于创建新的PetaLinux 工程:
# 注意--template对应的zynqMP后边两个字母是大写
petalinux-create -t project --template ${zynq_arch} -n $prj_name$prj_index

cd $prj_name$prj_index

# 确认离线编译目录下有arm、aarch64、downloads
ls /opt/Xilinx
# 运行离线编译脚本
/opt/Xilinx/zynq_auto.sh

petalinux-config --get-hw-description hardware/xilinx-zc706-2022.1/outputs/project_1.xsa
# 进入配置界面后验证以下配置即可,然后保存配置并退出。如果有其他功能需要的自行配置
<<'CONTENT'
→ Yocto Settings
   Add pre-mirror url   --->
   Local sstate feeds settings  --->
   [*] Enable BB NO NETWORK
CONTENT

# 增加time命令是为了查看最终编译花了多长时间
time petalinux-build

# 生成启动镜像
petalinux-package --boot --fsbl --fpga --u-boot --force

# 如果要封装预构建镜像
petalinux-package --prebuilt --fpga <FPGA bitstream>
# 例如:
petalinux-package --prebuilt --fpga images/system.bit

构建容器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
time DOCKER_BUILDKIT=1 docker build \
     --network=host \
     --build-arg UBUNTU_MIRROR=mirrors.aliyun.com \
     -t petalinux:2022.1 .

# 完成构建后运行容器
# 可以在本地创建并进入工作目录后与容器工作目录完成挂载
mkdir -p /data/disk/Projects/petalinux_2022.1
cd /data/disk/Projects/petalinux_2022.1
docker run -ti --rm \
       -e DISPLAY=$DISPLAY \
       --net="host" \
       -v /tmp/.X11-unix:/tmp/.X11-unix \
       -v $HOME/.Xauthority:/home/vivado/.Xauthority \
       -v ./:/home/vivado/project \
       petalinux:2022.1 /bin/bash

容器导出与导入

1
2
3
4
# 导出容器
time docker save -o petalinux_2022.1.tar petalinux:2022.1
# 导入容器
time docker load -i petalinux_2022.1.tar