반응형
작성일: 2024년 4월 25일

 

Go 언어를 2015~2020년 사이에 사용하고, 그 뒤로 거의 쓰지 않다가 오늘 go-pktgen 소스 코드를 보다가

몇년 사이 golang에 많은 변화가 있다는 것을 알았다.

내가 Go 언어를 좀 사용할 줄 안다고 생각했는데, 아니다. ㅠㅠ

새로운 Golang Feature도 파악하고, 다시 기억도 좀 살리기 위해 Golang 학습 문서를 봐야겠다. ㅠㅠ

 

오늘 기준으로 볼만한 온라인 문서를 찾아보니... 아래와 같다.

 

Effective Go (Go Official Site)

영어 문서: https://go.dev/doc/effective_go 

한국어 문서: https://gosudaweb.gitbooks.io/effective-go-in-korean/content/

 

Tucker의 Go 언어 프로그래밍 / 동영상 강의

YouTube 채널, Playlist: https://www.youtube.com/playlist?list=PLy-g2fnSzUTBHwuXkWQ834QHDZwLx6v6j

 

Tucker의 Go 언어 프로그래밍 (2021년, 공봉식)

종이 책(또는 eBook) 중에서는 이 책이 가장 괜찮은 것 같음 (나의 주관적 느낌)

 

Tucker의 Go 언어 프로그래밍 (책 표지)

 

 

Facebook 그룹

가끔 Facebook을 통해서 공식 행사를 알려준다. (예를 들어, GopherCon Korea 2024 같은 이벤트)

https://www.facebook.com/groups/golangko

 

 

 

 


 

반응형

 

작성일: 2024년 4월 24일

 

 

설치 작업을 시작하기 전에...

주의 - macOS에 기본 제공되는 VIM을 사용하는 경우 -> Homebrew로 재설치

모든 경우에 해당되는지 모르겠지만, 내 경우 macOS에 기본 제공되는 vim editor를 사용했더니

아래처럼 vim editor 화면에 E319 에러가 떴다.

VIM E319 Error

 

VIM E319 Error

 

아래와 같은 해결 방식이 정석인지는 모르겠지만, 내 경우에는 문제없이 vim과 vim-go 등 vim plugin들이 잘 동작했다.

따라서 macOS를 사용하는 사용자라면, Homebrew를 통해서 vim을 재설치하는 것을 추천한다.

 

$ brew remove vim
$ brew cleanup
$ brew install vim

 

그리고 macOS에 설치된 기본 vim editor보다 homebrew를 통해 설치된 vim editor의 실행 순서를 앞 당기기위 해서 아래와 같이 .zshrc 파일에 2줄을 추가한다.

 

$ cat ~/.zshrc
... 중간 생략 ...
alias vi=/opt/homebrew/Cellar/vim/9.1.0350/bin/vim
alias vim=/opt/homebrew/Cellar/vim/9.1.0350/bin/vim
... 중간 생략 ...

 

 

주의 - vim 버전 확인

$ brew info vim

 

만약, vim 8.0 이상이 아닌 경우라면 vim을 최신 버전으로 재설치

$ brew unlink vim
$ brew uninstall vim
$ brew install vim

 

 


 

 

 

공식 문서를 한번쯤 읽어주는 예절...

 

fatih/vimgo 공식 문서 열기

 

 


 

vim-plug 설치

vim-plug는 vim에서 사용할 수 있는 plugin manager로써 plugin을 설치하고 사용할 수 있게 해준다.

$ curl -fLo ~/.vim/autoload/plug.vim \
--create-dirs \
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim

 

vim-go 및 기타 plugin 설치

${HOME}/.vimrc 파일에 설치할 plugin을 정의한다.

$ vi ~/.vimrc

... 중간 생략 ...

" ------------------------------------------
" vim-go 설정
" -----------------------------------------
filetype plugin indent on

" vim-Plug Plugin List
call plug#begin('~/.vim/plugged')

" 자동완성을 해주는 Plugin.
" :CoCInstall coc-<lang> 으로 지원되는 Language 설치가 가능
" NOTE: 내 경우는 아래 neoclide/coc.nvim을 설치하지 않았다.
"       왜냐하면, 나는 node.js를 사용하지 않기 때문.
" Plug 'neoclide/coc.nvim', {'branch': 'release'}

