forked from python/cpython
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathMakefile.nanvix
More file actions
298 lines (277 loc) · 11.7 KB
/
Copy pathMakefile.nanvix
File metadata and controls
298 lines (277 loc) · 11.7 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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# Makefile.nanvix - CPython cross-compilation for Nanvix
#
# Copyright(c) The Maintainers of Nanvix.
# Licensed under the MIT License.
#
# Usage:
# make -f Makefile.nanvix CONFIG_NANVIX=y NANVIX_HOME=/path/to/nanvix all
#
# Thin cross-compilation wrapper: configure, build, install, clean.
# All other concerns (tests, ramfs, packaging) are handled by the Python
# modules in .nanvix/ and invoked via ./z.
#
# Dependencies:
# - zlib (libz.a in NANVIX_HOME/lib)
# - SQLite (libsqlite3.a in NANVIX_HOME/lib)
# - OpenSSL (libssl.a, libcrypto.a in NANVIX_HOME/lib)
# - bzip2 (libbz2.a in NANVIX_HOME/lib)
# - libffi (libffi.a in NANVIX_HOME/lib)
# - liblzma (liblzma.a in NANVIX_HOME/lib)
# Nanvix Docker image for cross-compilation
NANVIX_DOCKER_IMAGE ?= ghcr.io/nanvix/toolchain-python:latest
# Platform and deployment configuration
PLATFORM ?= microvm
PROCESS_MODE ?= standalone
MEMORY_SIZE ?= 256mb
# Install prefix baked into the python binary (sys.prefix, sys.path)
INSTALL_PREFIX ?= /sysroot
# Set to 'yes' for release packaging
NANVIX_RELEASE ?= no
# Nanvix cross-compilation configuration
ifdef CONFIG_NANVIX
NANVIX_TOOLCHAIN ?= /opt/nanvix
NANVIX_HOME ?= $(HOME)/nanvix
# Check if Docker is explicitly requested or native toolchain is not available
ifndef CONFIG_NANVIX_DOCKER
ifeq ($(wildcard $(NANVIX_TOOLCHAIN)/bin/i686-nanvix-gcc),)
# Native toolchain not found, check for Docker
DOCKER_AVAILABLE := $(shell command -v docker 2>/dev/null)
ifdef DOCKER_AVAILABLE
DOCKER_IMAGE_EXISTS := $(shell docker image inspect $(NANVIX_DOCKER_IMAGE) >/dev/null 2>&1 && echo yes)
ifdef DOCKER_IMAGE_EXISTS
CONFIG_NANVIX_DOCKER := y
$(info [INFO] Native toolchain not found at $(NANVIX_TOOLCHAIN), using Docker image $(NANVIX_DOCKER_IMAGE))
else
$(error Docker image $(NANVIX_DOCKER_IMAGE) not found. Run: docker pull $(NANVIX_DOCKER_IMAGE))
endif
else
$(error Nanvix toolchain not found at $(NANVIX_TOOLCHAIN) and Docker is not available)
endif
endif
else
# Docker explicitly requested via CONFIG_NANVIX_DOCKER=y
DOCKER_AVAILABLE := $(shell command -v docker 2>/dev/null)
ifndef DOCKER_AVAILABLE
$(error CONFIG_NANVIX_DOCKER=y but Docker is not installed)
endif
DOCKER_IMAGE_EXISTS := $(shell docker image inspect $(NANVIX_DOCKER_IMAGE) >/dev/null 2>&1 && echo yes)
ifndef DOCKER_IMAGE_EXISTS
$(error Docker image $(NANVIX_DOCKER_IMAGE) not found. Run: docker pull $(NANVIX_DOCKER_IMAGE))
endif
$(info [INFO] Using Docker image $(NANVIX_DOCKER_IMAGE) (explicitly requested))
endif
EXE=.elf
ifdef CONFIG_NANVIX_DOCKER
DOCKER_TOOLCHAIN_PATH := /opt/nanvix
DOCKER_SYSROOT_PATH := /mnt/sysroot
DOCKER_WORKSPACE_PATH := /mnt/workspace
DOCKER_UID := $(shell id -u)
DOCKER_GID := $(shell id -g)
DOCKER_RUN := docker run --rm --user $(DOCKER_UID):$(DOCKER_GID) \
-v $(CURDIR):$(DOCKER_WORKSPACE_PATH) \
-v $(abspath $(NANVIX_HOME)):$(DOCKER_SYSROOT_PATH):ro \
-w $(DOCKER_WORKSPACE_PATH) \
-e HOME=/tmp \
$(NANVIX_DOCKER_IMAGE)
TOOLCHAIN_PREFIX := $(DOCKER_TOOLCHAIN_PATH)
SYSROOT_PATH := $(DOCKER_SYSROOT_PATH)
LIBC := $(DOCKER_TOOLCHAIN_PATH)/i686-nanvix/lib/libc.a
LIBM := $(DOCKER_TOOLCHAIN_PATH)/i686-nanvix/lib/libm.a
LIBPOSIX := $(DOCKER_SYSROOT_PATH)/lib/libposix.a
LIBZ := $(DOCKER_SYSROOT_PATH)/lib/libz.a
LIBSQLITE3 := $(DOCKER_SYSROOT_PATH)/lib/libsqlite3.a
LIBSSL := $(DOCKER_SYSROOT_PATH)/lib/libssl.a
LIBCRYPTO := $(DOCKER_SYSROOT_PATH)/lib/libcrypto.a
BUILD_PYTHON := $(DOCKER_TOOLCHAIN_PATH)/bin/python3
else
TOOLCHAIN_PREFIX := $(NANVIX_TOOLCHAIN)
SYSROOT_PATH := $(abspath $(NANVIX_HOME))
LIBC := $(NANVIX_TOOLCHAIN)/i686-nanvix/lib/libc.a
LIBM := $(NANVIX_TOOLCHAIN)/i686-nanvix/lib/libm.a
LIBPOSIX := $(abspath $(NANVIX_HOME))/lib/libposix.a
LIBZ := $(abspath $(NANVIX_HOME))/lib/libz.a
LIBSQLITE3 := $(abspath $(NANVIX_HOME))/lib/libsqlite3.a
LIBSSL := $(abspath $(NANVIX_HOME))/lib/libssl.a
LIBCRYPTO := $(abspath $(NANVIX_HOME))/lib/libcrypto.a
BUILD_PYTHON := $(NANVIX_TOOLCHAIN)/bin/python3
endif
# libstdc++ / libgcc are referenced via `-l` rather than absolute paths so
# the GCC driver resolves them: libgcc lives under a versioned dir
# (`lib/gcc/i686-nanvix/<gcc-version>/libgcc.a`) and hardcoding a version
# would be fragile across toolchain upgrades. Defined once at top-level
# because the `-l` form is identical between the docker and host build
# paths above.
LIBSTDCXX := -lstdc++
LIBGCC := -lgcc
else
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(MAKECMDGOALS),distclean)
$(error CONFIG_NANVIX must be set to 'y'. Usage: make -f Makefile.nanvix CONFIG_NANVIX=y NANVIX_HOME=/path/to/nanvix)
endif
endif
EXE=.elf
endif
# Configure environment variables
#
# Linker flag rationale:
#
# `-Wl,--export-dynamic`: put every globally-defined symbol from python.elf
# into its `.dynsym`. Extension `.so`s (numpy's `_multiarray_umath.so`, ssl,
# etc.) leave C/C++ runtime symbols UND and resolve them against python.elf
# at dlopen() time. Without this, those `.so`s fail to load.
#
# `-Wl,--allow-multiple-definition`: tolerates duplicate symbol definitions
# that arise from forcing every libposix / libc / libm / libstdc++ / libgcc
# object into python.elf via `--whole-archive` below. The biggest set is
# newlib's long-double math helpers (`frexpl`, `llrintl`, `lrintl`, `rintl`
# are defined in three different newlib directories simultaneously — a
# newlib build-system bug). Other known overlaps include libposix vs. libc
# (`_start`, `copysign[f]`, `getenv`, `setenv`, `unsetenv`, `environ`,
# `isatty`), libc vs. libm (`frexp`, `ldexp`, `modf`, `isnan`, `isinf`,
# `scalbn`, …), libm vs. libstdc++ (`hypotf`), libgcc internal duplicates
# (`__x86.get_pc_thunk.*`), and a libc / libgcc `__eprintf`. The set is
# large and toolchain-build-version-dependent; treating the link as
# multiple-definition-tolerant is the only practical workaround until each
# upstream is fixed. Remove this flag once the contributing duplicates are
# resolved upstream.
#
# `LIBS` segment 1 (`--whole-archive ... --no-whole-archive`): force every
# object from libposix, libc, libm, libstdc++, and libgcc into python.elf
# so the runtime symbols extension `.so`s depend on are embedded and
# re-exported via `--export-dynamic`. Without `--whole-archive`, the static
# linker drops unreferenced objects (e.g. `fscanf`, `longjmp`, `strtold_l`
# for numpy; `operator new/delete[]`, `__cxa_*`, `_Unwind_*`,
# `std::type_info` vtables for any C++ extension) and subsequent dlopen()
# of those `.so`s fails with "symbol not found".
#
# `LIBS` segment 2 (`--start-group ... --end-group`): the external add-on
# libraries (sqlite3, ssl, crypto, z, bz2, lzma, ffi). The group is needed
# only for their inter-archive circular dependencies; they resolve symbols
# from libposix/libc/libm/libstdc++ against the already-embedded objects
# from segment 1.
CONFIGURE_ENV = \
CC="$(TOOLCHAIN_PREFIX)/bin/i686-nanvix-gcc" \
CXX="$(TOOLCHAIN_PREFIX)/bin/i686-nanvix-g++" \
LD="$(TOOLCHAIN_PREFIX)/bin/i686-nanvix-ld" \
AR="$(TOOLCHAIN_PREFIX)/bin/i686-nanvix-ar" \
RANLIB="$(TOOLCHAIN_PREFIX)/bin/i686-nanvix-ranlib" \
CFLAGS="-O3 -fomit-frame-pointer -fno-unwind-tables -fno-asynchronous-unwind-tables -I$(SYSROOT_PATH)/include" \
CFLAGS_NODIST="-fno-semantic-interposition" \
LDFLAGS="-L$(SYSROOT_PATH)/lib -T$(SYSROOT_PATH)/lib/user.ld -Wl,--allow-multiple-definition -no-pie -Wl,--export-dynamic -Wl,--no-dynamic-linker" \
LIBS="-Wl,--whole-archive $(LIBPOSIX) $(LIBC) $(LIBM) $(LIBSTDCXX) $(LIBGCC) -Wl,--no-whole-archive -Wl,--start-group -lsqlite3 -lssl -lcrypto -lz -lbz2 -llzma -lffi -Wl,--end-group" \
LIBSQLITE3_LIBS="-L$(SYSROOT_PATH)/lib -lsqlite3" \
LIBSQLITE3_CFLAGS="-I$(SYSROOT_PATH)/include" \
ZLIB_LIBS="-L$(SYSROOT_PATH)/lib -lz" \
ZLIB_CFLAGS="-I$(SYSROOT_PATH)/include" \
BZIP2_LIBS="-L$(SYSROOT_PATH)/lib -lbz2" \
BZIP2_CFLAGS="-I$(SYSROOT_PATH)/include" \
LIBLZMA_LIBS="-L$(SYSROOT_PATH)/lib -llzma" \
LIBLZMA_CFLAGS="-I$(SYSROOT_PATH)/include" \
LIBFFI_LIBS="-L$(SYSROOT_PATH)/lib -lffi" \
LIBFFI_CFLAGS="-I$(SYSROOT_PATH)/include"
# Configure options for Nanvix
CONFIGURE_OPTS = \
--disable-shared \
--build=x86_64-pc-linux-gnux32 \
--host=i686-nanvix \
--with-build-python="$(BUILD_PYTHON)" \
$(if $(filter yes,$(NANVIX_RELEASE)),--disable-test-modules,) \
--with-libc="$(LIBC)" \
--with-libm="$(LIBM)" \
--prefix="$(INSTALL_PREFIX)" \
--exec-prefix="$(INSTALL_PREFIX)" \
--with-ensurepip=no \
--with-pkg-config=no \
--with-openssl="$(SYSROOT_PATH)" \
--disable-ipv6 \
$(if $(filter yes,$(NANVIX_RELEASE)),--without-doc-strings,) \
--with-computed-gotos \
ac_cv_file__dev_ptmx=no \
ac_cv_file__dev_ptc=no \
ac_cv_pthread_is_default=yes \
ac_cv_pthread=yes \
ac_cv_kthread=no \
ac_cv_func_dlopen=yes \
ac_cv_header_dlfcn_h=yes \
ac_cv_header_sys_socket_h=yes \
ac_cv_header_netinet_in_h=yes \
ac_cv_header_arpa_inet_h=yes \
ac_cv_header_netdb_h=yes \
ac_cv_func_socket=yes \
ac_cv_func_bind=yes \
ac_cv_func_listen=yes \
ac_cv_func_accept=yes \
ac_cv_func_connect=yes \
ac_cv_func_sendto=yes \
ac_cv_func_recvfrom=yes \
ac_cv_func_setsockopt=yes \
ac_cv_func_getpeername=yes \
ac_cv_func_getsockname=yes \
ac_cv_func_inet_aton=no \
ac_cv_func_inet_ntoa=yes \
ac_cv_func_inet_pton=no
# Marker file to track if configure has been run
CONFIGURED_MARKER = .nanvix-configured
# Default target
all: build
# Configure target
configure: $(CONFIGURED_MARKER)
$(CONFIGURED_MARKER):
ifdef CONFIG_NANVIX_DOCKER
@echo "Running configure inside Docker..."
$(DOCKER_RUN) sh -c '$(CONFIGURE_ENV) ./configure $(CONFIGURE_OPTS)'
else
$(CONFIGURE_ENV) ./configure $(CONFIGURE_OPTS)
endif
touch $(CONFIGURED_MARKER)
# Build target
build: $(CONFIGURED_MARKER)
ifdef CONFIG_NANVIX_DOCKER
@echo "Building inside Docker..."
$(DOCKER_RUN) $(MAKE) -j$$(nproc) all
@if [ -f python ]; then cp -f python python$(EXE); fi
$(DOCKER_RUN) sh -c '\
if [ ! -x "$(DOCKER_TOOLCHAIN_PATH)/bin/i686-nanvix-strip" ]; then \
echo "Warning: i686-nanvix-strip not found in Docker toolchain; skipping strip."; \
elif [ ! -f "$(DOCKER_WORKSPACE_PATH)/python$(EXE)" ]; then \
echo "Warning: $(DOCKER_WORKSPACE_PATH)/python$(EXE) not found; skipping strip."; \
else \
"$(DOCKER_TOOLCHAIN_PATH)/bin/i686-nanvix-strip" --strip-all "$(DOCKER_WORKSPACE_PATH)/python$(EXE)" || { \
echo "Error: failed to strip python$(EXE) inside Docker."; exit 1; }; \
fi'
else
$(MAKE) -j$$(nproc) all
@if [ -f python ]; then cp -f python python$(EXE); fi
@if [ -x "$(TOOLCHAIN_PREFIX)/bin/i686-nanvix-strip" ]; then \
if [ -f "python$(EXE)" ]; then \
"$(TOOLCHAIN_PREFIX)/bin/i686-nanvix-strip" --strip-all "python$(EXE)" || { \
echo "Error: failed to strip python$(EXE)."; exit 1; }; \
else \
echo "Warning: python$(EXE) not found; skipping strip."; \
fi; \
else \
echo "Warning: i686-nanvix-strip not found in $(TOOLCHAIN_PREFIX); skipping strip."; \
fi
endif
# Install target
install: build
ifdef CONFIG_NANVIX_DOCKER
$(DOCKER_RUN) $(MAKE) install DESTDIR="$(patsubst $(CURDIR)%,$(DOCKER_WORKSPACE_PATH)%,$(abspath $(DESTDIR)))"
else
$(MAKE) install DESTDIR="$(DESTDIR)"
endif
# Clean target
clean:
-$(MAKE) clean 2>/dev/null || true
rm -f $(CONFIGURED_MARKER)
rm -f python$(EXE)
# Distclean target
distclean: clean
-$(MAKE) distclean 2>/dev/null || true
git clean -fdx -e Makefile.nanvix -e NANVIX.md -e .github \
-e .nanvix/z.py -e .nanvix/_loader.py -e .nanvix/nanvix.toml -e .nanvix/.gitignore \
-e .nanvix/config.py -e .nanvix/build.py -e .nanvix/docker.py \
-e .nanvix/ramfs.py -e .nanvix/test.py -e .nanvix/package.py \
-e .nanvix/run-regrtest.py -e .nanvix/run-tests.py \
-e z -e z.sh -e z.ps1 2>/dev/null || true
.PHONY: all configure build install clean distclean