-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathCommon.mk
450 lines (386 loc) · 18.7 KB
/
Common.mk
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
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
# Licensed under the Apache License, Version 2.0 or the MIT License.
# SPDX-License-Identifier: Apache-2.0 OR MIT
# Copyright Tock Contributors 2022.
# Force the Shell to be bash as some systems have strange default shells
SHELL := bash
# Remove built-in rules and variables
# n.b. no-op for make --version < 4.0
MAKEFLAGS += -r
MAKEFLAGS += -R
# The absolute path of the directory containing this `Makefile.common` file.
MAKEFILE_COMMON_PATH := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
# The absolute path of Tock's root directory.
# This is currently the parent directory of MAKEFILE_COMMON_PATH.
TOCK_ROOT_DIRECTORY := $(dir $(abspath $(MAKEFILE_COMMON_PATH)))
# The path to the root of the rust installation used for this build.
# Useful for remapping paths and for finding already-installed llvm tools.
RUSTC_SYSROOT := "$(shell rustc --print sysroot)"
# Common defaults that specific boards can override, but likely do not need to.
#
# The TOOLCHAIN parameter is set to the magic value "llvm-tools", which will
# cause the Makefile to resolve the llvm toolchain installed as part of the
# rustup component "llvm-tools". In case a system toolchain shall be used, this
# can be overridden to specify the toolchain prefix, e.g. "llvm" for
# llvm-{objdump,objcopy,...} or "arm-none-eabi".
TOOLCHAIN ?= llvm-tools
CARGO ?= cargo
# Not all platforms support the rustup tool. Those that do not can pass
# `NO_RUSTUP=1` to make and then all of the rustup commands will be ignored.
ifeq ($(NO_RUSTUP),)
RUSTUP ?= rustup
else
RUSTUP ?= true
endif
# Default location of target directory (relative to board makefile) passed to
# cargo `--target_dir`.
TARGET_DIRECTORY ?= $(TOCK_ROOT_DIRECTORY)target/
# RUSTC_FLAGS allows boards to define board-specific options.
# This will hopefully move into Cargo.toml (or Cargo.toml.local) eventually.
#
# - `-Tlayout.ld`: Use the linker script `layout.ld` all boards must provide.
# - `linker=rust-lld`: Tell rustc to use the LLVM linker. This avoids needing
# GCC as a dependency to build the kernel.
# - `linker-flavor=ld.lld`: Use the LLVM lld executable with the `-flavor gnu`
# flag.
# - `relocation-model=static`: See https://github.com/tock/tock/pull/2853
# - `-nmagic`: lld by default uses a default page size to align program
# sections. Tock expects that program sections are set back-to-back. `-nmagic`
# instructs the linker to not page-align sections.
# - `-icf=all`: Identical Code Folding (ICF) set to all. This tells the linker
# to be more aggressive about removing duplicate code. The default is `safe`,
# and the downside to `all` is that different functions in the code can end up
# with the same address in the binary. However, it can save a fair bit of code
# size.
# - `-C symbol-mangling-version=v0`: Opt-in to Rust v0 symbol mangling scheme.
# See https://github.com/rust-lang/rust/issues/60705 and
# https://github.com/tock/tock/issues/3529.
RUSTC_FLAGS ?= \
-C link-arg=-Tlayout.ld \
-C linker=rust-lld \
-C linker-flavor=ld.lld \
-C relocation-model=static \
-C link-arg=-nmagic \
-C link-arg=-icf=all \
-C symbol-mangling-version=v0 \
# RISC-V-specific flags.
ifneq ($(findstring riscv32i, $(TARGET)),)
# NOTE: This flag causes kernel panics on some ARM cores. Since the size
# benefit is almost exclusively for RISC-V, we only apply it for those
# targets.
RUSTC_FLAGS += -C force-frame-pointers=no
# Ensure relocations generated is eligible for linker relaxation.
# This provide huge space savings.
RUSTC_FLAGS += -C target-feature=+relax
endif
# RUSTC_FLAGS_TOCK by default extends RUSTC_FLAGS with options that are global
# to all Tock boards.
#
# We use `remap-path-prefix` to remove user-specific filepath strings for error
# reporting from appearing in the generated binary. The first line is used for
# remapping the tock directory, and the second line is for remapping paths to
# the source code of the core library, which end up in the binary as a result of
# our use of `-Zbuild-std=core`.
RUSTC_FLAGS_TOCK ?= \
$(RUSTC_FLAGS) \
--remap-path-prefix=$(TOCK_ROOT_DIRECTORY)= \
--remap-path-prefix=$(RUSTC_SYSROOT)/lib/rustlib/src/rust/library/core=/core/
# Disallow warnings only for continuous integration builds. Disallowing them
# here using the `RUSTC_FLAGS_TOCK` variable ensures that warnings during
# testing won't prevent compilation from succeeding.
ifeq ($(NOWARNINGS),true)
RUSTC_FLAGS_TOCK += -D warnings
endif
# The following flags should only be passed to the board's binary crate, but
# not to any of its dependencies (the kernel, capsules, chips, etc.). The
# dependencies wouldn't use it, but because the link path is different for each
# board, Cargo wouldn't be able to cache builds of the dependencies.
#
# Indeed, as far as Cargo is concerned, building the kernel with
# `-C link-arg=-L/tock/boards/imix` is different than building the kernel with
# `-C link-arg=-L/tock/boards/hail`, so Cargo would have to rebuild the kernel
# for each board instead of caching it per board (even if in reality the same
# kernel is built because the link-arg isn't used by the kernel).
#
# Ultimately, this should move to the Cargo.toml, for example when
# https://github.com/rust-lang/cargo/pull/7811 is merged into Cargo.
#
# The difference between `RUSTC_FLAGS_TOCK` and `RUSTC_FLAGS_FOR_BIN` is that
# the former is forwarded to all the dependencies (being passed to cargo via
# the `RUSTFLAGS` environment variable), whereas the latter is only applied to
# the final binary crate (being passed as parameter to `cargo rustc`).
RUSTC_FLAGS_FOR_BIN ?= \
-C link-arg=-L$(abspath .) \
# http://stackoverflow.com/questions/10858261/abort-makefile-if-variable-not-set
# Check that given variables are set and all have non-empty values, print an
# error otherwise.
check_defined = $(strip $(foreach 1,$1,$(if $(value $1),,$(error Undefined variable "$1"))))
# Check that we know the basics of what we are compiling for.
# - `PLATFORM`: The name of the board that the kernel is being compiled for.
# - `TARGET` : The Rust target architecture the kernel is being compiled for.
$(call check_defined, PLATFORM)
$(call check_defined, TARGET)
# Location of target-specific build.
TARGET_PATH := $(TARGET_DIRECTORY)$(TARGET)
# If environment variable V or VERBOSE is non-empty, be verbose.
ifneq ($(V),)
VERBOSE_MODE = 1
else ifneq ($(VERBOSE),)
VERBOSE_MODE = 1
else
VERBOSE_MODE =
endif
ifeq ($(VERBOSE_MODE),1)
Q =
VERBOSE_FLAGS = --verbose
DEVNULL =
else
Q = @
VERBOSE_FLAGS =
DEVNULL = > /dev/null
endif
# Ask git what version of the Tock kernel we are compiling, so we can include
# this within the binary. If Tock is not within a git repo then we fallback to
# a set string which should be updated with every release.
export TOCK_KERNEL_VERSION := $(shell git describe --tags --always 2> /dev/null || echo "2.1+")
# Allow users to opt out of using rustup.
ifeq ($(NO_RUSTUP),)
# Validate that rustup exists.
RUSTUP_ERROR := $(shell $(RUSTUP) --version > /dev/null 2>&1; echo $$?)
ifneq ($(RUSTUP_ERROR),0)
$(info Error! rustup not found.)
$(info Please follow the instructions at https://rustup.rs/ to install rustup.)
$(info Alternatively, install all required tools and Rust targets and set NO_RUSTUP=1 to disable this check.)
$(info )
$(error Rustup required to build Tock.)
endif
# Validate that rustup is new enough.
MINIMUM_RUSTUP_VERSION := 1.23.0
RUSTUP_VERSION := $(strip $(word 2, $(shell $(RUSTUP) --version 2> /dev/null)))
ifeq ($(shell $(TOCK_ROOT_DIRECTORY)tools/semver.sh $(RUSTUP_VERSION) \< $(MINIMUM_RUSTUP_VERSION)), true)
$(warning Required tool `$(RUSTUP)` is out-of-date.)
$(warning Running `$(RUSTUP) update` in 3 seconds (ctrl-c to cancel))
$(shell sleep 3s)
DUMMY := $(shell $(RUSTUP) update)
endif
# Verify that various required Rust components are installed. All of these steps
# only have to be done once per Rust version, but will take some time when
# compiling for the first time.
ifneq ($(shell $(RUSTUP) target list | grep "$(TARGET) (installed)"),$(TARGET) (installed))
$(warning Request to compile for a missing TARGET, make will install in 5s)
$(warning Consider updating 'targets' in 'rust-toolchain.toml')
$(shell sleep 5s && $(RUSTUP) target add $(TARGET))
endif
# check llvm_tools component
LLVM_TOOLS_INSTALLED := $(shell rustup component list --installed | grep llvm-tools 1>/dev/null 2>&1 && echo "true" || echo "no")
ifeq ($(LLVM_TOOLS_INSTALLED), true)
$(info llvm-tools component seems to be installed, continue...)
TOOLCHAIN := llvm-tools
else
$(warning Install llvm-tools component: rustup component add llvm-tools , and try again.)
TOOLCHAIN := N/A
endif
endif # $(NO_RUSTUP)
# If the user is using the standard toolchain provided as part of the llvm-tools
# rustup component we need to get the full path. rustup should take care of this
# for us by putting in a proxy in .cargo/bin, but until that is setup we
# workaround it.
ifeq ($(TOOLCHAIN),llvm-tools)
TOOLCHAIN = "$(shell dirname $(shell find $(RUSTC_SYSROOT) -name llvm-size))/llvm"
endif
# Set variables of the key tools we need to compile a Tock kernel. Need to do
# this after we handle if we are using the LLVM tools or not.
SIZE ?= $(TOOLCHAIN)-size
OBJCOPY ?= $(TOOLCHAIN)-objcopy
OBJDUMP ?= $(TOOLCHAIN)-objdump
# Set additional flags to produce binary from .elf.
#
# - `--strip-sections`: Prevents enormous binaries when SRAM is below flash.
# - `--strip-all`: Remove non-allocated sections outside segments.
# `.gnu.warning*` and `.ARM.attribute` sections are not removed.
# - `--remove-section .apps`: Prevents the .apps section from being included in
# the kernel binary file. This section is a placeholder for optionally
# including application binaries, and only needs to exist in the .elf. By
# removing it, we prevent the kernel binary from overwriting applications.
OBJCOPY_FLAGS ?= --strip-sections --strip-all --remove-section .apps
# This make variable allows board-specific Makefiles to pass down options to
# the Cargo build command. For example, in boards/<custom_board>/Makefile:
# `CARGO_FLAGS += --features=foo` would pass feature `foo` to the top level
# Cargo.toml.
CARGO_FLAGS ?=
# Add default flags to cargo. Boards can add additional options in
# `CARGO_FLAGS`.
#
# - `-Z build-std=core,compiler_builtins`: Build the std library from source
# using our optimization settings. This leads to significantly smaller binary
# sizes, and makes debugging easier since debug information for the core
# library is included in the resulting .elf file. See
# https://github.com/tock/tock/pull/2847 for more details.
CARGO_FLAGS_TOCK ?= \
$(VERBOSE_FLAGS) \
-Z build-std=core,compiler_builtins \
--target=$(TARGET) \
--package $(PLATFORM) \
--target-dir=$(TARGET_DIRECTORY) $(CARGO_FLAGS)
# Set the default flags we need for objdump to get a .lst file.
OBJDUMP_FLAGS ?= --disassemble-all --source --section-headers --demangle
# Set default flags for size.
SIZE_FLAGS ?=
# Need an extra flag for OBJDUMP if we are on a thumb platform.
ifneq (,$(findstring thumb,$(TARGET)))
OBJDUMP_FLAGS += --arch-name=thumb
endif
# Additional flags that can be passed to cargo bloat via an environment
# variable. Allows users to pass arbitrary flags supported by cargo bloat to
# customize the output. By default, pass an empty string.
CARGO_BLOAT_FLAGS ?=
# Additional flags that can be passed to print_tock_memory_usage.py via an
# environment variable. By default, pass an empty string.
PTMU_ARGS ?=
# `cargo bloat` does not support `-Z build-std`, so we must remove it from cargo
# flags. See https://github.com/RazrFalcon/cargo-bloat/issues/62.
CARGO_FLAGS_TOCK_NO_BUILD_STD := $(filter-out -Z build-std=core,$(CARGO_FLAGS_TOCK))
# Check whether the system already has a sha256sum or shasum application
# present. If not, use the custom shipped one.
ifeq (, $(shell sha256sum --version 2>/dev/null))
ifeq (, $(shell shasum --version 2>/dev/null))
# No system sha256sum available.
SHA256SUM := $(CARGO) run --manifest-path $(TOCK_ROOT_DIRECTORY)tools/sha256sum/Cargo.toml -- 2>/dev/null
else
SHA256SUM := shasum -a 256
endif
else
# Use system sha256sum.
SHA256SUM := sha256sum
endif
# virtual-function-elimination reduces the size of binaries, but is still
# experimental and has some possible miscompilation issues. This is only enabled
# for some boards by default, but is exposed via the `VFUNC_ELIM=1` option.
#
# For details on virtual-function-elimination see: https://github.com/rust-lang/rust/pull/96285
# See https://github.com/rust-lang/rust/issues/68262 for general tracking
ifneq ($(VFUNC_ELIM),)
RUSTC_FLAGS += -C lto -Z virtual-function-elimination
endif
# Dump configuration for verbose builds
ifeq ($(VERBOSE_MODE),1)
$(info )
$(info *******************************************************)
$(info TOCK KERNEL BUILD SYSTEM -- VERBOSE BUILD CONFIGURATION)
$(info *******************************************************)
$(info MAKEFILE_COMMON_PATH = $(MAKEFILE_COMMON_PATH))
$(info TOCK_ROOT_DIRECTORY = $(TOCK_ROOT_DIRECTORY))
$(info TARGET_DIRECTORY = $(TARGET_DIRECTORY))
$(info )
$(info PLATFORM = $(PLATFORM))
$(info TARGET = $(TARGET))
$(info TOCK_KERNEL_VERSION = $(TOCK_KERNEL_VERSION))
$(info RUSTC_FLAGS = $(RUSTC_FLAGS))
$(info RUSTC_FLAGS_TOCK = $(RUSTC_FLAGS_TOCK))
$(info MAKEFLAGS = $(MAKEFLAGS))
$(info OBJDUMP_FLAGS = $(OBJDUMP_FLAGS))
$(info OBJCOPY_FLAGS = $(OBJCOPY_FLAGS))
$(info CARGO_FLAGS = $(CARGO_FLAGS))
$(info CARGO_FLAGS_TOCK = $(CARGO_FLAGS_TOCK))
$(info CARGO_FLAGS_TOCK_NO_BUILD_STD = $(CARGO_FLAGS_TOCK_NO_BUILD_STD))
$(info SIZE_FLAGS = $(SIZE_FLAGS))
$(info CARGO_BLOAT_FLAGS = $(CARGO_BLOAT_FLAGS))
$(info )
$(info TOOLCHAIN = $(TOOLCHAIN))
$(info SIZE = $(SIZE))
$(info OBJCOPY = $(OBJCOPY))
$(info OBJDUMP = $(OBJDUMP))
$(info CARGO = $(CARGO))
$(info RUSTUP = $(RUSTUP))
$(info SHA256SUM = $(SHA256SUM))
$(info )
$(info cargo --version = $(shell $(CARGO) --version))
$(info rustc --version = $(shell rustc --version))
$(info rustup --version = $(shell $(RUSTUP) --version 2>/dev/null))
$(info *******************************************************)
$(info )
endif
.PRECIOUS: %.elf
# Support rules
# User-facing targets
.PHONY: all
all: release
# `make check` runs the Rust compiler but does not actually output the final
# binary. This makes checking for Rust errors much faster.
.PHONY: check
check:
$(Q)$(CARGO) check $(VERBOSE_FLAGS) $(CARGO_FLAGS_TOCK)
.PHONY: clean
clean::
$(Q)$(CARGO) clean $(VERBOSE_FLAGS) --target-dir=$(TARGET_DIRECTORY)
.PHONY: release
release: $(TARGET_PATH)/release/$(PLATFORM).bin
.PHONY: debug
debug: $(TARGET_PATH)/debug/$(PLATFORM).bin
.PHONY: debug-lst
debug-lst: $(TARGET_PATH)/debug/$(PLATFORM).lst
.PHONY: doc
doc: | target
@# This mess is all to work around rustdoc giving no way to return an
@# error if there are warnings. This effectively simulates that.
$(Q)RUSTDOCFLAGS='-Z unstable-options --document-hidden-items -D warnings' $(CARGO) --color=always doc $(VERBOSE_FLAGS) --release --package $(PLATFORM) --target-dir=$(TARGET_DIRECTORY) 2>&1 | grep -C 9999 warning && (echo "Warnings detected during doc build" && if [[ $$NOWARNINGS == "true" ]]; then echo "Erroring due to CI context" && exit 33; fi) || if [ $$? -eq 33 ]; then exit 1; fi
.PHONY: lst
lst: $(TARGET_PATH)/release/$(PLATFORM).lst
# Helper rule for showing the TARGET used by this board. Useful when building
# the documentation for all boards.
.PHONY: show-target
show-target:
$(info $(TARGET))
# This rule is a copy of the rule used to build the release target, but `cargo
# rustc` has been replaced with `cargo bloat`. `cargo bloat` replicates the
# interface of `cargo build`, rather than `cargo rustc`, so we need to move
# `RUSTC_FLAGS_FOR_BIN` into the `RUSTFLAGS` environment variable. This only
# means that cargo cannot reuse built dependencies built using `cargo bloat`.
# See the discussion on `RUSTC_FLAGS_FOR_BIN` above for additional details. To
# pass additional flags to `cargo bloat`, populate the CARGO_BLOAT_FLAGS
# environment variable, e.g. run `CARGO_BLOAT_FLAGS=--crates make cargobloat`
.PHONY: cargobloat
cargobloat:
$(Q)$(CARGO) install cargo-bloat > /dev/null 2>&1 || echo 'Error: Failed to install cargo-bloat'
$(Q)RUSTFLAGS="$(RUSTC_FLAGS_TOCK) $(RUSTC_FLAGS_FOR_BIN)" CARGO_FLAGS="-Z build-std=core" $(CARGO) bloat $(CARGO_FLAGS_TOCK_NO_BUILD_STD) --bin $(PLATFORM) --release $(CARGO_BLOAT_FLAGS)
# To pass additional flags to `cargo cargobloatnoinline`, populate the
# CARGO_BLOAT_FLAGS environment variable, e.g. run `CARGO_BLOAT_FLAGS=--crates
# make cargobloatnoinline`
.PHONY: cargobloatnoinline
cargobloatnoinline:
$(Q)$(CARGO) install cargo-bloat > \dev\null 2>&1 || echo 'Error: Failed to install cargo-bloat'
$(Q)RUSTFLAGS="$(RUSTC_FLAGS_TOCK) -C inline-threshold=0 $(RUSTC_FLAGS_FOR_BIN)" $(CARGO) bloat $(CARGO_FLAGS_TOCK) --bin $(PLATFORM) --release $(CARGO_BLOAT_FLAGS)
.PHONY: stack-analysis
#stack_analysis: RUSTC_FLAGS_TOCK += -Z emit-stack-sizes
stack-analysis:
@$ echo $(PLATFORM)
@$ echo ----------------------
$(Q)$(MAKE) release RUSTC_FLAGS="$(RUSTC_FLAGS) -Z emit-stack-sizes" $(DEVNULL) 2>&1
$(Q)$(TOCK_ROOT_DIRECTORY)/tools/stack_analysis.sh $(TARGET_PATH)/release/$(PLATFORM).elf
# Run the `print_tock_memory_usage.py` script for this board.
.PHONY: memory
memory: $(TARGET_PATH)/release/$(PLATFORM).elf
$(TOCK_ROOT_DIRECTORY)tools/print_tock_memory_usage.py --objdump $(OBJDUMP) -w $(PTMU_ARGS) $<
# Support rules
target:
@mkdir -p $(TARGET_PATH)
# Cargo outputs an elf file (just without a file extension)
%.elf: %
$(Q)cp $< $@
%.bin: %.elf
$(Q)$(OBJCOPY) --output-target=binary $(OBJCOPY_FLAGS) $< $@
$(Q)$(SHA256SUM) $@
%.lst: %.elf
$(Q)$(OBJDUMP) $(OBJDUMP_FLAGS) $< > $@
$(TOCK_ROOT_DIRECTORY)tools/sha256sum/target/debug/sha256sum:
$(Q)$(CARGO) build $(VERBOSE_FLAGS) --manifest-path $(TOCK_ROOT_DIRECTORY)tools/sha256sum/Cargo.toml
# Cargo-drivers
# We want to always invoke cargo (yay nested build systems), so these need to
# be phony, which means they can't be pattern rules.
.PHONY: $(TARGET_PATH)/release/$(PLATFORM)
$(TARGET_PATH)/release/$(PLATFORM):
$(Q)RUSTFLAGS="$(RUSTC_FLAGS_TOCK)" $(CARGO) rustc $(CARGO_FLAGS_TOCK) --bin $(PLATFORM) --release -- $(RUSTC_FLAGS_FOR_BIN)
$(Q)$(SIZE) $(SIZE_FLAGS) $@
.PHONY: $(TARGET_PATH)/debug/$(PLATFORM)
$(TARGET_PATH)/debug/$(PLATFORM):
$(Q)RUSTFLAGS="$(RUSTC_FLAGS_TOCK)" $(CARGO) rustc $(CARGO_FLAGS_TOCK) --bin $(PLATFORM) -- $(RUSTC_FLAGS_FOR_BIN)
$(Q)$(SIZE) $(SIZE_FLAGS) $@