sonumb

Go - release/debug 모드 빌드하기 - 1 본문

개발자 이야기/Go

Go - release/debug 모드 빌드하기 - 1

sonumb 2021. 11. 4. 17:05

개요

빌드 시, 릴리즈 모드에 따라 호출되는 함수의 기능을 달리하고 싶을 때가 있다.

"모드에 따른 다른 빌드"를 구현하는데, 두 가지 방법이 있다. 

두 방안에 대해 알아보고, 두 방안의 성능차이도 실제 측정하여 기록하였다. (이 주제의 두번째 게시물 마지막)

방안들

1. 빌드 시, 태그(-tags) 옵션을 이용하는 방법

파일을 두 개 동일하게 생성하되
그중 하나가 디버깅이라면 // +build debug을 맨 윗줄에,
디버깅이 아닌 것은 // +build |debug 을 소스코드 파일 맨 윗줄에 추가한다.

태그 옵션을 이용하여 모드에 따른 빌드는 가능하다.

⛔️ 주의
그러나 시스템 종속족인 기능과 같이, 빌드 시 "내용이 파일에서 분리가 되어야 하는 것"들인 경우 이를 이용하는게 가장 좋다. 왜냐하면, Go는 C/C++과 달리 프리프로세스가 없기 때문이다(😦) 따라서, 어떤 기능을 구현하는데, 호출해야 할 시스템 콜이 아예 없는 경우에 시스템별로 아예 파일들을 분리하여 각각 다른 파일에 내용을 작성하는 것이 맞다.

2. 빌드 시, 특정 변수에 모드를 기록. 이 변수를 이용하는 방법.

빌드시 특정 옵션으로 소스코드 내에 변수를 조작할 수 있을까? 가령 go build --set-value-into-variable-of-file='MODE=Debug' -o fooServer 으로 실행하면 소스코드내에 var MODE = """Debug" 로 변경되는 것을 기대할 수 있을까?

가능하다.

https://stackoverflow.com/questions/47509272/how-to-set-package-variable-using-ldflags-x-in-golang-build

 

How to set package variable using -ldflags -X in Golang build

I am creating an app using Go 1.9.2 and I am trying to add a version string variable to it using the ldflags -X options during the build. I've managed to set a Version variable in my main package by

stackoverflow.com

build 옵션에 ldflags 를 이용하여 소스 코드내 변수를 변경할 수 있다. (대개 버전 정보라던가, 패키지 이름을 바이너리 내에 기록하기 위해 이용한다.) 그렇다면 빌드시 모드를 기록하면, 모드에 따라 다른 함수가 호출이 가능할 것이다.

소스코드

아래는 위 1번 방안에 대한 소스코드다.
(2번 방안에 대한 소스코드는 2편에서...: )

https://sonumb.tistory.com/123

 

Go - release/debug 모드 빌드하기 - 2

개요 https://sonumb.tistory.com/124 Go - release/debug 모드 빌드하기 - 1 개요 빌드 시, 릴리즈 모드에 따라 호출되는 함수의 기능을 달리하고 싶을 때가 있다. "모드에 따른 다른 빌드"를 구현하는데, 두 가.

sonumb.tistory.com

main.go 파일

package main

import (
    "fmt"
    "time"
)

func foo() {
    _, _, fnname, err := GetTraceInfo()
    if err == nil {
        println(fnname)
    }

    time.Sleep(time.Second)
    fmt.Println("foo() : done")
}

func bar() {
    Trace()

    time.Sleep(1 * time.Second)
    fmt.Println("bar() : done")
}

func main() {
    foo()
    bar()
}

trace_debug.go 파일

// +build debug

package main

import (
    "fmt"
    "runtime"
    "errors"
)

func GetTraceInfo() (string, int, string, error) {
    pc, file, line, ok := runtime.Caller(1)
    if ok == false {
        return "", 0, "", errors.New("invalid calling")
    }

    fn := runtime.FuncForPC(pc)
    if fn == nil {
        return "", 0, "", errors.New("unknown method")
    }

    return file, line, fn.Name(), nil
}

func trace() {
    pc, file, line, ok := runtime.Caller(1)
    if ok == false {
        return
    }
    fnName := ""
    fn := runtime.FuncForPC(pc)
    if fn != nil {
        fnName = fn.Name()
    }

    fmt.Printf("%s:%d %s()\n", file, line, fnName)
}

trace.go 파일

// +build !debug

package main

import (
    "runtime"
    "errors"
)

func GetTraceInfo() (string, int, string, error) {
    pc, file, line, ok := runtime.Caller(1)
    if ok == false {
        return "", 0, "", errors.New("invalid calling")
    }

    fn := runtime.FuncForPC(pc)
    if fn == nil {
        return "", 0, "", errors.New("unknown method")
    }

    return file, line, fn.Name(), nil
}

func trace() {
    return
}

 

✅ 눈썰미가 좋은 분은 아시겠지만, GetTraceInfo() 함수가 중복되어 선언되어 있다.
따라서 중복제거를 위해 하나의 파일에 선언하면, trace를 위한 파일이 하나가 더 늘어난 총 3개가 생긴다.
관리해야할 파일이 늘어나는 점이 태깅옵션의 단점이자 장점이기도 하다. 흠..

Makefile 파일

all: release

release:
    go build -o buildSystem

debug:
    go build -tags debug -o buildSystem

clean:
    rm buildSystem

실행 및 결과

$ make clean all; ./buildSystem 
rm buildSystem
go build -o buildSystem
main.foo
foo() : done
bar() : done

$ make clean debug; ./buildSystem 
rm buildSystem
go build -tags debug -o buildSystem
main.foo
foo() : done
/Users/sonumb/work/go_exam/buildsystem/main.go:19 main.bar()
bar() : done

$

 

반응형