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

introduce operating system version ranges as part of the target; self-host native dynamic linker detection and native glibc version detection #4550

Merged
merged 37 commits into from
Feb 29, 2020

Conversation

andrewrk
Copy link
Member

@andrewrk andrewrk commented Feb 25, 2020

Commit Details

  • introduce std.zig.CrossTarget which is distinct from std.Target. std.zig.CrossTarget wraps std.Target so that it can be annotated as "the native target" or an explicitly specified target.
  • std.Target.Os is moved to std.Target.Os.Tag. The former is now a struct which has the tag as well as version range information.
  • std.elf gains some more ELF header constants.
  • std.Target.parse gains the ability to parse operating system version ranges as well as glibc version.
  • Added std.Target.isGnuLibC().
  • self-hosted dynamic linker detection and glibc version detection. This also adds the improved logic using /usr/bin/env rather than invoking the system C compiler to find the dynamic linker when zig is statically linked. Related: zig fails to detect musl as the native C ABI on alpine linux  #2084
    Note: this /usr/bin/env code is work-in-progress.
  • -target-glibc CLI option is removed in favor of the new -target syntax. Example: -target x86_64-linux-gnu.2.27

closes #1907

What this means for Zig programmers

comptime code will have access to exactly which version(s) of an OS are being targeted.

Updated syntax for -target to take into account OS version ranges:

# still valid. default version range
-target x86_64-windows-msvc

# minimum windows version: XP
# maximum windows version: 10
-target x86_64-windows.xp...win10-msvc

# minimum windows version: 7
# maximum windows version: latest
-target x86_64-windows.win7-msvc

# linux example
-target aarch64-linux.3.16...5.3.1-musl

# specifying glibc version
-target mipsel-linux.4.10-gnu.2.1

Here's what it will look like to populate a std.Target:

