I’ve been experimenting with static builds of crystal apps for binary distribution
However I’ve been struggling to make this work reliably.
I created an example application to demonstrate the issue:
you can build the application locally and run it, it works as expected:
crystal build ./src/app.cr
./app -e
however the static app errors and exits without any output
docker-compose build
docker-compose up -d
docker logs crystal-static-test-static-1
Simplifying the application, removing the spawn and channel, has the application building and running statically without issue. Alternatively, having the channel pass Nil instead of the exception also results in a functional application.
Running some of our more complicated applications statically has resulted in correct functionality for a period of time before exiting with
Failed to raise an exception: END_OF_STACK
[0x458236] ???
[0x42ce58] ???
[0x4395ae] ???
[0x433ec9] ???
[0xc75545] ???
Tried to raise:: Unknown DW_FORM_data16 (Exception)
from usr/lib/crystal/core/crystal/dwarf/info.cr:83:29 in '??'
from usr/lib/crystal/core/crystal/dwarf/info.cr:67:23 in '??'
from usr/lib/crystal/core/exception/call_stack/elf.cr:10:7 in '??'
from src/ldso/dl_iterate_phdr.c:45:1 in '??'
This might be unrelated. However I have a feeling the issues are related to calculating backtraces for exceptions that are no longer in the scope they originated in.
To extract the static executable for inspection / running on your local machine you can run docker buildx build --platform linux/amd64 --output type=local,dest=folder .
Any ideas or help in this matter would be much appreciated
I run the binary manually, it seem like terminated with no error.
/ $ ./static
test terminated
last error was:
when run with -e, it seem like work as expect?
/ $ ./static -e -c 5
running exception test:
!.!.!.!.!.
test terminated
last error was: example error (Exception)
from app/src/app.cr:52:9 in '->'
from usr/lib/crystal/core/fiber.cr:146:11 in 'run'
from usr/lib/crystal/core/fiber.cr:98:34 in '->'
from ???
If you change Dockerfile like this:
@@ -90,4 +92,4 @@ USER appuser:appuser
# Run the app binding on port 3000
EXPOSE 3000
ENTRYPOINT ["/static"]
-CMD ["/static", "-e"]
+CMD ["-e", "-c", "5"]
You can see same output as above.
╰─ $ docker-compose up
[+] Running 1/0
⠿ Container crystal-static-test-static-1 R... 0.1s
Attaching to crystal-static-test-static-1
crystal-static-test-static-1 | running exception test:
crystal-static-test-static-1 | !.!.!.!.!.
crystal-static-test-static-1 | test terminated
crystal-static-test-static-1 | last error was: example error (Exception)
crystal-static-test-static-1 | from app/src/app.cr:52:9 in '->'
crystal-static-test-static-1 | from usr/lib/crystal/core/fiber.cr:146:11 in 'run'
crystal-static-test-static-1 | from usr/lib/crystal/core/fiber.cr:98:34 in '->'
crystal-static-test-static-1 | from ???
crystal-static-test-static-1 exited with code 0
One thing you could do is patch the method where it raises (usr/lib/crystal/core/crystal/dwarf/info.cr:83) to, in addition to raising, writing the message to a file, maybe also write all of the Info’s instance vars. That way when it happens we’ll at least know what are the problematic values.