" 많이 사용되는 plugin list
Plug 'majutsushi/tagbar'
Plug 'vim-airline/vim-airline'
Plug 'tpope/vim-fugitive'

" vim-go 사용을 위한 Plugin
Plug 'fatih/vim-go', { 'do': ':GoUpdateBinaries' }

" 자동 완성 Plugin 이다.
Plug 'SirVer/ultisnips'
Plug 'maralla/completor.vim'

" Misc utilities
Plug 'milkypostman/vim-togglelist'
Plug 'AndrewRadev/splitjoin.vim'
Plug 'mhinz/vim-startify'

" preview plugin
Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' } " fzf 사용시 꼭 설치;  ~/.fzf 에서 ./install --all 실행해야 함.
Plug 'junegunn/fzf.vim'

" Initialize plugin system
call plug#end()

... 중간 생략 ...

 

 

${HOME}/.vimrc 파일을 저장하고, 아래와 vim 편집기를 실행 후 vim 내부 명령을 수행한다.

$ vim 

... 중간 생략 ...

:PlugInstall

 

수십 초 정도 시간이 흐르면서 plugin을 설치할 것이다. (시간이 많이 걸리니까 다른 일을 하면서 신경을 끄는게 좋다)

vim plugins 설치 화면

 

 

 

 

vim-go 관련 설정 (개인 취향에 따라 설정 값 정하기)

아래 vim-go 관련 설정은 개인 취향에 따라 값을 정하면 된다.

 

$ vim ~/.vimrc

... 중간 생략 ...

" -------------------------------------------------------
" NOTE: *.go 파일을 저장할 때 Auto formatting하고, 
"       관련 go package를 자동으로 .go 소스 코드 파일에 추가해준다.
let g:go_fmt_command = "goimports"
let g:go_list_type = "quickfix"
let g:go_addtags_transform = "camelcase"

let g:go_autodetect_gopath = 1
let g:go_highlight_types = 1
let g:go_highlight_fields = 1
let g:go_highlight_functions = 1
let g:go_highlight_function_calls = 1
let g:go_highlight_extra_types = 1
let g:go_highlight_generate_tags = 1
let g:go_highlight_operators = 1
let g:go_auto_type_info = 1
let g:go_auto_sameids = 1

" NOTE: 문서를 Popup window 형태로 보여주기 (:GoDoc 명령)
let g:go_doc_popup_window = 1 

" NOTE: go source code 작성할 때, 실시간으로 자동 완성할 추천 문장을 보여줌.
let g:completor_filetype_map = {}
let g:completor_filetype_map.go = {'ft': 'lsp', 'cmd': 'gopls - remote=auto'}

" NOTE: quickfix 이동 및 open/close
nnoremap <C-n> :cnext<CR>
nnoremap <C-p> :cprevious<CR>
nnoremap <LocalLeader>q :call ToggleQuickfixList()<CR>

" NOTE: Coverage toggle
nnoremap <LocalLeader>c :GoCoverageToggle<CR>

" NOTE: Go 프로그램을 build, run, test하는 명령에 대한 설정
autocmd FileType go nnoremap <Tab>b :GoBuild<CR>
autocmd FileType go nnoremap <Tab>r :GoRun<CR>
autocmd FileType go nnoremap <Tab><Tab>r :GoRun %<CR>

autocmd FileType go nnoremap <Tab>t :GoTest<CR>
autocmd FileType go nnoremap <Tab><Tab>t :GoTestFunc<CR>
autocmd FileType go nnoremap <Tab>c :GoCoverageToggle<CR>
" -------------------------------------------------------

... 중간 생략 ...

 

 

vim-go 및 관련 plugin 설치 완료

 

 

간단하게 vim-go 동작 유무 확인하기

 

아래와 같이 새 파일 my-main.go 를 편집해보다.

$ vim  my-main.go

 

아래와 같이 기본 소스 코드 틀이 만들어진 .go 파일이 자동으로 생긴다.

vim-go가 자동으로 만들어준 새 소스 코드 파일

 

 

 

 

vim-go 사용법

 

 

많은 분이 잘 정리했으니까, 아래 문서를 보는 것을 추천!

 

