/* * 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 args; bool link_in_crt; HashMap 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 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 c_source_files = {0}; for (size_t i = 0; i < array_length(unwind_src); i += 1) { CFile *c_file = allocate(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 "generic")); 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-musl", buf_ptr(parent->zig_lib_dir), target_arch_musl_name(parent->zig_target->arch), target_os_name(parent->zig_target->os)))); 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//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 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 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 / 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(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(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(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(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(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(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(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("-Wno-nonportable-include-path"); 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(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(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("-Wno-nonportable-include-path"); 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(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(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("-Wno-nonportable-include-path"); 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(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("-Wno-nonportable-include-path"); 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(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(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(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(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); } if (target_requires_pie(g->zig_target) && g->out_type == OutTypeExe) { lj->args.append("-pie"); } 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 (target_is_android(g->zig_target)) { if (g->have_dynamic_link) { crt1o = "crtbegin_dynamic.o"; } else { crt1o = "crtbegin_static.o"; } } else if (!g->have_dynamic_link) { crt1o = "crt1.o"; } else { crt1o = "Scrt1.o"; } lj->args.append(get_libc_crt_file(g, crt1o)); if (target_libc_needs_crti_crtn(g->zig_target)) { 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"); if (!target_is_android(g->zig_target)) { lj->args.append("-lgcc"); lj->args.append("-lgcc_eh"); } lj->args.append("-lc"); lj->args.append("-lm"); lj->args.append("--end-group"); } else { if (!target_is_android(g->zig_target)) { 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"); if (!target_is_android(g->zig_target)) { 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) { if (target_is_android(g->zig_target)) { lj->args.append(get_libc_crt_file(g, "crtend_android.o")); } else if (target_libc_needs_crti_crtn(g->zig_target)) { 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 *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(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 *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(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 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 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: case ZigLLVM_XCOFF: 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 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 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); } }