DEV Community

George Calianu
George Calianu

Posted on

5

Conditional compilation and runtime module names in Go

#go

Conditional compilation in Go language is a very nice feature but what if we want to know at runtime what modules we just compiled (do not confuse with the new Go modules!). We can define a file as a particular module of our application. So, knowing that if the files are compiled or not can be interesting but we haven't a standard mechanism to do this at runtime.

Let supose we have three dummy files main.go, module1.go and module2.go doing nothing and part of package main.

main.go file

package main

func main() {
}

module1.go file

//+build module1

package main

module2.go file

//+build module2

package main

Build arguments are given at compile time as tags, eg.:

 go build -tags="module1 module2" -o test

Unfortunately the build args are no more accesible after the compiling process, nowhere are writen what was compiled and what not. If we want for example at runtime to print the efective compiled files we simply can't.

Here it come the tricky part. In Go runtime package we have the Caller() function who knows the current invocation file and can be used to identify if the file is compiled or not. So, our dummy program become like following.

main.go file

package main

import (
    "fmt"
    "path/filepath"
    "runtime"
    "strings"
)

var mods []string

// include this in every init() function to detect linked modules
func _init() {
    _, file, _, _ := runtime.Caller(1)
    mods = append(mods, strings.TrimSuffix(filepath.Base(file), ".go"))

}
func init() {
    _init()
}

func main() {
    fmt.Println(mods)
}

module1.go file

//+build module1

package main

func init() {
    _init()
}

module2.go file

//+build module2

package main

func init() {
    _init()
}

We has defined _init() function which we will include in every init() functions from every module. At runtime init() functions will update an array of names which can be easy printed. The Caller() parameter mean the nesting level.

Running again.

go build -tags="module1 module2" -o test
./test
[main module1 module2]
go build -tags="module1" -o test
[main module1]

This technique suppose that you will have a consistency between the file name and build tags, so, be care to this aspect to avoid confusion.

Enjoy.

Imagine monitoring actually built for developers

Billboard image

Join Vercel, CrowdStrike, and thousands of other teams that trust Checkly to streamline monitor creation and configuration with Monitoring as Code.

Start Monitoring

Top comments (0)

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay