如何在功能级别而不是GoLang中的平台上进行元编程或条件编译?

时间:2018-09-13 05:20:36

标签: go design-patterns compilation

我正在尝试构建一个包含不同模块的二进制文件,但是同时,我希望用户能够选择将哪些模块包含在生成的二进制文件中。

我也在SE stackoverflow中问过:https://softwareengineering.stackexchange.com/questions/378319/building-object-with-arbitrary-functionalities

我认为这是我所不知道的,我可能需要一些帮助。

我正在考虑编写另一个Go程序,以便在编译之前从go文件中剥离功能。我以前从未做过/听说过,似乎有点不客气。只是想知道什么是解决此问题的最佳方法。

谢谢!我还附上了我使用的测试代码。

package main

import (
"strings"
"fmt"
"bufio"
"os"
"reflect"
"./f"
"./g"
)



func main() {
    // assume this is user input, enable f and disable g
    var options = map[string]bool{
        "f":true,
        "g":false,
    }

    // a map for all the functions
    m := map[string]interface{}{
        "f": f.F,
        "g": g.G,
    }
    // remove disabled function from the map
    for k,v := range options {
        if v == false{
            delete(m, k)
        }
    }


    // and now if user wanna use function g, it will return not ok since it is disabled in setting
    // and function f will work
    fmt.Println("Enter Options(f/g)")
    reader := bufio.NewReader(os.Stdin)
    user_input, _ := reader.ReadString('\n')
    user_input = strings.TrimSuffix(user_input, "\n")
    fmt.Println(user_input)
    // take input from user... f
    if x,ok := m[user_input]; ok {
        function := reflect.ValueOf(x)
        function_input := make([]reflect.Value, 1)
        function_input[0]=reflect.ValueOf("123")
        function.Call(function_input)
        fmt.Println("OK")
   } else {
        fmt.Println("Option doesnt exist or disabled.")
   }
}

包装g

package g

import "fmt"

func G(p string) { // removed second arguemt
    fmt.Println("function g parameters:", p)
}

包装f

package f

import "fmt"

func F(p string) {
    fmt.Println("function f parameter:", p)
}

我所做的只是运行env GOOS=linux GOARCH=386 go build test.go,然后运行objdump -t test,以查看翻转选项值后该函数是否包含在二进制文件中。

您可以看到f和g包含在二进制文件中,无论该选项的值为true还是false。

080bef10 g     F .text       000000a7 main.f
080befc0 g     F .text       000000c0 main.g
080bf080 g     F .text       00000544 main.main
080bf5d0 g     F .text       00000052 main.init

1 个答案:

答案 0 :(得分:2)

您可以使用Build Constraints 您需要将每个模块放置在单独的文件中。他们不需要放在单独的包装中。

foo模块中每个文件的顶部:

// +build foo

并放置在bar包中每个文件的顶部

// +build bar

您现在可以使用foo模块构建二进制文件

go build -tags foo ...

或全部

go build -tags 'foo bar' ...