Skip to content

Conversation

am11
Copy link
Member

@am11 am11 commented Mar 21, 2025

When using StaticICULinking, there is one moving part which we have to carry to the production environment (or the exported container layer). Since we already allow (16-byte aligned) ICU data embedding for wasm, android and other mono targets, PR reuses the same mechanism with a tiny bit of infra using POSIX-y tools like od, tr and sed which are guaranteed to be available in the context where built-local.sh is called.

This makes statically linked executable requiring globalization run in scratch container without copying the icudt.dat.

Example usage dotnet publish -p:StaticExecutable=true -p:InvariantGlobalization=false -p:StaticICULinking=true -p:EmbedIcuDataPath=/usr/share/icu/74.2/icudt74l.dat

@am11 am11 requested a review from MichalStrehovsky as a code owner March 21, 2025 13:48
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Mar 21, 2025
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

@am11
Copy link
Member Author

am11 commented Mar 21, 2025

Standalone scratch container example: docker build . -t frozen-exe

Dockerfile:

#######################################################
# STAGE 1: .NET NativeAOT static executable publishing.

FROM --platform=$BUILDPLATFORM alpine:3.21 AS builder

RUN apk add build-base curl bash clang lld cmake icu-static icu-dev openssl-dev openssl-libs-static

RUN curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel 10.0 --install-dir "$HOME/.dotnet" && \
  ln -s  /root/.dotnet/dotnet /usr/bin/dotnet

# bring your own app
RUN dotnet new webapiaot -n app1 && \
 # default template disables globalization, we want it enabled to turn on all external deps in demo
 sed -i 's|<InvariantGlobalization>true</InvariantGlobalization>||g' app1/app1.csproj && \
 # publish as static executable without PIE
 dotnet publish -p:StaticExecutable=true -p:StaticICULinking=true -p:StaticOpenSslLinking=true -p:PositionIndependentExecutable=false -o /dist app1

 RUN du -sh /dist/app1

# delete unneeded stuff from /dist
RUN rm /dist/appsettings.Development.json \
  /dist/app1.dbg

####################################################################
# STAGE 2: export scratch container with just your app and ICU data.

FROM scratch

COPY --from=builder /dist /app
COPY --from=builder /usr/share/icu/74.2/icudt74l.dat /usr/share/icu/74.2/icudt74l.dat

ENTRYPOINT ["/app/app1"]

After this PR, COPY --from=builder /usr/share/icu/ .. line in exported layer can be removed and replaced by -p:EmbedIcuDataPath=/usr/share/icu/74.2/icudt74l.dat in the builder layer.

@SingleAccretion
Copy link
Contributor

FWIW, we did a similar thing downstream with a slightly different data packaging approach that uses .incbin: dotnet/runtimelab#2490 (look for icu_data_lib.c).

@am11
Copy link
Member Author

am11 commented Mar 21, 2025

@SingleAccretion, thank you for the link. I think the __asm approach would yield a bit larger diff to cover all targets. This approach writes an .h file which gets compiled during dotnet-publish. od(1) is a POSIX utility, which should be present in all Unix shells by default; it instantly converts the 2.5MB icudtl.dat. Other options I explored:

  • System.Globalization.Native/CMakeLists.txt - pure cmake code to convert bin to byte array; takes minutes to complete compared to od(1)'s <1s instant dump.
  • Microsoft.NETCore.Native.Unix.targets - using msbuild inline C# task (using RoslynCodeTaskFactory), it was faster than cmake, but more LOC.

@am11 am11 force-pushed the feature/nativeaot/embed-icu-data branch from 359d04d to 6a864c0 Compare March 23, 2025 18:14
Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@jkotas jkotas merged commit ae64202 into dotnet:main Mar 23, 2025
155 of 158 checks passed
@am11 am11 deleted the feature/nativeaot/embed-icu-data branch March 23, 2025 21:44
@github-actions github-actions bot locked and limited conversation to collaborators Apr 23, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-NativeAOT-coreclr community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants