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  `