A 문서 링크 열기

 

B 문서 링크 열기

 

 

 

 

 


 

반응형

작성일: 2023년 9월 20일

 

 

 

Client 장비에 network port가 여러개 있는 경우, 특정 network port를 지정하여 IP 패킷을 전송하고 싶을 때가 있다.

이럴 때, source IP address를 binding하면 특정 network port를 통해 IP 패킷이 전송된다.

참고:
  일반적으로 Target IP address로 가기 위한 routing path 및 network port는 
  OS에 있는 Routing table을 통해서 자동으로 결정된다.
  그러나 Target IP address로 가기 위한 routing path가 1개가 아닌 2개 이상인 경우에는
  어느 network port를 통해서 IP 패킷이 나갈지 예측하기 어렵다.  
package main

import (
    "fmt"
    "io/ioutil"
    "net"
    "net/http"
    "time"
)


func main() {
##
## NOTE:  14.33.80.179를 Source IP address로 지정한다. (즉, Source IP address binding)
##
    localAddr, err := net.ResolveIPAddr("ip", "14.33.80.179")
    if err != nil {
        panic(err)
    }

    localTCPAddr := net.TCPAddr{
        IP: localAddr.IP,
    }

    d := net.Dialer{
        LocalAddr: &localTCPAddr,
        Timeout:   30 * time.Second,
        KeepAlive: 30 * time.Second,
    }

    tr := &http.Transport{
        Proxy:               http.ProxyFromEnvironment,
        Dial:                d.Dial,
        TLSHandshakeTimeout: 10 * time.Second,
    }

    webclient := &http.Client{Transport: tr}

    // Use NewRequest so we can change the UserAgent string in the header
    req, err := http.NewRequest("GET", "https://www.naver.com", nil)
    if err != nil {
        panic(err)
    }

    res, err := webclient.Do(req)
    if err != nil {
        panic(err)
    }

    fmt.Println("DEBUG", res)
    defer res.Body.Close()

    content, err := ioutil.ReadAll(res.Body)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%s", string(content))
}

 

 

 

 


 

반응형

gcc 컴파일 명령어를 사용할 때는 -D 옵션을 이용해서 Source Code 밖에서 상수를 지정할 수 있었다.

그런데, Go Language에도 이런 똑같은 기능이 있을까?

 

답: Go에도 GCC와 똑같은 기능이 있다!!!

 

아래 예제처럼 하면 된다. ^^

 


 

매번 go build 명령을 입력하기 귀찮으니까, 아래처럼 go build 스크립트를 만들자.

$ cat  my_go_build.sh

#!/bin/bash

export MY_APP_VERSION=0.1.0

go build -ldflags "-X main.appVersion=${MY_APP_VERSION} -X 'main.buildDate=$(date +%F) $(date +%T)' -X 'main.devNote=New Feature ABC is added'"

$

 

 

go source code를 작성하자. (아래는 예시를 위해서 간단하게 만든 것이니까, 참고만 할것 !!!)

$ cat main.go

package main

import (
        "fmt"
)

func main() {
    getAppVersion()

	// My Main Routine ...
    fmt.Printf("My Main Routing ...\n")
}

$

 

 `go build -ldflags "-X ... -X ... -X ..."` 이런 식으로 입력한 외부 상수를 go source code 내부에서 참조(reference)할 수 있도록 아래와 같이 변수를 선언하고, 사용하자 !!!

package main

import (
        "fmt"
)

var (
    appVersion string
    buildDate string
    devNote string
)

func getAppVersion() {
    fmt.Printf("App Name   : almighty\n")
    fmt.Printf("Version    : %s\n", appVersion)
    fmt.Printf("Build Date : %s\n", buildDate)
    fmt.Printf("Dev Note   : %s\n", devNote)
}

 

 

위와 같이 go source code가 작성되었다면, 아래와 같이 build하고 실행 바이너리 파일을 실행해보자.

 

$ my_go_build.sh

$ my_example_app

App Name   : almighty
Version    : 0.1.0
Build Date : 2022-07-05 16:18:12
Dev Note   : New Feature ABC is added
My Main Routing ...

$
반응형

 

