func waf_get_wscript(data map[string]interface{}) (*hlib.Wscript_t, error) { var err error var wscript hlib.Wscript_t wpkg := &wscript.Package // validate sections layout err = waf_validate_sections( data, "package", "options", "configure", "build", ) if err != nil { return nil, fmt.Errorf("invalid hscript:\n%v", err) } // ---------- package section --------------------------------------------- if _, ok := data["package"]; !ok { return nil, fmt.Errorf("missing mandatory 'package' section") } pkg := waf_get_yaml_map(data["package"]) err = waf_validate_sections( pkg, "name", "authors", "managers", "version", "deps", ) if err != nil { return nil, fmt.Errorf("invalid 'package' section:\n%v", err) } switch pkgname := pkg["name"].(type) { case string: wpkg.Name = pkgname default: return nil, fmt.Errorf("invalid type (%T) for 'package.name' field (expected a string)", pkgname) } if _, ok := pkg["authors"]; ok { switch v := pkg["authors"].(type) { case []interface{}: for _, vv := range v { wpkg.Authors = append(wpkg.Authors, hlib.Author(vv.(string))) } case string: wpkg.Authors = append(wpkg.Authors, hlib.Author(v)) default: return nil, fmt.Errorf("unknown type (%T) for 'authors' field", v) } } if _, ok := pkg["managers"]; ok { switch v := pkg["managers"].(type) { case []interface{}: for _, vv := range v { wpkg.Managers = append(wpkg.Managers, hlib.Manager(vv.(string))) } case string: wpkg.Managers = append(wpkg.Managers, hlib.Manager(v)) default: return nil, fmt.Errorf("unknown type (%T) for 'managers' field", v) } } if _, ok := pkg["version"]; ok { wpkg.Version = hlib.Version(pkg["version"].(string)) } if _, ok := pkg["deps"]; ok { if _, ok := pkg["deps"].(map[interface{}]interface{}); !ok { return nil, fmt.Errorf("'deps' field has to be a map") } deps := waf_get_yaml_map(pkg["deps"]) err = waf_validate_sections( deps, "public", "private", "runtime", ) if err != nil { return nil, fmt.Errorf("invalid 'package.deps' section:\n%v", err) } all_deps := make(map[string]int) if _, ok := deps["public"]; ok { pub_deps := deps["public"].([]interface{}) for _, idep := range pub_deps { dep := idep.(string) all_deps[dep] = len(wpkg.Deps) wpkg.Deps = append( wpkg.Deps, hlib.Dep_t{ Name: dep, Type: hlib.PublicDep, }, ) } } if _, ok := deps["private"]; ok { pri_deps := deps["private"].([]interface{}) for _, idep := range pri_deps { dep := idep.(string) all_deps[dep] = len(wpkg.Deps) wpkg.Deps = append( wpkg.Deps, hlib.Dep_t{ Name: dep, Type: hlib.PrivateDep, }, ) } } if _, ok := deps["runtime"]; ok { r_deps := deps["runtime"].([]interface{}) for _, idep := range r_deps { dep := idep.(string) if idx, ok := all_deps[dep]; ok { wpkg.Deps[idx].Type |= hlib.RuntimeDep } else { wpkg.Deps = append( wpkg.Deps, hlib.Dep_t{ Name: dep, Type: hlib.RuntimeDep, }, ) } } } } // ---------- options section --------------------------------------------- if _, ok := data["options"]; ok { wopt := &wscript.Options opt := waf_get_yaml_map(data["options"]) err = waf_validate_sections( opt, "tools", "hwaf-call", ) if err != nil { return nil, fmt.Errorf("invalid 'options' section:\n%v", err) } if _, ok := opt["tools"]; ok { tools := opt["tools"].([]interface{}) for _, itool := range tools { wopt.Tools = append(wopt.Tools, itool.(string)) } } if _, ok := opt["hwaf-call"]; ok { calls := opt["hwaf-call"].([]interface{}) for _, icall := range calls { wopt.HwafCall = append(wopt.HwafCall, icall.(string)) } } } // ---------- configure section ------------------------------------------- if _, ok := data["configure"]; ok { wcfg := &wscript.Configure cfg := waf_get_yaml_map(data["configure"]) err = waf_validate_sections( cfg, "tools", "hwaf-call", "env", "alias", "declare-tags", "apply-tags", ) if err != nil { return nil, fmt.Errorf("invalid 'configure' section:\n%v", err) } if _, ok := cfg["tools"]; ok { tools := cfg["tools"].([]interface{}) for _, itool := range tools { wcfg.Tools = append(wcfg.Tools, itool.(string)) } } // FIXME: // handle 'env' section if _, ok := cfg["env"]; ok { env := waf_get_yaml_map(cfg["env"]) for k, iv := range env { switch v := iv.(type) { case string: if strings.HasSuffix(v, fmt.Sprintf(":${%s}", k)) { // gamble: path_prepend str := v[:len(v)-len(fmt.Sprintf(":${%s}", k))] stmt := hlib.PathPrependStmt{ Value: hlib.Value{ Name: k, Set: []hlib.KeyValue{ {Tag: "default", Value: []string{str}}, }, }, } wcfg.Stmts = append( wcfg.Stmts, &stmt, ) } else if strings.HasPrefix(v, fmt.Sprintf("${%s}:", k)) { // gamble: path_append str := v[len(fmt.Sprintf("${%s}:", k)):] stmt := hlib.PathAppendStmt{ Value: hlib.Value{ Name: k, Set: []hlib.KeyValue{ {Tag: "default", Value: []string{str}}, }, }, } wcfg.Stmts = append( wcfg.Stmts, &stmt, ) } else { // gamble declare_path stmt := hlib.PathStmt{ Value: hlib.Value{ Name: k, Set: []hlib.KeyValue{ {Tag: "default", Value: []string{v}}, }, }, } wcfg.Stmts = append( wcfg.Stmts, &stmt, ) } case []interface{}: for _, v := range v { switch v := v.(type) { default: return nil, fmt.Errorf("unknown type (%T) for 'configure.env[%v]' field", v, k) } } default: return nil, fmt.Errorf("unknown type (%T) for 'configure.env' field", v) } } } // FIXME: // handle 'declare-tags' section if _, ok := cfg["declare-tags"]; ok { add_tag := func(name string, data ...string) { content := make([]string, len(data)) copy(content, data) stmt := hlib.TagStmt{ Name: name, Content: content, } wcfg.Stmts = append( wcfg.Stmts, &stmt, ) } switch tags := cfg["declare-tags"].(type) { case []interface{}: for _, iv := range tags { tags := waf_get_yaml_map(iv) for name, content := range tags { switch content := content.(type) { case string: add_tag(name, content) case []interface{}: tag_content := make([]string, 0, len(content)) for _, tag := range content { tag_content = append(tag_content, tag.(string)) } add_tag(name, tag_content...) case []string: add_tag(name, content...) default: return nil, fmt.Errorf("unknown type (%T) for 'configure.declare-tags' field", tags) } } } default: return nil, fmt.Errorf("unknown type (%T) for 'configure.declare-tags' field", tags) } } // handle 'apply-tag' section if _, ok := cfg["apply-tags"]; ok { add_tag := func(data ...string) { tags := make([]string, len(data)) copy(tags, data) stmt := hlib.ApplyTagStmt{ Value: hlib.Value{ Name: "", Set: []hlib.KeyValue{ {Tag: "default", Value: tags}, }, }, } wcfg.Stmts = append( wcfg.Stmts, &stmt, ) } switch tags := cfg["apply-tags"].(type) { case string: add_tag(tags) case []string: add_tag(tags...) case []interface{}: for _, iv := range tags { switch iv := iv.(type) { case string: add_tag(iv) default: return nil, fmt.Errorf("unknown type (%T) for 'configure.apply-tags' field", tags) } } default: return nil, fmt.Errorf("unknown type (%T) for 'configure.apply-tags' field", tags) } } // FIXME: // handle 'export-tools' section ? if _, ok := cfg["hwaf-call"]; ok { calls := cfg["hwaf-call"].([]interface{}) for _, icall := range calls { wcfg.HwafCall = append(wcfg.HwafCall, icall.(string)) } } } // ---------- build section ----------------------------------------------- if _, ok := data["build"]; ok { wbld := &wscript.Build bld := waf_get_yaml_map(data["build"]) if _, ok := bld["tools"]; ok { tools := bld["tools"].([]interface{}) for _, itool := range tools { wbld.Tools = append(wbld.Tools, itool.(string)) } } if _, ok := bld["hwaf-call"]; ok { calls := bld["hwaf-call"].([]interface{}) for _, icall := range calls { wbld.HwafCall = append(wbld.HwafCall, icall.(string)) } } // FIXME: // handle 'env' section // handle 'tag' section tgt_names := make([]string, 0, len(bld)) for k, _ := range bld { if k != "hwaf-call" && k != "tools" && k != "env" { tgt_names = append(tgt_names, k) } } for _, n := range tgt_names { tgt := waf_get_yaml_map(bld[n]) wtgt := hlib.Target_t{ Name: n, KwArgs: make(map[string][]hlib.Value), } if v, ok := tgt["features"]; ok { switch v := v.(type) { case string: tmps := strings.Split(v, " ") for _, tmp := range tmps { tmp = strings.Trim(tmp, " ") if tmp != "" { wtgt.Features = append(wtgt.Features, tmp) } } case []interface{}: for _, iv := range v { v := iv.(string) tmps := strings.Split(v, " ") for _, tmp := range tmps { tmp = strings.Trim(tmp, " ") if tmp != "" { wtgt.Features = append(wtgt.Features, tmp) } } } case []string: for _, iv := range v { tmps := strings.Split(iv, " ") for _, tmp := range tmps { tmp = strings.Trim(tmp, " ") if tmp != "" { wtgt.Features = append(wtgt.Features, tmp) } } } default: return nil, fmt.Errorf("unknown type (%T) for target [%s] in 'build' section", v, n) } delete(tgt, "features") } if _, ok := tgt["name"]; ok { nn := tgt["name"].(string) if nn != wtgt.Name { return nil, fmt.Errorf("inconsistency in target [%s] declaration: name=%q but key=%q", n, nn, wtgt.Name) } delete(tgt, "name") } if _, ok := tgt["target"]; ok { wtgt.Target = tgt["target"].(string) delete(tgt, "target") } if _, ok := tgt["group"]; ok { wtgt.Group = tgt["group"].(string) delete(tgt, "group") } cnvmap := map[string]*[]hlib.Value{ "source": &wtgt.Source, "use": &wtgt.Use, "defines": &wtgt.Defines, "cflags": &wtgt.CFlags, "cxxflags": &wtgt.CxxFlags, "linkflags": &wtgt.LinkFlags, "shlibflags": &wtgt.ShlibFlags, "stlibflags": &wtgt.StlibFlags, "rpath": &wtgt.RPath, "includes": &wtgt.Includes, "export_includes": &wtgt.ExportIncludes, "install_path": &wtgt.InstallPath, } for k, v := range tgt { vv := waf_gen_hvalue_from(k, v) if dst, ok := cnvmap[k]; ok { *dst = append(*dst, vv) } else { wtgt.KwArgs[k] = append(wtgt.KwArgs[k], vv) } } wbld.Targets = append(wbld.Targets, wtgt) } } return &wscript, err }
func (r *Renderer) analyze() error { var err error basedir := filepath.Dir(filepath.Dir(r.req.Filename)) r.pkg = hlib.Wscript_t{ Package: hlib.Package_t{Name: basedir}, Configure: hlib.Configure_t{Env: make(hlib.Env_t)}, Build: hlib.Build_t{Env: make(hlib.Env_t)}, } wscript := &r.pkg // targets apps := make(map[string]*Application) libs := make(map[string]*Library) // first pass: discover targets for _, stmt := range r.req.Stmts { switch stmt.(type) { case *Application: x := stmt.(*Application) apps[x.Name] = x case *Library: x := stmt.(*Library) libs[x.Name] = x } } // list of macros related to targets. // this will be used to: // - fold them together // - pre-process macro_append, macro_remove, ... // - dispatch to wscript equivalents. e.g.: // - <name>linkopts -> ctx(use=[...], cxxshlibflags=[...]) // - <name>_dependencies -> ctx(depends_on=[...]) // - includes -> ctx(includes=[..]) macros := make(map[string][]Stmt) tgt_names := make([]string, 0, len(apps)+len(libs)) for k, _ := range apps { tgt_names = append(tgt_names, k) } for k, _ := range libs { tgt_names = append(tgt_names, k) } sort.Strings(tgt_names) //fmt.Printf("+++ tgt_names: %v\n", tgt_names) // second pass: collect macros for _, stmt := range r.req.Stmts { switch x := stmt.(type) { default: continue case *Macro: //fmt.Printf("== [%s] ==\n", x.Name) //pat := x.Name+"(_dependencies|linkopts)" pat := ".*?" if !re_is_in_slice_suffix(tgt_names, x.Name, pat) { continue } macros[x.Name] = append(macros[x.Name], x) case *MacroAppend: pat := ".*?" if !re_is_in_slice_suffix(tgt_names, x.Name, pat) { continue } macros[x.Name] = append(macros[x.Name], x) case *MacroRemove: pat := ".*?" if !re_is_in_slice_suffix(tgt_names, x.Name, pat) { continue } macros[x.Name] = append(macros[x.Name], x) } } // models private/public, end_private/end_public ctx_visible := []bool{true} // 3rd pass: collect libraries and apps // this is to make sure the profile-converters get them already populated for _, stmt := range r.req.Stmts { wbld := &wscript.Build switch x := stmt.(type) { case *Library: tgt := hlib.Target_t{Name: x.Name} srcs, rest := sanitize_srcs(x.Source, "src") // FIXME: handle -s=some/dir if len(rest) > 0 { } val := hlib.Value{ Name: x.Name, Set: []hlib.KeyValue{ {Tag: "default", Value: srcs}, }, } tgt.Source = append(tgt.Source, val) if features, ok := g_profile.features["library"]; ok { tgt.Features = features } w_distill_tgt(&tgt, macros) wbld.Targets = append(wbld.Targets, tgt) case *Application: tgt := hlib.Target_t{Name: x.Name} srcs, rest := sanitize_srcs(x.Source, "src") // FIXME: handle -s=some/dir if len(rest) > 0 { } val := hlib.Value{ Name: x.Name, Set: []hlib.KeyValue{ {Tag: "default", Value: srcs}, }, } tgt.Source = append(tgt.Source, val) if features, ok := g_profile.features["application"]; ok { tgt.Features = features } w_distill_tgt(&tgt, macros) wbld.Targets = append(wbld.Targets, tgt) } } // 4th pass to collect for _, stmt := range r.req.Stmts { wpkg := &wscript.Package wbld := &wscript.Build wcfg := &wscript.Configure switch x := stmt.(type) { case *BeginPublic: ctx_visible = append(ctx_visible, true) case *EndPublic: ctx_visible = ctx_visible[:len(ctx_visible)-1] case *BeginPrivate: ctx_visible = append(ctx_visible, false) case *EndPrivate: ctx_visible = ctx_visible[:len(ctx_visible)-1] case *Author: wpkg.Authors = append(wpkg.Authors, hlib.Author(x.Name)) case *Manager: wpkg.Managers = append(wpkg.Managers, hlib.Manager(x.Name)) case *Version: wpkg.Version = hlib.Version(x.Value) case *UsePkg: deptype := hlib.PrivateDep if ctx_visible[len(ctx_visible)-1] { deptype = hlib.PublicDep } if str_is_in_slice(x.Switches, "-no_auto_imports") { deptype = hlib.RuntimeDep | deptype } wpkg.Deps = append( wpkg.Deps, hlib.Dep_t{ Name: path.Join(x.Path, x.Package), Version: hlib.Version(x.Version), Type: deptype, }, ) case *Alias: val := hlib.Value(*x) wcfg.Stmts = append(wcfg.Stmts, &hlib.AliasStmt{Value: val}) case *Macro: if _, ok := macros[x.Name]; ok { // this will be used by a library or application continue } val := hlib.Value(*x) wcfg.Stmts = append(wcfg.Stmts, &hlib.MacroStmt{Value: val}) case *MacroAppend: if _, ok := macros[x.Name]; ok { // this will be used by a library or application continue } val := hlib.Value(*x) wcfg.Stmts = append(wcfg.Stmts, &hlib.MacroAppendStmt{Value: val}) case *MacroPrepend: if _, ok := macros[x.Name]; ok { // this will be used by a library or application continue } val := hlib.Value(*x) wcfg.Stmts = append(wcfg.Stmts, &hlib.MacroPrependStmt{Value: val}) case *MacroRemove: if _, ok := macros[x.Name]; ok { // this will be used by a library or application continue } val := hlib.Value(*x) wcfg.Stmts = append(wcfg.Stmts, &hlib.MacroRemoveStmt{Value: val}) case *Path: val := hlib.Value(*x) wcfg.Stmts = append(wcfg.Stmts, &hlib.PathStmt{Value: val}) case *PathAppend: val := hlib.Value(*x) wcfg.Stmts = append(wcfg.Stmts, &hlib.PathAppendStmt{Value: val}) case *PathPrepend: val := hlib.Value(*x) wcfg.Stmts = append(wcfg.Stmts, &hlib.PathPrependStmt{Value: val}) case *PathRemove: val := hlib.Value(*x) wcfg.Stmts = append(wcfg.Stmts, &hlib.PathRemoveStmt{Value: val}) case *Pattern: wcfg.Stmts = append(wcfg.Stmts, (*hlib.PatternStmt)(x)) case *ApplyPattern: if cnv, ok := g_profile.cnvs[x.Name]; ok { err = cnv(wscript, x) if err != nil { return err } } else { wbld.Stmts = append(wbld.Stmts, (*hlib.ApplyPatternStmt)(x)) } case *Tag: wcfg.Stmts = append(wcfg.Stmts, (*hlib.TagStmt)(x)) case *ApplyTag: val := hlib.Value(*x) wcfg.Stmts = append(wcfg.Stmts, &hlib.ApplyTagStmt{Value: val}) case *TagExclude: wcfg.Stmts = append(wcfg.Stmts, (*hlib.TagExcludeStmt)(x)) case *MakeFragment: wcfg.Stmts = append(wcfg.Stmts, (*hlib.MakeFragmentStmt)(x)) case *SetEnv: val := hlib.Value(*x) wcfg.Stmts = append(wcfg.Stmts, &hlib.SetStmt{Value: val}) case *SetAppend: val := hlib.Value(*x) wcfg.Stmts = append(wcfg.Stmts, &hlib.SetAppendStmt{Value: val}) case *SetRemove: val := hlib.Value(*x) wcfg.Stmts = append(wcfg.Stmts, &hlib.SetRemoveStmt{Value: val}) case *Package: // already dealt with case *Action: // FIXME case *IncludePaths: wcfg.Stmts = append(wcfg.Stmts, (*hlib.IncludePathStmt)(x)) case *IncludeDirs: wcfg.Stmts = append(wcfg.Stmts, (*hlib.IncludeDirsStmt)(x)) case *CmtPathPattern: // FIXME case *CmtPathPatternReverse: // FIXME case *IgnorePattern: // FIXME case *Document: wbld.Stmts = append(wbld.Stmts, (*hlib.DocumentStmt)(x)) case *Library: // already dealt with case *Application: // already dealt with default: return fmt.Errorf("unhandled statement [%v] (type=%T)\ndir=%v", x, x, r.req.Filename) } } for _, stmt := range r.req.Stmts { switch stmt := stmt.(type) { case *PathRemove, *MakeFragment, *Pattern, *MacroRemove: r.wscript = true break case *Macro: if len(stmt.Set) > 1 { r.wscript = true break } } } // FIXME: refactor ? if strings.HasPrefix(r.pkg.Package.Name, "External") { r.wscript = true } // fixups for boost for _, tgt := range wscript.Build.Targets { for _, use := range tgt.Use { for _, kv := range use.Set { for i, vv := range kv.Value { vv = strings.Replace(vv, "-${boost_libsuffix}", "", -1) vv = strings.Replace(vv, "boost_", "boost-", -1) kv.Value[i] = vv } } } } return err }