While investigating slow build times with [a large project](https://github.com/hexops/mach/issues/124),
I found that the compiler was reading from disk nearly every C source file in my project
when rebuilding despite no changes having been made. This accounted for several seconds of
time (approx. 20-30% of running `zig build` without any changes to the sources.)
The cause of this was that comparisons of file mtimes would _always_ fail (the mtime of the file on
disk was always newer than that stored in the cache manifest), and so the cache logic would always
fall back to byte-for-byte file content comparisons with what is on disk vs. in the cache-reading every
C source file in my project from disk during each rebuild. Because file contents were the same, a cache
hit occurred, and _despite the mtime being different the cache manifest would not be updated._
One can reproduce this by building a Zig project so the cache is populated, and then changing mtimes
of their C source files to be newer than what is in the cache (without altering file contents.)
The fix is rather simple: we should always write the updated cache manifest regardless of
whether or not a cache hit occurred (a cache hit doesn't indicate if a manifest is dirty) Luckily,
`writeManifest` already contains logic to determine if a manifest is dirty and becomes no-op if no
change to the manifest file is necessary-so we merely need to ensure it is invoked.
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
When the Zig compiler is statically linked, it inspects the
/usr/bin/env ELF file to determine the native glibc version, by checking
the DT_RUNPATH, and then calling readlink() on the libc.so file, because
typically the symlink will have e.g. libc-2.33.so in the name, revealing
the glibc version.
Fortunately, this information is also in readlink() of ld.so, which is
available as the "INTERP" file path. This commit looks for e.g.
`ld-2.33.so` on the symlink data for the dynamic linker.
In theory a more complete solution would also look at `/etc/ld.so.cache`
if necessary, and finally fall back to some hard coded paths, in order
to resolve the location of libc.so, in order to do this readlink() trick
on the resulting path. You can find that flow chart with `man ld.so`.
But I think this logic will be enough to get a correct answer in all real
world cases.
This has been tested on Debian Buster and glibc-based Void Linux.
Fixes#6469
This commit upgrades glibc shared library stub-creating code to use the
new abilists file which is generated by the new glibc-abi-tool project:
https://github.com/ziglang/glibc-abi-tool/
The abilists file is different in these ways:
* It additionally encodes whether a symbol is a function or an object,
and if it is an object, it additionally encodes the size in bytes.
* It additionally encodes migrations of symbols from one library to
another between glibc versions.
* It is binary data instead of ascii.
* It is one file instead of three.
* It is 165 KB instead of 200 KB.
This solves three bugs:
Fixes#7667Fixes#8714Fixes#8896
This way, we will inform the user that there are unresolved symbols
in addition to missing library/framework as requested on the linker
line. If all symbols were resolved on the other hand, we still
flag up that the library/framework cannot be found.
Example behaviour:
```
$ zig cc hello.c -framework MyFoundation --verbose
warning(link): framework not found for '-framework MyFoundation'
warning(link): Framework search paths:
warning(link): /Library/Frameworks
warning(link): /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks
thread 1079397 panic: attempt to unwrap error: FrameworkNotFound
...stack trace...
```
and
```
❯ zig cc hello.c -lWAT --verbose
warning(link): library not found for '-lWAT'
warning(link): Library search paths:
warning(link): /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib
warning(link): /usr/local/lib
thread 1079824 panic: attempt to unwrap error: LibraryNotFound
...stack trace...
```
We now respect both `-fallow-shlib-undefined` and
`-Wl,"-undefined=dynamic_lookup"` flags. This is the first step
towards solving issues #8180 and #3000. We currently do not expose
any other ld64 equivalent flag for `-undefined` flag - we basically
throw an error should the user specify a different flag. Support for
those is conditional on closing #8180. As a result of this change,
it is now possible to generate a valid native Node.js addon with Zig
for macOS.
- each byte gets masked, shifted and combined
- use boring masks instead of comptime for readability
- tests: bit patterns with reverse operation, if applicable
See #1290
The previous commit tried to use atomics but not many CPUs support
128-bit atomics. So we use a mutex. In order to avoid contention, we
also store `recent_problematic_timestamp` locally on the `Manifest`
which is only ever accessed from a single thread at a time, and only
consult the global one if the local one is problematic.
This commit was tested by running `zig build test-behavior` in two
separate terminals at the same time.
Previously `recent_problematic_timestamp` was unprotected and accessed
potentially with multiple worker threads simultaneously.
This commit protects it with atomics and also introduces a flag to
prevent multiple timestamp checks from within the same call to hit().
Unfortunately the compiler-rt function __sync_val_compare_and_swap_16 is
not yet implemented, so I will have to take a different strategy in a
follow-up commit.
* put `recent_problematic_timestamp` onto `Cache` so that it can be
shared by multiple Manifest instances.
* make `isProblematicTimestamp` return true on any filesystem error.
* save 1 syscall by using truncate=true in createFile instead of
calling `setEndPos`.
1. It was looking for trailing zero bits when it should be looking for
trailing decimal zeros.
2. Clock timestamps had more precision than the actual file timestamps
The fix is to grab a timestamp from a 'just now changed' temp file.
This timestamp is "problematic". Any file timestamp greater than or equal
to this timestamp is considered problematic. File timestamps **prior** to
this **can** be trusted.
Downside is that it causes a disk I/O to write to and then read the
timestamp from this file ~1ms on my system. This is partially mitigated by
keeping track of the most recent problematic timestamp, and only checking
for a new problematic timestamp when checking a timestamp that is equal to
or larger than the last problematic one.
This fixes#6082.
This is the result of the work on tools/gen_stubs.zig. It now uses the
preprocessor to emit different symbols and sizes depending on the
architecture. The data is collected directly from multiple libc.so files
on disk built with upstream musl.
Closes#8178
Addresses #8896 for musl
There is still room for further improvement to this, which is to
put `.ds` directives after symbols that are not followed by aliases, to
avoid the potential problem of a linker believing that all symbols are
aliases of each other.
Now it outputs libc.S which can be assembled with zig, and the small
differences per-architecture are handled with preprocessor directives.
There is also now a set of blacklisted symbols which contains
compiler-rt.
tools/gen_stubs.zig now cuts out the middle man and operates directly on
the libc.so ELF file. it outputs accurate .size directives for objects.
std.elf gains an STV enum.
The previous commit (38b2d6209239f0dad7cb38e656d9d38506f126ca) regressed
the compile error test case for when doing saturating shift left of a
comptime-known negative RHS.
This commit additionally fixes the error for regular shifts in addition
to saturating shifts.
Saturating shift left (`<<|`) previously used the `ir_analyze_bin_op_math`
codepath rather than the `ir_analyze_bit_shift` codepath, leading to it
doing peer type resolution (incorrect) instead of using the LHS type as
the number of bits to do the saturating against.
This required implementing SIMD vector support for `@truncate`.
Additionall, this commit adds a compile error for saturating shift left
on a comptime_int.
stage2 does not pass these new behavior tests yet.
closes#10298
All Zig code is eligible to `@import("builtin")` which is mapped to a
generated file, build.zig, based on the target and other settings.
Zig invocations which share the same target settings will generate the
same builtin.zig file and thus the path to builtin.zig is in a shared
cache folder, and different projects can sometimes use the same file.
Before this commit, this led to race conditions where multiple
invocations of `zig` would race to write this file. If one process
wanted to *read* the file while the other process *wrote* the file, the
reading process could observe a truncated or partially written
builtin.zig file.
This commit makes the following improvements:
- limitations:
- avoid clobbering the inode, mtime in the hot path
- avoid creating a partially written file
- builtin.zig needs to be on disk for debug info / stack trace purposes
- don't mark the task as complete until the file is finished being populated
(possibly by an external process)
- strategy:
- create the `@import("builtin")` `Module.File` during the AstGen
work, based on generating the contents in memory rather than
loading from disk.
- write builtin.zig in a separate task that doesn't have
to complete until the end of the AstGen work queue so that it
can be done in parallel with everything else.
- when writing the file, first stat the file path. If it exists, we are done.
- otherwise, write the file to a temp file in the same directory and atomically
rename it into place (clobbering the inode, mtime in the cold path).
- summary:
- all limitations respected
- hot path: one stat() syscall that happens in a worker thread
This required adding a missing function to the standard library:
`std.fs.Dir.statFile`. In this commit, it does open() and then fstat()
which is two syscalls. It should be improved in a future commit to only
make one.
Fixes#9439.
Not sure why this warning is being emitted; let's reexamine it on the
next libunwind upgrade. I triggered it with this:
zig c++ -o hello hello.cpp -target x86_64-windows
The console test# label [test#/#tests] was being generated inside
refreshWithHeldLock (in lib/std/Progress.zig), using the number of
completed items. This was being incremented by 1 when displayed,
which is not required.