참고:
Go Module과 Package를 사용하는 방법이 Go Version에 따라 다를 수 있다.
아래 예제는 Go 1.17을 이용한 예제이고, 아마 Go 1.11 이상을 사용하는 경우라면 아래 설명이 잘 맞을 것이다.

 

여담:
나는 본업이 Go Language를 사용해서 개발하는 개발자가 아니다보니, 2~3년에 한번 잠깐 GoLang을 이용해서 개발하려고 하면 Go Package와 Module 때문에 시간을 허비하게 된다.
그래서 오늘은 기왕 스터디한 것을 2~3년 뒤에 또 GoLang을 사용할 일이 있을 경우, 쉽게 PackageModule 개념을 습득하기 위해 예제를 통해서 메모를 할까 한다.

 


 

Go PKG를 다루기 위해서는 크게 3가지 방식이 있다.

 

방식 A

  $GOPATH 경로를 설정하고, 이 $GOPATH 경로 안에서만 Package를 사용하는 방법. (암묵적 Module 사용하기)

 

방식 B    <-- 가장 많은 개발자가 선호하는 방식이 아닐까 생각한다.

  Module을 명시적으로 선언(go mod init x.y.z)하고, 내가 원하는 폴더 어디에서든 Go Source Code를 작성하는 방법.

 

방식 C

  go ven를 이용해서 현재 디렉토리 하위에서 모든 Package를 사용하는 방법.

 

각 Package 사용 방식에 대해서 아래에서 세부적으로 다룬다.

 

 

$GOPATH 경로를 선언하여 Package를 사용하는 방식

설명보다는 예제 코드를 보는 것이 좋을 듯~~~

 

$  vi  ~/.bash_profile
...
export GOPATH=$(go env GOPATH)
...

$  .  ~/.bash_profile
$  echo  $GOPATH
/Users/sejong/go

$  cd  $GOPATH
##
## 이제부터는 $GOPATH/src 디렉토리 밑에서만 코드를 작성해야 한다.
##
$  mkdir  -p src/myexample
$  cd  src/myexample
$  mkdir  myPkgAlpha
$  cd  myPkgAlpha
$  vi  example.go

package myPkgAlpha

import "fmt"

# 주의: 패키지 외부에서 참조할 수 있도록 함수 이름은 대문자로 시작해야 한다.

func MyExamplePrint() {
  fmt.Println("My Alpha PKG")
}

$  cd  ..
$  vi  main.go

package main

import (
  "fmt"
  "myexample/myPkgAlpha"
)

func main() {
  fmt.Println("This is main package.")
  myPkgAlpha.MyExamplePrint()
}

$  go  mod  init  myexample
$  go  mod  tidy
$  go  build

$  ./myexample
This is main package.
My Alpha PKG

$  tree
.
├── go.mod
├── main.go
├── myPkgAlpha
│   └── example.go
└── myexample
$

 

 

 

 

$GOPATH 경로가 아닌, 나만의 별도의 Project 폴더에서 Go Module 사용하는 방식

Go module을 사용하면 $GOPATH 경로가 아닌 아무 곳(디렉토리)에서 Go Source Code를 작성할 수 있는 자유가 생긴다.

긴 설명은 생략하고, 아래 예제처럼 Go Package와 Module을 사용하면 된다.

 

##
##  새로운 프로젝트를 위한 폴더를 만들자~
##
$  mkdir  go-mod-pkg-example
$  cd  go-mod-pkg-example

##
##  Go Package를 만들자.  (myPkgAA)
##  주의사항: package 이름과 folder 이름을 동일하게 작성해야 한다.
##
$  mkdir  myPkgAA
$  cd  myPkgAA

##
## 아래와 같이 myPkgAA 패키지에 대한 코드를 작성한다.
##
$  vi  example.go

package myPkgAA

const (
    COMPANY  = "Sejong Inc"
    LOCATION = "Seoul Korea"
)

##
##  Package가 1개만 있으면 심심하니까, 하나 더 만들자. (mypkg_bb)
##

$  cd  ..
$  mkdir  mypkg_bb
$  cd  mypkg_bb

##
## 아래와 같이 mypkg_bb 패키지에 대한 코드를 작성한다.
##
$  vi  example.go

package mypkg_bb

import (
    "fmt"
)

