zig/src/link.cpp
Andrew Kelley cf4bccf765
improvements targeted at improving async functions
* Reuse bytes of async function frames when non-async functions
   make `noasync` calls. This prevents explosive stack growth.
 * Zig now passes a stack size argument to the linker when linking ELF
   binaries. Linux ignores this value, but it is available as a program
   header called GNU_STACK. I prototyped some code that memory maps
   extra space to the stack using this program header, but there was
   still a problem when accessing stack memory very far down. Stack
   probing is needed or not working or something. I also prototyped
   using `@newStackCall` to call main and that does work around the
   issue but it also brings its own issues. That code is commented out
   for now in std/special/start.zig. I'm on a plane with no Internet,
   but I plan to consult with the musl community for advice when I get a
   chance.
 * Added `noasync` to a bunch of function calls in std.debug. It's very
   messy but it's a workaround that makes stack traces functional with
   evented I/O enabled. Eventually these will be cleaned up as the root
   bugs are found and fixed. Programs built in blocking mode are
   unaffected.
 * Lowered the default stack size of std.io.InStream (for the async
   version) to 1 MiB instead of 4. Until we figure out how to get
   choosing a stack size working (see 2nd bullet point above), 4 MiB
   tends to cause segfaults due to stack size running out, or usage of
   stack memory too far apart, or something like that.
 * Default thread stack size is bumped from 8 MiB to 16 to match the
   size we give for the main thread. It's planned to eventually remove
   this hard coded value and have Zig able to determine this value
   during semantic analysis, with call graph analysis and function
   pointer annotations and extern function annotations.
2019-09-12 01:40:58 -04:00

2633 lines
98 KiB
C++

