@@ -21,11 +21,10 @@ use middle::trans::context::CrateContext;
21
21
use middle:: trans:: common:: gensym_name;
22
22
use middle:: ty;
23
23
use util:: ppaux;
24
+ use util:: sha1:: { Sha1 , Digest } ;
24
25
25
26
use std:: c_str:: ToCStr ;
26
27
use std:: char;
27
- use std:: hash:: Streaming ;
28
- use std:: hash;
29
28
use std:: os:: consts:: { macos, freebsd, linux, android, win32} ;
30
29
use std:: ptr;
31
30
use std:: run;
@@ -37,7 +36,6 @@ use syntax::ast;
37
36
use syntax:: ast_map:: { path, path_mod, path_name, path_pretty_name} ;
38
37
use syntax:: attr;
39
38
use syntax:: attr:: { AttrMetaMethods } ;
40
- use syntax:: print:: pprust;
41
39
42
40
#[ deriving( Clone , Eq ) ]
43
41
pub enum output_type {
@@ -49,10 +47,6 @@ pub enum output_type {
49
47
output_type_exe,
50
48
}
51
49
52
- fn write_string < W : Writer > ( writer : & mut W , string : & str ) {
53
- writer. write ( string. as_bytes ( ) ) ;
54
- }
55
-
56
50
pub fn llvm_err ( sess : Session , msg : ~str ) -> ! {
57
51
unsafe {
58
52
let cstr = llvm:: LLVMRustGetLastError ( ) ;
@@ -484,209 +478,141 @@ pub mod write {
484
478
* - Symbols in different crates but with same names "within" the crate need
485
479
* to get different linkage-names.
486
480
*
487
- * So here is what we do:
481
+ * - The hash shown in the filename needs to be predictable and stable for
482
+ * build tooling integration. It also needs to be using a hash function
483
+ * which is easy to use from Python, make, etc.
488
484
*
489
- * - Separate the meta tags into two sets: exported and local. Only work with
490
- * the exported ones when considering linkage.
485
+ * So here is what we do:
491
486
*
492
- * - Consider two exported tags as special (and mandatory): name and vers.
493
- * Every crate gets them; if it doesn't name them explicitly we infer them
494
- * as basename(crate) and "0.1", respectively. Call these CNAME, CVERS.
487
+ * - Consider the package id; every crate has one (specified with pkgid
488
+ * attribute). If a package id isn't provided explicitly, we infer a
489
+ * versionless one from the output name. The version will end up being 0.0
490
+ * in this case. CNAME and CVERS are taken from this package id. For
491
+ * example, github.com/mozilla/CNAME#CVERS.
495
492
*
496
- * - Define CMETA as all the non-name, non-vers exported meta tags in the
497
- * crate (in sorted order).
493
+ * - Define CMH as SHA1(pkgid).
498
494
*
499
- * - Define CMH as hash(CMETA + hashes of dependent crates) .
495
+ * - Define CMH8 as the first 8 characters of CMH .
500
496
*
501
- * - Compile our crate to lib CNAME-CMH -CVERS.so
497
+ * - Compile our crate to lib CNAME-CMH8 -CVERS.so
502
498
*
503
- * - Define STH(sym) as hash(CNAME, CMH, type_str(sym))
499
+ * - Define STH(sym) as SHA1( CMH, type_str(sym))
504
500
*
505
501
* - Suffix a mangled sym with ::STH@CVERS, so that it is unique in the
506
502
* name, non-name metadata, and type sense, and versioned in the way
507
503
* system linkers understand.
508
- *
509
504
*/
510
505
511
506
pub fn build_link_meta ( sess : Session ,
512
507
c : & ast:: Crate ,
513
508
output : & Path ,
514
- symbol_hasher : & mut hash :: State )
509
+ symbol_hasher : & mut Sha1 )
515
510
-> LinkMeta {
516
511
struct ProvidedMetas {
517
512
name : Option < @str > ,
518
- vers : Option < @str > ,
519
- pkg_id : Option < @str > ,
520
- cmh_items : ~[ @ast:: MetaItem ]
513
+ vers : @str ,
514
+ pkg_id : @str ,
521
515
}
522
516
523
- fn provided_link_metas ( sess : Session , c : & ast:: Crate ) ->
524
- ProvidedMetas {
525
- let mut name = None ;
526
- let mut vers = None ;
527
- let mut pkg_id = None ;
528
- let mut cmh_items = ~[ ] ;
529
- let linkage_metas = attr:: find_linkage_metas ( c. attrs ) ;
530
- attr:: require_unique_names ( sess. diagnostic ( ) , linkage_metas) ;
531
- for meta in linkage_metas. iter ( ) {
532
- match meta. name_str_pair ( ) {
533
- Some ( ( n, value) ) if "name" == n => name = Some ( value) ,
534
- Some ( ( n, value) ) if "vers" == n => vers = Some ( value) ,
535
- Some ( ( n, value) ) if "package_id" == n => pkg_id = Some ( value) ,
536
- _ => cmh_items. push ( * meta)
517
+ fn provided_link_metas ( sess : Session , output : & Path , c : & ast:: Crate ) -> ProvidedMetas {
518
+ let pkg_id = attr:: first_attr_value_str_by_name ( c. attrs , "pkgid" ) ;
519
+ let pkg_id = match pkg_id {
520
+ None => {
521
+ session:: expect ( sess,
522
+ output. filestem_str ( ) ,
523
+ || format ! ( "output file name '{}' doesn't appear to have a stem" ,
524
+ output. display( ) ) ) . to_managed ( )
537
525
}
526
+ Some ( id) => id
527
+ } ;
528
+ let path = Path :: new ( pkg_id) ;
529
+ if !path. is_relative ( ) {
530
+ sess. fatal ( "pkgid must not be absolute" ) ;
531
+ }
532
+ if path. filename ( ) . is_none ( ) {
533
+ sess. fatal ( "empty or missing pkgid" ) ;
538
534
}
535
+ let name = crate_meta_name ( sess, pkg_id) ;
536
+ let version = crate_meta_version ( sess, pkg_id) ;
539
537
540
538
ProvidedMetas {
541
539
name : name,
542
- vers : vers ,
540
+ vers : version ,
543
541
pkg_id : pkg_id,
544
- cmh_items : cmh_items
545
542
}
546
543
}
547
544
548
- // This calculates CMH as defined above
549
- fn crate_meta_extras_hash ( symbol_hasher : & mut hash:: State ,
550
- cmh_items : ~[ @ast:: MetaItem ] ,
551
- dep_hashes : ~[ @str ] ,
552
- pkg_id : Option < @str > ) -> @str {
553
- fn len_and_str ( s : & str ) -> ~str {
554
- format ! ( "{}_{}" , s. len( ) , s)
555
- }
556
-
557
- fn len_and_str_lit ( l : ast:: lit ) -> ~str {
558
- len_and_str ( pprust:: lit_to_str ( @l) )
559
- }
560
-
561
- let cmh_items = attr:: sort_meta_items ( cmh_items) ;
562
-
563
- fn hash ( symbol_hasher : & mut hash:: State , m : & @ast:: MetaItem ) {
564
- match m. node {
565
- ast:: MetaNameValue ( key, value) => {
566
- write_string ( symbol_hasher, len_and_str ( key) ) ;
567
- write_string ( symbol_hasher, len_and_str_lit ( value) ) ;
568
- }
569
- ast:: MetaWord ( name) => {
570
- write_string ( symbol_hasher, len_and_str ( name) ) ;
571
- }
572
- ast:: MetaList ( name, ref mis) => {
573
- write_string ( symbol_hasher, len_and_str ( name) ) ;
574
- for m_ in mis. iter ( ) {
575
- hash ( symbol_hasher, m_) ;
576
- }
577
- }
578
- }
579
- }
580
-
581
- symbol_hasher. reset ( ) ;
582
- for m in cmh_items. iter ( ) {
583
- hash ( symbol_hasher, m) ;
584
- }
585
-
586
- for dh in dep_hashes. iter ( ) {
587
- write_string ( symbol_hasher, len_and_str ( * dh) ) ;
588
- }
589
-
590
- for p in pkg_id. iter ( ) {
591
- write_string ( symbol_hasher, len_and_str ( * p) ) ;
545
+ fn crate_meta_name ( sess : Session , pkg_id : @str ) -> Option < @str > {
546
+ let hash_idx = match pkg_id. find ( '#' ) {
547
+ None => pkg_id. len ( ) ,
548
+ Some ( idx) => idx,
549
+ } ;
550
+ let prefix = pkg_id. slice_to ( hash_idx) ;
551
+ let last_slash_idx = match prefix. rfind ( '/' ) {
552
+ None => -1 ,
553
+ Some ( idx) => idx,
554
+ } ;
555
+ let name = prefix. slice_from ( last_slash_idx + 1 ) ;
556
+ if name. len ( ) <= 0 {
557
+ sess. fatal ( "pkgid is missing name" ) ;
592
558
}
593
-
594
- return truncated_hash_result ( symbol_hasher) . to_managed ( ) ;
595
- }
596
-
597
- fn warn_missing ( sess : Session , name : & str , default : & str ) {
598
- if !* sess. building_library { return ; }
599
- sess. warn ( format ! ( "missing crate link meta `{}`, using `{}` as default" ,
600
- name, default ) ) ;
559
+ Some ( name. to_managed ( ) )
601
560
}
602
561
603
- fn crate_meta_name ( sess : Session , output : & Path , opt_name : Option < @str > )
604
- -> @str {
605
- match opt_name {
606
- Some ( v) if !v. is_empty ( ) => v,
607
- _ => {
608
- // to_managed could go away if there was a version of
609
- // filestem that returned an @str
610
- // FIXME (#9639): Non-utf8 filenames will give a misleading error
611
- let name = session:: expect ( sess,
612
- output. filestem_str ( ) ,
613
- || format ! ( "output file name `{}` doesn't\
614
- appear to have a stem",
615
- output. display( ) ) ) . to_managed ( ) ;
616
- if name. is_empty ( ) {
617
- sess. fatal ( "missing crate link meta `name`, and the \
618
- inferred name is blank") ;
562
+ fn crate_meta_version ( _sess : Session , pkg_id : @str ) -> @str {
563
+ match pkg_id. find ( '#' ) {
564
+ None => @"0.0 ",
565
+ Some ( idx) => {
566
+ if idx >= pkg_id. len ( ) {
567
+ @"0.0 "
568
+ } else {
569
+ pkg_id. slice_from ( idx + 1 ) . to_managed ( )
619
570
}
620
- warn_missing ( sess, "name" , name) ;
621
- name
622
- }
623
- }
624
- }
625
-
626
- fn crate_meta_vers ( sess : Session , opt_vers : Option < @str > ) -> @str {
627
- match opt_vers {
628
- Some ( v) if !v. is_empty ( ) => v,
629
- _ => {
630
- let vers = @"0.0 ";
631
- warn_missing ( sess, "vers" , vers) ;
632
- vers
633
571
}
634
572
}
635
573
}
636
574
637
- fn crate_meta_pkgid ( sess : Session , name : @str , opt_pkg_id : Option < @str > )
638
- -> @str {
639
- match opt_pkg_id {
640
- Some ( v) if !v. is_empty ( ) => v,
641
- _ => {
642
- let pkg_id = name. clone ( ) ;
643
- warn_missing ( sess, "package_id" , pkg_id) ;
644
- pkg_id
645
- }
646
- }
575
+ // This calculates CMH as defined above
576
+ fn crate_meta_hash ( symbol_hasher : & mut Sha1 , pkg_id : @str ) -> @str {
577
+ symbol_hasher. reset ( ) ;
578
+ symbol_hasher. input_str ( pkg_id) ;
579
+ truncated_hash_result ( symbol_hasher) . to_managed ( )
647
580
}
648
581
649
582
let ProvidedMetas {
650
- name : opt_name,
651
- vers : opt_vers,
652
- pkg_id : opt_pkg_id,
653
- cmh_items : cmh_items
654
- } = provided_link_metas ( sess, c) ;
655
- let name = crate_meta_name ( sess, output, opt_name) ;
656
- let vers = crate_meta_vers ( sess, opt_vers) ;
657
- let pkg_id = crate_meta_pkgid ( sess, name, opt_pkg_id) ;
658
- let dep_hashes = cstore:: get_dep_hashes ( sess. cstore ) ;
659
- let extras_hash =
660
- crate_meta_extras_hash ( symbol_hasher, cmh_items,
661
- dep_hashes, Some ( pkg_id) ) ;
583
+ name : name,
584
+ vers : vers,
585
+ pkg_id : pkg_id
586
+ } = provided_link_metas ( sess, output, c) ;
587
+ let hash = crate_meta_hash ( symbol_hasher, pkg_id) ;
662
588
663
589
LinkMeta {
664
- name : name,
590
+ name : name. unwrap ( ) ,
665
591
vers : vers,
666
- package_id : Some ( pkg_id) ,
667
- extras_hash : extras_hash
592
+ package_id : pkg_id,
593
+ extras_hash : hash
668
594
}
669
595
}
670
596
671
- pub fn truncated_hash_result ( symbol_hasher : & mut hash :: State ) -> ~str {
597
+ pub fn truncated_hash_result ( symbol_hasher : & mut Sha1 ) -> ~str {
672
598
symbol_hasher. result_str ( )
673
599
}
674
600
675
601
676
602
// This calculates STH for a symbol, as defined above
677
603
pub fn symbol_hash ( tcx : ty:: ctxt ,
678
- symbol_hasher : & mut hash :: State ,
604
+ symbol_hasher : & mut Sha1 ,
679
605
t : ty:: t ,
680
606
link_meta : LinkMeta ) -> @str {
681
607
// NB: do *not* use abbrevs here as we want the symbol names
682
608
// to be independent of one another in the crate.
683
609
684
610
symbol_hasher. reset ( ) ;
685
- write_string ( symbol_hasher, link_meta. name ) ;
686
- write_string ( symbol_hasher, "-" ) ;
687
- write_string ( symbol_hasher, link_meta. extras_hash ) ;
688
- write_string ( symbol_hasher, "-" ) ;
689
- write_string ( symbol_hasher, encoder:: encoded_ty ( tcx, t) ) ;
611
+ symbol_hasher. input_str ( link_meta. name ) ;
612
+ symbol_hasher. input_str ( "-" ) ;
613
+ symbol_hasher. input_str ( link_meta. extras_hash ) ;
614
+ symbol_hasher. input_str ( "-" ) ;
615
+ symbol_hasher. input_str ( encoder:: encoded_ty ( tcx, t) ) ;
690
616
let mut hash = truncated_hash_result ( symbol_hasher) ;
691
617
// Prefix with 'h' so that it never blends into adjacent digits
692
618
hash. unshift_char ( 'h' ) ;
@@ -885,7 +811,8 @@ pub fn output_dll_filename(os: abi::Os, lm: LinkMeta) -> ~str {
885
811
abi:: OsAndroid => ( android:: DLL_PREFIX , android:: DLL_SUFFIX ) ,
886
812
abi:: OsFreebsd => ( freebsd:: DLL_PREFIX , freebsd:: DLL_SUFFIX ) ,
887
813
} ;
888
- format ! ( "{}{}-{}-{}{}" , dll_prefix, lm. name, lm. extras_hash, lm. vers, dll_suffix)
814
+ format ! ( "{}{}-{}-{}{}" , dll_prefix, lm. name, lm. extras_hash. slice_chars( 0 , 8 ) ,
815
+ lm. vers, dll_suffix)
889
816
}
890
817
891
818
pub fn get_cc_prog ( sess : Session ) -> ~str {
0 commit comments