// NOTE: 함수 이름은 대문자로 시작해야 한다.
func DoSomething(company string, location string) {
    fmt.Println("[In mypkg_bb]")
    fmt.Println("  Company  :", company)
    fmt.Println("  Location :", location)
}


##
##  위에서 작성한 Package를 사용하는 Go Module Code를 작성하자.
##

$  go  mod  init  myexample.cncf/sejong/myexample
$  vi  main.go

// NOTE: package 이름을 main 으로 한다.
package main

// NOTE: 이 module의 이름이 "myexample.cncf/sejong/myexample" 이었기 때문에
//       myPkgAA 패키지를 import하려면 아래처럼 경로를 작성해야 한다.
import (
    "myexample.cncf/sejong/myexample/myPkgAA"
    "myexample.cncf/sejong/myexample/mypkg_bb"
)

func main() {
    mypkg_bb.DoSomething(myPkgAA.COMPANY, myPkgAA.LOCATION)
}

## 솔직히, 위 예제 패키지(로컬 패키지)만 이용하는 경우에는 아래 tidy 명령을 필요 없다.
## 그러나 main.go 파일에서 외부 pkg를 import 한 것도 포함했다면,
## 아래처럼 tidy 명령을 수행해야 한다.
$  go  mod  tidy

$  go  build

$  ./myexample
[In mypkg_bb]
  Company  : Sejong Inc
  Location : Seoul Korea
  
$  tree
.
├── go.mod
├── main.go
├── myPkgAA
│   └── example.go
├── myexample
└── mypkg_bb
    └── example.go

$

 

 

Vendor  방식의 패키지 관리

 

vendor 디렉토리에 특정 버전의 외부 패키지들을 저장 시킨 뒤 빌드에 참여시킴으로써 버전 일관성 문제를 해결 할 수 있다.

그리고 다운로드 불가한 외부 패키지를 어떻게든 한번만 구할 수만 있다면 다운로드 불가 문제도 피할 수 있다.

Container Image처럼 내가 작성한 Go Module 소스 코드가 있는 폴더에 의존성이 있는 모든 Package를 vendor/ 폴더 디렉토리에 다운로드 받는 다는 것이 가장 큰 특징이다.

 

자세한 내용은 아래 Go Module Vendoring 문서를 참고할 것 !!!

 

https://go.dev/ref/mod#go-mod-vendor

 

Go Modules Reference - The Go Programming Language

 

go.dev

 

## 코드를 작성한 상태에서 아래 명령을 실행~

$  mkdir MyExampleApp
$  vi main.go 
...
...

$  go mod vendor

$  ls
main.go   vendor/

 

 

 

 

반응형

 

REST API Server

Go 기본 Package만 사용해서 REST API Server 만들기

일단, 아래 블로그가 예제 코드를 복사해서 실습하기 좋게되어 있다.

https://woony-sik.tistory.com/12

 

Golang REST API 만들기

오늘은 Golang으로 간단한 REST API를 만드는 방법을 쓸까 한다. 바로 시작하자 우선은 Directory를 하나 만들고 시작 mkdir rest go module 등록 go mod init noah.io/ark/rest main.go 생성 touch main.go Direc..

woony-sik.tistory.com

 

 

gorilla package의 mux를 이용해서 REST API Server 만들기

이 블로그는 자동 Test하는 Code까지 포함되어 있다.

따라서 상용 Software PKG 개발할 때, 참고하면 좋다.

 

https://velog.io/@soosungp33/Golang%EC%9C%BC%EB%A1%9C-%EC%9B%B9%EC%84%9C%EB%B2%84-%EB%A7%8C%EB%93%A4%EA%B8%B04

 

 

Golang으로 웹서버 만들기(4)

RESTful API - GET과 POST 다뤄보기

velog.io

 

 

 

REST API Client

go-resty 라는 'REST client library'를 이용하면, 쉽게 REST API Client App을 개발할 수 있다.

아래 GitHub에 Case by Case로 Example이 있기 때문에 장황한 설명보다는 아래 Web Docs에 있는 Example Code를 보고 이해하고 따라해보는 것이 좋을 듯하다.

https://github.com/go-resty/resty
 

GitHub - go-resty/resty: Simple HTTP and REST client library for Go

