Repository navigation
Expand file tree
/
Copy pathMakefile.container
More file actions
212 lines (187 loc) · 9.14 KB
/
Copy pathMakefile.container
File metadata and controls
212 lines (187 loc) · 9.14 KB
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# Podman/Docker build configuration — uses prebuilt GHCR image
CONTAINER_IMAGE := ghcr.io/themactep/thingino-builder-image
CONTAINER_TAG := latest
SHELL := /bin/bash
CONTAINER_ENGINE ?= $(shell command -v podman 2>/dev/null || command -v docker 2>/dev/null)
USER_ID := $(shell id -u)
GROUP_ID := $(shell id -g)
DL_DIR := dl
DL_IMAGE := ghcr.io/themactep/thingino-dl
DL_CONTAINER := thingino-dl-cache
# Directories
WORKSPACE_DIR := $(shell pwd)
# SELinux volume labels (Podman/Docker on Fedora, Bazzite, RHEL, CentOS Stream).
# Without a label, Enforcing hosts often fail with "Permission denied" on bind mounts.
# Non-SELinux hosts (Debian/Ubuntu/etc.) leave this empty — :z/:Z are unnecessary there.
#
# Preference order:
# 1. CONTAINER_VOLUME_LABEL override (z | Z | none | off | empty)
# 2. Auto :z when getenforce reports Enforcing
# 3. Otherwise unlabeled
#
# Use shared :z (not private :Z) by default so the host IDE and container can both
# use the workspace. Override with CONTAINER_VOLUME_LABEL=Z only if you need a
# private container label.
CONTAINER_VOLUME_LABEL ?=
ifeq ($(CONTAINER_VOLUME_LABEL),)
ifeq ($(shell getenforce 2>/dev/null),Enforcing)
CONTAINER_VOLUME_LABEL := z
endif
endif
ifneq ($(filter $(CONTAINER_VOLUME_LABEL),none off),)
CONTAINER_VOLUME_SUFFIX :=
CONTAINER_VOLUME_LABEL_DESC := none (forced off)
else ifneq ($(CONTAINER_VOLUME_LABEL),)
CONTAINER_VOLUME_SUFFIX := :$(CONTAINER_VOLUME_LABEL)
CONTAINER_VOLUME_LABEL_DESC := $(CONTAINER_VOLUME_LABEL)
else
CONTAINER_VOLUME_SUFFIX :=
CONTAINER_VOLUME_LABEL_DESC := none (SELinux not enforcing or unavailable)
endif
# Container run command
ifeq ($(findstring podman,$(CONTAINER_ENGINE)),podman)
CONTAINER_RUN := $(CONTAINER_ENGINE) run --rm --userns=keep-id
else
CONTAINER_RUN := $(CONTAINER_ENGINE) run --rm --user $(USER_ID):$(GROUP_ID) --network=host
endif
CONTAINER_RUN_OPTS := \
--volumes-from $(DL_CONTAINER) \
-v $(WORKSPACE_DIR):/workspace$(CONTAINER_VOLUME_SUFFIX) \
-v $(shell readlink -f overrides):/overrides$(CONTAINER_VOLUME_SUFFIX) \
-w /workspace \
-e TERM=xterm-256color \
-e BR2_DL_DIR=/dl
# Mount external THINGINO_USER_DIR into container if set outside workspace.
# Default (user/ inside workspace) is already visible via the workspace mount.
USER_DIR_MOUNT :=
USER_DIR_LABEL := (default: workspace/user/)
ifdef THINGINO_USER_DIR
ifeq ($(THINGINO_USER_DIR),/dev/null)
USER_DIR_MOUNT := -e THINGINO_USER_DIR=/dev/null
USER_DIR_LABEL := /dev/null (PRISTINE)
else
_USER_DIR_REAL := $(shell readlink -f "$(THINGINO_USER_DIR)" 2>/dev/null || echo "$(THINGINO_USER_DIR)")
_USER_DIR_IN_WS := $(or $(filter $(WORKSPACE_DIR),$(_USER_DIR_REAL)),$(filter $(WORKSPACE_DIR)/%,$(_USER_DIR_REAL)))
ifeq ($(_USER_DIR_IN_WS),)
USER_DIR_MOUNT := -v $(_USER_DIR_REAL):/user-dir$(CONTAINER_VOLUME_SUFFIX) -e THINGINO_USER_DIR=/user-dir
USER_DIR_LABEL := $(THINGINO_USER_DIR) → /user-dir (mounted)
else
USER_DIR_LABEL := $(THINGINO_USER_DIR) (in workspace)
endif
endif
endif
# Workaround: prebuilt image ships uutils install which breaks Buildroot dep check.
# Switch to GNU install on every container invocation.
CONTAINER_PREBUILD := sudo update-alternatives --install /usr/bin/install install /usr/bin/gnuinstall 100 2>/dev/null && true &&
# Interactive container
CONTAINER_RUN_INTERACTIVE := $(CONTAINER_RUN) -it $(CONTAINER_RUN_OPTS) $(USER_DIR_MOUNT)
# Non-interactive container (with -i to receive signals, but no -t for non-TTY)
CONTAINER_RUN_EXEC := $(CONTAINER_RUN) -i $(CONTAINER_RUN_OPTS) $(USER_DIR_MOUNT)
.PHONY: container-pull
container-pull: dl-container
@if ! $(CONTAINER_ENGINE) images | grep -q "$(CONTAINER_IMAGE)"; then \
echo "Pulling container image: $(CONTAINER_IMAGE):$(CONTAINER_TAG)"; \
$(CONTAINER_ENGINE) pull $(CONTAINER_IMAGE):$(CONTAINER_TAG); \
else \
echo "Container image $(CONTAINER_IMAGE):$(CONTAINER_TAG) already present"; \
fi
.PHONY: dl-pull
dl-pull:
$(CONTAINER_ENGINE) pull $(DL_IMAGE):latest || \
echo "Warning: Could not pull dl cache image. Downloads will be needed."
.PHONY: dl-container
dl-container: dl-pull
@if ! $(CONTAINER_ENGINE) ps -a --format '{{.Names}}' | grep -q '^$(DL_CONTAINER)$$'; then \
echo "Creating dl cache helper container..."; \
$(CONTAINER_ENGINE) create --name $(DL_CONTAINER) $(DL_IMAGE):latest /bin/true; \
$(CONTAINER_ENGINE) create --name $(DL_CONTAINER)-src $(DL_IMAGE):latest /bin/true; \
$(CONTAINER_ENGINE) export $(DL_CONTAINER)-src | tar -x --strip-components=1 --directory=$$($(CONTAINER_ENGINE) inspect $(DL_CONTAINER) --format '{{range .Mounts}}{{if eq .Destination "/dl"}}{{.Source}}{{end}}{{end}}') dl/; \
$(CONTAINER_ENGINE) rm $(DL_CONTAINER)-src >/dev/null; \
echo "dl cache volume populated"; \
else \
echo "dl cache helper container already exists"; \
fi
.PHONY: dl-clean
dl-clean:
$(CONTAINER_ENGINE) rm -f $(DL_CONTAINER) || true
.PHONY: container-shell
container-shell: container-pull
@echo "Starting interactive shell in container..."
$(CONTAINER_RUN_INTERACTIVE) $(CONTAINER_IMAGE):$(CONTAINER_TAG) bash -c "$(CONTAINER_PREBUILD) exec /bin/bash"
.PHONY: container-make
container-make: container-pull
$(eval CAMERA_ARG := $(if $(CAMERA),CAMERA=$(CAMERA)))
$(eval GROUP_ARG := $(if $(GROUP),GROUP=$(GROUP)))
$(eval IP_ARG := $(if $(IP),IP=$(IP)))
@echo "Running make $(CAMERA_ARG) $(GROUP_ARG) $(IP_ARG) $(MAKECMDGOALS) in container..."
@echo '#!/bin/bash' > /tmp/container-make-run.sh
@echo 'cleanup() {' >> /tmp/container-make-run.sh
@echo ' echo' >> /tmp/container-make-run.sh
@echo ' echo "Interrupted! Stopping container..."' >> /tmp/container-make-run.sh
@echo ' $(CONTAINER_ENGINE) stop -t 2 $$($(CONTAINER_ENGINE) ps -q --filter ancestor=$(CONTAINER_IMAGE):$(CONTAINER_TAG)) 2>/dev/null || true' >> /tmp/container-make-run.sh
@echo ' exit 130' >> /tmp/container-make-run.sh
@echo '}' >> /tmp/container-make-run.sh
@echo 'trap cleanup INT TERM' >> /tmp/container-make-run.sh
@echo '$(CONTAINER_RUN_EXEC) $(CONTAINER_IMAGE):$(CONTAINER_TAG) bash -c "$(CONTAINER_PREBUILD) make $(CAMERA_ARG) $(GROUP_ARG) $(IP_ARG) $(MAKECMDGOALS)" &' >> /tmp/container-make-run.sh
@echo 'wait $$!' >> /tmp/container-make-run.sh
@chmod +x /tmp/container-make-run.sh
@/tmp/container-make-run.sh
.PHONY: container-clean
container-clean:
@echo "Removing container image..."
@echo "Stopping and removing containers using $(CONTAINER_IMAGE):$(CONTAINER_TAG)..."
@$(CONTAINER_ENGINE) ps -a --filter ancestor=$(CONTAINER_IMAGE):$(CONTAINER_TAG) -q | xargs -r $(CONTAINER_ENGINE) rm -f 2>/dev/null || true
$(CONTAINER_ENGINE) rmi $(CONTAINER_IMAGE):$(CONTAINER_TAG) || true
.PHONY: container-nuke
container-nuke: container-clean
@echo "Removing dl cache container and volume..."
@$(CONTAINER_ENGINE) ps -a --filter reference=$(DL_IMAGE) -q | xargs -r $(CONTAINER_ENGINE) rm -f 2>/dev/null || true
$(CONTAINER_ENGINE) rm -f $(DL_CONTAINER) 2>/dev/null || true
$(CONTAINER_ENGINE) rmi $(DL_IMAGE):latest 2>/dev/null || true
@echo "Pruning unused volumes..."
$(CONTAINER_ENGINE) volume prune -f 2>/dev/null || true
@echo "Pruning unused images..."
$(CONTAINER_ENGINE) image prune -f 2>/dev/null || true
@echo "All container artifacts removed."
.PHONY: container-info
container-info:
@echo "Container Configuration:"
@echo " Engine: $(CONTAINER_ENGINE)"
@echo " Image: $(CONTAINER_IMAGE):$(CONTAINER_TAG)"
@echo " DL Image: $(DL_IMAGE):latest"
@echo " DL Cache: $(DL_CONTAINER)"
@echo " DL Source: container volume"
@echo " User ID: $(USER_ID)"
@echo " Group ID: $(GROUP_ID)"
@echo " Workspace: $(WORKSPACE_DIR)"
@echo " Downloads: $(DL_DIR)"
@echo " User Dir: $(USER_DIR_LABEL)"
@echo " SELinux: $(CONTAINER_VOLUME_LABEL_DESC)"
# Convenience targets for building in container
.PHONY: container-build-firmware
container-build-firmware: container-pull
$(CONTAINER_RUN_EXEC) $(CONTAINER_IMAGE):$(CONTAINER_TAG) bash -c "$(CONTAINER_PREBUILD) make"
.PHONY: container-dev
container-dev: container-pull
$(CONTAINER_RUN_EXEC) $(CONTAINER_IMAGE):$(CONTAINER_TAG) bash -c "$(CONTAINER_PREBUILD) make dev"
.PHONY: container-menuconfig
container-menuconfig: container-pull
$(CONTAINER_RUN_INTERACTIVE) $(CONTAINER_IMAGE):$(CONTAINER_TAG) bash -c "$(CONTAINER_PREBUILD) make menuconfig"
.PHONY: container-linux-menuconfig
container-linux-menuconfig: container-pull
$(CONTAINER_RUN_INTERACTIVE) $(CONTAINER_IMAGE):$(CONTAINER_TAG) bash -c "$(CONTAINER_PREBUILD) make linux-menuconfig"
.PHONY: container-busybox-menuconfig
container-busybox-menuconfig: container-pull
$(CONTAINER_RUN_INTERACTIVE) $(CONTAINER_IMAGE):$(CONTAINER_TAG) bash -c "$(CONTAINER_PREBUILD) make busybox-menuconfig"
.PHONY: container-clean-build
container-clean-build: container-pull
$(CONTAINER_RUN_EXEC) $(CONTAINER_IMAGE):$(CONTAINER_TAG) bash -c "$(CONTAINER_PREBUILD) make distclean && make"
.PHONY: container-ota
container-ota: container-pull
$(eval IP_ARG := $(if $(IP),IP=$(IP)))
$(eval CAMERA_ARG := $(if $(CAMERA),CAMERA=$(CAMERA)))
$(eval GROUP_ARG := $(if $(GROUP),GROUP=$(GROUP)))
$(CONTAINER_RUN_INTERACTIVE) $(CONTAINER_IMAGE):$(CONTAINER_TAG) bash -c "$(CONTAINER_PREBUILD) make ota $(IP_ARG) $(CAMERA_ARG) $(GROUP_ARG)"
# Allow make targets to be passed through to container
%:
@: