Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zig ld: support LTO #8680

Open
xxxbxxx opened this issue May 4, 2021 · 15 comments
Open

zig ld: support LTO #8680

xxxbxxx opened this issue May 4, 2021 · 15 comments
Labels
bug Observed behavior contradicts documented or intended behavior linking os-macos
Milestone

Comments

@xxxbxxx
Copy link
Contributor

xxxbxxx commented May 4, 2021

main.zig:

const std = @import("std");

pub fn main() anyerror!void {
    std.log.info("All your codebase are belong to us.", .{});
}
zig build-exe main.zig -OReleaseFast -target native-macos

--> ok.

touch dummy.c
zig build-exe main.zig dummy.c -OReleaseFast -target native-macos

--> error: MissingMainEntrypoint

zig build-exe main.zig dummy.c -target native-macos

--> ok

@kubkon kubkon added os-macos linking bug Observed behavior contradicts documented or intended behavior labels May 5, 2021
@kubkon
Copy link
Member

kubkon commented May 5, 2021

Potentially related #8552

@xxxbxxx
Copy link
Contributor Author

xxxbxxx commented May 5, 2021

I wanted to verify this but it's probably that wanting to link with a c file makes the zip compilation unit compile with LTO, and so the .o file is a llvm ir and not a 'normal' object file.
And probably the new linker doesn't know how to deal with it.

@kubkon kubkon added this to the 0.9.0 milestone May 5, 2021
@kubkon
Copy link
Member

kubkon commented May 5, 2021

I wanted to verify this but it's probably that wanting to link with a c file makes the zip compilation unit compile with LTO, and so the .o file is a llvm ir and not a 'normal' object file.
And probably the new linker doesn't know how to deal with it.

Correct, zig ld is not advanced enough just yet, but it's defo on the roadmap. Thanks for filing the issue!

@wojtekmach
Copy link
Sponsor Contributor

not sure if it is related but I noticed a similar error when using zig cc -shared. Targeting x86_64 works perfectly but I'm getting this error for aarch64.

on an Intel Mac:

~% uname -a
Darwin imac.local 20.4.0 Darwin Kernel Version 20.4.0: Thu Apr 22 21:46:47 PDT 2021; root:xnu-7195.101.2~1/RELEASE_X86_64 x86_64
~% cat hello.c
int hello() {
  return 0;
}
~% zig cc hello.c -shared
~% zig cc hello.c -shared -target aarch64-macos
error: MissingMainEntrypoint

and on a M1 Mac:

~% uname -a
Darwin m1.local 20.4.0 Darwin Kernel Version 20.4.0: Thu Apr 22 21:46:41 PDT 2021; root:xnu-7195.101.2~1/RELEASE_ARM64_T8101 arm64
~% zig cc hello.c -shared -target x86_64-macos
~% zig cc hello.c -shared
error: MissingMainEntrypoint

@kubkon
Copy link
Member

kubkon commented May 13, 2021

@wojtekmach actually, your issue is related to #8317. zig ld is not yet able to link nor produce a shared library and on x64 we fallback to LLD hence why it works on a native host. On arm64, we always use zig ld however hence why the deceptive error message which I should really tweak!

@kubkon
Copy link
Member

kubkon commented May 13, 2021

@wojtekmach when linking natively on arm64, you could fallback to the system linker for the time being btw until zig ld gains the missing abilities to link and produce shared libs: see #8728

@wojtekmach
Copy link
Sponsor Contributor

I tried that too but I'm unfortunately getting the same error:

% zig version
0.8.0-dev.2133+ad33e3483
% ZIG_SYSTEM_LINKER_HACK=1 zig cc hello.c -shared -target aarch64-macos
error: MissingMainEntrypoint

@wojtekmach
Copy link
Sponsor Contributor

wojtekmach commented May 13, 2021

oh I'm sorry, I was cross-compiling from a x64 host. linker hack works from the arm64 host. Thanks and sorry for the noise!

@andrewrk andrewrk modified the milestones: 0.9.0, 0.10.0 May 19, 2021
@wojtekmach
Copy link
Sponsor Contributor

@kubkon I saw in #8317 that some zig ld preliminary work landed so just in case I gave it another shot here but I see the same result. I was wondering if this problem will be solved by this issue, #8317, or some other one. Just wondering which issue I should track is all :) In any case, thank you and the team for the work on this, I'm really keen on using Zig for this use case in particular. And again sorry for hijacking this issue!

~% uname -a
Darwin m1.local 20.4.0 Darwin Kernel Version 20.4.0: Thu Apr 22 21:46:41 PDT 2021; root:xnu-7195.101.2~1/RELEASE_ARM64_T8101 arm64
~% zig version
0.8.0-dev.2305+d228d8605
~% cat hello.c
int hello() {
  return 0;
}
~% zig cc hello.c -shared
error: MissingMainEntrypoint

