zig/src/link.cpp
Andrew Kelley 543e729398
Merge pull request #3331 from meme/android-ndk
Support Android NDK
2019-09-28 13:30:19 -04:00

2662 lines
100 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 "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/<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("-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<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("-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<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("-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<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("-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<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);
}
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<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:
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<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);
}
}