/*
* Copyright (c) 2015 Andrew Kelley
*
* This file is part of zig, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
#include "os.hpp"
#include "config.h"
#include "codegen.hpp"
#include "analyze.hpp"
#include "compiler.hpp"
#include "install_files.h"
#include "glibc.hpp"
static const char *msvcrt_common_src[] = {
"misc" OS_SEP "onexit_table.c",
"misc" OS_SEP "register_tls_atexit.c",
"stdio" OS_SEP "acrt_iob_func.c",
"misc" OS_SEP "_configthreadlocale.c",
"misc" OS_SEP "_get_current_locale.c",
"misc" OS_SEP "invalid_parameter_handler.c",
"misc" OS_SEP "output_format.c",
"misc" OS_SEP "purecall.c",
"secapi" OS_SEP "_access_s.c",
"secapi" OS_SEP "_cgets_s.c",
"secapi" OS_SEP "_cgetws_s.c",
"secapi" OS_SEP "_chsize_s.c",
"secapi" OS_SEP "_controlfp_s.c",
"secapi" OS_SEP "_cprintf_s.c",
"secapi" OS_SEP "_cprintf_s_l.c",
"secapi" OS_SEP "_ctime32_s.c",
"secapi" OS_SEP "_ctime64_s.c",
"secapi" OS_SEP "_cwprintf_s.c",
"secapi" OS_SEP "_cwprintf_s_l.c",
"secapi" OS_SEP "_gmtime32_s.c",
"secapi" OS_SEP "_gmtime64_s.c",
"secapi" OS_SEP "_localtime32_s.c",
"secapi" OS_SEP "_localtime64_s.c",
"secapi" OS_SEP "_mktemp_s.c",
"secapi" OS_SEP "_sopen_s.c",
"secapi" OS_SEP "_strdate_s.c",
"secapi" OS_SEP "_strtime_s.c",
"secapi" OS_SEP "_umask_s.c",
"secapi" OS_SEP "_vcprintf_s.c",
"secapi" OS_SEP "_vcprintf_s_l.c",
"secapi" OS_SEP "_vcwprintf_s.c",
"secapi" OS_SEP "_vcwprintf_s_l.c",
"secapi" OS_SEP "_vscprintf_p.c",
"secapi" OS_SEP "_vscwprintf_p.c",
"secapi" OS_SEP "_vswprintf_p.c",
"secapi" OS_SEP "_waccess_s.c",
"secapi" OS_SEP "_wasctime_s.c",
"secapi" OS_SEP "_wctime32_s.c",
"secapi" OS_SEP "_wctime64_s.c",
"secapi" OS_SEP "_wstrtime_s.c",
"secapi" OS_SEP "_wmktemp_s.c",
"secapi" OS_SEP "_wstrdate_s.c",
"secapi" OS_SEP "asctime_s.c",
"secapi" OS_SEP "memcpy_s.c",
"secapi" OS_SEP "memmove_s.c",
"secapi" OS_SEP "rand_s.c",
"secapi" OS_SEP "sprintf_s.c",
"secapi" OS_SEP "strerror_s.c",
"secapi" OS_SEP "vsprintf_s.c",
"secapi" OS_SEP "wmemcpy_s.c",
"secapi" OS_SEP "wmemmove_s.c",
"stdio" OS_SEP "mingw_lock.c",
};
static const char *msvcrt_i386_src[] = {
"misc" OS_SEP "lc_locale_func.c",
};
static const char *msvcrt_other_src[] = {
"misc" OS_SEP "__p___argv.c",
"misc" OS_SEP "__p__acmdln.c",
"misc" OS_SEP "__p__fmode.c",
"misc" OS_SEP "__p__wcmdln.c",
};
static const char *mingwex_generic_src[] = {
"complex" OS_SEP "_cabs.c",
"complex" OS_SEP "cabs.c",
"complex" OS_SEP "cabsf.c",
"complex" OS_SEP "cabsl.c",
"complex" OS_SEP "cacos.c",
"complex" OS_SEP "cacosf.c",
"complex" OS_SEP "cacosl.c",
"complex" OS_SEP "carg.c",
"complex" OS_SEP "cargf.c",
"complex" OS_SEP "cargl.c",
"complex" OS_SEP "casin.c",
"complex" OS_SEP "casinf.c",
"complex" OS_SEP "casinl.c",
"complex" OS_SEP "catan.c",
"complex" OS_SEP "catanf.c",
"complex" OS_SEP "catanl.c",
"complex" OS_SEP "ccos.c",
"complex" OS_SEP "ccosf.c",
"complex" OS_SEP "ccosl.c",
"complex" OS_SEP "cexp.c",
"complex" OS_SEP "cexpf.c",
"complex" OS_SEP "cexpl.c",
"complex" OS_SEP "cimag.c",
"complex" OS_SEP "cimagf.c",
"complex" OS_SEP "cimagl.c",
"complex" OS_SEP "clog.c",
"complex" OS_SEP "clog10.c",
"complex" OS_SEP "clog10f.c",
"complex" OS_SEP "clog10l.c",
"complex" OS_SEP "clogf.c",
"complex" OS_SEP "clogl.c",
"complex" OS_SEP "conj.c",
"complex" OS_SEP "conjf.c",
"complex" OS_SEP "conjl.c",
"complex" OS_SEP "cpow.c",
"complex" OS_SEP "cpowf.c",
"complex" OS_SEP "cpowl.c",
"complex" OS_SEP "cproj.c",
"complex" OS_SEP "cprojf.c",
"complex" OS_SEP "cprojl.c",
"complex" OS_SEP "creal.c",
"complex" OS_SEP "crealf.c",
"complex" OS_SEP "creall.c",
"complex" OS_SEP "csin.c",
"complex" OS_SEP "csinf.c",
"complex" OS_SEP "csinl.c",
"complex" OS_SEP "csqrt.c",
"complex" OS_SEP "csqrtf.c",
"complex" OS_SEP "csqrtl.c",
"complex" OS_SEP "ctan.c",
"complex" OS_SEP "ctanf.c",
"complex" OS_SEP "ctanl.c",
"crt" OS_SEP "dllentry.c",
"crt" OS_SEP "dllmain.c",
"gdtoa" OS_SEP "arithchk.c",
"gdtoa" OS_SEP "dmisc.c",
"gdtoa" OS_SEP "dtoa.c",
"gdtoa" OS_SEP "g__fmt.c",
"gdtoa" OS_SEP "g_dfmt.c",
"gdtoa" OS_SEP "g_ffmt.c",
"gdtoa" OS_SEP "g_xfmt.c",
"gdtoa" OS_SEP "gdtoa.c",
"gdtoa" OS_SEP "gethex.c",
"gdtoa" OS_SEP "gmisc.c",
"gdtoa" OS_SEP "hd_init.c",
"gdtoa" OS_SEP "hexnan.c",
"gdtoa" OS_SEP "misc.c",
"gdtoa" OS_SEP "qnan.c",
"gdtoa" OS_SEP "smisc.c",
"gdtoa" OS_SEP "strtodg.c",
"gdtoa" OS_SEP "strtodnrp.c",
"gdtoa" OS_SEP "strtof.c",
"gdtoa" OS_SEP "strtopx.c",
"gdtoa" OS_SEP "sum.c",
"gdtoa" OS_SEP "ulp.c",
"math" OS_SEP "abs64.c",
"math" OS_SEP "cbrt.c",
"math" OS_SEP "cbrtf.c",
"math" OS_SEP "cbrtl.c",
"math" OS_SEP "cephes_emath.c",
"math" OS_SEP "copysign.c",
"math" OS_SEP "copysignf.c",
"math" OS_SEP "coshf.c",
"math" OS_SEP "coshl.c",
"math" OS_SEP "erfl.c",
"math" OS_SEP "expf.c",
"math" OS_SEP "fabs.c",
"math" OS_SEP "fabsf.c",
"math" OS_SEP "fabsl.c",
"math" OS_SEP "fdim.c",
"math" OS_SEP "fdimf.c",
"math" OS_SEP "fdiml.c",
"math" OS_SEP "fma.c",
"math" OS_SEP "fmaf.c",
"math" OS_SEP "fmal.c",
"math" OS_SEP "fmax.c",
"math" OS_SEP "fmaxf.c",
"math" OS_SEP "fmaxl.c",
"math" OS_SEP "fmin.c",
"math" OS_SEP "fminf.c",
"math" OS_SEP "fminl.c",
"math" OS_SEP "fp_consts.c",
"math" OS_SEP "fp_constsf.c",
"math" OS_SEP "fp_constsl.c",
"math" OS_SEP "fpclassify.c",
"math" OS_SEP "fpclassifyf.c",
"math" OS_SEP "fpclassifyl.c",
"math" OS_SEP "frexpf.c",
"math" OS_SEP "hypot.c",
"math" OS_SEP "hypotf.c",
"math" OS_SEP "hypotl.c",
"math" OS_SEP "isnan.c",
"math" OS_SEP "isnanf.c",
"math" OS_SEP "isnanl.c",
"math" OS_SEP "ldexpf.c",
"math" OS_SEP "lgamma.c",
"math" OS_SEP "lgammaf.c",
"math" OS_SEP "lgammal.c",
"math" OS_SEP "llrint.c",
"math" OS_SEP "llrintf.c",
"math" OS_SEP "llrintl.c",
"math" OS_SEP "llround.c",
"math" OS_SEP "llroundf.c",
"math" OS_SEP "llroundl.c",
"math" OS_SEP "log10f.c",
"math" OS_SEP "logf.c",
"math" OS_SEP "lrint.c",
"math" OS_SEP "lrintf.c",
"math" OS_SEP "lrintl.c",
"math" OS_SEP "lround.c",
"math" OS_SEP "lroundf.c",
"math" OS_SEP "lroundl.c",
"math" OS_SEP "modf.c",
"math" OS_SEP "modff.c",
"math" OS_SEP "modfl.c",
"math" OS_SEP "nextafterf.c",
"math" OS_SEP "nextafterl.c",
"math" OS_SEP "nexttoward.c",
"math" OS_SEP "nexttowardf.c",
"math" OS_SEP "powf.c",
"math" OS_SEP "powi.c",
"math" OS_SEP "powif.c",
"math" OS_SEP "powil.c",
"math" OS_SEP "rint.c",
"math" OS_SEP "rintf.c",
"math" OS_SEP "rintl.c",
"math" OS_SEP "round.c",
"math" OS_SEP "roundf.c",
"math" OS_SEP "roundl.c",
"math" OS_SEP "s_erf.c",
"math" OS_SEP "sf_erf.c",
"math" OS_SEP "signbit.c",
"math" OS_SEP "signbitf.c",
"math" OS_SEP "signbitl.c",
"math" OS_SEP "signgam.c",
"math" OS_SEP "sinhf.c",
"math" OS_SEP "sinhl.c",
"math" OS_SEP "sqrt.c",
"math" OS_SEP "sqrtf.c",
"math" OS_SEP "sqrtl.c",
"math" OS_SEP "tanhf.c",
"math" OS_SEP "tanhl.c",
"math" OS_SEP "tgamma.c",
"math" OS_SEP "tgammaf.c",
"math" OS_SEP "tgammal.c",
"math" OS_SEP "truncl.c",
"misc" OS_SEP "alarm.c",
"misc" OS_SEP "assert.c",
"misc" OS_SEP "basename.c",
"misc" OS_SEP "btowc.c",
"misc" OS_SEP "delay-f.c",
"misc" OS_SEP "delay-n.c",
"misc" OS_SEP "delayimp.c",
"misc" OS_SEP "difftime.c",
"misc" OS_SEP "difftime32.c",
"misc" OS_SEP "difftime64.c",
"misc" OS_SEP "dirent.c",
"misc" OS_SEP "dirname.c",
"misc" OS_SEP "execv.c",
"misc" OS_SEP "execve.c",
"misc" OS_SEP "execvp.c",
"misc" OS_SEP "execvpe.c",
"misc" OS_SEP "feclearexcept.c",
"misc" OS_SEP "fegetenv.c",
"misc" OS_SEP "fegetexceptflag.c",
"misc" OS_SEP "fegetround.c",
"misc" OS_SEP "feholdexcept.c",
"misc" OS_SEP "feraiseexcept.c",
"misc" OS_SEP "fesetenv.c",
"misc" OS_SEP "fesetexceptflag.c",
"misc" OS_SEP "fesetround.c",
"misc" OS_SEP "fetestexcept.c",
"misc" OS_SEP "feupdateenv.c",
"misc" OS_SEP "ftruncate.c",
"misc" OS_SEP "ftw.c",
"misc" OS_SEP "ftw64.c",
"misc" OS_SEP "fwide.c",
"misc" OS_SEP "getlogin.c",
"misc" OS_SEP "getopt.c",
"misc" OS_SEP "gettimeofday.c",
"misc" OS_SEP "imaxabs.c",
"misc" OS_SEP "imaxdiv.c",
"misc" OS_SEP "isblank.c",
"misc" OS_SEP "iswblank.c",
"misc" OS_SEP "mbrtowc.c",
"misc" OS_SEP "mbsinit.c",
"misc" OS_SEP "mempcpy.c",
"misc" OS_SEP "mingw-aligned-malloc.c",
"misc" OS_SEP "mingw-fseek.c",
"misc" OS_SEP "mingw_getsp.S",
"misc" OS_SEP "mingw_matherr.c",
"misc" OS_SEP "mingw_mbwc_convert.c",
"misc" OS_SEP "mingw_usleep.c",
"misc" OS_SEP "mingw_wcstod.c",
"misc" OS_SEP "mingw_wcstof.c",
"misc" OS_SEP "mingw_wcstold.c",
"misc" OS_SEP "mkstemp.c",
"misc" OS_SEP "seterrno.c",
"misc" OS_SEP "sleep.c",
"misc" OS_SEP "spawnv.c",
"misc" OS_SEP "spawnve.c",
"misc" OS_SEP "spawnvp.c",
"misc" OS_SEP "spawnvpe.c",
"misc" OS_SEP "strnlen.c",
"misc" OS_SEP "strsafe.c",
"misc" OS_SEP "strtoimax.c",
"misc" OS_SEP "strtold.c",
"misc" OS_SEP "strtoumax.c",
"misc" OS_SEP "tdelete.c",
"misc" OS_SEP "tfind.c",
"misc" OS_SEP "tsearch.c",
"misc" OS_SEP "twalk.c",
"misc" OS_SEP "uchar_c16rtomb.c",
"misc" OS_SEP "uchar_c32rtomb.c",
"misc" OS_SEP "uchar_mbrtoc16.c",
"misc" OS_SEP "uchar_mbrtoc32.c",
"misc" OS_SEP "wassert.c",
"misc" OS_SEP "wcrtomb.c",
"misc" OS_SEP "wcsnlen.c",
"misc" OS_SEP "wcstof.c",
"misc" OS_SEP "wcstoimax.c",
"misc" OS_SEP "wcstold.c",
"misc" OS_SEP "wcstoumax.c",
"misc" OS_SEP "wctob.c",
"misc" OS_SEP "wctrans.c",
"misc" OS_SEP "wctype.c",
"misc" OS_SEP "wdirent.c",
"misc" OS_SEP "winbs_uint64.c",
"misc" OS_SEP "winbs_ulong.c",
"misc" OS_SEP "winbs_ushort.c",
"misc" OS_SEP "wmemchr.c",
"misc" OS_SEP "wmemcmp.c",
"misc" OS_SEP "wmemcpy.c",
"misc" OS_SEP "wmemmove.c",
"misc" OS_SEP "wmempcpy.c",
"misc" OS_SEP "wmemset.c",
"stdio" OS_SEP "_Exit.c",
"stdio" OS_SEP "_findfirst64i32.c",
"stdio" OS_SEP "_findnext64i32.c",
"stdio" OS_SEP "_fstat.c",
"stdio" OS_SEP "_fstat64i32.c",
"stdio" OS_SEP "_ftime.c",
"stdio" OS_SEP "_getc_nolock.c",
"stdio" OS_SEP "_getwc_nolock.c",
"stdio" OS_SEP "_putc_nolock.c",
"stdio" OS_SEP "_putwc_nolock.c",
"stdio" OS_SEP "_stat.c",
"stdio" OS_SEP "_stat64i32.c",
"stdio" OS_SEP "_wfindfirst64i32.c",
"stdio" OS_SEP "_wfindnext64i32.c",
"stdio" OS_SEP "_wstat.c",
"stdio" OS_SEP "_wstat64i32.c",
"stdio" OS_SEP "asprintf.c",
"stdio" OS_SEP "atoll.c",
"stdio" OS_SEP "fgetpos64.c",
"stdio" OS_SEP "fopen64.c",
"stdio" OS_SEP "fseeko32.c",
"stdio" OS_SEP "fseeko64.c",
"stdio" OS_SEP "fsetpos64.c",
"stdio" OS_SEP "ftello.c",
"stdio" OS_SEP "ftello64.c",
"stdio" OS_SEP "ftruncate64.c",
"stdio" OS_SEP "lltoa.c",
"stdio" OS_SEP "lltow.c",
"stdio" OS_SEP "lseek64.c",
"stdio" OS_SEP "mingw_asprintf.c",
"stdio" OS_SEP "mingw_fprintf.c",
"stdio" OS_SEP "mingw_fprintfw.c",
"stdio" OS_SEP "mingw_fscanf.c",
"stdio" OS_SEP "mingw_fwscanf.c",
"stdio" OS_SEP "mingw_pformat.c",
"stdio" OS_SEP "mingw_pformatw.c",
"stdio" OS_SEP "mingw_printf.c",
"stdio" OS_SEP "mingw_printfw.c",
"stdio" OS_SEP "mingw_scanf.c",
"stdio" OS_SEP "mingw_snprintf.c",
"stdio" OS_SEP "mingw_snprintfw.c",
"stdio" OS_SEP "mingw_sprintf.c",
"stdio" OS_SEP "mingw_sprintfw.c",
"stdio" OS_SEP "mingw_sscanf.c",
"stdio" OS_SEP "mingw_swscanf.c",
"stdio" OS_SEP "mingw_vasprintf.c",
"stdio" OS_SEP "mingw_vfprintf.c",
"stdio" OS_SEP "mingw_vfprintfw.c",
"stdio" OS_SEP "mingw_vfscanf.c",
"stdio" OS_SEP "mingw_vprintf.c",
"stdio" OS_SEP "mingw_vprintfw.c",
"stdio" OS_SEP "mingw_vsnprintf.c",
"stdio" OS_SEP "mingw_vsnprintfw.c",
"stdio" OS_SEP "mingw_vsprintf.c",
"stdio" OS_SEP "mingw_vsprintfw.c",
"stdio" OS_SEP "mingw_wscanf.c",
"stdio" OS_SEP "mingw_wvfscanf.c",
"stdio" OS_SEP "scanf.S",
"stdio" OS_SEP "snprintf.c",
"stdio" OS_SEP "snwprintf.c",
"stdio" OS_SEP "strtof.c",
"stdio" OS_SEP "strtok_r.c",
"stdio" OS_SEP "truncate.c",
"stdio" OS_SEP "ulltoa.c",
"stdio" OS_SEP "ulltow.c",
"stdio" OS_SEP "vasprintf.c",
"stdio" OS_SEP "vfscanf.c",
"stdio" OS_SEP "vfscanf2.S",
"stdio" OS_SEP "vfwscanf.c",
"stdio" OS_SEP "vfwscanf2.S",
"stdio" OS_SEP "vscanf.c",
"stdio" OS_SEP "vscanf2.S",
"stdio" OS_SEP "vsnprintf.c",
"stdio" OS_SEP "vsnwprintf.c",
"stdio" OS_SEP "vsscanf.c",
"stdio" OS_SEP "vsscanf2.S",
"stdio" OS_SEP "vswscanf.c",
"stdio" OS_SEP "vswscanf2.S",
"stdio" OS_SEP "vwscanf.c",
"stdio" OS_SEP "vwscanf2.S",
"stdio" OS_SEP "wtoll.c",
};
static const char *mingwex_x86_src[] = {
"math" OS_SEP "x86" OS_SEP "acosf.c",
"math" OS_SEP "x86" OS_SEP "acosh.c",
"math" OS_SEP "x86" OS_SEP "acoshf.c",
"math" OS_SEP "x86" OS_SEP "acoshl.c",
"math" OS_SEP "x86" OS_SEP "acosl.c",
"math" OS_SEP "x86" OS_SEP "asinf.c",
"math" OS_SEP "x86" OS_SEP "asinh.c",
"math" OS_SEP "x86" OS_SEP "asinhf.c",
"math" OS_SEP "x86" OS_SEP "asinhl.c",
"math" OS_SEP "x86" OS_SEP "asinl.c",
"math" OS_SEP "x86" OS_SEP "atan2.c",
"math" OS_SEP "x86" OS_SEP "atan2f.c",
"math" OS_SEP "x86" OS_SEP "atan2l.c",
"math" OS_SEP "x86" OS_SEP "atanf.c",
"math" OS_SEP "x86" OS_SEP "atanh.c",
"math" OS_SEP "x86" OS_SEP "atanhf.c",
"math" OS_SEP "x86" OS_SEP "atanhl.c",
"math" OS_SEP "x86" OS_SEP "atanl.c",
"math" OS_SEP "x86" OS_SEP "ceilf.S",
"math" OS_SEP "x86" OS_SEP "ceill.S",
"math" OS_SEP "x86" OS_SEP "ceil.S",
"math" OS_SEP "x86" OS_SEP "_chgsignl.S",
"math" OS_SEP "x86" OS_SEP "copysignl.S",
"math" OS_SEP "x86" OS_SEP "cos.c",
"math" OS_SEP "x86" OS_SEP "cosf.c",
"math" OS_SEP "x86" OS_SEP "cosl.c",
"math" OS_SEP "x86" OS_SEP "cosl_internal.S",
"math" OS_SEP "x86" OS_SEP "cossin.c",
"math" OS_SEP "x86" OS_SEP "exp2f.S",
"math" OS_SEP "x86" OS_SEP "exp2l.S",
"math" OS_SEP "x86" OS_SEP "exp2.S",
"math" OS_SEP "x86" OS_SEP "exp.c",
"math" OS_SEP "x86" OS_SEP "expl.c",
"math" OS_SEP "x86" OS_SEP "expm1.c",
"math" OS_SEP "x86" OS_SEP "expm1f.c",
"math" OS_SEP "x86" OS_SEP "expm1l.c",
"math" OS_SEP "x86" OS_SEP "floorf.S",
"math" OS_SEP "x86" OS_SEP "floorl.S",
"math" OS_SEP "x86" OS_SEP "floor.S",
"math" OS_SEP "x86" OS_SEP "fmod.c",
"math" OS_SEP "x86" OS_SEP "fmodf.c",
"math" OS_SEP "x86" OS_SEP "fmodl.c",
"math" OS_SEP "x86" OS_SEP "frexpl.S",
"math" OS_SEP "x86" OS_SEP "fucom.c",
"math" OS_SEP "x86" OS_SEP "ilogbf.S",
"math" OS_SEP "x86" OS_SEP "ilogbl.S",
"math" OS_SEP "x86" OS_SEP "ilogb.S",
"math" OS_SEP "x86" OS_SEP "internal_logl.S",
"math" OS_SEP "x86" OS_SEP "ldexp.c",
"math" OS_SEP "x86" OS_SEP "ldexpl.c",
"math" OS_SEP "x86" OS_SEP "log10l.S",
"math" OS_SEP "x86" OS_SEP "log1pf.S",
"math" OS_SEP "x86" OS_SEP "log1pl.S",
"math" OS_SEP "x86" OS_SEP "log1p.S",
"math" OS_SEP "x86" OS_SEP "log2f.S",
"math" OS_SEP "x86" OS_SEP "log2l.S",
"math" OS_SEP "x86" OS_SEP "log2.S",
"math" OS_SEP "x86" OS_SEP "logb.c",
"math" OS_SEP "x86" OS_SEP "logbf.c",
"math" OS_SEP "x86" OS_SEP "logbl.c",
"math" OS_SEP "x86" OS_SEP "log.c",
"math" OS_SEP "x86" OS_SEP "logl.c",
"math" OS_SEP "x86" OS_SEP "nearbyintf.S",
"math" OS_SEP "x86" OS_SEP "nearbyintl.S",
"math" OS_SEP "x86" OS_SEP "nearbyint.S",
"math" OS_SEP "x86" OS_SEP "pow.c",
"math" OS_SEP "x86" OS_SEP "powl.c",
"math" OS_SEP "x86" OS_SEP "remainderf.S",
"math" OS_SEP "x86" OS_SEP "remainderl.S",
"math" OS_SEP "x86" OS_SEP "remainder.S",
"math" OS_SEP "x86" OS_SEP "remquof.S",
"math" OS_SEP "x86" OS_SEP "remquol.S",
"math" OS_SEP "x86" OS_SEP "remquo.S",
"math" OS_SEP "x86" OS_SEP "scalbnf.S",
"math" OS_SEP "x86" OS_SEP "scalbnl.S",
"math" OS_SEP "x86" OS_SEP "scalbn.S",
"math" OS_SEP "x86" OS_SEP "sin.c",
"math" OS_SEP "x86" OS_SEP "sinf.c",
"math" OS_SEP "x86" OS_SEP "sinl.c",
"math" OS_SEP "x86" OS_SEP "sinl_internal.S",
"math" OS_SEP "x86" OS_SEP "tanf.c",
"math" OS_SEP "x86" OS_SEP "tanl.S",
"math" OS_SEP "x86" OS_SEP "truncf.S",
"math" OS_SEP "x86" OS_SEP "trunc.S",
};
static const char *mingwex_arm32_src[] = {
"math" OS_SEP "arm" OS_SEP "_chgsignl.S",
"math" OS_SEP "arm" OS_SEP "ceil.S",
"math" OS_SEP "arm" OS_SEP "ceilf.S",
"math" OS_SEP "arm" OS_SEP "ceill.S",
"math" OS_SEP "arm" OS_SEP "copysignl.c",
"math" OS_SEP "arm" OS_SEP "exp2.c",
"math" OS_SEP "arm" OS_SEP "floor.S",
"math" OS_SEP "arm" OS_SEP "floorf.S",
"math" OS_SEP "arm" OS_SEP "floorl.S",
"math" OS_SEP "arm" OS_SEP "ldexpl.c",
"math" OS_SEP "arm" OS_SEP "log2.c",
"math" OS_SEP "arm" OS_SEP "nearbyint.S",
"math" OS_SEP "arm" OS_SEP "nearbyintf.S",
"math" OS_SEP "arm" OS_SEP "nearbyintl.S",
"math" OS_SEP "arm" OS_SEP "scalbn.c",
"math" OS_SEP "arm" OS_SEP "sincos.c",
"math" OS_SEP "arm" OS_SEP "trunc.S",
"math" OS_SEP "arm" OS_SEP "truncf.S",
};
static const char *mingwex_arm64_src[] = {
"math" OS_SEP "arm64" OS_SEP "ceilf.S",
"math" OS_SEP "arm64" OS_SEP "ceill.S",
"math" OS_SEP "arm64" OS_SEP "ceil.S",
"math" OS_SEP "arm64" OS_SEP "_chgsignl.S",
"math" OS_SEP "arm64" OS_SEP "copysignl.c",
"math" OS_SEP "arm64" OS_SEP "exp2f.S",
"math" OS_SEP "arm64" OS_SEP "exp2.S",
"math" OS_SEP "arm64" OS_SEP "floorf.S",
"math" OS_SEP "arm64" OS_SEP "floorl.S",
"math" OS_SEP "arm64" OS_SEP "floor.S",
"math" OS_SEP "arm64" OS_SEP "ldexpl.c",
"math" OS_SEP "arm64" OS_SEP "log2.c",
"math" OS_SEP "arm64" OS_SEP "nearbyintf.S",
"math" OS_SEP "arm64" OS_SEP "nearbyintl.S",
"math" OS_SEP "arm64" OS_SEP "nearbyint.S",
"math" OS_SEP "arm64" OS_SEP "scalbn.c",
"math" OS_SEP "arm64" OS_SEP "sincos.c",
"math" OS_SEP "arm64" OS_SEP "truncf.S",
"math" OS_SEP "arm64" OS_SEP "trunc.S",
};
struct MinGWDef {
const char *name;
const char *path;
bool always_link;
};
static const MinGWDef mingw_def_list[] = {
{"msvcrt", "lib-common" OS_SEP "msvcrt.def.in", true},
{"setupapi", "libarm32" OS_SEP "setupapi.def", false},
{"setupapi", "libarm64" OS_SEP "setupapi.def", false},
{"setupapi", "lib32" OS_SEP "setupapi.def", false},
{"setupapi", "lib64" OS_SEP "setupapi.def", false},
{"winmm", "lib-common" OS_SEP "winmm.def", false},
{"gdi32", "lib-common" OS_SEP "gdi32.def", false},
{"imm32", "lib-common" OS_SEP "imm32.def", false},
{"version", "lib-common" OS_SEP "version.def", false},
{"advapi32", "lib-common" OS_SEP "advapi32.def.in", true},
{"oleaut32", "lib-common" OS_SEP "oleaut32.def.in", false},
{"ole32", "lib-common" OS_SEP "ole32.def.in", false},
{"shell32", "lib-common" OS_SEP "shell32.def", true},
{"user32", "lib-common" OS_SEP "user32.def.in", true},
{"kernel32", "lib-common" OS_SEP "kernel32.def.in", true},
{"ntdll", "libarm32" OS_SEP "ntdll.def", true},
{"ntdll", "lib32" OS_SEP "ntdll.def", true},
{"ntdll", "lib64" OS_SEP "ntdll.def", true},
};
struct LinkJob {
CodeGen *codegen;
ZigList<const char *> args;
bool link_in_crt;
HashMap<Buf *, bool, buf_hash, buf_eql_buf> rpath_table;
};
static const char *build_libc_object(CodeGen *parent_gen, const char *name, CFile *c_file) {
CodeGen *child_gen = create_child_codegen(parent_gen, nullptr, OutTypeObj, nullptr);
codegen_set_out_name(child_gen, buf_create_from_str(name));
ZigList<CFile *> c_source_files = {0};
c_source_files.append(c_file);
child_gen->c_source_files = c_source_files;
codegen_build_and_link(child_gen);
return buf_ptr(&child_gen->output_file_path);
}
static const char *path_from_zig_lib(CodeGen *g, const char *dir, const char *subpath) {
Buf *dir1 = buf_alloc();
os_path_join(g->zig_lib_dir, buf_create_from_str(dir), dir1);
Buf *result = buf_alloc();
os_path_join(dir1, buf_create_from_str(subpath), result);
return buf_ptr(result);
}
static const char *path_from_libc(CodeGen *g, const char *subpath) {
return path_from_zig_lib(g, "libc", subpath);
}
static const char *path_from_libunwind(CodeGen *g, const char *subpath) {
return path_from_zig_lib(g, "libunwind", subpath);
}
static const char *build_libunwind(CodeGen *parent) {
CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr);
codegen_set_out_name(child_gen, buf_create_from_str("unwind"));
LinkLib *new_link_lib = codegen_add_link_lib(child_gen, buf_create_from_str("c"));
new_link_lib->provided_explicitly = false;
enum SrcKind {
SrcCpp,
SrcC,
SrcAsm,
};
static const struct {
const char *path;
SrcKind kind;
} unwind_src[] = {
{"src" OS_SEP "libunwind.cpp", SrcCpp},
{"src" OS_SEP "Unwind-EHABI.cpp", SrcCpp},
{"src" OS_SEP "Unwind-seh.cpp", SrcCpp},
{"src" OS_SEP "UnwindLevel1.c", SrcC},
{"src" OS_SEP "UnwindLevel1-gcc-ext.c", SrcC},
{"src" OS_SEP "Unwind-sjlj.c", SrcC},
{"src" OS_SEP "UnwindRegistersRestore.S", SrcAsm},
{"src" OS_SEP "UnwindRegistersSave.S", SrcAsm},
};
ZigList<CFile *> c_source_files = {0};
for (size_t i = 0; i < array_length(unwind_src); i += 1) {
CFile *c_file = allocate<CFile>(1);
c_file->source_path = path_from_libunwind(parent, unwind_src[i].path);
switch (unwind_src[i].kind) {
case SrcC:
c_file->args.append("-std=c99");
break;
case SrcCpp:
c_file->args.append("-fno-rtti");
c_file->args.append("-I");
c_file->args.append(path_from_zig_lib(parent, "libcxx", "include"));
break;
case SrcAsm:
break;
}
c_file->args.append("-I");
c_file->args.append(path_from_libunwind(parent, "include"));
c_file->args.append("-fPIC");
c_file->args.append("-D_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS");
c_file->args.append("-Wa,--noexecstack");
if (parent->zig_target->is_native) {
c_file->args.append("-D_LIBUNWIND_IS_NATIVE_ONLY");
}
if (parent->build_mode == BuildModeDebug) {
c_file->args.append("-D_DEBUG");
}
if (parent->is_single_threaded) {
c_file->args.append("-D_LIBUNWIND_HAS_NO_THREADS");
}
c_source_files.append(c_file);
}
child_gen->c_source_files = c_source_files;
codegen_build_and_link(child_gen);
return buf_ptr(&child_gen->output_file_path);
}
static void mingw_add_cc_args(CodeGen *parent, CFile *c_file) {
c_file->args.append("-DHAVE_CONFIG_H");
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "include",
buf_ptr(parent->zig_lib_dir))));
c_file->args.append("-isystem");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "include" OS_SEP "any-windows-any",
buf_ptr(parent->zig_lib_dir))));
if (target_is_arm(parent->zig_target) &&
target_arch_pointer_bit_width(parent->zig_target->arch) == 32)
{
c_file->args.append("-mfpu=vfp");
}
c_file->args.append("-std=gnu11");
c_file->args.append("-D_CRTBLD");
c_file->args.append("-D_WIN32_WINNT=0x0f00");
c_file->args.append("-D__MSVCRT_VERSION__=0x700");
}
static void glibc_add_include_dirs_arch(CFile *c_file, ZigLLVM_ArchType arch, const char *nptl, const char *dir) {
bool is_x86 = arch == ZigLLVM_x86 || arch == ZigLLVM_x86_64;
bool is_aarch64 = arch == ZigLLVM_aarch64 || arch == ZigLLVM_aarch64_be;
bool is_mips = arch == ZigLLVM_mips || arch == ZigLLVM_mipsel ||
arch == ZigLLVM_mips64el || arch == ZigLLVM_mips64;
bool is_arm = arch == ZigLLVM_arm || arch == ZigLLVM_armeb;
bool is_ppc = arch == ZigLLVM_ppc || arch == ZigLLVM_ppc64 || arch == ZigLLVM_ppc64le;
bool is_riscv = arch == ZigLLVM_riscv32 || arch == ZigLLVM_riscv64;
bool is_sparc = arch == ZigLLVM_sparc || arch == ZigLLVM_sparcel || arch == ZigLLVM_sparcv9;
bool is_64 = target_arch_pointer_bit_width(arch) == 64;
if (is_x86) {
if (arch == ZigLLVM_x86_64) {
if (nptl != nullptr) {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "x86_64" OS_SEP "%s", dir, nptl)));
} else {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "x86_64", dir)));
}
} else if (arch == ZigLLVM_x86) {
if (nptl != nullptr) {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "i386" OS_SEP "%s", dir, nptl)));
} else {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "i386", dir)));
}
}
if (nptl != nullptr) {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "x86" OS_SEP "%s", dir, nptl)));
} else {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "x86", dir)));
}
} else if (is_arm) {
if (nptl != nullptr) {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "arm" OS_SEP "%s", dir, nptl)));
} else {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "arm", dir)));
}
} else if (is_mips) {
if (nptl != nullptr) {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "mips" OS_SEP "%s", dir, nptl)));
} else {
if (is_64) {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "mips" OS_SEP "mips64", dir)));
} else {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "mips" OS_SEP "mips32", dir)));
}
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "mips", dir)));
}
} else if (is_sparc) {
if (nptl != nullptr) {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "sparc" OS_SEP "%s", dir, nptl)));
} else {
if (is_64) {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "sparc" OS_SEP "sparc64", dir)));
} else {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "sparc" OS_SEP "sparc32", dir)));
}
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "sparc", dir)));
}
} else if (is_aarch64) {
if (nptl != nullptr) {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "aarch64" OS_SEP "%s", dir, nptl)));
} else {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "aarch64", dir)));
}
} else if (is_ppc) {
if (nptl != nullptr) {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "powerpc" OS_SEP "%s", dir, nptl)));
} else {
if (is_64) {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "powerpc" OS_SEP "powerpc64", dir)));
} else {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "powerpc" OS_SEP "powerpc32", dir)));
}
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "powerpc", dir)));
}
} else if (is_riscv) {
if (nptl != nullptr) {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "riscv" OS_SEP "%s", dir, nptl)));
} else {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "riscv", dir)));
}
}
}
static void glibc_add_include_dirs(CodeGen *parent, CFile *c_file) {
ZigLLVM_ArchType arch = parent->zig_target->arch;
const char *nptl = (parent->zig_target->os == OsLinux) ? "nptl" : "htl";
const char *glibc = path_from_libc(parent, "glibc");
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "include", glibc)));
if (parent->zig_target->os == OsLinux) {
glibc_add_include_dirs_arch(c_file, arch, nullptr,
path_from_libc(parent, "glibc" OS_SEP "sysdeps" OS_SEP "unix" OS_SEP "sysv" OS_SEP "linux"));
}
if (nptl != nullptr) {
glibc_add_include_dirs_arch(c_file, arch, nptl, path_from_libc(parent, "glibc" OS_SEP "sysdeps"));
}
if (parent->zig_target->os == OsLinux) {
c_file->args.append("-I");
c_file->args.append(path_from_libc(parent, "glibc" OS_SEP "sysdeps" OS_SEP
"unix" OS_SEP "sysv" OS_SEP "linux" OS_SEP "include"));
c_file->args.append("-I");
c_file->args.append(path_from_libc(parent, "glibc" OS_SEP "sysdeps" OS_SEP
"unix" OS_SEP "sysv" OS_SEP "linux"));
}
if (nptl != nullptr) {
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "sysdeps" OS_SEP "%s", glibc, nptl)));
}
c_file->args.append("-I");
c_file->args.append(path_from_libc(parent, "glibc" OS_SEP "sysdeps" OS_SEP "pthread"));
c_file->args.append("-I");
c_file->args.append(path_from_libc(parent, "glibc" OS_SEP "sysdeps" OS_SEP "unix" OS_SEP "sysv"));
glibc_add_include_dirs_arch(c_file, arch, nullptr,
path_from_libc(parent, "glibc" OS_SEP "sysdeps" OS_SEP "unix"));
c_file->args.append("-I");
c_file->args.append(path_from_libc(parent, "glibc" OS_SEP "sysdeps" OS_SEP "unix"));
glibc_add_include_dirs_arch(c_file, arch, nullptr, path_from_libc(parent, "glibc" OS_SEP "sysdeps"));
c_file->args.append("-I");
c_file->args.append(path_from_libc(parent, "glibc" OS_SEP "sysdeps" OS_SEP "generic"));
c_file->args.append("-I");
c_file->args.append(path_from_libc(parent, "glibc"));
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "include" OS_SEP "%s-%s-%s",
buf_ptr(parent->zig_lib_dir), target_arch_name(parent->zig_target->arch),
target_os_name(parent->zig_target->os), target_abi_name(parent->zig_target->abi))));
c_file->args.append("-I");
c_file->args.append(path_from_libc(parent, "include" OS_SEP "generic-glibc"));
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "include" OS_SEP "%s-linux-any",
buf_ptr(parent->zig_lib_dir), target_arch_name(parent->zig_target->arch))));
c_file->args.append("-I");
c_file->args.append(path_from_libc(parent, "include" OS_SEP "any-linux-any"));
}
static const char *glibc_start_asm_path(CodeGen *parent, const char *file) {
ZigLLVM_ArchType arch = parent->zig_target->arch;
bool is_aarch64 = arch == ZigLLVM_aarch64 || arch == ZigLLVM_aarch64_be;
bool is_mips = arch == ZigLLVM_mips || arch == ZigLLVM_mipsel ||
arch == ZigLLVM_mips64el || arch == ZigLLVM_mips64;
bool is_arm = arch == ZigLLVM_arm || arch == ZigLLVM_armeb;
bool is_ppc = arch == ZigLLVM_ppc || arch == ZigLLVM_ppc64 || arch == ZigLLVM_ppc64le;
bool is_riscv = arch == ZigLLVM_riscv32 || arch == ZigLLVM_riscv64;
bool is_sparc = arch == ZigLLVM_sparc || arch == ZigLLVM_sparcel || arch == ZigLLVM_sparcv9;
bool is_64 = target_arch_pointer_bit_width(arch) == 64;
Buf result = BUF_INIT;
buf_resize(&result, 0);
buf_append_buf(&result, parent->zig_lib_dir);
buf_append_str(&result, OS_SEP "libc" OS_SEP "glibc" OS_SEP "sysdeps" OS_SEP);
if (is_sparc) {
if (is_64) {
buf_append_str(&result, "sparc" OS_SEP "sparc64");
} else {
buf_append_str(&result, "sparc" OS_SEP "sparc32");
}
} else if (is_arm) {
buf_append_str(&result, "arm");
} else if (is_mips) {
buf_append_str(&result, "mips");
} else if (arch == ZigLLVM_x86_64) {
buf_append_str(&result, "x86_64");
} else if (arch == ZigLLVM_x86) {
buf_append_str(&result, "i386");
} else if (is_aarch64) {
buf_append_str(&result, "aarch64");
} else if (is_riscv) {
buf_append_str(&result, "riscv");
} else if (is_ppc) {
if (is_64) {
buf_append_str(&result, "powerpc" OS_SEP "powerpc64");
} else {
buf_append_str(&result, "powerpc" OS_SEP "powerpc32");
}
}
buf_append_str(&result, OS_SEP);
buf_append_str(&result, file);
return buf_ptr(&result);
}
static const char *musl_start_asm_path(CodeGen *parent, const char *file) {
Buf *result = buf_sprintf("%s" OS_SEP "libc" OS_SEP "musl" OS_SEP "crt" OS_SEP "%s" OS_SEP "%s",
buf_ptr(parent->zig_lib_dir), target_arch_musl_name(parent->zig_target->arch), file);
return buf_ptr(result);
}
static void musl_add_cc_args(CodeGen *parent, CFile *c_file, bool want_O3) {
c_file->args.append("-std=c99");
c_file->args.append("-ffreestanding");
// Musl adds these args to builds with gcc but clang does not support them.
//c_file->args.append("-fexcess-precision=standard");
//c_file->args.append("-frounding-math");
c_file->args.append("-Wa,--noexecstack");
c_file->args.append("-D_XOPEN_SOURCE=700");
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "musl" OS_SEP "arch" OS_SEP "%s",
buf_ptr(parent->zig_lib_dir), target_arch_musl_name(parent->zig_target->arch))));
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "musl" OS_SEP "arch" OS_SEP "generic",
buf_ptr(parent->zig_lib_dir))));
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "musl" OS_SEP "src" OS_SEP "include",
buf_ptr(parent->zig_lib_dir))));
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "musl" OS_SEP "src" OS_SEP "internal",
buf_ptr(parent->zig_lib_dir))));
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "musl" OS_SEP "include",
buf_ptr(parent->zig_lib_dir))));
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf(
"%s" OS_SEP "libc" OS_SEP "include" OS_SEP "%s-%s-%s",
buf_ptr(parent->zig_lib_dir),
target_arch_name(parent->zig_target->arch),
target_os_name(parent->zig_target->os),
target_abi_name(parent->zig_target->abi))));
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "include" OS_SEP "generic-musl",
buf_ptr(parent->zig_lib_dir))));
if (want_O3)
c_file->args.append("-O3");
else
c_file->args.append("-Os");
c_file->args.append("-fomit-frame-pointer");
c_file->args.append("-fno-unwind-tables");
c_file->args.append("-fno-asynchronous-unwind-tables");
c_file->args.append("-ffunction-sections");
c_file->args.append("-fdata-sections");
}
static const char *musl_arch_names[] = {
"aarch64",
"arm",
"generic",
"i386",
"m68k",
"microblaze",
"mips",
"mips64",
"mipsn32",
"or1k",
"powerpc",
"powerpc64",
"riscv64",
"s390x",
"sh",
"x32",
"x86_64",
};
static bool is_musl_arch_name(const char *name) {
for (size_t i = 0; i < array_length(musl_arch_names); i += 1) {
if (strcmp(name, musl_arch_names[i]) == 0)
return true;
}
return false;
}
static const char *build_musl(CodeGen *parent) {
CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr);
codegen_set_out_name(child_gen, buf_create_from_str("c"));
// When there is a src/<arch>/foo.* then it should substitute for src/foo.*
// Even a .s file can substitute for a .c file.
enum MuslSrc {
MuslSrcAsm,
MuslSrcNormal,
MuslSrcO3,
};
const char *target_musl_arch_name = target_arch_musl_name(parent->zig_target->arch);
HashMap<Buf *, MuslSrc, buf_hash, buf_eql_buf> source_table = {};
source_table.init(1800);
for (size_t i = 0; i < array_length(ZIG_MUSL_SRC_FILES); i += 1) {
Buf *src_file = buf_create_from_str(ZIG_MUSL_SRC_FILES[i]);
MuslSrc src_kind;
if (buf_ends_with_str(src_file, ".c")) {
assert(buf_starts_with_str(src_file, "musl/src/"));
bool want_O3 = buf_starts_with_str(src_file, "musl/src/malloc/") ||
buf_starts_with_str(src_file, "musl/src/string/") ||
buf_starts_with_str(src_file, "musl/src/internal/");
src_kind = want_O3 ? MuslSrcO3 : MuslSrcNormal;
} else if (buf_ends_with_str(src_file, ".s") || buf_ends_with_str(src_file, ".S")) {
src_kind = MuslSrcAsm;
} else {
continue;
}
if (ZIG_OS_SEP_CHAR != '/') {
buf_replace(src_file, '/', ZIG_OS_SEP_CHAR);
}
source_table.put_unique(src_file, src_kind);
}
ZigList<CFile *> c_source_files = {0};
Buf dirname = BUF_INIT;
Buf basename = BUF_INIT;
Buf noextbasename = BUF_INIT;
Buf dirbasename = BUF_INIT;
Buf before_arch_dir = BUF_INIT;
auto source_it = source_table.entry_iterator();
for (;;) {
auto *entry = source_it.next();
if (!entry) break;
Buf *src_file = entry->key;
MuslSrc src_kind = entry->value;
os_path_split(src_file, &dirname, &basename);
os_path_extname(&basename, &noextbasename, nullptr);
os_path_split(&dirname, &before_arch_dir, &dirbasename);
bool is_arch_specific = false;
// Architecture-specific implementations are under a <arch>/ folder.
if (is_musl_arch_name(buf_ptr(&dirbasename))) {
// Not the architecture we're compiling for.
if (strcmp(buf_ptr(&dirbasename), target_musl_arch_name) != 0)
continue;
is_arch_specific = true;
}
if (!is_arch_specific) {
Buf override_path = BUF_INIT;
// Look for an arch specific override.
buf_resize(&override_path, 0);
buf_appendf(&override_path, "%s" OS_SEP "%s" OS_SEP "%s.s",
buf_ptr(&dirname), target_musl_arch_name, buf_ptr(&noextbasename));
if (source_table.maybe_get(&override_path) != nullptr)
continue;
buf_resize(&override_path, 0);
buf_appendf(&override_path, "%s" OS_SEP "%s" OS_SEP "%s.S",
buf_ptr(&dirname), target_musl_arch_name, buf_ptr(&noextbasename));
if (source_table.maybe_get(&override_path) != nullptr)
continue;
buf_resize(&override_path, 0);
buf_appendf(&override_path, "%s" OS_SEP "%s" OS_SEP "%s.c",
buf_ptr(&dirname), target_musl_arch_name, buf_ptr(&noextbasename));
if (source_table.maybe_get(&override_path) != nullptr)
continue;
}
Buf *full_path = buf_sprintf("%s" OS_SEP "libc" OS_SEP "%s",
buf_ptr(parent->zig_lib_dir), buf_ptr(src_file));
CFile *c_file = allocate<CFile>(1);
c_file->source_path = buf_ptr(full_path);
musl_add_cc_args(parent, c_file, src_kind == MuslSrcO3);
c_file->args.append("-Qunused-arguments");
c_file->args.append("-w"); // disable all warnings
c_source_files.append(c_file);
}
child_gen->c_source_files = c_source_files;
codegen_build_and_link(child_gen);
return buf_ptr(&child_gen->output_file_path);
}
static void add_msvcrt_os_dep(CodeGen *parent, CodeGen *child_gen, const char *src_path) {
CFile *c_file = allocate<CFile>(1);
c_file->source_path = buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "%s",
buf_ptr(parent->zig_lib_dir), src_path));
c_file->args.append("-DHAVE_CONFIG_H");
c_file->args.append("-D__LIBMSVCRT__");
c_file->args.append("-I");
c_file->args.append(path_from_libc(parent, "mingw" OS_SEP "include"));
c_file->args.append("-std=gnu99");
c_file->args.append("-D_CRTBLD");
c_file->args.append("-D_WIN32_WINNT=0x0f00");
c_file->args.append("-D__MSVCRT_VERSION__=0x700");
c_file->args.append("-isystem");
c_file->args.append(path_from_libc(parent, "include" OS_SEP "any-windows-any"));
c_file->args.append("-g");
c_file->args.append("-O2");
child_gen->c_source_files.append(c_file);
}
static void add_mingwex_os_dep(CodeGen *parent, CodeGen *child_gen, const char *src_path) {
CFile *c_file = allocate<CFile>(1);
c_file->source_path = buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "%s",
buf_ptr(parent->zig_lib_dir), src_path));
c_file->args.append("-DHAVE_CONFIG_H");
c_file->args.append("-I");
c_file->args.append(path_from_libc(parent, "mingw"));
c_file->args.append("-I");
c_file->args.append(path_from_libc(parent, "mingw" OS_SEP "include"));
c_file->args.append("-std=gnu99");
c_file->args.append("-D_CRTBLD");
c_file->args.append("-D_WIN32_WINNT=0x0f00");
c_file->args.append("-D__MSVCRT_VERSION__=0x700");
c_file->args.append("-g");
c_file->args.append("-O2");
c_file->args.append("-isystem");
c_file->args.append(path_from_libc(parent, "include" OS_SEP "any-windows-any"));
child_gen->c_source_files.append(c_file);
}
static const char *get_libc_crt_file(CodeGen *parent, const char *file) {
if (parent->libc == nullptr && parent->zig_target->os == OsWindows) {
if (strcmp(file, "crt2.o") == 0) {
CFile *c_file = allocate<CFile>(1);
c_file->source_path = buf_ptr(buf_sprintf(
"%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "crt" OS_SEP "crtexe.c", buf_ptr(parent->zig_lib_dir)));
mingw_add_cc_args(parent, c_file);
c_file->args.append("-U__CRTDLL__");
c_file->args.append("-D__MSVCRT__");
// Uncomment these 3 things for crtu
//c_file->args.append("-DUNICODE");
//c_file->args.append("-D_UNICODE");
//c_file->args.append("-DWPRFLAG=1");
return build_libc_object(parent, "crt2", c_file);
} else if (strcmp(file, "dllcrt2.o") == 0) {
CFile *c_file = allocate<CFile>(1);
c_file->source_path = buf_ptr(buf_sprintf(
"%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "crt" OS_SEP "crtdll.c", buf_ptr(parent->zig_lib_dir)));
mingw_add_cc_args(parent, c_file);
c_file->args.append("-U__CRTDLL__");
c_file->args.append("-D__MSVCRT__");
return build_libc_object(parent, "dllcrt2", c_file);
} else if (strcmp(file, "mingw32.lib") == 0) {
CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr);
codegen_set_out_name(child_gen, buf_create_from_str("mingw32"));
static const char *deps[] = {
"mingw" OS_SEP "crt" OS_SEP "crt0_c.c",
"mingw" OS_SEP "crt" OS_SEP "dll_argv.c",
"mingw" OS_SEP "crt" OS_SEP "gccmain.c",
"mingw" OS_SEP "crt" OS_SEP "natstart.c",
"mingw" OS_SEP "crt" OS_SEP "pseudo-reloc-list.c",
"mingw" OS_SEP "crt" OS_SEP "wildcard.c",
"mingw" OS_SEP "crt" OS_SEP "charmax.c",
"mingw" OS_SEP "crt" OS_SEP "crt0_w.c",
"mingw" OS_SEP "crt" OS_SEP "dllargv.c",
"mingw" OS_SEP "crt" OS_SEP "gs_support.c",
"mingw" OS_SEP "crt" OS_SEP "_newmode.c",
"mingw" OS_SEP "crt" OS_SEP "tlssup.c",
"mingw" OS_SEP "crt" OS_SEP "xncommod.c",
"mingw" OS_SEP "crt" OS_SEP "cinitexe.c",
"mingw" OS_SEP "crt" OS_SEP "merr.c",
"mingw" OS_SEP "crt" OS_SEP "pesect.c",
"mingw" OS_SEP "crt" OS_SEP "udllargc.c",
"mingw" OS_SEP "crt" OS_SEP "xthdloc.c",
"mingw" OS_SEP "crt" OS_SEP "CRT_fp10.c",
"mingw" OS_SEP "crt" OS_SEP "mingw_helpers.c",
"mingw" OS_SEP "crt" OS_SEP "pseudo-reloc.c",
"mingw" OS_SEP "crt" OS_SEP "udll_argv.c",
"mingw" OS_SEP "crt" OS_SEP "xtxtmode.c",
"mingw" OS_SEP "crt" OS_SEP "crt_handler.c",
"mingw" OS_SEP "crt" OS_SEP "tlsthrd.c",
"mingw" OS_SEP "crt" OS_SEP "tlsmthread.c",
"mingw" OS_SEP "crt" OS_SEP "tlsmcrt.c",
"mingw" OS_SEP "crt" OS_SEP "cxa_atexit.c",
};
for (size_t i = 0; i < array_length(deps); i += 1) {
CFile *c_file = allocate<CFile>(1);
c_file->source_path = path_from_libc(parent, deps[i]);
c_file->args.append("-DHAVE_CONFIG_H");
c_file->args.append("-D_SYSCRT=1");
c_file->args.append("-DCRTDLL=1");
c_file->args.append("-isystem");
c_file->args.append(path_from_libc(parent, "include" OS_SEP "any-windows-any"));
c_file->args.append("-isystem");
c_file->args.append(path_from_libc(parent, "mingw" OS_SEP "include"));
c_file->args.append("-std=gnu99");
c_file->args.append("-D_CRTBLD");
c_file->args.append("-D_WIN32_WINNT=0x0f00");
c_file->args.append("-D__MSVCRT_VERSION__=0x700");
c_file->args.append("-g");
c_file->args.append("-O2");
child_gen->c_source_files.append(c_file);
}
codegen_build_and_link(child_gen);
return buf_ptr(&child_gen->output_file_path);
} else if (strcmp(file, "msvcrt-os.lib") == 0) {
CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr);
codegen_set_out_name(child_gen, buf_create_from_str("msvcrt-os"));
for (size_t i = 0; i < array_length(msvcrt_common_src); i += 1) {
add_msvcrt_os_dep(parent, child_gen, msvcrt_common_src[i]);
}
if (parent->zig_target->arch == ZigLLVM_x86) {
for (size_t i = 0; i < array_length(msvcrt_i386_src); i += 1) {
add_msvcrt_os_dep(parent, child_gen, msvcrt_i386_src[i]);
}
} else {
for (size_t i = 0; i < array_length(msvcrt_other_src); i += 1) {
add_msvcrt_os_dep(parent, child_gen, msvcrt_other_src[i]);
}
}
codegen_build_and_link(child_gen);
return buf_ptr(&child_gen->output_file_path);
} else if (strcmp(file, "mingwex.lib") == 0) {
CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr);
codegen_set_out_name(child_gen, buf_create_from_str("mingwex"));
for (size_t i = 0; i < array_length(mingwex_generic_src); i += 1) {
add_mingwex_os_dep(parent, child_gen, mingwex_generic_src[i]);
}
if (parent->zig_target->arch == ZigLLVM_x86 || parent->zig_target->arch == ZigLLVM_x86_64) {
for (size_t i = 0; i < array_length(mingwex_x86_src); i += 1) {
add_mingwex_os_dep(parent, child_gen, mingwex_x86_src[i]);
}
} else if (target_is_arm(parent->zig_target)) {
if (target_arch_pointer_bit_width(parent->zig_target->arch) == 32) {
for (size_t i = 0; i < array_length(mingwex_arm32_src); i += 1) {
add_mingwex_os_dep(parent, child_gen, mingwex_arm32_src[i]);
}
} else {
for (size_t i = 0; i < array_length(mingwex_arm64_src); i += 1) {
add_mingwex_os_dep(parent, child_gen, mingwex_arm64_src[i]);
}
}
} else {
zig_unreachable();
}
codegen_build_and_link(child_gen);
return buf_ptr(&child_gen->output_file_path);
} else {
zig_unreachable();
}
} else if (parent->libc == nullptr && target_is_glibc(parent->zig_target)) {
if (strcmp(file, "crti.o") == 0) {
CFile *c_file = allocate<CFile>(1);
c_file->source_path = glibc_start_asm_path(parent, "crti.S");
glibc_add_include_dirs(parent, c_file);
c_file->args.append("-D_LIBC_REENTRANT");
c_file->args.append("-include");
c_file->args.append(path_from_libc(parent, "glibc" OS_SEP "include" OS_SEP "libc-modules.h"));
c_file->args.append("-DMODULE_NAME=libc");
c_file->args.append("-include");
c_file->args.append(path_from_libc(parent, "glibc" OS_SEP "include" OS_SEP "libc-symbols.h"));
c_file->args.append("-DTOP_NAMESPACE=glibc");
c_file->args.append("-DASSEMBLER");
c_file->args.append("-g");
c_file->args.append("-Wa,--noexecstack");
return build_libc_object(parent, "crti", c_file);
} else if (strcmp(file, "crtn.o") == 0) {
CFile *c_file = allocate<CFile>(1);
c_file->source_path = glibc_start_asm_path(parent, "crtn.S");
glibc_add_include_dirs(parent, c_file);
c_file->args.append("-D_LIBC_REENTRANT");
c_file->args.append("-DMODULE_NAME=libc");
c_file->args.append("-DTOP_NAMESPACE=glibc");
c_file->args.append("-DASSEMBLER");
c_file->args.append("-g");
c_file->args.append("-Wa,--noexecstack");
return build_libc_object(parent, "crtn", c_file);
} else if (strcmp(file, "start.os") == 0) {
CFile *c_file = allocate<CFile>(1);
c_file->source_path = glibc_start_asm_path(parent, "start.S");
glibc_add_include_dirs(parent, c_file);
c_file->args.append("-D_LIBC_REENTRANT");
c_file->args.append("-include");
c_file->args.append(path_from_libc(parent, "glibc" OS_SEP "include" OS_SEP "libc-modules.h"));
c_file->args.append("-DMODULE_NAME=libc");
c_file->args.append("-include");
c_file->args.append(path_from_libc(parent, "glibc" OS_SEP "include" OS_SEP "libc-symbols.h"));
c_file->args.append("-DPIC");
c_file->args.append("-DSHARED");
c_file->args.append("-DTOP_NAMESPACE=glibc");
c_file->args.append("-DASSEMBLER");
c_file->args.append("-g");
c_file->args.append("-Wa,--noexecstack");
return build_libc_object(parent, "start", c_file);
} else if (strcmp(file, "abi-note.o") == 0) {
CFile *c_file = allocate<CFile>(1);
c_file->source_path = path_from_libc(parent, "glibc" OS_SEP "csu" OS_SEP "abi-note.S");
c_file->args.append("-I");
c_file->args.append(path_from_libc(parent, "glibc" OS_SEP "csu"));
glibc_add_include_dirs(parent, c_file);
c_file->args.append("-D_LIBC_REENTRANT");
c_file->args.append("-DMODULE_NAME=libc");
c_file->args.append("-DTOP_NAMESPACE=glibc");
c_file->args.append("-DASSEMBLER");
c_file->args.append("-g");
c_file->args.append("-Wa,--noexecstack");
return build_libc_object(parent, "abi-note", c_file);
} else if (strcmp(file, "Scrt1.o") == 0) {
const char *start_os = get_libc_crt_file(parent, "start.os");
const char *abi_note_o = get_libc_crt_file(parent, "abi-note.o");
CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeObj, nullptr);
codegen_set_out_name(child_gen, buf_create_from_str("Scrt1"));
codegen_add_object(child_gen, buf_create_from_str(start_os));
codegen_add_object(child_gen, buf_create_from_str(abi_note_o));
codegen_build_and_link(child_gen);
return buf_ptr(&child_gen->output_file_path);
} else if (strcmp(file, "libc_nonshared.a") == 0) {
CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr);
codegen_set_out_name(child_gen, buf_create_from_str("c_nonshared"));
{
CFile *c_file = allocate<CFile>(1);
c_file->source_path = path_from_libc(parent, "glibc" OS_SEP "csu" OS_SEP "elf-init.c");
c_file->args.append("-std=gnu11");
c_file->args.append("-fgnu89-inline");
c_file->args.append("-g");
c_file->args.append("-O2");
c_file->args.append("-fmerge-all-constants");
c_file->args.append("-fno-stack-protector");
c_file->args.append("-fmath-errno");
c_file->args.append("-fno-stack-protector");
c_file->args.append("-I");
c_file->args.append(path_from_libc(parent, "glibc" OS_SEP "csu"));
glibc_add_include_dirs(parent, c_file);
c_file->args.append("-DSTACK_PROTECTOR_LEVEL=0");
c_file->args.append("-fPIC");
c_file->args.append("-fno-stack-protector");
c_file->args.append("-ftls-model=initial-exec");
c_file->args.append("-D_LIBC_REENTRANT");
c_file->args.append("-include");
c_file->args.append(path_from_libc(parent, "glibc" OS_SEP "include" OS_SEP "libc-modules.h"));
c_file->args.append("-DMODULE_NAME=libc");
c_file->args.append("-include");
c_file->args.append(path_from_libc(parent, "glibc" OS_SEP "include" OS_SEP "libc-symbols.h"));
c_file->args.append("-DPIC");
c_file->args.append("-DLIBC_NONSHARED=1");
c_file->args.append("-DTOP_NAMESPACE=glibc");
codegen_add_object(child_gen, buf_create_from_str(build_libc_object(parent, "elf-init", c_file)));
}
static const struct {
const char *name;
const char *path;
} deps[] = {
{"atexit", "glibc" OS_SEP "stdlib" OS_SEP "atexit.c"},
{"at_quick_exit", "glibc" OS_SEP "stdlib" OS_SEP "at_quick_exit.c"},
{"stat", "glibc" OS_SEP "io" OS_SEP "stat.c"},
{"fstat", "glibc" OS_SEP "io" OS_SEP "fstat.c"},
{"lstat", "glibc" OS_SEP "io" OS_SEP "lstat.c"},
{"stat64", "glibc" OS_SEP "io" OS_SEP "stat64.c"},
{"fstat64", "glibc" OS_SEP "io" OS_SEP "fstat64.c"},
{"lstat64", "glibc" OS_SEP "io" OS_SEP "lstat64.c"},
{"fstatat", "glibc" OS_SEP "io" OS_SEP "fstatat.c"},
{"fstatat64", "glibc" OS_SEP "io" OS_SEP "fstatat64.c"},
{"mknod", "glibc" OS_SEP "io" OS_SEP "mknod.c"},
{"mknodat", "glibc" OS_SEP "io" OS_SEP "mknodat.c"},
{"pthread_atfork", "glibc" OS_SEP "nptl" OS_SEP "pthread_atfork.c"},
{"stack_chk_fail_local", "glibc" OS_SEP "debug" OS_SEP "stack_chk_fail_local.c"},
};
for (size_t i = 0; i < array_length(deps); i += 1) {
CFile *c_file = allocate<CFile>(1);
c_file->source_path = path_from_libc(parent, deps[i].path);
c_file->args.append("-std=gnu11");
c_file->args.append("-fgnu89-inline");
c_file->args.append("-g");
c_file->args.append("-O2");
c_file->args.append("-fmerge-all-constants");
c_file->args.append("-fno-stack-protector");
c_file->args.append("-fmath-errno");
c_file->args.append("-ftls-model=initial-exec");
c_file->args.append("-Wno-ignored-attributes");
glibc_add_include_dirs(parent, c_file);
c_file->args.append("-D_LIBC_REENTRANT");
c_file->args.append("-include");
c_file->args.append(path_from_libc(parent, "glibc" OS_SEP "include" OS_SEP "libc-modules.h"));
c_file->args.append("-DMODULE_NAME=libc");
c_file->args.append("-include");
c_file->args.append(path_from_libc(parent, "glibc" OS_SEP "include" OS_SEP "libc-symbols.h"));
c_file->args.append("-DPIC");
c_file->args.append("-DLIBC_NONSHARED=1");
c_file->args.append("-DTOP_NAMESPACE=glibc");
codegen_add_object(child_gen, buf_create_from_str(build_libc_object(parent, deps[i].name, c_file)));
}
codegen_build_and_link(child_gen);
return buf_ptr(&child_gen->output_file_path);
} else {
zig_unreachable();
}
} else if (parent->libc == nullptr && target_is_musl(parent->zig_target)) {
if (strcmp(file, "crti.o") == 0) {
CFile *c_file = allocate<CFile>(1);
c_file->source_path = musl_start_asm_path(parent, "crti.s");
musl_add_cc_args(parent, c_file, false);
c_file->args.append("-Qunused-arguments");
return build_libc_object(parent, "crti", c_file);
} else if (strcmp(file, "crtn.o") == 0) {
CFile *c_file = allocate<CFile>(1);
c_file->source_path = musl_start_asm_path(parent, "crtn.s");
c_file->args.append("-Qunused-arguments");
musl_add_cc_args(parent, c_file, false);
return build_libc_object(parent, "crtn", c_file);
} else if (strcmp(file, "crt1.o") == 0) {
CFile *c_file = allocate<CFile>(1);
c_file->source_path = path_from_libc(parent, "musl" OS_SEP "crt" OS_SEP "crt1.c");
musl_add_cc_args(parent, c_file, false);
c_file->args.append("-fno-stack-protector");
c_file->args.append("-DCRT");
return build_libc_object(parent, "crt1", c_file);
} else if (strcmp(file, "Scrt1.o") == 0) {
CFile *c_file = allocate<CFile>(1);
c_file->source_path = path_from_libc(parent, "musl" OS_SEP "crt" OS_SEP "Scrt1.c");
musl_add_cc_args(parent, c_file, false);
c_file->args.append("-fPIC");
c_file->args.append("-fno-stack-protector");
c_file->args.append("-DCRT");
return build_libc_object(parent, "Scrt1", c_file);
} else {
zig_unreachable();
}
} else {
assert(parent->libc != nullptr);
Buf *out_buf = buf_alloc();
os_path_join(&parent->libc->crt_dir, buf_create_from_str(file), out_buf);
return buf_ptr(out_buf);
}
}
static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path, OutType child_out_type) {
CodeGen *child_gen = create_child_codegen(parent_gen, full_path, child_out_type,
parent_gen->libc);
codegen_set_out_name(child_gen, buf_create_from_str(aname));
// This is so that compiler_rt and libc.zig libraries know whether they
// will eventually be linked with libc. They make different decisions
// about what to export depending on whether libc is linked.
if (parent_gen->libc_link_lib != nullptr) {
LinkLib *new_link_lib = codegen_add_link_lib(child_gen, parent_gen->libc_link_lib->name);
new_link_lib->provided_explicitly = parent_gen->libc_link_lib->provided_explicitly;
}
child_gen->function_sections = true;
child_gen->want_stack_check = WantStackCheckDisabled;
codegen_build_and_link(child_gen);
return &child_gen->output_file_path;
}
static Buf *build_compiler_rt(CodeGen *parent_gen, OutType child_out_type) {
Buf *full_path = buf_alloc();
os_path_join(parent_gen->zig_std_special_dir, buf_create_from_str("compiler_rt.zig"), full_path);
return build_a_raw(parent_gen, "compiler_rt", full_path, child_out_type);
}
static Buf *build_c(CodeGen *parent_gen, OutType child_out_type) {
Buf *full_path = buf_alloc();
os_path_join(parent_gen->zig_std_special_dir, buf_create_from_str("c.zig"), full_path);
return build_a_raw(parent_gen, "c", full_path, child_out_type);
}
static const char *get_darwin_arch_string(const ZigTarget *t) {
switch (t->arch) {
case ZigLLVM_aarch64:
return "arm64";
case ZigLLVM_thumb:
case ZigLLVM_arm:
return "arm";
case ZigLLVM_ppc:
return "ppc";
case ZigLLVM_ppc64:
return "ppc64";
case ZigLLVM_ppc64le:
return "ppc64le";
default:
return ZigLLVMGetArchTypeName(t->arch);
}
}
static const char *getLDMOption(const ZigTarget *t) {
switch (t->arch) {
case ZigLLVM_x86:
return "elf_i386";
case ZigLLVM_aarch64:
return "aarch64linux";
case ZigLLVM_aarch64_be:
return "aarch64_be_linux";
case ZigLLVM_arm:
case ZigLLVM_thumb:
return "armelf_linux_eabi";
case ZigLLVM_armeb:
case ZigLLVM_thumbeb:
return "armebelf_linux_eabi";
case ZigLLVM_ppc:
return "elf32ppclinux";
case ZigLLVM_ppc64:
return "elf64ppc";
case ZigLLVM_ppc64le:
return "elf64lppc";
case ZigLLVM_sparc:
case ZigLLVM_sparcel:
return "elf32_sparc";
case ZigLLVM_sparcv9:
return "elf64_sparc";
case ZigLLVM_mips:
return "elf32btsmip";
case ZigLLVM_mipsel:
return "elf32ltsmip";
return "elf64btsmip";
case ZigLLVM_mips64el:
return "elf64ltsmip";
case ZigLLVM_systemz:
return "elf64_s390";
case ZigLLVM_x86_64:
if (t->abi == ZigLLVM_GNUX32) {
return "elf32_x86_64";
}
// Any target elf will use the freebsd osabi if suffixed with "_fbsd".
if (t->os == OsFreeBSD) {
return "elf_x86_64_fbsd";
}
return "elf_x86_64";
case ZigLLVM_riscv32:
return "elf32lriscv";
case ZigLLVM_riscv64:
return "elf64lriscv";
default:
zig_unreachable();
}
}
static void add_rpath(LinkJob *lj, Buf *rpath) {
if (lj->rpath_table.maybe_get(rpath) != nullptr)
return;
lj->args.append("-rpath");
lj->args.append(buf_ptr(rpath));
lj->rpath_table.put(rpath, true);
}
static void add_glibc_libs(LinkJob *lj) {
Error err;
ZigGLibCAbi *glibc_abi;
if ((err = glibc_load_metadata(&glibc_abi, lj->codegen->zig_lib_dir, true))) {
fprintf(stderr, "%s\n", err_str(err));
exit(1);
}
Buf *artifact_dir;
if ((err = glibc_build_dummies_and_maps(lj->codegen, glibc_abi, lj->codegen->zig_target,
&artifact_dir, true)))
{
fprintf(stderr, "%s\n", err_str(err));
exit(1);
}
size_t lib_count = glibc_lib_count();
for (size_t i = 0; i < lib_count; i += 1) {
const ZigGLibCLib *lib = glibc_lib_enum(i);
Buf *so_path = buf_sprintf("%s" OS_SEP "lib%s.so.%d.0.0", buf_ptr(artifact_dir), lib->name, lib->sover);
lj->args.append(buf_ptr(so_path));
}
}
static void construct_linker_job_elf(LinkJob *lj) {
CodeGen *g = lj->codegen;
lj->args.append("-error-limit=0");
if (g->out_type == OutTypeExe) {
lj->args.append("-z");
lj->args.append("stack-size=16777216"); // default to 16 MiB
}
if (g->linker_script) {
lj->args.append("-T");
lj->args.append(g->linker_script);
}
if (g->out_type != OutTypeObj) {
lj->args.append("--gc-sections");
}
lj->args.append("-m");
lj->args.append(getLDMOption(g->zig_target));
bool is_lib = g->out_type == OutTypeLib;
bool is_dyn_lib = g->is_dynamic && is_lib;
Buf *soname = nullptr;
if (!g->have_dynamic_link) {
if (g->zig_target->arch == ZigLLVM_arm || g->zig_target->arch == ZigLLVM_armeb ||
g->zig_target->arch == ZigLLVM_thumb || g->zig_target->arch == ZigLLVM_thumbeb)
{
lj->args.append("-Bstatic");
} else {
lj->args.append("-static");
}
} else if (is_dyn_lib) {
lj->args.append("-shared");
assert(buf_len(&g->output_file_path) != 0);
soname = buf_sprintf("lib%s.so.%" ZIG_PRI_usize, buf_ptr(g->root_out_name), g->version_major);
}
lj->args.append("-o");
lj->args.append(buf_ptr(&g->output_file_path));
if (lj->link_in_crt) {
const char *crt1o;
if (g->zig_target->os == OsNetBSD) {
crt1o = "crt0.o";
} else if (!g->have_dynamic_link) {
crt1o = "crt1.o";
} else {
crt1o = "Scrt1.o";
}
lj->args.append(get_libc_crt_file(g, crt1o));
lj->args.append(get_libc_crt_file(g, "crti.o"));
}
for (size_t i = 0; i < g->rpath_list.length; i += 1) {
Buf *rpath = g->rpath_list.at(i);
add_rpath(lj, rpath);
}
if (g->each_lib_rpath) {
for (size_t i = 0; i < g->lib_dirs.length; i += 1) {
const char *lib_dir = g->lib_dirs.at(i);
for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
LinkLib *link_lib = g->link_libs_list.at(i);
if (buf_eql_str(link_lib->name, "c")) {
continue;
}
bool does_exist;
Buf *test_path = buf_sprintf("%s/lib%s.so", lib_dir, buf_ptr(link_lib->name));
if (os_file_exists(test_path, &does_exist) != ErrorNone) {
zig_panic("link: unable to check if file exists: %s", buf_ptr(test_path));
}
if (does_exist) {
add_rpath(lj, buf_create_from_str(lib_dir));
break;
}
}
}
}
for (size_t i = 0; i < g->lib_dirs.length; i += 1) {
const char *lib_dir = g->lib_dirs.at(i);
lj->args.append("-L");
lj->args.append(lib_dir);
}
if (g->libc_link_lib != nullptr) {
if (g->libc != nullptr) {
lj->args.append("-L");
lj->args.append(buf_ptr(&g->libc->crt_dir));
}
if (g->have_dynamic_link && (is_dyn_lib || g->out_type == OutTypeExe)) {
assert(g->dynamic_linker_path != nullptr);
lj->args.append("-dynamic-linker");
lj->args.append(buf_ptr(g->dynamic_linker_path));
}
}
if (is_dyn_lib) {
lj->args.append("-soname");
lj->args.append(buf_ptr(soname));
if (g->version_script_path != nullptr) {
lj->args.append("-version-script");
lj->args.append(buf_ptr(g->version_script_path));
}
}
// .o files
for (size_t i = 0; i < g->link_objects.length; i += 1) {
lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
}
if (!g->is_dummy_so && (g->out_type == OutTypeExe || is_dyn_lib)) {
if (g->libc_link_lib == nullptr) {
Buf *libc_a_path = build_c(g, OutTypeLib);
lj->args.append(buf_ptr(libc_a_path));
}
Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib);
lj->args.append(buf_ptr(compiler_rt_o_path));
}
for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
LinkLib *link_lib = g->link_libs_list.at(i);
if (buf_eql_str(link_lib->name, "c")) {
// libc is linked specially
continue;
}
if (g->libc == nullptr && target_is_libc_lib_name(g->zig_target, buf_ptr(link_lib->name))) {
// these libraries are always linked below when targeting glibc
continue;
}
Buf *arg;
if (buf_starts_with_str(link_lib->name, "/") || buf_ends_with_str(link_lib->name, ".a") ||
buf_ends_with_str(link_lib->name, ".so"))
{
arg = link_lib->name;
} else {
arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));
}
lj->args.append(buf_ptr(arg));
}
// libc dep
if (g->libc_link_lib != nullptr && g->out_type != OutTypeObj) {
if (g->libc != nullptr) {
if (!g->have_dynamic_link) {
lj->args.append("--start-group");
lj->args.append("-lgcc");
lj->args.append("-lgcc_eh");
lj->args.append("-lc");
lj->args.append("-lm");
lj->args.append("--end-group");
} else {
lj->args.append("-lgcc");
lj->args.append("--as-needed");
lj->args.append("-lgcc_s");
lj->args.append("--no-as-needed");
lj->args.append("-lc");
lj->args.append("-lm");
lj->args.append("-lgcc");
lj->args.append("--as-needed");
lj->args.append("-lgcc_s");
lj->args.append("--no-as-needed");
}
if (g->zig_target->os == OsFreeBSD) {
lj->args.append("-lpthread");
}
} else if (target_is_glibc(g->zig_target)) {
if (target_supports_libunwind(g->zig_target)) {
lj->args.append(build_libunwind(g));
}
add_glibc_libs(lj);
lj->args.append(get_libc_crt_file(g, "libc_nonshared.a"));
} else if (target_is_musl(g->zig_target)) {
if (target_supports_libunwind(g->zig_target)) {
lj->args.append(build_libunwind(g));
}
lj->args.append(build_musl(g));
} else {
zig_unreachable();
}
}
// crt end
if (lj->link_in_crt) {
lj->args.append(get_libc_crt_file(g, "crtn.o"));
}
if (!g->zig_target->is_native) {
lj->args.append("--allow-shlib-undefined");
}
if (g->zig_target->os == OsZen) {
lj->args.append("-e");
lj->args.append("_start");
lj->args.append("--image-base=0x10000000");
}
}
static void construct_linker_job_wasm(LinkJob *lj) {
CodeGen *g = lj->codegen;
lj->args.append("-error-limit=0");
if (g->out_type != OutTypeExe) {
lj->args.append("--no-entry"); // So lld doesn't look for _start.
// If there are any C source files we cannot rely on individual exports.
if (g->c_source_files.length != 0) {
lj->args.append("--export-all");
} else {
auto export_it = g->exported_symbol_names.entry_iterator();
decltype(g->exported_symbol_names)::Entry *curr_entry = nullptr;
while ((curr_entry = export_it.next()) != nullptr) {
Buf *arg = buf_sprintf("--export=%s", buf_ptr(curr_entry->key));
lj->args.append(buf_ptr(arg));
}
}
}
lj->args.append("--allow-undefined");
lj->args.append("-o");
lj->args.append(buf_ptr(&g->output_file_path));
// .o files
for (size_t i = 0; i < g->link_objects.length; i += 1) {
lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
}
if (g->out_type != OutTypeObj) {
Buf *libc_o_path = build_c(g, OutTypeObj);
lj->args.append(buf_ptr(libc_o_path));
Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeObj);
lj->args.append(buf_ptr(compiler_rt_o_path));
}
}
static void coff_append_machine_arg(CodeGen *g, ZigList<const char *> *list) {
if (g->zig_target->arch == ZigLLVM_x86) {
list->append("-MACHINE:X86");
} else if (g->zig_target->arch == ZigLLVM_x86_64) {
list->append("-MACHINE:X64");
} else if (target_is_arm(g->zig_target)) {
if (target_arch_pointer_bit_width(g->zig_target->arch) == 32) {
list->append("-MACHINE:ARM");
} else {
list->append("-MACHINE:ARM64");
}
}
}
static void link_diag_callback(void *context, const char *ptr, size_t len) {
Buf *diag = reinterpret_cast<Buf *>(context);
buf_append_mem(diag, ptr, len);
}
static bool zig_lld_link(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, Buf *diag) {
buf_resize(diag, 0);
return ZigLLDLink(oformat, args, arg_count, link_diag_callback, diag);
}
static void add_uefi_link_args(LinkJob *lj) {
lj->args.append("-BASE:0");
lj->args.append("-ENTRY:EfiMain");
lj->args.append("-OPT:REF");
lj->args.append("-SAFESEH:NO");
lj->args.append("-MERGE:.rdata=.data");
lj->args.append("-ALIGN:32");
lj->args.append("-NODEFAULTLIB");
lj->args.append("-SECTION:.xdata,D");
}
static void add_msvc_link_args(LinkJob *lj, bool is_library) {
CodeGen *g = lj->codegen;
bool is_dynamic = g->is_dynamic;
const char *lib_str = is_dynamic ? "" : "lib";
const char *d_str = (g->build_mode == BuildModeDebug) ? "d" : "";
if (!is_dynamic) {
Buf *cmt_lib_name = buf_sprintf("libcmt%s.lib", d_str);
lj->args.append(buf_ptr(cmt_lib_name));
} else {
Buf *msvcrt_lib_name = buf_sprintf("msvcrt%s.lib", d_str);
lj->args.append(buf_ptr(msvcrt_lib_name));
}
Buf *vcruntime_lib_name = buf_sprintf("%svcruntime%s.lib", lib_str, d_str);
lj->args.append(buf_ptr(vcruntime_lib_name));
Buf *crt_lib_name = buf_sprintf("%sucrt%s.lib", lib_str, d_str);
lj->args.append(buf_ptr(crt_lib_name));
//Visual C++ 2015 Conformance Changes
//https://msdn.microsoft.com/en-us/library/bb531344.aspx
lj->args.append("legacy_stdio_definitions.lib");
// msvcrt depends on kernel32 and ntdll
lj->args.append("kernel32.lib");
lj->args.append("ntdll.lib");
}
static void print_zig_cc_cmd(ZigList<const char *> *args) {
for (size_t arg_i = 0; arg_i < args->length; arg_i += 1) {
const char *space_str = (arg_i == 0) ? "" : " ";
fprintf(stderr, "%s%s", space_str, args->at(arg_i));
}
fprintf(stderr, "\n");
}
static const char *get_def_lib(CodeGen *parent, const char *name, Buf *def_in_rel_path) {
Error err;
Buf *self_exe_path = buf_alloc();
if ((err = os_self_exe_path(self_exe_path))) {
fprintf(stderr, "Unable to get self exe path: %s\n", err_str(err));
exit(1);
}
Buf *compiler_id;
if ((err = get_compiler_id(&compiler_id))) {
fprintf(stderr, "Unable to get compiler id: %s\n", err_str(err));
exit(1);
}
Buf *cache_dir = get_stage1_cache_path();
Buf *o_dir = buf_sprintf("%s" OS_SEP CACHE_OUT_SUBDIR, buf_ptr(cache_dir));
Buf *manifest_dir = buf_sprintf("%s" OS_SEP CACHE_HASH_SUBDIR, buf_ptr(cache_dir));
Buf *def_in_file = buf_sprintf("%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "%s",
buf_ptr(parent->zig_lib_dir), buf_ptr(def_in_rel_path));
Buf *def_include_dir = buf_sprintf("%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "def-include",
buf_ptr(parent->zig_lib_dir));
CacheHash *cache_hash = allocate<CacheHash>(1);
cache_init(cache_hash, manifest_dir);
cache_buf(cache_hash, compiler_id);
cache_file(cache_hash, def_in_file);
cache_buf(cache_hash, def_include_dir);
cache_int(cache_hash, parent->zig_target->arch);
Buf digest = BUF_INIT;
buf_resize(&digest, 0);
if ((err = cache_hit(cache_hash, &digest))) {
if (err != ErrorInvalidFormat) {
if (err == ErrorCacheUnavailable) {
// already printed error
} else {
fprintf(stderr, "unable to check cache when processing .def.in file: %s\n", err_str(err));
}
exit(1);
}
}
Buf *artifact_dir;
Buf *lib_final_path;
Buf *final_lib_basename = buf_sprintf("%s.lib", name);
bool is_cache_miss = (buf_len(&digest) == 0);
if (is_cache_miss) {
if ((err = cache_final(cache_hash, &digest))) {
fprintf(stderr, "Unable to finalize cache hash: %s\n", err_str(err));
exit(1);
}
artifact_dir = buf_alloc();
os_path_join(o_dir, &digest, artifact_dir);
if ((err = os_make_path(artifact_dir))) {
fprintf(stderr, "Unable to create output directory '%s': %s",
buf_ptr(artifact_dir), err_str(err));
exit(1);
}
Buf *final_def_basename = buf_sprintf("%s.def", name);
Buf *def_final_path = buf_alloc();
os_path_join(artifact_dir, final_def_basename, def_final_path);
ZigList<const char *> args = {};
args.append(buf_ptr(self_exe_path));
args.append("cc");
args.append("-x");
args.append("c");
args.append(buf_ptr(def_in_file));
args.append("-Wp,-w");
args.append("-undef");
args.append("-P");
args.append("-I");
args.append(buf_ptr(def_include_dir));
if (target_is_arm(parent->zig_target)) {
if (target_arch_pointer_bit_width(parent->zig_target->arch) == 32) {
args.append("-DDEF_ARM32");
} else {
args.append("-DDEF_ARM64");
}
} else if (parent->zig_target->arch == ZigLLVM_x86) {
args.append("-DDEF_I386");
} else if (parent->zig_target->arch == ZigLLVM_x86_64) {
args.append("-DDEF_X64");
} else {
zig_unreachable();
}
args.append("-E");
args.append("-o");
args.append(buf_ptr(def_final_path));
if (parent->verbose_cc) {
print_zig_cc_cmd(&args);
}
Termination term;
os_spawn_process(args, &term);
if (term.how != TerminationIdClean || term.code != 0) {
fprintf(stderr, "\nThe following command failed:\n");
print_zig_cc_cmd(&args);
exit(1);
}
lib_final_path = buf_alloc();
os_path_join(artifact_dir, final_lib_basename, lib_final_path);
args.resize(0);
args.append("link");
coff_append_machine_arg(parent, &args);
args.append(buf_ptr(buf_sprintf("-DEF:%s", buf_ptr(def_final_path))));
args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(lib_final_path))));
Buf diag = BUF_INIT;
ZigLLVM_ObjectFormatType target_ofmt = target_object_format(parent->zig_target);
if (!zig_lld_link(target_ofmt, args.items, args.length, &diag)) {
fprintf(stderr, "%s\n", buf_ptr(&diag));
exit(1);
}
} else {
// cache hit
artifact_dir = buf_alloc();
os_path_join(o_dir, &digest, artifact_dir);
lib_final_path = buf_alloc();
os_path_join(artifact_dir, final_lib_basename, lib_final_path);
}
parent->caches_to_release.append(cache_hash);
return buf_ptr(lib_final_path);
}
static bool is_linking_system_lib(CodeGen *g, const char *name) {
for (size_t lib_i = 0; lib_i < g->link_libs_list.length; lib_i += 1) {
LinkLib *link_lib = g->link_libs_list.at(lib_i);
if (buf_eql_str(link_lib->name, name)) {
return true;
}
}
return false;
}
static void add_mingw_link_args(LinkJob *lj, bool is_library) {
CodeGen *g = lj->codegen;
lj->args.append("-lldmingw");
bool is_dll = g->out_type == OutTypeLib && g->is_dynamic;
if (g->zig_target->arch == ZigLLVM_x86) {
lj->args.append("-ALTERNATENAME:__image_base__=___ImageBase");
} else {
lj->args.append("-ALTERNATENAME:__image_base__=__ImageBase");
}
if (is_dll) {
lj->args.append(get_libc_crt_file(g, "dllcrt2.o"));
} else {
lj->args.append(get_libc_crt_file(g, "crt2.o"));
}
lj->args.append(get_libc_crt_file(g, "mingw32.lib"));
lj->args.append(get_libc_crt_file(g, "mingwex.lib"));
lj->args.append(get_libc_crt_file(g, "msvcrt-os.lib"));
for (size_t def_i = 0; def_i < array_length(mingw_def_list); def_i += 1) {
const char *name = mingw_def_list[def_i].name;
Buf *path = buf_create_from_str(mingw_def_list[def_i].path);
bool always_link = mingw_def_list[def_i].always_link;
bool is_this_arch = false;
if (buf_starts_with_str(path, "lib-common" OS_SEP)) {
is_this_arch = true;
} else if (target_is_arm(g->zig_target)) {
if (target_arch_pointer_bit_width(g->zig_target->arch) == 32) {
is_this_arch = buf_starts_with_str(path, "libarm32" OS_SEP);
} else {
is_this_arch = buf_starts_with_str(path, "libarm64" OS_SEP);
}
} else if (g->zig_target->arch == ZigLLVM_x86) {
is_this_arch = buf_starts_with_str(path, "lib32" OS_SEP);
} else if (g->zig_target->arch == ZigLLVM_x86_64) {
is_this_arch = buf_starts_with_str(path, "lib64" OS_SEP);
}
if (is_this_arch && (always_link || is_linking_system_lib(g, name))) {
lj->args.append(get_def_lib(g, name, path));
}
}
}
static void add_win_link_args(LinkJob *lj, bool is_library, bool *have_windows_dll_import_libs) {
if (lj->link_in_crt) {
if (target_abi_is_gnu(lj->codegen->zig_target->abi)) {
*have_windows_dll_import_libs = true;
add_mingw_link_args(lj, is_library);
} else {
add_msvc_link_args(lj, is_library);
}
} else {
lj->args.append("-NODEFAULTLIB");
if (!is_library) {
if (lj->codegen->have_winmain) {
lj->args.append("-ENTRY:WinMain");
} else {
lj->args.append("-ENTRY:WinMainCRTStartup");
}
}
}
}
static bool is_mingw_link_lib(Buf *name) {
for (size_t def_i = 0; def_i < array_length(mingw_def_list); def_i += 1) {
if (buf_eql_str_ignore_case(name, mingw_def_list[def_i].name)) {
return true;
}
}
return false;
}
static void construct_linker_job_coff(LinkJob *lj) {
Error err;
CodeGen *g = lj->codegen;
lj->args.append("-ERRORLIMIT:0");
lj->args.append("-NOLOGO");
if (!g->strip_debug_symbols) {
lj->args.append("-DEBUG");
}
if (g->out_type == OutTypeExe) {
// TODO compile time stack upper bound detection
lj->args.append("-STACK:16777216");
}
coff_append_machine_arg(g, &lj->args);
bool is_library = g->out_type == OutTypeLib;
if (is_library && g->is_dynamic) {
lj->args.append("-DLL");
}
lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path))));
if (g->libc_link_lib != nullptr && g->libc != nullptr) {
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->crt_dir))));
if (target_abi_is_gnu(g->zig_target->abi)) {
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->sys_include_dir))));
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->include_dir))));
} else {
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->msvc_lib_dir))));
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->kernel32_lib_dir))));
}
}
for (size_t i = 0; i < g->lib_dirs.length; i += 1) {
const char *lib_dir = g->lib_dirs.at(i);
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", lib_dir)));
}
for (size_t i = 0; i < g->link_objects.length; i += 1) {
lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
}
bool have_windows_dll_import_libs = false;
switch (detect_subsystem(g)) {
case TargetSubsystemAuto:
if (g->zig_target->os == OsUefi) {
add_uefi_link_args(lj);
} else {
add_win_link_args(lj, is_library, &have_windows_dll_import_libs);
}
break;
case TargetSubsystemConsole:
lj->args.append("-SUBSYSTEM:console");
add_win_link_args(lj, is_library, &have_windows_dll_import_libs);
break;
case TargetSubsystemEfiApplication:
lj->args.append("-SUBSYSTEM:efi_application");
add_uefi_link_args(lj);
break;
case TargetSubsystemEfiBootServiceDriver:
lj->args.append("-SUBSYSTEM:efi_boot_service_driver");
add_uefi_link_args(lj);
break;
case TargetSubsystemEfiRom:
lj->args.append("-SUBSYSTEM:efi_rom");
add_uefi_link_args(lj);
break;
case TargetSubsystemEfiRuntimeDriver:
lj->args.append("-SUBSYSTEM:efi_runtime_driver");
add_uefi_link_args(lj);
break;
case TargetSubsystemNative:
lj->args.append("-SUBSYSTEM:native");
add_win_link_args(lj, is_library, &have_windows_dll_import_libs);
break;
case TargetSubsystemPosix:
lj->args.append("-SUBSYSTEM:posix");
add_win_link_args(lj, is_library, &have_windows_dll_import_libs);
break;
case TargetSubsystemWindows:
lj->args.append("-SUBSYSTEM:windows");
add_win_link_args(lj, is_library, &have_windows_dll_import_libs);
break;
}
if (g->out_type == OutTypeExe || (g->out_type == OutTypeLib && g->is_dynamic)) {
if (g->libc_link_lib == nullptr && !g->is_dummy_so) {
Buf *libc_a_path = build_c(g, OutTypeLib);
lj->args.append(buf_ptr(libc_a_path));
}
// msvc compiler_rt is missing some stuff, so we still build it and rely on weak linkage
Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib);
lj->args.append(buf_ptr(compiler_rt_o_path));
}
Buf *def_contents = buf_alloc();
ZigList<const char *> gen_lib_args = {0};
for (size_t lib_i = 0; lib_i < g->link_libs_list.length; lib_i += 1) {
LinkLib *link_lib = g->link_libs_list.at(lib_i);
if (buf_eql_str(link_lib->name, "c")) {
continue;
}
bool is_sys_lib = is_mingw_link_lib(link_lib->name);
if (have_windows_dll_import_libs && is_sys_lib) {
continue;
}
// If we're linking in the CRT or the libs are provided explictly we don't want to generate def/libs
if ((lj->link_in_crt && is_sys_lib) || link_lib->provided_explicitly) {
if (target_abi_is_gnu(lj->codegen->zig_target->abi)) {
Buf* lib_name = buf_sprintf("lib%s.a", buf_ptr(link_lib->name));
lj->args.append(buf_ptr(lib_name));
}
else {
Buf* lib_name = buf_sprintf("%s.lib", buf_ptr(link_lib->name));
lj->args.append(buf_ptr(lib_name));
}
continue;
}
buf_resize(def_contents, 0);
buf_appendf(def_contents, "LIBRARY %s\nEXPORTS\n", buf_ptr(link_lib->name));
for (size_t exp_i = 0; exp_i < link_lib->symbols.length; exp_i += 1) {
Buf *symbol_name = link_lib->symbols.at(exp_i);
buf_appendf(def_contents, "%s\n", buf_ptr(symbol_name));
}
buf_appendf(def_contents, "\n");
Buf *def_path = buf_alloc();
os_path_join(g->output_dir, buf_sprintf("%s.def", buf_ptr(link_lib->name)), def_path);
if ((err = os_write_file(def_path, def_contents))) {
zig_panic("error writing def file: %s", err_str(err));
}
Buf *generated_lib_path = buf_alloc();
os_path_join(g->output_dir, buf_sprintf("%s.lib", buf_ptr(link_lib->name)), generated_lib_path);
gen_lib_args.resize(0);
gen_lib_args.append("link");
coff_append_machine_arg(g, &gen_lib_args);
gen_lib_args.append(buf_ptr(buf_sprintf("-DEF:%s", buf_ptr(def_path))));
gen_lib_args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(generated_lib_path))));
Buf diag = BUF_INIT;
ZigLLVM_ObjectFormatType target_ofmt = target_object_format(g->zig_target);
if (!zig_lld_link(target_ofmt, gen_lib_args.items, gen_lib_args.length, &diag)) {
fprintf(stderr, "%s\n", buf_ptr(&diag));
exit(1);
}
lj->args.append(buf_ptr(generated_lib_path));
}
}
// Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and return the
// grouped values as integers. Numbers which are not provided are set to 0.
// return true if the entire string was parsed (9.2), or all groups were
// parsed (10.3.5extrastuff).
static bool darwin_get_release_version(const char *str, int *major, int *minor, int *micro, bool *had_extra) {
*had_extra = false;
*major = 0;
*minor = 0;
*micro = 0;
if (*str == '\0')
return false;
char *end;
*major = (int)strtol(str, &end, 10);
if (*str != '\0' && *end == '\0')
return true;
if (*end != '.')
return false;
str = end + 1;
*minor = (int)strtol(str, &end, 10);
if (*str != '\0' && *end == '\0')
return true;
if (*end != '.')
return false;
str = end + 1;
*micro = (int)strtol(str, &end, 10);
if (*str != '\0' && *end == '\0')
return true;
if (str == end)
return false;
*had_extra = true;
return true;
}
enum DarwinPlatformKind {
MacOS,
IPhoneOS,
IPhoneOSSimulator,
};
struct DarwinPlatform {
DarwinPlatformKind kind;
int major;
int minor;
int micro;
};
static void get_darwin_platform(LinkJob *lj, DarwinPlatform *platform) {
CodeGen *g = lj->codegen;
if (g->mmacosx_version_min) {
platform->kind = MacOS;
} else if (g->mios_version_min) {
platform->kind = IPhoneOS;
} else if (g->zig_target->os == OsMacOSX) {
platform->kind = MacOS;
g->mmacosx_version_min = buf_create_from_str("10.14");
} else {
zig_panic("unable to infer -mmacosx-version-min or -mios-version-min");
}
bool had_extra;
if (platform->kind == MacOS) {
if (!darwin_get_release_version(buf_ptr(g->mmacosx_version_min),
&platform->major, &platform->minor, &platform->micro, &had_extra) ||
had_extra || platform->major != 10 || platform->minor >= 100 || platform->micro >= 100)
{
zig_panic("invalid -mmacosx-version-min");
}
} else if (platform->kind == IPhoneOS) {
if (!darwin_get_release_version(buf_ptr(g->mios_version_min),
&platform->major, &platform->minor, &platform->micro, &had_extra) ||
had_extra || platform->major >= 10 || platform->minor >= 100 || platform->micro >= 100)
{
zig_panic("invalid -mios-version-min");
}
} else {
zig_unreachable();
}
if (platform->kind == IPhoneOS &&
(g->zig_target->arch == ZigLLVM_x86 ||
g->zig_target->arch == ZigLLVM_x86_64))
{
platform->kind = IPhoneOSSimulator;
}
}
static void construct_linker_job_macho(LinkJob *lj) {
CodeGen *g = lj->codegen;
// LLD MACH-O has no error limit option.
//lj->args.append("-error-limit=0");
lj->args.append("-demangle");
if (g->linker_rdynamic) {
lj->args.append("-export_dynamic");
}
bool is_lib = g->out_type == OutTypeLib;
bool is_dyn_lib = g->is_dynamic && is_lib;
if (is_lib && !g->is_dynamic) {
lj->args.append("-static");
} else {
lj->args.append("-dynamic");
}
if (is_dyn_lib) {
lj->args.append("-dylib");
Buf *compat_vers = buf_sprintf("%" ZIG_PRI_usize ".0.0", g->version_major);
lj->args.append("-compatibility_version");
lj->args.append(buf_ptr(compat_vers));
Buf *cur_vers = buf_sprintf("%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize,
g->version_major, g->version_minor, g->version_patch);
lj->args.append("-current_version");
lj->args.append(buf_ptr(cur_vers));
// TODO getting an error when running an executable when doing this rpath thing
//Buf *dylib_install_name = buf_sprintf("@rpath/lib%s.%" ZIG_PRI_usize ".dylib",
// buf_ptr(g->root_out_name), g->version_major);
//lj->args.append("-install_name");
//lj->args.append(buf_ptr(dylib_install_name));
assert(buf_len(&g->output_file_path) != 0);
}
lj->args.append("-arch");
lj->args.append(get_darwin_arch_string(g->zig_target));
DarwinPlatform platform;
get_darwin_platform(lj, &platform);
switch (platform.kind) {
case MacOS:
lj->args.append("-macosx_version_min");
break;
case IPhoneOS:
lj->args.append("-iphoneos_version_min");
break;
case IPhoneOSSimulator:
lj->args.append("-ios_simulator_version_min");
break;
}
Buf *version_string = buf_sprintf("%d.%d.%d", platform.major, platform.minor, platform.micro);
lj->args.append(buf_ptr(version_string));
lj->args.append("-sdk_version");
lj->args.append(buf_ptr(version_string));
if (g->out_type == OutTypeExe) {
lj->args.append("-pie");
}
lj->args.append("-o");
lj->args.append(buf_ptr(&g->output_file_path));
for (size_t i = 0; i < g->rpath_list.length; i += 1) {
Buf *rpath = g->rpath_list.at(i);
add_rpath(lj, rpath);
}
if (is_dyn_lib) {
add_rpath(lj, &g->output_file_path);
}
if (is_dyn_lib) {
if (g->system_linker_hack) {
lj->args.append("-headerpad_max_install_names");
}
}
for (size_t i = 0; i < g->lib_dirs.length; i += 1) {
const char *lib_dir = g->lib_dirs.at(i);
lj->args.append("-L");
lj->args.append(lib_dir);
}
for (size_t i = 0; i < g->link_objects.length; i += 1) {
lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
}
// compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce
if (g->out_type == OutTypeExe || is_dyn_lib) {
Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib);
lj->args.append(buf_ptr(compiler_rt_o_path));
}
if (g->zig_target->is_native) {
for (size_t lib_i = 0; lib_i < g->link_libs_list.length; lib_i += 1) {
LinkLib *link_lib = g->link_libs_list.at(lib_i);
if (target_is_libc_lib_name(g->zig_target, buf_ptr(link_lib->name))) {
// handled by libSystem
continue;
}
if (strchr(buf_ptr(link_lib->name), '/') == nullptr) {
Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));
lj->args.append(buf_ptr(arg));
} else {
lj->args.append(buf_ptr(link_lib->name));
}
}
// on Darwin, libSystem has libc in it, but also you have to use it
// to make syscalls because the syscall numbers are not documented
// and change between versions.
// so we always link against libSystem
lj->args.append("-lSystem");
} else {
lj->args.append("-undefined");
lj->args.append("dynamic_lookup");
}
for (size_t i = 0; i < g->framework_dirs.length; i += 1) {
const char *framework_dir = g->framework_dirs.at(i);
lj->args.append("-F");
lj->args.append(framework_dir);
}
for (size_t i = 0; i < g->darwin_frameworks.length; i += 1) {
lj->args.append("-framework");
lj->args.append(buf_ptr(g->darwin_frameworks.at(i)));
}
}
static void construct_linker_job(LinkJob *lj) {
switch (target_object_format(lj->codegen->zig_target)) {
case ZigLLVM_UnknownObjectFormat:
zig_unreachable();
case ZigLLVM_COFF:
return construct_linker_job_coff(lj);
case ZigLLVM_ELF:
return construct_linker_job_elf(lj);
case ZigLLVM_MachO:
return construct_linker_job_macho(lj);
case ZigLLVM_Wasm:
return construct_linker_job_wasm(lj);
}
}
void zig_link_add_compiler_rt(CodeGen *g) {
Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeObj);
g->link_objects.append(compiler_rt_o_path);
}
void codegen_link(CodeGen *g) {
codegen_add_time_event(g, "Build Dependencies");
LinkJob lj = {0};
// even though we're calling LLD as a library it thinks the first
// argument is its own exe name
lj.args.append("lld");
lj.rpath_table.init(4);
lj.codegen = g;
if (g->verbose_llvm_ir) {
fprintf(stderr, "\nOptimization:\n");
fprintf(stderr, "---------------\n");
fflush(stderr);
LLVMDumpModule(g->module);
}
if (g->out_type == OutTypeObj) {
lj.args.append("-r");
}
if (g->out_type == OutTypeLib && !g->is_dynamic && !target_is_wasm(g->zig_target)) {
ZigList<const char *> file_names = {};
for (size_t i = 0; i < g->link_objects.length; i += 1) {
file_names.append(buf_ptr(g->link_objects.at(i)));
}
ZigLLVM_OSType os_type = get_llvm_os_type(g->zig_target->os);
codegen_add_time_event(g, "LLVM Link");
if (g->verbose_link) {
fprintf(stderr, "ar rcs %s", buf_ptr(&g->output_file_path));
for (size_t i = 0; i < file_names.length; i += 1) {
fprintf(stderr, " %s", file_names.at(i));
}
fprintf(stderr, "\n");
}
if (ZigLLVMWriteArchive(buf_ptr(&g->output_file_path), file_names.items, file_names.length, os_type)) {
fprintf(stderr, "Unable to write archive '%s'\n", buf_ptr(&g->output_file_path));
exit(1);
}
return;
}
lj.link_in_crt = (g->libc_link_lib != nullptr && g->out_type == OutTypeExe);
construct_linker_job(&lj);
if (g->verbose_link) {
for (size_t i = 0; i < lj.args.length; i += 1) {
const char *space = (i != 0) ? " " : "";
fprintf(stderr, "%s%s", space, lj.args.at(i));
}
fprintf(stderr, "\n");
}
Buf diag = BUF_INIT;
codegen_add_time_event(g, "LLVM Link");
if (g->system_linker_hack && g->zig_target->os == OsMacOSX) {
Termination term;
ZigList<const char *> args = {};
args.append("ld");
for (size_t i = 1; i < lj.args.length; i += 1) {
args.append(lj.args.at(i));
}
os_spawn_process(args, &term);
if (term.how != TerminationIdClean || term.code != 0) {
exit(1);
}
} else if (!zig_lld_link(target_object_format(g->zig_target), lj.args.items, lj.args.length, &diag)) {
fprintf(stderr, "%s\n", buf_ptr(&diag));
exit(1);
}
}