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

Get hello world compiling for iOS #5145

Open
tanis2000 opened this issue Apr 23, 2020 · 35 comments
Open

Get hello world compiling for iOS #5145

tanis2000 opened this issue Apr 23, 2020 · 35 comments
Labels
contributor friendly This issue is limited in scope and/or knowledge of Zig internals. enhancement Solving this issue will likely involve adding new logic or components to the codebase.
Milestone

Comments

@tanis2000
Copy link

I'm just figuring out at what point in time you are with iOS support for Zig. I tried to compile the basic project that you get when you initialize a new Zig project with the following command:

zig build-exe ./src/main.zig -target aarch64-ios

And I get the following error:

/usr/local/Cellar/zig/0.6.0_1/lib/zig/std/debug.zig:662:21: error: openSelfDebugInfo unsupported for this platform
            else => @compileError("openSelfDebugInfo unsupported for this platform"),
                    ^

Does that mean that iOS is not supported at all or is there anything I could do to help adding support for that platform?

@Sobeston
Copy link
Contributor

Compiling a debug build (the default) has safety features enabled, and many of these things are OS specific. If you want to make good use of zig's runtime safety features, someone would have to implement these for IOS.

Large areas of the standard library as a whole likely won't be available yet.

For now, I think IOS will work in release fast and release small (providing you can avoid using a lot of the standard library).

@tanis2000
Copy link
Author

Both release-fast and release-small seem to fail with the same error. Am I doing something wrong?

➜  test-zig zig build-exe ./src/main.zig -target aarch64-ios --release-fast
/usr/local/Cellar/zig/0.6.0_1/lib/zig/std/debug.zig:662:21: error: openSelfDebugInfo unsupported for this platform
            else => @compileError("openSelfDebugInfo unsupported for this platform"),
                    ^
➜  test-zig zig build-exe ./src/main.zig -target aarch64-ios --release-small
/usr/local/Cellar/zig/0.6.0_1/lib/zig/std/debug.zig:662:21: error: openSelfDebugInfo unsupported for this platform
            else => @compileError("openSelfDebugInfo unsupported for this platform"),
                    ^

@LemonBoy
Copy link
Contributor

Am I doing something wrong?

The --release-* switches won't do anything for your problem. Try adding .ios in the switch where the @compilError is, I believe the Darwin codepath works just fine on IOS too.

@tanis2000
Copy link
Author

So far my src/main.zig file (the only one I have besides the build.zig) is the following:

const std = @import("std");

pub fn main() anyerror!void {
    std.debug.warn("All your codebase are belong to us.\n", .{});
}

I even tried this because I thought std.debug could be the issue:

const std = @import("std");

pub fn main() anyerror!void {
    const stdout = std.io.getStdOut().outStream();
    try stdout.print("Hello, {}!\n", .{"world"});
}

but the error is still the same.
I don't get where I should add an .ios to a switch... which switch? :)

@daurnimator
Copy link
Contributor

The --release-* switches won't do anything for your problem. Try adding .ios in the switch where the @compilError is, I believe the Darwin codepath works just fine on IOS too.

wait..... why is ios different to darwin? they're the same kernel

@tanis2000
Copy link
Author

@daurnimator yes it is the same kernel. But if I add .ios to this switch in the std library (I believe this is the switch @LemonBoy was referring to) then it compiles:

/// TODO resources https://github.com/ziglang/zig/issues/4353
pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo {
    noasync {
        if (builtin.strip_debug_info)
            return error.MissingDebugInfo;
        if (@hasDecl(root, "os") and @hasDecl(root.os, "debug") and @hasDecl(root.os.debug, "openSelfDebugInfo")) {
            return root.os.debug.openSelfDebugInfo(allocator);
        }
        switch (builtin.os.tag) {
            .linux,
            .freebsd,
            .netbsd,
            .dragonfly,
            .macosx,
            .windows,
            .ios,
            => return DebugInfo.init(allocator),
            else => @compileError("openSelfDebugInfo unsupported for this platform"),
        }
    }
}

@LemonBoy
Copy link
Contributor

I don't get where I should add an .ios to a switch... which switch? :)

The one above /usr/local/Cellar/zig/0.6.0_1/lib/zig/std/debug.zig:662. I'd suggest you to fetch a copy from git to avoid modifying the homebrew copy.

wait..... why is ios different to darwin? they're the same kernel

I forgot to put back the .ios, .watchos and friends when I refactored the debug stuff.

@tanis2000
Copy link
Author

@LemonBoy hah! now that's clear :)

Ok, then I have one more question regarding compiling for iOS. Let's assume that:

  • I have a C library that I wrote that I use to make games on all kind of platforms with.
  • In that library I am including SDL2 and other libraries as source code and compile them all statically into my library to make sure that I'm using the same versions that I have written my code with.
  • I believe that Zig has no clue about CMake files
  • But Zig is using clang to compile C code, so I guess it should be able to understand Obj-C code, too

