工作环境搭建合集

工作及学习调试环境搭建合集

index.org是主文件,其他文件或目录都是基于此文件导出生成。LICENSE则是另外添加的。

基于Ubuntu 20.04.4使用Docker构建工作环境。petalinux-2018.3/2022.1采用了分阶段构建,镜像体积大幅缩小。

使用emacs导出index.org代码块,快捷方式:

1
emacs index.org --batch --eval '(org-babel-tangle)'

代码块导出在index.org文件所在目录下。

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

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 -f

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
12
13
14
# 使用内网镜像源构建
# 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 system prune -f

# 验证
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` ― 本文档

ubuntu22.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:22.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
12
13
14
15
16
17
18
# 使用内网镜像源构建
# docker build --build-arg UBUNTU_MIRROR=mirrors.aliyun.com -t ubuntu16-dev .
# 或
time docker pull ubuntu:22.04 && \
  time DOCKER_BUILDKIT=1 docker build \
     --network=host \
     --build-arg UBUNTU_MIRROR=mirrors.tuna.tsinghua.edu.cn \
     -t ubuntu22-dev:latest .

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

# 验证
docker run --rm -it \
       --network=host \
       -e http_proxy=http://127.0.0.1:10808 \
       -e https_proxy=http://127.0.0.1:10808 \
       ubuntu22-dev

ubuntu24.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:24.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
12
13
14
15
16
17
18
19
# 使用内网镜像源构建
# docker build --build-arg UBUNTU_MIRROR=mirrors.aliyun.com -t ubuntu16-dev .
# 或
time docker pull ubuntu:24.04 && \
  time DOCKER_BUILDKIT=1 docker build \
     --network=host \
     --build-arg UBUNTU_MIRROR=mirrors.tuna.tsinghua.edu.cn \
     -t ubuntu24-dev:latest .

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

# 验证
docker run --rm -it ubuntu24-dev
# 如果git clone gitee仓库失败时可进入容器后取消代理
unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY && \
  env | grep -i proxy
# 克隆emacs(个人喜欢使用emacs)
git clone https://gitee.com/emacsd/emacs.d.git

cmake-examples

ubuntu16.04-cmake-3.5.1

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
# Container for building and testing cmake-examples with default cmake v3.5.1
FROM ubuntu:16.04

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 DEBIAN_FRONTEND=noninteractive  && \
  apt-get update && apt-get install -y \
                            --no-install-recommends \
                            build-essential \
                            clang-3.6 \
                            clang-format-3.6 \
                            cmake \
                            curl \
                            emacs \
                            findutils \
                            git \
                            iputils-ping \
                            less \
                            libboost-all-dev \
                            libprotobuf-dev \
                            locales \
                            ninja-build \
                            protobuf-compiler \
                            python3 \
                            python3-pip \
                            software-properties-common \
                            sudo \
                            tree \
                            vim \
                            wget \
                            net-tools \
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# Make `python` point to python3 as well (conan may probe both)
RUN ln -sf /usr/bin/python3 /usr/bin/python

# 用 PyPA Py3.5 专用 bootstrap 升 pip 到 20.3.4
RUN curl -sS https://bootstrap.pypa.io/pip/3.5/get-pip.py -o /tmp/get-pip-35.py && \
  python3 /tmp/get-pip-35.py && \
  python3 -m pip --version

# Conan via miniforge (Python 3.7 pre-built, fast)
RUN curl -x 127.0.0.1:10808 -fsSL https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh \
    -o /tmp/mamba.sh  && \
  bash /tmp/mamba.sh -b -p /opt/conda && \
  rm /tmp/mamba.sh && \
  /opt/conda/bin/conda install -y -q -c conda-forge \
                       'python=3.7' 'conan=1.59' && \
  /opt/conda/bin/conda clean -afy && \
  ln -sf /opt/conda/bin/conan /usr/local/bin/conan 

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

# cppcheck
RUN cd /usr/local/src && \
  wget -e "https_proxy=127.0.0.1:10808" https://github.com/cppcheck-opensource/cppcheck/archive/refs/tags/1.79.tar.gz && \
  tar xvf 1.79.tar.gz && \
  cd cppcheck-1.79 && \
  mkdir build && \
  cd build && \
  cmake .. && \
  make -j"$(nproc)" install && \
  cd ../.. && rm -rf cppcheck*

RUN cd /usr/local/src && \
  wget  -e "https_proxy=127.0.0.1:10808" https://github.com/tianon/gosu/releases/download/1.10/gosu-amd64 && \
  mv gosu-amd64 /usr/local/bin/gosu && \
  chmod +x /usr/local/bin/gosu

RUN adduser --disabled-password --gecos '' devuser && \
  usermod -aG sudo devuser && \
  echo "devuser ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \
  mkdir -p /home/devuser/project && \
  chown devuser:devuser /home/devuser/project


ENV LANG=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8
WORKDIR /home/devuser/project
构建与运行容器

既使用了代理,又换了安装源。使用代理是因为构建容器过程需要访问github资源,而更换镜像源则是为了运行容器后方便根据需要安装apt包,同时运行容器也传入了代理,以备不时之需

 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
# 构建容器
time docker pull ubuntu:16.04 && \
  time DOCKER_BUILDKIT=1 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.04-cmake-3.5.1 .

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

# ================================================================
docker run --rm -it \
       --network=host \
       -e http_proxy=http://127.0.0.1:10808 \
       -e https_proxy=http://127.0.0.1:10808 \
       ubuntu16.04-cmake-3.5.1

# 容器内操作。cmake-examples:因为 conancenter 上只有无 user/channel 的 fmt/5.3.0#<revision>,所以sed命令修改conanfile.txt以适配
git clone https://github.com/ttroy50/cmake-examples.git ~/code && \
  cd ~/code && \
  sed -i 's|fmt/5\.3\.0@bincrafters/stable|fmt/5.3.0@|' \
      07-package-management/D-conan/i-basic/conanfile.txt \
      07-package-management/D-conan/ii-basic-targets/conanfile.txt && \
  ./test.sh
# ================================================================
# 或
# ================================================================
# git clone -c http.proxy="127.0.0.1:10808" https://github.com/ttroy50/cmake-examples.git code
git clone https://github.com/ttroy50/cmake-examples.git && \
  cd cmake-examples && \
  sed -i 's|fmt/5\.3\.0@bincrafters/stable|fmt/5.3.0@|' \
      07-package-management/D-conan/i-basic/conanfile.txt \
      07-package-management/D-conan/ii-basic-targets/conanfile.txt

docker run --rm -it \
       --network=host \
       -v "$PWD":/home/devuser/project \
       ubuntu16.04-cmake-3.5.1 /bin/bash -c './test.sh' && \
  docker run --rm -it \
         --network=host \
         -v "$PWD":/home/devuser/project \
         ubuntu16.04-cmake-3.5.1
<<'CONTENT'
其实就是调用容器环境编译然后再进入容器,也可以直接进入容器后执行 ./test.sh,只是为了方便没有这样做,当然,根据个人习惯,很难说哪个更方便 
CONTENT
# ================================================================

ubuntu16.04-cmake-3.10.3

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
# Container for building and testing cmake-examples with default cmake v3.5.1
FROM ubuntu:16.04

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 DEBIAN_FRONTEND=noninteractive  && \
  apt-get update && apt-get install -y \
                            --no-install-recommends \
                            build-essential \
                            clang-3.6 \
                            clang-format-3.6 \
                            curl \
                            emacs \
                            findutils \
                            git \
                            iputils-ping \
                            less \
                            libboost-all-dev \
                            libprotobuf-dev \
                            locales \
                            ninja-build \
                            protobuf-compiler \
                            python3 \
                            python3-pip \
                            software-properties-common \
                            sudo \
                            tree \
                            vim \
                            wget \
                            net-tools \
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# cmake-3.10.3
RUN cd /usr/local/src && \
  wget -c -e "https_proxy=127.0.0.1:10808" https://github.com/Kitware/CMake/releases/download/v3.10.3/cmake-3.10.3.tar.gz && \
  tar xvf cmake-3.10.3.tar.gz && \
  cd cmake-3.10.3 && \
  ./bootstrap && \
  make && \
  make install && \
  cd .. && \
  rm -rf cmake*

# Make `python` point to python3 as well (conan may probe both)
RUN ln -sf /usr/bin/python3 /usr/bin/python

# 用 PyPA Py3.5 专用 bootstrap 升 pip 到 20.3.4
RUN curl -sS https://bootstrap.pypa.io/pip/3.5/get-pip.py -o /tmp/get-pip-35.py && \
  python3 /tmp/get-pip-35.py && \
  python3 -m pip --version

# Conan via miniforge (Python 3.7 pre-built, fast)
RUN curl -x 127.0.0.1:10808 -fsSL https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh \
    -o /tmp/mamba.sh  && \
  bash /tmp/mamba.sh -b -p /opt/conda && \
  rm /tmp/mamba.sh && \
  /opt/conda/bin/conda install -y -q -c conda-forge \
                       'python=3.7' 'conan=1.59' && \
  /opt/conda/bin/conda clean -afy && \
  ln -sf /opt/conda/bin/conan /usr/local/bin/conan 

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

# cppcheck
RUN cd /usr/local/src && \
  wget -e "https_proxy=127.0.0.1:10808" https://github.com/cppcheck-opensource/cppcheck/archive/refs/tags/1.79.tar.gz && \
  tar xvf 1.79.tar.gz && \
  cd cppcheck-1.79 && \
  mkdir build && \
  cd build && \
  cmake .. && \
  make -j"$(nproc)" install && \
  cd ../.. && rm -rf cppcheck*

RUN cd /usr/local/src && \
  wget  -e "https_proxy=127.0.0.1:10808" https://github.com/tianon/gosu/releases/download/1.10/gosu-amd64 && \
  mv gosu-amd64 /usr/local/bin/gosu && \
  chmod +x /usr/local/bin/gosu

RUN adduser --disabled-password --gecos '' devuser && \
  usermod -aG sudo devuser && \
  echo "devuser ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \
  mkdir -p /home/devuser/project && \
  chown devuser:devuser /home/devuser/project


ENV LANG=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8
WORKDIR /home/devuser/project
构建与运行容器

既使用了代理,又换了安装源。使用代理是因为构建容器过程需要访问github资源,而更换镜像源则是为了运行容器后方便根据需要安装apt包,同时运行容器也传入了代理,以备不时之需

 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
# 构建容器
time docker pull ubuntu:16.04 && \
  time DOCKER_BUILDKIT=1 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.04-cmake-3.10.3 .

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

# ================================================================
docker run --rm -it \
       --network=host \
       -e http_proxy=http://127.0.0.1:10808 \
       -e https_proxy=http://127.0.0.1:10808 \
       ubuntu16.04-cmake-3.10.3

# 容器内操作。cmake-examples:因为 conancenter 上只有无 user/channel 的 fmt/5.3.0#<revision>,所以sed命令修改conanfile.txt以适配
git clone https://github.com/ttroy50/cmake-examples.git ~/code && \
  cd ~/code && \
  sed -i 's|fmt/5\.3\.0@bincrafters/stable|fmt/5.3.0@|' \
      07-package-management/D-conan/i-basic/conanfile.txt \
      07-package-management/D-conan/ii-basic-targets/conanfile.txt && \
  ./test.sh
# ================================================================
# 或
# ================================================================
# git clone -c http.proxy="127.0.0.1:10808" https://github.com/ttroy50/cmake-examples.git code
git clone https://github.com/ttroy50/cmake-examples.git && \
  cd cmake-examples && \
  sed -i 's|fmt/5\.3\.0@bincrafters/stable|fmt/5.3.0@|' \
      07-package-management/D-conan/i-basic/conanfile.txt \
      07-package-management/D-conan/ii-basic-targets/conanfile.txt

docker run --rm -it \
       --network=host \
       -v "$PWD":/home/devuser/project \
       ubuntu16.04-cmake-3.10.3 \
       /bin/bash -c './test.sh' && \
  docker run --rm -it \
         --network=host \
         -v "$PWD":/home/devuser/project \
         ubuntu16.04-cmake-3.10.3
<<'CONTENT'
其实就是调用容器环境编译然后再进入容器,也可以直接进入容器后执行 ./test.sh,只是为了方便没有这样做,当然,根据个人习惯,很难说哪个更方便 
CONTENT
# ================================================================

petalinux-2018.3

依赖文件

依赖文件放在 Dockerfile 同目录下

online_compileoffline_compile
petalinux-v2018.3-final-installer.runpetalinux-v2018.3-final-installer.run
sstate-rel-v2018.3.tar.gz
下载petalinux或相关的离线编译包

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

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

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
16
# 构建容器
time docker pull ubuntu:16.04 && \
  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

FMQL-Linux-SDK

FMQL系列BSP包适用于: JFMQL/FMQL10S/15T/20S/45T系列PSOC芯片。

FMQLMP系列BSP包仅适用于: JFMQL100T/100TAI系列PSOC芯片。

petalinux2018.3_FMQL-Linux-SDK-Prj-20240923

依赖文件

依赖文件放在 Dockerfile 同目录下

petalinux-v2018.3-final-installer.run
FMQL-Linux-SDK-Prj-20240923.tar.bz2
0001-fix-xilinx_dma_stop_transfer-poll-extra-XILINX_DMA_D.patch
0002-fix-can-add-thread-handler-to-reset-after-overrun.patch
下载petalinux或相关的离线编译包

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

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

复旦微下载站官网:https://download.fdwxhb.com

复旦微下载站需要访问账户,由公司向官方销售获取,或者网上有的博客文章中也会有不慎提供出来的账户

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 在网页下载单文件,如果希望下载网页整个目录的话,模板(cygwin/git-bash)如下:
export user="test"
export passwd="123456"

url=(
  "url1"
  "url2"
)

for i in ${url[@]}; do
  wget --no-check-certificate -c -r -np -nH --reject="index.html*" --user=${user} --password=${passwd} --user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36"  -P './' -r ${i}

  # 如果是 Windows 下避免提示文件权限错乱,执行以下命令:
  cmd /c icacls . /reset /t
  <<'CONTENT'
- `/reset`:将对象的 DACL 恢复为**继承父目录的权限**;**不会直接作用到子文件夹和子文件**。
- `/t` = 遍历所有子目录,对匹配的文件 / 文件夹执行操作。
- 仅windows需要重置权限(默认可以注释不重置,如果提示权限顺序错乱则可以重置权限),其他系统平台则不需要
CONTENT
done
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
171
172
173
174
175
176
177
178
179
# 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.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=FMQL-Linux-SDK-Prj-20240923.tar.bz2 ...
ARG PETA_RUN_FILE=petalinux-v2018.3-final-installer.run
ARG FMQLMP_SDK_TAR=FMQL-Linux-SDK-Prj-20240923.tar.bz2
ARG FMQLMP_SDK_PATCH_1=0001-fix-xilinx_dma_stop_transfer-poll-extra-XILINX_DMA_D.patch
ARG FMQLMP_SDK_PATCH_2=0002-fix-can-add-thread-handler-to-reset-after-overrun.patch
ARG FMQLMP_SDK_DIR=/opt/pkg/FMQL-Linux-SDK-Prj-20240923
ARG PETALINUX_PATH=/opt/Xilinx/petalinux

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

# --- 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 -- . && \
  cp "/${FMQLMP_SDK_PATCH_1}" "/${FMQLMP_SDK_PATCH_2}" "${FMQLMP_SDK_DIR}" && \
  cd "${FMQLMP_SDK_DIR}" && \
  patch -p1 < "${FMQLMP_SDK_PATCH_1}" && \
  patch -p1 < "${FMQLMP_SDK_PATCH_2}" && \
  cd - && \
  sed -i 's|\(^[[:space:]]*export PETALINUX=\).*|\1'"${PETALINUX_PATH}"'|g' \
      "${FMQLMP_SDK_DIR}/env.sh" && \
  chown -R vivado:vivado "${PETALINUX_PATH}" "${FMQLMP_SDK_DIR}" && \
  rm -f /${FMQLMP_SDK_TAR} /${FMQLMP_SDK_PATCH_1} /${FMQLMP_SDK_PATCH_2}


# =====================================================================
# 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/FMQL-Linux-SDK-Prj-20240923

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.sh"; \
    } >> /home/vivado/.bashrc && \
    { echo; \
      echo '# FMQLMP-Linux-SDK environment'; \
      echo "source ${FMQLMP_SDK_DIR}/env.sh"; \
    } >> /home/vivado/.profile
构建容器
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 构建容器
time docker pull ubuntu:16.04 && \
  time DOCKER_BUILDKIT=1 docker build \
     --network=host \
     --build-arg UBUNTU_MIRROR=mirrors.tuna.tsinghua.edu.cn \
     -t petalinux2018.3-fmql-linux-sdk-prj-20240923 .

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

# 运行容器
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-fmql-linux-sdk-prj-20240923 /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-fmql-linux-sdk-prj-20240923.tar \
     petalinux2018.3-fmql-linux-sdk-prj-20240923:latest
# 导入容器
time docker load -i petalinux2018.3-fmql-linux-sdk-prj-20240923.tar

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

依赖文件

依赖文件放在 Dockerfile 同目录下

petalinux-v2018.3-final-installer.run
FMQLMP-Linux-SDK-Prj-20250408.tar.bz2
0001-don-t-disable-gic-group1-and-group0.patch
0002-fix-Resolve-bootamp-compile-error-for-ql10-ql45.patch
0003-fix-Force-clean-the-atf-to-update-the-configuration-.patch
下载petalinux或相关的离线编译包

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

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

复旦微下载站官网:https://download.fdwxhb.com

复旦微下载站需要访问账户,由公司向官方销售获取,或者网上有的博客文章中也会有不慎提供出来的账户

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 在网页下载单文件,如果希望下载网页整个目录的话,模板(cygwin/git-bash)如下:
export user="test"
export passwd="123456"

url=(
  "url1"
  "url2"
)

for i in ${url[@]}; do
  wget --no-check-certificate -c -r -np -nH --reject="index.html*" --user=${user} --password=${passwd} --user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36"  -P './' -r ${i}

  # 如果是 Windows 下避免提示文件权限错乱,执行以下命令:
  cmd /c icacls . /reset /t
  <<'CONTENT'
- `/reset`:将对象的 DACL 恢复为**继承父目录的权限**;**不会直接作用到子文件夹和子文件**。
- `/t` = 遍历所有子目录,对匹配的文件 / 文件夹执行操作。
- 仅windows需要重置权限(默认可以注释不重置,如果提示权限顺序错乱则可以重置权限),其他系统平台则不需要
CONTENT
done
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
171
172
173
174
175
176
177
178
179
180
181
182
183
# 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_PATCH_1=0001-don-t-disable-gic-group1-and-group0.patch
ARG FMQLMP_SDK_PATCH_2=0002-fix-Resolve-bootamp-compile-error-for-ql10-ql45.patch
ARG FMQLMP_SDK_PATCH_3=0003-fix-Force-clean-the-atf-to-update-the-configuration-.patch
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} \
     /${FMQLMP_SDK_PATCH_1} \
     /${FMQLMP_SDK_PATCH_2} \
     /${FMQLMP_SDK_PATCH_3} \
     /

# --- 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 -- . && \
  cp "/${FMQLMP_SDK_PATCH_1}" "/${FMQLMP_SDK_PATCH_2}" "/${FMQLMP_SDK_PATCH_3}" \
     "${FMQLMP_SDK_DIR}" && \
  cd "${FMQLMP_SDK_DIR}" && \
  patch -p1 < "${FMQLMP_SDK_PATCH_1}" && \
  patch -p1 < "${FMQLMP_SDK_PATCH_2}" && \
  patch -p1 < "${FMQLMP_SDK_PATCH_3}" && \
  cd - && \
  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} /${FMQLMP_SDK_PATCH_1} /${FMQLMP_SDK_PATCH_2} /${FMQLMP_SDK_PATCH_3}


# =====================================================================
# 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
17
18
19
20
# 构建容器
time docker pull ubuntu:16.04 && \
  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 .

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

# 运行容器
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

依赖文件

依赖文件放在 Dockerfile 同目录下

online_compileoffline_compile
petalinux-v2022.1-04191534-installer.runpetalinux-v2022.1-04191534-installer.run
downloads_2022.1_09151236.tar.gz
sstate_arm_2022.1_04190222.tar.gz
sstate_aarch64_2022.1_09151236.tar.gz
下载petalinux或相关的离线编译包

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

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

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
17
18
19
20
time docker pull ubuntu:16.04 && \
  time DOCKER_BUILDKIT=1 docker build \
     --network=host \
     --build-arg UBUNTU_MIRROR=mirrors.aliyun.com \
     -t petalinux:2022.1 .

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

# 完成构建后运行容器
# 可以在本地创建并进入工作目录后与容器工作目录完成挂载
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

用 Docker 部署 Syncthing:Compose、端口和目录映射避坑

方案一:Docker Compose

 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
# 添加docker-compose.yml
dirs=(
  ~/syncthing
  ~/syncthing/config
  ~/syncthing/data
)

for i in ${dirs[@]}; do
  mkdir -p ${i}
  chown -R 1000:1000 ${i}
done

cd ~/syncthing
cat > docker-compose.yml <<'EOF'
services:
  syncthing:
    image: syncthing/syncthing:latest
    container_name: syncthing
    hostname: my-nas-syncthing
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Asia/Shanghai
    volumes:
      - ./config:/var/syncthing/config
      - ./data:/var/syncthing/data
    ports:
      - 8384:8384
      - 22000:22000/tcp
      - 22000:22000/udp
      - 21027:21027/udp
      # 如需只允许局域网/本机访问 GUI,可改绑具体地址(二选一):
      # - "192.168.1.10:8384:8384"
      # - "127.0.0.1:8384:8384"
    restart: unless-stopped
EOF

<<'CONTENT'
# 想要再次创建同名容器,都需要先删除已存在的syncthing容器
# (首次部署没有该容器,用 || true 忽略报错)
docker rm -f syncthing 2>/dev/null || true
CONTENT

# 放行规则(面向服务器对外端口;注意其作用范围,见文末“避坑说明”)
ufw allow 8384/tcp
ufw allow 22000/tcp
ufw allow 22000/udp
ufw allow 21027/udp
# 使能ufw
ufw enable
# 重加载ufw
ufw reload

# 查看ufw状态
ufw status

# UFW 通过 systemd 服务管理
sudo systemctl enable ufw
sudo systemctl start ufw
# 查看服务状态
sudo systemctl status ufw

# 如果要删除IPv4和IPv6规则,逐条执行
ufw delete allow 8384/tcp
ufw delete allow 22000/tcp
ufw delete allow 22000/udp
ufw delete allow 21027/udp

# 在yml所在目录启动项目
docker compose up -d

# 查看日志
docker logs -f syncthing

# 如果要停止容器
docker compose down

# 查看状态
docker compose ps
docker logs -f syncthing

# 打开 Web UI(局域网):http://服务器IP:8384
# 首次进入后台后,先设置 GUI 用户名和密码。

方案二:docker run

 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
# 准备目录(与方案一同一套路径,便于对照)
dirs=(
  ~/syncthing
  ~/syncthing/config
  ~/syncthing/data
)

for i in ${dirs[@]}; do
  mkdir -p ${i}
  chown -R 1000:1000 ${i}
done

cd ~/syncthing

<<'CONTENT'
# 想要再次创建同名容器,都需要先删除已存在的syncthing容器
# 【注意:必须在 docker run 之前删除】,首次为空用 || true 忽略报错
docker rm -f syncthing 2>/dev/null || true
CONTENT

docker run -d \
       --name syncthing \
       --hostname my-nas-syncthing \
       -e PUID=1000 \
       -e PGID=1000 \
       -e TZ=Asia/Shanghai \
       -p 8384:8384 \
       -p 22000:22000/tcp \
       -p 22000:22000/udp \
       -p 21027:21027/udp \
       -v ~/syncthing/config:/var/syncthing/config \
       -v ~/syncthing/data:/var/syncthing/data \
       --restart unless-stopped \
       syncthing/syncthing:latest

# 放行规则(面向服务器对外端口;注意其作用范围,见文末“避坑说明”)
ufw allow 8384/tcp
ufw allow 22000/tcp
ufw allow 22000/udp
ufw allow 21027/udp
# 使能ufw
ufw enable
# 重加载ufw
ufw reload

# 查看ufw状态
ufw status

# UFW 通过 systemd 服务管理
sudo systemctl enable ufw
sudo systemctl start ufw
# 查看服务状态
sudo systemctl status ufw

# 如果要删除IPv4和IPv6规则,逐条执行
ufw delete allow 8384/tcp
ufw delete allow 22000/tcp
ufw delete allow 22000/udp
ufw delete allow 21027/udp

# 查看日志
docker logs -f syncthing

# 查看状态(docker run 方式用 docker ps;对应 compose 的 docker compose ps)
docker ps

# 如果要停止/删除容器(对应 compose 的 docker compose down)
docker stop syncthing
docker rm syncthing

# 打开 Web UI(局域网):http://服务器IP:8384
# 首次进入后台后,先设置 GUI 用户名和密码。

避坑说明(UFW、持久化、命名、鉴权)

 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
# 【避坑 1】ufw 与 Docker 的作用层次
#   云服务器上,一个端口的实际可达性从外到内由三层决定:
#     1) 云平台安全组 / 网络 ACL —— 最先生效,也是云端最关键的一层;
#        想对外只开必要端口(如 22、22000/udp+tcp、21027/udp),应优先在这里配置。
#     2) Docker iptables(DOCKER 链)—— -p 发布的端口直接写入这里,
#        在 ufw 的 INPUT 规则之前转发,因此 ufw 的 allow/deny 管不到容器端口。
#     3) ufw —— 只管“主机自身”的端口(非 Docker 发布)。
#   结论:8384/22000/21027 属于 Docker 发布的端口,ufw allow 实际不起作用;
#         要限制它们,请在“云安全组”里配,或用 DOCKER-USER 链 / 端口 bind 到指定地址。
#   例:仅允许云端内网段 10.0.0.0/8 访问 22000(其余丢弃):
#     sudo iptables -I DOCKER-USER -p tcp --dport 22000 ! -s 10.0.0.0/8 -j DROP
#     sudo iptables -I DOCKER-USER -p udp --dport 22000 ! -s 10.0.0.0/8 -j DROP
#   或用 ufw-docker:https://github.com/chaifeng/ufw-docker
#
# 【避坑 2】数据持久化
#   官方镜像家目录是 /var/syncthing,含 config/ 与 data/(索引库);
#   两者都要挂出来,只挂 config 会在容器重建后重新扫描/哈希。
#
# 【避坑 3】container_name 固定时,重建前需先删同名容器
#   (上面两节均已用 docker rm -f … 2>/dev/null || true 处理)。
#
# 【避坑 4】GUI 首次启动无鉴权,进入 http://…:8384 后应立即设置用户名和密码。
#
# 【避坑 5】数据目录属主要与 PUID/PGID 一致(默认 1000:1000);
#   官方 syncthing/syncthing 镜像支持 PUID/PGID。

termux安装配置syncthing

方案一:termux内安装运行syncthing

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
pkg update

pkg install -y syncthing

# syncthing配置为局域网访问
IPV4="0.0.0.0"
sed -i 's|\(^[[:space:]]*<address>\).*\(:8384</address>\)|\1'"${IPV4}"'\2|g' ~/.local/state/syncthing/config.xml

# 运行
syncthing
注意

如果报错 folder marker missing:

  • 原因:同步目录顶层缺失 .stfolder 标记目录;删除/恢复目录时,空隐藏目录未被备份恢复,Syncthing触发保护停止同步,防止误删扩散
  • 风险警告:手动重建.stfolder前,先将远端对应文件夹设为仅接收(receive only),避免删除指令同步到其他设备
  • 修复方案一(确认本地文件完整):
1
2
3
cd "同步目录根路径"
mkdir .stfolder
touch .stfolder/marker

方案二:termux基于ubuntu容器安装配置syncthing

使用体验效果不太好,界面刷新慢

termux配置ubuntu容器
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 使用 proot-distro 安装 Ubuntu
pkg update
pkg install proot-distro

# 安装 Ubuntu
proot-distro install ubuntu

# ubuntu挂载termux家目录
echo 'alias ubl="proot-distro login ubuntu --bind /data/data/com.termux/files/home:/termux"' >> ~/.bashrc
source ~/.bashrc

# 执行 ubl 登录ubuntu系统
ubl

# 如果需要解决中文乱码问题
echo 'export LANG=C.UTF-8' >> ~/.profile
echo 'export LC_ALL=C.UTF-8' >> ~/.profile
source ~/.profile
安装配置syncthing
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 进入ubuntu容器
ubl
# 更新软件源
apt update
# 安装syncthing
apt install -y syncthing

# 进入syncthing配置目录
cd ~/.local/state/syncthing

# IP修改为局域网访问
IPV4="0.0.0.0"
sed -i 's|\(^[[:space:]]*<address>\).*\(:8384</address>\)|\1'"${IPV4}"'\2|g' config.xml

# 运行
syncthing
syncthing命令行重置GUI密码
1
2
3
4
5
# 1. 先停止正在运行的 syncthing 进程,否则修改会被覆盖
# 2. 在 syncthing 二进制程序所在目录执行下面命令(windows是在二进制文件所在目录,如果是termux则直接执行就行)
syncthing generate --gui-user=yenao_syncthing --gui-password=你新设的密码

# 3. 启动 syncthing,使用上面设置的账号密码登录
参考链接

https://www.doubao.com/thread/xri1y5YjcJMVGQo85