go-hep.org/x/hep@v0.38.1/groot/gen.rboot.go (about) 1 // Copyright ©2018 The go-hep Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build ignore 6 7 // gen.rboot generates rdict streamers from the C++/ROOT ones. 8 // gen.rboot generates ROOT class versions from the C++/ROOT streamers. 9 package main 10 11 import ( 12 "bytes" 13 "encoding/json" 14 "fmt" 15 "io" 16 "log" 17 "os" 18 "strings" 19 "text/template" 20 21 "go-hep.org/x/hep/groot/internal/genroot" 22 "go-hep.org/x/hep/groot/internal/rtests" 23 "go-hep.org/x/hep/groot/rbytes" 24 "go-hep.org/x/hep/groot/rdict" 25 "go-hep.org/x/hep/groot/riofs" 26 ) 27 28 var ( 29 classes = []string{ 30 // rbase 31 "TAttAxis", "TAttBBox2D", "TAttFill", "TAttLine", "TAttMarker", "TAttPad", 32 "TDatime", 33 "TNamed", 34 "TObject", "TObjString", 35 "TProcessID", "TProcessUUID", 36 "TQObject", 37 "TRef", 38 "TString", 39 "TUUID", 40 "TVirtualPad", 41 42 // rcont 43 "TArray", "TArrayC", "TArrayS", "TArrayI", "TArrayL", "TArrayL64", "TArrayF", "TArrayD", 44 "TBits", 45 "TCollection", 46 "TClonesArray", 47 "TList", 48 "THashList", 49 "THashTable", 50 "TMap", 51 "TObjArray", 52 "TRefArray", 53 "TRefTable", 54 "TSeqCollection", 55 56 // rdict 57 "TStreamerInfo", 58 "TStreamerElement", 59 "TStreamerBase", 60 "TStreamerBasicType", 61 "TStreamerBasicPointer", 62 "TStreamerLoop", 63 "TStreamerObject", 64 "TStreamerObjectPointer", 65 "TStreamerObjectAny", 66 "TStreamerObjectAnyPointer", 67 "TStreamerString", 68 "TStreamerSTL", 69 "TStreamerSTLstring", 70 "TStreamerArtificial", 71 72 // rhist 73 "TAxis", 74 "TConfidenceLevel", 75 "TEfficiency", 76 "TF1", 77 "TF1AbsComposition", "TF1Convolution", "TF1NormSum", "TF1Parameters", 78 "TFormula", 79 "TGraph", "TGraphErrors", "TGraphAsymmErrors", "TGraphMultiErrors", 80 "TH1", "TH1C", "TH1D", "TH1F", "TH1I", "TH1K", "TH1S", 81 "TH2", "TH2C", "TH2D", "TH2F", "TH2I", "TH2Poly", "TH2PolyBin", "TH2S", 82 "TLimit", "TLimitDataSource", 83 "TMultiGraph", 84 "TProfile", "TProfile2D", 85 "TScatter", 86 87 // riofs 88 "TDirectory", 89 "TDirectoryFile", 90 "TFile", 91 "TKey", 92 93 // rntup 94 // "ROOT::Experimental::RNTuple", // FIXME(sbinet): TODO 95 96 // rphys 97 "TFeldmanCousins", 98 "TLorentzVector", 99 "TVector2", "TVector3", 100 101 // rtree 102 "ROOT::TIOFeatures", 103 "TBasket", 104 "TBranch", "TBranchElement", "TBranchObject", "TBranchRef", 105 "TChain", 106 "TLeaf", "TLeafElement", "TLeafObject", 107 "TLeafO", 108 "TLeafB", "TLeafS", "TLeafI", "TLeafL", "TLeafG", 109 "TLeafF", "TLeafD", 110 "TLeafF16", "TLeafD32", 111 "TLeafC", 112 "TNtuple", "TNtupleD", 113 "TTree", 114 115 // rpad 116 "TAttCanvas", 117 "TCanvas", 118 "TPad", 119 } 120 ) 121 122 func main() { 123 genStreamers(classes) 124 } 125 126 func genStreamers(classes []string) { 127 const ( 128 oname = "streamers.root" 129 ) 130 defer os.Remove(oname) 131 132 tmpl := template.Must(template.New("genstreamers").Parse(` 133 void genstreamers(const char* fname) { 134 auto f = TFile::Open(fname, "RECREATE"); 135 136 {{range .}} 137 TClass::GetClass("{{.}}")->GetStreamerInfo()->Write("streamer-info-{{.}}"); 138 {{end }} 139 140 f->Write(); 141 f->Close(); 142 143 exit(0); 144 } 145 `)) 146 147 macro := new(strings.Builder) 148 err := tmpl.Execute(macro, classes) 149 if err != nil { 150 log.Fatal(err) 151 } 152 153 out, err := rtests.RunCxxROOT("genstreamers", []byte(macro.String()), oname) 154 if err != nil { 155 log.Fatalf("could not run gen-streamers:\n%s\nerror: %+v", out, err) 156 } 157 158 root, err := riofs.Open(oname) 159 if err != nil { 160 log.Fatalf("could not open ROOT streamers file: %+v", err) 161 } 162 defer root.Close() 163 164 var streamers []rbytes.StreamerInfo 165 for _, k := range root.Keys() { 166 if !strings.HasPrefix(k.Name(), "streamer-info-") { 167 continue 168 } 169 obj, err := k.Object() 170 if err != nil { 171 log.Fatalf("could not load streamer %q: +v", k.Name(), err) 172 } 173 si, ok := obj.(rbytes.StreamerInfo) 174 if !ok { 175 log.Fatalf("object %q is not a streamer info: type=%T", k.Name(), obj) 176 } 177 streamers = append(streamers, si) 178 } 179 if got, want := len(streamers), len(classes); got != want { 180 log.Fatalf("missing streamers: got=%d, want=%d", got, want) 181 } 182 183 var ( 184 fname = "rdict/cxx_root_streamers_gen.go" 185 year = genroot.ExtractYear(fname) 186 ) 187 f, err := os.Create(fname) 188 if err != nil { 189 log.Fatal(err) 190 } 191 defer f.Close() 192 193 _, err = f.Write([]byte(fmt.Sprintf(`// Copyright ©%d The go-hep Authors. All rights reserved. 194 // Use of this source code is governed by a BSD-style 195 // license that can be found in the LICENSE file. 196 197 // Automatically generated. DO NOT EDIT. 198 199 package rdict 200 201 import ( 202 "go-hep.org/x/hep/groot/rbase" 203 "go-hep.org/x/hep/groot/rbytes" 204 "go-hep.org/x/hep/groot/rmeta" 205 ) 206 207 func init() { 208 `, year))) 209 if err != nil { 210 log.Fatalf("could not write groot streamers header: %+v", err) 211 } 212 for _, sinfo := range streamers { 213 fmt.Fprintf(f, "StreamerInfos.Add(") 214 err = writeStreamer(f, sinfo) 215 if err != nil { 216 log.Fatalf("could not generate groot streamer %v: %+v", sinfo, err) 217 } 218 f.WriteString(")\n") 219 } 220 fmt.Fprintf(f, "\n}\n") 221 222 err = f.Close() 223 if err != nil { 224 log.Fatal(err) 225 } 226 genroot.GoFmt(f) 227 228 genVersions(streamers) 229 } 230 231 func writeStreamer(w io.Writer, si rbytes.StreamerInfo) error { 232 const verbose = true 233 err := rdict.GenCxxStreamerInfo(w, si, verbose) 234 if err != nil { 235 return fmt.Errorf("could not write streamer info %q: %w", si.Name(), err) 236 } 237 return nil 238 } 239 240 type Type struct { 241 Name string `json:"name"` 242 Version int `json:"version"` 243 } 244 245 func (t Type) GoName() string { 246 var ( 247 namespace = "" 248 name = t.Name 249 ) 250 if strings.HasPrefix(name, "ROOT::Experimental") { 251 namespace = "ROOT_Experimental" 252 name = name[len("ROOT::Experimental"):] 253 } 254 255 if strings.HasPrefix(name, "ROOT::") { 256 namespace = "ROOT_" 257 name = name[len("ROOT::"):] 258 } 259 260 if strings.HasPrefix(name, "T") { 261 name = name[1:] 262 } 263 return namespace + name 264 } 265 266 func genVersions(streamers []rbytes.StreamerInfo) { 267 types, err := genROOTTypes(streamers) 268 if err != nil { 269 log.Fatalf("could not generate ROOT classes versions: %+v", err) 270 } 271 272 fname := "./rvers/versions_gen.go" 273 year := genroot.ExtractYear(fname) 274 f, err := os.Create(fname) 275 if err != nil { 276 log.Fatal(err) 277 } 278 defer f.Close() 279 280 genroot.GenImports(year, "rvers", f) 281 282 fmt.Fprintf(f, "\n\n// ROOT version\nconst ROOT = %d\n\n", types[len(types)-1].Version) 283 284 tmpl := template.Must(template.New("types").Parse(tmpl)) 285 err = tmpl.Execute(f, types[:len(types)-1]) 286 if err != nil { 287 log.Fatalf("error executing template: %+v\n", err) 288 } 289 290 err = f.Close() 291 if err != nil { 292 log.Fatalf("could not close generated Go file: %+v", err) 293 } 294 genroot.GoFmt(f) 295 } 296 297 func genROOTTypes(streamers []rbytes.StreamerInfo) ([]Type, error) { 298 const ( 299 oname = "rversions.json" 300 ) 301 defer os.Remove(oname) 302 303 tmpl := template.Must(template.New("genrversions").Parse(` 304 #include <fstream> 305 306 void genrversions(const char* fname) { 307 auto f = fopen(fname, "w"); 308 fprintf(f, "[\n"); 309 {{range .}} 310 fprintf(f, "{\"name\": \"{{.Name}}\", \"version\": %d},\n", {{.ClassVersion}}); 311 {{- end }} 312 fprintf(f, "{\"name\": \"TROOT\", \"version\": %d}\n]\n", gROOT->GetVersionInt()); 313 314 fclose(f); 315 316 exit(0); 317 } 318 `)) 319 320 macro := new(strings.Builder) 321 err := tmpl.Execute(macro, streamers) 322 if err != nil { 323 log.Fatal(err) 324 } 325 326 out, err := rtests.RunCxxROOT("genrversions", []byte(macro.String()), oname) 327 if err != nil { 328 log.Fatalf("could not run gen-rversions:\n%s\nerror: %+v", out, err) 329 } 330 331 f, err := os.ReadFile(oname) 332 if err != nil { 333 log.Fatal(err) 334 } 335 336 var types []Type 337 err = json.NewDecoder(bytes.NewReader(f)).Decode(&types) 338 return types, err 339 } 340 341 const tmpl = `// ROOT classes versions 342 const ( 343 {{range .}} 344 {{.GoName}} = {{.Version}} // ROOT version for {{.Name}} 345 {{- end}} 346 ) 347 `