@wojtekmach
Copy link
Sponsor Contributor

not sure what changed but zig cc -shared worked on the arm64 host, thanks everyone!

~% zig version
0.8.0-dev.2729+87dae0ce9
~% uname -sm
Darwin arm64
~% zig cc hello.c -shared
~%

still can't cross-compile from an x86_64 host though.

~% uname -sm
Darwin x86_64
~% zig cc hello.c -shared -target aarch64-macos
error: MissingMainEntrypoint

@kubkon
Copy link
Member

kubkon commented Jul 13, 2021

I have now renamed this issue to better reflect the root issue, namely, lack of support for LTO in zig ld.

@alloveras
Copy link

alloveras commented Mar 28, 2023

@kubkon - I think I managed to hit the same error without (to my knowledge) having LTO enabled. Here is the smalest reproduction case I could come up with:

$ uname -a
Darwin MBP-Albert.local 22.3.0 Darwin Kernel Version 22.3.0: Mon Jan 30 20:39:35 PST 2023; root:xnu-8792.81.3~2/RELEASE_ARM64_T8103 arm64

$ cat > repro.cc <<'EOF'
#include <iostream>
int main(int argc, char ** argv) { std::cout << "Hello World" << std::endl; return 0; }
EOF
$ zig c++ -fno-lto -target aarch64-macos.13-none -c repro.cc
$ zig ar rcsD librepro.a repro.o
$ zig build-exe -fno-lto -target aarch64-macos.13-none librepro.a -lc++ -lSystem --name repro
MachO Flush... error(link): entrypoint '_main' not found
error: MissingMainEntrypoint

The same reproduction steps seem to work when using the MacOS system linker instead:

$ cat > repro.cc <<'EOF'
#include <iostream>
int main(int argc, char ** argv) { std::cout << "Hello World" << std::endl; return 0; }
EOF
$ zig c++ -fno-lto -target aarch64-macos.13-none -c repro.cc
$ zig ar rcsD librepro.a repro.o
$ ld librepro.a -arch arm64 -platform_version macos 13.2.1 13.2.1 -syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib -lc++ -lSystem -o main
$ ./repro
Hello World

Finally, the same reproduction steps also seem to work when targeting aarch64-linux-gnu.2.34 for example:

$ cat > repro.cc <<'EOF'
#include <iostream>
int main(int argc, char ** argv) { std::cout << "Hello World" << std::endl; return 0; }
EOF
$ zig c++ -fno-lto -target aarch64-linux-gnu.2.34 -c repro.cc
$ zig ar rcsD librepro.a repro.o
$ zig build-exe -fno-lto -target aarch64-linux-gnu.2.34 librepro.a -lc++ --name repro
$ file repro
repro: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 2.0.0, with debug_info, not stripped

# Move the binary to a Ubuntu 22.04 container (on the same MacOS host)

$ uname -a
Linux f905d25e8b5b 5.15.49-linuxkit #1 SMP PREEMPT Tue Sep 13 07:51:32 UTC 2022 aarch64 aarch64 aarch64 GNU/Linux
$ ./repro
Hello World

For context, I understand that the reproduction case is a bit "weird" on its own as putting the _main entry-point into a library archive librepro.a is probably not the most common and/or encouraged approach. However, the real-world use-case that lead me to hit the issue in the first place was me trying to build a piece of software that uses googletest and has some test cases that rely on a convenience particularity offered by this test library to avoid having to repeat some main() boilerplate on the test source files:

But maybe you think that writing all those main functions is too much work? We agree with you completely, and that’s why Google Test provides a basic implementation of main(). If it fits your needs, then just link your test with the gtest_main library and you are good to go.

Source: https://google.github.io/googletest/primer.html#writing-the-main-function

I am not an expert in the C/C++ world so it is very possible that the two issues are completely unrelated. However, my searches in Google and GitHub issues kept bringing me here so I thought I would share it in case it is relevant and/or you can provide guidance/advice.

@kubkon
Copy link
Member

kubkon commented Mar 28, 2023

@kubkon - I think I managed to hit the same error without (to my knowledge) having LTO enabled. Here is the smalest reproduction case I could come up with:

$ uname -a
Darwin MBP-Albert.local 22.3.0 Darwin Kernel Version 22.3.0: Mon Jan 30 20:39:35 PST 2023; root:xnu-8792.81.3~2/RELEASE_ARM64_T8103 arm64

$ cat > repro.cc <<'EOF'
#include <iostream>
int main(int argc, char ** argv) { std::cout << "Hello World" << std::endl; return 0; }
EOF
$ zig c++ -fno-lto -target aarch64-macos.13-none -c repro.cc
$ zig ar rcsD librepro.a repro.o
$ zig build-exe -fno-lto -target aarch64-macos.13-none librepro.a -lc++ -lSystem --name repro
MachO Flush... error(link): entrypoint '_main' not found
error: MissingMainEntrypoint

