/* Ensure that the directories we need exist and are empty. * * Our base directory has the name: * output/progname-docs/ * where output/progname is the executable we are producing (without any * extension). * * Within this base directory we have the following: * mkdocs.yml * docs/ * *.md */ static void doc_setup_dirs(docgen_t* docgen, ast_t* program, pass_opt_t* opt) { assert(docgen != NULL); assert(program != NULL); assert(opt != NULL); // First build our directory strings const char* output = opt->output; const char* progname = package_filename(ast_child(program)); docgen->base_dir = doc_cat(output, "/", progname, "-docs/", "", &docgen->base_dir_buf_len); docgen->sub_dir = doc_cat(docgen->base_dir, "docs/", "", "", "", &docgen->sub_dir_buf_len); PONY_LOG(opt, VERBOSITY_INFO, ("Writing docs to %s\n", docgen->base_dir)); // Create and clear out base directory pony_mkdir(docgen->base_dir); doc_rm_star(docgen->base_dir); // Create and clear out sub directory pony_mkdir(docgen->sub_dir); doc_rm_star(docgen->sub_dir); }
bool codegen(ast_t* program, pass_opt_t* opt) { PONY_LOG(opt, VERBOSITY_MINIMAL, ("Generating\n")); pony_mkdir(opt->output); compile_t c; memset(&c, 0, sizeof(compile_t)); init_module(&c, program, opt); init_runtime(&c); genprim_reachable_init(&c, program); bool ok; if(c.opt->library) ok = genlib(&c, program); else ok = genexe(&c, program); codegen_cleanup(&c); return ok; }
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; }
bool gentypes(compile_t* c) { reachable_type_t* t; size_t i; genprim_builtins(c); PONY_LOG(c->opt, VERBOSITY_INFO, (" Data prototypes\n")); i = HASHMAP_BEGIN; while((t = reachable_types_next(&c->reachable->types, &i)) != NULL) { if(!make_opaque_struct(c, t)) return false; gendesc_type(c, t); make_debug_info(c, t); make_box_type(c, t); make_dispatch(c, t); gentrace_prototype(c, t); } PONY_LOG(c->opt, VERBOSITY_INFO, (" Data types\n")); i = HASHMAP_BEGIN; while((t = reachable_types_next(&c->reachable->types, &i)) != NULL) { if(!make_struct(c, t)) return false; make_global_instance(c, t); } PONY_LOG(c->opt, VERBOSITY_INFO, (" Function prototypes\n")); i = HASHMAP_BEGIN; while((t = reachable_types_next(&c->reachable->types, &i)) != NULL) { make_debug_final(c, t); make_pointer_methods(c, t); if(!genfun_method_sigs(c, t)) return false; } PONY_LOG(c->opt, VERBOSITY_INFO, (" Functions\n")); i = HASHMAP_BEGIN; while((t = reachable_types_next(&c->reachable->types, &i)) != NULL) { if(!genfun_method_bodies(c, t)) return false; } PONY_LOG(c->opt, VERBOSITY_INFO, (" Descriptors\n")); i = HASHMAP_BEGIN; while((t = reachable_types_next(&c->reachable->types, &i)) != NULL) { if(!make_trace(c, t)) return false; gendesc_init(c, t); } return true; }
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, ""); PONY_LOG(c->opt, VERBOSITY_DEFAULT, ("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*)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 ); PONY_LOG(c->opt, VERBOSITY_TOOL_INFO, ("%s\n", ld_cmd)); if(system(ld_cmd) != 0) { errorf(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(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->opt->output, "", c->filename, ""); PONY_LOG(c->opt, VERBOSITY_DEFAULT, ("Linking %s\n", file_exe)); program_lib_build_args(program, "-L", "-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 ); PONY_LOG(c->opt, VERBOSITY_TOOL_INFO, ("%s\n", ld_cmd)); if(system(ld_cmd) != 0) { errorf(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)) { errorf(NULL, "unable to link: no vcvars"); return false; } const char* file_exe = suffix_filename(c->opt->output, "", c->filename, ".exe"); PONY_LOG(c->opt, VERBOSITY_DEFAULT, ("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*)ponyint_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 ); PONY_LOG(c->opt, VERBOSITY_TOOL_INFO, ("%s\n", ld_cmd)); if(system(ld_cmd) == -1) { errorf(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; }