ld.lld fails with "undefined symbol: _fopen" on macOS, while working as expected on Linux

Hi,

I’m trying to cross-compile my app.

#include <stdio.h>
int main() {
puts(“test”);
fopen(“test”, “r”); // removing fopen() call removes the error
return 0;
}

clang -c -target x86_64-linux-gnu test.c

ld.lld -v -o test -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o test.o /usr/lib/x86_64-linux-gnu/libc.so /usr/lib/x86_64-linux-gnu/crtn.o

This works fine on Linux, but when I run the same command on macOS, I get

LLD 8.0.0 (compatible with GNU linkers)
ld.lld: error: undefined symbol: _fopen

referenced by fopen.c
test.o:(main)

I haven’t set up --sysroot yet, I just copied all these files from the Linux machine for now.

This only happens with fopen(). Using puts() or printf() is fine.

LLVM version is 8.0.0.

Thanks!

Hi Ivan,

LLD 8.0.0 (compatible with GNU linkers)
ld.lld: error: undefined symbol: _fopen
>>> referenced by fopen.c
>>> test.o:(main)

I suspect you're getting the macOS version of stdio.h, which makes
fopen some kind of alias. You really should use a sysroot when
cross-compiling, though you *might* get away with just
-I/path/to/linux/usr/include. Just what you've copied across might
well be sufficient to use with --sysroot.

Cheers.

Tim.

Thanks, Tim.

You are right, it’s using macOS’ stdio.h, which is a terrible idea.

Clang docs on --sysroot:

When you have extracted your cross-compiler from a zip file into a directory, you have to use --sysroot=. The path is the root directory where you have unpacked your file, and Clang will look for the directories bin, lib, include in there.

I have a silly question: where can I download the mentioned zip file with all bin, lib, and include files for x64 Linux target?

So far I’ve been copying files one by one (/lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o, etc) and it’s been a painful process.

I have a silly question: where can I download the mentioned zip file with all bin, lib, and include files for x64 Linux target?

There's no official source really. Systems can vary so much that it's
probably best to take it from the system you're cross-compiling for.

So far I've been copying files one by one (/lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o, etc) and it's been a painful process.

I'd probably tar up all of /usr/lib, /usr/include, and /lib rather
than copying them one at a time. For many use-cases that would be
enough, but if you've got a build-system that uses pkg-config or
something things rapidly get harder.

Cheers.

Tim.

I managed to make it work by just copying everything from /usr/include, /usr/lib/, and /lib.

It works surprisingly well.

Thanks a lot, Tim!

There’s no official source really. Systems can vary so much that it’s
probably best to take it from the system you’re cross-compiling for.

I think it would be good to add this information to the docs: https://clang.llvm.org/docs/CrossCompilation.html

Right now it says “When you have extracted your cross-compiler from a zip file into a directory”, so it’s not clear that the user must assemble this zip file themselves.