Would it be possible to provide to Zig a list of folders with the source code of SDL2 and the like and write a build.zig script that compiles all of them with the correct inclusion files and the correct switches for clang and also for the Obj-C files?

@prime31
Copy link
Contributor

prime31 commented May 3, 2020

@tanis2000 you're prolly gonna need to dive into this, update SDL and add iOS to the build script: https://github.com/andrewrk/zig-sdl

@tanis2000
Copy link
Author

@prime31 I already did all of that in my own repo without all the extra stuff of that SDL repo. But I still have issues compiling for macOS, not even iOS... Actually the compiler itself is crashing: #5188

@andrewrk andrewrk added this to the 0.8.0 milestone May 30, 2020
@andrewrk andrewrk added contributor friendly This issue is limited in scope and/or knowledge of Zig internals. enhancement Solving this issue will likely involve adding new logic or components to the codebase. labels May 30, 2020
@andrewrk andrewrk changed the title Compiling for iOS Get hello world compiling for iOS May 30, 2020
@andrewrk
Copy link
Member

Would it be possible to provide to Zig a list of folders with the source code of SDL2 and the like and write a build.zig script that compiles all of them with the correct inclusion files and the correct switches for clang and also for the Obj-C files?

Yes, and you can see a proof-of-concept here: https://github.com/andrewrk/zig-sdl

@andrewrk andrewrk modified the milestones: 0.8.0, 0.9.0 Nov 6, 2020
@SebastianKeller
Copy link
Contributor

SebastianKeller commented Dec 22, 2020

I guess this issue can be closed. A simple hello-world compiles just fine.

zig version is 0.7.1+43dbe8622

~/temp ❯❯❯ cat hello-world.zig
const std = @import("std");

pub fn main() !void {
    std.debug.print("Hello world\n", .{});
}
~/temp ❯❯❯ zig build-exe hello-world.zig -target aarch64-ios
~/temp ❯❯❯ file hello-world
hello-world: Mach-O 64-bit arm64 executable, flags:<NOUNDEFS|DYLDLINK|TWOLEVEL|PIE|HAS_TLV_DESCRIPTORS>

@tanis2000
Copy link
Author

@SebastianKeller we can close the original issue but I will open a new one for what concerns SDL2 as that's not yet been fixed

@coolbluewater
Copy link

coolbluewater commented Feb 3, 2021

@SebastianKeller, @tanis2000, is the code that compiles in the above example expected to run correctly on the iOS simulator? Is zig's c standard library code correct for iOS?

I dropped the compiled binary into a test app bundle and installed the bundle into the simulator.
Running the app via springboard crashes right away. That is, I think it crashes - there's no "Hello, world" output in the Console app.

Using lldb to wait for the process to start and then break also fails: the debugger errors out that it is unable to connect to the process.

Let me know if you need the detailed steps I followed.

@SebastianKeller
Copy link
Contributor

@coolbluewater I'm a bit confused. Could you please provide more information on 'dropped the binary into an app'?

Besides, the simulator runs in x86. The devices run in arm.

A more common usecase would be to write a zig-library, export c headers and link the static library. You then call the zig-lib using the c-header.

@coolbluewater
Copy link

coolbluewater commented Feb 3, 2021

@SebastianKeller

A more common usecase would be to write a zig-library, export c headers and link the static library. You then call the zig-lib using the c-header.

:) It helps my learning to create a simple app in zig without depending on Swift or Objective-C. In a real world app your use case is more appropriate.

Besides, the simulator runs in x86. The devices run in arm.

Ah yes, I used the x86_64-ios target instead. I will provide more details if you can confirm that this target should work.

@SebastianKeller
Copy link
Contributor

Alright. Good luck then.

@coolbluewater
Copy link

Here are the steps:

  1. Compile the code to produce a binary named MyApp:
    zig build-exe hello-world.zig -target x86_64-ios --name MyApp

  2. Create a folder for the bundle named MyApp.app and move the MyApp binary into it.

  3. You need two more files under MyApp.app: an icon - any small .png file will do - named AppIcon.png and a text file named Info.plist with these contents:

<plist version="1.0">
<dict>
    <key>CFBundleDisplayName</key>
    <string>MyApp</string>
    <key>CFBundleExecutable</key>
    <string>MyApp</string>
    <key>CFBundleIconFiles</key>
    <string>AppIcon</string>
    <key>CFBundleIdentifier</key>
    <string>xxx.sample</string>
    <key>CFBundleVersion</key>
    <string>1</string>
    <key>CFBundleShortVersionString</key>
    <string>1</string>
</dict>
</plist>
  1. Start the iOS Simulator and install the app bundle from Terminal:
    xcrun simctl install booted MyApp.app
    You should see the app icon on the simulator screen.

