diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs index 2ae7b6a6fab..6469bbd3ced 100644 --- a/src/comp/back/link.rs +++ b/src/comp/back/link.rs @@ -1,8 +1,18 @@ import driver::session; import lib::llvm::llvm; import middle::trans; +import middle::metadata; +import middle::ty; import std::str; import std::fs; +import std::vec; +import std::option; +import option::some; +import option::none; +import std::sha1::sha1; +import std::sort; +import trans::crate_ctxt; +import front::ast; import lib::llvm::llvm::ModuleRef; import lib::llvm::llvm::ValueRef; @@ -49,7 +59,7 @@ fn link_intrinsics(session::session sess, ModuleRef llmod) { auto linkres = llvm::LLVMLinkModules(llmod, llintrinsicsmod); llvm::LLVMDisposeModule(llintrinsicsmod); - + if (linkres == False) { llvm_err(sess, "couldn't link the module with the intrinsics"); fail; @@ -58,7 +68,7 @@ fn link_intrinsics(session::session sess, ModuleRef llmod) { mod write { fn is_object_or_assembly_or_exe(output_type ot) -> bool { - if ( (ot == output_type_assembly) || + if ( (ot == output_type_assembly) || (ot == output_type_object) || (ot == output_type_exe) ) { ret true; @@ -218,3 +228,235 @@ mod write { } } +/* + * Name mangling and its relationship to metadata. This is complex. Read + * carefully. + * + * The semantic model of Rust linkage is, broadly, that "there's no global + * namespace" between crates. Our aim is to preserve the illusion of this + * model despite the fact that it's not *quite* possible to implement on + * modern linkers. We initially didn't use system linkers at all, but have + * been convinced of their utility. + * + * There are a few issues to handle: + * + * - Linkers operate on a flat namespace, so we have to flatten names. + * We do this using the C++ namespace-mangling technique. Foo::bar + * symbols and such. + * + * - Symbols with the same name but different types need to get different + * linkage-names. We do this by hashing a string-encoding of the type into + * a fixed-size (currently 16-byte hex) cryptographic hash function (CHF: + * we use SHA1) to "prevent collisions". This is not airtight but 16 hex + * digits on uniform probability means you're going to need 2**32 same-name + * symbols in the same process before you're even hitting birthday-paradox + * collision probability. + * + * - Symbols in dirrerent crates but with same names "within" the crate need + * to get different linkage-names. + * + * So here is what we do: + * + * - Separate the meta tags into two sets: exported and local. Only work with + * the exported ones when considering linkage. + * + * - Consider two exported tags as special (and madatory): name and vers. + * Every crate gets them; if it doesn't name them explicitly we infer them + * as basename(crate) and "0.1", respectively. Call these CNAME, CVERS. + * + * - Define CMETA as all the non-name, non-vers exported meta tags in the + * crate (in sorted order). + * + * - Define CMH as hash(CMETA). + * + * - Compile our crate to lib CNAME-CMH-CVERS.so + * + * - Define STH(sym) as hash(CNAME, CMH, type_str(sym)) + * + * - Suffix a mangled sym with ::STH@CVERS, so that it is unique in the + * name, non-name metadata, and type sense, and versioned in the way + * system linkers understand. + * + */ + + +iter crate_export_metas(ast::crate c) -> @ast::meta_item { + for (@ast::crate_directive cdir in c.node.directives) { + alt (cdir.node) { + case (ast::cdir_meta(?v, ?mis)) { + if (v == ast::export_meta) { + for (@ast::meta_item mi in mis) { + put mi; + } + } + } + case (_) {} + } + } +} +fn get_crate_meta(&session::session sess, + &ast::crate c, str k, str default, + bool warn_default) -> str { + let vec[@ast::meta_item] v = []; + for each (@ast::meta_item mi in crate_export_metas(c)) { + if (mi.node.name == k) { + v += [mi]; + } + } + alt (vec::len(v)) { + case (0u) { + if (warn_default) { + sess.warn(#fmt("missing meta '%s', using '%s' as default", + k, default)); + } + ret default; + } + case (1u) { + ret v.(0).node.value; + } + case (_) { + sess.span_err(v.(1).span, #fmt("duplicate meta '%s'", k)); + } + } +} + +// This calculates CMH as defined above +fn crate_meta_extras_hash(sha1 sha, &ast::crate crate) -> str { + fn lteq(&@ast::meta_item ma, + &@ast::meta_item mb) -> bool { + ret ma.node.name <= mb.node.name; + } + + fn len_and_str(&str s) -> str { + ret #fmt("%u_%s", str::byte_len(s), s); + } + + let vec[mutable @ast::meta_item] v = [mutable]; + for each (@ast::meta_item mi in crate_export_metas(crate)) { + if (mi.node.name != "name" && + mi.node.name != "vers") { + v += [mutable mi]; + } + } + sort::quick_sort(lteq, v); + sha.reset(); + for (@ast::meta_item m in v) { + sha.input_str(len_and_str(m.node.name)); + sha.input_str(len_and_str(m.node.value)); + } + ret truncated_sha1_result(sha); +} + +fn crate_meta_name(&session::session sess, &ast::crate crate, + &str output) -> str { + auto os = str::split(fs::basename(output), '.' as u8); + assert vec::len(os) >= 2u; + vec::pop(os); + ret get_crate_meta(sess, crate, "name", str::connect(os, "."), + sess.get_opts().shared); +} + +fn crate_meta_vers(&session::session sess, &ast::crate crate) -> str { + ret get_crate_meta(sess, crate, "vers", "0.0", + sess.get_opts().shared); +} + +fn truncated_sha1_result(sha1 sha) -> str { + ret str::substr(sha.result_str(), 0u, 16u); +} + + + +// This calculates STH for a symbol, as defined above +fn symbol_hash(ty::ctxt tcx, sha1 sha, &ty::t t, + str crate_meta_name, + str crate_meta_extras_hash) -> str { + // NB: do *not* use abbrevs here as we want the symbol names + // to be independent of one another in the crate. + auto cx = @rec(ds=metadata::def_to_str, tcx=tcx, + abbrevs=metadata::ac_no_abbrevs); + sha.reset(); + sha.input_str(crate_meta_name); + sha.input_str("-"); + sha.input_str(crate_meta_name); + sha.input_str("-"); + sha.input_str(metadata::Encode::ty_str(cx, t)); + auto hash = truncated_sha1_result(sha); + // Prefix with _ so that it never blends into adjacent digits + ret "_" + hash; +} + +fn get_symbol_hash(&@crate_ctxt ccx, &ty::t t) -> str { + auto hash = ""; + alt (ccx.type_sha1s.find(t)) { + case (some(?h)) { hash = h; } + case (none) { + hash = symbol_hash(ccx.tcx, ccx.sha, t, + ccx.crate_meta_name, + ccx.crate_meta_extras_hash); + ccx.type_sha1s.insert(t, hash); + } + } + ret hash; +} + + +fn mangle(&vec[str] ss) -> str { + + // Follow C++ namespace-mangling style + + auto n = "_ZN"; // Begin name-sequence. + + for (str s in ss) { + n += #fmt("%u%s", str::byte_len(s), s); + } + + n += "E"; // End name-sequence. + ret n; +} + + +fn exported_name(&vec[str] path, &str hash, &str vers) -> str { + // FIXME: versioning isn't working yet + ret mangle(path + [hash]); // + "@" + vers; +} + +fn mangle_exported_name(&@crate_ctxt ccx, &vec[str] path, + &ty::t t) -> str { + auto hash = get_symbol_hash(ccx, t); + ret exported_name(path, hash, ccx.crate_meta_vers); +} + +fn mangle_internal_name_by_type_only(&@crate_ctxt ccx, &ty::t t, + &str name) -> str { + auto f = metadata::def_to_str; + auto cx = @rec(ds=f, tcx=ccx.tcx, abbrevs=metadata::ac_no_abbrevs); + auto s = ty::ty_to_short_str(ccx.tcx, t); + + auto hash = get_symbol_hash(ccx, t); + ret mangle([name, s, hash]); +} + +fn mangle_internal_name_by_path_and_seq(&@crate_ctxt ccx, &vec[str] path, + &str flav) -> str { + ret mangle(path + [ccx.names.next(flav)]); +} + +fn mangle_internal_name_by_path(&@crate_ctxt ccx, &vec[str] path) -> str { + ret mangle(path); +} + +fn mangle_internal_name_by_seq(&@crate_ctxt ccx, &str flav) -> str { + ret ccx.names.next(flav); +} + +// +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: +// diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs index 9f025849402..e0080ca2651 100644 --- a/src/comp/driver/session.rs +++ b/src/comp/driver/session.rs @@ -6,6 +6,9 @@ import std::uint; import std::term; import std::io; import std::map; +import std::option; +import std::option::some; +import std::option::none; tag os { os_win32; @@ -48,9 +51,16 @@ fn span_to_str(span sp, codemap::codemap cm) -> str { lo.col, hi.line, hi.col)); } -fn emit_diagnostic(span sp, str msg, str kind, u8 color, +fn emit_diagnostic(option::t[span] sp, str msg, str kind, u8 color, codemap::codemap cm) { - io::stdout().write_str(span_to_str(sp, cm) + ": "); + auto ss = ":0:0:0:0"; + alt (sp) { + case (some(?ssp)) { + ss = span_to_str(ssp, cm); + } + case (none) {} + } + io::stdout().write_str(ss + ": "); if (term::color_supported()) { term::fg(io::stdout().get_buf_writer(), color); @@ -85,12 +95,12 @@ state obj session(ast::crate_num cnum, fn span_err(span sp, str msg) -> ! { // FIXME: Use constants, but rustboot doesn't know how to export them. - emit_diagnostic(sp, msg, "error", 9u8, cm); + emit_diagnostic(some(sp), msg, "error", 9u8, cm); fail; } fn err(str msg) -> ! { - log_err #fmt("error: %s", msg); + emit_diagnostic(none[span], msg, "error", 9u8, cm); fail; } @@ -103,29 +113,32 @@ state obj session(ast::crate_num cnum, fn span_warn(span sp, str msg) { // FIXME: Use constants, but rustboot doesn't know how to export them. - emit_diagnostic(sp, msg, "warning", 11u8, cm); + emit_diagnostic(some(sp), msg, "warning", 11u8, cm); + } + + fn warn(str msg) { + emit_diagnostic(none[span], msg, "warning", 11u8, cm); } fn span_note(span sp, str msg) { // FIXME: Use constants, but rustboot doesn't know how to export them. - emit_diagnostic(sp, msg, "note", 10u8, cm); + emit_diagnostic(some(sp), msg, "note", 10u8, cm); + } + + fn span_bug(span sp, str msg) -> ! { + self.span_err(sp, #fmt("internal compiler error %s", msg)); } fn bug(str msg) -> ! { - log_err #fmt("error: internal compiler error %s", msg); - fail; + self.err(#fmt("internal compiler error %s", msg)); } fn span_unimpl(span sp, str msg) -> ! { - // FIXME: Use constants, but rustboot doesn't know how to export them. - emit_diagnostic(sp, "internal compiler error: unimplemented " + msg, - "error", 9u8, cm); - fail; + self.span_bug(sp, "unimplemented " + msg); } - + fn unimpl(str msg) -> ! { - log_err #fmt("error: unimplemented %s", msg); - fail; + self.bug("unimplemented " + msg); } fn get_external_crate(int num) -> crate_metadata { diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index 92f12c3dc1b..f670c2760a7 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -71,6 +71,11 @@ type crate = spanned[crate_]; type crate_ = rec(vec[@crate_directive] directives, _mod module); +tag meta_visibility { + export_meta; + local_meta; +} + tag crate_directive_ { cdir_expr(@expr); // FIXME: cdir_let should be eliminated @@ -80,7 +85,7 @@ tag crate_directive_ { cdir_src_mod(ident, option::t[filename]); cdir_dir_mod(ident, option::t[filename], vec[@crate_directive]); cdir_view_item(@view_item); - cdir_meta(vec[@meta_item]); + cdir_meta(meta_visibility, vec[@meta_item]); cdir_syntax(path); cdir_auth(path, _auth); } diff --git a/src/comp/front/eval.rs b/src/comp/front/eval.rs index d5a76372846..a8e881ee036 100644 --- a/src/comp/front/eval.rs +++ b/src/comp/front/eval.rs @@ -418,8 +418,13 @@ fn eval_crate_directive(ctx cx, vec::push[@ast::view_item](view_items, vi); } - case (ast::cdir_meta(?mi)) { - cx.sess.add_metadata(mi); + case (ast::cdir_meta(?vi, ?mi)) { + // FIXME: we should actually record, for documentation-sake, + // the metadata that's not exported. It would be nice to have + // compiled-in to the target crate, not just in theh AST. + if (vi == ast::export_meta) { + cx.sess.add_metadata(mi); + } } case (ast::cdir_syntax(?pth)) {} diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 62ba7325f99..b84a740a917 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -2362,10 +2362,14 @@ fn parse_crate_directive(&parser p) -> ast::crate_directive expect(p, token::SEMI); ret spanned(lo, hi, ast::cdir_auth(n, a)); } else if (eat_word(p, "meta")) { + auto mv = ast::local_meta; + if (eat_word(p, "export")) { + mv = ast::export_meta; + } auto mis = parse_meta(p); auto hi = p.get_hi_pos(); expect(p, token::SEMI); - ret spanned(lo, hi, ast::cdir_meta(mis)); + ret spanned(lo, hi, ast::cdir_meta(mv, mis)); } else if (eat_word(p, "mod")) { auto id = parse_ident(p); auto file_opt = none[filename]; diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 7333375b902..1687a62fa57 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -6,7 +6,7 @@ // particular definition to the LLVM IR output we're producing. // // Hopefully useful general knowledge about trans: -// +// // * There's no way to find out the ty::t type of a ValueRef. Doing so // would be "trying to get the eggs out of an omelette" (credit: // pcwalton). You can, instead, find out its TypeRef by calling val_ty, @@ -24,6 +24,7 @@ import std::map::hashmap; import std::option; import std::option::some; import std::option::none; +import std::fs; import front::ast; import front::creader; @@ -62,6 +63,15 @@ import lib::llvm::False; import lib::llvm::True; import lib::llvm::Bool; +import link::mangle_internal_name_by_type_only; +import link::mangle_internal_name_by_seq; +import link::mangle_internal_name_by_path; +import link::mangle_internal_name_by_path_and_seq; +import link::mangle_exported_name; +import link::crate_meta_name; +import link::crate_meta_vers; +import link::crate_meta_extras_hash; + state obj namegen(mutable int i) { fn next(str prefix) -> str { i += 1; @@ -119,6 +129,9 @@ state type crate_ctxt = rec(session::session sess, @ast::native_item] native_items, hashmap[ast::def_id, str] item_symbols, mutable option::t[ValueRef] main_fn, + str crate_meta_name, + str crate_meta_vers, + str crate_meta_extras_hash, // TODO: hashmap[tup(tag_id,subtys), @tag_info] hashmap[ty::t, uint] tag_sizes, hashmap[ast::def_id, ValueRef] discrims, @@ -166,14 +179,14 @@ type fn_ctxt = rec( ValueRef lltaskptr, ValueRef llenv, ValueRef llretptr, - + // The next three elements: "hoisted basic blocks" containing // administrative activities that have to happen in only one place in the // function, due to LLVM's quirks. // A block for all the function's allocas, so that LLVM will coalesce them // into a single alloca call. - mutable BasicBlockRef llallocas, + mutable BasicBlockRef llallocas, // A block containing code that copies incoming arguments to space already // allocated by code in the llallocas block. (LLVM requires that @@ -313,73 +326,6 @@ fn extend_path(@local_ctxt cx, &str name) -> @local_ctxt { ret @rec(path = cx.path + [name] with *cx); } -fn get_type_sha1(&@crate_ctxt ccx, &ty::t t) -> str { - auto hash = ""; - alt (ccx.type_sha1s.find(t)) { - case (some(?h)) { hash = h; } - case (none) { - ccx.sha.reset(); - auto f = metadata::def_to_str; - // NB: do *not* use abbrevs here as we want the symbol names - // to be independent of one another in the crate. - auto cx = @rec(ds=f, - tcx=ccx.tcx, - abbrevs=metadata::ac_no_abbrevs); - - ccx.sha.input_str(metadata::Encode::ty_str(cx, t)); - hash = str::substr(ccx.sha.result_str(), 0u, 16u); - // Prefix with _ so that it never blends into adjacent digits - hash = "_" + hash; - ccx.type_sha1s.insert(t, hash); - } - } - ret hash; -} - -fn mangle(&vec[str] ss) -> str { - - if (vec::len(ss) > 0u && str::eq(vec::top(ss), "main")) { - ret "_rust_main"; - } - // Follow C++ namespace-mangling style - - auto n = "_ZN"; // Begin name-sequence. - - for (str s in ss) { - n += #fmt("%u%s", str::byte_len(s), s); - } - - n += "E"; // End name-sequence. - ret n; -} - -fn mangle_name_by_type(&@crate_ctxt ccx, &vec[str] path, &ty::t t) -> str { - auto hash = get_type_sha1(ccx, t); - ret mangle(path + [hash]); -} - -fn mangle_name_by_type_only(&@crate_ctxt ccx, &ty::t t, &str name) -> str { - auto f = metadata::def_to_str; - auto cx = @rec(ds=f, tcx=ccx.tcx, abbrevs=metadata::ac_no_abbrevs); - auto s = ty::ty_to_short_str(ccx.tcx, t); - - auto hash = get_type_sha1(ccx, t); - ret mangle([name, s, hash]); -} - -fn mangle_name_by_path_and_seq(&@crate_ctxt ccx, &vec[str] path, - &str flav) -> str { - ret mangle(path + [ccx.names.next(flav)]); -} - -fn mangle_name_by_path(&vec[str] path) -> str { - ret mangle(path); -} - -fn mangle_name_by_seq(&@crate_ctxt ccx, &str flav) -> str { - ret ccx.names.next(flav); -} - fn res(@block_ctxt bcx, ValueRef val) -> result { ret rec(bcx = bcx, val = val); @@ -1917,10 +1863,10 @@ fn declare_tydesc(&@local_ctxt cx, &span sp, &ty::t t, auto name; if (cx.ccx.sess.get_opts().debuginfo) { - name = mangle_name_by_type_only(cx.ccx, t, "tydesc"); + name = mangle_internal_name_by_type_only(cx.ccx, t, "tydesc"); name = sanitize(name); } else { - name = mangle_name_by_seq(cx.ccx, "tydesc"); + name = mangle_internal_name_by_seq(cx.ccx, "tydesc"); } auto gvar = llvm::LLVMAddGlobal(ccx.llmod, T_tydesc(ccx.tn), @@ -1951,10 +1897,12 @@ fn declare_generic_glue(&@local_ctxt cx, &str name) -> ValueRef { auto fn_nm; if (cx.ccx.sess.get_opts().debuginfo) { - fn_nm = mangle_name_by_type_only(cx.ccx, t, "glue_" + name); + fn_nm = mangle_internal_name_by_type_only(cx.ccx, t, + "glue_" + name); fn_nm = sanitize(fn_nm); } else { - fn_nm = mangle_name_by_seq(cx.ccx, "glue_" + name); + fn_nm = mangle_internal_name_by_seq(cx.ccx, + "glue_" + name); } auto llfn = decl_fastcall_fn(cx.ccx.llmod, fn_nm, llfnty); set_glue_inlining(cx, llfn, t); @@ -4106,7 +4054,8 @@ fn trans_for_each(&@block_ctxt cx, // Step 2: Declare foreach body function. - let str s = mangle_name_by_path_and_seq(lcx.ccx, lcx.path, "foreach"); + let str s = mangle_internal_name_by_path_and_seq(lcx.ccx, lcx.path, + "foreach"); // The 'env' arg entering the body function is a fake env member (as in // the env-part of the normal rust calling convention) that actually @@ -4805,7 +4754,8 @@ fn trans_bind_thunk(&@local_ctxt cx, // Construct a thunk-call with signature incoming_fty, and that copies // args forward into a call to outgoing_fty: - let str s = mangle_name_by_path_and_seq(cx.ccx, cx.path, "thunk"); + let str s = mangle_internal_name_by_path_and_seq(cx.ccx, cx.path, + "thunk"); let TypeRef llthunk_ty = get_pair_fn_ty(type_of(cx.ccx, sp, incoming_fty)); let ValueRef llthunk = decl_internal_fastcall_fn(cx.ccx.llmod, @@ -5823,13 +5773,17 @@ fn load_if_immediate(&@block_ctxt cx, ValueRef v, &ty::t t) -> ValueRef { fn trans_log(int lvl, &@block_ctxt cx, &@ast::expr e) -> result { auto lcx = cx.fcx.lcx; - auto modname = str::connect(lcx.module_path, "::"); + auto modname = link::mangle_internal_name_by_path(lcx.ccx, + lcx.module_path); auto global; if (lcx.ccx.module_data.contains_key(modname)) { global = lcx.ccx.module_data.get(modname); } else { - global = llvm::LLVMAddGlobal(lcx.ccx.llmod, T_int(), - str::buf("_rust_mod_log_" + modname)); + auto s = + link::mangle_internal_name_by_path_and_seq(lcx.ccx, + lcx.module_path, + "loglevel"); + global = llvm::LLVMAddGlobal(lcx.ccx.llmod, T_int(), str::buf(s)); llvm::LLVMSetGlobalConstant(global, False); llvm::LLVMSetInitializer(global, C_null(T_int())); llvm::LLVMSetLinkage(global, lib::llvm::LLVMInternalLinkage @@ -6225,8 +6179,8 @@ fn trans_spawn(&@block_ctxt cx, ret res(bcx, new_task); } -fn mk_spawn_wrapper(&@block_ctxt cx, - &@ast::expr func, +fn mk_spawn_wrapper(&@block_ctxt cx, + &@ast::expr func, &ty::t args_ty) -> result { auto llmod = cx.fcx.lcx.ccx.llmod; let TypeRef args_ty_tref = type_of(cx.fcx.lcx.ccx, cx.sp, args_ty); @@ -6239,9 +6193,9 @@ fn mk_spawn_wrapper(&@block_ctxt cx, // TODO: construct a name based on tname let str wrap_name = - mangle_name_by_path_and_seq(cx.fcx.lcx.ccx, - cx.fcx.lcx.path, - "spawn_wrapper"); + mangle_internal_name_by_path_and_seq(cx.fcx.lcx.ccx, + cx.fcx.lcx.path, + "spawn_wrapper"); auto llfndecl = decl_fastcall_fn(llmod, wrap_name, wrapper_fn_type); @@ -6252,7 +6206,7 @@ fn mk_spawn_wrapper(&@block_ctxt cx, // 3u to skip the three implicit args let ValueRef arg = llvm::LLVMGetParam(fcx.llfn, 3u); - let vec[ValueRef] child_args = + let vec[ValueRef] child_args = [llvm::LLVMGetParam(fcx.llfn, 0u), llvm::LLVMGetParam(fcx.llfn, 1u), llvm::LLVMGetParam(fcx.llfn, 2u)]; @@ -6271,19 +6225,19 @@ fn mk_spawn_wrapper(&@block_ctxt cx, } } } - + // Find the function auto fnptr = trans_lval(fbcx, func).res; fbcx = fnptr.bcx; - + auto llfnptr = fbcx.build.GEP(fnptr.val, [C_int(0), C_int(0)]); auto llfn = fbcx.build.Load(llfnptr); - + fbcx.build.FastCall(llfn, child_args); fbcx.build.RetVoid(); - + finish_fn(fcx, fbcx.llbb); // TODO: make sure we clean up everything we need to. @@ -6719,7 +6673,7 @@ fn new_local_ctxt(&@crate_ctxt ccx) -> @local_ctxt { let vec[ast::ty_param] obj_typarams = []; let vec[ast::obj_field] obj_fields = []; ret @rec(path=pth, - module_path=[crate_name(ccx, "main")], + module_path=[ccx.crate_meta_name], obj_typarams = obj_typarams, obj_fields = obj_fields, ccx = ccx); @@ -7094,7 +7048,7 @@ fn create_vtbl(@local_ctxt cx, let @local_ctxt mcx = @rec(path = cx.path + ["method", m.node.ident] with *cx); - let str s = mangle_name_by_path(mcx.path); + let str s = mangle_internal_name_by_path(mcx.ccx, mcx.path); let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty); cx.ccx.item_ids.insert(m.node.id, llfn); @@ -7106,7 +7060,8 @@ fn create_vtbl(@local_ctxt cx, methods += [llfn]; } auto vtbl = C_struct(methods); - auto vtbl_name = mangle_name_by_path(cx.path + ["vtbl"]); + auto vtbl_name = mangle_internal_name_by_path(cx.ccx, + cx.path + ["vtbl"]); auto gvar = llvm::LLVMAddGlobal(cx.ccx.llmod, val_ty(vtbl), str::buf(vtbl_name)); llvm::LLVMSetInitializer(gvar, vtbl); @@ -7123,7 +7078,7 @@ fn trans_dtor(@local_ctxt cx, &@ast::method dtor) -> ValueRef { auto llfnty = T_dtor(cx.ccx, dtor.span, llself_ty); - let str s = mangle_name_by_path(cx.path + ["drop"]); + let str s = mangle_internal_name_by_path(cx.ccx, cx.path + ["drop"]); let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty); cx.ccx.item_ids.insert(dtor.node.id, llfn); cx.ccx.item_symbols.insert(dtor.node.id, s); @@ -7516,25 +7471,29 @@ fn decl_fn_and_pair(&@crate_ctxt ccx, &span sp, } } + let bool is_main = (str::eq(vec::top(path), "main") && + !ccx.sess.get_opts().shared); + // Declare the function itself. - let str s = mangle_name_by_path(path); + let str s = + if (is_main) { "_rust_main" } + else { mangle_internal_name_by_path(ccx, path) }; + let ValueRef llfn = decl_internal_fastcall_fn(ccx.llmod, s, llfty); // Declare the global constant pair that points to it. - let str ps = mangle_name_by_type(ccx, path, node_ann_type(ccx, ann)); - + let str ps = mangle_exported_name(ccx, path, node_ann_type(ccx, ann)); register_fn_pair(ccx, ps, llpairty, llfn, id); - if (str::eq(vec::top(path), "main") && - !ccx.sess.get_opts().shared) { + if (is_main) { if (ccx.main_fn != none[ValueRef]) { ccx.sess.span_err(sp, "multiple 'main' functions"); } - log #fmt("registering %s as main function for crate", ps); llvm::LLVMSetLinkage(llfn, lib::llvm::LLVMExternalLinkage as llvm::Linkage); ccx.main_fn = some(llfn); } + } fn register_fn_pair(&@crate_ctxt cx, str ps, TypeRef llpairty, ValueRef llfn, @@ -7565,7 +7524,7 @@ fn native_fn_ty_param_count(&@crate_ctxt cx, &ast::def_id id) -> uint { alt (native_item.node) { case (ast::native_item_ty(_,_)) { cx.sess.bug("decl_native_fn_and_pair(): native fn isn't " + - "actually a fn?!"); + "actually a fn"); } case (ast::native_item_fn(_, _, _, ?tps, _, _)) { count = vec::len[ast::ty_param](tps); @@ -7594,13 +7553,13 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, // Declare the wrapper. auto t = node_ann_type(ccx, ann); auto wrapper_type = native_fn_wrapper_type(ccx, sp, num_ty_param, t); - let str s = mangle_name_by_path(path); + let str s = mangle_internal_name_by_path(ccx, path); let ValueRef wrapper_fn = decl_internal_fastcall_fn(ccx.llmod, s, wrapper_type); // Declare the global constant pair that points to it. auto wrapper_pair_type = T_fn_pair(ccx.tn, wrapper_type); - let str ps = mangle_name_by_type(ccx, path, node_ann_type(ccx, ann)); + let str ps = mangle_exported_name(ccx, path, node_ann_type(ccx, ann)); register_fn_pair(ccx, ps, wrapper_pair_type, wrapper_fn, id); @@ -7938,7 +7897,7 @@ fn trans_constant(&@crate_ctxt ccx, @walk_ctxt wcx, &@ast::item it) { auto discrim_val = C_int(i as int); auto p = wcx.path + [ident, variant.node.name, "discrim"]; - auto s = mangle_name_by_type(ccx, p, ty::mk_int(ccx.tcx)); + auto s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx)); auto discrim_gvar = llvm::LLVMAddGlobal(ccx.llmod, T_int(), str::buf(s)); @@ -7957,8 +7916,8 @@ fn trans_constant(&@crate_ctxt ccx, @walk_ctxt wcx, &@ast::item it) { // with consts. auto v = C_int(1); ccx.item_ids.insert(cid, v); - auto s = mangle_name_by_type(ccx, wcx.path + [name], - node_ann_type(ccx, ann)); + auto s = mangle_exported_name(ccx, wcx.path + [name], + node_ann_type(ccx, ann)); ccx.item_symbols.insert(cid, s); } @@ -8178,15 +8137,6 @@ fn create_module_map(&@crate_ctxt ccx) -> ValueRef { ret map; } -fn crate_name(&@crate_ctxt ccx, &str deflt) -> str { - for (@ast::meta_item item in ccx.sess.get_metadata()) { - if (str::eq(item.node.name, "name")) { - ret item.node.value; - } - } - ret deflt; -} - // FIXME use hashed metadata instead of crate names once we have that fn create_crate_map(&@crate_ctxt ccx) -> ValueRef { let vec[ValueRef] subcrates = []; @@ -8199,10 +8149,9 @@ fn create_crate_map(&@crate_ctxt ccx) -> ValueRef { i += 1; } vec::push[ValueRef](subcrates, C_int(0)); - auto cname = crate_name(ccx, "__none__"); auto mapname; if (ccx.sess.get_opts().shared) { - mapname = cname; + mapname = ccx.crate_meta_name; } else { mapname = "toplevel"; } @@ -8240,7 +8189,7 @@ fn trans_crate(&session::session sess, &@ast::crate crate, auto sha1s = map::mk_hashmap[ty::t,str](hasher, eqer); auto abbrevs = map::mk_hashmap[ty::t,metadata::ty_abbrev](hasher, eqer); auto short_names = map::mk_hashmap[ty::t,str](hasher, eqer); - + auto sha = std::sha1::mk_sha1(); auto ccx = @rec(sess = sess, llmod = llmod, td = td, @@ -8252,6 +8201,10 @@ fn trans_crate(&session::session sess, &@ast::crate crate, native_items = new_def_hash[@ast::native_item](), item_symbols = new_def_hash[str](), mutable main_fn = none[ValueRef], + crate_meta_name = crate_meta_name(sess, *crate, output), + crate_meta_vers = crate_meta_vers(sess, *crate), + crate_meta_extras_hash = + crate_meta_extras_hash(sha, *crate), tag_sizes = tag_sizes, discrims = new_def_hash[ValueRef](), discrim_symbols = new_def_hash[str](), @@ -8263,7 +8216,7 @@ fn trans_crate(&session::session sess, &@ast::crate crate, lltypes = lltypes, glues = glues, names = namegen(0), - sha = std::sha1::mk_sha1(), + sha = sha, type_sha1s = sha1s, type_abbrevs = abbrevs, type_short_names = short_names, diff --git a/src/comp/middle/walk.rs b/src/comp/middle/walk.rs index 426f72d9bed..1ecafe1f02f 100644 --- a/src/comp/middle/walk.rs +++ b/src/comp/middle/walk.rs @@ -68,7 +68,7 @@ fn walk_crate_directive(&ast_visitor v, @ast::crate_directive cd) { case (ast::cdir_view_item(?vi)) { walk_view_item(v, vi); } - case (ast::cdir_meta(_)) {} + case (ast::cdir_meta(_,_)) {} case (ast::cdir_syntax(_)) {} case (ast::cdir_auth(_, _)) {} } diff --git a/src/lib/fs.rs b/src/lib/fs.rs index d051d574fd2..92e90e62cbf 100644 --- a/src/lib/fs.rs +++ b/src/lib/fs.rs @@ -19,6 +19,20 @@ fn dirname(path p) -> path { ret str::substr(p, 0u, i as uint); } +fn basename(path p) -> path { + let int i = str::rindex(p, os_fs::path_sep as u8); + if (i == -1) { + i = str::rindex(p, os_fs::alt_path_sep as u8); + if (i == -1) { + ret p; + } + } + auto len = str::byte_len(p); + if ((i+1) as uint >= len) { ret p; } + + ret str::slice(p, i+1 as uint, len); +} + // FIXME: Need some typestate to avoid bounds check when len(pre) == 0 fn connect(path pre, path post) -> path { auto len = str::byte_len(pre); diff --git a/src/lib/std.rc b/src/lib/std.rc index 3619ede40f8..b35b150528d 100644 --- a/src/lib/std.rc +++ b/src/lib/std.rc @@ -1,8 +1,10 @@ meta (name = "std", - desc = "Rust standard library", + vers = "0.1", uuid = "122bed0b-c19b-4b82-b0b7-7ae8aead7297", - url = "http://rust-lang.org/src/std", - ver = "0.0.1"); + url = "http://rust-lang.org/src/std"); + +meta (comment = "Rust standard library", + license = "BSD"); // Built-in types support modules.