The same reproduction steps seem to work when using the MacOS system linker instead:

$ cat > repro.cc <<'EOF'
#include <iostream>
int main(int argc, char ** argv) { std::cout << "Hello World" << std::endl; return 0; }
EOF
$ zig c++ -fno-lto -target aarch64-macos.13-none -c repro.cc
$ zig ar rcsD librepro.a repro.o
$ ld librepro.a -arch arm64 -platform_version macos 13.2.1 13.2.1 -syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib -lc++ -lSystem -o main
$ ./repro
Hello World

Finally, the same reproduction steps also seem to work when targeting aarch64-linux-gnu.2.34 for example:

$ cat > repro.cc <<'EOF'
#include <iostream>
int main(int argc, char ** argv) { std::cout << "Hello World" << std::endl; return 0; }
EOF
$ zig c++ -fno-lto -target aarch64-linux-gnu.2.34 -c repro.cc
$ zig ar rcsD librepro.a repro.o
$ zig build-exe -fno-lto -target aarch64-linux-gnu.2.34 librepro.a -lc++ --name repro
$ file repro
repro: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 2.0.0, with debug_info, not stripped

# Move the binary to a Ubuntu 22.04 container (on the same MacOS host)

$ uname -a
Linux f905d25e8b5b 5.15.49-linuxkit #1 SMP PREEMPT Tue Sep 13 07:51:32 UTC 2022 aarch64 aarch64 aarch64 GNU/Linux
$ ./repro
Hello World

For context, I understand that the reproduction case is a bit "weird" on its own as putting the _main entry-point into a library archive librepro.a is probably not the most common and/or encouraged approach. However, the real-world use-case that lead me to hit the issue in the first place was me trying to build a piece of software that uses googletest and has some test cases that rely on a convenience particularity offered by this test library to avoid having to repeat some main() boilerplate on the test source files:

But maybe you think that writing all those main functions is too much work? We agree with you completely, and that’s why Google Test provides a basic implementation of main(). If it fits your needs, then just link your test with the gtest_main library and you are good to go.

Source: https://google.github.io/googletest/primer.html#writing-the-main-function

I am not an expert in the C/C++ world so it is very possible that the two issues are completely unrelated. However, my searches in Google and GitHub issues kept bringing me here so I thought I would share it in case it is relevant and/or you can provide guidance/advice.

That's unrelated to LTO. The error happens because zig ld doesn't look into the archives unless there are symbols missing in any of the object files. That's interesting that this works for Apple system linker. I wonder if zig ld should perhaps look through archives in case no object file was explicitly specified. I will extract it into a separate issue as it's unrelated to LTO.

@kubkon
Copy link
Member

kubkon commented Mar 28, 2023

@alloveras issue extracted into #15103. Thanks for filing it!

@alloveras
Copy link

@alloveras issue extracted into #15103. Thanks for filing it!

Thanks to you for the super fast response and for extracting it into a separate issue 🙇

ee7 added a commit to ee7/exercism-configlet that referenced this issue Aug 14, 2023
Try to resolve error:

    error: LTO is not yet supported with the Mach-O object format. More details: ziglang/zig#8680
    Error: execution of an external compiler program
    'zigcc -c -w -ferror-limit=3 -pthread -target aarch64-macos-none -flto -Os
    -I/home/runner/work/configlet/configlet/nimdir/lib
    -I/home/runner/work/configlet/configlet/src
    -o /home/runner/.cache/nim/configlet_r/@m..@snimdir@slib@ssystem@sctypes.nim.c.o
    /home/runner/.cache/nim/configlet_r/@m..@snimdir@slib@ssystem@sctypes.nim.c'
    failed with exit code: 1
ee7 added a commit to ee7/exercism-configlet that referenced this issue Aug 16, 2023
This reverts commit d0e67f6.

It produced the error:

    error: LTO is not yet supported with the Mach-O object format. More details: ziglang/zig#8680
avdv added a commit to avdv/scalals that referenced this issue Mar 1, 2024
It is currently not supported by zig.

See ziglang/zig#8680
avdv added a commit to avdv/scalals that referenced this issue Mar 1, 2024
It is currently not supported by zig.

See ziglang/zig#8680
avdv added a commit to avdv/scalals that referenced this issue Mar 1, 2024
It is currently not supported by zig.

See ziglang/zig#8680
avdv added a commit to avdv/scalals that referenced this issue Mar 1, 2024
It is currently not supported by zig.

See ziglang/zig#8680
avdv added a commit to avdv/scalals that referenced this issue Mar 1, 2024
It is currently not supported by zig.

See ziglang/zig#8680
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Observed behavior contradicts documented or intended behavior linking os-macos
Projects
None yet
Development

No branches or pull requests

5 participants