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

I am trying to build a binary that will contain different modules, but at the same time, I want the user to be able to choose what modules will be included in the generated binary.

I have also asked in SE stackoverflow: https://softwareengineering.stackexchange.com/questions/378319/building-object-with-arbitrary-functionalities

I think this is out of my knowledge and I might need some help with this.

I am thinking about writing another Go Program that strip out functions from the go files before compilation. I have never done/heard about this before and it seems to be a bit hacky. Just wondering what will be the best approach to this problem.

Thanks! I have also attached a testing code that I used.

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('
')
    user_input = strings.TrimSuffix(user_input, "
")
    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.")
   }
}

Package g

package g

import "fmt"

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

Package f

package f

import "fmt"

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

What I did was just run env GOOS=linux GOARCH=386 go build test.go and run objdump -t test to see if the function is included in the binary after flipping the option values.

And you can see f and g are included in the binary, no matter the value of the option is true or 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

You can use Build Constraints You need to place each of your modules in separate file(s) . They don't need to be in a separate package.

At the top of each file in the foo module you place:

// +build foo

And at top of each file in the bar package you place

// +build bar

You can now build your binary with the foo module,

go build -tags foo ...

Or both

go build -tags 'foo bar' ...