zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 68bb3945708c43109c48bda3664176307d45b62c (tree)
parent 6128bc728d1e1024a178c16c2149f5b1a167a013
Author: Andrew Kelley <andrew@ziglang.org>
Date:   Thu, 26 Sep 2019 01:54:45 -0400

Merge pull request #3315 from ziglang/mv-std-lib

Move std/ to lib/std/
Diffstat:
MCMakeLists.txt | 3+--
Mbuild.zig | 9++-------
Rstd/array_list.zig -> lib/std/array_list.zig | 0
Rstd/ascii.zig -> lib/std/ascii.zig | 0
Rstd/atomic.zig -> lib/std/atomic.zig | 0
Rstd/atomic/int.zig -> lib/std/atomic/int.zig | 0
Rstd/atomic/queue.zig -> lib/std/atomic/queue.zig | 0
Rstd/atomic/stack.zig -> lib/std/atomic/stack.zig | 0
Rstd/base64.zig -> lib/std/base64.zig | 0
Rstd/bloom_filter.zig -> lib/std/bloom_filter.zig | 0
Rstd/buf_map.zig -> lib/std/buf_map.zig | 0
Rstd/buf_set.zig -> lib/std/buf_set.zig | 0
Rstd/buffer.zig -> lib/std/buffer.zig | 0
Alib/std/build.zig | 2731+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rstd/build/fmt.zig -> lib/std/build/fmt.zig | 0
Rstd/c.zig -> lib/std/c.zig | 0
Rstd/c/darwin.zig -> lib/std/c/darwin.zig | 0
Rstd/c/freebsd.zig -> lib/std/c/freebsd.zig | 0
Rstd/c/linux.zig -> lib/std/c/linux.zig | 0
Rstd/c/netbsd.zig -> lib/std/c/netbsd.zig | 0
Rstd/c/windows.zig -> lib/std/c/windows.zig | 0
Rstd/child_process.zig -> lib/std/child_process.zig | 0
Rstd/coff.zig -> lib/std/coff.zig | 0
Rstd/crypto.zig -> lib/std/crypto.zig | 0
Rstd/crypto/benchmark.zig -> lib/std/crypto/benchmark.zig | 0
Rstd/crypto/blake2.zig -> lib/std/crypto/blake2.zig | 0
Rstd/crypto/chacha20.zig -> lib/std/crypto/chacha20.zig | 0
Rstd/crypto/gimli.zig -> lib/std/crypto/gimli.zig | 0
Rstd/crypto/hmac.zig -> lib/std/crypto/hmac.zig | 0
Rstd/crypto/md5.zig -> lib/std/crypto/md5.zig | 0
Rstd/crypto/poly1305.zig -> lib/std/crypto/poly1305.zig | 0
Rstd/crypto/sha1.zig -> lib/std/crypto/sha1.zig | 0
Rstd/crypto/sha2.zig -> lib/std/crypto/sha2.zig | 0
Rstd/crypto/sha3.zig -> lib/std/crypto/sha3.zig | 0
Rstd/crypto/test.zig -> lib/std/crypto/test.zig | 0
Rstd/crypto/x25519.zig -> lib/std/crypto/x25519.zig | 0
Rstd/cstr.zig -> lib/std/cstr.zig | 0
Rstd/debug.zig -> lib/std/debug.zig | 0
Rstd/debug/failing_allocator.zig -> lib/std/debug/failing_allocator.zig | 0
Rstd/debug/leb128.zig -> lib/std/debug/leb128.zig | 0
Rstd/dwarf.zig -> lib/std/dwarf.zig | 0
Rstd/dynamic_library.zig -> lib/std/dynamic_library.zig | 0
Rstd/elf.zig -> lib/std/elf.zig | 0
Rstd/event.zig -> lib/std/event.zig | 0
Rstd/event/channel.zig -> lib/std/event/channel.zig | 0
Rstd/event/fs.zig -> lib/std/event/fs.zig | 0
Rstd/event/future.zig -> lib/std/event/future.zig | 0
Rstd/event/group.zig -> lib/std/event/group.zig | 0
Rstd/event/lock.zig -> lib/std/event/lock.zig | 0
Rstd/event/locked.zig -> lib/std/event/locked.zig | 0
Rstd/event/loop.zig -> lib/std/event/loop.zig | 0
Rstd/event/net.zig -> lib/std/event/net.zig | 0
Rstd/event/rwlock.zig -> lib/std/event/rwlock.zig | 0
Rstd/event/rwlocked.zig -> lib/std/event/rwlocked.zig | 0
Rstd/fmt.zig -> lib/std/fmt.zig | 0
Rstd/fmt/errol.zig -> lib/std/fmt/errol.zig | 0
Rstd/fmt/errol/enum3.zig -> lib/std/fmt/errol/enum3.zig | 0
Rstd/fmt/errol/lookup.zig -> lib/std/fmt/errol/lookup.zig | 0
Rstd/fmt/parse_float.zig -> lib/std/fmt/parse_float.zig | 0
Rstd/fs.zig -> lib/std/fs.zig | 0
Rstd/fs/file.zig -> lib/std/fs/file.zig | 0
Rstd/fs/get_app_data_dir.zig -> lib/std/fs/get_app_data_dir.zig | 0
Rstd/fs/path.zig -> lib/std/fs/path.zig | 0
Rstd/hash.zig -> lib/std/hash.zig | 0
Rstd/hash/adler.zig -> lib/std/hash/adler.zig | 0
Rstd/hash/auto_hash.zig -> lib/std/hash/auto_hash.zig | 0
Rstd/hash/benchmark.zig -> lib/std/hash/benchmark.zig | 0
Rstd/hash/cityhash.zig -> lib/std/hash/cityhash.zig | 0
Rstd/hash/crc.zig -> lib/std/hash/crc.zig | 0
Rstd/hash/fnv.zig -> lib/std/hash/fnv.zig | 0
Rstd/hash/murmur.zig -> lib/std/hash/murmur.zig | 0
Rstd/hash/siphash.zig -> lib/std/hash/siphash.zig | 0
Rstd/hash/wyhash.zig -> lib/std/hash/wyhash.zig | 0
Rstd/hash_map.zig -> lib/std/hash_map.zig | 0
Rstd/heap.zig -> lib/std/heap.zig | 0
Rstd/heap/logging_allocator.zig -> lib/std/heap/logging_allocator.zig | 0
Rstd/http.zig -> lib/std/http.zig | 0
Rstd/http/headers.zig -> lib/std/http/headers.zig | 0
Rstd/io.zig -> lib/std/io.zig | 0
Rstd/io/c_out_stream.zig -> lib/std/io/c_out_stream.zig | 0
Rstd/io/in_stream.zig -> lib/std/io/in_stream.zig | 0
Rstd/io/seekable_stream.zig -> lib/std/io/seekable_stream.zig | 0
Rstd/io/test.zig -> lib/std/io/test.zig | 0
Rstd/json.zig -> lib/std/json.zig | 0
Rstd/json/test.zig -> lib/std/json/test.zig | 0
Rstd/lazy_init.zig -> lib/std/lazy_init.zig | 0
Rstd/linked_list.zig -> lib/std/linked_list.zig | 0
Rstd/macho.zig -> lib/std/macho.zig | 0
Rstd/math.zig -> lib/std/math.zig | 0
Rstd/math/acos.zig -> lib/std/math/acos.zig | 0
Rstd/math/acosh.zig -> lib/std/math/acosh.zig | 0
Rstd/math/asin.zig -> lib/std/math/asin.zig | 0
Rstd/math/asinh.zig -> lib/std/math/asinh.zig | 0
Rstd/math/atan.zig -> lib/std/math/atan.zig | 0
Rstd/math/atan2.zig -> lib/std/math/atan2.zig | 0
Rstd/math/atanh.zig -> lib/std/math/atanh.zig | 0
Rstd/math/big.zig -> lib/std/math/big.zig | 0
Rstd/math/big/int.zig -> lib/std/math/big/int.zig | 0
Rstd/math/big/rational.zig -> lib/std/math/big/rational.zig | 0
Rstd/math/cbrt.zig -> lib/std/math/cbrt.zig | 0
Rstd/math/ceil.zig -> lib/std/math/ceil.zig | 0
Rstd/math/complex.zig -> lib/std/math/complex.zig | 0
Rstd/math/complex/abs.zig -> lib/std/math/complex/abs.zig | 0
Rstd/math/complex/acos.zig -> lib/std/math/complex/acos.zig | 0
Rstd/math/complex/acosh.zig -> lib/std/math/complex/acosh.zig | 0
Rstd/math/complex/arg.zig -> lib/std/math/complex/arg.zig | 0
Rstd/math/complex/asin.zig -> lib/std/math/complex/asin.zig | 0
Rstd/math/complex/asinh.zig -> lib/std/math/complex/asinh.zig | 0
Rstd/math/complex/atan.zig -> lib/std/math/complex/atan.zig | 0
Rstd/math/complex/atanh.zig -> lib/std/math/complex/atanh.zig | 0
Rstd/math/complex/conj.zig -> lib/std/math/complex/conj.zig | 0
Rstd/math/complex/cos.zig -> lib/std/math/complex/cos.zig | 0
Rstd/math/complex/cosh.zig -> lib/std/math/complex/cosh.zig | 0
Rstd/math/complex/exp.zig -> lib/std/math/complex/exp.zig | 0
Rstd/math/complex/ldexp.zig -> lib/std/math/complex/ldexp.zig | 0
Rstd/math/complex/log.zig -> lib/std/math/complex/log.zig | 0
Rstd/math/complex/pow.zig -> lib/std/math/complex/pow.zig | 0
Rstd/math/complex/proj.zig -> lib/std/math/complex/proj.zig | 0
Rstd/math/complex/sin.zig -> lib/std/math/complex/sin.zig | 0
Rstd/math/complex/sinh.zig -> lib/std/math/complex/sinh.zig | 0
Rstd/math/complex/sqrt.zig -> lib/std/math/complex/sqrt.zig | 0
Rstd/math/complex/tan.zig -> lib/std/math/complex/tan.zig | 0
Rstd/math/complex/tanh.zig -> lib/std/math/complex/tanh.zig | 0
Rstd/math/copysign.zig -> lib/std/math/copysign.zig | 0
Rstd/math/cos.zig -> lib/std/math/cos.zig | 0
Rstd/math/cosh.zig -> lib/std/math/cosh.zig | 0
Rstd/math/exp.zig -> lib/std/math/exp.zig | 0
Rstd/math/exp2.zig -> lib/std/math/exp2.zig | 0
Rstd/math/expm1.zig -> lib/std/math/expm1.zig | 0
Rstd/math/expo2.zig -> lib/std/math/expo2.zig | 0
Rstd/math/fabs.zig -> lib/std/math/fabs.zig | 0
Rstd/math/floor.zig -> lib/std/math/floor.zig | 0
Rstd/math/fma.zig -> lib/std/math/fma.zig | 0
Rstd/math/frexp.zig -> lib/std/math/frexp.zig | 0
Rstd/math/hypot.zig -> lib/std/math/hypot.zig | 0
Rstd/math/ilogb.zig -> lib/std/math/ilogb.zig | 0
Rstd/math/inf.zig -> lib/std/math/inf.zig | 0
Rstd/math/isfinite.zig -> lib/std/math/isfinite.zig | 0
Rstd/math/isinf.zig -> lib/std/math/isinf.zig | 0
Rstd/math/isnan.zig -> lib/std/math/isnan.zig | 0
Rstd/math/isnormal.zig -> lib/std/math/isnormal.zig | 0
Rstd/math/ln.zig -> lib/std/math/ln.zig | 0
Rstd/math/log.zig -> lib/std/math/log.zig | 0
Rstd/math/log10.zig -> lib/std/math/log10.zig | 0
Rstd/math/log1p.zig -> lib/std/math/log1p.zig | 0
Rstd/math/log2.zig -> lib/std/math/log2.zig | 0
Rstd/math/modf.zig -> lib/std/math/modf.zig | 0
Rstd/math/nan.zig -> lib/std/math/nan.zig | 0
Rstd/math/pow.zig -> lib/std/math/pow.zig | 0
Rstd/math/powi.zig -> lib/std/math/powi.zig | 0
Rstd/math/round.zig -> lib/std/math/round.zig | 0
Rstd/math/scalbn.zig -> lib/std/math/scalbn.zig | 0
Rstd/math/signbit.zig -> lib/std/math/signbit.zig | 0
Rstd/math/sin.zig -> lib/std/math/sin.zig | 0
Rstd/math/sinh.zig -> lib/std/math/sinh.zig | 0
Rstd/math/sqrt.zig -> lib/std/math/sqrt.zig | 0
Rstd/math/tan.zig -> lib/std/math/tan.zig | 0
Rstd/math/tanh.zig -> lib/std/math/tanh.zig | 0
Rstd/math/trunc.zig -> lib/std/math/trunc.zig | 0
Rstd/mem.zig -> lib/std/mem.zig | 0
Rstd/meta.zig -> lib/std/meta.zig | 0
Rstd/meta/trait.zig -> lib/std/meta/trait.zig | 0
Rstd/mutex.zig -> lib/std/mutex.zig | 0
Rstd/net.zig -> lib/std/net.zig | 0
Rstd/os.zig -> lib/std/os.zig | 0
Rstd/os/bits.zig -> lib/std/os/bits.zig | 0
Rstd/os/bits/darwin.zig -> lib/std/os/bits/darwin.zig | 0
Rstd/os/bits/freebsd.zig -> lib/std/os/bits/freebsd.zig | 0
Rstd/os/bits/linux.zig -> lib/std/os/bits/linux.zig | 0
Rstd/os/bits/linux/arm-eabi.zig -> lib/std/os/bits/linux/arm-eabi.zig | 0
Rstd/os/bits/linux/arm64.zig -> lib/std/os/bits/linux/arm64.zig | 0
Rstd/os/bits/linux/errno.zig -> lib/std/os/bits/linux/errno.zig | 0
Rstd/os/bits/linux/riscv64.zig -> lib/std/os/bits/linux/riscv64.zig | 0
Rstd/os/bits/linux/x86_64.zig -> lib/std/os/bits/linux/x86_64.zig | 0
Rstd/os/bits/netbsd.zig -> lib/std/os/bits/netbsd.zig | 0
Rstd/os/bits/wasi.zig -> lib/std/os/bits/wasi.zig | 0
Rstd/os/bits/windows.zig -> lib/std/os/bits/windows.zig | 0
Rstd/os/darwin.zig -> lib/std/os/darwin.zig | 0
Rstd/os/freebsd.zig -> lib/std/os/freebsd.zig | 0
Rstd/os/linux.zig -> lib/std/os/linux.zig | 0
Rstd/os/linux/arm-eabi.zig -> lib/std/os/linux/arm-eabi.zig | 0
Rstd/os/linux/arm64.zig -> lib/std/os/linux/arm64.zig | 0
Rstd/os/linux/riscv64.zig -> lib/std/os/linux/riscv64.zig | 0
Rstd/os/linux/test.zig -> lib/std/os/linux/test.zig | 0
Rstd/os/linux/tls.zig -> lib/std/os/linux/tls.zig | 0
Rstd/os/linux/vdso.zig -> lib/std/os/linux/vdso.zig | 0
Rstd/os/linux/x86_64.zig -> lib/std/os/linux/x86_64.zig | 0
Rstd/os/netbsd.zig -> lib/std/os/netbsd.zig | 0
Rstd/os/test.zig -> lib/std/os/test.zig | 0
Rstd/os/uefi.zig -> lib/std/os/uefi.zig | 0
Rstd/os/uefi/protocols.zig -> lib/std/os/uefi/protocols.zig | 0
Rstd/os/uefi/protocols/absolute_pointer_protocol.zig -> lib/std/os/uefi/protocols/absolute_pointer_protocol.zig | 0
Rstd/os/uefi/protocols/edid_active_protocol.zig -> lib/std/os/uefi/protocols/edid_active_protocol.zig | 0
Rstd/os/uefi/protocols/edid_discovered_protocol.zig -> lib/std/os/uefi/protocols/edid_discovered_protocol.zig | 0
Rstd/os/uefi/protocols/edid_override_protocol.zig -> lib/std/os/uefi/protocols/edid_override_protocol.zig | 0
Rstd/os/uefi/protocols/graphics_output_protocol.zig -> lib/std/os/uefi/protocols/graphics_output_protocol.zig | 0
Rstd/os/uefi/protocols/rng_protocol.zig -> lib/std/os/uefi/protocols/rng_protocol.zig | 0
Rstd/os/uefi/protocols/simple_pointer_protocol.zig -> lib/std/os/uefi/protocols/simple_pointer_protocol.zig | 0
Rstd/os/uefi/protocols/simple_text_input_ex_protocol.zig -> lib/std/os/uefi/protocols/simple_text_input_ex_protocol.zig | 0
Rstd/os/uefi/protocols/simple_text_output_protocol.zig -> lib/std/os/uefi/protocols/simple_text_output_protocol.zig | 0
Rstd/os/uefi/status.zig -> lib/std/os/uefi/status.zig | 0
Rstd/os/uefi/tables.zig -> lib/std/os/uefi/tables.zig | 0
Rstd/os/uefi/tables/boot_services.zig -> lib/std/os/uefi/tables/boot_services.zig | 0
Rstd/os/uefi/tables/configuration_table.zig -> lib/std/os/uefi/tables/configuration_table.zig | 0
Rstd/os/uefi/tables/runtime_services.zig -> lib/std/os/uefi/tables/runtime_services.zig | 0
Rstd/os/uefi/tables/system_table.zig -> lib/std/os/uefi/tables/system_table.zig | 0
Rstd/os/uefi/tables/table_header.zig -> lib/std/os/uefi/tables/table_header.zig | 0
Rstd/os/wasi.zig -> lib/std/os/wasi.zig | 0
Rstd/os/windows.zig -> lib/std/os/windows.zig | 0
Rstd/os/windows/advapi32.zig -> lib/std/os/windows/advapi32.zig | 0
Rstd/os/windows/bits.zig -> lib/std/os/windows/bits.zig | 0
Rstd/os/windows/error.zig -> lib/std/os/windows/error.zig | 0
Rstd/os/windows/kernel32.zig -> lib/std/os/windows/kernel32.zig | 0
Rstd/os/windows/lang.zig -> lib/std/os/windows/lang.zig | 0
Rstd/os/windows/ntdll.zig -> lib/std/os/windows/ntdll.zig | 0
Rstd/os/windows/ole32.zig -> lib/std/os/windows/ole32.zig | 0
Rstd/os/windows/shell32.zig -> lib/std/os/windows/shell32.zig | 0
Rstd/os/windows/status.zig -> lib/std/os/windows/status.zig | 0
Rstd/os/windows/sublang.zig -> lib/std/os/windows/sublang.zig | 0
Rstd/os/zen.zig -> lib/std/os/zen.zig | 0
Rstd/packed_int_array.zig -> lib/std/packed_int_array.zig | 0
Rstd/pdb.zig -> lib/std/pdb.zig | 0
Rstd/priority_queue.zig -> lib/std/priority_queue.zig | 0
Rstd/process.zig -> lib/std/process.zig | 0
Rstd/rand.zig -> lib/std/rand.zig | 0
Rstd/rand/ziggurat.zig -> lib/std/rand/ziggurat.zig | 0
Rstd/rb.zig -> lib/std/rb.zig | 0
Rstd/segmented_list.zig -> lib/std/segmented_list.zig | 0
Rstd/sort.zig -> lib/std/sort.zig | 0
Alib/std/special/build_runner.zig | 221+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rstd/special/c.zig -> lib/std/special/c.zig | 0
Rstd/special/compiler_rt.zig -> lib/std/special/compiler_rt.zig | 0
Rstd/special/compiler_rt/README.md -> lib/std/special/compiler_rt/README.md | 0
Rstd/special/compiler_rt/addXf3.zig -> lib/std/special/compiler_rt/addXf3.zig | 0
Rstd/special/compiler_rt/addXf3_test.zig -> lib/std/special/compiler_rt/addXf3_test.zig | 0
Rstd/special/compiler_rt/arm/aeabi_dcmp.zig -> lib/std/special/compiler_rt/arm/aeabi_dcmp.zig | 0
Rstd/special/compiler_rt/arm/aeabi_fcmp.zig -> lib/std/special/compiler_rt/arm/aeabi_fcmp.zig | 0
Rstd/special/compiler_rt/ashlti3.zig -> lib/std/special/compiler_rt/ashlti3.zig | 0
Rstd/special/compiler_rt/ashlti3_test.zig -> lib/std/special/compiler_rt/ashlti3_test.zig | 0
Rstd/special/compiler_rt/ashrti3.zig -> lib/std/special/compiler_rt/ashrti3.zig | 0
Rstd/special/compiler_rt/ashrti3_test.zig -> lib/std/special/compiler_rt/ashrti3_test.zig | 0
Rstd/special/compiler_rt/aulldiv.zig -> lib/std/special/compiler_rt/aulldiv.zig | 0
Rstd/special/compiler_rt/aullrem.zig -> lib/std/special/compiler_rt/aullrem.zig | 0
Rstd/special/compiler_rt/comparedf2.zig -> lib/std/special/compiler_rt/comparedf2.zig | 0
Rstd/special/compiler_rt/comparedf2_test.zig -> lib/std/special/compiler_rt/comparedf2_test.zig | 0
Rstd/special/compiler_rt/comparesf2.zig -> lib/std/special/compiler_rt/comparesf2.zig | 0
Rstd/special/compiler_rt/comparesf2_test.zig -> lib/std/special/compiler_rt/comparesf2_test.zig | 0
Rstd/special/compiler_rt/comparetf2.zig -> lib/std/special/compiler_rt/comparetf2.zig | 0
Rstd/special/compiler_rt/divdf3.zig -> lib/std/special/compiler_rt/divdf3.zig | 0
Rstd/special/compiler_rt/divdf3_test.zig -> lib/std/special/compiler_rt/divdf3_test.zig | 0
Rstd/special/compiler_rt/divsf3.zig -> lib/std/special/compiler_rt/divsf3.zig | 0
Rstd/special/compiler_rt/divsf3_test.zig -> lib/std/special/compiler_rt/divsf3_test.zig | 0
Rstd/special/compiler_rt/divti3.zig -> lib/std/special/compiler_rt/divti3.zig | 0
Rstd/special/compiler_rt/divti3_test.zig -> lib/std/special/compiler_rt/divti3_test.zig | 0
Rstd/special/compiler_rt/extendXfYf2.zig -> lib/std/special/compiler_rt/extendXfYf2.zig | 0
Rstd/special/compiler_rt/extendXfYf2_test.zig -> lib/std/special/compiler_rt/extendXfYf2_test.zig | 0
Rstd/special/compiler_rt/fixdfdi.zig -> lib/std/special/compiler_rt/fixdfdi.zig | 0
Rstd/special/compiler_rt/fixdfdi_test.zig -> lib/std/special/compiler_rt/fixdfdi_test.zig | 0
Rstd/special/compiler_rt/fixdfsi.zig -> lib/std/special/compiler_rt/fixdfsi.zig | 0
Rstd/special/compiler_rt/fixdfsi_test.zig -> lib/std/special/compiler_rt/fixdfsi_test.zig | 0
Rstd/special/compiler_rt/fixdfti.zig -> lib/std/special/compiler_rt/fixdfti.zig | 0
Rstd/special/compiler_rt/fixdfti_test.zig -> lib/std/special/compiler_rt/fixdfti_test.zig | 0
Rstd/special/compiler_rt/fixint.zig -> lib/std/special/compiler_rt/fixint.zig | 0
Rstd/special/compiler_rt/fixint_test.zig -> lib/std/special/compiler_rt/fixint_test.zig | 0
Rstd/special/compiler_rt/fixsfdi.zig -> lib/std/special/compiler_rt/fixsfdi.zig | 0
Rstd/special/compiler_rt/fixsfdi_test.zig -> lib/std/special/compiler_rt/fixsfdi_test.zig | 0
Rstd/special/compiler_rt/fixsfsi.zig -> lib/std/special/compiler_rt/fixsfsi.zig | 0
Rstd/special/compiler_rt/fixsfsi_test.zig -> lib/std/special/compiler_rt/fixsfsi_test.zig | 0
Rstd/special/compiler_rt/fixsfti.zig -> lib/std/special/compiler_rt/fixsfti.zig | 0
Rstd/special/compiler_rt/fixsfti_test.zig -> lib/std/special/compiler_rt/fixsfti_test.zig | 0
Rstd/special/compiler_rt/fixtfdi.zig -> lib/std/special/compiler_rt/fixtfdi.zig | 0
Rstd/special/compiler_rt/fixtfdi_test.zig -> lib/std/special/compiler_rt/fixtfdi_test.zig | 0
Rstd/special/compiler_rt/fixtfsi.zig -> lib/std/special/compiler_rt/fixtfsi.zig | 0
Rstd/special/compiler_rt/fixtfsi_test.zig -> lib/std/special/compiler_rt/fixtfsi_test.zig | 0
Rstd/special/compiler_rt/fixtfti.zig -> lib/std/special/compiler_rt/fixtfti.zig | 0
Rstd/special/compiler_rt/fixtfti_test.zig -> lib/std/special/compiler_rt/fixtfti_test.zig | 0
Rstd/special/compiler_rt/fixuint.zig -> lib/std/special/compiler_rt/fixuint.zig | 0
Rstd/special/compiler_rt/fixunsdfdi.zig -> lib/std/special/compiler_rt/fixunsdfdi.zig | 0
Rstd/special/compiler_rt/fixunsdfdi_test.zig -> lib/std/special/compiler_rt/fixunsdfdi_test.zig | 0
Rstd/special/compiler_rt/fixunsdfsi.zig -> lib/std/special/compiler_rt/fixunsdfsi.zig | 0
Rstd/special/compiler_rt/fixunsdfsi_test.zig -> lib/std/special/compiler_rt/fixunsdfsi_test.zig | 0
Rstd/special/compiler_rt/fixunsdfti.zig -> lib/std/special/compiler_rt/fixunsdfti.zig | 0
Rstd/special/compiler_rt/fixunsdfti_test.zig -> lib/std/special/compiler_rt/fixunsdfti_test.zig | 0
Rstd/special/compiler_rt/fixunssfdi.zig -> lib/std/special/compiler_rt/fixunssfdi.zig | 0
Rstd/special/compiler_rt/fixunssfdi_test.zig -> lib/std/special/compiler_rt/fixunssfdi_test.zig | 0
Rstd/special/compiler_rt/fixunssfsi.zig -> lib/std/special/compiler_rt/fixunssfsi.zig | 0
Rstd/special/compiler_rt/fixunssfsi_test.zig -> lib/std/special/compiler_rt/fixunssfsi_test.zig | 0
Rstd/special/compiler_rt/fixunssfti.zig -> lib/std/special/compiler_rt/fixunssfti.zig | 0
Rstd/special/compiler_rt/fixunssfti_test.zig -> lib/std/special/compiler_rt/fixunssfti_test.zig | 0
Rstd/special/compiler_rt/fixunstfdi.zig -> lib/std/special/compiler_rt/fixunstfdi.zig | 0
Rstd/special/compiler_rt/fixunstfdi_test.zig -> lib/std/special/compiler_rt/fixunstfdi_test.zig | 0
Rstd/special/compiler_rt/fixunstfsi.zig -> lib/std/special/compiler_rt/fixunstfsi.zig | 0
Rstd/special/compiler_rt/fixunstfsi_test.zig -> lib/std/special/compiler_rt/fixunstfsi_test.zig | 0
Rstd/special/compiler_rt/fixunstfti.zig -> lib/std/special/compiler_rt/fixunstfti.zig | 0
Rstd/special/compiler_rt/fixunstfti_test.zig -> lib/std/special/compiler_rt/fixunstfti_test.zig | 0
Rstd/special/compiler_rt/floatdidf.zig -> lib/std/special/compiler_rt/floatdidf.zig | 0
Rstd/special/compiler_rt/floatdidf_test.zig -> lib/std/special/compiler_rt/floatdidf_test.zig | 0
Rstd/special/compiler_rt/floatsiXf.zig -> lib/std/special/compiler_rt/floatsiXf.zig | 0
Rstd/special/compiler_rt/floattidf.zig -> lib/std/special/compiler_rt/floattidf.zig | 0
Rstd/special/compiler_rt/floattidf_test.zig -> lib/std/special/compiler_rt/floattidf_test.zig | 0
Rstd/special/compiler_rt/floattisf.zig -> lib/std/special/compiler_rt/floattisf.zig | 0
Rstd/special/compiler_rt/floattisf_test.zig -> lib/std/special/compiler_rt/floattisf_test.zig | 0
Rstd/special/compiler_rt/floattitf.zig -> lib/std/special/compiler_rt/floattitf.zig | 0
Rstd/special/compiler_rt/floattitf_test.zig -> lib/std/special/compiler_rt/floattitf_test.zig | 0
Rstd/special/compiler_rt/floatundidf.zig -> lib/std/special/compiler_rt/floatundidf.zig | 0
Rstd/special/compiler_rt/floatundidf_test.zig -> lib/std/special/compiler_rt/floatundidf_test.zig | 0
Rstd/special/compiler_rt/floatunditf.zig -> lib/std/special/compiler_rt/floatunditf.zig | 0
Rstd/special/compiler_rt/floatunditf_test.zig -> lib/std/special/compiler_rt/floatunditf_test.zig | 0
Rstd/special/compiler_rt/floatunsidf.zig -> lib/std/special/compiler_rt/floatunsidf.zig | 0
Rstd/special/compiler_rt/floatunsitf.zig -> lib/std/special/compiler_rt/floatunsitf.zig | 0
Rstd/special/compiler_rt/floatunsitf_test.zig -> lib/std/special/compiler_rt/floatunsitf_test.zig | 0
Rstd/special/compiler_rt/floatuntidf.zig -> lib/std/special/compiler_rt/floatuntidf.zig | 0
Rstd/special/compiler_rt/floatuntidf_test.zig -> lib/std/special/compiler_rt/floatuntidf_test.zig | 0
Rstd/special/compiler_rt/floatuntisf.zig -> lib/std/special/compiler_rt/floatuntisf.zig | 0
Rstd/special/compiler_rt/floatuntisf_test.zig -> lib/std/special/compiler_rt/floatuntisf_test.zig | 0
Rstd/special/compiler_rt/floatuntitf.zig -> lib/std/special/compiler_rt/floatuntitf.zig | 0
Rstd/special/compiler_rt/floatuntitf_test.zig -> lib/std/special/compiler_rt/floatuntitf_test.zig | 0
Rstd/special/compiler_rt/lshrti3.zig -> lib/std/special/compiler_rt/lshrti3.zig | 0
Rstd/special/compiler_rt/lshrti3_test.zig -> lib/std/special/compiler_rt/lshrti3_test.zig | 0
Rstd/special/compiler_rt/modti3.zig -> lib/std/special/compiler_rt/modti3.zig | 0
Rstd/special/compiler_rt/modti3_test.zig -> lib/std/special/compiler_rt/modti3_test.zig | 0
Rstd/special/compiler_rt/mulXf3.zig -> lib/std/special/compiler_rt/mulXf3.zig | 0
Rstd/special/compiler_rt/mulXf3_test.zig -> lib/std/special/compiler_rt/mulXf3_test.zig | 0
Rstd/special/compiler_rt/muldi3.zig -> lib/std/special/compiler_rt/muldi3.zig | 0
Rstd/special/compiler_rt/muldi3_test.zig -> lib/std/special/compiler_rt/muldi3_test.zig | 0
Rstd/special/compiler_rt/mulodi4.zig -> lib/std/special/compiler_rt/mulodi4.zig | 0
Rstd/special/compiler_rt/mulodi4_test.zig -> lib/std/special/compiler_rt/mulodi4_test.zig | 0
Rstd/special/compiler_rt/muloti4.zig -> lib/std/special/compiler_rt/muloti4.zig | 0
Rstd/special/compiler_rt/muloti4_test.zig -> lib/std/special/compiler_rt/muloti4_test.zig | 0
Rstd/special/compiler_rt/multi3.zig -> lib/std/special/compiler_rt/multi3.zig | 0
Rstd/special/compiler_rt/multi3_test.zig -> lib/std/special/compiler_rt/multi3_test.zig | 0
Rstd/special/compiler_rt/negXf2.zig -> lib/std/special/compiler_rt/negXf2.zig | 0
Rstd/special/compiler_rt/popcountdi2.zig -> lib/std/special/compiler_rt/popcountdi2.zig | 0
Rstd/special/compiler_rt/popcountdi2_test.zig -> lib/std/special/compiler_rt/popcountdi2_test.zig | 0
Rstd/special/compiler_rt/stack_probe.zig -> lib/std/special/compiler_rt/stack_probe.zig | 0
Rstd/special/compiler_rt/truncXfYf2.zig -> lib/std/special/compiler_rt/truncXfYf2.zig | 0
Rstd/special/compiler_rt/truncXfYf2_test.zig -> lib/std/special/compiler_rt/truncXfYf2_test.zig | 0
Rstd/special/compiler_rt/udivmod.zig -> lib/std/special/compiler_rt/udivmod.zig | 0
Rstd/special/compiler_rt/udivmoddi4.zig -> lib/std/special/compiler_rt/udivmoddi4.zig | 0
Rstd/special/compiler_rt/udivmoddi4_test.zig -> lib/std/special/compiler_rt/udivmoddi4_test.zig | 0
Rstd/special/compiler_rt/udivmodti4.zig -> lib/std/special/compiler_rt/udivmodti4.zig | 0
Rstd/special/compiler_rt/udivmodti4_test.zig -> lib/std/special/compiler_rt/udivmodti4_test.zig | 0
Rstd/special/compiler_rt/udivti3.zig -> lib/std/special/compiler_rt/udivti3.zig | 0
Rstd/special/compiler_rt/umodti3.zig -> lib/std/special/compiler_rt/umodti3.zig | 0
Rstd/special/init-exe/build.zig -> lib/std/special/init-exe/build.zig | 0
Rstd/special/init-exe/src/main.zig -> lib/std/special/init-exe/src/main.zig | 0
Rstd/special/init-lib/build.zig -> lib/std/special/init-lib/build.zig | 0
Rstd/special/init-lib/src/main.zig -> lib/std/special/init-lib/src/main.zig | 0
Rstd/special/panic.zig -> lib/std/special/panic.zig | 0
Rstd/special/start.zig -> lib/std/special/start.zig | 0
Rstd/special/start_lib.zig -> lib/std/special/start_lib.zig | 0
Rstd/special/start_windows_tls.zig -> lib/std/special/start_windows_tls.zig | 0
Rstd/special/test_runner.zig -> lib/std/special/test_runner.zig | 0
Rstd/spinlock.zig -> lib/std/spinlock.zig | 0
Rstd/statically_initialized_mutex.zig -> lib/std/statically_initialized_mutex.zig | 0
Rstd/std.zig -> lib/std/std.zig | 0
Rstd/testing.zig -> lib/std/testing.zig | 0
Rstd/thread.zig -> lib/std/thread.zig | 0
Rstd/time.zig -> lib/std/time.zig | 0
Rstd/time/epoch.zig -> lib/std/time/epoch.zig | 0
Rstd/unicode.zig -> lib/std/unicode.zig | 0
Rstd/unicode/throughput_test.zig -> lib/std/unicode/throughput_test.zig | 0
Rstd/valgrind.zig -> lib/std/valgrind.zig | 0
Rstd/valgrind/callgrind.zig -> lib/std/valgrind/callgrind.zig | 0
Rstd/valgrind/memcheck.zig -> lib/std/valgrind/memcheck.zig | 0
Rstd/zig.zig -> lib/std/zig.zig | 0
Rstd/zig/ast.zig -> lib/std/zig/ast.zig | 0
Rstd/zig/parse.zig -> lib/std/zig/parse.zig | 0
Rstd/zig/parse_string_literal.zig -> lib/std/zig/parse_string_literal.zig | 0
Rstd/zig/parser_test.zig -> lib/std/zig/parser_test.zig | 0
Rstd/zig/perf_test.zig -> lib/std/zig/perf_test.zig | 0
Rstd/zig/render.zig -> lib/std/zig/render.zig | 0
Rstd/zig/tokenizer.zig -> lib/std/zig/tokenizer.zig | 0
Msrc/codegen.cpp | 13++++---------
Msrc/codegen.hpp | 2+-
Msrc/compiler.cpp | 56+++++++++++++++++++++++++++-----------------------------
Msrc/main.cpp | 18++++--------------
Dstd/build.zig | 2743-------------------------------------------------------------------------------
Dstd/special/build_runner.zig | 227-------------------------------------------------------------------------------
Mtest/tests.zig | 2+-
380 files changed, 2992 insertions(+), 3033 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -601,8 +601,7 @@ else() endif() add_custom_target(zig_build_libuserland ALL COMMAND zig0 build - --override-std-dir std - --override-lib-dir "${CMAKE_SOURCE_DIR}" + --override-lib-dir "${CMAKE_SOURCE_DIR}/lib" libuserland install "-Doutput-dir=${CMAKE_BINARY_DIR}" "-Drelease=${LIBUSERLAND_RELEASE_MODE}" diff --git a/build.zig b/build.zig @@ -87,11 +87,6 @@ pub fn build(b: *Builder) !void { .source_dir = "lib", .install_dir = .Lib, .install_subdir = "zig", - }); - b.installDirectory(InstallDirectoryOptions{ - .source_dir = "std", - .install_dir = .Lib, - .install_subdir = "zig" ++ fs.path.sep_str ++ "std", .exclude_extensions = [_][]const u8{ "test.zig", "README.md" }, }); @@ -134,9 +129,9 @@ pub fn build(b: *Builder) !void { test_step.dependOn(tests.addPkgTests(b, test_filter, "test/stage1/behavior.zig", "behavior", "Run the behavior tests", modes, false, skip_non_native, skip_libc, is_wine_enabled, is_qemu_enabled, glibc_multi_dir)); - test_step.dependOn(tests.addPkgTests(b, test_filter, "std/std.zig", "std", "Run the standard library tests", modes, false, skip_non_native, skip_libc, is_wine_enabled, is_qemu_enabled, glibc_multi_dir)); + test_step.dependOn(tests.addPkgTests(b, test_filter, "lib/std/std.zig", "std", "Run the standard library tests", modes, false, skip_non_native, skip_libc, is_wine_enabled, is_qemu_enabled, glibc_multi_dir)); - test_step.dependOn(tests.addPkgTests(b, test_filter, "std/special/compiler_rt.zig", "compiler-rt", "Run the compiler_rt tests", modes, true, skip_non_native, true, is_wine_enabled, is_qemu_enabled, glibc_multi_dir)); + test_step.dependOn(tests.addPkgTests(b, test_filter, "lib/std/special/compiler_rt.zig", "compiler-rt", "Run the compiler_rt tests", modes, true, skip_non_native, true, is_wine_enabled, is_qemu_enabled, glibc_multi_dir)); test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes)); test_step.dependOn(tests.addStandaloneTests(b, test_filter, modes)); diff --git a/std/array_list.zig b/lib/std/array_list.zig diff --git a/std/ascii.zig b/lib/std/ascii.zig diff --git a/std/atomic.zig b/lib/std/atomic.zig diff --git a/std/atomic/int.zig b/lib/std/atomic/int.zig diff --git a/std/atomic/queue.zig b/lib/std/atomic/queue.zig diff --git a/std/atomic/stack.zig b/lib/std/atomic/stack.zig diff --git a/std/base64.zig b/lib/std/base64.zig diff --git a/std/bloom_filter.zig b/lib/std/bloom_filter.zig diff --git a/std/buf_map.zig b/lib/std/buf_map.zig diff --git a/std/buf_set.zig b/lib/std/buf_set.zig diff --git a/std/buffer.zig b/lib/std/buffer.zig diff --git a/lib/std/build.zig b/lib/std/build.zig @@ -0,0 +1,2731 @@ +const std = @import("std.zig"); +const builtin = @import("builtin"); +const io = std.io; +const fs = std.fs; +const mem = std.mem; +const debug = std.debug; +const panic = std.debug.panic; +const assert = debug.assert; +const warn = std.debug.warn; +const ArrayList = std.ArrayList; +const StringHashMap = std.StringHashMap; +const Allocator = mem.Allocator; +const process = std.process; +const BufSet = std.BufSet; +const BufMap = std.BufMap; +const fmt_lib = std.fmt; +const File = std.fs.File; + +pub const FmtStep = @import("build/fmt.zig").FmtStep; + +pub const Builder = struct { + install_tls: TopLevelStep, + uninstall_tls: TopLevelStep, + allocator: *Allocator, + native_system_lib_paths: ArrayList([]const u8), + native_system_include_dirs: ArrayList([]const u8), + native_system_rpaths: ArrayList([]const u8), + user_input_options: UserInputOptionsMap, + available_options_map: AvailableOptionsMap, + available_options_list: ArrayList(AvailableOption), + verbose: bool, + verbose_tokenize: bool, + verbose_ast: bool, + verbose_link: bool, + verbose_cc: bool, + verbose_ir: bool, + verbose_llvm_ir: bool, + verbose_cimport: bool, + invalid_user_input: bool, + zig_exe: []const u8, + default_step: *Step, + env_map: *BufMap, + top_level_steps: ArrayList(*TopLevelStep), + install_prefix: ?[]const u8, + dest_dir: ?[]const u8, + lib_dir: []const u8, + exe_dir: []const u8, + install_path: []const u8, + search_prefixes: ArrayList([]const u8), + installed_files: ArrayList(InstalledFile), + build_root: []const u8, + cache_root: []const u8, + release_mode: ?builtin.Mode, + is_release: bool, + override_lib_dir: ?[]const u8, + + pkg_config_pkg_list: ?(PkgConfigError![]const PkgConfigPkg) = null, + + const PkgConfigError = error{ + PkgConfigCrashed, + PkgConfigFailed, + PkgConfigNotInstalled, + PkgConfigInvalidOutput, + }; + + pub const PkgConfigPkg = struct { + name: []const u8, + desc: []const u8, + }; + + pub const CStd = enum { + C89, + C99, + C11, + }; + + const UserInputOptionsMap = StringHashMap(UserInputOption); + const AvailableOptionsMap = StringHashMap(AvailableOption); + + const AvailableOption = struct { + name: []const u8, + type_id: TypeId, + description: []const u8, + }; + + const UserInputOption = struct { + name: []const u8, + value: UserValue, + used: bool, + }; + + const UserValue = union(enum) { + Flag: void, + Scalar: []const u8, + List: ArrayList([]const u8), + }; + + const TypeId = enum { + Bool, + Int, + Float, + String, + List, + }; + + const TopLevelStep = struct { + step: Step, + description: []const u8, + }; + + pub fn create( + allocator: *Allocator, + zig_exe: []const u8, + build_root: []const u8, + cache_root: []const u8, + ) !*Builder { + const env_map = try allocator.create(BufMap); + env_map.* = try process.getEnvMap(allocator); + + const self = try allocator.create(Builder); + self.* = Builder{ + .zig_exe = zig_exe, + .build_root = build_root, + .cache_root = try fs.path.relative(allocator, build_root, cache_root), + .verbose = false, + .verbose_tokenize = false, + .verbose_ast = false, + .verbose_link = false, + .verbose_cc = false, + .verbose_ir = false, + .verbose_llvm_ir = false, + .verbose_cimport = false, + .invalid_user_input = false, + .allocator = allocator, + .native_system_lib_paths = ArrayList([]const u8).init(allocator), + .native_system_include_dirs = ArrayList([]const u8).init(allocator), + .native_system_rpaths = ArrayList([]const u8).init(allocator), + .user_input_options = UserInputOptionsMap.init(allocator), + .available_options_map = AvailableOptionsMap.init(allocator), + .available_options_list = ArrayList(AvailableOption).init(allocator), + .top_level_steps = ArrayList(*TopLevelStep).init(allocator), + .default_step = undefined, + .env_map = env_map, + .search_prefixes = ArrayList([]const u8).init(allocator), + .install_prefix = null, + .lib_dir = undefined, + .exe_dir = undefined, + .dest_dir = env_map.get("DESTDIR"), + .installed_files = ArrayList(InstalledFile).init(allocator), + .install_tls = TopLevelStep{ + .step = Step.initNoOp("install", allocator), + .description = "Copy build artifacts to prefix path", + }, + .uninstall_tls = TopLevelStep{ + .step = Step.init("uninstall", allocator, makeUninstall), + .description = "Remove build artifacts from prefix path", + }, + .release_mode = null, + .is_release = false, + .override_lib_dir = null, + .install_path = undefined, + }; + try self.top_level_steps.append(&self.install_tls); + try self.top_level_steps.append(&self.uninstall_tls); + self.detectNativeSystemPaths(); + self.default_step = &self.install_tls.step; + return self; + } + + pub fn destroy(self: *Builder) void { + self.native_system_lib_paths.deinit(); + self.native_system_include_dirs.deinit(); + self.native_system_rpaths.deinit(); + self.env_map.deinit(); + self.top_level_steps.deinit(); + self.allocator.destroy(self); + } + + /// This function is intended to be called by std/special/build_runner.zig, not a build.zig file. + pub fn setInstallPrefix(self: *Builder, optional_prefix: ?[]const u8) void { + self.install_prefix = optional_prefix; + } + + /// This function is intended to be called by std/special/build_runner.zig, not a build.zig file. + pub fn resolveInstallPrefix(self: *Builder) void { + if (self.dest_dir) |dest_dir| { + const install_prefix = self.install_prefix orelse "/usr"; + self.install_path = fs.path.join(self.allocator, [_][]const u8{ dest_dir, install_prefix }) catch unreachable; + } else { + const install_prefix = self.install_prefix orelse blk: { + const p = self.cache_root; + self.install_prefix = p; + break :blk p; + }; + self.install_path = install_prefix; + } + self.lib_dir = fs.path.join(self.allocator, [_][]const u8{ self.install_path, "lib" }) catch unreachable; + self.exe_dir = fs.path.join(self.allocator, [_][]const u8{ self.install_path, "bin" }) catch unreachable; + } + + pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { + return LibExeObjStep.createExecutable(self, name, root_src, false); + } + + pub fn addObject(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { + return LibExeObjStep.createObject(self, name, root_src); + } + + pub fn addSharedLibrary(self: *Builder, name: []const u8, root_src: ?[]const u8, ver: Version) *LibExeObjStep { + return LibExeObjStep.createSharedLibrary(self, name, root_src, ver); + } + + pub fn addStaticLibrary(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { + return LibExeObjStep.createStaticLibrary(self, name, root_src); + } + + pub fn addTest(self: *Builder, root_src: []const u8) *LibExeObjStep { + return LibExeObjStep.createTest(self, "test", root_src); + } + + pub fn addAssemble(self: *Builder, name: []const u8, src: []const u8) *LibExeObjStep { + const obj_step = LibExeObjStep.createObject(self, name, null); + obj_step.addAssemblyFile(src); + return obj_step; + } + + /// Initializes a RunStep with argv, which must at least have the path to the + /// executable. More command line arguments can be added with `addArg`, + /// `addArgs`, and `addArtifactArg`. + /// Be careful using this function, as it introduces a system dependency. + /// To run an executable built with zig build, see `LibExeObjStep.run`. + pub fn addSystemCommand(self: *Builder, argv: []const []const u8) *RunStep { + assert(argv.len >= 1); + const run_step = RunStep.create(self, self.fmt("run {}", argv[0])); + run_step.addArgs(argv); + return run_step; + } + + fn dupe(self: *Builder, bytes: []const u8) []u8 { + return mem.dupe(self.allocator, u8, bytes) catch unreachable; + } + + fn dupePath(self: *Builder, bytes: []const u8) []u8 { + const the_copy = self.dupe(bytes); + for (the_copy) |*byte| { + switch (byte.*) { + '/', '\\' => byte.* = fs.path.sep, + else => {}, + } + } + return the_copy; + } + + pub fn addWriteFile(self: *Builder, file_path: []const u8, data: []const u8) *WriteFileStep { + const write_file_step = self.allocator.create(WriteFileStep) catch unreachable; + write_file_step.* = WriteFileStep.init(self, file_path, data); + return write_file_step; + } + + pub fn addLog(self: *Builder, comptime format: []const u8, args: ...) *LogStep { + const data = self.fmt(format, args); + const log_step = self.allocator.create(LogStep) catch unreachable; + log_step.* = LogStep.init(self, data); + return log_step; + } + + pub fn addRemoveDirTree(self: *Builder, dir_path: []const u8) *RemoveDirStep { + const remove_dir_step = self.allocator.create(RemoveDirStep) catch unreachable; + remove_dir_step.* = RemoveDirStep.init(self, dir_path); + return remove_dir_step; + } + + pub fn addFmt(self: *Builder, paths: []const []const u8) *FmtStep { + return FmtStep.create(self, paths); + } + + pub fn version(self: *const Builder, major: u32, minor: u32, patch: u32) Version { + return Version{ + .major = major, + .minor = minor, + .patch = patch, + }; + } + + pub fn addNativeSystemIncludeDir(self: *Builder, path: []const u8) void { + self.native_system_include_dirs.append(path) catch unreachable; + } + + pub fn addNativeSystemRPath(self: *Builder, path: []const u8) void { + self.native_system_rpaths.append(path) catch unreachable; + } + + pub fn addNativeSystemLibPath(self: *Builder, path: []const u8) void { + self.native_system_lib_paths.append(path) catch unreachable; + } + + pub fn make(self: *Builder, step_names: []const []const u8) !void { + try self.makePath(self.cache_root); + + var wanted_steps = ArrayList(*Step).init(self.allocator); + defer wanted_steps.deinit(); + + if (step_names.len == 0) { + try wanted_steps.append(self.default_step); + } else { + for (step_names) |step_name| { + const s = try self.getTopLevelStepByName(step_name); + try wanted_steps.append(s); + } + } + + for (wanted_steps.toSliceConst()) |s| { + try self.makeOneStep(s); + } + } + + pub fn getInstallStep(self: *Builder) *Step { + return &self.install_tls.step; + } + + pub fn getUninstallStep(self: *Builder) *Step { + return &self.uninstall_tls.step; + } + + fn makeUninstall(uninstall_step: *Step) anyerror!void { + const uninstall_tls = @fieldParentPtr(TopLevelStep, "step", uninstall_step); + const self = @fieldParentPtr(Builder, "uninstall_tls", uninstall_tls); + + for (self.installed_files.toSliceConst()) |installed_file| { + const full_path = self.getInstallPath(installed_file.dir, installed_file.path); + if (self.verbose) { + warn("rm {}\n", full_path); + } + fs.deleteTree(self.allocator, full_path) catch {}; + } + + // TODO remove empty directories + } + + fn makeOneStep(self: *Builder, s: *Step) anyerror!void { + if (s.loop_flag) { + warn("Dependency loop detected:\n {}\n", s.name); + return error.DependencyLoopDetected; + } + s.loop_flag = true; + + for (s.dependencies.toSlice()) |dep| { + self.makeOneStep(dep) catch |err| { + if (err == error.DependencyLoopDetected) { + warn(" {}\n", s.name); + } + return err; + }; + } + + s.loop_flag = false; + + try s.make(); + } + + fn getTopLevelStepByName(self: *Builder, name: []const u8) !*Step { + for (self.top_level_steps.toSliceConst()) |top_level_step| { + if (mem.eql(u8, top_level_step.step.name, name)) { + return &top_level_step.step; + } + } + warn("Cannot run step '{}' because it does not exist\n", name); + return error.InvalidStepName; + } + + fn detectNativeSystemPaths(self: *Builder) void { + var is_nixos = false; + if (process.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| { + is_nixos = true; + var it = mem.tokenize(nix_cflags_compile, " "); + while (true) { + const word = it.next() orelse break; + if (mem.eql(u8, word, "-isystem")) { + const include_path = it.next() orelse { + warn("Expected argument after -isystem in NIX_CFLAGS_COMPILE\n"); + break; + }; + self.addNativeSystemIncludeDir(include_path); + } else { + warn("Unrecognized C flag from NIX_CFLAGS_COMPILE: {}\n", word); + break; + } + } + } else |err| { + assert(err == error.EnvironmentVariableNotFound); + } + if (process.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| { + is_nixos = true; + var it = mem.tokenize(nix_ldflags, " "); + while (true) { + const word = it.next() orelse break; + if (mem.eql(u8, word, "-rpath")) { + const rpath = it.next() orelse { + warn("Expected argument after -rpath in NIX_LDFLAGS\n"); + break; + }; + self.addNativeSystemRPath(rpath); + } else if (word.len > 2 and word[0] == '-' and word[1] == 'L') { + const lib_path = word[2..]; + self.addNativeSystemLibPath(lib_path); + } else { + warn("Unrecognized C flag from NIX_LDFLAGS: {}\n", word); + break; + } + } + } else |err| { + assert(err == error.EnvironmentVariableNotFound); + } + if (is_nixos) return; + switch (builtin.os) { + .windows => {}, + else => { + const triple = (Target{ + .Cross = CrossTarget{ + .arch = builtin.arch, + .os = builtin.os, + .abi = builtin.abi, + }, + }).linuxTriple(self.allocator); + + // TODO: $ ld --verbose | grep SEARCH_DIR + // the output contains some paths that end with lib64, maybe include them too? + // also, what is the best possible order of things? + + self.addNativeSystemIncludeDir("/usr/local/include"); + self.addNativeSystemLibPath("/usr/local/lib"); + + self.addNativeSystemIncludeDir(self.fmt("/usr/include/{}", triple)); + self.addNativeSystemLibPath(self.fmt("/usr/lib/{}", triple)); + + self.addNativeSystemIncludeDir("/usr/include"); + self.addNativeSystemLibPath("/usr/lib"); + + // example: on a 64-bit debian-based linux distro, with zlib installed from apt: + // zlib.h is in /usr/include (added above) + // libz.so.1 is in /lib/x86_64-linux-gnu (added here) + self.addNativeSystemLibPath(self.fmt("/lib/{}", triple)); + }, + } + } + + pub fn option(self: *Builder, comptime T: type, name: []const u8, description: []const u8) ?T { + const type_id = comptime typeToEnum(T); + const available_option = AvailableOption{ + .name = name, + .type_id = type_id, + .description = description, + }; + if ((self.available_options_map.put(name, available_option) catch unreachable) != null) { + panic("Option '{}' declared twice", name); + } + self.available_options_list.append(available_option) catch unreachable; + + const entry = self.user_input_options.get(name) orelse return null; + entry.value.used = true; + switch (type_id) { + TypeId.Bool => switch (entry.value.value) { + UserValue.Flag => return true, + UserValue.Scalar => |s| { + if (mem.eql(u8, s, "true")) { + return true; + } else if (mem.eql(u8, s, "false")) { + return false; + } else { + warn("Expected -D{} to be a boolean, but received '{}'\n", name, s); + self.markInvalidUserInput(); + return null; + } + }, + UserValue.List => { + warn("Expected -D{} to be a boolean, but received a list.\n", name); + self.markInvalidUserInput(); + return null; + }, + }, + TypeId.Int => panic("TODO integer options to build script"), + TypeId.Float => panic("TODO float options to build script"), + TypeId.String => switch (entry.value.value) { + UserValue.Flag => { + warn("Expected -D{} to be a string, but received a boolean.\n", name); + self.markInvalidUserInput(); + return null; + }, + UserValue.List => { + warn("Expected -D{} to be a string, but received a list.\n", name); + self.markInvalidUserInput(); + return null; + }, + UserValue.Scalar => |s| return s, + }, + TypeId.List => panic("TODO list options to build script"), + } + } + + pub fn step(self: *Builder, name: []const u8, description: []const u8) *Step { + const step_info = self.allocator.create(TopLevelStep) catch unreachable; + step_info.* = TopLevelStep{ + .step = Step.initNoOp(name, self.allocator), + .description = description, + }; + self.top_level_steps.append(step_info) catch unreachable; + return &step_info.step; + } + + /// This provides the -Drelease option to the build user and does not give them the choice. + pub fn setPreferredReleaseMode(self: *Builder, mode: builtin.Mode) void { + if (self.release_mode != null) { + @panic("setPreferredReleaseMode must be called before standardReleaseOptions and may not be called twice"); + } + const description = self.fmt("create a release build ({})", @tagName(mode)); + self.is_release = self.option(bool, "release", description) orelse false; + self.release_mode = if (self.is_release) mode else builtin.Mode.Debug; + } + + /// If you call this without first calling `setPreferredReleaseMode` then it gives the build user + /// the choice of what kind of release. + pub fn standardReleaseOptions(self: *Builder) builtin.Mode { + if (self.release_mode) |mode| return mode; + + const release_safe = self.option(bool, "release-safe", "optimizations on and safety on") orelse false; + const release_fast = self.option(bool, "release-fast", "optimizations on and safety off") orelse false; + const release_small = self.option(bool, "release-small", "size optimizations on and safety off") orelse false; + + const mode = if (release_safe and !release_fast and !release_small) + builtin.Mode.ReleaseSafe + else if (release_fast and !release_safe and !release_small) + builtin.Mode.ReleaseFast + else if (release_small and !release_fast and !release_safe) + builtin.Mode.ReleaseSmall + else if (!release_fast and !release_safe and !release_small) + builtin.Mode.Debug + else x: { + warn("Multiple release modes (of -Drelease-safe, -Drelease-fast and -Drelease-small)"); + self.markInvalidUserInput(); + break :x builtin.Mode.Debug; + }; + self.is_release = mode != .Debug; + self.release_mode = mode; + return mode; + } + + /// Exposes standard `zig build` options for choosing a target. Pass `null` to support all targets. + pub fn standardTargetOptions(self: *Builder, supported_targets: ?[]const Target) Target { + if (supported_targets) |target_list| { + // TODO detect multiple args and emit an error message + // there's probably a better way to collect the target + for (target_list) |targ| { + const targ_str = targ.zigTriple(self.allocator) catch unreachable; + const targ_desc = targ.allocDescription(self.allocator) catch unreachable; + const this_targ_opt = self.option(bool, targ_str, targ_desc) orelse false; + if (this_targ_opt) { + return targ; + } + } + return Target.Native; + } else { + const target_str = self.option([]const u8, "target", "the target to build for") orelse return Target.Native; + return Target.parse(target_str) catch unreachable; // TODO better error message for bad target + } + } + + pub fn addUserInputOption(self: *Builder, name: []const u8, value: []const u8) !bool { + const gop = try self.user_input_options.getOrPut(name); + if (!gop.found_existing) { + gop.kv.value = UserInputOption{ + .name = name, + .value = UserValue{ .Scalar = value }, + .used = false, + }; + return false; + } + + // option already exists + switch (gop.kv.value.value) { + UserValue.Scalar => |s| { + // turn it into a list + var list = ArrayList([]const u8).init(self.allocator); + list.append(s) catch unreachable; + list.append(value) catch unreachable; + _ = self.user_input_options.put(name, UserInputOption{ + .name = name, + .value = UserValue{ .List = list }, + .used = false, + }) catch unreachable; + }, + UserValue.List => |*list| { + // append to the list + list.append(value) catch unreachable; + _ = self.user_input_options.put(name, UserInputOption{ + .name = name, + .value = UserValue{ .List = list.* }, + .used = false, + }) catch unreachable; + }, + UserValue.Flag => { + warn("Option '-D{}={}' conflicts with flag '-D{}'.\n", name, value, name); + return true; + }, + } + return false; + } + + pub fn addUserInputFlag(self: *Builder, name: []const u8) !bool { + const gop = try self.user_input_options.getOrPut(name); + if (!gop.found_existing) { + gop.kv.value = UserInputOption{ + .name = name, + .value = UserValue{ .Flag = {} }, + .used = false, + }; + return false; + } + + // option already exists + switch (gop.kv.value.value) { + UserValue.Scalar => |s| { + warn("Flag '-D{}' conflicts with option '-D{}={}'.\n", name, name, s); + return true; + }, + UserValue.List => { + warn("Flag '-D{}' conflicts with multiple options of the same name.\n", name); + return true; + }, + UserValue.Flag => {}, + } + return false; + } + + fn typeToEnum(comptime T: type) TypeId { + return switch (@typeId(T)) { + builtin.TypeId.Int => TypeId.Int, + builtin.TypeId.Float => TypeId.Float, + builtin.TypeId.Bool => TypeId.Bool, + else => switch (T) { + []const u8 => TypeId.String, + []const []const u8 => TypeId.List, + else => @compileError("Unsupported type: " ++ @typeName(T)), + }, + }; + } + + fn markInvalidUserInput(self: *Builder) void { + self.invalid_user_input = true; + } + + pub fn typeIdName(id: TypeId) []const u8 { + return switch (id) { + TypeId.Bool => "bool", + TypeId.Int => "int", + TypeId.Float => "float", + TypeId.String => "string", + TypeId.List => "list", + }; + } + + pub fn validateUserInputDidItFail(self: *Builder) bool { + // make sure all args are used + var it = self.user_input_options.iterator(); + while (true) { + const entry = it.next() orelse break; + if (!entry.value.used) { + warn("Invalid option: -D{}\n\n", entry.key); + self.markInvalidUserInput(); + } + } + + return self.invalid_user_input; + } + + fn spawnChild(self: *Builder, argv: []const []const u8) !void { + return self.spawnChildEnvMap(null, self.env_map, argv); + } + + fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void { + if (cwd) |yes_cwd| warn("cd {} && ", yes_cwd); + for (argv) |arg| { + warn("{} ", arg); + } + warn("\n"); + } + + fn spawnChildEnvMap(self: *Builder, cwd: ?[]const u8, env_map: *const BufMap, argv: []const []const u8) !void { + if (self.verbose) { + printCmd(cwd, argv); + } + + const child = std.ChildProcess.init(argv, self.allocator) catch unreachable; + defer child.deinit(); + + child.cwd = cwd; + child.env_map = env_map; + + const term = child.spawnAndWait() catch |err| { + warn("Unable to spawn {}: {}\n", argv[0], @errorName(err)); + return err; + }; + + switch (term) { + .Exited => |code| { + if (code != 0) { + warn("The following command exited with error code {}:\n", code); + printCmd(cwd, argv); + return error.UncleanExit; + } + }, + else => { + warn("The following command terminated unexpectedly:\n"); + printCmd(cwd, argv); + + return error.UncleanExit; + }, + } + } + + pub fn makePath(self: *Builder, path: []const u8) !void { + fs.makePath(self.allocator, self.pathFromRoot(path)) catch |err| { + warn("Unable to create path {}: {}\n", path, @errorName(err)); + return err; + }; + } + + pub fn installArtifact(self: *Builder, artifact: *LibExeObjStep) void { + self.getInstallStep().dependOn(&self.addInstallArtifact(artifact).step); + } + + pub fn addInstallArtifact(self: *Builder, artifact: *LibExeObjStep) *InstallArtifactStep { + return InstallArtifactStep.create(self, artifact); + } + + ///`dest_rel_path` is relative to prefix path + pub fn installFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void { + self.getInstallStep().dependOn(&self.addInstallFileWithDir(src_path, .Prefix, dest_rel_path).step); + } + + pub fn installDirectory(self: *Builder, options: InstallDirectoryOptions) void { + self.getInstallStep().dependOn(&self.addInstallDirectory(options).step); + } + + ///`dest_rel_path` is relative to bin path + pub fn installBinFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void { + self.getInstallStep().dependOn(&self.addInstallFileWithDir(src_path, .Bin, dest_rel_path).step); + } + + ///`dest_rel_path` is relative to lib path + pub fn installLibFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void { + self.getInstallStep().dependOn(&self.addInstallFileWithDir(src_path, .Lib, dest_rel_path).step); + } + + ///`dest_rel_path` is relative to install prefix path + pub fn addInstallFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep { + return self.addInstallFileWithDir(src_path, .Prefix, dest_rel_path); + } + + ///`dest_rel_path` is relative to bin path + pub fn addInstallBinFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep { + return self.addInstallFileWithDir(src_path, .Bin, dest_rel_path); + } + + ///`dest_rel_path` is relative to lib path + pub fn addInstallLibFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep { + return self.addInstallFileWithDir(src_path, .Lib, dest_rel_path); + } + + pub fn addInstallFileWithDir( + self: *Builder, + src_path: []const u8, + install_dir: InstallDir, + dest_rel_path: []const u8, + ) *InstallFileStep { + const install_step = self.allocator.create(InstallFileStep) catch unreachable; + install_step.* = InstallFileStep.init(self, src_path, install_dir, dest_rel_path); + return install_step; + } + + pub fn addInstallDirectory(self: *Builder, options: InstallDirectoryOptions) *InstallDirStep { + const install_step = self.allocator.create(InstallDirStep) catch unreachable; + install_step.* = InstallDirStep.init(self, options); + return install_step; + } + + pub fn pushInstalledFile(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) void { + self.installed_files.append(InstalledFile{ + .dir = dir, + .path = dest_rel_path, + }) catch unreachable; + } + + fn updateFile(self: *Builder, source_path: []const u8, dest_path: []const u8) !void { + if (self.verbose) { + warn("cp {} {} ", source_path, dest_path); + } + const prev_status = try fs.updateFile(source_path, dest_path); + if (self.verbose) switch (prev_status) { + .stale => warn("# installed\n"), + .fresh => warn("# up-to-date\n"), + }; + } + + fn pathFromRoot(self: *Builder, rel_path: []const u8) []u8 { + return fs.path.resolve(self.allocator, [_][]const u8{ self.build_root, rel_path }) catch unreachable; + } + + pub fn fmt(self: *Builder, comptime format: []const u8, args: ...) []u8 { + return fmt_lib.allocPrint(self.allocator, format, args) catch unreachable; + } + + pub fn findProgram(self: *Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 { + // TODO report error for ambiguous situations + const exe_extension = (Target{ .Native = {} }).exeFileExt(); + for (self.search_prefixes.toSliceConst()) |search_prefix| { + for (names) |name| { + if (fs.path.isAbsolute(name)) { + return name; + } + const full_path = try fs.path.join(self.allocator, [_][]const u8{ search_prefix, "bin", self.fmt("{}{}", name, exe_extension) }); + return fs.realpathAlloc(self.allocator, full_path) catch continue; + } + } + if (self.env_map.get("PATH")) |PATH| { + for (names) |name| { + if (fs.path.isAbsolute(name)) { + return name; + } + var it = mem.tokenize(PATH, [_]u8{fs.path.delimiter}); + while (it.next()) |path| { + const full_path = try fs.path.join(self.allocator, [_][]const u8{ path, self.fmt("{}{}", name, exe_extension) }); + return fs.realpathAlloc(self.allocator, full_path) catch continue; + } + } + } + for (names) |name| { + if (fs.path.isAbsolute(name)) { + return name; + } + for (paths) |path| { + const full_path = try fs.path.join(self.allocator, [_][]const u8{ path, self.fmt("{}{}", name, exe_extension) }); + return fs.realpathAlloc(self.allocator, full_path) catch continue; + } + } + return error.FileNotFound; + } + + pub fn execAllowFail( + self: *Builder, + argv: []const []const u8, + out_code: *u8, + stderr_behavior: std.ChildProcess.StdIo, + ) ![]u8 { + assert(argv.len != 0); + + const max_output_size = 100 * 1024; + const child = try std.ChildProcess.init(argv, self.allocator); + defer child.deinit(); + + child.stdin_behavior = .Ignore; + child.stdout_behavior = .Pipe; + child.stderr_behavior = stderr_behavior; + + try child.spawn(); + + var stdout = std.Buffer.initNull(self.allocator); + defer std.Buffer.deinit(&stdout); + + var stdout_file_in_stream = child.stdout.?.inStream(); + try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size); + + const term = try child.wait(); + switch (term) { + .Exited => |code| { + if (code != 0) { + out_code.* = @truncate(u8, code); + return error.ExitCodeFailure; + } + return stdout.toOwnedSlice(); + }, + .Signal, .Stopped, .Unknown => |code| { + out_code.* = @truncate(u8, code); + return error.ProcessTerminated; + }, + } + } + + pub fn exec(self: *Builder, argv: []const []const u8) ![]u8 { + assert(argv.len != 0); + + if (self.verbose) { + printCmd(null, argv); + } + + var code: u8 = undefined; + return self.execAllowFail(argv, &code, .Inherit) catch |err| switch (err) { + error.FileNotFound => { + warn("Unable to spawn the following command: file not found\n"); + printCmd(null, argv); + std.os.exit(@truncate(u8, code)); + }, + error.ExitCodeFailure => { + warn("The following command exited with error code {}:\n", code); + printCmd(null, argv); + std.os.exit(@truncate(u8, code)); + }, + error.ProcessTerminated => { + warn("The following command terminated unexpectedly:\n"); + printCmd(null, argv); + std.os.exit(@truncate(u8, code)); + }, + else => |e| return e, + }; + } + + pub fn addSearchPrefix(self: *Builder, search_prefix: []const u8) void { + self.search_prefixes.append(search_prefix) catch unreachable; + } + + fn getInstallPath(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) []const u8 { + const base_dir = switch (dir) { + .Prefix => self.install_path, + .Bin => self.exe_dir, + .Lib => self.lib_dir, + }; + return fs.path.resolve( + self.allocator, + [_][]const u8{ base_dir, dest_rel_path }, + ) catch unreachable; + } + + fn execPkgConfigList(self: *Builder, out_code: *u8) ![]const PkgConfigPkg { + const stdout = try self.execAllowFail([_][]const u8{ "pkg-config", "--list-all" }, out_code, .Ignore); + var list = ArrayList(PkgConfigPkg).init(self.allocator); + var line_it = mem.tokenize(stdout, "\r\n"); + while (line_it.next()) |line| { + if (mem.trim(u8, line, " \t").len == 0) continue; + var tok_it = mem.tokenize(line, " \t"); + try list.append(PkgConfigPkg{ + .name = tok_it.next() orelse return error.PkgConfigInvalidOutput, + .desc = tok_it.rest(), + }); + } + return list.toSliceConst(); + } + + fn getPkgConfigList(self: *Builder) ![]const PkgConfigPkg { + if (self.pkg_config_pkg_list) |res| { + return res; + } + var code: u8 = undefined; + if (self.execPkgConfigList(&code)) |list| { + self.pkg_config_pkg_list = list; + return list; + } else |err| { + const result = switch (err) { + error.ProcessTerminated => error.PkgConfigCrashed, + error.ExitCodeFailure => error.PkgConfigFailed, + error.FileNotFound => error.PkgConfigNotInstalled, + error.PkgConfigInvalidOutput => error.PkgConfigInvalidOutput, + else => return err, + }; + self.pkg_config_pkg_list = result; + return result; + } + } +}; + +test "builder.findProgram compiles" { + const builder = try Builder.create(std.heap.direct_allocator, "zig", "zig-cache", "zig-cache"); + _ = builder.findProgram([_][]const u8{}, [_][]const u8{}) catch null; +} + +pub const Version = struct { + major: u32, + minor: u32, + patch: u32, +}; + +pub const CrossTarget = struct { + arch: builtin.Arch, + os: builtin.Os, + abi: builtin.Abi, +}; + +pub const Target = union(enum) { + Native: void, + Cross: CrossTarget, + + pub fn zigTriple(self: Target, allocator: *Allocator) ![]u8 { + return std.fmt.allocPrint( + allocator, + "{}{}-{}-{}", + @tagName(self.getArch()), + Target.archSubArchName(self.getArch()), + @tagName(self.getOs()), + @tagName(self.getAbi()), + ); + } + + pub fn allocDescription(self: Target, allocator: *Allocator) ![]u8 { + // TODO is there anything else worthy of the description that is not + // already captured in the triple? + return self.zigTriple(allocator); + } + + pub fn zigTripleNoSubArch(self: Target, allocator: *Allocator) ![]u8 { + return std.fmt.allocPrint( + allocator, + "{}-{}-{}", + @tagName(self.getArch()), + @tagName(self.getOs()), + @tagName(self.getAbi()), + ); + } + + pub fn linuxTriple(self: Target, allocator: *Allocator) ![]u8 { + return std.fmt.allocPrint( + allocator, + "{}-{}-{}", + @tagName(self.getArch()), + @tagName(self.getOs()), + @tagName(self.getAbi()), + ); + } + + pub fn parse(text: []const u8) !Target { + var it = mem.separate(text, "-"); + const arch_name = it.next() orelse return error.MissingArchitecture; + const os_name = it.next() orelse return error.MissingOperatingSystem; + const abi_name = it.next(); + + var cross = CrossTarget{ + .arch = try parseArchSub(arch_name), + .os = try parseOs(os_name), + .abi = undefined, + }; + cross.abi = if (abi_name) |n| try parseAbi(n) else defaultAbi(cross.arch, cross.os); + return Target{ .Cross = cross }; + } + + pub fn defaultAbi(arch: builtin.Arch, target_os: builtin.Os) builtin.Abi { + switch (arch) { + .wasm32, .wasm64 => return .musl, + else => {}, + } + switch (target_os) { + .freestanding, + .ananas, + .cloudabi, + .dragonfly, + .lv2, + .solaris, + .haiku, + .minix, + .rtems, + .nacl, + .cnk, + .aix, + .cuda, + .nvcl, + .amdhsa, + .ps4, + .elfiamcu, + .mesa3d, + .contiki, + .amdpal, + .zen, + .hermit, + => return .eabi, + .openbsd, + .macosx, + .freebsd, + .ios, + .tvos, + .watchos, + .fuchsia, + .kfreebsd, + .netbsd, + .hurd, + => return .gnu, + .windows, + .uefi, + => return .msvc, + .linux, + .wasi, + .emscripten, + => return .musl, + } + } + + pub const ParseArchSubError = error{ + UnknownArchitecture, + UnknownSubArchitecture, + }; + + pub fn parseArchSub(text: []const u8) ParseArchSubError!builtin.Arch { + const info = @typeInfo(builtin.Arch); + inline for (info.Union.fields) |field| { + if (mem.eql(u8, text, field.name)) { + if (field.field_type == void) { + return (builtin.Arch)(@field(builtin.Arch, field.name)); + } else { + const sub_info = @typeInfo(field.field_type); + inline for (sub_info.Enum.fields) |sub_field| { + const combined = field.name ++ sub_field.name; + if (mem.eql(u8, text, combined)) { + return @unionInit(builtin.Arch, field.name, @field(field.field_type, sub_field.name)); + } + } + return error.UnknownSubArchitecture; + } + } + } + return error.UnknownArchitecture; + } + + pub fn parseOs(text: []const u8) !builtin.Os { + const info = @typeInfo(builtin.Os); + inline for (info.Enum.fields) |field| { + if (mem.eql(u8, text, field.name)) { + return @field(builtin.Os, field.name); + } + } + return error.UnknownOperatingSystem; + } + + pub fn parseAbi(text: []const u8) !builtin.Abi { + const info = @typeInfo(builtin.Abi); + inline for (info.Enum.fields) |field| { + if (mem.eql(u8, text, field.name)) { + return @field(builtin.Abi, field.name); + } + } + return error.UnknownApplicationBinaryInterface; + } + + fn archSubArchName(arch: builtin.Arch) []const u8 { + return switch (arch) { + .arm => |sub| @tagName(sub), + .armeb => |sub| @tagName(sub), + .thumb => |sub| @tagName(sub), + .thumbeb => |sub| @tagName(sub), + .aarch64 => |sub| @tagName(sub), + .aarch64_be => |sub| @tagName(sub), + .kalimba => |sub| @tagName(sub), + else => "", + }; + } + + pub fn subArchName(self: Target) []const u8 { + switch (self) { + .Native => return archSubArchName(builtin.arch), + .Cross => |cross| return archSubArchName(cross.arch), + } + } + + pub fn oFileExt(self: Target) []const u8 { + return switch (self.getAbi()) { + builtin.Abi.msvc => ".obj", + else => ".o", + }; + } + + pub fn exeFileExt(self: Target) []const u8 { + return switch (self.getOs()) { + .windows => ".exe", + else => "", + }; + } + + pub fn staticLibSuffix(self: Target) []const u8 { + if (self.isWasm()) { + return ".wasm"; + } + switch (self.getAbi()) { + .msvc => return ".lib", + else => return ".a", + } + } + + pub fn dynamicLibSuffix(self: Target) []const u8 { + if (self.isDarwin()) { + return ".dylib"; + } + switch (self.getOs()) { + .windows => return ".dll", + else => return ".so", + } + } + + pub fn libPrefix(self: Target) []const u8 { + if (self.isWasm()) { + return ""; + } + switch (self.getAbi()) { + .msvc => return "", + else => return "lib", + } + } + + pub fn getOs(self: Target) builtin.Os { + return switch (self) { + .Native => builtin.os, + .Cross => |t| t.os, + }; + } + + pub fn getArch(self: Target) builtin.Arch { + switch (self) { + .Native => return builtin.arch, + .Cross => |t| return t.arch, + } + } + + pub fn getAbi(self: Target) builtin.Abi { + switch (self) { + .Native => return builtin.abi, + .Cross => |t| return t.abi, + } + } + + pub fn isMinGW(self: Target) bool { + return self.isWindows() and self.isGnu(); + } + + pub fn isGnu(self: Target) bool { + return switch (self.getAbi()) { + .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true, + else => false, + }; + } + + pub fn isDarwin(self: Target) bool { + return switch (self.getOs()) { + .ios, .macosx, .watchos, .tvos => true, + else => false, + }; + } + + pub fn isWindows(self: Target) bool { + return switch (self.getOs()) { + .windows => true, + else => false, + }; + } + + pub fn isLinux(self: Target) bool { + return switch (self.getOs()) { + .linux => true, + else => false, + }; + } + + pub fn isUefi(self: Target) bool { + return switch (self.getOs()) { + .uefi => true, + else => false, + }; + } + + pub fn isWasm(self: Target) bool { + return switch (self.getArch()) { + .wasm32, .wasm64 => true, + else => false, + }; + } + + pub fn isFreeBSD(self: Target) bool { + return switch (self.getOs()) { + .freebsd => true, + else => false, + }; + } + + pub fn isNetBSD(self: Target) bool { + return switch (self.getOs()) { + .netbsd => true, + else => false, + }; + } + + pub fn wantSharedLibSymLinks(self: Target) bool { + return !self.isWindows(); + } + + pub fn osRequiresLibC(self: Target) bool { + return self.isDarwin() or self.isFreeBSD() or self.isNetBSD(); + } + + pub fn getArchPtrBitWidth(self: Target) u32 { + switch (self.getArch()) { + .avr, + .msp430, + => return 16, + + .arc, + .arm, + .armeb, + .hexagon, + .le32, + .mips, + .mipsel, + .powerpc, + .r600, + .riscv32, + .sparc, + .sparcel, + .tce, + .tcele, + .thumb, + .thumbeb, + .i386, + .xcore, + .nvptx, + .amdil, + .hsail, + .spir, + .kalimba, + .shave, + .lanai, + .wasm32, + .renderscript32, + .aarch64_32, + => return 32, + + .aarch64, + .aarch64_be, + .mips64, + .mips64el, + .powerpc64, + .powerpc64le, + .riscv64, + .x86_64, + .nvptx64, + .le64, + .amdil64, + .hsail64, + .spir64, + .wasm64, + .renderscript64, + .amdgcn, + .bpfel, + .bpfeb, + .sparcv9, + .s390x, + => return 64, + } + } + + pub const Executor = union(enum) { + native, + qemu: []const u8, + wine: []const u8, + unavailable, + }; + + pub fn getExternalExecutor(self: Target) Executor { + if (@TagType(Target)(self) == .Native) return .native; + + // If the target OS matches the host OS, we can use QEMU to emulate a foreign architecture. + if (self.getOs() == builtin.os) { + return switch (self.getArch()) { + .aarch64 => Executor{ .qemu = "qemu-aarch64" }, + .aarch64_be => Executor{ .qemu = "qemu-aarch64_be" }, + .arm => Executor{ .qemu = "qemu-arm" }, + .armeb => Executor{ .qemu = "qemu-armeb" }, + .i386 => Executor{ .qemu = "qemu-i386" }, + .mips => Executor{ .qemu = "qemu-mips" }, + .mipsel => Executor{ .qemu = "qemu-mipsel" }, + .mips64 => Executor{ .qemu = "qemu-mips64" }, + .mips64el => Executor{ .qemu = "qemu-mips64el" }, + .powerpc => Executor{ .qemu = "qemu-ppc" }, + .powerpc64 => Executor{ .qemu = "qemu-ppc64" }, + .powerpc64le => Executor{ .qemu = "qemu-ppc64le" }, + .riscv32 => Executor{ .qemu = "qemu-riscv32" }, + .riscv64 => Executor{ .qemu = "qemu-riscv64" }, + .s390x => Executor{ .qemu = "qemu-s390x" }, + .sparc => Executor{ .qemu = "qemu-sparc" }, + .x86_64 => Executor{ .qemu = "qemu-x86_64" }, + else => return .unavailable, + }; + } + + if (self.isWindows()) { + switch (self.getArchPtrBitWidth()) { + 32 => return Executor{ .wine = "wine" }, + 64 => return Executor{ .wine = "wine64" }, + else => return .unavailable, + } + } + + return .unavailable; + } +}; + +const Pkg = struct { + name: []const u8, + path: []const u8, +}; + +const CSourceFile = struct { + source_path: []const u8, + args: []const []const u8, +}; + +fn isLibCLibrary(name: []const u8) bool { + const libc_libraries = [_][]const u8{ "c", "m", "dl", "rt", "pthread" }; + for (libc_libraries) |libc_lib_name| { + if (mem.eql(u8, name, libc_lib_name)) + return true; + } + return false; +} + +pub const LibExeObjStep = struct { + step: Step, + builder: *Builder, + name: []const u8, + target: Target, + linker_script: ?[]const u8 = null, + version_script: ?[]const u8 = null, + out_filename: []const u8, + is_dynamic: bool, + version: Version, + build_mode: builtin.Mode, + kind: Kind, + major_only_filename: []const u8, + name_only_filename: []const u8, + strip: bool, + lib_paths: ArrayList([]const u8), + framework_dirs: ArrayList([]const u8), + frameworks: BufSet, + verbose_link: bool, + verbose_cc: bool, + disable_gen_h: bool, + bundle_compiler_rt: bool, + disable_stack_probing: bool, + c_std: Builder.CStd, + override_lib_dir: ?[]const u8, + main_pkg_path: ?[]const u8, + exec_cmd_args: ?[]const ?[]const u8, + name_prefix: []const u8, + filter: ?[]const u8, + single_threaded: bool, + + root_src: ?[]const u8, + out_h_filename: []const u8, + out_lib_filename: []const u8, + out_pdb_filename: []const u8, + packages: ArrayList(Pkg), + build_options_contents: std.Buffer, + system_linker_hack: bool, + + object_src: []const u8, + + link_objects: ArrayList(LinkObject), + include_dirs: ArrayList(IncludeDir), + c_macros: ArrayList([]const u8), + output_dir: ?[]const u8, + need_system_paths: bool, + is_linking_libc: bool = false, + + installed_path: ?[]const u8, + install_step: ?*InstallArtifactStep, + + libc_file: ?[]const u8 = null, + target_glibc: ?Version = null, + + valgrind_support: ?bool = null, + + /// Uses system Wine installation to run cross compiled Windows build artifacts. + enable_wine: bool = false, + + /// Uses system QEMU installation to run cross compiled foreign architecture build artifacts. + enable_qemu: bool = false, + + /// After following the steps in https://github.com/ziglang/zig/wiki/Updating-libc#glibc, + /// this will be the directory $glibc-build-dir/install/glibcs + /// Given the example of the aarch64 target, this is the directory + /// that contains the path `aarch64-linux-gnu/lib/ld-linux-aarch64.so.1`. + glibc_multi_install_dir: ?[]const u8 = null, + + dynamic_linker: ?[]const u8 = null, + + const LinkObject = union(enum) { + StaticPath: []const u8, + OtherStep: *LibExeObjStep, + SystemLib: []const u8, + AssemblyFile: []const u8, + CSourceFile: *CSourceFile, + }; + + const IncludeDir = union(enum) { + RawPath: []const u8, + OtherStep: *LibExeObjStep, + }; + + const Kind = enum { + Exe, + Lib, + Obj, + Test, + }; + + pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8, ver: Version) *LibExeObjStep { + const self = builder.allocator.create(LibExeObjStep) catch unreachable; + self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, ver); + return self; + } + + pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { + const self = builder.allocator.create(LibExeObjStep) catch unreachable; + self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, builder.version(0, 0, 0)); + return self; + } + + pub fn createObject(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { + const self = builder.allocator.create(LibExeObjStep) catch unreachable; + self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0)); + return self; + } + + pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, is_dynamic: bool) *LibExeObjStep { + const self = builder.allocator.create(LibExeObjStep) catch unreachable; + self.* = initExtraArgs(builder, name, root_src, Kind.Exe, is_dynamic, builder.version(0, 0, 0)); + return self; + } + + pub fn createTest(builder: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep { + const self = builder.allocator.create(LibExeObjStep) catch unreachable; + self.* = initExtraArgs(builder, name, root_src, Kind.Test, false, builder.version(0, 0, 0)); + return self; + } + + fn initExtraArgs(builder: *Builder, name: []const u8, root_src: ?[]const u8, kind: Kind, is_dynamic: bool, ver: Version) LibExeObjStep { + if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) { + panic("invalid name: '{}'. It looks like a file path, but it is supposed to be the library or application name.", name); + } + var self = LibExeObjStep{ + .strip = false, + .builder = builder, + .verbose_link = false, + .verbose_cc = false, + .build_mode = builtin.Mode.Debug, + .is_dynamic = is_dynamic, + .kind = kind, + .root_src = root_src, + .name = name, + .target = Target.Native, + .frameworks = BufSet.init(builder.allocator), + .step = Step.init(name, builder.allocator, make), + .version = ver, + .out_filename = undefined, + .out_h_filename = builder.fmt("{}.h", name), + .out_lib_filename = undefined, + .out_pdb_filename = builder.fmt("{}.pdb", name), + .major_only_filename = undefined, + .name_only_filename = undefined, + .packages = ArrayList(Pkg).init(builder.allocator), + .include_dirs = ArrayList(IncludeDir).init(builder.allocator), + .link_objects = ArrayList(LinkObject).init(builder.allocator), + .c_macros = ArrayList([]const u8).init(builder.allocator), + .lib_paths = ArrayList([]const u8).init(builder.allocator), + .framework_dirs = ArrayList([]const u8).init(builder.allocator), + .object_src = undefined, + .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable, + .c_std = Builder.CStd.C99, + .system_linker_hack = false, + .override_lib_dir = null, + .main_pkg_path = null, + .exec_cmd_args = null, + .name_prefix = "", + .filter = null, + .disable_gen_h = false, + .bundle_compiler_rt = false, + .disable_stack_probing = false, + .output_dir = null, + .need_system_paths = false, + .single_threaded = false, + .installed_path = null, + .install_step = null, + }; + self.computeOutFileNames(); + return self; + } + + fn computeOutFileNames(self: *LibExeObjStep) void { + switch (self.kind) { + .Obj => { + self.out_filename = self.builder.fmt("{}{}", self.name, self.target.oFileExt()); + }, + .Exe => { + self.out_filename = self.builder.fmt("{}{}", self.name, self.target.exeFileExt()); + }, + .Test => { + self.out_filename = self.builder.fmt("test{}", self.target.exeFileExt()); + }, + .Lib => { + if (!self.is_dynamic) { + self.out_filename = self.builder.fmt( + "{}{}{}", + self.target.libPrefix(), + self.name, + self.target.staticLibSuffix(), + ); + self.out_lib_filename = self.out_filename; + } else { + if (self.target.isDarwin()) { + self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib", self.name, self.version.major, self.version.minor, self.version.patch); + self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", self.name, self.version.major); + self.name_only_filename = self.builder.fmt("lib{}.dylib", self.name); + self.out_lib_filename = self.out_filename; + } else if (self.target.isWindows()) { + self.out_filename = self.builder.fmt("{}.dll", self.name); + self.out_lib_filename = self.builder.fmt("{}.lib", self.name); + } else { + self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}", self.name, self.version.major, self.version.minor, self.version.patch); + self.major_only_filename = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major); + self.name_only_filename = self.builder.fmt("lib{}.so", self.name); + self.out_lib_filename = self.out_filename; + } + } + }, + } + } + + /// Deprecated. Use `setTheTarget`. + pub fn setTarget( + self: *LibExeObjStep, + target_arch: builtin.Arch, + target_os: builtin.Os, + target_abi: builtin.Abi, + ) void { + return self.setTheTarget(Target{ + .Cross = CrossTarget{ + .arch = target_arch, + .os = target_os, + .abi = target_abi, + }, + }); + } + + pub fn setTheTarget(self: *LibExeObjStep, target: Target) void { + self.target = target; + self.computeOutFileNames(); + } + + pub fn setTargetGLibC(self: *LibExeObjStep, major: u32, minor: u32, patch: u32) void { + self.target_glibc = Version{ + .major = major, + .minor = minor, + .patch = patch, + }; + } + + pub fn setOutputDir(self: *LibExeObjStep, dir: []const u8) void { + self.output_dir = self.builder.dupePath(dir); + } + + pub fn install(self: *LibExeObjStep) void { + self.builder.installArtifact(self); + } + + /// Creates a `RunStep` with an executable built with `addExecutable`. + /// Add command line arguments with `addArg`. + pub fn run(exe: *LibExeObjStep) *RunStep { + assert(exe.kind == Kind.Exe); + + // It doesn't have to be native. We catch that if you actually try to run it. + // Consider that this is declarative; the run step may not be run unless a user + // option is supplied. + const run_step = RunStep.create(exe.builder, exe.builder.fmt("run {}", exe.step.name)); + run_step.addArtifactArg(exe); + return run_step; + } + + pub fn setLinkerScriptPath(self: *LibExeObjStep, path: []const u8) void { + self.linker_script = path; + } + + pub fn linkFramework(self: *LibExeObjStep, framework_name: []const u8) void { + assert(self.target.isDarwin()); + self.frameworks.put(framework_name) catch unreachable; + } + + /// Returns whether the library, executable, or object depends on a particular system library. + pub fn dependsOnSystemLibrary(self: LibExeObjStep, name: []const u8) bool { + if (isLibCLibrary(name)) { + return self.is_linking_libc; + } + for (self.link_objects.toSliceConst()) |link_object| { + switch (link_object) { + LinkObject.SystemLib => |n| if (mem.eql(u8, n, name)) return true, + else => continue, + } + } + return false; + } + + pub fn linkLibrary(self: *LibExeObjStep, lib: *LibExeObjStep) void { + assert(lib.kind == Kind.Lib); + self.linkLibraryOrObject(lib); + } + + pub fn isDynamicLibrary(self: *LibExeObjStep) bool { + return self.kind == Kind.Lib and self.is_dynamic; + } + + pub fn producesPdbFile(self: *LibExeObjStep) bool { + if (!self.target.isWindows() and !self.target.isUefi()) return false; + if (self.strip) return false; + return self.isDynamicLibrary() or self.kind == .Exe; + } + + pub fn linkLibC(self: *LibExeObjStep) void { + if (!self.is_linking_libc) { + self.is_linking_libc = true; + self.link_objects.append(LinkObject{ .SystemLib = "c" }) catch unreachable; + } + } + + /// name_and_value looks like [name]=[value]. If the value is omitted, it is set to 1. + pub fn defineCMacro(self: *LibExeObjStep, name_and_value: []const u8) void { + self.c_macros.append(self.builder.dupe(name_and_value)) catch unreachable; + } + + /// This one has no integration with anything, it just puts -lname on the command line. + /// Prefer to use `linkSystemLibrary` instead. + pub fn linkSystemLibraryName(self: *LibExeObjStep, name: []const u8) void { + self.link_objects.append(LinkObject{ .SystemLib = self.builder.dupe(name) }) catch unreachable; + self.need_system_paths = true; + } + + /// This links against a system library, exclusively using pkg-config to find the library. + /// Prefer to use `linkSystemLibrary` instead. + pub fn linkSystemLibraryPkgConfigOnly(self: *LibExeObjStep, lib_name: []const u8) !void { + const pkg_name = match: { + // First we have to map the library name to pkg config name. Unfortunately, + // there are several examples where this is not straightforward: + // -lSDL2 -> pkg-config sdl2 + // -lgdk-3 -> pkg-config gdk-3.0 + // -latk-1.0 -> pkg-config atk + const pkgs = try self.builder.getPkgConfigList(); + + // Exact match means instant winner. + for (pkgs) |pkg| { + if (mem.eql(u8, pkg.name, lib_name)) { + break :match pkg.name; + } + } + + // Next we'll try ignoring case. + for (pkgs) |pkg| { + if (std.ascii.eqlIgnoreCase(pkg.name, lib_name)) { + break :match pkg.name; + } + } + + // Now try appending ".0". + for (pkgs) |pkg| { + if (std.ascii.indexOfIgnoreCase(pkg.name, lib_name)) |pos| { + if (pos != 0) continue; + if (mem.eql(u8, pkg.name[lib_name.len..], ".0")) { + break :match pkg.name; + } + } + } + + // Trimming "-1.0". + if (mem.endsWith(u8, lib_name, "-1.0")) { + const trimmed_lib_name = lib_name[0 .. lib_name.len - "-1.0".len]; + for (pkgs) |pkg| { + if (std.ascii.eqlIgnoreCase(pkg.name, trimmed_lib_name)) { + break :match pkg.name; + } + } + } + + return error.PackageNotFound; + }; + + var code: u8 = undefined; + const stdout = if (self.builder.execAllowFail([_][]const u8{ + "pkg-config", + pkg_name, + "--cflags", + "--libs", + }, &code, .Ignore)) |stdout| stdout else |err| switch (err) { + error.ProcessTerminated => return error.PkgConfigCrashed, + error.ExitCodeFailure => return error.PkgConfigFailed, + error.FileNotFound => return error.PkgConfigNotInstalled, + else => return err, + }; + var it = mem.tokenize(stdout, " \r\n\t"); + while (it.next()) |tok| { + if (mem.eql(u8, tok, "-I")) { + const dir = it.next() orelse return error.PkgConfigInvalidOutput; + self.addIncludeDir(dir); + } else if (mem.startsWith(u8, tok, "-I")) { + self.addIncludeDir(tok["-I".len..]); + } else if (mem.eql(u8, tok, "-L")) { + const dir = it.next() orelse return error.PkgConfigInvalidOutput; + self.addLibPath(dir); + } else if (mem.startsWith(u8, tok, "-L")) { + self.addLibPath(tok["-L".len..]); + } else if (mem.eql(u8, tok, "-l")) { + const lib = it.next() orelse return error.PkgConfigInvalidOutput; + self.linkSystemLibraryName(lib); + } else if (mem.startsWith(u8, tok, "-l")) { + self.linkSystemLibraryName(tok["-l".len..]); + } else if (mem.eql(u8, tok, "-D")) { + const macro = it.next() orelse return error.PkgConfigInvalidOutput; + self.defineCMacro(macro); + } else if (mem.startsWith(u8, tok, "-D")) { + self.defineCMacro(tok["-D".len..]); + } else if (mem.eql(u8, tok, "-pthread")) { + self.linkLibC(); + } else if (self.builder.verbose) { + warn("Ignoring pkg-config flag '{}'\n", tok); + } + } + } + + pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void { + if (isLibCLibrary(name)) { + self.linkLibC(); + return; + } + if (self.linkSystemLibraryPkgConfigOnly(name)) |_| { + // pkg-config worked, so nothing further needed to do. + return; + } else |err| switch (err) { + error.PkgConfigInvalidOutput, + error.PkgConfigCrashed, + error.PkgConfigFailed, + error.PkgConfigNotInstalled, + error.PackageNotFound, + => {}, + + else => unreachable, + } + + self.linkSystemLibraryName(name); + } + + pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void { + assert(self.kind == Kind.Test); + self.name_prefix = text; + } + + pub fn setFilter(self: *LibExeObjStep, text: ?[]const u8) void { + assert(self.kind == Kind.Test); + self.filter = text; + } + + pub fn addCSourceFile(self: *LibExeObjStep, file: []const u8, args: []const []const u8) void { + const c_source_file = self.builder.allocator.create(CSourceFile) catch unreachable; + const args_copy = self.builder.allocator.alloc([]u8, args.len) catch unreachable; + for (args) |arg, i| { + args_copy[i] = self.builder.dupe(arg); + } + c_source_file.* = CSourceFile{ + .source_path = self.builder.dupe(file), + .args = args_copy, + }; + self.link_objects.append(LinkObject{ .CSourceFile = c_source_file }) catch unreachable; + } + + pub fn setVerboseLink(self: *LibExeObjStep, value: bool) void { + self.verbose_link = value; + } + + pub fn setVerboseCC(self: *LibExeObjStep, value: bool) void { + self.verbose_cc = value; + } + + pub fn setBuildMode(self: *LibExeObjStep, mode: builtin.Mode) void { + self.build_mode = mode; + } + + pub fn overrideZigLibDir(self: *LibExeObjStep, dir_path: []const u8) void { + self.override_lib_dir = self.builder.dupe(dir_path); + } + + pub fn setMainPkgPath(self: *LibExeObjStep, dir_path: []const u8) void { + self.main_pkg_path = dir_path; + } + + pub fn setDisableGenH(self: *LibExeObjStep, value: bool) void { + self.disable_gen_h = value; + } + + pub fn setLibCFile(self: *LibExeObjStep, libc_file: ?[]const u8) void { + self.libc_file = libc_file; + } + + /// Unless setOutputDir was called, this function must be called only in + /// the make step, from a step that has declared a dependency on this one. + /// To run an executable built with zig build, use `run`, or create an install step and invoke it. + pub fn getOutputPath(self: *LibExeObjStep) []const u8 { + return fs.path.join( + self.builder.allocator, + [_][]const u8{ self.output_dir.?, self.out_filename }, + ) catch unreachable; + } + + /// Unless setOutputDir was called, this function must be called only in + /// the make step, from a step that has declared a dependency on this one. + pub fn getOutputLibPath(self: *LibExeObjStep) []const u8 { + assert(self.kind == Kind.Lib); + return fs.path.join( + self.builder.allocator, + [_][]const u8{ self.output_dir.?, self.out_lib_filename }, + ) catch unreachable; + } + + /// Unless setOutputDir was called, this function must be called only in + /// the make step, from a step that has declared a dependency on this one. + pub fn getOutputHPath(self: *LibExeObjStep) []const u8 { + assert(self.kind != Kind.Exe); + assert(!self.disable_gen_h); + return fs.path.join( + self.builder.allocator, + [_][]const u8{ self.output_dir.?, self.out_h_filename }, + ) catch unreachable; + } + + /// Unless setOutputDir was called, this function must be called only in + /// the make step, from a step that has declared a dependency on this one. + pub fn getOutputPdbPath(self: *LibExeObjStep) []const u8 { + assert(self.target.isWindows() or self.target.isUefi()); + return fs.path.join( + self.builder.allocator, + [_][]const u8{ self.output_dir.?, self.out_pdb_filename }, + ) catch unreachable; + } + + pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void { + self.link_objects.append(LinkObject{ .AssemblyFile = self.builder.dupe(path) }) catch unreachable; + } + + pub fn addObjectFile(self: *LibExeObjStep, path: []const u8) void { + self.link_objects.append(LinkObject{ .StaticPath = self.builder.dupe(path) }) catch unreachable; + } + + pub fn addObject(self: *LibExeObjStep, obj: *LibExeObjStep) void { + assert(obj.kind == Kind.Obj); + self.linkLibraryOrObject(obj); + } + + pub fn addBuildOption(self: *LibExeObjStep, comptime T: type, name: []const u8, value: T) void { + const out = &std.io.BufferOutStream.init(&self.build_options_contents).stream; + out.print("pub const {} = {};\n", name, value) catch unreachable; + } + + pub fn addIncludeDir(self: *LibExeObjStep, path: []const u8) void { + self.include_dirs.append(IncludeDir{ .RawPath = self.builder.dupe(path) }) catch unreachable; + } + + pub fn addLibPath(self: *LibExeObjStep, path: []const u8) void { + self.lib_paths.append(path) catch unreachable; + } + + pub fn addFrameworkDir(self: *LibExeObjStep, dir_path: []const u8) void { + self.framework_dirs.append(dir_path) catch unreachable; + } + + pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void { + self.packages.append(Pkg{ + .name = name, + .path = pkg_index_path, + }) catch unreachable; + } + + pub fn setExecCmd(self: *LibExeObjStep, args: []const ?[]const u8) void { + assert(self.kind == Kind.Test); + self.exec_cmd_args = args; + } + + pub fn enableSystemLinkerHack(self: *LibExeObjStep) void { + self.system_linker_hack = true; + } + + fn linkLibraryOrObject(self: *LibExeObjStep, other: *LibExeObjStep) void { + self.step.dependOn(&other.step); + self.link_objects.append(LinkObject{ .OtherStep = other }) catch unreachable; + self.include_dirs.append(IncludeDir{ .OtherStep = other }) catch unreachable; + + // Inherit dependency on system libraries + for (other.link_objects.toSliceConst()) |link_object| { + switch (link_object) { + .SystemLib => |name| self.linkSystemLibrary(name), + else => continue, + } + } + + // Inherit dependencies on darwin frameworks + if (self.target.isDarwin() and !other.isDynamicLibrary()) { + var it = other.frameworks.iterator(); + while (it.next()) |entry| { + self.frameworks.put(entry.key) catch unreachable; + } + } + } + + fn make(step: *Step) !void { + const self = @fieldParentPtr(LibExeObjStep, "step", step); + const builder = self.builder; + + if (self.root_src == null and self.link_objects.len == 0) { + warn("{}: linker needs 1 or more objects to link\n", self.step.name); + return error.NeedAnObject; + } + + var zig_args = ArrayList([]const u8).init(builder.allocator); + defer zig_args.deinit(); + + zig_args.append(builder.zig_exe) catch unreachable; + + const cmd = switch (self.kind) { + Kind.Lib => "build-lib", + Kind.Exe => "build-exe", + Kind.Obj => "build-obj", + Kind.Test => "test", + }; + zig_args.append(cmd) catch unreachable; + + if (self.root_src) |root_src| { + zig_args.append(builder.pathFromRoot(root_src)) catch unreachable; + } + + for (self.link_objects.toSlice()) |link_object| { + switch (link_object) { + LinkObject.StaticPath => |static_path| { + try zig_args.append("--object"); + try zig_args.append(builder.pathFromRoot(static_path)); + }, + + LinkObject.OtherStep => |other| switch (other.kind) { + LibExeObjStep.Kind.Exe => unreachable, + LibExeObjStep.Kind.Test => unreachable, + LibExeObjStep.Kind.Obj => { + try zig_args.append("--object"); + try zig_args.append(other.getOutputPath()); + }, + LibExeObjStep.Kind.Lib => { + if (!other.is_dynamic or self.target.isWindows()) { + try zig_args.append("--object"); + try zig_args.append(other.getOutputLibPath()); + } else { + const full_path_lib = other.getOutputPath(); + try zig_args.append("--library"); + try zig_args.append(full_path_lib); + + if (fs.path.dirname(full_path_lib)) |dirname| { + try zig_args.append("-rpath"); + try zig_args.append(dirname); + } + } + }, + }, + LinkObject.SystemLib => |name| { + try zig_args.append("--library"); + try zig_args.append(name); + }, + LinkObject.AssemblyFile => |asm_file| { + try zig_args.append("--c-source"); + try zig_args.append(builder.pathFromRoot(asm_file)); + }, + LinkObject.CSourceFile => |c_source_file| { + try zig_args.append("--c-source"); + for (c_source_file.args) |arg| { + try zig_args.append(arg); + } + try zig_args.append(self.builder.pathFromRoot(c_source_file.source_path)); + }, + } + } + + if (self.build_options_contents.len() > 0) { + const build_options_file = try fs.path.join( + builder.allocator, + [_][]const u8{ builder.cache_root, builder.fmt("{}_build_options.zig", self.name) }, + ); + try std.io.writeFile(build_options_file, self.build_options_contents.toSliceConst()); + try zig_args.append("--pkg-begin"); + try zig_args.append("build_options"); + try zig_args.append(builder.pathFromRoot(build_options_file)); + try zig_args.append("--pkg-end"); + } + + if (self.filter) |filter| { + try zig_args.append("--test-filter"); + try zig_args.append(filter); + } + + if (self.name_prefix.len != 0) { + try zig_args.append("--test-name-prefix"); + try zig_args.append(self.name_prefix); + } + + if (builder.verbose_tokenize) zig_args.append("--verbose-tokenize") catch unreachable; + if (builder.verbose_ast) zig_args.append("--verbose-ast") catch unreachable; + if (builder.verbose_cimport) zig_args.append("--verbose-cimport") catch unreachable; + if (builder.verbose_ir) zig_args.append("--verbose-ir") catch unreachable; + if (builder.verbose_llvm_ir) zig_args.append("--verbose-llvm-ir") catch unreachable; + if (builder.verbose_link or self.verbose_link) zig_args.append("--verbose-link") catch unreachable; + if (builder.verbose_cc or self.verbose_cc) zig_args.append("--verbose-cc") catch unreachable; + + if (self.strip) { + zig_args.append("--strip") catch unreachable; + } + + if (self.single_threaded) { + try zig_args.append("--single-threaded"); + } + + if (self.libc_file) |libc_file| { + try zig_args.append("--libc"); + try zig_args.append(builder.pathFromRoot(libc_file)); + } + + switch (self.build_mode) { + builtin.Mode.Debug => {}, + builtin.Mode.ReleaseSafe => zig_args.append("--release-safe") catch unreachable, + builtin.Mode.ReleaseFast => zig_args.append("--release-fast") catch unreachable, + builtin.Mode.ReleaseSmall => zig_args.append("--release-small") catch unreachable, + } + + try zig_args.append("--cache-dir"); + try zig_args.append(builder.pathFromRoot(builder.cache_root)); + + zig_args.append("--name") catch unreachable; + zig_args.append(self.name) catch unreachable; + + if (self.kind == Kind.Lib and self.is_dynamic) { + zig_args.append("--ver-major") catch unreachable; + zig_args.append(builder.fmt("{}", self.version.major)) catch unreachable; + + zig_args.append("--ver-minor") catch unreachable; + zig_args.append(builder.fmt("{}", self.version.minor)) catch unreachable; + + zig_args.append("--ver-patch") catch unreachable; + zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable; + } + if (self.is_dynamic) { + try zig_args.append("-dynamic"); + } + if (self.disable_gen_h) { + try zig_args.append("--disable-gen-h"); + } + if (self.bundle_compiler_rt) { + try zig_args.append("--bundle-compiler-rt"); + } + if (self.disable_stack_probing) { + try zig_args.append("-fno-stack-check"); + } + + switch (self.target) { + Target.Native => {}, + Target.Cross => { + try zig_args.append("-target"); + try zig_args.append(self.target.zigTriple(builder.allocator) catch unreachable); + }, + } + + if (self.target_glibc) |ver| { + try zig_args.append("-target-glibc"); + try zig_args.append(builder.fmt("{}.{}.{}", ver.major, ver.minor, ver.patch)); + } + + if (self.linker_script) |linker_script| { + zig_args.append("--linker-script") catch unreachable; + zig_args.append(builder.pathFromRoot(linker_script)) catch unreachable; + } + + if (self.dynamic_linker) |dynamic_linker| { + try zig_args.append("--dynamic-linker"); + try zig_args.append(dynamic_linker); + } + + if (self.version_script) |version_script| { + try zig_args.append("--version-script"); + try zig_args.append(builder.pathFromRoot(version_script)); + } + + if (self.exec_cmd_args) |exec_cmd_args| { + for (exec_cmd_args) |cmd_arg| { + if (cmd_arg) |arg| { + try zig_args.append("--test-cmd"); + try zig_args.append(arg); + } else { + try zig_args.append("--test-cmd-bin"); + } + } + } else switch (self.target.getExternalExecutor()) { + .native, .unavailable => {}, + .qemu => |bin_name| if (self.enable_qemu) qemu: { + const need_cross_glibc = self.target.isGnu() and self.target.isLinux() and self.is_linking_libc; + const glibc_dir_arg = if (need_cross_glibc) + self.glibc_multi_install_dir orelse break :qemu + else + null; + try zig_args.append("--test-cmd"); + try zig_args.append(bin_name); + if (glibc_dir_arg) |dir| { + const full_dir = try fs.path.join(builder.allocator, [_][]const u8{ + dir, + try self.target.linuxTriple(builder.allocator), + }); + + try zig_args.append("--test-cmd"); + try zig_args.append("-L"); + try zig_args.append("--test-cmd"); + try zig_args.append(full_dir); + } + try zig_args.append("--test-cmd-bin"); + }, + .wine => |bin_name| if (self.enable_wine) { + try zig_args.append("--test-cmd"); + try zig_args.append(bin_name); + try zig_args.append("--test-cmd-bin"); + }, + } + for (self.packages.toSliceConst()) |pkg| { + zig_args.append("--pkg-begin") catch unreachable; + zig_args.append(pkg.name) catch unreachable; + zig_args.append(builder.pathFromRoot(pkg.path)) catch unreachable; + zig_args.append("--pkg-end") catch unreachable; + } + + for (self.include_dirs.toSliceConst()) |include_dir| { + switch (include_dir) { + IncludeDir.RawPath => |include_path| { + try zig_args.append("-isystem"); + try zig_args.append(self.builder.pathFromRoot(include_path)); + }, + IncludeDir.OtherStep => |other| { + const h_path = other.getOutputHPath(); + try zig_args.append("-isystem"); + try zig_args.append(fs.path.dirname(h_path).?); + }, + } + } + + for (self.lib_paths.toSliceConst()) |lib_path| { + try zig_args.append("-L"); + try zig_args.append(lib_path); + } + + if (self.need_system_paths and self.target == Target.Native) { + for (builder.native_system_include_dirs.toSliceConst()) |include_path| { + zig_args.append("-isystem") catch unreachable; + zig_args.append(builder.pathFromRoot(include_path)) catch unreachable; + } + + for (builder.native_system_rpaths.toSliceConst()) |rpath| { + zig_args.append("-rpath") catch unreachable; + zig_args.append(rpath) catch unreachable; + } + + for (builder.native_system_lib_paths.toSliceConst()) |lib_path| { + zig_args.append("--library-path") catch unreachable; + zig_args.append(lib_path) catch unreachable; + } + } + + for (self.c_macros.toSliceConst()) |c_macro| { + try zig_args.append("-D"); + try zig_args.append(c_macro); + } + + if (self.target.isDarwin()) { + for (self.framework_dirs.toSliceConst()) |dir| { + try zig_args.append("-F"); + try zig_args.append(dir); + } + + var it = self.frameworks.iterator(); + while (it.next()) |entry| { + zig_args.append("-framework") catch unreachable; + zig_args.append(entry.key) catch unreachable; + } + } + + if (self.system_linker_hack) { + try zig_args.append("--system-linker-hack"); + } + + if (self.valgrind_support) |valgrind_support| { + if (valgrind_support) { + try zig_args.append("--enable-valgrind"); + } else { + try zig_args.append("--disable-valgrind"); + } + } + + if (self.override_lib_dir) |dir| { + try zig_args.append("--override-lib-dir"); + try zig_args.append(builder.pathFromRoot(dir)); + } else if (self.builder.override_lib_dir) |dir| { + try zig_args.append("--override-lib-dir"); + try zig_args.append(builder.pathFromRoot(dir)); + } + + if (self.main_pkg_path) |dir| { + try zig_args.append("--main-pkg-path"); + try zig_args.append(builder.pathFromRoot(dir)); + } + + if (self.kind == Kind.Test) { + try builder.spawnChild(zig_args.toSliceConst()); + } else { + try zig_args.append("--cache"); + try zig_args.append("on"); + + const output_path_nl = try builder.exec(zig_args.toSliceConst()); + const output_path = mem.trimRight(u8, output_path_nl, "\r\n"); + + if (self.output_dir) |output_dir| { + const full_dest = try fs.path.join(builder.allocator, [_][]const u8{ + output_dir, + fs.path.basename(output_path), + }); + try builder.updateFile(output_path, full_dest); + } else { + self.output_dir = fs.path.dirname(output_path).?; + } + } + + if (self.kind == Kind.Lib and self.is_dynamic and self.target.wantSharedLibSymLinks()) { + try doAtomicSymLinks(builder.allocator, self.getOutputPath(), self.major_only_filename, self.name_only_filename); + } + } +}; + +pub const RunStep = struct { + step: Step, + builder: *Builder, + + /// See also addArg and addArgs to modifying this directly + argv: ArrayList(Arg), + + /// Set this to modify the current working directory + cwd: ?[]const u8, + + /// Override this field to modify the environment, or use setEnvironmentVariable + env_map: ?*BufMap, + + pub const Arg = union(enum) { + Artifact: *LibExeObjStep, + Bytes: []u8, + }; + + pub fn create(builder: *Builder, name: []const u8) *RunStep { + const self = builder.allocator.create(RunStep) catch unreachable; + self.* = RunStep{ + .builder = builder, + .step = Step.init(name, builder.allocator, make), + .argv = ArrayList(Arg).init(builder.allocator), + .cwd = null, + .env_map = null, + }; + return self; + } + + pub fn addArtifactArg(self: *RunStep, artifact: *LibExeObjStep) void { + self.argv.append(Arg{ .Artifact = artifact }) catch unreachable; + self.step.dependOn(&artifact.step); + } + + pub fn addArg(self: *RunStep, arg: []const u8) void { + self.argv.append(Arg{ .Bytes = self.builder.dupe(arg) }) catch unreachable; + } + + pub fn addArgs(self: *RunStep, args: []const []const u8) void { + for (args) |arg| { + self.addArg(arg); + } + } + + pub fn clearEnvironment(self: *RunStep) void { + const new_env_map = self.builder.allocator.create(BufMap) catch unreachable; + new_env_map.* = BufMap.init(self.builder.allocator); + self.env_map = new_env_map; + } + + pub fn addPathDir(self: *RunStep, search_path: []const u8) void { + const PATH = if (std.os.windows.is_the_target) "Path" else "PATH"; + const env_map = self.getEnvMap(); + const prev_path = env_map.get(PATH) orelse { + env_map.set(PATH, search_path) catch unreachable; + return; + }; + const new_path = self.builder.fmt("{}" ++ [1]u8{fs.path.delimiter} ++ "{}", prev_path, search_path); + env_map.set(PATH, new_path) catch unreachable; + } + + pub fn getEnvMap(self: *RunStep) *BufMap { + return self.env_map orelse { + const env_map = self.builder.allocator.create(BufMap) catch unreachable; + env_map.* = process.getEnvMap(self.builder.allocator) catch unreachable; + self.env_map = env_map; + return env_map; + }; + } + + pub fn setEnvironmentVariable(self: *RunStep, key: []const u8, value: []const u8) void { + const env_map = self.getEnvMap(); + env_map.set(key, value) catch unreachable; + } + + fn make(step: *Step) !void { + const self = @fieldParentPtr(RunStep, "step", step); + + const cwd = if (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else self.builder.build_root; + + var argv = ArrayList([]const u8).init(self.builder.allocator); + for (self.argv.toSlice()) |arg| { + switch (arg) { + Arg.Bytes => |bytes| try argv.append(bytes), + Arg.Artifact => |artifact| { + if (artifact.target.isWindows()) { + // On Windows we don't have rpaths so we have to add .dll search paths to PATH + self.addPathForDynLibs(artifact); + } + const executable_path = artifact.installed_path orelse artifact.getOutputPath(); + try argv.append(executable_path); + }, + } + } + + return self.builder.spawnChildEnvMap(cwd, self.env_map orelse self.builder.env_map, argv.toSliceConst()); + } + + fn addPathForDynLibs(self: *RunStep, artifact: *LibExeObjStep) void { + for (artifact.link_objects.toSliceConst()) |link_object| { + switch (link_object) { + LibExeObjStep.LinkObject.OtherStep => |other| { + if (other.target.isWindows() and other.isDynamicLibrary()) { + self.addPathDir(fs.path.dirname(other.getOutputPath()).?); + self.addPathForDynLibs(other); + } + }, + else => {}, + } + } + } +}; + +const InstallArtifactStep = struct { + step: Step, + builder: *Builder, + artifact: *LibExeObjStep, + dest_dir: InstallDir, + pdb_dir: ?InstallDir, + + const Self = @This(); + + pub fn create(builder: *Builder, artifact: *LibExeObjStep) *Self { + if (artifact.install_step) |s| return s; + + const self = builder.allocator.create(Self) catch unreachable; + self.* = Self{ + .builder = builder, + .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make), + .artifact = artifact, + .dest_dir = switch (artifact.kind) { + .Obj => unreachable, + .Test => unreachable, + .Exe => InstallDir.Bin, + .Lib => InstallDir.Lib, + }, + .pdb_dir = if (artifact.producesPdbFile()) blk: { + if (artifact.kind == .Exe) { + break :blk InstallDir.Bin; + } else { + break :blk InstallDir.Lib; + } + } else null, + }; + self.step.dependOn(&artifact.step); + artifact.install_step = self; + + builder.pushInstalledFile(self.dest_dir, artifact.out_filename); + if (self.artifact.isDynamicLibrary()) { + builder.pushInstalledFile(.Lib, artifact.major_only_filename); + builder.pushInstalledFile(.Lib, artifact.name_only_filename); + } + if (self.pdb_dir) |pdb_dir| { + builder.pushInstalledFile(pdb_dir, artifact.out_pdb_filename); + } + return self; + } + + fn make(step: *Step) !void { + const self = @fieldParentPtr(Self, "step", step); + const builder = self.builder; + + const full_dest_path = builder.getInstallPath(self.dest_dir, self.artifact.out_filename); + try builder.updateFile(self.artifact.getOutputPath(), full_dest_path); + if (self.artifact.isDynamicLibrary()) { + try doAtomicSymLinks(builder.allocator, full_dest_path, self.artifact.major_only_filename, self.artifact.name_only_filename); + } + if (self.pdb_dir) |pdb_dir| { + const full_pdb_path = builder.getInstallPath(pdb_dir, self.artifact.out_pdb_filename); + try builder.updateFile(self.artifact.getOutputPdbPath(), full_pdb_path); + } + self.artifact.installed_path = full_dest_path; + } +}; + +pub const InstallFileStep = struct { + step: Step, + builder: *Builder, + src_path: []const u8, + dir: InstallDir, + dest_rel_path: []const u8, + + pub fn init( + builder: *Builder, + src_path: []const u8, + dir: InstallDir, + dest_rel_path: []const u8, + ) InstallFileStep { + builder.pushInstalledFile(dir, dest_rel_path); + return InstallFileStep{ + .builder = builder, + .step = Step.init(builder.fmt("install {}", src_path), builder.allocator, make), + .src_path = src_path, + .dir = dir, + .dest_rel_path = dest_rel_path, + }; + } + + fn make(step: *Step) !void { + const self = @fieldParentPtr(InstallFileStep, "step", step); + const full_dest_path = self.builder.getInstallPath(self.dir, self.dest_rel_path); + const full_src_path = self.builder.pathFromRoot(self.src_path); + try self.builder.updateFile(full_src_path, full_dest_path); + } +}; + +pub const InstallDirectoryOptions = struct { + source_dir: []const u8, + install_dir: InstallDir, + install_subdir: []const u8, + exclude_extensions: ?[]const []const u8 = null, +}; + +pub const InstallDirStep = struct { + step: Step, + builder: *Builder, + options: InstallDirectoryOptions, + + pub fn init( + builder: *Builder, + options: InstallDirectoryOptions, + ) InstallDirStep { + builder.pushInstalledFile(options.install_dir, options.install_subdir); + return InstallDirStep{ + .builder = builder, + .step = Step.init(builder.fmt("install {}/", options.source_dir), builder.allocator, make), + .options = options, + }; + } + + fn make(step: *Step) !void { + const self = @fieldParentPtr(InstallDirStep, "step", step); + const dest_prefix = self.builder.getInstallPath(self.options.install_dir, self.options.install_subdir); + const full_src_dir = self.builder.pathFromRoot(self.options.source_dir); + var it = try fs.walkPath(self.builder.allocator, full_src_dir); + next_entry: while (try it.next()) |entry| { + if (self.options.exclude_extensions) |ext_list| for (ext_list) |ext| { + if (mem.endsWith(u8, entry.path, ext)) { + continue :next_entry; + } + }; + + const rel_path = entry.path[full_src_dir.len + 1 ..]; + const dest_path = try fs.path.join(self.builder.allocator, [_][]const u8{ dest_prefix, rel_path }); + switch (entry.kind) { + .Directory => try fs.makePath(self.builder.allocator, dest_path), + .File => try self.builder.updateFile(entry.path, dest_path), + else => continue, + } + } + } +}; + +pub const WriteFileStep = struct { + step: Step, + builder: *Builder, + file_path: []const u8, + data: []const u8, + + pub fn init(builder: *Builder, file_path: []const u8, data: []const u8) WriteFileStep { + return WriteFileStep{ + .builder = builder, + .step = Step.init(builder.fmt("writefile {}", file_path), builder.allocator, make), + .file_path = file_path, + .data = data, + }; + } + + fn make(step: *Step) !void { + const self = @fieldParentPtr(WriteFileStep, "step", step); + const full_path = self.builder.pathFromRoot(self.file_path); + const full_path_dir = fs.path.dirname(full_path) orelse "."; + fs.makePath(self.builder.allocator, full_path_dir) catch |err| { + warn("unable to make path {}: {}\n", full_path_dir, @errorName(err)); + return err; + }; + io.writeFile(full_path, self.data) catch |err| { + warn("unable to write {}: {}\n", full_path, @errorName(err)); + return err; + }; + } +}; + +pub const LogStep = struct { + step: Step, + builder: *Builder, + data: []const u8, + + pub fn init(builder: *Builder, data: []const u8) LogStep { + return LogStep{ + .builder = builder, + .step = Step.init(builder.fmt("log {}", data), builder.allocator, make), + .data = data, + }; + } + + fn make(step: *Step) anyerror!void { + const self = @fieldParentPtr(LogStep, "step", step); + warn("{}", self.data); + } +}; + +pub const RemoveDirStep = struct { + step: Step, + builder: *Builder, + dir_path: []const u8, + + pub fn init(builder: *Builder, dir_path: []const u8) RemoveDirStep { + return RemoveDirStep{ + .builder = builder, + .step = Step.init(builder.fmt("RemoveDir {}", dir_path), builder.allocator, make), + .dir_path = dir_path, + }; + } + + fn make(step: *Step) !void { + const self = @fieldParentPtr(RemoveDirStep, "step", step); + + const full_path = self.builder.pathFromRoot(self.dir_path); + fs.deleteTree(self.builder.allocator, full_path) catch |err| { + warn("Unable to remove {}: {}\n", full_path, @errorName(err)); + return err; + }; + } +}; + +pub const Step = struct { + name: []const u8, + makeFn: fn (self: *Step) anyerror!void, + dependencies: ArrayList(*Step), + loop_flag: bool, + done_flag: bool, + + pub fn init(name: []const u8, allocator: *Allocator, makeFn: fn (*Step) anyerror!void) Step { + return Step{ + .name = name, + .makeFn = makeFn, + .dependencies = ArrayList(*Step).init(allocator), + .loop_flag = false, + .done_flag = false, + }; + } + pub fn initNoOp(name: []const u8, allocator: *Allocator) Step { + return init(name, allocator, makeNoOp); + } + + pub fn make(self: *Step) !void { + if (self.done_flag) return; + + try self.makeFn(self); + self.done_flag = true; + } + + pub fn dependOn(self: *Step, other: *Step) void { + self.dependencies.append(other) catch unreachable; + } + + fn makeNoOp(self: *Step) anyerror!void {} +}; + +fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void { + const out_dir = fs.path.dirname(output_path) orelse "."; + const out_basename = fs.path.basename(output_path); + // sym link for libfoo.so.1 to libfoo.so.1.2.3 + const major_only_path = fs.path.join( + allocator, + [_][]const u8{ out_dir, filename_major_only }, + ) catch unreachable; + fs.atomicSymLink(allocator, out_basename, major_only_path) catch |err| { + warn("Unable to symlink {} -> {}\n", major_only_path, out_basename); + return err; + }; + // sym link for libfoo.so to libfoo.so.1 + const name_only_path = fs.path.join( + allocator, + [_][]const u8{ out_dir, filename_name_only }, + ) catch unreachable; + fs.atomicSymLink(allocator, filename_major_only, name_only_path) catch |err| { + warn("Unable to symlink {} -> {}\n", name_only_path, filename_major_only); + return err; + }; +} + +pub const InstallDir = enum { + Prefix, + Lib, + Bin, +}; + +pub const InstalledFile = struct { + dir: InstallDir, + path: []const u8, +}; diff --git a/std/build/fmt.zig b/lib/std/build/fmt.zig diff --git a/std/c.zig b/lib/std/c.zig diff --git a/std/c/darwin.zig b/lib/std/c/darwin.zig diff --git a/std/c/freebsd.zig b/lib/std/c/freebsd.zig diff --git a/std/c/linux.zig b/lib/std/c/linux.zig diff --git a/std/c/netbsd.zig b/lib/std/c/netbsd.zig diff --git a/std/c/windows.zig b/lib/std/c/windows.zig diff --git a/std/child_process.zig b/lib/std/child_process.zig diff --git a/std/coff.zig b/lib/std/coff.zig diff --git a/std/crypto.zig b/lib/std/crypto.zig diff --git a/std/crypto/benchmark.zig b/lib/std/crypto/benchmark.zig diff --git a/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig diff --git a/std/crypto/chacha20.zig b/lib/std/crypto/chacha20.zig diff --git a/std/crypto/gimli.zig b/lib/std/crypto/gimli.zig diff --git a/std/crypto/hmac.zig b/lib/std/crypto/hmac.zig diff --git a/std/crypto/md5.zig b/lib/std/crypto/md5.zig diff --git a/std/crypto/poly1305.zig b/lib/std/crypto/poly1305.zig diff --git a/std/crypto/sha1.zig b/lib/std/crypto/sha1.zig diff --git a/std/crypto/sha2.zig b/lib/std/crypto/sha2.zig diff --git a/std/crypto/sha3.zig b/lib/std/crypto/sha3.zig diff --git a/std/crypto/test.zig b/lib/std/crypto/test.zig diff --git a/std/crypto/x25519.zig b/lib/std/crypto/x25519.zig diff --git a/std/cstr.zig b/lib/std/cstr.zig diff --git a/std/debug.zig b/lib/std/debug.zig diff --git a/std/debug/failing_allocator.zig b/lib/std/debug/failing_allocator.zig diff --git a/std/debug/leb128.zig b/lib/std/debug/leb128.zig diff --git a/std/dwarf.zig b/lib/std/dwarf.zig diff --git a/std/dynamic_library.zig b/lib/std/dynamic_library.zig diff --git a/std/elf.zig b/lib/std/elf.zig diff --git a/std/event.zig b/lib/std/event.zig diff --git a/std/event/channel.zig b/lib/std/event/channel.zig diff --git a/std/event/fs.zig b/lib/std/event/fs.zig diff --git a/std/event/future.zig b/lib/std/event/future.zig diff --git a/std/event/group.zig b/lib/std/event/group.zig diff --git a/std/event/lock.zig b/lib/std/event/lock.zig diff --git a/std/event/locked.zig b/lib/std/event/locked.zig diff --git a/std/event/loop.zig b/lib/std/event/loop.zig diff --git a/std/event/net.zig b/lib/std/event/net.zig diff --git a/std/event/rwlock.zig b/lib/std/event/rwlock.zig diff --git a/std/event/rwlocked.zig b/lib/std/event/rwlocked.zig diff --git a/std/fmt.zig b/lib/std/fmt.zig diff --git a/std/fmt/errol.zig b/lib/std/fmt/errol.zig diff --git a/std/fmt/errol/enum3.zig b/lib/std/fmt/errol/enum3.zig diff --git a/std/fmt/errol/lookup.zig b/lib/std/fmt/errol/lookup.zig diff --git a/std/fmt/parse_float.zig b/lib/std/fmt/parse_float.zig diff --git a/std/fs.zig b/lib/std/fs.zig diff --git a/std/fs/file.zig b/lib/std/fs/file.zig diff --git a/std/fs/get_app_data_dir.zig b/lib/std/fs/get_app_data_dir.zig diff --git a/std/fs/path.zig b/lib/std/fs/path.zig diff --git a/std/hash.zig b/lib/std/hash.zig diff --git a/std/hash/adler.zig b/lib/std/hash/adler.zig diff --git a/std/hash/auto_hash.zig b/lib/std/hash/auto_hash.zig diff --git a/std/hash/benchmark.zig b/lib/std/hash/benchmark.zig diff --git a/std/hash/cityhash.zig b/lib/std/hash/cityhash.zig diff --git a/std/hash/crc.zig b/lib/std/hash/crc.zig diff --git a/std/hash/fnv.zig b/lib/std/hash/fnv.zig diff --git a/std/hash/murmur.zig b/lib/std/hash/murmur.zig diff --git a/std/hash/siphash.zig b/lib/std/hash/siphash.zig diff --git a/std/hash/wyhash.zig b/lib/std/hash/wyhash.zig diff --git a/std/hash_map.zig b/lib/std/hash_map.zig diff --git a/std/heap.zig b/lib/std/heap.zig diff --git a/std/heap/logging_allocator.zig b/lib/std/heap/logging_allocator.zig diff --git a/std/http.zig b/lib/std/http.zig diff --git a/std/http/headers.zig b/lib/std/http/headers.zig diff --git a/std/io.zig b/lib/std/io.zig diff --git a/std/io/c_out_stream.zig b/lib/std/io/c_out_stream.zig diff --git a/std/io/in_stream.zig b/lib/std/io/in_stream.zig diff --git a/std/io/seekable_stream.zig b/lib/std/io/seekable_stream.zig diff --git a/std/io/test.zig b/lib/std/io/test.zig diff --git a/std/json.zig b/lib/std/json.zig diff --git a/std/json/test.zig b/lib/std/json/test.zig diff --git a/std/lazy_init.zig b/lib/std/lazy_init.zig diff --git a/std/linked_list.zig b/lib/std/linked_list.zig diff --git a/std/macho.zig b/lib/std/macho.zig diff --git a/std/math.zig b/lib/std/math.zig diff --git a/std/math/acos.zig b/lib/std/math/acos.zig diff --git a/std/math/acosh.zig b/lib/std/math/acosh.zig diff --git a/std/math/asin.zig b/lib/std/math/asin.zig diff --git a/std/math/asinh.zig b/lib/std/math/asinh.zig diff --git a/std/math/atan.zig b/lib/std/math/atan.zig diff --git a/std/math/atan2.zig b/lib/std/math/atan2.zig diff --git a/std/math/atanh.zig b/lib/std/math/atanh.zig diff --git a/std/math/big.zig b/lib/std/math/big.zig diff --git a/std/math/big/int.zig b/lib/std/math/big/int.zig diff --git a/std/math/big/rational.zig b/lib/std/math/big/rational.zig diff --git a/std/math/cbrt.zig b/lib/std/math/cbrt.zig diff --git a/std/math/ceil.zig b/lib/std/math/ceil.zig diff --git a/std/math/complex.zig b/lib/std/math/complex.zig diff --git a/std/math/complex/abs.zig b/lib/std/math/complex/abs.zig diff --git a/std/math/complex/acos.zig b/lib/std/math/complex/acos.zig diff --git a/std/math/complex/acosh.zig b/lib/std/math/complex/acosh.zig diff --git a/std/math/complex/arg.zig b/lib/std/math/complex/arg.zig diff --git a/std/math/complex/asin.zig b/lib/std/math/complex/asin.zig diff --git a/std/math/complex/asinh.zig b/lib/std/math/complex/asinh.zig diff --git a/std/math/complex/atan.zig b/lib/std/math/complex/atan.zig diff --git a/std/math/complex/atanh.zig b/lib/std/math/complex/atanh.zig diff --git a/std/math/complex/conj.zig b/lib/std/math/complex/conj.zig diff --git a/std/math/complex/cos.zig b/lib/std/math/complex/cos.zig diff --git a/std/math/complex/cosh.zig b/lib/std/math/complex/cosh.zig diff --git a/std/math/complex/exp.zig b/lib/std/math/complex/exp.zig diff --git a/std/math/complex/ldexp.zig b/lib/std/math/complex/ldexp.zig diff --git a/std/math/complex/log.zig b/lib/std/math/complex/log.zig diff --git a/std/math/complex/pow.zig b/lib/std/math/complex/pow.zig diff --git a/std/math/complex/proj.zig b/lib/std/math/complex/proj.zig diff --git a/std/math/complex/sin.zig b/lib/std/math/complex/sin.zig diff --git a/std/math/complex/sinh.zig b/lib/std/math/complex/sinh.zig diff --git a/std/math/complex/sqrt.zig b/lib/std/math/complex/sqrt.zig diff --git a/std/math/complex/tan.zig b/lib/std/math/complex/tan.zig diff --git a/std/math/complex/tanh.zig b/lib/std/math/complex/tanh.zig diff --git a/std/math/copysign.zig b/lib/std/math/copysign.zig diff --git a/std/math/cos.zig b/lib/std/math/cos.zig diff --git a/std/math/cosh.zig b/lib/std/math/cosh.zig diff --git a/std/math/exp.zig b/lib/std/math/exp.zig diff --git a/std/math/exp2.zig b/lib/std/math/exp2.zig diff --git a/std/math/expm1.zig b/lib/std/math/expm1.zig diff --git a/std/math/expo2.zig b/lib/std/math/expo2.zig diff --git a/std/math/fabs.zig b/lib/std/math/fabs.zig diff --git a/std/math/floor.zig b/lib/std/math/floor.zig diff --git a/std/math/fma.zig b/lib/std/math/fma.zig diff --git a/std/math/frexp.zig b/lib/std/math/frexp.zig diff --git a/std/math/hypot.zig b/lib/std/math/hypot.zig diff --git a/std/math/ilogb.zig b/lib/std/math/ilogb.zig diff --git a/std/math/inf.zig b/lib/std/math/inf.zig diff --git a/std/math/isfinite.zig b/lib/std/math/isfinite.zig diff --git a/std/math/isinf.zig b/lib/std/math/isinf.zig diff --git a/std/math/isnan.zig b/lib/std/math/isnan.zig diff --git a/std/math/isnormal.zig b/lib/std/math/isnormal.zig diff --git a/std/math/ln.zig b/lib/std/math/ln.zig diff --git a/std/math/log.zig b/lib/std/math/log.zig diff --git a/std/math/log10.zig b/lib/std/math/log10.zig diff --git a/std/math/log1p.zig b/lib/std/math/log1p.zig diff --git a/std/math/log2.zig b/lib/std/math/log2.zig diff --git a/std/math/modf.zig b/lib/std/math/modf.zig diff --git a/std/math/nan.zig b/lib/std/math/nan.zig diff --git a/std/math/pow.zig b/lib/std/math/pow.zig diff --git a/std/math/powi.zig b/lib/std/math/powi.zig diff --git a/std/math/round.zig b/lib/std/math/round.zig diff --git a/std/math/scalbn.zig b/lib/std/math/scalbn.zig diff --git a/std/math/signbit.zig b/lib/std/math/signbit.zig diff --git a/std/math/sin.zig b/lib/std/math/sin.zig diff --git a/std/math/sinh.zig b/lib/std/math/sinh.zig diff --git a/std/math/sqrt.zig b/lib/std/math/sqrt.zig diff --git a/std/math/tan.zig b/lib/std/math/tan.zig diff --git a/std/math/tanh.zig b/lib/std/math/tanh.zig diff --git a/std/math/trunc.zig b/lib/std/math/trunc.zig diff --git a/std/mem.zig b/lib/std/mem.zig diff --git a/std/meta.zig b/lib/std/meta.zig diff --git a/std/meta/trait.zig b/lib/std/meta/trait.zig diff --git a/std/mutex.zig b/lib/std/mutex.zig diff --git a/std/net.zig b/lib/std/net.zig diff --git a/std/os.zig b/lib/std/os.zig diff --git a/std/os/bits.zig b/lib/std/os/bits.zig diff --git a/std/os/bits/darwin.zig b/lib/std/os/bits/darwin.zig diff --git a/std/os/bits/freebsd.zig b/lib/std/os/bits/freebsd.zig diff --git a/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig diff --git a/std/os/bits/linux/arm-eabi.zig b/lib/std/os/bits/linux/arm-eabi.zig diff --git a/std/os/bits/linux/arm64.zig b/lib/std/os/bits/linux/arm64.zig diff --git a/std/os/bits/linux/errno.zig b/lib/std/os/bits/linux/errno.zig diff --git a/std/os/bits/linux/riscv64.zig b/lib/std/os/bits/linux/riscv64.zig diff --git a/std/os/bits/linux/x86_64.zig b/lib/std/os/bits/linux/x86_64.zig diff --git a/std/os/bits/netbsd.zig b/lib/std/os/bits/netbsd.zig diff --git a/std/os/bits/wasi.zig b/lib/std/os/bits/wasi.zig diff --git a/std/os/bits/windows.zig b/lib/std/os/bits/windows.zig diff --git a/std/os/darwin.zig b/lib/std/os/darwin.zig diff --git a/std/os/freebsd.zig b/lib/std/os/freebsd.zig diff --git a/std/os/linux.zig b/lib/std/os/linux.zig diff --git a/std/os/linux/arm-eabi.zig b/lib/std/os/linux/arm-eabi.zig diff --git a/std/os/linux/arm64.zig b/lib/std/os/linux/arm64.zig diff --git a/std/os/linux/riscv64.zig b/lib/std/os/linux/riscv64.zig diff --git a/std/os/linux/test.zig b/lib/std/os/linux/test.zig diff --git a/std/os/linux/tls.zig b/lib/std/os/linux/tls.zig diff --git a/std/os/linux/vdso.zig b/lib/std/os/linux/vdso.zig diff --git a/std/os/linux/x86_64.zig b/lib/std/os/linux/x86_64.zig diff --git a/std/os/netbsd.zig b/lib/std/os/netbsd.zig diff --git a/std/os/test.zig b/lib/std/os/test.zig diff --git a/std/os/uefi.zig b/lib/std/os/uefi.zig diff --git a/std/os/uefi/protocols.zig b/lib/std/os/uefi/protocols.zig diff --git a/std/os/uefi/protocols/absolute_pointer_protocol.zig b/lib/std/os/uefi/protocols/absolute_pointer_protocol.zig diff --git a/std/os/uefi/protocols/edid_active_protocol.zig b/lib/std/os/uefi/protocols/edid_active_protocol.zig diff --git a/std/os/uefi/protocols/edid_discovered_protocol.zig b/lib/std/os/uefi/protocols/edid_discovered_protocol.zig diff --git a/std/os/uefi/protocols/edid_override_protocol.zig b/lib/std/os/uefi/protocols/edid_override_protocol.zig diff --git a/std/os/uefi/protocols/graphics_output_protocol.zig b/lib/std/os/uefi/protocols/graphics_output_protocol.zig diff --git a/std/os/uefi/protocols/rng_protocol.zig b/lib/std/os/uefi/protocols/rng_protocol.zig diff --git a/std/os/uefi/protocols/simple_pointer_protocol.zig b/lib/std/os/uefi/protocols/simple_pointer_protocol.zig diff --git a/std/os/uefi/protocols/simple_text_input_ex_protocol.zig b/lib/std/os/uefi/protocols/simple_text_input_ex_protocol.zig diff --git a/std/os/uefi/protocols/simple_text_output_protocol.zig b/lib/std/os/uefi/protocols/simple_text_output_protocol.zig diff --git a/std/os/uefi/status.zig b/lib/std/os/uefi/status.zig diff --git a/std/os/uefi/tables.zig b/lib/std/os/uefi/tables.zig diff --git a/std/os/uefi/tables/boot_services.zig b/lib/std/os/uefi/tables/boot_services.zig diff --git a/std/os/uefi/tables/configuration_table.zig b/lib/std/os/uefi/tables/configuration_table.zig diff --git a/std/os/uefi/tables/runtime_services.zig b/lib/std/os/uefi/tables/runtime_services.zig diff --git a/std/os/uefi/tables/system_table.zig b/lib/std/os/uefi/tables/system_table.zig diff --git a/std/os/uefi/tables/table_header.zig b/lib/std/os/uefi/tables/table_header.zig diff --git a/std/os/wasi.zig b/lib/std/os/wasi.zig diff --git a/std/os/windows.zig b/lib/std/os/windows.zig diff --git a/std/os/windows/advapi32.zig b/lib/std/os/windows/advapi32.zig diff --git a/std/os/windows/bits.zig b/lib/std/os/windows/bits.zig diff --git a/std/os/windows/error.zig b/lib/std/os/windows/error.zig diff --git a/std/os/windows/kernel32.zig b/lib/std/os/windows/kernel32.zig diff --git a/std/os/windows/lang.zig b/lib/std/os/windows/lang.zig diff --git a/std/os/windows/ntdll.zig b/lib/std/os/windows/ntdll.zig diff --git a/std/os/windows/ole32.zig b/lib/std/os/windows/ole32.zig diff --git a/std/os/windows/shell32.zig b/lib/std/os/windows/shell32.zig diff --git a/std/os/windows/status.zig b/lib/std/os/windows/status.zig diff --git a/std/os/windows/sublang.zig b/lib/std/os/windows/sublang.zig diff --git a/std/os/zen.zig b/lib/std/os/zen.zig diff --git a/std/packed_int_array.zig b/lib/std/packed_int_array.zig diff --git a/std/pdb.zig b/lib/std/pdb.zig diff --git a/std/priority_queue.zig b/lib/std/priority_queue.zig diff --git a/std/process.zig b/lib/std/process.zig diff --git a/std/rand.zig b/lib/std/rand.zig diff --git a/std/rand/ziggurat.zig b/lib/std/rand/ziggurat.zig diff --git a/std/rb.zig b/lib/std/rb.zig diff --git a/std/segmented_list.zig b/lib/std/segmented_list.zig diff --git a/std/sort.zig b/lib/std/sort.zig diff --git a/lib/std/special/build_runner.zig b/lib/std/special/build_runner.zig @@ -0,0 +1,221 @@ +const root = @import("@build"); +const std = @import("std"); +const builtin = @import("builtin"); +const io = std.io; +const fmt = std.fmt; +const Builder = std.build.Builder; +const mem = std.mem; +const process = std.process; +const ArrayList = std.ArrayList; +const warn = std.debug.warn; +const File = std.fs.File; + +pub fn main() !void { + var arg_it = process.args(); + + // Here we use an ArenaAllocator backed by a DirectAllocator because a build is a short-lived, + // one shot program. We don't need to waste time freeing memory and finding places to squish + // bytes into. So we free everything all at once at the very end. + + var arena = std.heap.ArenaAllocator.init(std.heap.direct_allocator); + defer arena.deinit(); + + const allocator = &arena.allocator; + + // skip my own exe name + _ = arg_it.skip(); + + const zig_exe = try unwrapArg(arg_it.next(allocator) orelse { + warn("Expected first argument to be path to zig compiler\n"); + return error.InvalidArgs; + }); + const build_root = try unwrapArg(arg_it.next(allocator) orelse { + warn("Expected second argument to be build root directory path\n"); + return error.InvalidArgs; + }); + const cache_root = try unwrapArg(arg_it.next(allocator) orelse { + warn("Expected third argument to be cache root directory path\n"); + return error.InvalidArgs; + }); + + const builder = try Builder.create(allocator, zig_exe, build_root, cache_root); + defer builder.destroy(); + + var targets = ArrayList([]const u8).init(allocator); + + var stderr_file = io.getStdErr(); + var stderr_file_stream: File.OutStream = undefined; + var stderr_stream = if (stderr_file) |f| x: { + stderr_file_stream = f.outStream(); + break :x &stderr_file_stream.stream; + } else |err| err; + + var stdout_file = io.getStdOut(); + var stdout_file_stream: File.OutStream = undefined; + var stdout_stream = if (stdout_file) |f| x: { + stdout_file_stream = f.outStream(); + break :x &stdout_file_stream.stream; + } else |err| err; + + while (arg_it.next(allocator)) |err_or_arg| { + const arg = try unwrapArg(err_or_arg); + if (mem.startsWith(u8, arg, "-D")) { + const option_contents = arg[2..]; + if (option_contents.len == 0) { + warn("Expected option name after '-D'\n\n"); + return usageAndErr(builder, false, try stderr_stream); + } + if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| { + const option_name = option_contents[0..name_end]; + const option_value = option_contents[name_end + 1 ..]; + if (try builder.addUserInputOption(option_name, option_value)) + return usageAndErr(builder, false, try stderr_stream); + } else { + if (try builder.addUserInputFlag(option_contents)) + return usageAndErr(builder, false, try stderr_stream); + } + } else if (mem.startsWith(u8, arg, "-")) { + if (mem.eql(u8, arg, "--verbose")) { + builder.verbose = true; + } else if (mem.eql(u8, arg, "--help")) { + return usage(builder, false, try stdout_stream); + } else if (mem.eql(u8, arg, "--prefix")) { + builder.install_prefix = try unwrapArg(arg_it.next(allocator) orelse { + warn("Expected argument after --prefix\n\n"); + return usageAndErr(builder, false, try stderr_stream); + }); + } else if (mem.eql(u8, arg, "--search-prefix")) { + const search_prefix = try unwrapArg(arg_it.next(allocator) orelse { + warn("Expected argument after --search-prefix\n\n"); + return usageAndErr(builder, false, try stderr_stream); + }); + builder.addSearchPrefix(search_prefix); + } else if (mem.eql(u8, arg, "--override-lib-dir")) { + builder.override_lib_dir = try unwrapArg(arg_it.next(allocator) orelse { + warn("Expected argument after --override-lib-dir\n\n"); + return usageAndErr(builder, false, try stderr_stream); + }); + } else if (mem.eql(u8, arg, "--verbose-tokenize")) { + builder.verbose_tokenize = true; + } else if (mem.eql(u8, arg, "--verbose-ast")) { + builder.verbose_ast = true; + } else if (mem.eql(u8, arg, "--verbose-link")) { + builder.verbose_link = true; + } else if (mem.eql(u8, arg, "--verbose-ir")) { + builder.verbose_ir = true; + } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { + builder.verbose_llvm_ir = true; + } else if (mem.eql(u8, arg, "--verbose-cimport")) { + builder.verbose_cimport = true; + } else if (mem.eql(u8, arg, "--verbose-cc")) { + builder.verbose_cc = true; + } else { + warn("Unrecognized argument: {}\n\n", arg); + return usageAndErr(builder, false, try stderr_stream); + } + } else { + try targets.append(arg); + } + } + + builder.resolveInstallPrefix(); + try runBuild(builder); + + if (builder.validateUserInputDidItFail()) + return usageAndErr(builder, true, try stderr_stream); + + builder.make(targets.toSliceConst()) catch |err| { + switch (err) { + error.InvalidStepName => { + return usageAndErr(builder, true, try stderr_stream); + }, + error.UncleanExit => process.exit(1), + else => return err, + } + }; +} + +fn runBuild(builder: *Builder) anyerror!void { + switch (@typeId(@typeOf(root.build).ReturnType)) { + .Void => root.build(builder), + .ErrorUnion => try root.build(builder), + else => @compileError("expected return type of build to be 'void' or '!void'"), + } +} + +fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void { + // run the build script to collect the options + if (!already_ran_build) { + builder.setInstallPrefix(null); + builder.resolveInstallPrefix(); + try runBuild(builder); + } + + try out_stream.print( + \\Usage: {} build [steps] [options] + \\ + \\Steps: + \\ + , builder.zig_exe); + + const allocator = builder.allocator; + for (builder.top_level_steps.toSliceConst()) |top_level_step| { + const name = if (&top_level_step.step == builder.default_step) + try fmt.allocPrint(allocator, "{} (default)", top_level_step.step.name) + else + top_level_step.step.name; + try out_stream.print(" {s:22} {}\n", name, top_level_step.description); + } + + try out_stream.write( + \\ + \\General Options: + \\ --help Print this help and exit + \\ --verbose Print commands before executing them + \\ --prefix [path] Override default install prefix + \\ --search-prefix [path] Add a path to look for binaries, libraries, headers + \\ + \\Project-Specific Options: + \\ + ); + + if (builder.available_options_list.len == 0) { + try out_stream.print(" (none)\n"); + } else { + for (builder.available_options_list.toSliceConst()) |option| { + const name = try fmt.allocPrint(allocator, " -D{}=[{}]", option.name, Builder.typeIdName(option.type_id)); + defer allocator.free(name); + try out_stream.print("{s:24} {}\n", name, option.description); + } + } + + try out_stream.write( + \\ + \\Advanced Options: + \\ --build-file [file] Override path to build.zig + \\ --cache-dir [path] Override path to zig cache directory + \\ --override-lib-dir [arg] Override path to Zig lib directory + \\ --verbose-tokenize Enable compiler debug output for tokenization + \\ --verbose-ast Enable compiler debug output for parsing into an AST + \\ --verbose-link Enable compiler debug output for linking + \\ --verbose-ir Enable compiler debug output for Zig IR + \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR + \\ --verbose-cimport Enable compiler debug output for C imports + \\ --verbose-cc Enable compiler debug output for C compilation + \\ + ); +} + +fn usageAndErr(builder: *Builder, already_ran_build: bool, out_stream: var) void { + usage(builder, already_ran_build, out_stream) catch {}; + process.exit(1); +} + +const UnwrapArgError = error{OutOfMemory}; + +fn unwrapArg(arg: UnwrapArgError![]u8) UnwrapArgError![]u8 { + return arg catch |err| { + warn("Unable to parse command line: {}\n", err); + return err; + }; +} diff --git a/std/special/c.zig b/lib/std/special/c.zig diff --git a/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig diff --git a/std/special/compiler_rt/README.md b/lib/std/special/compiler_rt/README.md diff --git a/std/special/compiler_rt/addXf3.zig b/lib/std/special/compiler_rt/addXf3.zig diff --git a/std/special/compiler_rt/addXf3_test.zig b/lib/std/special/compiler_rt/addXf3_test.zig diff --git a/std/special/compiler_rt/arm/aeabi_dcmp.zig b/lib/std/special/compiler_rt/arm/aeabi_dcmp.zig diff --git a/std/special/compiler_rt/arm/aeabi_fcmp.zig b/lib/std/special/compiler_rt/arm/aeabi_fcmp.zig diff --git a/std/special/compiler_rt/ashlti3.zig b/lib/std/special/compiler_rt/ashlti3.zig diff --git a/std/special/compiler_rt/ashlti3_test.zig b/lib/std/special/compiler_rt/ashlti3_test.zig diff --git a/std/special/compiler_rt/ashrti3.zig b/lib/std/special/compiler_rt/ashrti3.zig diff --git a/std/special/compiler_rt/ashrti3_test.zig b/lib/std/special/compiler_rt/ashrti3_test.zig diff --git a/std/special/compiler_rt/aulldiv.zig b/lib/std/special/compiler_rt/aulldiv.zig diff --git a/std/special/compiler_rt/aullrem.zig b/lib/std/special/compiler_rt/aullrem.zig diff --git a/std/special/compiler_rt/comparedf2.zig b/lib/std/special/compiler_rt/comparedf2.zig diff --git a/std/special/compiler_rt/comparedf2_test.zig b/lib/std/special/compiler_rt/comparedf2_test.zig diff --git a/std/special/compiler_rt/comparesf2.zig b/lib/std/special/compiler_rt/comparesf2.zig diff --git a/std/special/compiler_rt/comparesf2_test.zig b/lib/std/special/compiler_rt/comparesf2_test.zig diff --git a/std/special/compiler_rt/comparetf2.zig b/lib/std/special/compiler_rt/comparetf2.zig diff --git a/std/special/compiler_rt/divdf3.zig b/lib/std/special/compiler_rt/divdf3.zig diff --git a/std/special/compiler_rt/divdf3_test.zig b/lib/std/special/compiler_rt/divdf3_test.zig diff --git a/std/special/compiler_rt/divsf3.zig b/lib/std/special/compiler_rt/divsf3.zig diff --git a/std/special/compiler_rt/divsf3_test.zig b/lib/std/special/compiler_rt/divsf3_test.zig diff --git a/std/special/compiler_rt/divti3.zig b/lib/std/special/compiler_rt/divti3.zig diff --git a/std/special/compiler_rt/divti3_test.zig b/lib/std/special/compiler_rt/divti3_test.zig diff --git a/std/special/compiler_rt/extendXfYf2.zig b/lib/std/special/compiler_rt/extendXfYf2.zig diff --git a/std/special/compiler_rt/extendXfYf2_test.zig b/lib/std/special/compiler_rt/extendXfYf2_test.zig diff --git a/std/special/compiler_rt/fixdfdi.zig b/lib/std/special/compiler_rt/fixdfdi.zig diff --git a/std/special/compiler_rt/fixdfdi_test.zig b/lib/std/special/compiler_rt/fixdfdi_test.zig diff --git a/std/special/compiler_rt/fixdfsi.zig b/lib/std/special/compiler_rt/fixdfsi.zig diff --git a/std/special/compiler_rt/fixdfsi_test.zig b/lib/std/special/compiler_rt/fixdfsi_test.zig diff --git a/std/special/compiler_rt/fixdfti.zig b/lib/std/special/compiler_rt/fixdfti.zig diff --git a/std/special/compiler_rt/fixdfti_test.zig b/lib/std/special/compiler_rt/fixdfti_test.zig diff --git a/std/special/compiler_rt/fixint.zig b/lib/std/special/compiler_rt/fixint.zig diff --git a/std/special/compiler_rt/fixint_test.zig b/lib/std/special/compiler_rt/fixint_test.zig diff --git a/std/special/compiler_rt/fixsfdi.zig b/lib/std/special/compiler_rt/fixsfdi.zig diff --git a/std/special/compiler_rt/fixsfdi_test.zig b/lib/std/special/compiler_rt/fixsfdi_test.zig diff --git a/std/special/compiler_rt/fixsfsi.zig b/lib/std/special/compiler_rt/fixsfsi.zig diff --git a/std/special/compiler_rt/fixsfsi_test.zig b/lib/std/special/compiler_rt/fixsfsi_test.zig diff --git a/std/special/compiler_rt/fixsfti.zig b/lib/std/special/compiler_rt/fixsfti.zig diff --git a/std/special/compiler_rt/fixsfti_test.zig b/lib/std/special/compiler_rt/fixsfti_test.zig diff --git a/std/special/compiler_rt/fixtfdi.zig b/lib/std/special/compiler_rt/fixtfdi.zig diff --git a/std/special/compiler_rt/fixtfdi_test.zig b/lib/std/special/compiler_rt/fixtfdi_test.zig diff --git a/std/special/compiler_rt/fixtfsi.zig b/lib/std/special/compiler_rt/fixtfsi.zig diff --git a/std/special/compiler_rt/fixtfsi_test.zig b/lib/std/special/compiler_rt/fixtfsi_test.zig diff --git a/std/special/compiler_rt/fixtfti.zig b/lib/std/special/compiler_rt/fixtfti.zig diff --git a/std/special/compiler_rt/fixtfti_test.zig b/lib/std/special/compiler_rt/fixtfti_test.zig diff --git a/std/special/compiler_rt/fixuint.zig b/lib/std/special/compiler_rt/fixuint.zig diff --git a/std/special/compiler_rt/fixunsdfdi.zig b/lib/std/special/compiler_rt/fixunsdfdi.zig diff --git a/std/special/compiler_rt/fixunsdfdi_test.zig b/lib/std/special/compiler_rt/fixunsdfdi_test.zig diff --git a/std/special/compiler_rt/fixunsdfsi.zig b/lib/std/special/compiler_rt/fixunsdfsi.zig diff --git a/std/special/compiler_rt/fixunsdfsi_test.zig b/lib/std/special/compiler_rt/fixunsdfsi_test.zig diff --git a/std/special/compiler_rt/fixunsdfti.zig b/lib/std/special/compiler_rt/fixunsdfti.zig diff --git a/std/special/compiler_rt/fixunsdfti_test.zig b/lib/std/special/compiler_rt/fixunsdfti_test.zig diff --git a/std/special/compiler_rt/fixunssfdi.zig b/lib/std/special/compiler_rt/fixunssfdi.zig diff --git a/std/special/compiler_rt/fixunssfdi_test.zig b/lib/std/special/compiler_rt/fixunssfdi_test.zig diff --git a/std/special/compiler_rt/fixunssfsi.zig b/lib/std/special/compiler_rt/fixunssfsi.zig diff --git a/std/special/compiler_rt/fixunssfsi_test.zig b/lib/std/special/compiler_rt/fixunssfsi_test.zig diff --git a/std/special/compiler_rt/fixunssfti.zig b/lib/std/special/compiler_rt/fixunssfti.zig diff --git a/std/special/compiler_rt/fixunssfti_test.zig b/lib/std/special/compiler_rt/fixunssfti_test.zig diff --git a/std/special/compiler_rt/fixunstfdi.zig b/lib/std/special/compiler_rt/fixunstfdi.zig diff --git a/std/special/compiler_rt/fixunstfdi_test.zig b/lib/std/special/compiler_rt/fixunstfdi_test.zig diff --git a/std/special/compiler_rt/fixunstfsi.zig b/lib/std/special/compiler_rt/fixunstfsi.zig diff --git a/std/special/compiler_rt/fixunstfsi_test.zig b/lib/std/special/compiler_rt/fixunstfsi_test.zig diff --git a/std/special/compiler_rt/fixunstfti.zig b/lib/std/special/compiler_rt/fixunstfti.zig diff --git a/std/special/compiler_rt/fixunstfti_test.zig b/lib/std/special/compiler_rt/fixunstfti_test.zig diff --git a/std/special/compiler_rt/floatdidf.zig b/lib/std/special/compiler_rt/floatdidf.zig diff --git a/std/special/compiler_rt/floatdidf_test.zig b/lib/std/special/compiler_rt/floatdidf_test.zig diff --git a/std/special/compiler_rt/floatsiXf.zig b/lib/std/special/compiler_rt/floatsiXf.zig diff --git a/std/special/compiler_rt/floattidf.zig b/lib/std/special/compiler_rt/floattidf.zig diff --git a/std/special/compiler_rt/floattidf_test.zig b/lib/std/special/compiler_rt/floattidf_test.zig diff --git a/std/special/compiler_rt/floattisf.zig b/lib/std/special/compiler_rt/floattisf.zig diff --git a/std/special/compiler_rt/floattisf_test.zig b/lib/std/special/compiler_rt/floattisf_test.zig diff --git a/std/special/compiler_rt/floattitf.zig b/lib/std/special/compiler_rt/floattitf.zig diff --git a/std/special/compiler_rt/floattitf_test.zig b/lib/std/special/compiler_rt/floattitf_test.zig diff --git a/std/special/compiler_rt/floatundidf.zig b/lib/std/special/compiler_rt/floatundidf.zig diff --git a/std/special/compiler_rt/floatundidf_test.zig b/lib/std/special/compiler_rt/floatundidf_test.zig diff --git a/std/special/compiler_rt/floatunditf.zig b/lib/std/special/compiler_rt/floatunditf.zig diff --git a/std/special/compiler_rt/floatunditf_test.zig b/lib/std/special/compiler_rt/floatunditf_test.zig diff --git a/std/special/compiler_rt/floatunsidf.zig b/lib/std/special/compiler_rt/floatunsidf.zig diff --git a/std/special/compiler_rt/floatunsitf.zig b/lib/std/special/compiler_rt/floatunsitf.zig diff --git a/std/special/compiler_rt/floatunsitf_test.zig b/lib/std/special/compiler_rt/floatunsitf_test.zig diff --git a/std/special/compiler_rt/floatuntidf.zig b/lib/std/special/compiler_rt/floatuntidf.zig diff --git a/std/special/compiler_rt/floatuntidf_test.zig b/lib/std/special/compiler_rt/floatuntidf_test.zig diff --git a/std/special/compiler_rt/floatuntisf.zig b/lib/std/special/compiler_rt/floatuntisf.zig diff --git a/std/special/compiler_rt/floatuntisf_test.zig b/lib/std/special/compiler_rt/floatuntisf_test.zig diff --git a/std/special/compiler_rt/floatuntitf.zig b/lib/std/special/compiler_rt/floatuntitf.zig diff --git a/std/special/compiler_rt/floatuntitf_test.zig b/lib/std/special/compiler_rt/floatuntitf_test.zig diff --git a/std/special/compiler_rt/lshrti3.zig b/lib/std/special/compiler_rt/lshrti3.zig diff --git a/std/special/compiler_rt/lshrti3_test.zig b/lib/std/special/compiler_rt/lshrti3_test.zig diff --git a/std/special/compiler_rt/modti3.zig b/lib/std/special/compiler_rt/modti3.zig diff --git a/std/special/compiler_rt/modti3_test.zig b/lib/std/special/compiler_rt/modti3_test.zig diff --git a/std/special/compiler_rt/mulXf3.zig b/lib/std/special/compiler_rt/mulXf3.zig diff --git a/std/special/compiler_rt/mulXf3_test.zig b/lib/std/special/compiler_rt/mulXf3_test.zig diff --git a/std/special/compiler_rt/muldi3.zig b/lib/std/special/compiler_rt/muldi3.zig diff --git a/std/special/compiler_rt/muldi3_test.zig b/lib/std/special/compiler_rt/muldi3_test.zig diff --git a/std/special/compiler_rt/mulodi4.zig b/lib/std/special/compiler_rt/mulodi4.zig diff --git a/std/special/compiler_rt/mulodi4_test.zig b/lib/std/special/compiler_rt/mulodi4_test.zig diff --git a/std/special/compiler_rt/muloti4.zig b/lib/std/special/compiler_rt/muloti4.zig diff --git a/std/special/compiler_rt/muloti4_test.zig b/lib/std/special/compiler_rt/muloti4_test.zig diff --git a/std/special/compiler_rt/multi3.zig b/lib/std/special/compiler_rt/multi3.zig diff --git a/std/special/compiler_rt/multi3_test.zig b/lib/std/special/compiler_rt/multi3_test.zig diff --git a/std/special/compiler_rt/negXf2.zig b/lib/std/special/compiler_rt/negXf2.zig diff --git a/std/special/compiler_rt/popcountdi2.zig b/lib/std/special/compiler_rt/popcountdi2.zig diff --git a/std/special/compiler_rt/popcountdi2_test.zig b/lib/std/special/compiler_rt/popcountdi2_test.zig diff --git a/std/special/compiler_rt/stack_probe.zig b/lib/std/special/compiler_rt/stack_probe.zig diff --git a/std/special/compiler_rt/truncXfYf2.zig b/lib/std/special/compiler_rt/truncXfYf2.zig diff --git a/std/special/compiler_rt/truncXfYf2_test.zig b/lib/std/special/compiler_rt/truncXfYf2_test.zig diff --git a/std/special/compiler_rt/udivmod.zig b/lib/std/special/compiler_rt/udivmod.zig diff --git a/std/special/compiler_rt/udivmoddi4.zig b/lib/std/special/compiler_rt/udivmoddi4.zig diff --git a/std/special/compiler_rt/udivmoddi4_test.zig b/lib/std/special/compiler_rt/udivmoddi4_test.zig diff --git a/std/special/compiler_rt/udivmodti4.zig b/lib/std/special/compiler_rt/udivmodti4.zig diff --git a/std/special/compiler_rt/udivmodti4_test.zig b/lib/std/special/compiler_rt/udivmodti4_test.zig diff --git a/std/special/compiler_rt/udivti3.zig b/lib/std/special/compiler_rt/udivti3.zig diff --git a/std/special/compiler_rt/umodti3.zig b/lib/std/special/compiler_rt/umodti3.zig diff --git a/std/special/init-exe/build.zig b/lib/std/special/init-exe/build.zig diff --git a/std/special/init-exe/src/main.zig b/lib/std/special/init-exe/src/main.zig diff --git a/std/special/init-lib/build.zig b/lib/std/special/init-lib/build.zig diff --git a/std/special/init-lib/src/main.zig b/lib/std/special/init-lib/src/main.zig diff --git a/std/special/panic.zig b/lib/std/special/panic.zig diff --git a/std/special/start.zig b/lib/std/special/start.zig diff --git a/std/special/start_lib.zig b/lib/std/special/start_lib.zig diff --git a/std/special/start_windows_tls.zig b/lib/std/special/start_windows_tls.zig diff --git a/std/special/test_runner.zig b/lib/std/special/test_runner.zig diff --git a/std/spinlock.zig b/lib/std/spinlock.zig diff --git a/std/statically_initialized_mutex.zig b/lib/std/statically_initialized_mutex.zig diff --git a/std/std.zig b/lib/std/std.zig diff --git a/std/testing.zig b/lib/std/testing.zig diff --git a/std/thread.zig b/lib/std/thread.zig diff --git a/std/time.zig b/lib/std/time.zig diff --git a/std/time/epoch.zig b/lib/std/time/epoch.zig diff --git a/std/unicode.zig b/lib/std/unicode.zig diff --git a/std/unicode/throughput_test.zig b/lib/std/unicode/throughput_test.zig diff --git a/std/valgrind.zig b/lib/std/valgrind.zig diff --git a/std/valgrind/callgrind.zig b/lib/std/valgrind/callgrind.zig diff --git a/std/valgrind/memcheck.zig b/lib/std/valgrind/memcheck.zig diff --git a/std/zig.zig b/lib/std/zig.zig diff --git a/std/zig/ast.zig b/lib/std/zig/ast.zig diff --git a/std/zig/parse.zig b/lib/std/zig/parse.zig diff --git a/std/zig/parse_string_literal.zig b/lib/std/zig/parse_string_literal.zig diff --git a/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig diff --git a/std/zig/perf_test.zig b/lib/std/zig/perf_test.zig diff --git a/std/zig/render.zig b/lib/std/zig/render.zig diff --git a/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig diff --git a/src/codegen.cpp b/src/codegen.cpp @@ -10367,8 +10367,7 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o ZigLibCInstallation *libc) { CodeGen *child_gen = codegen_create(nullptr, root_src_path, parent_gen->zig_target, out_type, - parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir, libc, get_stage1_cache_path(), - false); + parent_gen->build_mode, parent_gen->zig_lib_dir, libc, get_stage1_cache_path(), false); child_gen->disable_gen_h = true; child_gen->want_stack_check = WantStackCheckDisabled; child_gen->verbose_tokenize = parent_gen->verbose_tokenize; @@ -10396,7 +10395,7 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o } CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target, - OutType out_type, BuildMode build_mode, Buf *override_lib_dir, Buf *override_std_dir, + OutType out_type, BuildMode build_mode, Buf *override_lib_dir, ZigLibCInstallation *libc, Buf *cache_dir, bool is_test_build) { CodeGen *g = allocate<CodeGen>(1); @@ -10414,12 +10413,8 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget g->zig_lib_dir = override_lib_dir; } - if (override_std_dir == nullptr) { - g->zig_std_dir = buf_alloc(); - os_path_join(g->zig_lib_dir, buf_create_from_str("std"), g->zig_std_dir); - } else { - g->zig_std_dir = override_std_dir; - } + g->zig_std_dir = buf_alloc(); + os_path_join(g->zig_lib_dir, buf_create_from_str("std"), g->zig_std_dir); g->zig_c_headers_dir = buf_alloc(); os_path_join(g->zig_lib_dir, buf_create_from_str("include"), g->zig_c_headers_dir); diff --git a/src/codegen.hpp b/src/codegen.hpp @@ -17,7 +17,7 @@ #include <stdio.h> CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target, - OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, Buf *override_std_dir, + OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, ZigLibCInstallation *libc, Buf *cache_dir, bool is_test_build); CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type, diff --git a/src/compiler.cpp b/src/compiler.cpp @@ -130,37 +130,35 @@ Error get_compiler_id(Buf **result) { } static bool test_zig_install_prefix(Buf *test_path, Buf *out_zig_lib_dir) { - Buf lib_buf = BUF_INIT; - buf_init_from_str(&lib_buf, "lib"); - - Buf zig_buf = BUF_INIT; - buf_init_from_str(&zig_buf, "zig"); - - Buf std_buf = BUF_INIT; - buf_init_from_str(&std_buf, "std"); - - Buf std_zig_buf = BUF_INIT; - buf_init_from_str(&std_zig_buf, "std.zig"); - - Buf test_lib_dir = BUF_INIT; - Buf test_zig_dir = BUF_INIT; - Buf test_std_dir = BUF_INIT; - Buf test_index_file = BUF_INIT; - - os_path_join(test_path, &lib_buf, &test_lib_dir); - os_path_join(&test_lib_dir, &zig_buf, &test_zig_dir); - os_path_join(&test_zig_dir, &std_buf, &test_std_dir); - os_path_join(&test_std_dir, &std_zig_buf, &test_index_file); - - int err; - bool exists; - if ((err = os_file_exists(&test_index_file, &exists))) { - exists = false; + { + Buf *test_zig_dir = buf_sprintf("%s" OS_SEP "lib" OS_SEP "zig", buf_ptr(test_path)); + Buf *test_index_file = buf_sprintf("%s" OS_SEP "std" OS_SEP "std.zig", buf_ptr(test_zig_dir)); + int err; + bool exists; + if ((err = os_file_exists(test_index_file, &exists))) { + exists = false; + } + if (exists) { + buf_init_from_buf(out_zig_lib_dir, test_zig_dir); + return true; + } } - if (exists) { - buf_init_from_buf(out_zig_lib_dir, &test_zig_dir); - return true; + + // Also try without "zig" + { + Buf *test_zig_dir = buf_sprintf("%s" OS_SEP "lib", buf_ptr(test_path)); + Buf *test_index_file = buf_sprintf("%s" OS_SEP "std" OS_SEP "std.zig", buf_ptr(test_zig_dir)); + int err; + bool exists; + if ((err = os_file_exists(test_index_file, &exists))) { + exists = false; + } + if (exists) { + buf_init_from_buf(out_zig_lib_dir, test_zig_dir); + return true; + } } + return false; } diff --git a/src/main.cpp b/src/main.cpp @@ -88,8 +88,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " -dirafter [dir] same as -isystem but do it last\n" " -isystem [dir] add additional search path for other .h files\n" " -mllvm [arg] (unsupported) forward an arg to LLVM's option processing\n" - " --override-std-dir [arg] override path to Zig standard library\n" - " --override-lib-dir [arg] override path to Zig lib library\n" + " --override-lib-dir [arg] override path to Zig lib directory\n" " -ffunction-sections places each function in a separate section\n" " -D[macro]=[value] define C [macro] to [value] (1 if [value] omitted)\n" "\n" @@ -490,7 +489,6 @@ int main(int argc, char **argv) { bool want_single_threaded = false; bool disable_gen_h = false; bool bundle_compiler_rt = false; - Buf *override_std_dir = nullptr; Buf *override_lib_dir = nullptr; Buf *main_pkg_path = nullptr; ValgrindSupport valgrind_support = ValgrindSupportAuto; @@ -526,12 +524,6 @@ int main(int argc, char **argv) { } else if (i + 1 < argc && strcmp(argv[i], "--cache-dir") == 0) { cache_dir = argv[i + 1]; i += 1; - } else if (i + 1 < argc && strcmp(argv[i], "--override-std-dir") == 0) { - override_std_dir = buf_create_from_str(argv[i + 1]); - i += 1; - - args.append("--override-std-dir"); - args.append(buf_ptr(override_std_dir)); } else if (i + 1 < argc && strcmp(argv[i], "--override-lib-dir") == 0) { override_lib_dir = buf_create_from_str(argv[i + 1]); i += 1; @@ -590,7 +582,7 @@ int main(int argc, char **argv) { } CodeGen *g = codegen_create(main_pkg_path, build_runner_path, &target, OutTypeExe, - BuildModeDebug, override_lib_dir, override_std_dir, nullptr, &full_cache_dir, false); + BuildModeDebug, override_lib_dir, nullptr, &full_cache_dir, false); g->valgrind_support = valgrind_support; g->enable_time_report = timing_info; codegen_set_out_name(g, buf_create_from_str("build")); @@ -787,8 +779,6 @@ int main(int argc, char **argv) { clang_argv.append(argv[i]); llvm_argv.append(argv[i]); - } else if (strcmp(arg, "--override-std-dir") == 0) { - override_std_dir = buf_create_from_str(argv[i]); } else if (strcmp(arg, "--override-lib-dir") == 0) { override_lib_dir = buf_create_from_str(argv[i]); } else if (strcmp(arg, "--main-pkg-path") == 0) { @@ -1036,7 +1026,7 @@ int main(int argc, char **argv) { } case CmdBuiltin: { CodeGen *g = codegen_create(main_pkg_path, nullptr, &target, - out_type, build_mode, override_lib_dir, override_std_dir, nullptr, nullptr, false); + out_type, build_mode, override_lib_dir, nullptr, nullptr, false); codegen_set_strip(g, strip); for (size_t i = 0; i < link_libs.length; i += 1) { LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i))); @@ -1140,7 +1130,7 @@ int main(int argc, char **argv) { cache_dir_buf = buf_create_from_str(cache_dir); } CodeGen *g = codegen_create(main_pkg_path, zig_root_source_file, &target, out_type, build_mode, - override_lib_dir, override_std_dir, libc, cache_dir_buf, cmd == CmdTest); + override_lib_dir, libc, cache_dir_buf, cmd == CmdTest); if (llvm_argv.length >= 2) codegen_set_llvm_argv(g, llvm_argv.items + 1, llvm_argv.length - 2); g->valgrind_support = valgrind_support; g->want_pic = want_pic; diff --git a/std/build.zig b/std/build.zig @@ -1,2743 +0,0 @@ -const std = @import("std.zig"); -const builtin = @import("builtin"); -const io = std.io; -const fs = std.fs; -const mem = std.mem; -const debug = std.debug; -const panic = std.debug.panic; -const assert = debug.assert; -const warn = std.debug.warn; -const ArrayList = std.ArrayList; -const StringHashMap = std.StringHashMap; -const Allocator = mem.Allocator; -const process = std.process; -const BufSet = std.BufSet; -const BufMap = std.BufMap; -const fmt_lib = std.fmt; -const File = std.fs.File; - -pub const FmtStep = @import("build/fmt.zig").FmtStep; - -pub const Builder = struct { - install_tls: TopLevelStep, - uninstall_tls: TopLevelStep, - allocator: *Allocator, - native_system_lib_paths: ArrayList([]const u8), - native_system_include_dirs: ArrayList([]const u8), - native_system_rpaths: ArrayList([]const u8), - user_input_options: UserInputOptionsMap, - available_options_map: AvailableOptionsMap, - available_options_list: ArrayList(AvailableOption), - verbose: bool, - verbose_tokenize: bool, - verbose_ast: bool, - verbose_link: bool, - verbose_cc: bool, - verbose_ir: bool, - verbose_llvm_ir: bool, - verbose_cimport: bool, - invalid_user_input: bool, - zig_exe: []const u8, - default_step: *Step, - env_map: *BufMap, - top_level_steps: ArrayList(*TopLevelStep), - install_prefix: ?[]const u8, - dest_dir: ?[]const u8, - lib_dir: []const u8, - exe_dir: []const u8, - install_path: []const u8, - search_prefixes: ArrayList([]const u8), - installed_files: ArrayList(InstalledFile), - build_root: []const u8, - cache_root: []const u8, - release_mode: ?builtin.Mode, - is_release: bool, - override_std_dir: ?[]const u8, - override_lib_dir: ?[]const u8, - - pkg_config_pkg_list: ?(PkgConfigError![]const PkgConfigPkg) = null, - - const PkgConfigError = error{ - PkgConfigCrashed, - PkgConfigFailed, - PkgConfigNotInstalled, - PkgConfigInvalidOutput, - }; - - pub const PkgConfigPkg = struct { - name: []const u8, - desc: []const u8, - }; - - pub const CStd = enum { - C89, - C99, - C11, - }; - - const UserInputOptionsMap = StringHashMap(UserInputOption); - const AvailableOptionsMap = StringHashMap(AvailableOption); - - const AvailableOption = struct { - name: []const u8, - type_id: TypeId, - description: []const u8, - }; - - const UserInputOption = struct { - name: []const u8, - value: UserValue, - used: bool, - }; - - const UserValue = union(enum) { - Flag: void, - Scalar: []const u8, - List: ArrayList([]const u8), - }; - - const TypeId = enum { - Bool, - Int, - Float, - String, - List, - }; - - const TopLevelStep = struct { - step: Step, - description: []const u8, - }; - - pub fn create( - allocator: *Allocator, - zig_exe: []const u8, - build_root: []const u8, - cache_root: []const u8, - ) !*Builder { - const env_map = try allocator.create(BufMap); - env_map.* = try process.getEnvMap(allocator); - - const self = try allocator.create(Builder); - self.* = Builder{ - .zig_exe = zig_exe, - .build_root = build_root, - .cache_root = try fs.path.relative(allocator, build_root, cache_root), - .verbose = false, - .verbose_tokenize = false, - .verbose_ast = false, - .verbose_link = false, - .verbose_cc = false, - .verbose_ir = false, - .verbose_llvm_ir = false, - .verbose_cimport = false, - .invalid_user_input = false, - .allocator = allocator, - .native_system_lib_paths = ArrayList([]const u8).init(allocator), - .native_system_include_dirs = ArrayList([]const u8).init(allocator), - .native_system_rpaths = ArrayList([]const u8).init(allocator), - .user_input_options = UserInputOptionsMap.init(allocator), - .available_options_map = AvailableOptionsMap.init(allocator), - .available_options_list = ArrayList(AvailableOption).init(allocator), - .top_level_steps = ArrayList(*TopLevelStep).init(allocator), - .default_step = undefined, - .env_map = env_map, - .search_prefixes = ArrayList([]const u8).init(allocator), - .install_prefix = null, - .lib_dir = undefined, - .exe_dir = undefined, - .dest_dir = env_map.get("DESTDIR"), - .installed_files = ArrayList(InstalledFile).init(allocator), - .install_tls = TopLevelStep{ - .step = Step.initNoOp("install", allocator), - .description = "Copy build artifacts to prefix path", - }, - .uninstall_tls = TopLevelStep{ - .step = Step.init("uninstall", allocator, makeUninstall), - .description = "Remove build artifacts from prefix path", - }, - .release_mode = null, - .is_release = false, - .override_std_dir = null, - .override_lib_dir = null, - .install_path = undefined, - }; - try self.top_level_steps.append(&self.install_tls); - try self.top_level_steps.append(&self.uninstall_tls); - self.detectNativeSystemPaths(); - self.default_step = &self.install_tls.step; - return self; - } - - pub fn destroy(self: *Builder) void { - self.native_system_lib_paths.deinit(); - self.native_system_include_dirs.deinit(); - self.native_system_rpaths.deinit(); - self.env_map.deinit(); - self.top_level_steps.deinit(); - self.allocator.destroy(self); - } - - /// This function is intended to be called by std/special/build_runner.zig, not a build.zig file. - pub fn setInstallPrefix(self: *Builder, optional_prefix: ?[]const u8) void { - self.install_prefix = optional_prefix; - } - - /// This function is intended to be called by std/special/build_runner.zig, not a build.zig file. - pub fn resolveInstallPrefix(self: *Builder) void { - if (self.dest_dir) |dest_dir| { - const install_prefix = self.install_prefix orelse "/usr"; - self.install_path = fs.path.join(self.allocator, [_][]const u8{ dest_dir, install_prefix }) catch unreachable; - } else { - const install_prefix = self.install_prefix orelse blk: { - const p = self.cache_root; - self.install_prefix = p; - break :blk p; - }; - self.install_path = install_prefix; - } - self.lib_dir = fs.path.join(self.allocator, [_][]const u8{ self.install_path, "lib" }) catch unreachable; - self.exe_dir = fs.path.join(self.allocator, [_][]const u8{ self.install_path, "bin" }) catch unreachable; - } - - pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { - return LibExeObjStep.createExecutable(self, name, root_src, false); - } - - pub fn addObject(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { - return LibExeObjStep.createObject(self, name, root_src); - } - - pub fn addSharedLibrary(self: *Builder, name: []const u8, root_src: ?[]const u8, ver: Version) *LibExeObjStep { - return LibExeObjStep.createSharedLibrary(self, name, root_src, ver); - } - - pub fn addStaticLibrary(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { - return LibExeObjStep.createStaticLibrary(self, name, root_src); - } - - pub fn addTest(self: *Builder, root_src: []const u8) *LibExeObjStep { - return LibExeObjStep.createTest(self, "test", root_src); - } - - pub fn addAssemble(self: *Builder, name: []const u8, src: []const u8) *LibExeObjStep { - const obj_step = LibExeObjStep.createObject(self, name, null); - obj_step.addAssemblyFile(src); - return obj_step; - } - - /// Initializes a RunStep with argv, which must at least have the path to the - /// executable. More command line arguments can be added with `addArg`, - /// `addArgs`, and `addArtifactArg`. - /// Be careful using this function, as it introduces a system dependency. - /// To run an executable built with zig build, see `LibExeObjStep.run`. - pub fn addSystemCommand(self: *Builder, argv: []const []const u8) *RunStep { - assert(argv.len >= 1); - const run_step = RunStep.create(self, self.fmt("run {}", argv[0])); - run_step.addArgs(argv); - return run_step; - } - - fn dupe(self: *Builder, bytes: []const u8) []u8 { - return mem.dupe(self.allocator, u8, bytes) catch unreachable; - } - - fn dupePath(self: *Builder, bytes: []const u8) []u8 { - const the_copy = self.dupe(bytes); - for (the_copy) |*byte| { - switch (byte.*) { - '/', '\\' => byte.* = fs.path.sep, - else => {}, - } - } - return the_copy; - } - - pub fn addWriteFile(self: *Builder, file_path: []const u8, data: []const u8) *WriteFileStep { - const write_file_step = self.allocator.create(WriteFileStep) catch unreachable; - write_file_step.* = WriteFileStep.init(self, file_path, data); - return write_file_step; - } - - pub fn addLog(self: *Builder, comptime format: []const u8, args: ...) *LogStep { - const data = self.fmt(format, args); - const log_step = self.allocator.create(LogStep) catch unreachable; - log_step.* = LogStep.init(self, data); - return log_step; - } - - pub fn addRemoveDirTree(self: *Builder, dir_path: []const u8) *RemoveDirStep { - const remove_dir_step = self.allocator.create(RemoveDirStep) catch unreachable; - remove_dir_step.* = RemoveDirStep.init(self, dir_path); - return remove_dir_step; - } - - pub fn addFmt(self: *Builder, paths: []const []const u8) *FmtStep { - return FmtStep.create(self, paths); - } - - pub fn version(self: *const Builder, major: u32, minor: u32, patch: u32) Version { - return Version{ - .major = major, - .minor = minor, - .patch = patch, - }; - } - - pub fn addNativeSystemIncludeDir(self: *Builder, path: []const u8) void { - self.native_system_include_dirs.append(path) catch unreachable; - } - - pub fn addNativeSystemRPath(self: *Builder, path: []const u8) void { - self.native_system_rpaths.append(path) catch unreachable; - } - - pub fn addNativeSystemLibPath(self: *Builder, path: []const u8) void { - self.native_system_lib_paths.append(path) catch unreachable; - } - - pub fn make(self: *Builder, step_names: []const []const u8) !void { - try self.makePath(self.cache_root); - - var wanted_steps = ArrayList(*Step).init(self.allocator); - defer wanted_steps.deinit(); - - if (step_names.len == 0) { - try wanted_steps.append(self.default_step); - } else { - for (step_names) |step_name| { - const s = try self.getTopLevelStepByName(step_name); - try wanted_steps.append(s); - } - } - - for (wanted_steps.toSliceConst()) |s| { - try self.makeOneStep(s); - } - } - - pub fn getInstallStep(self: *Builder) *Step { - return &self.install_tls.step; - } - - pub fn getUninstallStep(self: *Builder) *Step { - return &self.uninstall_tls.step; - } - - fn makeUninstall(uninstall_step: *Step) anyerror!void { - const uninstall_tls = @fieldParentPtr(TopLevelStep, "step", uninstall_step); - const self = @fieldParentPtr(Builder, "uninstall_tls", uninstall_tls); - - for (self.installed_files.toSliceConst()) |installed_file| { - const full_path = self.getInstallPath(installed_file.dir, installed_file.path); - if (self.verbose) { - warn("rm {}\n", full_path); - } - fs.deleteTree(self.allocator, full_path) catch {}; - } - - // TODO remove empty directories - } - - fn makeOneStep(self: *Builder, s: *Step) anyerror!void { - if (s.loop_flag) { - warn("Dependency loop detected:\n {}\n", s.name); - return error.DependencyLoopDetected; - } - s.loop_flag = true; - - for (s.dependencies.toSlice()) |dep| { - self.makeOneStep(dep) catch |err| { - if (err == error.DependencyLoopDetected) { - warn(" {}\n", s.name); - } - return err; - }; - } - - s.loop_flag = false; - - try s.make(); - } - - fn getTopLevelStepByName(self: *Builder, name: []const u8) !*Step { - for (self.top_level_steps.toSliceConst()) |top_level_step| { - if (mem.eql(u8, top_level_step.step.name, name)) { - return &top_level_step.step; - } - } - warn("Cannot run step '{}' because it does not exist\n", name); - return error.InvalidStepName; - } - - fn detectNativeSystemPaths(self: *Builder) void { - var is_nixos = false; - if (process.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| { - is_nixos = true; - var it = mem.tokenize(nix_cflags_compile, " "); - while (true) { - const word = it.next() orelse break; - if (mem.eql(u8, word, "-isystem")) { - const include_path = it.next() orelse { - warn("Expected argument after -isystem in NIX_CFLAGS_COMPILE\n"); - break; - }; - self.addNativeSystemIncludeDir(include_path); - } else { - warn("Unrecognized C flag from NIX_CFLAGS_COMPILE: {}\n", word); - break; - } - } - } else |err| { - assert(err == error.EnvironmentVariableNotFound); - } - if (process.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| { - is_nixos = true; - var it = mem.tokenize(nix_ldflags, " "); - while (true) { - const word = it.next() orelse break; - if (mem.eql(u8, word, "-rpath")) { - const rpath = it.next() orelse { - warn("Expected argument after -rpath in NIX_LDFLAGS\n"); - break; - }; - self.addNativeSystemRPath(rpath); - } else if (word.len > 2 and word[0] == '-' and word[1] == 'L') { - const lib_path = word[2..]; - self.addNativeSystemLibPath(lib_path); - } else { - warn("Unrecognized C flag from NIX_LDFLAGS: {}\n", word); - break; - } - } - } else |err| { - assert(err == error.EnvironmentVariableNotFound); - } - if (is_nixos) return; - switch (builtin.os) { - .windows => {}, - else => { - const triple = (Target{ - .Cross = CrossTarget{ - .arch = builtin.arch, - .os = builtin.os, - .abi = builtin.abi, - }, - }).linuxTriple(self.allocator); - - // TODO: $ ld --verbose | grep SEARCH_DIR - // the output contains some paths that end with lib64, maybe include them too? - // also, what is the best possible order of things? - - self.addNativeSystemIncludeDir("/usr/local/include"); - self.addNativeSystemLibPath("/usr/local/lib"); - - self.addNativeSystemIncludeDir(self.fmt("/usr/include/{}", triple)); - self.addNativeSystemLibPath(self.fmt("/usr/lib/{}", triple)); - - self.addNativeSystemIncludeDir("/usr/include"); - self.addNativeSystemLibPath("/usr/lib"); - - // example: on a 64-bit debian-based linux distro, with zlib installed from apt: - // zlib.h is in /usr/include (added above) - // libz.so.1 is in /lib/x86_64-linux-gnu (added here) - self.addNativeSystemLibPath(self.fmt("/lib/{}", triple)); - }, - } - } - - pub fn option(self: *Builder, comptime T: type, name: []const u8, description: []const u8) ?T { - const type_id = comptime typeToEnum(T); - const available_option = AvailableOption{ - .name = name, - .type_id = type_id, - .description = description, - }; - if ((self.available_options_map.put(name, available_option) catch unreachable) != null) { - panic("Option '{}' declared twice", name); - } - self.available_options_list.append(available_option) catch unreachable; - - const entry = self.user_input_options.get(name) orelse return null; - entry.value.used = true; - switch (type_id) { - TypeId.Bool => switch (entry.value.value) { - UserValue.Flag => return true, - UserValue.Scalar => |s| { - if (mem.eql(u8, s, "true")) { - return true; - } else if (mem.eql(u8, s, "false")) { - return false; - } else { - warn("Expected -D{} to be a boolean, but received '{}'\n", name, s); - self.markInvalidUserInput(); - return null; - } - }, - UserValue.List => { - warn("Expected -D{} to be a boolean, but received a list.\n", name); - self.markInvalidUserInput(); - return null; - }, - }, - TypeId.Int => panic("TODO integer options to build script"), - TypeId.Float => panic("TODO float options to build script"), - TypeId.String => switch (entry.value.value) { - UserValue.Flag => { - warn("Expected -D{} to be a string, but received a boolean.\n", name); - self.markInvalidUserInput(); - return null; - }, - UserValue.List => { - warn("Expected -D{} to be a string, but received a list.\n", name); - self.markInvalidUserInput(); - return null; - }, - UserValue.Scalar => |s| return s, - }, - TypeId.List => panic("TODO list options to build script"), - } - } - - pub fn step(self: *Builder, name: []const u8, description: []const u8) *Step { - const step_info = self.allocator.create(TopLevelStep) catch unreachable; - step_info.* = TopLevelStep{ - .step = Step.initNoOp(name, self.allocator), - .description = description, - }; - self.top_level_steps.append(step_info) catch unreachable; - return &step_info.step; - } - - /// This provides the -Drelease option to the build user and does not give them the choice. - pub fn setPreferredReleaseMode(self: *Builder, mode: builtin.Mode) void { - if (self.release_mode != null) { - @panic("setPreferredReleaseMode must be called before standardReleaseOptions and may not be called twice"); - } - const description = self.fmt("create a release build ({})", @tagName(mode)); - self.is_release = self.option(bool, "release", description) orelse false; - self.release_mode = if (self.is_release) mode else builtin.Mode.Debug; - } - - /// If you call this without first calling `setPreferredReleaseMode` then it gives the build user - /// the choice of what kind of release. - pub fn standardReleaseOptions(self: *Builder) builtin.Mode { - if (self.release_mode) |mode| return mode; - - const release_safe = self.option(bool, "release-safe", "optimizations on and safety on") orelse false; - const release_fast = self.option(bool, "release-fast", "optimizations on and safety off") orelse false; - const release_small = self.option(bool, "release-small", "size optimizations on and safety off") orelse false; - - const mode = if (release_safe and !release_fast and !release_small) - builtin.Mode.ReleaseSafe - else if (release_fast and !release_safe and !release_small) - builtin.Mode.ReleaseFast - else if (release_small and !release_fast and !release_safe) - builtin.Mode.ReleaseSmall - else if (!release_fast and !release_safe and !release_small) - builtin.Mode.Debug - else x: { - warn("Multiple release modes (of -Drelease-safe, -Drelease-fast and -Drelease-small)"); - self.markInvalidUserInput(); - break :x builtin.Mode.Debug; - }; - self.is_release = mode != .Debug; - self.release_mode = mode; - return mode; - } - - /// Exposes standard `zig build` options for choosing a target. Pass `null` to support all targets. - pub fn standardTargetOptions(self: *Builder, supported_targets: ?[]const Target) Target { - if (supported_targets) |target_list| { - // TODO detect multiple args and emit an error message - // there's probably a better way to collect the target - for (target_list) |targ| { - const targ_str = targ.zigTriple(self.allocator) catch unreachable; - const targ_desc = targ.allocDescription(self.allocator) catch unreachable; - const this_targ_opt = self.option(bool, targ_str, targ_desc) orelse false; - if (this_targ_opt) { - return targ; - } - } - return Target.Native; - } else { - const target_str = self.option([]const u8, "target", "the target to build for") orelse return Target.Native; - return Target.parse(target_str) catch unreachable; // TODO better error message for bad target - } - } - - pub fn addUserInputOption(self: *Builder, name: []const u8, value: []const u8) !bool { - const gop = try self.user_input_options.getOrPut(name); - if (!gop.found_existing) { - gop.kv.value = UserInputOption{ - .name = name, - .value = UserValue{ .Scalar = value }, - .used = false, - }; - return false; - } - - // option already exists - switch (gop.kv.value.value) { - UserValue.Scalar => |s| { - // turn it into a list - var list = ArrayList([]const u8).init(self.allocator); - list.append(s) catch unreachable; - list.append(value) catch unreachable; - _ = self.user_input_options.put(name, UserInputOption{ - .name = name, - .value = UserValue{ .List = list }, - .used = false, - }) catch unreachable; - }, - UserValue.List => |*list| { - // append to the list - list.append(value) catch unreachable; - _ = self.user_input_options.put(name, UserInputOption{ - .name = name, - .value = UserValue{ .List = list.* }, - .used = false, - }) catch unreachable; - }, - UserValue.Flag => { - warn("Option '-D{}={}' conflicts with flag '-D{}'.\n", name, value, name); - return true; - }, - } - return false; - } - - pub fn addUserInputFlag(self: *Builder, name: []const u8) !bool { - const gop = try self.user_input_options.getOrPut(name); - if (!gop.found_existing) { - gop.kv.value = UserInputOption{ - .name = name, - .value = UserValue{ .Flag = {} }, - .used = false, - }; - return false; - } - - // option already exists - switch (gop.kv.value.value) { - UserValue.Scalar => |s| { - warn("Flag '-D{}' conflicts with option '-D{}={}'.\n", name, name, s); - return true; - }, - UserValue.List => { - warn("Flag '-D{}' conflicts with multiple options of the same name.\n", name); - return true; - }, - UserValue.Flag => {}, - } - return false; - } - - fn typeToEnum(comptime T: type) TypeId { - return switch (@typeId(T)) { - builtin.TypeId.Int => TypeId.Int, - builtin.TypeId.Float => TypeId.Float, - builtin.TypeId.Bool => TypeId.Bool, - else => switch (T) { - []const u8 => TypeId.String, - []const []const u8 => TypeId.List, - else => @compileError("Unsupported type: " ++ @typeName(T)), - }, - }; - } - - fn markInvalidUserInput(self: *Builder) void { - self.invalid_user_input = true; - } - - pub fn typeIdName(id: TypeId) []const u8 { - return switch (id) { - TypeId.Bool => "bool", - TypeId.Int => "int", - TypeId.Float => "float", - TypeId.String => "string", - TypeId.List => "list", - }; - } - - pub fn validateUserInputDidItFail(self: *Builder) bool { - // make sure all args are used - var it = self.user_input_options.iterator(); - while (true) { - const entry = it.next() orelse break; - if (!entry.value.used) { - warn("Invalid option: -D{}\n\n", entry.key); - self.markInvalidUserInput(); - } - } - - return self.invalid_user_input; - } - - fn spawnChild(self: *Builder, argv: []const []const u8) !void { - return self.spawnChildEnvMap(null, self.env_map, argv); - } - - fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void { - if (cwd) |yes_cwd| warn("cd {} && ", yes_cwd); - for (argv) |arg| { - warn("{} ", arg); - } - warn("\n"); - } - - fn spawnChildEnvMap(self: *Builder, cwd: ?[]const u8, env_map: *const BufMap, argv: []const []const u8) !void { - if (self.verbose) { - printCmd(cwd, argv); - } - - const child = std.ChildProcess.init(argv, self.allocator) catch unreachable; - defer child.deinit(); - - child.cwd = cwd; - child.env_map = env_map; - - const term = child.spawnAndWait() catch |err| { - warn("Unable to spawn {}: {}\n", argv[0], @errorName(err)); - return err; - }; - - switch (term) { - .Exited => |code| { - if (code != 0) { - warn("The following command exited with error code {}:\n", code); - printCmd(cwd, argv); - return error.UncleanExit; - } - }, - else => { - warn("The following command terminated unexpectedly:\n"); - printCmd(cwd, argv); - - return error.UncleanExit; - }, - } - } - - pub fn makePath(self: *Builder, path: []const u8) !void { - fs.makePath(self.allocator, self.pathFromRoot(path)) catch |err| { - warn("Unable to create path {}: {}\n", path, @errorName(err)); - return err; - }; - } - - pub fn installArtifact(self: *Builder, artifact: *LibExeObjStep) void { - self.getInstallStep().dependOn(&self.addInstallArtifact(artifact).step); - } - - pub fn addInstallArtifact(self: *Builder, artifact: *LibExeObjStep) *InstallArtifactStep { - return InstallArtifactStep.create(self, artifact); - } - - ///`dest_rel_path` is relative to prefix path - pub fn installFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void { - self.getInstallStep().dependOn(&self.addInstallFileWithDir(src_path, .Prefix, dest_rel_path).step); - } - - pub fn installDirectory(self: *Builder, options: InstallDirectoryOptions) void { - self.getInstallStep().dependOn(&self.addInstallDirectory(options).step); - } - - ///`dest_rel_path` is relative to bin path - pub fn installBinFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void { - self.getInstallStep().dependOn(&self.addInstallFileWithDir(src_path, .Bin, dest_rel_path).step); - } - - ///`dest_rel_path` is relative to lib path - pub fn installLibFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void { - self.getInstallStep().dependOn(&self.addInstallFileWithDir(src_path, .Lib, dest_rel_path).step); - } - - ///`dest_rel_path` is relative to install prefix path - pub fn addInstallFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep { - return self.addInstallFileWithDir(src_path, .Prefix, dest_rel_path); - } - - ///`dest_rel_path` is relative to bin path - pub fn addInstallBinFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep { - return self.addInstallFileWithDir(src_path, .Bin, dest_rel_path); - } - - ///`dest_rel_path` is relative to lib path - pub fn addInstallLibFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep { - return self.addInstallFileWithDir(src_path, .Lib, dest_rel_path); - } - - pub fn addInstallFileWithDir( - self: *Builder, - src_path: []const u8, - install_dir: InstallDir, - dest_rel_path: []const u8, - ) *InstallFileStep { - const install_step = self.allocator.create(InstallFileStep) catch unreachable; - install_step.* = InstallFileStep.init(self, src_path, install_dir, dest_rel_path); - return install_step; - } - - pub fn addInstallDirectory(self: *Builder, options: InstallDirectoryOptions) *InstallDirStep { - const install_step = self.allocator.create(InstallDirStep) catch unreachable; - install_step.* = InstallDirStep.init(self, options); - return install_step; - } - - pub fn pushInstalledFile(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) void { - self.installed_files.append(InstalledFile{ - .dir = dir, - .path = dest_rel_path, - }) catch unreachable; - } - - fn updateFile(self: *Builder, source_path: []const u8, dest_path: []const u8) !void { - if (self.verbose) { - warn("cp {} {} ", source_path, dest_path); - } - const prev_status = try fs.updateFile(source_path, dest_path); - if (self.verbose) switch (prev_status) { - .stale => warn("# installed\n"), - .fresh => warn("# up-to-date\n"), - }; - } - - fn pathFromRoot(self: *Builder, rel_path: []const u8) []u8 { - return fs.path.resolve(self.allocator, [_][]const u8{ self.build_root, rel_path }) catch unreachable; - } - - pub fn fmt(self: *Builder, comptime format: []const u8, args: ...) []u8 { - return fmt_lib.allocPrint(self.allocator, format, args) catch unreachable; - } - - pub fn findProgram(self: *Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 { - // TODO report error for ambiguous situations - const exe_extension = (Target{ .Native = {} }).exeFileExt(); - for (self.search_prefixes.toSliceConst()) |search_prefix| { - for (names) |name| { - if (fs.path.isAbsolute(name)) { - return name; - } - const full_path = try fs.path.join(self.allocator, [_][]const u8{ search_prefix, "bin", self.fmt("{}{}", name, exe_extension) }); - return fs.realpathAlloc(self.allocator, full_path) catch continue; - } - } - if (self.env_map.get("PATH")) |PATH| { - for (names) |name| { - if (fs.path.isAbsolute(name)) { - return name; - } - var it = mem.tokenize(PATH, [_]u8{fs.path.delimiter}); - while (it.next()) |path| { - const full_path = try fs.path.join(self.allocator, [_][]const u8{ path, self.fmt("{}{}", name, exe_extension) }); - return fs.realpathAlloc(self.allocator, full_path) catch continue; - } - } - } - for (names) |name| { - if (fs.path.isAbsolute(name)) { - return name; - } - for (paths) |path| { - const full_path = try fs.path.join(self.allocator, [_][]const u8{ path, self.fmt("{}{}", name, exe_extension) }); - return fs.realpathAlloc(self.allocator, full_path) catch continue; - } - } - return error.FileNotFound; - } - - pub fn execAllowFail( - self: *Builder, - argv: []const []const u8, - out_code: *u8, - stderr_behavior: std.ChildProcess.StdIo, - ) ![]u8 { - assert(argv.len != 0); - - const max_output_size = 100 * 1024; - const child = try std.ChildProcess.init(argv, self.allocator); - defer child.deinit(); - - child.stdin_behavior = .Ignore; - child.stdout_behavior = .Pipe; - child.stderr_behavior = stderr_behavior; - - try child.spawn(); - - var stdout = std.Buffer.initNull(self.allocator); - defer std.Buffer.deinit(&stdout); - - var stdout_file_in_stream = child.stdout.?.inStream(); - try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size); - - const term = try child.wait(); - switch (term) { - .Exited => |code| { - if (code != 0) { - out_code.* = @truncate(u8, code); - return error.ExitCodeFailure; - } - return stdout.toOwnedSlice(); - }, - .Signal, .Stopped, .Unknown => |code| { - out_code.* = @truncate(u8, code); - return error.ProcessTerminated; - }, - } - } - - pub fn exec(self: *Builder, argv: []const []const u8) ![]u8 { - assert(argv.len != 0); - - if (self.verbose) { - printCmd(null, argv); - } - - var code: u8 = undefined; - return self.execAllowFail(argv, &code, .Inherit) catch |err| switch (err) { - error.FileNotFound => { - warn("Unable to spawn the following command: file not found\n"); - printCmd(null, argv); - std.os.exit(@truncate(u8, code)); - }, - error.ExitCodeFailure => { - warn("The following command exited with error code {}:\n", code); - printCmd(null, argv); - std.os.exit(@truncate(u8, code)); - }, - error.ProcessTerminated => { - warn("The following command terminated unexpectedly:\n"); - printCmd(null, argv); - std.os.exit(@truncate(u8, code)); - }, - else => |e| return e, - }; - } - - pub fn addSearchPrefix(self: *Builder, search_prefix: []const u8) void { - self.search_prefixes.append(search_prefix) catch unreachable; - } - - fn getInstallPath(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) []const u8 { - const base_dir = switch (dir) { - .Prefix => self.install_path, - .Bin => self.exe_dir, - .Lib => self.lib_dir, - }; - return fs.path.resolve( - self.allocator, - [_][]const u8{ base_dir, dest_rel_path }, - ) catch unreachable; - } - - fn execPkgConfigList(self: *Builder, out_code: *u8) ![]const PkgConfigPkg { - const stdout = try self.execAllowFail([_][]const u8{ "pkg-config", "--list-all" }, out_code, .Ignore); - var list = ArrayList(PkgConfigPkg).init(self.allocator); - var line_it = mem.tokenize(stdout, "\r\n"); - while (line_it.next()) |line| { - if (mem.trim(u8, line, " \t").len == 0) continue; - var tok_it = mem.tokenize(line, " \t"); - try list.append(PkgConfigPkg{ - .name = tok_it.next() orelse return error.PkgConfigInvalidOutput, - .desc = tok_it.rest(), - }); - } - return list.toSliceConst(); - } - - fn getPkgConfigList(self: *Builder) ![]const PkgConfigPkg { - if (self.pkg_config_pkg_list) |res| { - return res; - } - var code: u8 = undefined; - if (self.execPkgConfigList(&code)) |list| { - self.pkg_config_pkg_list = list; - return list; - } else |err| { - const result = switch (err) { - error.ProcessTerminated => error.PkgConfigCrashed, - error.ExitCodeFailure => error.PkgConfigFailed, - error.FileNotFound => error.PkgConfigNotInstalled, - error.PkgConfigInvalidOutput => error.PkgConfigInvalidOutput, - else => return err, - }; - self.pkg_config_pkg_list = result; - return result; - } - } -}; - -test "builder.findProgram compiles" { - const builder = try Builder.create(std.heap.direct_allocator, "zig", "zig-cache", "zig-cache"); - _ = builder.findProgram([_][]const u8{}, [_][]const u8{}) catch null; -} - -pub const Version = struct { - major: u32, - minor: u32, - patch: u32, -}; - -pub const CrossTarget = struct { - arch: builtin.Arch, - os: builtin.Os, - abi: builtin.Abi, -}; - -pub const Target = union(enum) { - Native: void, - Cross: CrossTarget, - - pub fn zigTriple(self: Target, allocator: *Allocator) ![]u8 { - return std.fmt.allocPrint( - allocator, - "{}{}-{}-{}", - @tagName(self.getArch()), - Target.archSubArchName(self.getArch()), - @tagName(self.getOs()), - @tagName(self.getAbi()), - ); - } - - pub fn allocDescription(self: Target, allocator: *Allocator) ![]u8 { - // TODO is there anything else worthy of the description that is not - // already captured in the triple? - return self.zigTriple(allocator); - } - - pub fn zigTripleNoSubArch(self: Target, allocator: *Allocator) ![]u8 { - return std.fmt.allocPrint( - allocator, - "{}-{}-{}", - @tagName(self.getArch()), - @tagName(self.getOs()), - @tagName(self.getAbi()), - ); - } - - pub fn linuxTriple(self: Target, allocator: *Allocator) ![]u8 { - return std.fmt.allocPrint( - allocator, - "{}-{}-{}", - @tagName(self.getArch()), - @tagName(self.getOs()), - @tagName(self.getAbi()), - ); - } - - pub fn parse(text: []const u8) !Target { - var it = mem.separate(text, "-"); - const arch_name = it.next() orelse return error.MissingArchitecture; - const os_name = it.next() orelse return error.MissingOperatingSystem; - const abi_name = it.next(); - - var cross = CrossTarget{ - .arch = try parseArchSub(arch_name), - .os = try parseOs(os_name), - .abi = undefined, - }; - cross.abi = if (abi_name) |n| try parseAbi(n) else defaultAbi(cross.arch, cross.os); - return Target{ .Cross = cross }; - } - - pub fn defaultAbi(arch: builtin.Arch, target_os: builtin.Os) builtin.Abi { - switch (arch) { - .wasm32, .wasm64 => return .musl, - else => {}, - } - switch (target_os) { - .freestanding, - .ananas, - .cloudabi, - .dragonfly, - .lv2, - .solaris, - .haiku, - .minix, - .rtems, - .nacl, - .cnk, - .aix, - .cuda, - .nvcl, - .amdhsa, - .ps4, - .elfiamcu, - .mesa3d, - .contiki, - .amdpal, - .zen, - .hermit, - => return .eabi, - .openbsd, - .macosx, - .freebsd, - .ios, - .tvos, - .watchos, - .fuchsia, - .kfreebsd, - .netbsd, - .hurd, - => return .gnu, - .windows, - .uefi, - => return .msvc, - .linux, - .wasi, - .emscripten, - => return .musl, - } - } - - pub const ParseArchSubError = error{ - UnknownArchitecture, - UnknownSubArchitecture, - }; - - pub fn parseArchSub(text: []const u8) ParseArchSubError!builtin.Arch { - const info = @typeInfo(builtin.Arch); - inline for (info.Union.fields) |field| { - if (mem.eql(u8, text, field.name)) { - if (field.field_type == void) { - return (builtin.Arch)(@field(builtin.Arch, field.name)); - } else { - const sub_info = @typeInfo(field.field_type); - inline for (sub_info.Enum.fields) |sub_field| { - const combined = field.name ++ sub_field.name; - if (mem.eql(u8, text, combined)) { - return @unionInit(builtin.Arch, field.name, @field(field.field_type, sub_field.name)); - } - } - return error.UnknownSubArchitecture; - } - } - } - return error.UnknownArchitecture; - } - - pub fn parseOs(text: []const u8) !builtin.Os { - const info = @typeInfo(builtin.Os); - inline for (info.Enum.fields) |field| { - if (mem.eql(u8, text, field.name)) { - return @field(builtin.Os, field.name); - } - } - return error.UnknownOperatingSystem; - } - - pub fn parseAbi(text: []const u8) !builtin.Abi { - const info = @typeInfo(builtin.Abi); - inline for (info.Enum.fields) |field| { - if (mem.eql(u8, text, field.name)) { - return @field(builtin.Abi, field.name); - } - } - return error.UnknownApplicationBinaryInterface; - } - - fn archSubArchName(arch: builtin.Arch) []const u8 { - return switch (arch) { - .arm => |sub| @tagName(sub), - .armeb => |sub| @tagName(sub), - .thumb => |sub| @tagName(sub), - .thumbeb => |sub| @tagName(sub), - .aarch64 => |sub| @tagName(sub), - .aarch64_be => |sub| @tagName(sub), - .kalimba => |sub| @tagName(sub), - else => "", - }; - } - - pub fn subArchName(self: Target) []const u8 { - switch (self) { - .Native => return archSubArchName(builtin.arch), - .Cross => |cross| return archSubArchName(cross.arch), - } - } - - pub fn oFileExt(self: Target) []const u8 { - return switch (self.getAbi()) { - builtin.Abi.msvc => ".obj", - else => ".o", - }; - } - - pub fn exeFileExt(self: Target) []const u8 { - return switch (self.getOs()) { - .windows => ".exe", - else => "", - }; - } - - pub fn staticLibSuffix(self: Target) []const u8 { - if (self.isWasm()) { - return ".wasm"; - } - switch (self.getAbi()) { - .msvc => return ".lib", - else => return ".a", - } - } - - pub fn dynamicLibSuffix(self: Target) []const u8 { - if (self.isDarwin()) { - return ".dylib"; - } - switch (self.getOs()) { - .windows => return ".dll", - else => return ".so", - } - } - - pub fn libPrefix(self: Target) []const u8 { - if (self.isWasm()) { - return ""; - } - switch (self.getAbi()) { - .msvc => return "", - else => return "lib", - } - } - - pub fn getOs(self: Target) builtin.Os { - return switch (self) { - .Native => builtin.os, - .Cross => |t| t.os, - }; - } - - pub fn getArch(self: Target) builtin.Arch { - switch (self) { - .Native => return builtin.arch, - .Cross => |t| return t.arch, - } - } - - pub fn getAbi(self: Target) builtin.Abi { - switch (self) { - .Native => return builtin.abi, - .Cross => |t| return t.abi, - } - } - - pub fn isMinGW(self: Target) bool { - return self.isWindows() and self.isGnu(); - } - - pub fn isGnu(self: Target) bool { - return switch (self.getAbi()) { - .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true, - else => false, - }; - } - - pub fn isDarwin(self: Target) bool { - return switch (self.getOs()) { - .ios, .macosx, .watchos, .tvos => true, - else => false, - }; - } - - pub fn isWindows(self: Target) bool { - return switch (self.getOs()) { - .windows => true, - else => false, - }; - } - - pub fn isLinux(self: Target) bool { - return switch (self.getOs()) { - .linux => true, - else => false, - }; - } - - pub fn isUefi(self: Target) bool { - return switch (self.getOs()) { - .uefi => true, - else => false, - }; - } - - pub fn isWasm(self: Target) bool { - return switch (self.getArch()) { - .wasm32, .wasm64 => true, - else => false, - }; - } - - pub fn isFreeBSD(self: Target) bool { - return switch (self.getOs()) { - .freebsd => true, - else => false, - }; - } - - pub fn isNetBSD(self: Target) bool { - return switch (self.getOs()) { - .netbsd => true, - else => false, - }; - } - - pub fn wantSharedLibSymLinks(self: Target) bool { - return !self.isWindows(); - } - - pub fn osRequiresLibC(self: Target) bool { - return self.isDarwin() or self.isFreeBSD() or self.isNetBSD(); - } - - pub fn getArchPtrBitWidth(self: Target) u32 { - switch (self.getArch()) { - .avr, - .msp430, - => return 16, - - .arc, - .arm, - .armeb, - .hexagon, - .le32, - .mips, - .mipsel, - .powerpc, - .r600, - .riscv32, - .sparc, - .sparcel, - .tce, - .tcele, - .thumb, - .thumbeb, - .i386, - .xcore, - .nvptx, - .amdil, - .hsail, - .spir, - .kalimba, - .shave, - .lanai, - .wasm32, - .renderscript32, - .aarch64_32, - => return 32, - - .aarch64, - .aarch64_be, - .mips64, - .mips64el, - .powerpc64, - .powerpc64le, - .riscv64, - .x86_64, - .nvptx64, - .le64, - .amdil64, - .hsail64, - .spir64, - .wasm64, - .renderscript64, - .amdgcn, - .bpfel, - .bpfeb, - .sparcv9, - .s390x, - => return 64, - } - } - - pub const Executor = union(enum) { - native, - qemu: []const u8, - wine: []const u8, - unavailable, - }; - - pub fn getExternalExecutor(self: Target) Executor { - if (@TagType(Target)(self) == .Native) return .native; - - // If the target OS matches the host OS, we can use QEMU to emulate a foreign architecture. - if (self.getOs() == builtin.os) { - return switch (self.getArch()) { - .aarch64 => Executor{ .qemu = "qemu-aarch64" }, - .aarch64_be => Executor{ .qemu = "qemu-aarch64_be" }, - .arm => Executor{ .qemu = "qemu-arm" }, - .armeb => Executor{ .qemu = "qemu-armeb" }, - .i386 => Executor{ .qemu = "qemu-i386" }, - .mips => Executor{ .qemu = "qemu-mips" }, - .mipsel => Executor{ .qemu = "qemu-mipsel" }, - .mips64 => Executor{ .qemu = "qemu-mips64" }, - .mips64el => Executor{ .qemu = "qemu-mips64el" }, - .powerpc => Executor{ .qemu = "qemu-ppc" }, - .powerpc64 => Executor{ .qemu = "qemu-ppc64" }, - .powerpc64le => Executor{ .qemu = "qemu-ppc64le" }, - .riscv32 => Executor{ .qemu = "qemu-riscv32" }, - .riscv64 => Executor{ .qemu = "qemu-riscv64" }, - .s390x => Executor{ .qemu = "qemu-s390x" }, - .sparc => Executor{ .qemu = "qemu-sparc" }, - .x86_64 => Executor{ .qemu = "qemu-x86_64" }, - else => return .unavailable, - }; - } - - if (self.isWindows()) { - switch (self.getArchPtrBitWidth()) { - 32 => return Executor{ .wine = "wine" }, - 64 => return Executor{ .wine = "wine64" }, - else => return .unavailable, - } - } - - return .unavailable; - } -}; - -const Pkg = struct { - name: []const u8, - path: []const u8, -}; - -const CSourceFile = struct { - source_path: []const u8, - args: []const []const u8, -}; - -fn isLibCLibrary(name: []const u8) bool { - const libc_libraries = [_][]const u8{ "c", "m", "dl", "rt", "pthread" }; - for (libc_libraries) |libc_lib_name| { - if (mem.eql(u8, name, libc_lib_name)) - return true; - } - return false; -} - -pub const LibExeObjStep = struct { - step: Step, - builder: *Builder, - name: []const u8, - target: Target, - linker_script: ?[]const u8 = null, - version_script: ?[]const u8 = null, - out_filename: []const u8, - is_dynamic: bool, - version: Version, - build_mode: builtin.Mode, - kind: Kind, - major_only_filename: []const u8, - name_only_filename: []const u8, - strip: bool, - lib_paths: ArrayList([]const u8), - framework_dirs: ArrayList([]const u8), - frameworks: BufSet, - verbose_link: bool, - verbose_cc: bool, - disable_gen_h: bool, - bundle_compiler_rt: bool, - disable_stack_probing: bool, - c_std: Builder.CStd, - override_std_dir: ?[]const u8, - override_lib_dir: ?[]const u8, - main_pkg_path: ?[]const u8, - exec_cmd_args: ?[]const ?[]const u8, - name_prefix: []const u8, - filter: ?[]const u8, - single_threaded: bool, - - root_src: ?[]const u8, - out_h_filename: []const u8, - out_lib_filename: []const u8, - out_pdb_filename: []const u8, - packages: ArrayList(Pkg), - build_options_contents: std.Buffer, - system_linker_hack: bool, - - object_src: []const u8, - - link_objects: ArrayList(LinkObject), - include_dirs: ArrayList(IncludeDir), - c_macros: ArrayList([]const u8), - output_dir: ?[]const u8, - need_system_paths: bool, - is_linking_libc: bool = false, - - installed_path: ?[]const u8, - install_step: ?*InstallArtifactStep, - - libc_file: ?[]const u8 = null, - target_glibc: ?Version = null, - - valgrind_support: ?bool = null, - - /// Uses system Wine installation to run cross compiled Windows build artifacts. - enable_wine: bool = false, - - /// Uses system QEMU installation to run cross compiled foreign architecture build artifacts. - enable_qemu: bool = false, - - /// After following the steps in https://github.com/ziglang/zig/wiki/Updating-libc#glibc, - /// this will be the directory $glibc-build-dir/install/glibcs - /// Given the example of the aarch64 target, this is the directory - /// that contains the path `aarch64-linux-gnu/lib/ld-linux-aarch64.so.1`. - glibc_multi_install_dir: ?[]const u8 = null, - - dynamic_linker: ?[]const u8 = null, - - const LinkObject = union(enum) { - StaticPath: []const u8, - OtherStep: *LibExeObjStep, - SystemLib: []const u8, - AssemblyFile: []const u8, - CSourceFile: *CSourceFile, - }; - - const IncludeDir = union(enum) { - RawPath: []const u8, - OtherStep: *LibExeObjStep, - }; - - const Kind = enum { - Exe, - Lib, - Obj, - Test, - }; - - pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8, ver: Version) *LibExeObjStep { - const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, ver); - return self; - } - - pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { - const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, builder.version(0, 0, 0)); - return self; - } - - pub fn createObject(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { - const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0)); - return self; - } - - pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, is_dynamic: bool) *LibExeObjStep { - const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Exe, is_dynamic, builder.version(0, 0, 0)); - return self; - } - - pub fn createTest(builder: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep { - const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Test, false, builder.version(0, 0, 0)); - return self; - } - - fn initExtraArgs(builder: *Builder, name: []const u8, root_src: ?[]const u8, kind: Kind, is_dynamic: bool, ver: Version) LibExeObjStep { - if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) { - panic("invalid name: '{}'. It looks like a file path, but it is supposed to be the library or application name.", name); - } - var self = LibExeObjStep{ - .strip = false, - .builder = builder, - .verbose_link = false, - .verbose_cc = false, - .build_mode = builtin.Mode.Debug, - .is_dynamic = is_dynamic, - .kind = kind, - .root_src = root_src, - .name = name, - .target = Target.Native, - .frameworks = BufSet.init(builder.allocator), - .step = Step.init(name, builder.allocator, make), - .version = ver, - .out_filename = undefined, - .out_h_filename = builder.fmt("{}.h", name), - .out_lib_filename = undefined, - .out_pdb_filename = builder.fmt("{}.pdb", name), - .major_only_filename = undefined, - .name_only_filename = undefined, - .packages = ArrayList(Pkg).init(builder.allocator), - .include_dirs = ArrayList(IncludeDir).init(builder.allocator), - .link_objects = ArrayList(LinkObject).init(builder.allocator), - .c_macros = ArrayList([]const u8).init(builder.allocator), - .lib_paths = ArrayList([]const u8).init(builder.allocator), - .framework_dirs = ArrayList([]const u8).init(builder.allocator), - .object_src = undefined, - .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable, - .c_std = Builder.CStd.C99, - .system_linker_hack = false, - .override_std_dir = null, - .override_lib_dir = null, - .main_pkg_path = null, - .exec_cmd_args = null, - .name_prefix = "", - .filter = null, - .disable_gen_h = false, - .bundle_compiler_rt = false, - .disable_stack_probing = false, - .output_dir = null, - .need_system_paths = false, - .single_threaded = false, - .installed_path = null, - .install_step = null, - }; - self.computeOutFileNames(); - return self; - } - - fn computeOutFileNames(self: *LibExeObjStep) void { - switch (self.kind) { - .Obj => { - self.out_filename = self.builder.fmt("{}{}", self.name, self.target.oFileExt()); - }, - .Exe => { - self.out_filename = self.builder.fmt("{}{}", self.name, self.target.exeFileExt()); - }, - .Test => { - self.out_filename = self.builder.fmt("test{}", self.target.exeFileExt()); - }, - .Lib => { - if (!self.is_dynamic) { - self.out_filename = self.builder.fmt( - "{}{}{}", - self.target.libPrefix(), - self.name, - self.target.staticLibSuffix(), - ); - self.out_lib_filename = self.out_filename; - } else { - if (self.target.isDarwin()) { - self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib", self.name, self.version.major, self.version.minor, self.version.patch); - self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", self.name, self.version.major); - self.name_only_filename = self.builder.fmt("lib{}.dylib", self.name); - self.out_lib_filename = self.out_filename; - } else if (self.target.isWindows()) { - self.out_filename = self.builder.fmt("{}.dll", self.name); - self.out_lib_filename = self.builder.fmt("{}.lib", self.name); - } else { - self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}", self.name, self.version.major, self.version.minor, self.version.patch); - self.major_only_filename = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major); - self.name_only_filename = self.builder.fmt("lib{}.so", self.name); - self.out_lib_filename = self.out_filename; - } - } - }, - } - } - - /// Deprecated. Use `setTheTarget`. - pub fn setTarget( - self: *LibExeObjStep, - target_arch: builtin.Arch, - target_os: builtin.Os, - target_abi: builtin.Abi, - ) void { - return self.setTheTarget(Target{ - .Cross = CrossTarget{ - .arch = target_arch, - .os = target_os, - .abi = target_abi, - }, - }); - } - - pub fn setTheTarget(self: *LibExeObjStep, target: Target) void { - self.target = target; - self.computeOutFileNames(); - } - - pub fn setTargetGLibC(self: *LibExeObjStep, major: u32, minor: u32, patch: u32) void { - self.target_glibc = Version{ - .major = major, - .minor = minor, - .patch = patch, - }; - } - - pub fn setOutputDir(self: *LibExeObjStep, dir: []const u8) void { - self.output_dir = self.builder.dupePath(dir); - } - - pub fn install(self: *LibExeObjStep) void { - self.builder.installArtifact(self); - } - - /// Creates a `RunStep` with an executable built with `addExecutable`. - /// Add command line arguments with `addArg`. - pub fn run(exe: *LibExeObjStep) *RunStep { - assert(exe.kind == Kind.Exe); - - // It doesn't have to be native. We catch that if you actually try to run it. - // Consider that this is declarative; the run step may not be run unless a user - // option is supplied. - const run_step = RunStep.create(exe.builder, exe.builder.fmt("run {}", exe.step.name)); - run_step.addArtifactArg(exe); - return run_step; - } - - pub fn setLinkerScriptPath(self: *LibExeObjStep, path: []const u8) void { - self.linker_script = path; - } - - pub fn linkFramework(self: *LibExeObjStep, framework_name: []const u8) void { - assert(self.target.isDarwin()); - self.frameworks.put(framework_name) catch unreachable; - } - - /// Returns whether the library, executable, or object depends on a particular system library. - pub fn dependsOnSystemLibrary(self: LibExeObjStep, name: []const u8) bool { - if (isLibCLibrary(name)) { - return self.is_linking_libc; - } - for (self.link_objects.toSliceConst()) |link_object| { - switch (link_object) { - LinkObject.SystemLib => |n| if (mem.eql(u8, n, name)) return true, - else => continue, - } - } - return false; - } - - pub fn linkLibrary(self: *LibExeObjStep, lib: *LibExeObjStep) void { - assert(lib.kind == Kind.Lib); - self.linkLibraryOrObject(lib); - } - - pub fn isDynamicLibrary(self: *LibExeObjStep) bool { - return self.kind == Kind.Lib and self.is_dynamic; - } - - pub fn producesPdbFile(self: *LibExeObjStep) bool { - if (!self.target.isWindows() and !self.target.isUefi()) return false; - if (self.strip) return false; - return self.isDynamicLibrary() or self.kind == .Exe; - } - - pub fn linkLibC(self: *LibExeObjStep) void { - if (!self.is_linking_libc) { - self.is_linking_libc = true; - self.link_objects.append(LinkObject{ .SystemLib = "c" }) catch unreachable; - } - } - - /// name_and_value looks like [name]=[value]. If the value is omitted, it is set to 1. - pub fn defineCMacro(self: *LibExeObjStep, name_and_value: []const u8) void { - self.c_macros.append(self.builder.dupe(name_and_value)) catch unreachable; - } - - /// This one has no integration with anything, it just puts -lname on the command line. - /// Prefer to use `linkSystemLibrary` instead. - pub fn linkSystemLibraryName(self: *LibExeObjStep, name: []const u8) void { - self.link_objects.append(LinkObject{ .SystemLib = self.builder.dupe(name) }) catch unreachable; - self.need_system_paths = true; - } - - /// This links against a system library, exclusively using pkg-config to find the library. - /// Prefer to use `linkSystemLibrary` instead. - pub fn linkSystemLibraryPkgConfigOnly(self: *LibExeObjStep, lib_name: []const u8) !void { - const pkg_name = match: { - // First we have to map the library name to pkg config name. Unfortunately, - // there are several examples where this is not straightforward: - // -lSDL2 -> pkg-config sdl2 - // -lgdk-3 -> pkg-config gdk-3.0 - // -latk-1.0 -> pkg-config atk - const pkgs = try self.builder.getPkgConfigList(); - - // Exact match means instant winner. - for (pkgs) |pkg| { - if (mem.eql(u8, pkg.name, lib_name)) { - break :match pkg.name; - } - } - - // Next we'll try ignoring case. - for (pkgs) |pkg| { - if (std.ascii.eqlIgnoreCase(pkg.name, lib_name)) { - break :match pkg.name; - } - } - - // Now try appending ".0". - for (pkgs) |pkg| { - if (std.ascii.indexOfIgnoreCase(pkg.name, lib_name)) |pos| { - if (pos != 0) continue; - if (mem.eql(u8, pkg.name[lib_name.len..], ".0")) { - break :match pkg.name; - } - } - } - - // Trimming "-1.0". - if (mem.endsWith(u8, lib_name, "-1.0")) { - const trimmed_lib_name = lib_name[0 .. lib_name.len - "-1.0".len]; - for (pkgs) |pkg| { - if (std.ascii.eqlIgnoreCase(pkg.name, trimmed_lib_name)) { - break :match pkg.name; - } - } - } - - return error.PackageNotFound; - }; - - var code: u8 = undefined; - const stdout = if (self.builder.execAllowFail([_][]const u8{ - "pkg-config", - pkg_name, - "--cflags", - "--libs", - }, &code, .Ignore)) |stdout| stdout else |err| switch (err) { - error.ProcessTerminated => return error.PkgConfigCrashed, - error.ExitCodeFailure => return error.PkgConfigFailed, - error.FileNotFound => return error.PkgConfigNotInstalled, - else => return err, - }; - var it = mem.tokenize(stdout, " \r\n\t"); - while (it.next()) |tok| { - if (mem.eql(u8, tok, "-I")) { - const dir = it.next() orelse return error.PkgConfigInvalidOutput; - self.addIncludeDir(dir); - } else if (mem.startsWith(u8, tok, "-I")) { - self.addIncludeDir(tok["-I".len..]); - } else if (mem.eql(u8, tok, "-L")) { - const dir = it.next() orelse return error.PkgConfigInvalidOutput; - self.addLibPath(dir); - } else if (mem.startsWith(u8, tok, "-L")) { - self.addLibPath(tok["-L".len..]); - } else if (mem.eql(u8, tok, "-l")) { - const lib = it.next() orelse return error.PkgConfigInvalidOutput; - self.linkSystemLibraryName(lib); - } else if (mem.startsWith(u8, tok, "-l")) { - self.linkSystemLibraryName(tok["-l".len..]); - } else if (mem.eql(u8, tok, "-D")) { - const macro = it.next() orelse return error.PkgConfigInvalidOutput; - self.defineCMacro(macro); - } else if (mem.startsWith(u8, tok, "-D")) { - self.defineCMacro(tok["-D".len..]); - } else if (mem.eql(u8, tok, "-pthread")) { - self.linkLibC(); - } else if (self.builder.verbose) { - warn("Ignoring pkg-config flag '{}'\n", tok); - } - } - } - - pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void { - if (isLibCLibrary(name)) { - self.linkLibC(); - return; - } - if (self.linkSystemLibraryPkgConfigOnly(name)) |_| { - // pkg-config worked, so nothing further needed to do. - return; - } else |err| switch (err) { - error.PkgConfigInvalidOutput, - error.PkgConfigCrashed, - error.PkgConfigFailed, - error.PkgConfigNotInstalled, - error.PackageNotFound, - => {}, - - else => unreachable, - } - - self.linkSystemLibraryName(name); - } - - pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void { - assert(self.kind == Kind.Test); - self.name_prefix = text; - } - - pub fn setFilter(self: *LibExeObjStep, text: ?[]const u8) void { - assert(self.kind == Kind.Test); - self.filter = text; - } - - pub fn addCSourceFile(self: *LibExeObjStep, file: []const u8, args: []const []const u8) void { - const c_source_file = self.builder.allocator.create(CSourceFile) catch unreachable; - const args_copy = self.builder.allocator.alloc([]u8, args.len) catch unreachable; - for (args) |arg, i| { - args_copy[i] = self.builder.dupe(arg); - } - c_source_file.* = CSourceFile{ - .source_path = self.builder.dupe(file), - .args = args_copy, - }; - self.link_objects.append(LinkObject{ .CSourceFile = c_source_file }) catch unreachable; - } - - pub fn setVerboseLink(self: *LibExeObjStep, value: bool) void { - self.verbose_link = value; - } - - pub fn setVerboseCC(self: *LibExeObjStep, value: bool) void { - self.verbose_cc = value; - } - - pub fn setBuildMode(self: *LibExeObjStep, mode: builtin.Mode) void { - self.build_mode = mode; - } - - pub fn overrideStdDir(self: *LibExeObjStep, dir_path: []const u8) void { - self.override_std_dir = dir_path; - } - - pub fn setMainPkgPath(self: *LibExeObjStep, dir_path: []const u8) void { - self.main_pkg_path = dir_path; - } - - pub fn setDisableGenH(self: *LibExeObjStep, value: bool) void { - self.disable_gen_h = value; - } - - pub fn setLibCFile(self: *LibExeObjStep, libc_file: ?[]const u8) void { - self.libc_file = libc_file; - } - - /// Unless setOutputDir was called, this function must be called only in - /// the make step, from a step that has declared a dependency on this one. - /// To run an executable built with zig build, use `run`, or create an install step and invoke it. - pub fn getOutputPath(self: *LibExeObjStep) []const u8 { - return fs.path.join( - self.builder.allocator, - [_][]const u8{ self.output_dir.?, self.out_filename }, - ) catch unreachable; - } - - /// Unless setOutputDir was called, this function must be called only in - /// the make step, from a step that has declared a dependency on this one. - pub fn getOutputLibPath(self: *LibExeObjStep) []const u8 { - assert(self.kind == Kind.Lib); - return fs.path.join( - self.builder.allocator, - [_][]const u8{ self.output_dir.?, self.out_lib_filename }, - ) catch unreachable; - } - - /// Unless setOutputDir was called, this function must be called only in - /// the make step, from a step that has declared a dependency on this one. - pub fn getOutputHPath(self: *LibExeObjStep) []const u8 { - assert(self.kind != Kind.Exe); - assert(!self.disable_gen_h); - return fs.path.join( - self.builder.allocator, - [_][]const u8{ self.output_dir.?, self.out_h_filename }, - ) catch unreachable; - } - - /// Unless setOutputDir was called, this function must be called only in - /// the make step, from a step that has declared a dependency on this one. - pub fn getOutputPdbPath(self: *LibExeObjStep) []const u8 { - assert(self.target.isWindows() or self.target.isUefi()); - return fs.path.join( - self.builder.allocator, - [_][]const u8{ self.output_dir.?, self.out_pdb_filename }, - ) catch unreachable; - } - - pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void { - self.link_objects.append(LinkObject{ .AssemblyFile = self.builder.dupe(path) }) catch unreachable; - } - - pub fn addObjectFile(self: *LibExeObjStep, path: []const u8) void { - self.link_objects.append(LinkObject{ .StaticPath = self.builder.dupe(path) }) catch unreachable; - } - - pub fn addObject(self: *LibExeObjStep, obj: *LibExeObjStep) void { - assert(obj.kind == Kind.Obj); - self.linkLibraryOrObject(obj); - } - - pub fn addBuildOption(self: *LibExeObjStep, comptime T: type, name: []const u8, value: T) void { - const out = &std.io.BufferOutStream.init(&self.build_options_contents).stream; - out.print("pub const {} = {};\n", name, value) catch unreachable; - } - - pub fn addIncludeDir(self: *LibExeObjStep, path: []const u8) void { - self.include_dirs.append(IncludeDir{ .RawPath = self.builder.dupe(path) }) catch unreachable; - } - - pub fn addLibPath(self: *LibExeObjStep, path: []const u8) void { - self.lib_paths.append(path) catch unreachable; - } - - pub fn addFrameworkDir(self: *LibExeObjStep, dir_path: []const u8) void { - self.framework_dirs.append(dir_path) catch unreachable; - } - - pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void { - self.packages.append(Pkg{ - .name = name, - .path = pkg_index_path, - }) catch unreachable; - } - - pub fn setExecCmd(self: *LibExeObjStep, args: []const ?[]const u8) void { - assert(self.kind == Kind.Test); - self.exec_cmd_args = args; - } - - pub fn enableSystemLinkerHack(self: *LibExeObjStep) void { - self.system_linker_hack = true; - } - - fn linkLibraryOrObject(self: *LibExeObjStep, other: *LibExeObjStep) void { - self.step.dependOn(&other.step); - self.link_objects.append(LinkObject{ .OtherStep = other }) catch unreachable; - self.include_dirs.append(IncludeDir{ .OtherStep = other }) catch unreachable; - - // Inherit dependency on system libraries - for (other.link_objects.toSliceConst()) |link_object| { - switch (link_object) { - .SystemLib => |name| self.linkSystemLibrary(name), - else => continue, - } - } - - // Inherit dependencies on darwin frameworks - if (self.target.isDarwin() and !other.isDynamicLibrary()) { - var it = other.frameworks.iterator(); - while (it.next()) |entry| { - self.frameworks.put(entry.key) catch unreachable; - } - } - } - - fn make(step: *Step) !void { - const self = @fieldParentPtr(LibExeObjStep, "step", step); - const builder = self.builder; - - if (self.root_src == null and self.link_objects.len == 0) { - warn("{}: linker needs 1 or more objects to link\n", self.step.name); - return error.NeedAnObject; - } - - var zig_args = ArrayList([]const u8).init(builder.allocator); - defer zig_args.deinit(); - - zig_args.append(builder.zig_exe) catch unreachable; - - const cmd = switch (self.kind) { - Kind.Lib => "build-lib", - Kind.Exe => "build-exe", - Kind.Obj => "build-obj", - Kind.Test => "test", - }; - zig_args.append(cmd) catch unreachable; - - if (self.root_src) |root_src| { - zig_args.append(builder.pathFromRoot(root_src)) catch unreachable; - } - - for (self.link_objects.toSlice()) |link_object| { - switch (link_object) { - LinkObject.StaticPath => |static_path| { - try zig_args.append("--object"); - try zig_args.append(builder.pathFromRoot(static_path)); - }, - - LinkObject.OtherStep => |other| switch (other.kind) { - LibExeObjStep.Kind.Exe => unreachable, - LibExeObjStep.Kind.Test => unreachable, - LibExeObjStep.Kind.Obj => { - try zig_args.append("--object"); - try zig_args.append(other.getOutputPath()); - }, - LibExeObjStep.Kind.Lib => { - if (!other.is_dynamic or self.target.isWindows()) { - try zig_args.append("--object"); - try zig_args.append(other.getOutputLibPath()); - } else { - const full_path_lib = other.getOutputPath(); - try zig_args.append("--library"); - try zig_args.append(full_path_lib); - - if (fs.path.dirname(full_path_lib)) |dirname| { - try zig_args.append("-rpath"); - try zig_args.append(dirname); - } - } - }, - }, - LinkObject.SystemLib => |name| { - try zig_args.append("--library"); - try zig_args.append(name); - }, - LinkObject.AssemblyFile => |asm_file| { - try zig_args.append("--c-source"); - try zig_args.append(builder.pathFromRoot(asm_file)); - }, - LinkObject.CSourceFile => |c_source_file| { - try zig_args.append("--c-source"); - for (c_source_file.args) |arg| { - try zig_args.append(arg); - } - try zig_args.append(self.builder.pathFromRoot(c_source_file.source_path)); - }, - } - } - - if (self.build_options_contents.len() > 0) { - const build_options_file = try fs.path.join( - builder.allocator, - [_][]const u8{ builder.cache_root, builder.fmt("{}_build_options.zig", self.name) }, - ); - try std.io.writeFile(build_options_file, self.build_options_contents.toSliceConst()); - try zig_args.append("--pkg-begin"); - try zig_args.append("build_options"); - try zig_args.append(builder.pathFromRoot(build_options_file)); - try zig_args.append("--pkg-end"); - } - - if (self.filter) |filter| { - try zig_args.append("--test-filter"); - try zig_args.append(filter); - } - - if (self.name_prefix.len != 0) { - try zig_args.append("--test-name-prefix"); - try zig_args.append(self.name_prefix); - } - - if (builder.verbose_tokenize) zig_args.append("--verbose-tokenize") catch unreachable; - if (builder.verbose_ast) zig_args.append("--verbose-ast") catch unreachable; - if (builder.verbose_cimport) zig_args.append("--verbose-cimport") catch unreachable; - if (builder.verbose_ir) zig_args.append("--verbose-ir") catch unreachable; - if (builder.verbose_llvm_ir) zig_args.append("--verbose-llvm-ir") catch unreachable; - if (builder.verbose_link or self.verbose_link) zig_args.append("--verbose-link") catch unreachable; - if (builder.verbose_cc or self.verbose_cc) zig_args.append("--verbose-cc") catch unreachable; - - if (self.strip) { - zig_args.append("--strip") catch unreachable; - } - - if (self.single_threaded) { - try zig_args.append("--single-threaded"); - } - - if (self.libc_file) |libc_file| { - try zig_args.append("--libc"); - try zig_args.append(builder.pathFromRoot(libc_file)); - } - - switch (self.build_mode) { - builtin.Mode.Debug => {}, - builtin.Mode.ReleaseSafe => zig_args.append("--release-safe") catch unreachable, - builtin.Mode.ReleaseFast => zig_args.append("--release-fast") catch unreachable, - builtin.Mode.ReleaseSmall => zig_args.append("--release-small") catch unreachable, - } - - try zig_args.append("--cache-dir"); - try zig_args.append(builder.pathFromRoot(builder.cache_root)); - - zig_args.append("--name") catch unreachable; - zig_args.append(self.name) catch unreachable; - - if (self.kind == Kind.Lib and self.is_dynamic) { - zig_args.append("--ver-major") catch unreachable; - zig_args.append(builder.fmt("{}", self.version.major)) catch unreachable; - - zig_args.append("--ver-minor") catch unreachable; - zig_args.append(builder.fmt("{}", self.version.minor)) catch unreachable; - - zig_args.append("--ver-patch") catch unreachable; - zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable; - } - if (self.is_dynamic) { - try zig_args.append("-dynamic"); - } - if (self.disable_gen_h) { - try zig_args.append("--disable-gen-h"); - } - if (self.bundle_compiler_rt) { - try zig_args.append("--bundle-compiler-rt"); - } - if (self.disable_stack_probing) { - try zig_args.append("-fno-stack-check"); - } - - switch (self.target) { - Target.Native => {}, - Target.Cross => { - try zig_args.append("-target"); - try zig_args.append(self.target.zigTriple(builder.allocator) catch unreachable); - }, - } - - if (self.target_glibc) |ver| { - try zig_args.append("-target-glibc"); - try zig_args.append(builder.fmt("{}.{}.{}", ver.major, ver.minor, ver.patch)); - } - - if (self.linker_script) |linker_script| { - zig_args.append("--linker-script") catch unreachable; - zig_args.append(builder.pathFromRoot(linker_script)) catch unreachable; - } - - if (self.dynamic_linker) |dynamic_linker| { - try zig_args.append("--dynamic-linker"); - try zig_args.append(dynamic_linker); - } - - if (self.version_script) |version_script| { - try zig_args.append("--version-script"); - try zig_args.append(builder.pathFromRoot(version_script)); - } - - if (self.exec_cmd_args) |exec_cmd_args| { - for (exec_cmd_args) |cmd_arg| { - if (cmd_arg) |arg| { - try zig_args.append("--test-cmd"); - try zig_args.append(arg); - } else { - try zig_args.append("--test-cmd-bin"); - } - } - } else switch (self.target.getExternalExecutor()) { - .native, .unavailable => {}, - .qemu => |bin_name| if (self.enable_qemu) qemu: { - const need_cross_glibc = self.target.isGnu() and self.target.isLinux() and self.is_linking_libc; - const glibc_dir_arg = if (need_cross_glibc) - self.glibc_multi_install_dir orelse break :qemu - else - null; - try zig_args.append("--test-cmd"); - try zig_args.append(bin_name); - if (glibc_dir_arg) |dir| { - const full_dir = try fs.path.join(builder.allocator, [_][]const u8{ - dir, - try self.target.linuxTriple(builder.allocator), - }); - - try zig_args.append("--test-cmd"); - try zig_args.append("-L"); - try zig_args.append("--test-cmd"); - try zig_args.append(full_dir); - } - try zig_args.append("--test-cmd-bin"); - }, - .wine => |bin_name| if (self.enable_wine) { - try zig_args.append("--test-cmd"); - try zig_args.append(bin_name); - try zig_args.append("--test-cmd-bin"); - }, - } - for (self.packages.toSliceConst()) |pkg| { - zig_args.append("--pkg-begin") catch unreachable; - zig_args.append(pkg.name) catch unreachable; - zig_args.append(builder.pathFromRoot(pkg.path)) catch unreachable; - zig_args.append("--pkg-end") catch unreachable; - } - - for (self.include_dirs.toSliceConst()) |include_dir| { - switch (include_dir) { - IncludeDir.RawPath => |include_path| { - try zig_args.append("-isystem"); - try zig_args.append(self.builder.pathFromRoot(include_path)); - }, - IncludeDir.OtherStep => |other| { - const h_path = other.getOutputHPath(); - try zig_args.append("-isystem"); - try zig_args.append(fs.path.dirname(h_path).?); - }, - } - } - - for (self.lib_paths.toSliceConst()) |lib_path| { - try zig_args.append("-L"); - try zig_args.append(lib_path); - } - - if (self.need_system_paths and self.target == Target.Native) { - for (builder.native_system_include_dirs.toSliceConst()) |include_path| { - zig_args.append("-isystem") catch unreachable; - zig_args.append(builder.pathFromRoot(include_path)) catch unreachable; - } - - for (builder.native_system_rpaths.toSliceConst()) |rpath| { - zig_args.append("-rpath") catch unreachable; - zig_args.append(rpath) catch unreachable; - } - - for (builder.native_system_lib_paths.toSliceConst()) |lib_path| { - zig_args.append("--library-path") catch unreachable; - zig_args.append(lib_path) catch unreachable; - } - } - - for (self.c_macros.toSliceConst()) |c_macro| { - try zig_args.append("-D"); - try zig_args.append(c_macro); - } - - if (self.target.isDarwin()) { - for (self.framework_dirs.toSliceConst()) |dir| { - try zig_args.append("-F"); - try zig_args.append(dir); - } - - var it = self.frameworks.iterator(); - while (it.next()) |entry| { - zig_args.append("-framework") catch unreachable; - zig_args.append(entry.key) catch unreachable; - } - } - - if (self.system_linker_hack) { - try zig_args.append("--system-linker-hack"); - } - - if (self.valgrind_support) |valgrind_support| { - if (valgrind_support) { - try zig_args.append("--enable-valgrind"); - } else { - try zig_args.append("--disable-valgrind"); - } - } - - if (self.override_std_dir) |dir| { - try zig_args.append("--override-std-dir"); - try zig_args.append(builder.pathFromRoot(dir)); - } else if (self.builder.override_std_dir) |dir| { - try zig_args.append("--override-std-dir"); - try zig_args.append(builder.pathFromRoot(dir)); - } - - if (self.override_lib_dir) |dir| { - try zig_args.append("--override-lib-dir"); - try zig_args.append(builder.pathFromRoot(dir)); - } else if (self.builder.override_lib_dir) |dir| { - try zig_args.append("--override-lib-dir"); - try zig_args.append(builder.pathFromRoot(dir)); - } - - if (self.main_pkg_path) |dir| { - try zig_args.append("--main-pkg-path"); - try zig_args.append(builder.pathFromRoot(dir)); - } - - if (self.kind == Kind.Test) { - try builder.spawnChild(zig_args.toSliceConst()); - } else { - try zig_args.append("--cache"); - try zig_args.append("on"); - - const output_path_nl = try builder.exec(zig_args.toSliceConst()); - const output_path = mem.trimRight(u8, output_path_nl, "\r\n"); - - if (self.output_dir) |output_dir| { - const full_dest = try fs.path.join(builder.allocator, [_][]const u8{ - output_dir, - fs.path.basename(output_path), - }); - try builder.updateFile(output_path, full_dest); - } else { - self.output_dir = fs.path.dirname(output_path).?; - } - } - - if (self.kind == Kind.Lib and self.is_dynamic and self.target.wantSharedLibSymLinks()) { - try doAtomicSymLinks(builder.allocator, self.getOutputPath(), self.major_only_filename, self.name_only_filename); - } - } -}; - -pub const RunStep = struct { - step: Step, - builder: *Builder, - - /// See also addArg and addArgs to modifying this directly - argv: ArrayList(Arg), - - /// Set this to modify the current working directory - cwd: ?[]const u8, - - /// Override this field to modify the environment, or use setEnvironmentVariable - env_map: ?*BufMap, - - pub const Arg = union(enum) { - Artifact: *LibExeObjStep, - Bytes: []u8, - }; - - pub fn create(builder: *Builder, name: []const u8) *RunStep { - const self = builder.allocator.create(RunStep) catch unreachable; - self.* = RunStep{ - .builder = builder, - .step = Step.init(name, builder.allocator, make), - .argv = ArrayList(Arg).init(builder.allocator), - .cwd = null, - .env_map = null, - }; - return self; - } - - pub fn addArtifactArg(self: *RunStep, artifact: *LibExeObjStep) void { - self.argv.append(Arg{ .Artifact = artifact }) catch unreachable; - self.step.dependOn(&artifact.step); - } - - pub fn addArg(self: *RunStep, arg: []const u8) void { - self.argv.append(Arg{ .Bytes = self.builder.dupe(arg) }) catch unreachable; - } - - pub fn addArgs(self: *RunStep, args: []const []const u8) void { - for (args) |arg| { - self.addArg(arg); - } - } - - pub fn clearEnvironment(self: *RunStep) void { - const new_env_map = self.builder.allocator.create(BufMap) catch unreachable; - new_env_map.* = BufMap.init(self.builder.allocator); - self.env_map = new_env_map; - } - - pub fn addPathDir(self: *RunStep, search_path: []const u8) void { - const PATH = if (std.os.windows.is_the_target) "Path" else "PATH"; - const env_map = self.getEnvMap(); - const prev_path = env_map.get(PATH) orelse { - env_map.set(PATH, search_path) catch unreachable; - return; - }; - const new_path = self.builder.fmt("{}" ++ [1]u8{fs.path.delimiter} ++ "{}", prev_path, search_path); - env_map.set(PATH, new_path) catch unreachable; - } - - pub fn getEnvMap(self: *RunStep) *BufMap { - return self.env_map orelse { - const env_map = self.builder.allocator.create(BufMap) catch unreachable; - env_map.* = process.getEnvMap(self.builder.allocator) catch unreachable; - self.env_map = env_map; - return env_map; - }; - } - - pub fn setEnvironmentVariable(self: *RunStep, key: []const u8, value: []const u8) void { - const env_map = self.getEnvMap(); - env_map.set(key, value) catch unreachable; - } - - fn make(step: *Step) !void { - const self = @fieldParentPtr(RunStep, "step", step); - - const cwd = if (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else self.builder.build_root; - - var argv = ArrayList([]const u8).init(self.builder.allocator); - for (self.argv.toSlice()) |arg| { - switch (arg) { - Arg.Bytes => |bytes| try argv.append(bytes), - Arg.Artifact => |artifact| { - if (artifact.target.isWindows()) { - // On Windows we don't have rpaths so we have to add .dll search paths to PATH - self.addPathForDynLibs(artifact); - } - const executable_path = artifact.installed_path orelse artifact.getOutputPath(); - try argv.append(executable_path); - }, - } - } - - return self.builder.spawnChildEnvMap(cwd, self.env_map orelse self.builder.env_map, argv.toSliceConst()); - } - - fn addPathForDynLibs(self: *RunStep, artifact: *LibExeObjStep) void { - for (artifact.link_objects.toSliceConst()) |link_object| { - switch (link_object) { - LibExeObjStep.LinkObject.OtherStep => |other| { - if (other.target.isWindows() and other.isDynamicLibrary()) { - self.addPathDir(fs.path.dirname(other.getOutputPath()).?); - self.addPathForDynLibs(other); - } - }, - else => {}, - } - } - } -}; - -const InstallArtifactStep = struct { - step: Step, - builder: *Builder, - artifact: *LibExeObjStep, - dest_dir: InstallDir, - pdb_dir: ?InstallDir, - - const Self = @This(); - - pub fn create(builder: *Builder, artifact: *LibExeObjStep) *Self { - if (artifact.install_step) |s| return s; - - const self = builder.allocator.create(Self) catch unreachable; - self.* = Self{ - .builder = builder, - .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make), - .artifact = artifact, - .dest_dir = switch (artifact.kind) { - .Obj => unreachable, - .Test => unreachable, - .Exe => InstallDir.Bin, - .Lib => InstallDir.Lib, - }, - .pdb_dir = if (artifact.producesPdbFile()) blk: { - if (artifact.kind == .Exe) { - break :blk InstallDir.Bin; - } else { - break :blk InstallDir.Lib; - } - } else null, - }; - self.step.dependOn(&artifact.step); - artifact.install_step = self; - - builder.pushInstalledFile(self.dest_dir, artifact.out_filename); - if (self.artifact.isDynamicLibrary()) { - builder.pushInstalledFile(.Lib, artifact.major_only_filename); - builder.pushInstalledFile(.Lib, artifact.name_only_filename); - } - if (self.pdb_dir) |pdb_dir| { - builder.pushInstalledFile(pdb_dir, artifact.out_pdb_filename); - } - return self; - } - - fn make(step: *Step) !void { - const self = @fieldParentPtr(Self, "step", step); - const builder = self.builder; - - const full_dest_path = builder.getInstallPath(self.dest_dir, self.artifact.out_filename); - try builder.updateFile(self.artifact.getOutputPath(), full_dest_path); - if (self.artifact.isDynamicLibrary()) { - try doAtomicSymLinks(builder.allocator, full_dest_path, self.artifact.major_only_filename, self.artifact.name_only_filename); - } - if (self.pdb_dir) |pdb_dir| { - const full_pdb_path = builder.getInstallPath(pdb_dir, self.artifact.out_pdb_filename); - try builder.updateFile(self.artifact.getOutputPdbPath(), full_pdb_path); - } - self.artifact.installed_path = full_dest_path; - } -}; - -pub const InstallFileStep = struct { - step: Step, - builder: *Builder, - src_path: []const u8, - dir: InstallDir, - dest_rel_path: []const u8, - - pub fn init( - builder: *Builder, - src_path: []const u8, - dir: InstallDir, - dest_rel_path: []const u8, - ) InstallFileStep { - builder.pushInstalledFile(dir, dest_rel_path); - return InstallFileStep{ - .builder = builder, - .step = Step.init(builder.fmt("install {}", src_path), builder.allocator, make), - .src_path = src_path, - .dir = dir, - .dest_rel_path = dest_rel_path, - }; - } - - fn make(step: *Step) !void { - const self = @fieldParentPtr(InstallFileStep, "step", step); - const full_dest_path = self.builder.getInstallPath(self.dir, self.dest_rel_path); - const full_src_path = self.builder.pathFromRoot(self.src_path); - try self.builder.updateFile(full_src_path, full_dest_path); - } -}; - -pub const InstallDirectoryOptions = struct { - source_dir: []const u8, - install_dir: InstallDir, - install_subdir: []const u8, - exclude_extensions: ?[]const []const u8 = null, -}; - -pub const InstallDirStep = struct { - step: Step, - builder: *Builder, - options: InstallDirectoryOptions, - - pub fn init( - builder: *Builder, - options: InstallDirectoryOptions, - ) InstallDirStep { - builder.pushInstalledFile(options.install_dir, options.install_subdir); - return InstallDirStep{ - .builder = builder, - .step = Step.init(builder.fmt("install {}/", options.source_dir), builder.allocator, make), - .options = options, - }; - } - - fn make(step: *Step) !void { - const self = @fieldParentPtr(InstallDirStep, "step", step); - const dest_prefix = self.builder.getInstallPath(self.options.install_dir, self.options.install_subdir); - const full_src_dir = self.builder.pathFromRoot(self.options.source_dir); - var it = try fs.walkPath(self.builder.allocator, full_src_dir); - next_entry: while (try it.next()) |entry| { - if (self.options.exclude_extensions) |ext_list| for (ext_list) |ext| { - if (mem.endsWith(u8, entry.path, ext)) { - continue :next_entry; - } - }; - - const rel_path = entry.path[full_src_dir.len + 1 ..]; - const dest_path = try fs.path.join(self.builder.allocator, [_][]const u8{ dest_prefix, rel_path }); - switch (entry.kind) { - .Directory => try fs.makePath(self.builder.allocator, dest_path), - .File => try self.builder.updateFile(entry.path, dest_path), - else => continue, - } - } - } -}; - -pub const WriteFileStep = struct { - step: Step, - builder: *Builder, - file_path: []const u8, - data: []const u8, - - pub fn init(builder: *Builder, file_path: []const u8, data: []const u8) WriteFileStep { - return WriteFileStep{ - .builder = builder, - .step = Step.init(builder.fmt("writefile {}", file_path), builder.allocator, make), - .file_path = file_path, - .data = data, - }; - } - - fn make(step: *Step) !void { - const self = @fieldParentPtr(WriteFileStep, "step", step); - const full_path = self.builder.pathFromRoot(self.file_path); - const full_path_dir = fs.path.dirname(full_path) orelse "."; - fs.makePath(self.builder.allocator, full_path_dir) catch |err| { - warn("unable to make path {}: {}\n", full_path_dir, @errorName(err)); - return err; - }; - io.writeFile(full_path, self.data) catch |err| { - warn("unable to write {}: {}\n", full_path, @errorName(err)); - return err; - }; - } -}; - -pub const LogStep = struct { - step: Step, - builder: *Builder, - data: []const u8, - - pub fn init(builder: *Builder, data: []const u8) LogStep { - return LogStep{ - .builder = builder, - .step = Step.init(builder.fmt("log {}", data), builder.allocator, make), - .data = data, - }; - } - - fn make(step: *Step) anyerror!void { - const self = @fieldParentPtr(LogStep, "step", step); - warn("{}", self.data); - } -}; - -pub const RemoveDirStep = struct { - step: Step, - builder: *Builder, - dir_path: []const u8, - - pub fn init(builder: *Builder, dir_path: []const u8) RemoveDirStep { - return RemoveDirStep{ - .builder = builder, - .step = Step.init(builder.fmt("RemoveDir {}", dir_path), builder.allocator, make), - .dir_path = dir_path, - }; - } - - fn make(step: *Step) !void { - const self = @fieldParentPtr(RemoveDirStep, "step", step); - - const full_path = self.builder.pathFromRoot(self.dir_path); - fs.deleteTree(self.builder.allocator, full_path) catch |err| { - warn("Unable to remove {}: {}\n", full_path, @errorName(err)); - return err; - }; - } -}; - -pub const Step = struct { - name: []const u8, - makeFn: fn (self: *Step) anyerror!void, - dependencies: ArrayList(*Step), - loop_flag: bool, - done_flag: bool, - - pub fn init(name: []const u8, allocator: *Allocator, makeFn: fn (*Step) anyerror!void) Step { - return Step{ - .name = name, - .makeFn = makeFn, - .dependencies = ArrayList(*Step).init(allocator), - .loop_flag = false, - .done_flag = false, - }; - } - pub fn initNoOp(name: []const u8, allocator: *Allocator) Step { - return init(name, allocator, makeNoOp); - } - - pub fn make(self: *Step) !void { - if (self.done_flag) return; - - try self.makeFn(self); - self.done_flag = true; - } - - pub fn dependOn(self: *Step, other: *Step) void { - self.dependencies.append(other) catch unreachable; - } - - fn makeNoOp(self: *Step) anyerror!void {} -}; - -fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void { - const out_dir = fs.path.dirname(output_path) orelse "."; - const out_basename = fs.path.basename(output_path); - // sym link for libfoo.so.1 to libfoo.so.1.2.3 - const major_only_path = fs.path.join( - allocator, - [_][]const u8{ out_dir, filename_major_only }, - ) catch unreachable; - fs.atomicSymLink(allocator, out_basename, major_only_path) catch |err| { - warn("Unable to symlink {} -> {}\n", major_only_path, out_basename); - return err; - }; - // sym link for libfoo.so to libfoo.so.1 - const name_only_path = fs.path.join( - allocator, - [_][]const u8{ out_dir, filename_name_only }, - ) catch unreachable; - fs.atomicSymLink(allocator, filename_major_only, name_only_path) catch |err| { - warn("Unable to symlink {} -> {}\n", name_only_path, filename_major_only); - return err; - }; -} - -pub const InstallDir = enum { - Prefix, - Lib, - Bin, -}; - -pub const InstalledFile = struct { - dir: InstallDir, - path: []const u8, -}; diff --git a/std/special/build_runner.zig b/std/special/build_runner.zig @@ -1,227 +0,0 @@ -const root = @import("@build"); -const std = @import("std"); -const builtin = @import("builtin"); -const io = std.io; -const fmt = std.fmt; -const Builder = std.build.Builder; -const mem = std.mem; -const process = std.process; -const ArrayList = std.ArrayList; -const warn = std.debug.warn; -const File = std.fs.File; - -pub fn main() !void { - var arg_it = process.args(); - - // Here we use an ArenaAllocator backed by a DirectAllocator because a build is a short-lived, - // one shot program. We don't need to waste time freeing memory and finding places to squish - // bytes into. So we free everything all at once at the very end. - - var arena = std.heap.ArenaAllocator.init(std.heap.direct_allocator); - defer arena.deinit(); - - const allocator = &arena.allocator; - - // skip my own exe name - _ = arg_it.skip(); - - const zig_exe = try unwrapArg(arg_it.next(allocator) orelse { - warn("Expected first argument to be path to zig compiler\n"); - return error.InvalidArgs; - }); - const build_root = try unwrapArg(arg_it.next(allocator) orelse { - warn("Expected second argument to be build root directory path\n"); - return error.InvalidArgs; - }); - const cache_root = try unwrapArg(arg_it.next(allocator) orelse { - warn("Expected third argument to be cache root directory path\n"); - return error.InvalidArgs; - }); - - const builder = try Builder.create(allocator, zig_exe, build_root, cache_root); - defer builder.destroy(); - - var targets = ArrayList([]const u8).init(allocator); - - var stderr_file = io.getStdErr(); - var stderr_file_stream: File.OutStream = undefined; - var stderr_stream = if (stderr_file) |f| x: { - stderr_file_stream = f.outStream(); - break :x &stderr_file_stream.stream; - } else |err| err; - - var stdout_file = io.getStdOut(); - var stdout_file_stream: File.OutStream = undefined; - var stdout_stream = if (stdout_file) |f| x: { - stdout_file_stream = f.outStream(); - break :x &stdout_file_stream.stream; - } else |err| err; - - while (arg_it.next(allocator)) |err_or_arg| { - const arg = try unwrapArg(err_or_arg); - if (mem.startsWith(u8, arg, "-D")) { - const option_contents = arg[2..]; - if (option_contents.len == 0) { - warn("Expected option name after '-D'\n\n"); - return usageAndErr(builder, false, try stderr_stream); - } - if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| { - const option_name = option_contents[0..name_end]; - const option_value = option_contents[name_end + 1 ..]; - if (try builder.addUserInputOption(option_name, option_value)) - return usageAndErr(builder, false, try stderr_stream); - } else { - if (try builder.addUserInputFlag(option_contents)) - return usageAndErr(builder, false, try stderr_stream); - } - } else if (mem.startsWith(u8, arg, "-")) { - if (mem.eql(u8, arg, "--verbose")) { - builder.verbose = true; - } else if (mem.eql(u8, arg, "--help")) { - return usage(builder, false, try stdout_stream); - } else if (mem.eql(u8, arg, "--prefix")) { - builder.install_prefix = try unwrapArg(arg_it.next(allocator) orelse { - warn("Expected argument after --prefix\n\n"); - return usageAndErr(builder, false, try stderr_stream); - }); - } else if (mem.eql(u8, arg, "--search-prefix")) { - const search_prefix = try unwrapArg(arg_it.next(allocator) orelse { - warn("Expected argument after --search-prefix\n\n"); - return usageAndErr(builder, false, try stderr_stream); - }); - builder.addSearchPrefix(search_prefix); - } else if (mem.eql(u8, arg, "--override-std-dir")) { - builder.override_std_dir = try unwrapArg(arg_it.next(allocator) orelse { - warn("Expected argument after --override-std-dir\n\n"); - return usageAndErr(builder, false, try stderr_stream); - }); - } else if (mem.eql(u8, arg, "--override-lib-dir")) { - builder.override_lib_dir = try unwrapArg(arg_it.next(allocator) orelse { - warn("Expected argument after --override-lib-dir\n\n"); - return usageAndErr(builder, false, try stderr_stream); - }); - } else if (mem.eql(u8, arg, "--verbose-tokenize")) { - builder.verbose_tokenize = true; - } else if (mem.eql(u8, arg, "--verbose-ast")) { - builder.verbose_ast = true; - } else if (mem.eql(u8, arg, "--verbose-link")) { - builder.verbose_link = true; - } else if (mem.eql(u8, arg, "--verbose-ir")) { - builder.verbose_ir = true; - } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { - builder.verbose_llvm_ir = true; - } else if (mem.eql(u8, arg, "--verbose-cimport")) { - builder.verbose_cimport = true; - } else if (mem.eql(u8, arg, "--verbose-cc")) { - builder.verbose_cc = true; - } else { - warn("Unrecognized argument: {}\n\n", arg); - return usageAndErr(builder, false, try stderr_stream); - } - } else { - try targets.append(arg); - } - } - - builder.resolveInstallPrefix(); - try runBuild(builder); - - if (builder.validateUserInputDidItFail()) - return usageAndErr(builder, true, try stderr_stream); - - builder.make(targets.toSliceConst()) catch |err| { - switch (err) { - error.InvalidStepName => { - return usageAndErr(builder, true, try stderr_stream); - }, - error.UncleanExit => process.exit(1), - else => return err, - } - }; -} - -fn runBuild(builder: *Builder) anyerror!void { - switch (@typeId(@typeOf(root.build).ReturnType)) { - .Void => root.build(builder), - .ErrorUnion => try root.build(builder), - else => @compileError("expected return type of build to be 'void' or '!void'"), - } -} - -fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void { - // run the build script to collect the options - if (!already_ran_build) { - builder.setInstallPrefix(null); - builder.resolveInstallPrefix(); - try runBuild(builder); - } - - try out_stream.print( - \\Usage: {} build [steps] [options] - \\ - \\Steps: - \\ - , builder.zig_exe); - - const allocator = builder.allocator; - for (builder.top_level_steps.toSliceConst()) |top_level_step| { - const name = if (&top_level_step.step == builder.default_step) - try fmt.allocPrint(allocator, "{} (default)", top_level_step.step.name) - else - top_level_step.step.name; - try out_stream.print(" {s:22} {}\n", name, top_level_step.description); - } - - try out_stream.write( - \\ - \\General Options: - \\ --help Print this help and exit - \\ --verbose Print commands before executing them - \\ --prefix [path] Override default install prefix - \\ --search-prefix [path] Add a path to look for binaries, libraries, headers - \\ - \\Project-Specific Options: - \\ - ); - - if (builder.available_options_list.len == 0) { - try out_stream.print(" (none)\n"); - } else { - for (builder.available_options_list.toSliceConst()) |option| { - const name = try fmt.allocPrint(allocator, " -D{}=[{}]", option.name, Builder.typeIdName(option.type_id)); - defer allocator.free(name); - try out_stream.print("{s:24} {}\n", name, option.description); - } - } - - try out_stream.write( - \\ - \\Advanced Options: - \\ --build-file [file] Override path to build.zig - \\ --cache-dir [path] Override path to zig cache directory - \\ --override-std-dir [arg] Override path to Zig standard library - \\ --override-lib-dir [arg] Override path to Zig lib directory - \\ --verbose-tokenize Enable compiler debug output for tokenization - \\ --verbose-ast Enable compiler debug output for parsing into an AST - \\ --verbose-link Enable compiler debug output for linking - \\ --verbose-ir Enable compiler debug output for Zig IR - \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR - \\ --verbose-cimport Enable compiler debug output for C imports - \\ --verbose-cc Enable compiler debug output for C compilation - \\ - ); -} - -fn usageAndErr(builder: *Builder, already_ran_build: bool, out_stream: var) void { - usage(builder, already_ran_build, out_stream) catch {}; - process.exit(1); -} - -const UnwrapArgError = error{OutOfMemory}; - -fn unwrapArg(arg: UnwrapArgError![]u8) UnwrapArgError![]u8 { - return arg catch |err| { - warn("Unable to parse command line: {}\n", err); - return err; - }; -} diff --git a/test/tests.zig b/test/tests.zig @@ -408,7 +408,7 @@ pub fn addPkgTests( if (test_target.link_libc) { these_tests.linkSystemLibrary("c"); } - these_tests.overrideStdDir("std"); + these_tests.overrideZigLibDir("lib"); these_tests.enable_wine = is_wine_enabled; these_tests.enable_qemu = is_qemu_enabled; these_tests.glibc_multi_install_dir = glibc_dir;