-        tc.target = tests.Target{
-            .Cross = .{
-                .cpu = Target.Cpu.baseline(.x86_64),
-                .os = Target.Os.defaultVersionRange(.linux),
-                .abi = .gnu,
-            },
+        tc.target = std.zig.CrossTarget{
+            .cpu_arch = .x86_64,
+            .os_tag = .linux,
+            .abi = .gnu,

Code that used Target.parse need not be updated.

Checking for the OS when doing conditional compilation:

Option 1: easy, might get deprecated in the future:

--- a/lib/std/build/run.zig
+++ b/lib/std/build/run.zig
@@ -82,7 +82,7 @@ pub const RunStep = struct {
 
         var key: []const u8 = undefined;
         var prev_path: ?[]const u8 = undefined;
-        if (builtin.os == .windows) {
+        if (builtin.os.tag == .windows) {
             key = "Path";
             prev_path = env_map.get(key);
             if (prev_path == null) {

Option 2, more verbose, less likely to be deprecated in the future:

--- a/test/stage1/behavior/byteswap.zig
+++ b/test/stage1/behavior/byteswap.zig
@@ -1,6 +1,5 @@
 const std = @import("std");
 const expect = std.testing.expect;
-const builtin = @import("builtin");
 
 test "@byteSwap integers" {
     const ByteSwapIntTest = struct {
@@ -41,10 +40,10 @@ test "@byteSwap integers" {
 
 test "@byteSwap vectors" {
     // https://github.com/ziglang/zig/issues/3563
-    if (builtin.os == .dragonfly) return error.SkipZigTest;
+    if (std.Target.current.os.tag == .dragonfly) return error.SkipZigTest;
 
     // https://github.com/ziglang/zig/issues/3317
-    if (builtin.arch == .mipsel) return error.SkipZigTest;
+    if (std.Target.current.cpu.arch == .mipsel) return error.SkipZigTest;
 
     const ByteSwapVectorTest = struct {
         fn run() void {

Checklist:

  • complete the fallback /usr/bin/env ELF implementation
  • remove stage1 code for dynamic linker detection and glibc version detection
  • improve the std.Target.zigTriple function to render os version info
  • update zig build
  • update codebase to the new std.Target API
  • remove -mmacos_version_min and related features since it can now be automatically handled by the target OS version range feature
  • implement operating system version detection, which sets the min and max both to that value done for linux; others will become contributor friendly issues.
  • support -target native-native-gnu and -mcpu=native.
  • move -mcpu to be part of the target triple will open separate proposal for this
  • improve Builder.standardTargetOptions API and allow specifying a different default target, so that e.g. native-native-gnu could be the default for a given project on windows (as chosen by build.zig).
  • add dynamic linker path to CrossTarget and Target
  • compiler assertion tripped with multiple comptime fn calls and default initialized array #4578
  • merge std.zig.CrossTarget.toTarget and std.zig.system.NativeTargetInfo.detect.
  • test a static build on alpine linux and make sure it detects the native ABI and dynamic linker (zig fails to detect musl as the native C ABI on alpine linux  #2084)

Follow-up Items

@andrewrk andrewrk changed the title introduce operating system version ranges as part of the target introduce operating system version ranges as part of the target; self-host native dynamic linker detection and native glibc version detection Feb 25, 2020
@andrewrk
Copy link
Member Author

andrewrk commented Feb 26, 2020

In this branch Zig supports a more fine-grained sense of what is native and what is
not. Some examples:

# This is now allowed:
-target native

# Different OS but native CPU, default Windows C ABI:
-target native-windows
# This could be useful for example when running in Wine.

# Different CPU but native OS, native C ABI.
-target x86_64-native -mcpu=skylake

# Different C ABI but otherwise native target:
-target native-native-musl
-target native-native-gnu

# Different glibc version but otherwise native target:
-target native-native-gnu.2.25

# Different OS minimum version, but otherwise native target:
-target native-native.xp

Lots of breaking changes to related std lib APIs.
Calls to getOs() will need to be changed to getOsTag().
Calls to getArch() will need to be changed to getCpuArch().

Usage of Target.Cross and Target.Native need to be updated to use
CrossTarget API.

std.build.Builder.standardTargetOptions is changed to accept its
parameters as a struct with default values. It now has the ability to
specify a whitelist of targets allowed, as well as the default target.
Rather than two different ways of collecting the target, it's now always
a string that is validated, and prints helpful diagnostics for invalid
targets. This feature should now be actually useful, and contributions
welcome to further improve the user experience.

std.build.LibExeObjStep.setTheTarget is removed.
std.build.LibExeObjStep.setTarget is updated to take a CrossTarget
parameter.

std.build.LibExeObjStep.setTargetGLibC is removed. glibc versions are
handled in the CrossTarget API and can be specified with the -target
triple.

std.builtin.Version gains a format method.

@andrewrk andrewrk force-pushed the os-version-ranges branch 2 times, most recently from fde3a8f to 6d008f1 Compare February 27, 2020 16:53

pub const LinuxVersionRange = struct {
range: Version.Range,
glibc: Version,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this field only be present for glibc targets?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's correct, the field is only valid for glibc targets and is otherwise undefined

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than undefined should it be an optional with null? Or union(enum) { Musl, Glibc: Version }

lib/std/target.zig Outdated Show resolved Hide resolved
lib/std/target.zig Show resolved Hide resolved
lib/std/target.zig Show resolved Hide resolved
lib/std/target.zig Show resolved Hide resolved
 * re-introduce `std.build.Target` which is distinct from `std.Target`.
   `std.build.Target` wraps `std.Target` so that it can be annotated as
   "the native target" or an explicitly specified target.
 * `std.Target.Os` is moved to `std.Target.Os.Tag`. The former is now a
   struct which has the tag as well as version range information.
 * `std.elf` gains some more ELF header constants.
 * `std.Target.parse` gains the ability to parse operating system
   version ranges as well as glibc version.
 * Added `std.Target.isGnuLibC()`.
 * self-hosted dynamic linker detection and glibc version detection.
   This also adds the improved logic using `/usr/bin/env` rather than
   invoking the system C compiler to find the dynamic linker when zig
   is statically linked. Related: #2084
   Note: this `/usr/bin/env` code is work-in-progress.
 * `-target-glibc` CLI option is removed in favor of the new `-target`
   syntax. Example: `-target x86_64-linux-gnu.2.27`

closes #1907
and glibc_detect_native_version
Zig now supports a more fine-grained sense of what is native and what is
not. Some examples:

This is now allowed:
-target native

Different OS but native CPU, default Windows C ABI:
-target native-windows
This could be useful for example when running in Wine.

Different CPU but native OS, native C ABI.
-target x86_64-native -mcpu=skylake

Different C ABI but otherwise native target:
-target native-native-musl
-target native-native-gnu

Lots of breaking changes to related std lib APIs.
Calls to getOs() will need to be changed to getOsTag().
Calls to getArch() will need to be changed to getCpuArch().

Usage of Target.Cross and Target.Native need to be updated to use
CrossTarget API.

`std.build.Builder.standardTargetOptions` is changed to accept its
parameters as a struct with default values. It now has the ability to
specify a whitelist of targets allowed, as well as the default target.
Rather than two different ways of collecting the target, it's now always
a string that is validated, and prints helpful diagnostics for invalid
targets. This feature should now be actually useful, and contributions
welcome to further improve the user experience.

`std.build.LibExeObjStep.setTheTarget` is removed.
`std.build.LibExeObjStep.setTarget` is updated to take a CrossTarget
parameter.

`std.build.LibExeObjStep.setTargetGLibC` is removed. glibc versions are
handled in the CrossTarget API and can be specified with the `-target`
triple.

`std.builtin.Version` gains a `format` method.
 * `std.Target.getStandardDynamicLinkerPath` =>
   `std.Target.standardDynamicLinkerPath`
 * it now takes a pointer to fixed size array rather than an allocator
 * `std.zig.system.NativeTargetInfo.detect` now supports reading
   PT_INTERP from /usr/bin/env
@andrewrk
Copy link
Member Author

Blocking on #4578

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

introduce operating system version ranges as part of the target
2 participants