Rebuild ARM64 binary (without file changes) use podman is slow and probably ~/.cache/crystal invalid?

Following is a all-in-one BASH script to reproduce this:

When ran the first time successful, no code changes, re run it again, the build process still slow.

as you can see, I try to use cache like this:

RUN --mount=type=cache,target=/root/.cache/crystal shards build …

And, following is the output of the files in the /root/.cache/crystal before the next build


app-lib-baked_file_system-src-loader.cr
app-lib-baked_file_system_mounter-src-baked_file_system_mounter-baked_files.cr
app-lib-lucky-src-run_macros-generate_asset_helpers.cr
app-lib-rosetta-src-rosetta-runner.cr
app-src-build_doc_index.cr
app-src-crystal_china.cr
usr-lib-crystal-core-ecr-process.cr

And sum the file sizes in that folder, before and after the build process.

17.7M   /root/.cache/crystal

cc /app/bin/crystal_china.o -o /app/bin/crystal_china -Wl,-L/app -s -pie -rdynamic -static -L/usr/bin/../lib/crystal -lxml2 -lm -lz -llzma -pthread -lpthread -lgmp -lyaml -lz command -v pkg-config > /dev/null && pkg-config --libs --silence-errors libssl || printf %s '-lssl -lcrypto' command -v pkg-config > /dev/null && pkg-config --libs --silence-errors libcrypto || printf %s '-lcrypto' -lpcre2-8 -pthread -lpthread -lgc -lpthread -ldl
cc /app/bin/index.o -o /app/bin/index -Wl,-L/app -s -pie -rdynamic -static -L/usr/bin/../lib/crystal -lyaml -lgc -lpthread -ldl

17.7M   /root/.cache/crystal

But, the (the cross compile )build process speed far slow than development build (on AMD64) on my local.

I am not use the --release or others optimization option, following is my build options:

ARG flags=“–stats --time”

ARG compile_time_flags=“-Dstrict_multi_assign -Dno_number_autocast -Duse_pcre2 -Dpreview_overload_order”

link_flags=“–link-flags=-Wl,-L/app --link-flags=-s --link-flags=-pie”

shards build --production --static $flags $compile_time_flags $link_flags --cross-compile --target=aarch64-linux-musl

Hi. Your script uses --cross-compile to build for ARM64.

I’m not very familiar with this topic, but as usual I spent about 30 minutes looking into it with ChatGPT and DeepWiki.

Normally, the Crystal compiler compares bc (bitcode) files and reuses existing .o files if they are identical. You can confirm this behavior with the --stats option:

Codegen (bc+obj):
 - all previous .o files were reused

However, when --cross-compile is enabled, it always shows:

 - no previous .o files were reused

According to DeepWiki, in this mode the following condition is triggered:

return true unless compiler.emit_targets.none?

Because of this, must_compile? always returns true, so the compiler always recompiles and never reuses object files by design.

In other words, as long as --cross-compile is used, the build is almost a full recompilation every time.

According to a quick search on Perplexity, Go, Rust, and C/C++ seem to use caching even during cross-compilation. Perhaps Crystal could also benefit from separating the cache directory structure per target, or revisiting the conditions for must_compile? .