Simple HTTP and REST client library for Go. Contribute to go-resty/resty development by creating an account on GitHub.

github.com

 

go-resty를 소개한 블로그이다. 쉽게 설명했으니까 한번 읽어보면 좋을 것이다.

go-resty를 사용하면, JSON Type의 Request / Response 를 Marshal, Unmarshal할 필요가 없다.

 

https://wookiist.dev/104
 

[Go/Golang] Go의 HTTP & REST Client 라이브러리 - Resty

Go의 HTTP & REST Client 라이브러리 - Resty API Client 이전 포스팅에서 다뤘던 Echo는 Go의 Web Framework입니다. Echo로 구현한 프로그램은 API Server 등으로 동작할 수 있고, 큰 어려움 없이 Web Server로..

wookiist.dev

 

 

 

 

 

기타 Reference 하면 좋을 Blog

 

https://doitnow-man.tistory.com/259

 

[Go Lang] 4. 실전 - http server + swagger 만들기

목표 web framework를 사용하여 간단한 web api server를 만들어 보겠습니다. 배포는 추후 포스트에서 다루겠습니다. 개발 환경 - ubnutu 18.04 - go version go1.16.3 linux/amd64 (업그레이드 방법: golang.org..

doitnow-man.tistory.com

 

 

블로그 작성자: sejong.jeonjo@gmail.com

 

 

반응형

 

 

작성일: 2024년 4월 11일

 

 

Go 언어를 사용해서 CLI를 개발할 일이 생겼는데, 기존 C언어로 개발하던 개발 습성 때문인지 CLI를 개발할 생각하니까 귀찮고 짜증부터 났다.

Java처럼 CLI를 쉽게 개발할 수 있는 Go Package가 있지 않을까 싶어서 구글링을 해보니, 역시나 GoLang은 개발 도구나 Library package가 훌륭하다는 것을 또 한번 느끼게 되었다.

 

일단 딱 눈에 들어온 것은 Cobra library였다.

https://pkg.go.dev/github.com/spf13/cobra#section-readme

 

cobra package - github.com/spf13/cobra - pkg.go.dev

SetOutput sets the destination for usage and error messages. If output is nil, os.Stderr is used. Deprecated: Use SetOut and/or SetErr instead

pkg.go.dev

 

Cobra is a library providing a simple interface to create powerful modern CLI interfaces similar to git & go tools.
Cobra is also an application that will generate your application scaffolding to rapidly develop a Cobra-based application.

 

위 Cobra Web Docs 문서에서 소개하는 것처럼 Cobra는 library이면서, application scaffoling을 만들어주는 개발 도구이다.

그래서 단순하게 library reference만 읽고 사용법을 익히는 것이 아니라 Cobra 도구를 이용해서 scaffolding을 만들고, 그 scaffolding 안에서 나의 logic을 추가해야 한다.

Cobra의 개발 절차만 잘 따라하면, 시간을 팍팍 줄여가면서 CLI를 붕어빵 찍어내듯이 만들 수 있을 것 같은 느낌적인 느낌이 들었다.

그럼 그 개발 절차를 자세히 들여다 보면 이렇다.

 

 

https://www.youtube.com/watch?v=so3VZwdWcBg&t=4s 

 

 

 

 

 

 

Reference

https://yjwang.tistory.com/137

 

[Go-lang] Cobra를 사용해서 cli 프로그램 개발

cobra 사용해서 cli tool을 개발해보고자 한다. 아무래도 Infra 작업을 하다보면 cli tool이 있으면 편하겠다는 생각을 하곤하는데 생각한 김에 만들어보고자합니다. cobra 프로젝트는 kubectl에서도 사용

yjwang.tistory.com

 

 

https://www.sktenterprise.com/bizInsight/blogDetail/dev/2755

 

[Golang] Cobra를 이용한 CLI 유틸리티 만들기 | 개발자 Story | SKT Enterprise

현대사회에서 대부분의 유저들은 휴대폰이나 컴퓨터 화면을 통해 쉽고 편한 GUI(Graphic User Interface)를 선호합니다. 그러나 GUI로는 채우기 힘든 여전히 CLI(Command Line Interface)를 선호하는 분야도 많

www.sktenterprise.com

 

https://nangman14.tistory.com/97

 

Go로 커맨드를 실행할 수 있는 CLI를 구현해보자 (With Cobra)

CLI(Command Line Interface)란 터미널을 통해 사용자와 컴퓨터가 상호작용하는 인터페이스를 말합니다. CLI는 그래픽을 통해 직관적으로 사용할 수 있는 GUI(Graphic User Interface)와 달리 명령줄로만 입력을

nangman14.tistory.com

 

 

 

 

기타: 다른 방식의 CLI 개발 예제

 

https://dev.to/tidalmigrations/interactive-cli-prompts-in-go-3bj9

 

Interactive CLI prompts in Go

Tidal Migrations 💓 CLI applications Do you like CLI applications? We love them! At Tidal...

dev.to

 

 

https://github.com/manifoldco/promptui

 

GitHub - manifoldco/promptui: Interactive prompt for command-line applications

Interactive prompt for command-line applications. Contribute to manifoldco/promptui development by creating an account on GitHub.

github.com

 

반응형

Macbook M1을 구입하고, 대체로 만족하면서 사용하고 있었는데

막상 go source code를 작성하고 compile하려고 생각해보니, 실제로 실행 파일(executable file)을 돌릴 대상 장비가 x86 cpu를 사용하는 경우가 대부분이라서 cross compile 필요성을 느꼈다.

아직 한번도 go cross compile을 하지 않았던터라, 이번 기회에 짧게 메모를 해본다.

 

cross compile 지원되는 OS와 CPU architecture 확인

$ go tool dist list
aix/ppc64
android/386
... 중간 생략 ...
darwin/amd64    <-- Intel Mac을 사용하는 경우
darwin/arm64    <-- M1 Mac을 사용하는 경우
...
linux/386
linux/amd64     <-- Intel Linux를 사용하는 경우 (아마 대부분 이 경우가 아닐까?)
linux/arm
linux/arm64
... 중간 생략 ...
windows/386
windows/amd64
windows/arm
windows/arm64
$

 

go cross compile

Case: Linux OS & Intel CPU

M1 Macbook에서 Linux OS에서 돌릴 executable file을 build하는 방법이다.

GOOS=linux  GOARCH=amd64 환경 변수만 설정하고, go build 명령을 수행하면 Linux OS에서 돌아가는 실행 파일이 만들어진다.

$ go mod init  andrew.space/myapp
$ go mod tidy
$ GOOS=linux GOARCH=amd64  go build 
$ ls
myapp
$

 

Case: Linux OS & ARM CPU

Intel Macbook에서 M1 Macbook에서 돌릴 executable file을 build하는 방법이다.

GOOS=darwin  GOARCH=arm64 환경 변수만 설정하고, go build 명령을 수행하면 M1 Mac OS에서 돌아가는 실행 파일이 만들어진다.

(여담이지만, 이미 M1 Mac OS는 OS 자체적으로 Intel->ARM 구조로 변환해주는 기능이 있어서 굳이 이렇게까지 열심히 Cross compile을 하지 않아도 된다)

$ go mod init  andrew.space/myapp
$ go mod tidy
$ GOOS=darwin GOARCH=arm64  go build 
$ ls
myapp
$

 

Case:  다양의 OS와 CPU에 대한 일괄적으로 Cross Compile하기

매번 대상 OS와 CPU에 맞춰서 Cross Compile하기 귀찮다면, 아래와 같이 모든 OS, CPU에 대해서 Cross compile하도록  script를 만든다.

#!/usr/local/bin/bash

archs=(amd64 arm64 ppc64)

for arch in ${archs[@]}
do
        env GOOS=linux GOARCH=${arch} go build -o myapp_${arch}
done

 

 

Tip:  .bashrc 파일에 GO 환경 변수 설정

위에서 설명한 $GOOS, $GOARCH 환경 변수를 매번 타이핑하기 싫다면

아래처럼 .bashrc 파일에 한번만 기록해놓자!!!

 

$  cat ~/.bashrc

... 중간 생략 ...

##
## For GoLang
##
export GOPATH=$(go env GOPATH)
export GO111MODULE=on
export GOOS=linux
export GOARCH=amd64

... 중간 생략 ...

$

+ Recent posts