github.com/hwaf/hwaf@v0.0.0-20140814122253-5465f73b20f1/hlib/render.go (about) 1 package hlib 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "reflect" 8 "sort" 9 "strconv" 10 "strings" 11 "text/template" 12 ) 13 14 type HscriptPyEncoder struct { 15 w io.Writer 16 } 17 18 func NewHscriptPyEncoder(w io.Writer) *HscriptPyEncoder { 19 return &HscriptPyEncoder{w: w} 20 } 21 22 func (enc *HscriptPyEncoder) Encode(wscript *Wscript_t) error { 23 var err error 24 25 _, err = fmt.Fprintf( 26 enc.w, 27 `## -*- python -*- 28 ## automatically generated from a hscript 29 ## do NOT edit. 30 31 ## waf imports 32 import waflib.Logs as msg 33 `, 34 ) 35 if err != nil { 36 return err 37 } 38 39 // generate package header 40 const pkg_hdr_tmpl = ` 41 PACKAGE = { 42 "name": "{{.Name}}", 43 "authors": {{.Authors | as_pylist}}, 44 {{if .Managers}} "managers": {{.Managers | as_pylist}},{{end}} 45 {{if .Version}} "version": "{{.Version}}",{{end}} 46 } 47 48 ### --------------------------------------------------------------------------- 49 def pkg_deps(ctx): 50 {{. | gen_wscript_pkg_deps}} 51 return # pkg_deps 52 ` 53 err = w_tmpl(enc.w, pkg_hdr_tmpl, wscript.Package) 54 if err != nil { 55 return err 56 } 57 58 // generate options - section 59 err = w_tmpl( 60 enc.w, 61 ` 62 63 ### --------------------------------------------------------------------------- 64 def options(ctx): 65 {{with .Tools}}{{. | gen_wscript_tools}}{{end}} 66 return # options 67 `, 68 wscript.Options, 69 ) 70 if err != nil { 71 return err 72 } 73 74 // generate configure - section 75 err = w_tmpl( 76 enc.w, 77 ` 78 79 ### --------------------------------------------------------------------------- 80 def configure(ctx): 81 {{with .Tools}}{{. | gen_wscript_tools}}{{end}} 82 {{with .HwafCall}}{{. | gen_wscript_hwaf_call}} 83 {{end}} 84 {{.Env | gen_wscript_env}} 85 {{range .Stmts}}##{{. | gen_wscript_stmts}} 86 {{end}} 87 return # configure 88 `, 89 wscript.Configure, 90 ) 91 if err != nil { 92 return err 93 } 94 95 // generate build - section 96 err = w_tmpl( 97 enc.w, 98 ` 99 100 ### --------------------------------------------------------------------------- 101 def build(ctx): 102 {{with .Tools}}{{. | gen_wscript_tools}}{{end}} 103 {{with .HwafCall}}{{. | gen_wscript_hwaf_call}} 104 {{end}} 105 {{range .Stmts}}##{{. | gen_wscript_stmts}} 106 {{end}} 107 {{with .Targets}}{{. | gen_wscript_targets}}{{end}} 108 return # build 109 `, 110 wscript.Build, 111 ) 112 if err != nil { 113 return err 114 } 115 116 _, err = fmt.Fprintf( 117 enc.w, 118 "\n## EOF ##\n", 119 ) 120 if err != nil { 121 return err 122 } 123 124 return err 125 } 126 127 func w_tmpl(w io.Writer, text string, data interface{}) error { 128 t := template.New("wscript") 129 t.Funcs(template.FuncMap{ 130 "trim": strings.TrimSpace, 131 "as_pylist": func(alist interface{}) string { 132 rv := reflect.ValueOf(alist) 133 str := make([]string, 0, rv.Len()) 134 for i := 0; i < rv.Len(); i++ { 135 s := rv.Index(i) 136 str = append(str, fmt.Sprintf("%q", s)) 137 } 138 return "[" + strings.Join(str, ", ") + "]" 139 }, 140 "gen_wscript_pkg_deps": gen_wscript_pkg_deps, 141 "gen_wscript_tools": gen_wscript_tools, 142 "gen_wscript_hwaf_call": gen_wscript_hwaf_call, 143 "gen_wscript_env": gen_wscript_env, 144 "gen_wscript_stmts": gen_wscript_stmts, 145 "gen_wscript_targets": gen_wscript_targets, 146 }) 147 template.Must(t.Parse(text)) 148 return t.Execute(w, data) 149 } 150 151 func w_gen_taglist(tags string) []string { 152 str := make([]string, 0, strings.Count(tags, "&")) 153 for _, v := range strings.Split(tags, "&") { 154 v = strings.Trim(v, " ") 155 if len(v) > 0 { 156 str = append(str, v) 157 } 158 } 159 return str 160 } 161 162 func w_gen_valdict_switch_str(indent string, values [][2]string) string { 163 o := make([]string, 0, len(values)) 164 o = append(o, "(") 165 for _, v := range values { 166 tags := w_gen_taglist(v[0]) 167 key_fmt := "(%s)" 168 if strings.Count(v[0], "&") <= 0 { 169 key_fmt = "%s" 170 } 171 val_fmt := "%s" 172 if strings.Count(v[1], ",") > 0 { 173 val_fmt = "[%s]" 174 } 175 if len(v[1]) == 0 { 176 val_fmt = "%q" 177 } 178 179 o = append(o, 180 fmt.Sprintf( 181 "%s {%s: %s},", 182 indent, 183 fmt.Sprintf(key_fmt, w_py_strlist(tags)), 184 fmt.Sprintf(val_fmt, v[1]), 185 ), 186 ) 187 } 188 o = append(o, indent+")") 189 return strings.Join(o, "\n") 190 } 191 192 func w_py_hlib_value(indent string, fctname string, x Value) []string { 193 str := make([]string, 0) 194 195 values := make([][2]string, 0, len(x.Set)) 196 for _, v := range x.Set { 197 k := v.Tag 198 values = append(values, [2]string{k, w_py_strlist(v.Value)}) 199 } 200 str = append( 201 str, 202 fmt.Sprintf( 203 "ctx.%s(%q, %s)", 204 fctname, 205 x.Name, 206 w_gen_valdict_switch_str(indent, values), 207 ), 208 ) 209 210 return str 211 } 212 213 func w_py_strlist(str []string) string { 214 o := make([]string, 0, len(str)) 215 for _, v := range str { 216 vv, err := strconv.Unquote(v) 217 if err != nil { 218 vv = v 219 } 220 if strings.HasPrefix(vv, `"`) && strings.HasSuffix(vv, `"`) { 221 if len(vv) > 1 { 222 vv = vv[1 : len(vv)-1] 223 } 224 } 225 o = append(o, fmt.Sprintf("%q", vv)) 226 } 227 return strings.Join(o, ", ") 228 } 229 230 func gen_wscript_pkg_deps(pkg Package_t) string { 231 const indent = " " 232 var str []string 233 public_deps := make([]Dep_t, 0, len(pkg.Deps)) 234 private_deps := make([]Dep_t, 0, len(pkg.Deps)) 235 runtime_deps := make([]Dep_t, 0, len(pkg.Deps)) 236 for _, dep := range pkg.Deps { 237 if dep.Type.HasMask(RuntimeDep) { 238 runtime_deps = append(runtime_deps, dep) 239 } 240 if dep.Type.HasMask(PublicDep) { 241 public_deps = append(public_deps, dep) 242 } 243 if dep.Type.HasMask(PrivateDep) { 244 private_deps = append(private_deps, dep) 245 } 246 } 247 248 str = append(str, "") 249 if len(public_deps) > 0 { 250 str = append(str, "## public dependencies") 251 for _, dep := range public_deps { 252 str = append( 253 str, 254 fmt.Sprintf( 255 "ctx.use_pkg(%q, version=%q, public=True)", 256 dep.Name, 257 dep.Version, 258 ), 259 ) 260 } 261 str = append(str, "") 262 } else { 263 str = append(str, "## no public dependencies") 264 } 265 266 if len(private_deps) > 0 { 267 str = append(str, "## private dependencies") 268 for _, dep := range private_deps { 269 str = append( 270 str, 271 fmt.Sprintf( 272 "ctx.use_pkg(%q, version=%q, private=True)", 273 dep.Name, 274 dep.Version, 275 ), 276 ) 277 } 278 str = append(str, "") 279 } else { 280 str = append(str, "## no private dependencies") 281 } 282 283 if len(runtime_deps) > 0 { 284 str = append(str, "## runtime dependencies") 285 for _, dep := range runtime_deps { 286 str = append( 287 str, 288 fmt.Sprintf( 289 "ctx.use_pkg(%q, version=%q, runtime=True)", 290 dep.Name, 291 dep.Version, 292 ), 293 ) 294 } 295 } else { 296 str = append(str, "## no runtime dependencies") 297 } 298 299 // reindent: 300 for i, s := range str[1:] { 301 str[i+1] = indent + s 302 } 303 304 return strings.Join(str, "\n") 305 } 306 307 func gen_wscript_tools(tools []string) string { 308 const indent = " " 309 str := []string{""} 310 311 for _, tool := range tools { 312 str = append( 313 str, 314 fmt.Sprintf("ctx.load(%q)", tool), 315 fmt.Sprintf("try: ctx.%s()", tool), 316 "except AttributeError: pass", 317 "", 318 ) 319 } 320 321 // reindent: 322 for i, s := range str[1:] { 323 str[i+1] = indent + s 324 } 325 326 return strings.Join(str, "\n") 327 } 328 329 func gen_wscript_hwaf_call(calls []string) string { 330 const indent = " " 331 str := []string{""} 332 333 for _, script := range calls { 334 str = append( 335 str, 336 fmt.Sprintf( 337 "ctx._hwaf_load_fct(PACKAGE['name'], %q)", 338 script, 339 ), 340 "", 341 ) 342 } 343 344 // reindent: 345 for i, s := range str[1:] { 346 str[i+1] = indent + s 347 } 348 349 return strings.Join(str, "\n") 350 } 351 352 func gen_wscript_env(env Env_t) string { 353 const indent = " " 354 var str []string 355 356 //str = append(str, "## environment -- begin") 357 for k := range env { 358 str = append(str, fmt.Sprintf("ctx.hwaf_declare_runtime_env(%q)", k)) 359 // switch len(values) { 360 // case 0: 361 // case 1: 362 // if len(values.Set) > 1 { 363 // // str = append( 364 // // str, 365 // // fmt.Sprintf("%s: {"), 366 // // ) 367 // } else { 368 // kvs := values.Set[0] 369 // for k, v := range kvs { 370 371 // } 372 // } 373 // default: 374 // } 375 } 376 //str = append(str, "## environment -- end") 377 378 // // reindent: 379 // for i, s := range str[1:] { 380 // str[i+1] = indent + s 381 // } 382 383 return strings.Join(str, "\n") 384 } 385 386 func gen_wscript_stmts(stmt Stmt) string { 387 const indent = " " 388 var str []string 389 switch x := stmt.(type) { 390 case *AliasStmt: 391 str = []string{fmt.Sprintf("## alias %v", stmt)} 392 str = append( 393 str, 394 w_py_hlib_value(indent, "hwaf_declare_runtime_alias", x.Value)..., 395 ) 396 397 case *MacroStmt: 398 str = []string{fmt.Sprintf("## macro %v", stmt)} 399 str = append( 400 str, 401 w_py_hlib_value(indent, "hwaf_declare_macro", x.Value)..., 402 ) 403 404 case *MacroAppendStmt: 405 str = []string{fmt.Sprintf("## macro_append %v", stmt)} 406 str = append( 407 str, 408 w_py_hlib_value(indent, "hwaf_macro_append", x.Value)..., 409 ) 410 411 case *MacroPrependStmt: 412 str = []string{fmt.Sprintf("## macro_prepend %v", stmt)} 413 str = append( 414 str, 415 w_py_hlib_value(indent, "hwaf_macro_prepend", x.Value)..., 416 ) 417 418 case *MacroRemoveStmt: 419 str = []string{fmt.Sprintf("## macro_remove %v", stmt)} 420 str = append( 421 str, 422 w_py_hlib_value(indent, "hwaf_macro_remove", x.Value)..., 423 ) 424 425 case *SetStmt: 426 str = []string{fmt.Sprintf("## set %v", stmt)} 427 str = append( 428 str, 429 w_py_hlib_value(indent, "hwaf_declare_macro", x.Value)..., 430 ) 431 str = append( 432 str, 433 fmt.Sprintf("ctx.hwaf_declare_runtime_env(%q)", x.Value.Name), 434 ) 435 436 case *SetPrependStmt: 437 str = []string{fmt.Sprintf("## set_prepend %v", stmt)} 438 str = append( 439 str, 440 w_py_hlib_value(indent, "hwaf_macro_prepend", x.Value)..., 441 ) 442 443 case *SetRemoveStmt: 444 str = []string{fmt.Sprintf("## set_remove %v", stmt)} 445 str = append( 446 str, 447 w_py_hlib_value(indent, "hwaf_macro_remove", x.Value)..., 448 ) 449 case *TagStmt: 450 str = []string{fmt.Sprintf("## tag %v", stmt)} 451 values := w_py_strlist(x.Content) 452 str = append(str, 453 "ctx.hwaf_declare_tag(", 454 fmt.Sprintf("%s%q,", indent, x.Name), 455 fmt.Sprintf("%scontent=[%s]", indent, values), 456 ")", 457 ) 458 459 case *ApplyTagStmt: 460 str = []string{fmt.Sprintf("## apply_tag %v", stmt)} 461 if len(x.Value.Set) > 0 { 462 str = append( 463 str, 464 fmt.Sprintf("ctx.hwaf_apply_tag(%v)", w_py_strlist(x.Value.Set[0].Value)), 465 ) 466 } else { 467 str = append( 468 str, 469 fmt.Sprintf("ctx.hwaf_apply_tag(%q)", x.Value.Name), 470 ) 471 } 472 473 case *PathStmt: 474 str = []string{fmt.Sprintf("## path %v", stmt)} 475 str = append( 476 str, 477 w_py_hlib_value(indent, "hwaf_declare_path", x.Value)..., 478 ) 479 480 case *PathAppendStmt: 481 str = []string{fmt.Sprintf("## path_append %v", stmt)} 482 str = append( 483 str, 484 w_py_hlib_value(indent, "hwaf_path_append", x.Value)..., 485 ) 486 487 case *PathPrependStmt: 488 str = []string{fmt.Sprintf("## path_prepend %v", stmt)} 489 str = append( 490 str, 491 w_py_hlib_value(indent, "hwaf_path_prepend", x.Value)..., 492 ) 493 494 case *PathRemoveStmt: 495 str = []string{fmt.Sprintf("## path_remove %v", stmt)} 496 str = append( 497 str, 498 w_py_hlib_value(indent, "hwaf_path_remove", x.Value)..., 499 ) 500 501 //case *ApplyPatternStmt: 502 503 default: 504 str = []string{fmt.Sprintf("### **** statement %T (%v)", stmt, stmt)} 505 } 506 507 // reindent: 508 for i, s := range str[1:] { 509 str[i+1] = indent + s 510 } 511 512 return strings.Join(str, "\n") 513 } 514 515 func gen_wscript_targets(tgts Targets_t) string { 516 const indent = " " 517 var str []string 518 519 // sort targets by name. 520 // waf uses the task order as an internal id. 521 // to make incremental builds to work properly, we need to 522 // always create the same wscript from a given hscript.yml file. 523 sort.Sort(tgts) 524 525 cnv_values := func(values []Value) []string { 526 out := make([]string, 0, len(values)) 527 for _, v := range values { 528 if len(v.Set) > 0 { 529 // FIXME what about the non-default values ?? 530 out = append(out, v.Set[0].Value...) 531 } else { 532 fmt.Fprintf(os.Stderr, "**warn** in target: %v\n", tgts) 533 fmt.Fprintf(os.Stderr, "**warn** invalid value: %v\n", v) 534 } 535 } 536 return out 537 } 538 539 for i, tgt := range tgts { 540 if i != 0 { 541 str = append(str, "") 542 } 543 srcs := cnv_values(tgt.Source) 544 features := strings.Join(tgt.Features, " ") 545 target_name := tgt.Target 546 if target_name == "" { 547 target_name = tgt.Name 548 } 549 str = append(str, 550 "ctx(", 551 fmt.Sprintf("%sfeatures = %q,", indent, features), 552 fmt.Sprintf("%sname = %q,", indent, tgt.Name), 553 fmt.Sprintf("%starget = %q,", indent, target_name), 554 fmt.Sprintf("%ssource = [%s],", indent, w_py_strlist(srcs)), 555 ) 556 557 if tgt.Group != "" { 558 str = append( 559 str, 560 fmt.Sprintf("%sgroup = %q,", indent, tgt.Group), 561 ) 562 } 563 564 for _, vv := range []struct { 565 hdr string 566 values []Value 567 }{ 568 {"use", tgt.Use}, 569 {"defines", tgt.Defines}, 570 {"cflags", tgt.CFlags}, 571 {"cxxflags", tgt.CxxFlags}, 572 {"linkflags", tgt.LinkFlags}, 573 {"shlibflags", tgt.ShlibFlags}, 574 {"stlibflags", tgt.StlibFlags}, 575 {"rpath", tgt.RPath}, 576 {"includes", tgt.Includes}, 577 {"export_includes", tgt.ExportIncludes}, 578 {"install_path", tgt.InstallPath}, 579 } { 580 if len(vv.values) > 0 { 581 vals := cnv_values(vv.values) 582 str = append(str, 583 fmt.Sprintf( 584 "%s%s = [%s],", 585 indent, 586 vv.hdr, 587 w_py_strlist(vals), 588 ), 589 ) 590 } 591 } 592 593 if len(tgt.Env) > 0 { 594 str = append(str, 595 fmt.Sprintf("%senv = ctx._hwaf_subenv({", indent), 596 ) 597 for hdr, value := range tgt.Env { 598 vals := cnv_values([]Value{value}) 599 str = append(str, 600 fmt.Sprintf( 601 "%s'%s': [%s],", 602 indent+indent, 603 hdr, 604 w_py_strlist(vals), 605 ), 606 ) 607 } 608 str = append(str, 609 indent+"}),", 610 ) 611 612 } 613 614 for kk, vv := range tgt.KwArgs { 615 if len(vv) > 0 { 616 vals := cnv_values(vv) 617 str = append(str, 618 fmt.Sprintf( 619 "%s%s = [%s],", 620 indent, 621 kk, 622 w_py_strlist(vals), 623 ), 624 ) 625 } 626 } 627 str = append(str, 628 ")", 629 ) 630 631 } 632 633 // reindent: 634 for i, s := range str[1:] { 635 str[i+1] = indent + s 636 } 637 638 return strings.Join(str, "\n") 639 } 640 641 // EOF