Skip to content

Commit

Permalink
Properly handle crates whose compilation results in multiple object f…
Browse files Browse the repository at this point in the history
…iles (theseus-os#517)

* Some crates have build scripts that generate multiple arbitrary object files, such as those compiled from external C code. In these cases, those crates' `.rlib` archives will have more content than their rustc-emitted `.o` object files, which leads to missing symbols at load time.

* One important example of this is the `wasmtime-runtime` crate, which builds a `helpers.o` file that is only included in the `.rlib`, not its emitted `.o` file.

* Note: this may actually allow us to use multiple codegen units too, in the future. That rustc feature has been disabled for several years now.
  • Loading branch information
kevinaboos authored May 11, 2022
1 parent 9ae6395 commit 2b1d624
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 4 deletions.
23 changes: 20 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,24 @@ $(iso): clean-old-build build extra_files
## Obviously, if a crate is used by both other application crates and by kernel crates, it is still a kernel crate.
## Then, we give all kernel crate object files the KERNEL_PREFIX and all application crate object files the APP_PREFIX.
build: $(nano_core_binary)
## Copy all object files into the main build directory and prepend the kernel or app prefix appropriately.
## Here, the main Rust build has just occurred.
##
## First, if an .rlib archive contains multiple object files, we need to extract them all out of the archive
## and combine them into one object file using partial linking (`ld -r ...`), overwriting the rustc-emitted .o file.
## Note: we skip "normal" .rlib archives that have 2 members: a single .o object file and a single .rmeta file.
## Note: the below line with the `cut` invocations simply removes the `lib` prefix and the `.rlib` suffix from the file name.
@for f in $(shell find ./target/$(TARGET)/$(BUILD_MODE)/deps/ -name "*.rlib"); do \
if [ "`$(CROSS)ar -t $${f} | wc -l`" != "2" ]; then \
echo -e "\033[1;34mUnarchiving multi-file rlib: \033[0m $${f}" ; \
mkdir -p "$(BUILD_DIR)/extracted_rlibs/`basename $${f}`-unpacked/" ; \
$(CROSS)ar -xo --output "$(BUILD_DIR)/extracted_rlibs/`basename $${f}`-unpacked/" $${f} ; \
$(CROSS)ld -r \
--output "./target/$(TARGET)/$(BUILD_MODE)/deps/`basename $${f} | cut -c 4- | rev | cut -c 6- | rev`.o" \
$$(find $(BUILD_DIR)/extracted_rlibs/$$(basename $${f})-unpacked/ -name "*.o") ; \
fi ; \
done

## Second, copy all object files into the main build directory and prepend the kernel or app prefix appropriately.
@cargo run --release --manifest-path $(ROOT_DIR)/tools/copy_latest_crate_objects/Cargo.toml -- \
-i ./target/$(TARGET)/$(BUILD_MODE)/deps \
--output-objects $(OBJECT_FILES_BUILD_DIR) \
Expand All @@ -159,7 +176,7 @@ build: $(nano_core_binary)
--app-prefix $(APP_PREFIX) \
-e "$(EXTRA_APP_CRATE_NAMES) libtheseus"

## Create the items needed for future out-of-tree builds that depend upon the parameters of this current build.
## Third, create the items needed for future out-of-tree builds that depend upon the parameters of this current build.
## This includes the target file, host OS dependencies (proc macros, etc).,
## and most importantly, a TOML file to describe these and other config variables.
@rm -rf $(THESEUS_BUILD_TOML)
Expand All @@ -172,7 +189,7 @@ build: $(nano_core_binary)
@echo -e 'cargoflags = "$(CARGOFLAGS)"' >> $(THESEUS_BUILD_TOML)
@echo -e 'host_deps = "./host_deps"' >> $(THESEUS_BUILD_TOML)

## Strip debug information if requested. This reduces object file size, improving load times and reducing memory usage.
## Fourth, strip debug information if requested. This reduces object file size, improving load times and reducing memory usage.
@mkdir -p $(DEBUG_SYMBOLS_DIR)
ifeq ($(debug),full)
# don't strip any files
Expand Down
5 changes: 4 additions & 1 deletion cfg/Config.mk
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ BUILD_STD_CARGOFLAGS += -Z build-std=core,alloc
BUILD_STD_CARGOFLAGS += -Z build-std-features=compiler-builtins-mem


## emit obj gives us the object file for the crate, instead of an rlib that we have to unpack.
## Tell rustc to output the native object file for each crate,
## which avoids always having to unpack the crate's .rlib archive to extract the object files within.
## Note that we still do have to extract and partially link object files from .rlib archives for crates that
## use a build script to generate additional object files during build time.
RUSTFLAGS += --emit=obj
## enable debug info even for release builds
RUSTFLAGS += -C debuginfo=2
Expand Down

0 comments on commit 2b1d624

Please sign in to comment.