Result binary issues: CPU ISA level is lower than required

I tried to compile my program on my PC using crystal build src/main.cr -p -s --release but after uploading the result binary to my low RAM server I got this message when I tried to execute it: ./main: CPU ISA level is lower than required

At that moment I tried to compile the program using either:

  • crystal build src/main.cr -p -s --release --mcpu=x86-64-v3
  • crystal build src/main.cr -p -s --release --mcpu=x86-64-v2
  • crystal build src/main.cr -p -s --release --mcpu=x86-64
  • crystal build src/main.cr -p -s --release --mcpu=generic

and none of the generated binaries were able to run on my server which supports x86-64-v3 binaries.

The PC where do all the development is able to compile x86-64-v4 binaries.

Using --static doesn’t work either because the compiler complains about missing development packages which I actually have on my system (Arch Linux):

/usr/bin/ld: cannot find -lyaml (this usually means you need to install the development package for libyaml): No such file or directory
/usr/bin/ld: cannot find -lssl (this usually means you need to install the development package for libssl): No such file or directory
/usr/bin/ld: cannot find -lcrypto (this usually means you need to install the development package for libcrypto): No such file or directory

There is any ways to fix it? Is this a known bug or I am missing something? I only want to be able to compile on my PC and then upload the binary to my server.

In my computer I can generate different versions and it works well. Maybe some required lib was compiled using a v4 target?

Are you sure this error message is coming from the Crystal part of the program?

According to a quick google search the error might be coming from an incompatible version of glibc.
You could check that by executing the dynamically linked libc library on your target system. You can get the path via ldd main | grep libc and execute the resolved path. It should show some diagnostic information (or maybe the same error message).

Correction: If I interpret the C code that prints this error correctly, the prefix ./main should tell us that the error is on the executable, not a library. Not 100% certain, it would still be useful to do the test.

Assuming it’s an issue with the Crystal code, you may need to be more specific with the CPU or CPU feature targeting.
Which processor do you want the code to run on?

A Ryzen 9 of 3rd generation. It’s a VPS but that is the processor that it has assigned to it. My PC has a i7-11850H and there is where I compile the program

You might want to try --mcpu=zenver3 then.

When executing libc on my PC, I get this:

GNU C Library (GNU libc) stable release version 2.39.
Copyright (C) 2024 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 14.1.1 20240507.
libc ABIs: UNIQUE IFUNC ABSOLUTE
Minimum supported kernel: 6.1.0
For bug reporting instructions, please see:
<https://gitlab.archlinux.org/archlinux/packaging/packages/glibc/-/issues>.

And on my server I get this:

GNU C Library (Debian GLIBC 2.36-9+deb12u7) stable release version 2.36.
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 12.2.0.
libc ABIs: UNIQUE IFUNC ABSOLUTE
Minimum supported kernel: 3.2.0
For bug reporting instructions, please see:
<http://www.debian.org/Bugs/>.

If the problem is the difference between the installed glibc packages I could make use of the --static argument but it just doesn’t work as I pointed in OP.

$ crystal build src/main.cr --release --mcpu=zenver3                                                                                         ✘ 
'zenver3' is not a recognized processor for this target (ignoring processor)
'zenver3' is not a recognized processor for this target (ignoring processor)
'zenver3' is not a recognized processor for this target (ignoring processor)
'zenver3' is not a recognized processor for this target (ignoring processor)
'zenver3' is not a recognized processor for this target (ignoring processor)
'zenver3' is not a recognized processor for this target (ignoring processor)
LLVM ERROR: 64-bit code requested on a subtarget that doesn't support it!
[1]    324977 IOT instruction (core dumped)  crystal build src/main.cr --release --mcpu=zenver3

Static linking is completely unrelated and won’t fix any issues with Crystal codegen not working for your target CPU.

1 Like

Sorry, I forgot to mention but you need to add --cross-compile because you’re explicitly building for a different CPU than the host.
In this mode the compiler prints a linker command which you need to execute. It might work fine to run it on the host and upload the final executable. But the proper process is to upload he object file to the target system and run the linker command there.

Yeah this doesn’t seem to work too.

$ crystal build src/main.cr --mcpu=zenver3 --cross-compile

'zenver3' is not a recognized processor for this target (ignoring processor)
'zenver3' is not a recognized processor for this target (ignoring processor)
'zenver3' is not a recognized processor for this target (ignoring processor)
'zenver3' is not a recognized processor for this target (ignoring processor)
'zenver3' is not a recognized processor for this target (ignoring processor)
'zenver3' is not a recognized processor for this target (ignoring processor)
LLVM ERROR: 64-bit code requested on a subtarget that doesn't support it!
[1]    325951 IOT instruction (core dumped)  crystal build src/main.cr --mcpu=zenver3 --cross-compile
$ crystal build src/main.cr --release --mcpu=zenver3 --cross-compile
'zenver3' is not a recognized processor for this target (ignoring processor)
'zenver3' is not a recognized processor for this target (ignoring processor)
'zenver3' is not a recognized processor for this target (ignoring processor)
'zenver3' is not a recognized processor for this target (ignoring processor)
'zenver3' is not a recognized processor for this target (ignoring processor)
'zenver3' is not a recognized processor for this target (ignoring processor)
LLVM ERROR: 64-bit code requested on a subtarget that doesn't support it!
[1]    326030 IOT instruction (core dumped)  crystal build src/main.cr --release --mcpu=zenver3 --cross-compile

Sorry, the correct spelling is --mcpu=znver3 :see_no_evil:

Thanks, that did the trick. I used crystal build src/main.cr --mcpu=znver3 --cross-compile, uploaded the generated object and linked the object inside the VPS using the command that crystal build src/main.cr --mcpu=znver3 --cross-compile outputs (cc main.o -o main -rdynamic ...)

crystal build src/main.cr --release --no-debug --mcpu=x86-64-v3 --cross-compile also works well. Thank you <3

1 Like

Great to hear that it works now! :rocket:

I’m a bit stumped why this is even necessary, though. Zen 3 is a pretty modern architecture. Surely the default configuration for an x86_64 target should produce compatible code.

If you’re willing to help investigate this a bit further, could you try building in a different environment, just to exclude any influence from local configuration? An easy way would be to use the docker image crystallang/crystal to build the executable there (without any special configuration). Then check if that runs on the Ryzen system.

Using the crystallang/crystal:latest docker image to compile the program works without problems and the VPS is able to execute the binary.

I used docker run -v "$(pwd)":/app -w /app -i -t crystallang/crystal:latest crystal build src/main.cr by the way.

All right, thanks. That seems to indicate that the default configuration is working out okay.
There must be something specific to your system that causes the ISA incompatibility.
Maybe gcc on ArchLinux is just targeting a tighter architecture :person_shrugging:

1 Like