github.com/goplus/llgo@v0.8.3/xtool/nm/index.go (about) 1 /* 2 * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package nm 18 19 import ( 20 "bytes" 21 "crypto/md5" 22 "encoding/base64" 23 "log" 24 "os" 25 "path/filepath" 26 "strings" 27 ) 28 29 type IndexBuilder struct { 30 nm *Cmd 31 } 32 33 func NewIndexBuilder(nm *Cmd) *IndexBuilder { 34 return &IndexBuilder{nm} 35 } 36 37 func (p *IndexBuilder) Index(fromDir []string, toDir string, progress func(path string)) error { 38 for _, dir := range fromDir { 39 if dir == "" { 40 continue 41 } 42 if e := p.IndexDir(dir, toDir, progress); e != nil { 43 if !os.IsNotExist(e) { 44 log.Println(e) 45 } 46 } 47 } 48 return nil 49 } 50 51 func (p *IndexBuilder) IndexDir(fromDir, toDir string, progress func(path string)) error { 52 if abs, e := filepath.Abs(fromDir); e == nil { 53 fromDir = abs 54 } 55 return filepath.WalkDir(fromDir, func(path string, d os.DirEntry, err error) error { 56 if err != nil { 57 return err 58 } 59 if d.IsDir() { 60 return nil 61 } 62 fname := d.Name() 63 switch filepath.Ext(fname) { 64 case ".a", ".dylib", ".tbd", ".so", ".dll", ".lib": 65 progress(path) 66 hash := md5.Sum([]byte(path)) 67 hashStr := base64.RawURLEncoding.EncodeToString(hash[:]) 68 outFile := filepath.Join(toDir, strings.TrimPrefix(fname, "lib")+hashStr+".pub") 69 e := p.IndexFile(path, outFile) 70 if e != nil { 71 log.Println(e) 72 } 73 } 74 return nil 75 }) 76 } 77 78 func (p *IndexBuilder) IndexFile(arFile, outFile string) (err error) { 79 items, err := p.nm.List(arFile) 80 if err != nil { 81 if len(items) == 0 { 82 return 83 } 84 } 85 var b bytes.Buffer 86 b.WriteString("nm ") 87 b.WriteString(arFile) 88 b.WriteByte('\n') 89 nbase := b.Len() 90 for _, item := range items { 91 if item.File != "" { 92 b.WriteString("file ") 93 b.WriteString(item.File) 94 b.WriteByte('\n') 95 } 96 for _, sym := range item.Symbols { 97 switch sym.Type { 98 case Text, Data, BSS, Rodata, 'S', 'C', 'W', 'A': 99 b.WriteByte(byte(sym.Type)) 100 b.WriteByte(' ') 101 b.WriteString(sym.Name) 102 b.WriteByte('\n') 103 case Undefined, LocalText, LocalData, LocalBSS, LocalASym, 'I', 'i', 'a', 'w': 104 /* 105 if sym.Type != Undefined && strings.Contains(sym.Name, "fprintf") { 106 log.Printf("skip symbol type %c: %s\n", sym.Type, sym.Name) 107 } 108 */ 109 default: 110 log.Printf("unknown symbol type %c: %s\n", sym.Type, sym.Name) 111 } 112 } 113 } 114 buf := b.Bytes() 115 if len(buf) <= nbase { 116 return 117 } 118 return os.WriteFile(outFile, buf, 0666) 119 }