@coolbluewater
Copy link

coolbluewater commented Feb 3, 2021

@SebastianKeller

Alright. Good luck then.

So you think that the x86_64-ios target should work correctly?

@tanis2000, @andrewrk

@SebastianKeller
Copy link
Contributor

@coolbluewater

The binary runs on the simulator.

❯ cat hello-world.zig
const std = @import("std");

pub fn main() !void {
    std.debug.print("Hello world\n", .{});
}

❯ zig build-exe hello-world.zig -target x86_64-ios

❯ xcrun simctl spawn booted ./hello-world
Hello world

My guess is that the .app-Container is somehow not correct.

@tanis2000
Copy link
Author

@coolbluewater this is not how you create an iOS app. You can't just create a binary that has a main function entrypoint and pretend it will work without instantiating the UIAppDelegate. As @SebastianKeller pointed out, you should create a library and then import that into your iOS project. This is the easiest approach.

BTW we should just close this issue as the original problem has been solved and we're talking about a different issue now.

@coolbluewater
Copy link

coolbluewater commented Feb 3, 2021

@SebastianKeller, thanks.

@tanis2000,

@coolbluewater this is not how you create an iOS app. You can't just create a binary that has a main function entrypoint and pretend it will work without instantiating the UIAppDelegate.

According to the iOS docs for the app launch sequence, there's nothing special about the UIAppDelegate. It just so happens that that's what the Xcode-supplied main() function (in an Xcode-generated project) winds up creating. But it should certainly call our main() function, which just logs a string and exits. That's the barest stub of functionality I'm looking for at this point.

@coolbluewater
Copy link

coolbluewater commented Feb 3, 2021

@SebastianKeller,
Running the steps you listed produces
dyld: Symbol not found: __tlv_bootstrap

Any idea what might be causing this? I'm running zig 0.7.1 and the simulator is iOS 14.3.

@g-w1
Copy link
Contributor

g-w1 commented Feb 3, 2021

The symbol is defined on master, not 0.7.1
image

@coolbluewater
Copy link

@g-w1, Thanks that would explain it. As a zig newbie, are builds of master available to install?
If not, I'll compile from source, a good way to learn the system.

@g-w1
Copy link
Contributor

g-w1 commented Feb 3, 2021 via email

@SebastianKeller
Copy link
Contributor

@coolbluewater
Copy link

@g-w1, @SebastianKeller - thanks all. Will report back.

@coolbluewater
Copy link

coolbluewater commented Feb 3, 2021

@SebastianKeller, running xcrun simctl spawn works, and the output is in Terminal.

But running the .app bundle doesn't seem to produce any output in Console. Investigating.

@coolbluewater
Copy link

coolbluewater commented Feb 3, 2021

Update: while I'm still unable to find where the "Hello, world" got written to, adding this worked:

std.os.exit(1);

Now Console shows Service exited with abnormal code: 1
So that's probably the first iOS app written entirely in zig with no Objective-C or Swift! :)

@mikdusan
Copy link
Member

mikdusan commented Feb 3, 2021

hmm... don't app launchers close file handles 0,1,2 and force use of logging api ... and console.app can read?

@coolbluewater
Copy link

coolbluewater commented Feb 4, 2021

@mikdusan, you're probably correct. Now trying to use os_log.

What is the zig equivalent of Objective-C's#import <os/log.h>? This allows framework headers to be imported easily.

I tried const log = @import("os/log.h"); but that fails with or without the .h.

Edit: Think I may need to create an objective-C library with that exposes functionality to zig via the C ABI. Also opened #7944 to discuss whether Objective-C frameworks can be supported more directly in zig.

@g-w1
Copy link
Contributor

g-w1 commented Feb 4, 2021

If you want to include the c library you probably want

const c = @cImport({
@cInclude("os/log.h");
});

@coolbluewater
Copy link

@g-w1, unfortunately that doesn't work.
More detail: Apple frameworks have a known location and layout that clang uses to resolve #import <os/log.h> when parsing a source file as objective-c, but not as plain C. Since zig uses clang in plain-C mode to parse files, this mechanism isn't invoked and so the header can't be located. That's why I've opened the issue mentioned above to discuss the future of objective-C interop in zig.

@kerrhome
Copy link

kerrhome commented Feb 17, 2021

@coolbluewater my buddy Bill just did some writing to the iOS console yesterday for us testing a Zig build (using the iOS SDK still). He used os_log(), which you should be able to create an extern for _os_log_internal to using this within your Zig app without needing the full SDK to build against. It was extremely helpful in our debugging yesterday (which we have working beautifully now). Man, Zig is great.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contributor friendly This issue is limited in scope and/or knowledge of Zig internals. enhancement Solving this issue will likely involve adding new logic or components to the codebase.
Projects
None yet
Development

No branches or pull requests