Esempio n. 1
0
static bool link_lib(compile_t* c, const char* file_o)
{
  size_t len = strlen(c->filename);

#if defined(PLATFORM_IS_POSIX_BASED)
  VLA(char, libname, len + 4);
  memcpy(libname, "lib", 3);
  memcpy(libname + 3, c->filename, len + 1);

  const char* file_lib = suffix_filename(c->opt->output, libname, ".a");
  printf("Archiving %s\n", file_lib);

  len = 32 + strlen(file_lib) + strlen(file_o);
  VLA(char, cmd, len);

  snprintf(cmd, len, "ar -rcs %s %s", file_lib, file_o);

  if(system(cmd) != 0)
  {
    errorf(NULL, "unable to link");
    return false;
  }
#elif defined(PLATFORM_IS_WINDOWS)
  VLA(char, libname, len + 1);
  memcpy(libname, c->filename, len + 1);

  const char* file_lib = suffix_filename(c->opt->output, libname, ".lib");
  printf("Archiving %s\n", file_lib);

  vcvars_t vcvars;

  if(!vcvars_get(&vcvars))
  {
    errorf(NULL, "unable to link");
    return false;
  }

  len = 128 + strlen(file_lib) + strlen(file_o);
  VLA(char, cmd, len);

  snprintf(cmd, len, "cmd /C \"\"%s\" /NOLOGO /OUT:%s %s\"", vcvars.ar,
    file_lib, file_o);

  if(system(cmd) == -1)
  {
    errorf(NULL, "unable to link");
    return false;
  }
#endif

  return true;
}
Esempio n. 2
0
static bool link_lib(compile_t* c, const char* file_o)
{
#if defined(PLATFORM_IS_POSIX_BASED)
  const char* file_lib = suffix_filename(c->opt->output, "lib", c->filename,
    ".a");
  printf("Archiving %s\n", file_lib);

  size_t len = 32 + strlen(file_lib) + strlen(file_o);
  char* cmd = (char*)pool_alloc_size(len);

  snprintf(cmd, len, "ar -rcs %s %s", file_lib, file_o);

  if(system(cmd) != 0)
  {
    errorf(NULL, "unable to link");
    pool_free_size(len, cmd);
    return false;
  }

  pool_free_size(len, cmd);
#elif defined(PLATFORM_IS_WINDOWS)
  const char* file_lib = suffix_filename(c->opt->output, "", c->filename,
    ".lib");
  printf("Archiving %s\n", file_lib);

  vcvars_t vcvars;

  if(!vcvars_get(&vcvars))
  {
    errorf(NULL, "unable to link");
    return false;
  }

  size_t len = 128 + strlen(file_lib) + strlen(file_o);
  char* cmd = (char*)pool_alloc_size(len);

  snprintf(cmd, len, "cmd /C \"\"%s\" /NOLOGO /OUT:%s %s\"", vcvars.ar,
    file_lib, file_o);

  if(system(cmd) == -1)
  {
    errorf(NULL, "unable to link");
    pool_free_size(len, cmd);
    return false;
  }

  pool_free_size(len, cmd);
#endif

  return true;
}
Esempio n. 3
0
bool genheader(compile_t* c)
{
  // Open a header file.
  const char* file_h = suffix_filename(c->opt->output, "", c->filename, ".h");
  FILE* fp = fopen(file_h, "wt");

  if(fp == NULL)
  {
    errorf(NULL, "couldn't write to %s", file_h);
    return false;
  }

  fprintf(fp,
    "#ifndef pony_%s_h\n"
    "#define pony_%s_h\n"
    "\n"
    "/* This is an auto-generated header file. Do not edit. */\n"
    "\n"
    "#include <stdint.h>\n"
    "#include <stdbool.h>\n"
    "\n"
    "#ifdef __cplusplus\n"
    "extern \"C\" {\n"
    "#endif\n"
    "\n"
    "#ifdef _MSC_VER\n"
    "typedef struct __int128_t { uint64_t low; int64_t high; } __int128_t;\n"
    "typedef struct __uint128_t { uint64_t low; uint64_t high; } "
      "__uint128_t;\n"
    "#endif\n"
    "\n",
    c->filename,
    c->filename
    );

  printbuf_t* buf = printbuf_new();
  print_types(c, fp, buf);
  fwrite(buf->m, 1, buf->offset, fp);
  printbuf_free(buf);

  fprintf(fp,
    "\n"
    "#ifdef __cplusplus\n"
    "}\n"
    "#endif\n"
    "\n"
    "#endif\n"
    );

  fclose(fp);
  return true;
}
Esempio n. 4
0
static bool link_lib(compile_t* c, const char* file_o)
{
  errors_t* errors = c->opt->check.errors;

#if defined(PLATFORM_IS_POSIX_BASED)
  const char* file_lib = suffix_filename(c, c->opt->output, "lib", c->filename,
    ".a");
  if(c->opt->verbosity >= VERBOSITY_MINIMAL)
    fprintf(stderr, "Archiving %s\n", file_lib);

  size_t len = 32 + strlen(file_lib) + strlen(file_o);
  char* cmd = (char*)ponyint_pool_alloc_size(len);

#if defined(PLATFORM_IS_MACOSX)
  snprintf(cmd, len, "/usr/bin/ar -rcs %s %s", file_lib, file_o);
#else
  snprintf(cmd, len, "ar -rcs %s %s", file_lib, file_o);
#endif

  if(c->opt->verbosity >= VERBOSITY_TOOL_INFO)
    fprintf(stderr, "%s\n", cmd);
  if(system(cmd) != 0)
  {
    errorf(errors, NULL, "unable to link: %s", cmd);
    ponyint_pool_free_size(len, cmd);
    return false;
  }

  ponyint_pool_free_size(len, cmd);
#elif defined(PLATFORM_IS_WINDOWS)
  const char* file_lib = suffix_filename(c, c->opt->output, "", c->filename,
    ".lib");
  if(c->opt->verbosity >= VERBOSITY_MINIMAL)
    fprintf(stderr, "Archiving %s\n", file_lib);

  vcvars_t vcvars;

  if(!vcvars_get(c, &vcvars, errors))
  {
    errorf(errors, NULL, "unable to link: no vcvars");
    return false;
  }

  size_t len = strlen(vcvars.ar) + strlen(file_lib) + strlen(file_o) + 64;
  char* cmd = (char*)ponyint_pool_alloc_size(len);

  snprintf(cmd, len, "cmd /C \"\"%s\" /NOLOGO /OUT:%s %s\"", vcvars.ar,
    file_lib, file_o);

  if(c->opt->verbosity >= VERBOSITY_TOOL_INFO)
    fprintf(stderr, "%s\n", cmd);
  if(system(cmd) == -1)
  {
    errorf(errors, NULL, "unable to link: %s", cmd);
    ponyint_pool_free_size(len, cmd);
    return false;
  }

  ponyint_pool_free_size(len, cmd);
#endif

  return true;
}
Esempio n. 5
0
File: genexe.c Progetto: volth/ponyc
static bool link_exe(compile_t* c, ast_t* program,
  const char* file_o)
{
#if defined(PLATFORM_IS_MACOSX)
  char* arch = strchr(c->opt->triple, '-');

  if(arch == NULL)
  {
    errorf(NULL, "couldn't determine architecture from %s", c->opt->triple);
    return false;
  }

  const char* file_exe = suffix_filename(c->opt->output, "", c->filename, "");
  printf("Linking %s\n", file_exe);

  program_lib_build_args(program, "-L", "", "", "-l", "");
  const char* lib_args = program_lib_args(program);

  size_t arch_len = arch - c->opt->triple;
  size_t ld_len = 128 + arch_len + strlen(file_exe) + strlen(file_o) +
    strlen(lib_args);
  char* ld_cmd = (char*)pool_alloc_size(ld_len);

  snprintf(ld_cmd, ld_len,
    "ld -execute -no_pie -dead_strip -arch %.*s -macosx_version_min 10.8 "
    "-o %s %s %s -lponyrt -lSystem",
    (int)arch_len, c->opt->triple, file_exe, file_o, lib_args
    );

  if(system(ld_cmd) != 0)
  {
    errorf(NULL, "unable to link");
    pool_free_size(ld_len, ld_cmd);
    return false;
  }

  pool_free_size(ld_len, ld_cmd);

  if(!c->opt->strip_debug)
  {
    size_t dsym_len = 16 + strlen(file_exe);
    char* dsym_cmd = (char*)pool_alloc_size(dsym_len);

    snprintf(dsym_cmd, dsym_len, "rm -rf %s.dSYM", file_exe);
    system(dsym_cmd);

    snprintf(dsym_cmd, dsym_len, "dsymutil %s", file_exe);

    if(system(dsym_cmd) != 0)
      errorf(NULL, "unable to create dsym");

    pool_free_size(dsym_len, dsym_cmd);
  }

#elif defined(PLATFORM_IS_LINUX) || defined(PLATFORM_IS_FREEBSD)
  const char* file_exe = suffix_filename(c->opt->output, "", c->filename, "");
  printf("Linking %s\n", file_exe);

#ifdef PLATFORM_IS_FREEBSD
  use_path(program, "/usr/local/lib", NULL, NULL);
#endif

  program_lib_build_args(program, "-L", "--start-group ", "--end-group ",
    "-l", "");
  const char* lib_args = program_lib_args(program);
  const char* crt_dir = crt_directory();
  const char* gccs_dir = gccs_directory();

  if((crt_dir == NULL) || (gccs_dir == NULL))
  {
    errorf(NULL, "could not find CRT");
    return false;
  }

  size_t ld_len = 256 + strlen(file_exe) + strlen(file_o) + strlen(lib_args) +
    strlen(gccs_dir) + (3 * strlen(crt_dir));
  char* ld_cmd = (char*)pool_alloc_size(ld_len);

  snprintf(ld_cmd, ld_len,
    "ld --eh-frame-hdr --hash-style=gnu "
#if defined(PLATFORM_IS_LINUX)
    "-m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 "
#elif defined(PLATFORM_IS_FREEBSD)
    "-m elf_x86_64_fbsd "
#endif
    "-o %s %scrt1.o %scrti.o %s %s -lponyrt -lpthread "
#ifdef PLATFORM_IS_LINUX
    "-ldl "
#endif
    "-lm -lc %slibgcc_s.so.1 %scrtn.o",
    file_exe, crt_dir, crt_dir, file_o, lib_args, gccs_dir, crt_dir
    );

  if(system(ld_cmd) != 0)
  {
    errorf(NULL, "unable to link");
    pool_free_size(ld_len, ld_cmd);
    return false;
  }

  pool_free_size(ld_len, ld_cmd);
#elif defined(PLATFORM_IS_WINDOWS)
  vcvars_t vcvars;

  if(!vcvars_get(&vcvars))
  {
    errorf(NULL, "unable to link");
    return false;
  }

  const char* file_exe = suffix_filename(c->opt->output, "", c->filename,
    ".exe");
  printf("Linking %s\n", file_exe);

  program_lib_build_args(program, "/LIBPATH:", "", "", "", ".lib");
  const char* lib_args = program_lib_args(program);

  size_t ld_len = 256 + strlen(file_exe) + strlen(file_o) +
    strlen(vcvars.kernel32) + strlen(vcvars.msvcrt) + strlen(lib_args);
  char* ld_cmd = (char*)pool_alloc_size(ld_len);

  snprintf(ld_cmd, ld_len,
    "cmd /C \"\"%s\" /DEBUG /NOLOGO /MACHINE:X64 "
    "/OUT:%s "
    "%s "
    "/LIBPATH:\"%s\" "
    "/LIBPATH:\"%s\" "
    "%s ponyrt.lib kernel32.lib msvcrt.lib Ws2_32.lib \"",
    vcvars.link, file_exe, file_o, vcvars.kernel32, vcvars.msvcrt, lib_args
    );

  if(system(ld_cmd) == -1)
  {
    errorf(NULL, "unable to link");
    pool_free_size(ld_len, ld_cmd);
    return false;
  }

  pool_free_size(ld_len, ld_cmd);
#endif

  return true;
}
Esempio n. 6
0
static bool link_exe(compile_t* c, ast_t* program,
  const char* file_o)
{
  errors_t* errors = c->opt->check.errors;

  const char* ponyrt = c->opt->runtimebc ? "" :
#if defined(PLATFORM_IS_WINDOWS)
    "ponyrt.lib";
#elif defined(PLATFORM_IS_LINUX)
    c->opt->pic ? "-lponyrt-pic" : "-lponyrt";
#else
    "-lponyrt";
#endif

#if defined(PLATFORM_IS_MACOSX)
  char* arch = strchr(c->opt->triple, '-');

  if(arch == NULL)
  {
    errorf(errors, NULL, "couldn't determine architecture from %s",
      c->opt->triple);
    return false;
  }

  const char* file_exe =
    suffix_filename(c, c->opt->output, "", c->filename, "");

  if(c->opt->verbosity >= VERBOSITY_MINIMAL)
    fprintf(stderr, "Linking %s\n", file_exe);

  program_lib_build_args(program, c->opt, "-L", NULL, "", "", "-l", "");
  const char* lib_args = program_lib_args(program);

  size_t arch_len = arch - c->opt->triple;
  size_t ld_len = 128 + arch_len + strlen(file_exe) + strlen(file_o) +
    strlen(lib_args);
  char* ld_cmd = (char*)ponyint_pool_alloc_size(ld_len);
  const char* linker = c->opt->linker != NULL ? c->opt->linker
                                              : "ld";

  snprintf(ld_cmd, ld_len,
    "%s -execute -no_pie -dead_strip -arch %.*s "
    "-macosx_version_min 10.8 -o %s %s %s %s -lSystem",
           linker, (int)arch_len, c->opt->triple, file_exe, file_o,
           lib_args, ponyrt
    );

  if(c->opt->verbosity >= VERBOSITY_TOOL_INFO)
    fprintf(stderr, "%s\n", ld_cmd);

  if(system(ld_cmd) != 0)
  {
    errorf(errors, NULL, "unable to link: %s", ld_cmd);
    ponyint_pool_free_size(ld_len, ld_cmd);
    return false;
  }

  ponyint_pool_free_size(ld_len, ld_cmd);

  if(!c->opt->strip_debug)
  {
    size_t dsym_len = 16 + strlen(file_exe);
    char* dsym_cmd = (char*)ponyint_pool_alloc_size(dsym_len);

    snprintf(dsym_cmd, dsym_len, "rm -rf %s.dSYM", file_exe);
    system(dsym_cmd);

    snprintf(dsym_cmd, dsym_len, "dsymutil %s", file_exe);

    if(system(dsym_cmd) != 0)
      errorf(errors, NULL, "unable to create dsym");

    ponyint_pool_free_size(dsym_len, dsym_cmd);
  }

#elif defined(PLATFORM_IS_LINUX) || defined(PLATFORM_IS_FREEBSD)
  const char* file_exe =
    suffix_filename(c, c->opt->output, "", c->filename, "");

  if(c->opt->verbosity >= VERBOSITY_MINIMAL)
    fprintf(stderr, "Linking %s\n", file_exe);

  program_lib_build_args(program, c->opt, "-L", "-Wl,-rpath,",
    "-Wl,--start-group ", "-Wl,--end-group ", "-l", "");
  const char* lib_args = program_lib_args(program);

  const char* arch = c->opt->link_arch != NULL ? c->opt->link_arch : PONY_ARCH;
  bool fallback_linker = false;
  const char* linker = c->opt->linker != NULL ? c->opt->linker :
    env_cc_or_pony_compiler(&fallback_linker);

  if((c->opt->verbosity >= VERBOSITY_MINIMAL) && fallback_linker)
  {
    fprintf(stderr,
      "Warning: environment variable $CC undefined, using %s as the linker\n",
      PONY_COMPILER);
  }
  const char* mcx16_arg = target_is_ilp32(c->opt->triple) ? "" : "-mcx16";
  const char* fuseld = target_is_linux(c->opt->triple) ? "-fuse-ld=gold " : "";
  const char* ldl = target_is_linux(c->opt->triple) ? "-ldl  " : "";

  size_t ld_len = 512 + strlen(file_exe) + strlen(file_o) + strlen(lib_args)
                  + strlen(arch) + strlen(mcx16_arg) + strlen(fuseld)
                  + strlen(ldl);

  char* ld_cmd = (char*)ponyint_pool_alloc_size(ld_len);

  snprintf(ld_cmd, ld_len, "%s -o %s -O3 -march=%s "
    "%s "
#ifdef PONY_USE_LTO
    "-flto -fuse-linker-plugin "
#endif
    "%s %s %s %s -lpthread %s "
    "-lm",
    linker, file_exe, arch, mcx16_arg, fuseld, file_o, lib_args, ponyrt, ldl
    );

  if(c->opt->verbosity >= VERBOSITY_TOOL_INFO)
    fprintf(stderr, "%s\n", ld_cmd);

  if(system(ld_cmd) != 0)
  {
    errorf(errors, NULL, "unable to link: %s", ld_cmd);
    ponyint_pool_free_size(ld_len, ld_cmd);
    return false;
  }

  ponyint_pool_free_size(ld_len, ld_cmd);
#elif defined(PLATFORM_IS_WINDOWS)
  vcvars_t vcvars;

  if(!vcvars_get(&vcvars, errors))
  {
    errorf(errors, NULL, "unable to link: no vcvars");
    return false;
  }

  const char* file_exe = suffix_filename(c, c->opt->output, "", c->filename,
    ".exe");
  if(c->opt->verbosity >= VERBOSITY_MINIMAL)
    fprintf(stderr, "Linking %s\n", file_exe);

  program_lib_build_args(program, c->opt,
    "/LIBPATH:", NULL, "", "", "", ".lib");
  const char* lib_args = program_lib_args(program);

  char ucrt_lib[MAX_PATH + 12];
  if (strlen(vcvars.ucrt) > 0)
    snprintf(ucrt_lib, MAX_PATH + 12, "/LIBPATH:\"%s\"", vcvars.ucrt);
  else
    ucrt_lib[0] = '\0';

  size_t ld_len = 256 + strlen(file_exe) + strlen(file_o) +
    strlen(vcvars.kernel32) + strlen(vcvars.msvcrt) + strlen(lib_args);
  char* ld_cmd = (char*)ponyint_pool_alloc_size(ld_len);

  while (true)
  {
    int num_written = snprintf(ld_cmd, ld_len,
      "cmd /C \"\"%s\" /DEBUG /NOLOGO /MACHINE:X64 "
      "/OUT:%s "
      "%s %s "
      "/LIBPATH:\"%s\" "
      "/LIBPATH:\"%s\" "
      "%s %s %s \"",
      vcvars.link, file_exe, file_o, ucrt_lib, vcvars.kernel32, 
      vcvars.msvcrt, lib_args, vcvars.default_libs, ponyrt
    );

    if (num_written < ld_len)
      break;

    ponyint_pool_free_size(ld_len, ld_cmd);
    ld_len += 256;
    ld_cmd = (char*)ponyint_pool_alloc_size(ld_len);
  }

  if(c->opt->verbosity >= VERBOSITY_TOOL_INFO)
    fprintf(stderr, "%s\n", ld_cmd);

  if (system(ld_cmd) == -1)
  {
    errorf(errors, NULL, "unable to link: %s", ld_cmd);
    ponyint_pool_free_size(ld_len, ld_cmd);
    return false;
  }

  ponyint_pool_free_size(ld_len, ld_cmd);
#endif

  return true;
}
Esempio n. 7
0
const char* genobj(compile_t* c)
{
  errors_t* errors = c->opt->check.errors;

  /*
   * Could store the pony runtime as a bitcode file. Build an executable by
   * amalgamating the program and the runtime.
   *
   * For building a library, could generate a .o without the runtime in it. The
   * user then has to link both the .o and the runtime. Would need a flag for
   * PIC or not PIC. Could even generate a .a and maybe a .so/.dll.
   */
  if(c->opt->limit == PASS_LLVM_IR)
  {
    const char* file_o = suffix_filename(c, c->opt->output, "", c->filename,
      ".ll");
    PONY_LOG(c->opt, VERBOSITY_MINIMAL, ("Writing %s\n", file_o));

    char* err;

    if(LLVMPrintModuleToFile(c->module, file_o, &err) != 0)
    {
      errorf(errors, NULL, "couldn't write IR to %s: %s", file_o, err);
      LLVMDisposeMessage(err);
      return NULL;
    }

    return file_o;
  }

  if(c->opt->limit == PASS_BITCODE)
  {
    const char* file_o = suffix_filename(c, c->opt->output, "", c->filename,
      ".bc");
    PONY_LOG(c->opt, VERBOSITY_MINIMAL, ("Writing %s\n", file_o));

    if(LLVMWriteBitcodeToFile(c->module, file_o) != 0)
    {
      errorf(errors, NULL, "couldn't write bitcode to %s", file_o);
      return NULL;
    }

    return file_o;
  }

  LLVMCodeGenFileType fmt;
  const char* file_o;

  if(c->opt->limit == PASS_ASM)
  {
    fmt = LLVMAssemblyFile;
    file_o = suffix_filename(c, c->opt->output, "", c->filename, ".s");
  } else {
    fmt = LLVMObjectFile;
#ifdef PLATFORM_IS_WINDOWS
    file_o = suffix_filename(c, c->opt->output, "", c->filename, ".obj");
#else
    file_o = suffix_filename(c, c->opt->output, "", c->filename, ".o");
#endif
  }

  PONY_LOG(c->opt, VERBOSITY_MINIMAL, ("Writing %s\n", file_o));
  char* err;

  if(LLVMTargetMachineEmitToFile(
      c->machine, c->module, (char*)file_o, fmt, &err) != 0
    )
  {
    errorf(errors, NULL, "couldn't create file: %s", err);
    LLVMDisposeMessage(err);
    return NULL;
  }

  return file_o;
}
Esempio n. 8
0
static bool link_exe(compile_t* c, ast_t* program,
  const char* file_o)
{
  errors_t* errors = c->opt->check.errors;

#if defined(PLATFORM_IS_MACOSX)
  char* arch = strchr(c->opt->triple, '-');

  if(arch == NULL)
  {
    errorf(errors, NULL, "couldn't determine architecture from %s",
      c->opt->triple);
    return false;
  }

  const char* file_exe =
    suffix_filename(c, c->opt->output, "", c->filename, "");

  if(c->opt->verbosity >= VERBOSITY_MINIMAL)
    fprintf(stderr, "Linking %s\n", file_exe);

  program_lib_build_args(program, c->opt, "-L", NULL, "", "", "-l", "");
  const char* lib_args = program_lib_args(program);

  size_t arch_len = arch - c->opt->triple;
  size_t ld_len = 128 + arch_len + strlen(file_exe) + strlen(file_o) +
    strlen(lib_args);
  char* ld_cmd = (char*)ponyint_pool_alloc_size(ld_len);

  // Avoid incorrect ld, eg from macports.
  snprintf(ld_cmd, ld_len,
    "/usr/bin/ld -execute -no_pie -dead_strip -arch %.*s "
    "-macosx_version_min 10.8 -o %s %s %s -lponyrt -lSystem",
    (int)arch_len, c->opt->triple, file_exe, file_o, lib_args
    );

  if(c->opt->verbosity >= VERBOSITY_TOOL_INFO)
    fprintf(stderr, "%s\n", ld_cmd);

  if(system(ld_cmd) != 0)
  {
    errorf(errors, NULL, "unable to link: %s", ld_cmd);
    ponyint_pool_free_size(ld_len, ld_cmd);
    return false;
  }

  ponyint_pool_free_size(ld_len, ld_cmd);

  if(!c->opt->strip_debug)
  {
    size_t dsym_len = 16 + strlen(file_exe);
    char* dsym_cmd = (char*)ponyint_pool_alloc_size(dsym_len);

    snprintf(dsym_cmd, dsym_len, "rm -rf %s.dSYM", file_exe);
    system(dsym_cmd);

    snprintf(dsym_cmd, dsym_len, "dsymutil %s", file_exe);

    if(system(dsym_cmd) != 0)
      errorf(errors, NULL, "unable to create dsym");

    ponyint_pool_free_size(dsym_len, dsym_cmd);
  }

#elif defined(PLATFORM_IS_LINUX) || defined(PLATFORM_IS_FREEBSD)
  const char* file_exe =
    suffix_filename(c, c->opt->output, "", c->filename, "");

  if(c->opt->verbosity >= VERBOSITY_MINIMAL)
    fprintf(stderr, "Linking %s\n", file_exe);

  program_lib_build_args(program, c->opt, "-L", "-Wl,-rpath,",
    "-Wl,--start-group ", "-Wl,--end-group ", "-l", "");
  const char* lib_args = program_lib_args(program);

  size_t ld_len = 512 + strlen(file_exe) + strlen(file_o) + strlen(lib_args);
  char* ld_cmd = (char*)ponyint_pool_alloc_size(ld_len);

  snprintf(ld_cmd, ld_len, PONY_COMPILER " -o %s -O3 -march=" PONY_ARCH " "
#ifndef PLATFORM_IS_ILP32
    "-mcx16 "
#endif

#ifdef PONY_USE_LTO
    "-flto -fuse-linker-plugin "
#endif

#ifdef PLATFORM_IS_LINUX
    "-fuse-ld=gold "
#endif
    "%s %s -lponyrt -lpthread "
#ifdef PLATFORM_IS_LINUX
    "-ldl "
#endif
    "-lm",
    file_exe, file_o, lib_args
    );

  if(c->opt->verbosity >= VERBOSITY_TOOL_INFO)
    fprintf(stderr, "%s\n", ld_cmd);

  if(system(ld_cmd) != 0)
  {
    errorf(errors, NULL, "unable to link: %s", ld_cmd);
    ponyint_pool_free_size(ld_len, ld_cmd);
    return false;
  }

  ponyint_pool_free_size(ld_len, ld_cmd);
#elif defined(PLATFORM_IS_WINDOWS)
  vcvars_t vcvars;

  if(!vcvars_get(&vcvars, errors))
  {
    errorf(errors, NULL, "unable to link: no vcvars");
    return false;
  }

  const char* file_exe = suffix_filename(c, c->opt->output, "", c->filename,
    ".exe");
  if(c->opt->verbosity >= VERBOSITY_MINIMAL)
    fprintf(stderr, "Linking %s\n", file_exe);

  program_lib_build_args(program, c->opt,
    "/LIBPATH:", NULL, "", "", "", ".lib");
  const char* lib_args = program_lib_args(program);

  size_t ld_len = 256 + strlen(file_exe) + strlen(file_o) +
    strlen(vcvars.kernel32) + strlen(vcvars.msvcrt) + strlen(lib_args);
  char* ld_cmd = (char*)ponyint_pool_alloc_size(ld_len);

  while (true)
  {
    int num_written = snprintf(ld_cmd, ld_len,
      "cmd /C \"\"%s\" /DEBUG /NOLOGO /MACHINE:X64 "
      "/OUT:%s "
      "%s "
      "/LIBPATH:\"%s\" "
      "/LIBPATH:\"%s\" "
      "%s kernel32.lib msvcrt.lib Ws2_32.lib vcruntime.lib legacy_stdio_definitions.lib ponyrt.lib \"",
      vcvars.link, file_exe, file_o, vcvars.kernel32, vcvars.msvcrt, lib_args
    );

    if (num_written < ld_len)
      break;

    ponyint_pool_free_size(ld_len, ld_cmd);
    ld_len += 256;
    ld_cmd = (char*)ponyint_pool_alloc_size(ld_len);
  }

  if(c->opt->verbosity >= VERBOSITY_TOOL_INFO)
    fprintf(stderr, "%s\n", ld_cmd);

  if (system(ld_cmd) == -1)
  {
    errorf(errors, NULL, "unable to link: %s", ld_cmd);
    ponyint_pool_free_size(ld_len, ld_cmd);
    return false;
  }

  ponyint_pool_free_size(ld_len, ld_cmd);
#endif

  return true;
}