기본 문법 요소들에 대해 알아보겠다. 이전에도 이야기했듯이 Go 는 코드 포맷에 대해 상당히 신경을 쓴다. 

1. 중괄호 { }, 소괄호 (), 세미콜론 ; 의 사용이 약간 다르다 (아래 참조)
2. Statement 들여쓰기 공백(space)은 탭으로 대체된다
3. 모든 코드는 UTF-8 기반 Unicode 이다.


▌세미콜론 ;

Go 는 ; 이 옵션이다. 있어도 되고 없어도 된다. 행여 쓰더라도 gofmt 를 돌리면 ; 은 삭제해버린다.
그러나 코드 작성 중에는 

fmt.Println("백 ");fmt.Println("입니다")
처럼 쓸 수 있다. 그러나 gofmt 를 돌리면 
fmt.Println("백 ")
fmt.Println("입니다")
이렇게 세미콜론을 없애고 두줄로 바뀐다.

▌중괄호 {}

중괄호는 반드시 inline 으로 시작하여야 한다. 다음줄에서 시작하면 오류다. 또한 if 문의 경우 else 문은 반드시 닫는 중괄호 } 뒤에 inline 으로 와야 한다.

package main

import "fmt"

func main(){
       some := 100
       if (some == 100) {
              fmt.Println("백 ");fmt.Println("입니다")
       } else {
              fmt.Println("뭥미")
       }

       for i:=i<10 i++ {
              fmt.Println("==> "i)
       }
}

▌소괄호 ()

소괄호는 함수가 아닌 경우 사용하지 않는다. 사용해도 무방하지만 gofmt 를 돌리면 이 역시 날아간다
위 코드를 gofmt 를 적용한 결과는

package main

import "fmt"

func main() {
       some := 100
       if some == 100 {
              fmt.Println("백 ")
              fmt.Println("입니다")
       } else {
              fmt.Println("뭥미")
       }

       for i := 0i < 10i++ {
              fmt.Println("==> "i)
       }
}

어찌 보면 이게 더 코드 가독성을 떨어뜨리는것 같기도 하지만, 함수 호출이 눈에 좀더 들어오기는 한다.

▌변수 선언

변수 선언은 아래 방법이 있다

var <변수> = <값> 를 사용한 자동 타입 결정 선언
var <변수> <타입> 을 사용한 명시적 타입 변수 선언
var <변수> [타입] [= <값>] 을 사용한 명시적 타입의 변수 선언 및 할당
<변수> := <값> 을 사용한 자동 변수 선언 및 값에 의한 타입 결정 후 할당

여러 변수 선언 방법은 
var <변수>[,<변수>,…] = <값> [,<값>,…]
var <변수>[,<변수>,…] <타입>
var (
     <위 여러 변수 선언 방법에서 var 키워드를 제외한 부분과 동일>
     [, <변수선언>]
     […]
)

/**
변수 선언 예제
*/
package main

import "fmt"

func main() {
       // 변수 선언 예제
       var val1 = "1"
       var val2 int
       var val3 int 3
       val4 := 0x04

       // 여러 변수 동시 선언
       var val5val6 = "5"6
       var val7val8 int
       var val9val10 int 910
       val11val12 := 11"12"

       var (
              val13val14 int 1314
              val15val16 = "15"16
       )
}

그런데 위 코드를 빌드하면 에러가 발생한다

1. “fmt” 를 import 하였으나 사용하지 않았음
2. 모든 변수를 선언하였으나 사용하지 않았음

다른 언어에서는 그냥 Warning 으로 지나칠것을 Go 에서는 에러로 간주한다. 이때에는 _ 를 사용하여 이러한 에러를 내지 않도록 할 수 있다.

import 문
import "fmt"

사용하지 않은 변수 에러 회피
var val1 = "1"
_ = val1

위 처럼 _ 를 사용하여 에러를 회피 가능하나 좋은 방법은 아니다.

▌숫자형 데이터 타입

uint8       the set of all unsigned  8-bit integers (to 255)
uint16      the set of all unsigned 16-bit integers (to 65535)
uint32      the set of all unsigned 32-bit integers (to 4294967295)
uint64      the set of all unsigned 64-bit integers (to 18446744073709551615)

int8        the set of all signed  8-bit integers (-128 to 127)
int16       the set of all signed 16-bit integers (-32768 to 32767)
int32       the set of all signed 32-bit integers (-2147483648 to 2147483647)
int64       the set of all signed 64-bit integers (-9223372036854775808 to 9223372036854775807)

float32     the set of all IEEE-754 32-bit floating-point numbers
float64     the set of all IEEE-754 64-bit floating-point numbers

complex64   the set of all complex numbers with float32 real and imaginary parts
complex128  the set of all complex numbers with float64 real and imaginary parts

byte        alias for uint8
rune        alias for int32


32bit 플랫폼은 int, uint = int32, uint32
64bit 플랫폼은 int, uint = int64, uint64 이다
float 타입은 플랫폼에 상관없이 32 나 64 를 직접 지정해줘야 한다

생소한 타입은 float64, complex64, complex128, rune 정도이다.
float64 : 64bit 의 float 이다
complex64 : float32 의 실수 + 32비트 허수부로 구성된 복소수
complex128 : float64 의 실수 + 64비트 허수부로 구성된 복소수


▌정수

정수는 크게 다를게 없으므로 Pass

▌실수

다른 언어와 마찬가지로 부동 소수점 방식으로 저장됨. 
지수는 e, E 로 표기하며 + 또는 - 이후에 소수점 위치를 나타냄

var val1 float64 0.1
var val2 float64 .2
var val3 float64 3.3123e3
var val4 float64 4.4123e+5
var val5 float64 5.5123e-5

val3 => 3312.3
val4 => 441230
val5 => 0.00005123

실수 연산의 오차율
실수 연산 시 Go 언어의 실수 오차범위는 1e-14 임. 값 비교 시 실수 값의 실수부 차를 제외한 값의 차이가 1e-14 이내이면 같은 실수값으로 보아야 하며, 비교시에는 math 패키지의 abs() 를 통해 비교해야 부호에 의한 오판 없음

▌복소수 (Complex)

실수부 + 허수부 로 표현되는 복소수. 고정소수점 과 부동소수점 으로 표현함.
복소수를 변수에 저장할때에는 실수부 또는 허수부 생략 가능함.

일단, 복소수의 수학적 개념을 보면

머리가 아플수도 있지만 허수 계산이 필요한 경우 이 complex 타입을 사용한다.


complex 타입을 위한 함수
real() : complex 에서 실수부 가져옴
imag() : complex 에서 허수부 가져옴

표현 방법:
var <변수> complex32 = <실수부> + <허수부>i 또는 complex(<실수부>, <허수부>) 로 표현

var val0 complex128 1.123e-4 2.234e+3i // 실수와 허수 모두 입력 
var val1 complex128 2.234e+3i
var val2 complex128 2.234e+3i // 허수부만 입력
var val3 complex128 complex(1.123e-42.234e+3i// complex() 로 입력

var rVal1 float64 real(val1) // 실수부
var iVal1 float64 imag(val1) // 허수부

위 처럼 표현 가능함

▌rune

UTF-8 character 를 저장하기 위한 타입. 값은 char 처럼 ‘ ‘ 로 묶어줌.

var val1 rune '굿'
var val2 = '준'
var val3 rune '\uAD7F'
val4 := '\uC900'

fmt.Println(val1" "val2)
fmt.Println(val3" "val4)
fmt.Printf("%c%c"val3val4)

실행결과
44415   51456
44415   51456
굿준

▌형변환

Go 는 암시적(자동) 형변환을 제공하지 않는다. 명시적인 형변환은 <타입>(<값>) 형태로 하면 된다.

아래 코드는 오류가 발생한다.
package main

import "fmt"

func main() {
   var val1 int64 1000000
   var val2 float32 1.234e-3

   var res = val1 + val2

   fmt.Println(res)
}

위 코드를
var res = float32(val1) + val2
처럼 수정해야 에러가 나지 않는다.

정수와 소수의 최소/최대 크기는 math 패키지의 정의로 확인할 수 있다
// int
fmt.Println(math.MinInt16)
fmt.Println(math.MaxInt16)
fmt.Println(math.MinInt32)
fmt.Println(math.MaxInt32)
fmt.Println(math.MinInt64)
fmt.Println(math.MaxInt64)

// float
fmt.Println(math.MaxFloat32)
fmt.Println(math.MaxFloat64)

결과는
-32768
32767
-2147483648
2147483647
-9223372036854775808
9223372036854775807
3.4028234663852886e+38
1.7976931348623157e+308

이외에, 변수의 Size 를 알아보려면 unsafe 패키지의 Sizeof() 를 사용하면 된다.

▌문자열

string 타입을 사용한다. + 연산자 사용 가능, == 연산자로 문자열 비교
len() 으로 전체 size 가져옴. utf8 패키지로 utf8 문자열의 카운팅 등

package main

import (
   "fmt"
   "unicode/utf8"
)

func main() {
   var str1 string "goodjoon.tistory.com "
   var str2 string `굿준 블로그`
   var str3 string `
어서 오세요
환영합니다` // 여러줄을 사용

   fmt.Println(str1" - "str2str3)
   fmt.Println("len str1 : "len(str1)) // len() 을 사용하면 문자열 전체 바이트 수 가져옴
   fmt.Println("len str2 : "len(str2))
   // utf8 패키지 사용하여 utf8 문자열의 문자 수 카운트
   fmt.Println("RuneCountInString(str1) : "utf8.RuneCountInString(str1))
   fmt.Println("RuneCountInString(str2) : "utf8.RuneCountInString(str2))

   fmt.Println(" + : "str1 + " - " + str2) // + 연산자
   fmt.Println(" == "str2 == "굿준 블로그"" / "str1 == str2) // Go 는 == 로 문자열 비교함
   fmt.Println("str1[1]"str1[1]) // 배열로 문자열 []byte 를 접근함. 수정은 불가함 read-only
   fmt.Println("str2[1]"str2[1])
   for i:=i<len(str2) i++ {
      fmt.Printf("%x|",str2[i])
   }
}

결과
/usr/local/go/bin/go run /Users/korean44/src/go_workspace/src/Grammar1/string_type.go
goodjoon.tistory.com   -  굿준 블로그 
어서 오세요
환영합니다
len str1 :  21
len str2 :  16
RuneCountInString(str1) :  21
RuneCountInString(str2) :  6
 + :  goodjoon.tistory.com  - 굿준 블로그
 ==  true  /  false
str1[1] 111
str2[1] 181
ea|b5|bf|ec|a4|80|20|eb|b8|94|eb|a1|9c|ea|b7|b8|


▌상수 및 Enumeration

C/C++ 처럼 const 로 상수 만듦. 
const 로 선언하는 문자열은 var 키워드를 붙이지 않음.
iota 키워드를 사용하면 const 선언 내에서 1씩 증가하는 수가 생성됨
const 변수는 선언하고 사용하지 않아도 에러 나지 않음

package main

import "fmt"

const CONST_NUM 100
const CONST_STR string "굿준"
const (
   RED int 0
   GREEN int 1
   BLUE int 2
)
const (
   ZERO iota       // 0 부터 시작하며 하나씩 증가
   ONE
   TWO
   THREE
   FOUR
)
const (
   HANA 0
   DUL
   SET
)

func main() {
   fmt.Println(CONST_STR)
   fmt.Println(GREEN)
   fmt.Println(THREE)
   fmt.Println(DUL)
}



▌연산자

나머지는 다른 언어들과 동일하며, 몇가지 연산자만 추가설명

&^ : AND 연산 값을 NOT 연산 함 

func main() {
   var val1 byte 0x70 // 0111 0000
   var val2 byte 0x11 // 0001 0001
   var val3,val4 = 0x700x11

   fmt.Println("==== Bit Operator ====")
   fmt.Printf("%08b\n"val1 ^ val2) // XOR 연산
   fmt.Printf("%08b\n"^val1)
   // &^ : 좌항과 XOR 연산 값을 다시 좌항과 AND 연산 함 (좌항 값의 Bit Clear)
   fmt.Printf("%08b\n"val1 &^ val2)
   fmt.Printf("%08b\n"(val1 ^ val2) & val1) // &^ 과 같음
   val3 &^= val4
   fmt.Printf("%08b\n"val3)

   // Pointer 관련 연산자
   var val5 = 10
   var ref1 = &val5

   fmt.Println("==== Pointer ====")
   fmt.Printf("%d\n",*ref1)
   fmt.Printf("val5's address : %x / ref1's value : %x"&val5ref1)
   
}

결과
==== Bit Operator ====
01100001
10001111
01100000
01100000
01100000
==== Pointer ====
10
val5's address : c82000a2a8 / ref1's value : c82000a2a8



반응형

'Software Development > Go (golang)' 카테고리의 다른 글

3.4 Go - 제어문  (340) 2016.03.01
3.3 Go - Package  (4) 2016.03.01
3.1 Go - Hello World  (5) 2016.02.29
2. Go - 개발환경 구성  (3) 2016.02.28
1.3 Go 언어란? - 다른 언어와 비교  (999) 2016.02.28
블로그 이미지

Good Joon

IT Professionalist Since 1999

,

GO 언어 익히기

Go 언어는 Strong Type 의 언어이며 문법이 매우 간결한 편이다. 또한 gofmt 와 같은 유틸리티가 기본적으로 내장되어 있어 코드를 일관성 있는 포맷으로 유지시키도록 되어있다.

LiteIDE 의 경우, 심지어 작성중인 코드를 ctrl+S 로 저장함과 동시에 gofmt 가 동작하여 코드를 일관성있는 포맷으로 변경시켜준다. 아키텍트였던 필자에게는 Java 개발 시 PMD 와 Eclipse 의 Formatter 기능을 합쳐놓은듯한 기분이 든다. 

이 강좌는 적어도 한두개 이상의 프로그래밍 언어를 할 줄 아는 사람을 대상으로 하기 때문에 가급적 연산자나 타입의 “의미”에 대해서는 길게 언급하지 않으며 Java, C/C++, JavaScript 와 비교해볼 때 새롭거나 다른 개념이 적용된 부분에 대해 주로 이야기 하도록 하겠다.


Hello World

Fortran, COBOL, Shell Script 까지 포함하여 이 Hello World 를 찍어볼 언어가 몇가지나 되는지 기억도 안날정도이다. 못해도 20여개 이상의 언어로 Hello World 를 찍어본듯하다.
이번에도 또 찍어보자. Hello World 를 찍고 Go 언어에 대해 설명을 들어가보도록 하겠다.

일반 모든 진행은 LiteIDE 를 사용하여 해 나아가므로 화면캡춰를 자주 사용하더라도 양해 부탁한다.

LiteIDE 를 실행한 후 제일 먼저 해주어야 할 것은 바로 GOPATH 를 LiteIDE 에 추가해주는 것이다.
(Windows 버전은 아직 확인을 안해보았지만 Mac OS X 버전의 경우, .app 이 사용하는 환경변수와 Terminal 에서 사용하는 Shell 의 환경변수가 공용하지 않기 때문에 Mac 에서는 GOPATH 를 수동으로 입력해주어야 한다)


메뉴에서 “Manage GOPATH…” 를 누르면 다이얼로그가 뜨는데, 하단부의 “custom Directories” 부분에 원하는 GOPATH 를 추가해준다

GOPATH 가 추가된 모습이다.

File>New… 메뉴를 누르면 New Project or File 다이얼로그가 보인다.
GOPATH: 리스트에서 위에서 추가한 GOPATH 를 “더블클릭” 한다. 그러면 하단의 Location: 부분의 경로가 업데이트 된다.

Template: 에서 Go Source File 을 선택하고, Name 에 HelloWorld 를 입력한다.
Location: 을 $GOPATH/src/HelloWorld 로 입력하고 OK 를 누른다


HelloWorld.go 파일이 자동으로 생성되었지만 좌측 상단의 “1:Folders” 뷰에 아무것도 보이지 않는다.
나중에 설명하겠지만 일단 “Folders” 로 선택되어있는 콤보박스를 눌러 “File System” 으로 다시 선택한다. 그러면 HelloWorld.go 가 보일것이다.


아래는 기본으로 생성된 HelloWorld.go 파일의 코드이다.
// HelloWorld
package main

import (
       "fmt"
)

func main() {
       fmt.Println("Hello World!")
}

package 는 현재 go 파일이 속하는 패키지 이름을 적는다. main 패키지는 특수한 패키지로, 프로그램의 Entry Point 가 되는 main() 함수를 갖는 Entry 패키지임을 지정하는 것이다.

import "fmt" 는 fmt 패키지를 import 한다는 의미이다.
    fmt 패키지는 Formatted I/O 패키지로, C 의 printf 나 println 과 유사한 함수들을 포함한다.

func 함수 선언자이다

CMD+B 를 눌러서 Build 를 해보면, File System Window 에 파일이 하나 추가된것을 볼 수 있다

소스파일이 컴파일되고 실행파일이 빌드되었다. Mac OS X 기준으로 2.1MB 용량의 파일이 생겼다. 
Go 는 VM 자체를 개별 실행파일에 포함하도록 되어있어서 기본적인 Footprint 사이즈가 이정도 나오게 된다.

CMD+R 로 실행을 시켜본다.

하단의 Output Window 에 Hello World! 가 출력됨을 볼 수 있다.


반응형

'Software Development > Go (golang)' 카테고리의 다른 글

3.3 Go - Package  (4) 2016.03.01
3.2 Go - 기본 문법 및 Type  (326) 2016.02.29
2. Go - 개발환경 구성  (3) 2016.02.28
1.3 Go 언어란? - 다른 언어와 비교  (999) 2016.02.28
1.2 Go 언어란? - 주요 특징  (845) 2016.02.28
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
Go 개발환경 설치는 어렵지 않다. 

우선 Go SDK 를 다운로드 받고, IDE 만 준비되면 된다.

Go 설치
공식 홈페이지인 golang.org 사이트에 가서 자신의 OS 에 맞는 GO SDK 를 다운로드 하고 설치한다.


설치가 완료되면 Terminal (Windows 는 Command Prompt)에서 go version 으로 설치가 잘 되었는지 확인한다.

버전이 보이면 잘 설치된것이다.


▌Lite IDE 설치
이번에는 LiteIDE 를 설치해본다. Source 로 빌드할 수도 있지만 소스를 수정할 일이 없으므로 바이너리를 다운로드 받아 실행해본다.
1. X28 버전 다운로드
2. /usr/local 밑에 압축 풀기
3. LiteIDE.app 실행


▌Workspace 디렉토리 구조
Go 언어는 언어 자체적인 패키지 관리를 한다고 앞서 이야기 하였다. 이런 관계로 Go 는 특정한 구조의 디렉토리와 이러한 디렉토리의 위치를 알기 위한 환경변수 설정이 필요하다.

원하는 Workspace 디렉토리를 결정하고 만든다. 나는 /Users/korean44/src/go_workspace 를 Workspace 로 결정했다.

Workspace 디렉토리는 GOPATH 라는 이름의 환경변수로 정의되어 있어야 go 언어가 이후 개발할 프로젝트에서 import 를 통해 지정한 패키지가 없을 때 GOPATH 에서 찾거나 없는 패키지를 다운로드 받아 $GOPATH/pkg 디렉토리에 저장한다

GOPATH 디렉토리의 구조는 아래와 같다.

우리가 myproject 를 만든다면 위 처럼 GOPATH(Workspace)/src 밑에 프로젝트를 만들면 된다.
GOPATH 를 Workspace 로 볼 수도 있지만, 단일 Project 를 GOPATH 로 잡을 수도 있다. 그러면 해당 프로젝트의 구조가 저렇게 bin, pkg, src 처럼 정형화 되어 깔끔해질 수도 있다.

▌환경변수

위에서 GOPATH 환경변수가 필요하다는 것을 알았으므로 일단 .profile 이나 windows 의 경우 환경변수를 편집하여 GOPATH 변수를 추가해준다.

go 와 관련된 환경변수는 go env 를 실행하면 출력된다
macbook-joon:go_workspace korean44$ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/korean44/src/go_workspace"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GO15VENDOREXPERIMENT="1"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics 
            -Qunused-arguments -fmessage-length=0 -fno-common"

CXX="clang++"
CGO_ENABLED="1"
macbook-joon:go_workspace korean44$ 

이중에
$GOROOT : go 가 설치된 경로
$GOPATH : 위에서 설명한 GOPATH. Workspace 로 이해가 편하도록 설명하였으나 사실은 Dependency 관리를 위해 참조할 pkg, src 디렉토리와 go install 시에 실행파일을 위치시킬 bin 디렉토리를 포함하는 지정 구조의 디렉토리 루트가 필요해서 지정하는 것이다.

반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
Go 로 응용프로그램을 개발하기 위해서는 일단 Go SDK 를 설치하여야 한다.
그후 개발자라면 고민하게 될 것은 바로 IDE 이다. 

Go SDK 와 텍스트 편집기만 있으면 개발 가능하다고 Golang 사이트에서는 이야기 하지만 사실 어떤 언어이건 텍스트 에디터만 있으면 개발되지 않는 언어가 어디있겠는가? 하지만 디버깅을 하고 파라미터 정보를 보여주고 Definition 이나 Reference 를 보여주는 등의 기본적인 개발지원 기능이 있는 IDE 가 없다면 어떠한 개발자라도 왠만한 이유 아니면 그 언어로 개발하려고 하지 않을것이다.

Go 언어는 아직 나온지 얼마 안된 언어인 탓에 Go 언어를 지원하는 제대로된 IDE 는 아직 그리 많지 않은편이다 (Java 나 C/C++ 의 IDE 들은 정말이지 아직 Go 의 IDE 들에게는 넘사벽이다)

Cloud 에디터, 텍스트 편집기의 Syntex Highlight 플러그인을  제외한 Go 언어를 위한 대표적인 설치형 IDE 는 아래와 같다.

Eclipse - GoClipse : Eclipse 의 플러그인
GoWorks - Netbeans 의 플러그인이나 Netbeans 기반의 Standalone 형태로 사용
IntelliJ IDEA - IntelliJ IDEA 용 플러그인
LiteIDE - Go 언어 전용의 IDE 로, Go 언어 릴리즈 초기부터 함께한 IDE
Visual Studio - Visual Studio 용 플러그인
그외에 상용 IDE 로는, KomodoIDE, Zeus 등이 있음

위 IDE 들 중 빠르고 깔끔한 LiteIDE (크로스플랫폼지원)를 Go 개발자들이 가장 많이 사용중이므로 본 강좌에서도 이 IDE 를 기준으로 하도록 한다.

Lite IDE 중에서도 Mac 버전을 기준으로 하겠으나, 어차피 Qt 기반의 UI 이므로 UI 구성은 Windows 나 Mac 이나 Linux 나 유사하여 다른 플랫폼에서도 큰 문제없이 이해가 가능할것이다.
(사실 Windows 에서 주로 작업하지만 당분간 노트북으로 글을 써야하는 상황에 노트북이 맥북 밖에 없다)

반응형

'Software Development > Go (golang)' 카테고리의 다른 글

3.2 Go - 기본 문법 및 Type  (326) 2016.02.29
3.1 Go - Hello World  (5) 2016.02.29
1.3 Go 언어란? - 다른 언어와 비교  (999) 2016.02.28
1.2 Go 언어란? - 주요 특징  (845) 2016.02.28
1.1 Go 언어란? - History  (169) 2016.02.27
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
IT 를 하며 C, C++, Java, Objective C, JavaScript 와 같은 프로그래밍 언어를 배우고 사용해왔지만 어떠한 언어이든 최고의 언어는 없으며 내가 해야하는 업무나 개발에 최적의 언어만이 있었고, 또 그 업무가 바뀌면 언어는 업무를 위한 수단에 불과하지 않았다.

그럼에도 불구하고 천여개가 넘는 언어들이 생겨나고 또 인정받는 이유는 분명 그 언어가 목표하는 시장이 있으며 그 시장에서 필요로 하는 “효과”를 잘 보여주었기 때문이었다.

Go 언어 또한 목표로 하는 시장이 분명히 있으며, C/C++, Java, JavaScript, PHP, Swift 등등 셀 수 없이 많은 언어들을 제치고 “언어의 왕좌”를 차지하려는 목적으로 개발된 것은 아니다. 

프로그래밍 언어들이 갖는 특성은 모두 제각각이며 언어의 절대적 우열을 가리기 위한 잣대란 존재하지 않는다. 아래 비교자료들은 재미삼아 보는것을 권장하며, 무엇보다 “목적에 맞는 언어”를 선택하는데에 시간을 투자하고, Go 언어 또한 이후 강좌들을 통해 직접 그 장점과 단점을 체감하며 “자신이 느끼는 언어 활용 적합 용도”를 찾기를 바란다.


[인기도에 따른 언어 비교]
RedMonk 의 2016년 1월 프로그래밍 언어 Ranking 이다.

X 축은 Github 내 Project 들이 즐겨 사용하고있는 언어, Y 축은 Stack Overflow 에서의 언어 Tag 를 통한 인기도이다. 두가지를 합쳐보면 최종 Top 10 인기순위는

1 JavaScript
2 Java
3 PHP
4 Python
5 C#
5 C++
5 Ruby
8 CSS
9 C
10 Objective-C
11 Shell
12 Perl
13 R
14 Scala
15 Go
15 Haskell
17 Swift
18 Matlab
19 Clojure
19 Groovy
19 Visual Basic

정도가 된다. Go 언어는 15위에 Rank 했다.
Go 언어가 실질적으로 활용되기 시작한 2011년 부터 보면 5년 남짓 된 언어이며, 이를 감안한다면 다른 언어들 대비 상당히 빠른 속도로 확산되고 있다는것을 알 수 있다.


하지만 여전히 JavaScript, Java, PHP, Python, C/C++ 과 같은 전통적인 언어들이 최상위권에 위치한다. 위 언어들 중 JavaScript, PHP, Python 은 Script 언어이다. 태생 목적과 동작방식 자체가 다르기때문에 이를 직접 비교하는것은 무리일듯 하다. (JavaScript 는 Node.js 를 만나 Java 나 C/C++, Go 가 목적하는 영역과 상당부분의 교집합이 생겨나긴 했다)

아래 자료는 Anderson 과 Retting 의 Fannkuch 라는 이름의 벤치마크 점수이다.
이 벤치마크는 긴 수열을 주고 정렬 작업과 Checksum 작업을 n! 만큼 하는 알고리즘을 수행하는 형태이다. 결과는 최종 수행 시간, 사용한 메모리와 CPU 등이다.
 
× source code secs KB gz cpu cpu load
1.0 C gcc #5 9.16 3,624 910 35.83 95% 99% 99% 99%
1.2 Ada 2005 GNAT #3 11.25 4,116 2100 44.84 100% 100% 100% 100%
1.4 C++ g++ #5 13.12 2,032 1440 51.38 99% 99% 94% 100%
1.5 Rust #2 13.42 8,464 1191 53.10 96% 100% 100% 100%
1.5 Swift #2 13.55 7,036 1152 50.53 91% 99% 90% 93%
1.5 Fortran Intel #3 13.98 10,536 1148 55.74 100% 100% 100% 100%
1.5 C++ g++ 13.98 1,844 1059 54.72 99% 99% 94% 100%
1.6 C gcc #2 14.72 964 1557 57.71 99% 99% 100% 95%
1.7 Scala #2 15.23 36,820 1017 59.62 99% 98% 98% 97%
1.7 C++ g++ #4 15.98 2,024 1439 62.94 98% 99% 98% 99%
1.8 OCaml #3 16.25 22,308 1017 0.01 100% 100% 100% 100%
1.8 Go 16.41 1,884 900 65.25 99% 100% 99% 100%
1.8 OCaml #4 16.49 12,160 1004 0.01 100% 100% 100% 100%
1.8 Lisp SBCL #4 16.58 47,692 1518 64.33 100% 98% 99% 92%
1.9 Pascal Free Pascal 17.39 1,732 1018 69.38 99% 100% 100% 100%
1.9 Java  17.41 33,032 1282 68.64 98% 98% 99% 99%

물론 위의 한가지 알고리즘 계산이 언어의 실행속도를 대표하는것은 아니다. 문자열이나 I/O, 병렬처리 등 언어의 성능을 Benchmark 대상요소는 수없이 많다. Binary Tree 와 정규식 처리 등에서는 Java 가 Go 언어 보다 2배 이상의 좋은 성능을 내며, V8 엔진에서의 JavaScript 가 Java 보다 2배 이상의 성능을 낸다. 
(여기서 다른 알고리즘 실행시간 비교자료들도 볼 수 있다)

향후에 실행시간 이외에도 다른 비교자료를 업데이트 해보도록 하겠다

반응형

'Software Development > Go (golang)' 카테고리의 다른 글

3.1 Go - Hello World  (5) 2016.02.29
2. Go - 개발환경 구성  (3) 2016.02.28
1.2 Go 언어란? - 주요 특징  (845) 2016.02.28
1.1 Go 언어란? - History  (169) 2016.02.27
1. Go 언어란?  (317) 2016.02.27
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
많은 사람들이 Go 언어를 두고 높은 “생산성” 과 “성능”을 위한 언어라고 이야기 한다.

Go 언어의 주요 특징은 아래와 같다.

  • 정적 타입, 강 타입
    C/C++, Java 와 같이 Compile Time 에 Type 결정이 이루어 지며, 코드 내에서 암시적 형변환이 일어나지 않는다.

  • 컴파일 언어
    C/C++, Java, C# 등과 같이 컴파일이 필요한 언어임. Java 나 C# 과 달리 실행파일을 만들어냄.  별도의 Runtime 환경이 필요없어 실행 환경이 복잡하지 않음.

  • 가비지 컬렉션
    실행파일 내에 Garbage Collector 가 탑재 됨.

  • 병행성(Concurrency)
    Multi Thread, Multi Core 에 Go Routine 이라는 단위의 함수실행을 한 Thread 나 Core 별로 동시에 실행시킬 수 있다. Thread 와 Go Routine 은 1:N 관계를 이룰 수 있다.

  • 멀티코어 환경 지원
    Go Routine 간에 “채널” 을 통해 통신하여 데이터를 공유하고 실행 순서를 제어할 수 있다. 제어는 Multi Thread 의 동기화와 비슷하다.

  • 모듈화 및 패키지 시스템npm, pip, gem 이나 Maven과 같은 모듈 의존성에 따른 패키지 관리를 언어 차원에서 지원. 인터넷 상의 패키지들을 바로 가져올 수 있다. import 키워드만 있으면 되며, go get 이나 go install 명령으로 자동으로 패키지들을 가져온다.
    import "github.com/kylelemons/go-gypsy/yaml"
                 ^         ^          ^     ^
                 |         |          |     `-- Package name
                 |         |          `-------- Project name
                 |         `------------------- Author's handle
                 `----------------------------- Hosting site
    
  • 빠른 컴파일 속도
    C/C++ 은 헤더파일 처리 부담으로 컴파일 속도가 느리고 의존관계가 복잡함. Go 는 헤더파일이 없고 소스코드를 패키지화 하므로 변결 시 패키지만 재컴파일 함. 문법도 최대한 단순화 하여 컴파일 속도도 빠르고 생산성이 좋음.

참고로, Go 언어를 사용해본 한 개발자 분은 Go 에 대해 이렇게 이야기 한다.

  1. 컴파일러 언어의 이점 : 저는 컴파일러 언어로 돌아가는 것에 대한 이점을 알고 있습니다. 컴파일러는 프로그램이 실행가능한지 여부를 이론적으로 판단하여 에러를 체크할 뿐 아니라 이후에 문제를 해결하도록 에러를 도출 합니다. Go의 특별한 능력은 아니라 할 수 있지만 Go는 인터프리터와 함께 컴파일 기능을 동시에 가지고 있습니다.
  2. 표준 포맷 : Go는 C나 PHP보다는 엄격한 코딩 포맷을 가지고 있습니다. 파이썬보다는 덜 엄격하지만, 파이썬의 포맷보다 유연합니다.
  3. 작은 언어 : Go는 아주 작고 쉽게 설치가 됩니다. 이는 프로그래밍을 배우고 시작하는데 도움을 줍니다.
  4. 많은 기능 들 : Go언어는 파이썬과 같이 많은 서버프로그램의 기능을 언어 자체에 내장하고 있습니다. 가령, 웹서버를 돌린다거나 소켓 서버를 작성하는 것, OS의 내부 기능을 엑세스하는 것등 파이썬과 거의 유사하게 이용할 수 있습니다.
  5. 쉬운 다중 작업 : Go의 채널과 go루틴은 다중작업을 쉽게 처리하도록 해줍니다. 이는 Node.js와 파이썬의 Twisted보다 나은 기능을 제공합니다. 
  6. 쉬운 시작 : Go를 배우는데 시간이 그렇게 오래 걸리지 않습니다. 개발 환경도 컴파일러와 에디터만 있으면 바로 시작 가능합니다.
  7. 빠른 개발 속도 : Go의 개발 생산성은 무척 높습니다. 언어 내부에 공용 서버 컴포넌트가 있어 복잡한 서버를 빠른 시간안에 작성 할 수 있습니다. 적은 코드는 정확한 기능을 빠르게 만든다는 것을 의미합니다.
  8. 멀티코어 지원, 높은 성능 : 언어의 실행은 놀랍게도 빠르고 안정적입니다. 심지어 파이썬으로 개발하는 사람들에게는 경이적이다는 생각까지 들 정도입니다. 파이썬과 Node.js의 런타임과는 달리 Go의 런타임은 다중 OS 쓰레드를 지원하고, 동시적인 실행기능을 지원합니다.

Go 언어는 서버, 브라우져, Database, 기타 복잡하고 큰 사이즈의 어플리케이션 개발에 유리함. 그러나 엄격한 메모리 제어를 필요로하는 시스템 라이브러리, Device Driver, OS 개발에는 적합하지 않음.


반응형

'Software Development > Go (golang)' 카테고리의 다른 글

3.1 Go - Hello World  (5) 2016.02.29
2. Go - 개발환경 구성  (3) 2016.02.28
1.3 Go 언어란? - 다른 언어와 비교  (999) 2016.02.28
1.1 Go 언어란? - History  (169) 2016.02.27
1. Go 언어란?  (317) 2016.02.27
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
Go 언어 프로젝트는,

2007년 9월에 Robert Grimmer, Rob Pike, Ken Thompson 이라는 천재 프로그래머가 분산운영체제와 관련된 작업을 하면서 시작되었다.

2008년 초, Ken Thompson 이 C 코드를 만들어내는 컴파일러를 개발하게 되고, 2008년 Google 이 풀타임 잡으로 승격
2008년 5월, Ian Taylor 가 Go 언어를 GCC 를 통해 컴파일 할 수 있도록 개발함
2008년 말,  Russ Cox 가 합류하며 Go 언어의 프로토타입을 만들어냄
2009년 11월 10일, Mac OS X 과 Linux 플랫폼을 대상으로 Go 언어를 Release 함

위와 같은 History 를 갖는 Go 언어는 저~ 위의 멤버들의 이력만 보아도 “드림팀”으로 결성된 프로젝트임을 알 수 있다.

Robert Grimmer : Chrome V8 엔진 개발, Java Hotspot 컴파일러 개발
Ken Thompson : UNIX 개발 주역, C 언어의 모체인 B 언어 개발
Rob Pike : UTF-8 개발, 분산 운영체제 개발 전문가
Russ Cox : 하버드대 출신으로, 천재 개발자로 불리움
Ian Taylor : 예일대 출신으로, 주로 GNU Toolchain 개발

위 개발자들은 아래와 같은 목적으로 Go 언어를 디자인 하고 개발한다

1. Static Type (정적 타입) 언어의 효율성과 Dynamic Type (동적타입) 언어의 쉬운 개발방법 지원
2.  타입 안정성과 메모리 안정성
3. 병행성(Concurrency) 과 훌륭한 통신기능 지원
4. 효율적인 Garbage Collection
5. 빠른 Compile

또한 애초부터 “System Programming” 을 위한 언어를 목적으로 하여
웹서버, 웹브라우저, 검색엔진, 컴파일러, 프로그래밍 도구, 서버프로그램 등을 개발하기에 적합한 언어로 타겟팅 한다


반응형

'Software Development > Go (golang)' 카테고리의 다른 글

3.1 Go - Hello World  (5) 2016.02.29
2. Go - 개발환경 구성  (3) 2016.02.28
1.3 Go 언어란? - 다른 언어와 비교  (999) 2016.02.28
1.2 Go 언어란? - 주요 특징  (845) 2016.02.28
1. Go 언어란?  (317) 2016.02.27
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
1. Go 언어란?

Go 언어에 대한 강좌를 시작해봅니다.

Go 언어는 사실 Ethereum 의 C++ 버전이 불안정한 이유와 해석이 용이하지 않다는 이유로 Geth 를 분석하고 수정하기 위한 용도로 이제 막 시작한다.

실제로 Eris 도 2014년에 C++ Ethereum 버전 기반으로 Eris 를 만들기 시작했으나 결국 Codebase 를 Geth 로 변경하고, 자신들의 Product 도 Go 언어로 개발한다.
 
저도 작년에 Poc7 버전 부터 보기 시작했으나 Go 언어를 기반으로 한 Geth 가 훨씬 깔끔하고 가독성이 있으며 심지어 Go 언어를 모르는 상태에서 C++ Ethereum 의 로직을 파악하기 힘든 경우 Go 를 부분적으로 참고하기도 했다.

Go 언어의 마스코트는 Go Gopher (땅다람쥐) 이다.


Renee French 라는 사람이 Go 언어의 로고를 디자인 하게 되었는데, 예전 뉴져지의 WFMU 라는 라디오 방송국의 마스코트 디자인에 이 gopher 를 사용했었고, 이후 마스코트를 변경했었는데, Renee 가 Go 프로젝트에 합류하고 디자인해낸게 그때 썼던 Gopher (:=)를 부활시키는 것이었다.

개인적으로는 좀 촌스러워 보이고 코믹해보이는 캐릭터이지만 친근감 있고 부드러운 인상을 주어 사람들에게 "이건 좀 만만하겠는데" 같은 느낌을 주는듯 하다.

Go 언어는 탄생한지 불과 8년 밖에 되지 않은 언어입니다. Docker 가 Go 언어로 구현되면서 특히 더 유명해졌죠. Eric 도 그렇지만, IBM 이 개발중인 Open Blockchain 또한 Go 언어로 구현중입니다. 간결함과 성능, Go 언어 개발 프로젝트에 관여한 유명한 개발자들로 더욱 기대를 높인 Go 언어에 대해 차츰 알아보도록 하겠습니다.

강좌는 상세하고 깊게 들어가기 보다는 Java, C/C++, JavaScript 등의 기존 프로그래밍 언어 두어개 이상은 할줄 안다는 가정하에 기본적인 부분들은 휙휙 넘어가보도록 하겠습니다.

반응형

'Software Development > Go (golang)' 카테고리의 다른 글

3.1 Go - Hello World  (5) 2016.02.29
2. Go - 개발환경 구성  (3) 2016.02.28
1.3 Go 언어란? - 다른 언어와 비교  (999) 2016.02.28
1.2 Go 언어란? - 주요 특징  (845) 2016.02.28
1.1 Go 언어란? - History  (169) 2016.02.27
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
C++ 이더리움으로 Private/Local Network 을 구성해보도록 하겠다.
Frontier 나 testnet 이 아닌, 두 개 혹은 그 이상의 peer 간에 상호 통신이 가능한 환경을 만들어 보도록 한다.

Windows 버전과 Mac OS X, Linux 버전을 사용하도록 하겠다. 
Windows 버전의 빌드는 지난번 블로그로 올렸고, Mac 과 Linux (Ubuntu) 버전은 Ethereum 의 가이드 대로 소스빌드를 하면 별 어려움 없이 빌드 가능하다.

▌Mac OS X 소스빌드 전 필요사항

  1. Mac OS X Yosemite 또는 El Capitan
  2. Home Brew
  3. git

▌Mac OS X 소스 빌드 방법

아래 커맨드 들을 순차적으로 입력하자
brew install boost --c++11
brew install cmake cryptopp miniupnpc leveldb gmp jsoncpp libmicrohttpd libjson-rpc-cpp
brew install homebrew/versions/v8-315
brew install llvm --HEAD --with-clang
brew install qt5 --with-d-bus

시간이 꽤나 걸리기때문에 인내심이 필요하다
다음으로는 소스코드를 Clone 하고 cmake 로 XCode 용 프로젝트를 생성한다
git clone --recursive https://github.com/ethereum/webthree-umbrella.git
cd webthree-umbrella

XCode 용 프로젝트를 생성한다
mkdir build_xc
cd build_xc
LLVM_DIR=/usr/local/Cellar/llvm/HEAD/lib/cmake cmake -G Xcode ..

XCode 를 띄우고 프로젝트를 Build 한다. Windows 와 다르게 매우 매끄럽게 빌드된다는 점에 놀라지 않을 수 없다

만약 빌드시에 LLVM 관련한 오류가 발생한다면, LLVM Library 의 버전을 체크하기 바란다. LLVM 라이브러리 버전은 3.7.0 이상이면 되고, 현재 Release 된 최신 LLVM Library 버전은 3.7.1 이다.
El Capitan OS X 이 내 Mac 은 이상하게 LLVM 3.9.0 이 설치되어있었다 (뭐하다가 이게 설치되어있었는지는 모른다). 그런데 3.9.0 은 Develop 버전이며, 빌드 시 오류가 생긴다. 3.7.1 버전으로 재설치 해주도록 한다.

▌Linux 소스 빌드 방법 (ubuntu 14.04 이후)

리눅스 빌드 방법도 거침 없이 진행된다. 사실 이 블로그를 쓰는 이유는 Windows 버전 때문이다. 아무리 생각해도 C++ Ethereum 은 Windows 버전은 빌드 되는지 정도만 테스트 하는것 같다. 개발은 Mac 과 Linux 로 하고있지않나 싶을정도이다. 

나는 Ubuntu 15.10 으로 apt-get 으로 upgrade 한 후 아래 가이드를 따라 소스빌드 했다.

나의 경우 오류 없이 잘 빌드되었다. 또한 console 모드로 실행해도 console 도 잘 실행된다.
(별 문제없는 과정들은 다음부터는 간단히 간단히~)

▌UPNP 코드 수정 (옵션)

eth 는 NAT 환경의 지원을 위해 upnp 기능을 제공하고있다. upnp 를 지원하는 공유기나 라우터 안에 node 가 있다면, upnp 기능으로 자동으로 포트 포워딩을 설정하도록 하는 것이다.
그러나 우리는 외부와 연결 없이 내부 node 끼리 테스트하고 싶으므로 upnp 기능까지는 필요 없다.

eth 간에 상호 peer 와 연결하기 위해 Node 간 통신 시에 자신의 IP 를 상대방에게 알려주도록 되어있는데, 이때 약간의 문제가 발생한다.
IPV4 는 Public IP 와 함께 주소 부족과 보안등의 이유로 주로 NAT 내에서 Private IP 를 사용하도록 되어있는데, 
Class A (10.*), Class B 172.(16 ~ 31).* Class C 192.168.* 는 모두 Private IP 로 분류된다.

그런데 만약 upnp 를 지원하지 않는 라우터 내에 있는 Node 간에 연결해야 하는 경우, --upnp off 옵션을 주도록 하는데, 이렇게 되면 Node 의 IP 가 public IP 를 사용하는것으로 간주한다.
하지만 public IP 가 아니므로 Exception 이 발생하고 eth 가 죽고만다.

그래서, 해당 코드를 수정해서 Private IP 를 public 으로 간주하도록 해주어야 한다.

<프로젝트 루트>\libweb3core\libp2p\common.cpp 을 열고 84 라인 부터 보면 (1.1.3 기준) 아래와 같은 코드가 있다.
bool p2p::isPrivateAddress(bi::address const& _addressToCheck)
{
    if (_addressToCheck.is_v4())
    {
        bi::address_v4 v4Address = _addressToCheck.to_v4();
        bi::address_v4::bytes_type bytesToCheck = v4Address.to_bytes();
        if (bytesToCheck[0] == 10 || bytesToCheck[0] == 127)
            return true;
        if (bytesToCheck[0] == 172 && (bytesToCheck[1] >= 16 && bytesToCheck[1] <= 31))
            return true;
        if (bytesToCheck[0] == 192 && bytesToCheck[1] == 168)
            return true;
    }
    else if (_addressToCheck.is_v6())

위 부분에서, 자신이 속하는 class 를 체크하는 로직을 // 로 comment 처리 하거나 삭제한다.
예를들어 Class A 체크하는 부분을 삭제하면 아래와 같다.
bool p2p::isPrivateAddress(bi::address const& _addressToCheck)
{
    if (_addressToCheck.is_v4())
    {
        bi::address_v4 v4Address = _addressToCheck.to_v4();
        bi::address_v4::bytes_type bytesToCheck = v4Address.to_bytes();

        if (bytesToCheck[0] == 127)
            return true;
        if (bytesToCheck[0] == 172 && (bytesToCheck[1] >= 16 && bytesToCheck[1] <= 31))
            return true;
        if (bytesToCheck[0] == 192 && bytesToCheck[1] == 168)
            return true;
    }

위 과정은 upnp 를 지원하지 않는 라우터나 네트워크 내에 있을 때 활용할 수 있는 방법이며, 그 외의 경우는 그냥 그대로 사용하도록 한다.

이제 Account 를 만들고 나만의 genesis 를 만들어서 ether 도 충분히 넣은 후 Java Script Console, JSON-RPC 를 사용하여 Smart Contract 를 만들고 실행해보면 된다.

▌Account 만들기

Account 를 만드는 방법은 2가지가 있다. 

  1. 자동생성 방법
  2. 직접 만들기

※ 자동생성 방법
자동 생성 방법은 일단 eth 를 실행시키면 된다. eth 를 그냥 실행만 시켜도 최초 실행시에 master password 를 물어보고, master password 를 입력하면 그 즉시 Account 를 하나 생성해주고 address 를 콘솔에 출력해준다.

만약 그냥 지나갔다면, JS console 에서 web3.eth.accounts 를 쳐보면 생성된 Account 의 주소를 볼 수 있다.

※ 수동생성 방법
C++ Ethereum 팀은 Account 와 Key 를 관리하기 위한 도구를 별도로 개발했다. ethkey 가 그것이며, 프로젝트 전체를 빌드했다면 (ALL_BUILD), 
<빌드디렉토리>/libethereum/ethkey/Debug
안에 ethkey 실행파일이 있을것이다.

C++ Ethereum 과 Go-Ethereum (Geth) 는 이 키를 관리하는 디렉토리의 위치가 약간 다르다.
eth 는 Windows 의 경우 %APPDATA%\web3\keys 안에 키를 저장하도록 되어있다
geth 는 Windows 의 경우 Ethereum 의 <datadir>\keyfiles 안에 저장한다

ethkey 는 Cygwin 이나 MinGW 의 Bash 에서 실행하면 Master Password 를 물어보는 과정에서 Exception 이 발생하고 죽는다. Windows 의 Command Prompt 를 통해 실행하도록 한다.

ethkey 로 새로운 key 를 생성해본다
ethkey new <Account 이름> 을 입력하면 아래와 같은 과정이 실행된다.
> ethkey new myname
Please enter your MASTER passphrase: 
Enter a passphrase with which to secure this account (or nothing to use the master passphrase):
Please confirm the passphrase by entering it again: 
Created key 6ecc980b-2f99-013d-167e-0ea9caffde4e
  Name: myname
  Password hint:
  ICAP: XE561WBEXUY46M6G05SDKF5P9C334V3JT6
  Raw hex: 007386abec97fc9f994abafa85b1b42dd97f860a
myname 이라는 이름으로 대표할 수 있는 007386abec97fc9f994abafa85b1b42dd97f860a 주소의 Account 가 생성되었다.
처음 물어보는것은 MASTER 패스워드이며, 모든 Account 와 관련한 동작을 할 때 이 Master Password 를 입력해야 한다. eth 를 실행할때에도 마찬가지이다.
귀챦다면, --master 옵션으로 Command Line 에서 미리 주어 물어보지 않게 할 수도 있다.

ICAP (Inter-exchange Client Address Protocol)는 IBAN 의 국제 공용 계좌번호의 형식이다. 향후에 좀더 소개할 기회가 있을지 모르겠으나, Ethereum 은 향후 Ethereum과 직접적인 국제계좌 연계를 염두에 두고 이런 무리한(?) 사상을 추가도입하였다. 물론 현재 실제 ether 가 IBAN 계좌로 이체되지는 않지만 이러한 주소체계를 기본적인 20바이트 Address 외에도 추가로 표시해주고있다.

추가적으로, registrar 라는 기본 Smart Contract 를 통해 20바이트 주소 대신 Alias Name 을 통해 거래나 Smart Contract Call 도 가능하다. Frontier 이후 부터 해당 Contract 가 기본적으로 들어갔다.

말이 옆으로 샜는데, 다시 돌아와서..
위에 추가한 Account 가 잘 보이는지 확인해 본다.
>ethkey list

Please enter your MASTER passphrase: 1a7e55b0-3eb7-05ec-248e-8d901e268d76 0096bb98??XE602H4XB00HUY08LU416SCBGO3CS63H66  Default key
6ecc980b-2f99-013d-167e-0ea9caffde4e 007386ab??XE561WBEXUY46M6G05SDKF5P9C334V3JT6  myname
처음 보이는게 자동으로 만들어졌던 Account Address 이고, 두번째 것이 myname 이라는 이름으로 만든 Account Address 이다.

MASTER 패스워드라는 개념은 현재 C++ Ethereum 에서만 도입되었다. Geth 의 경우, Account 별 패스워드를 넣지만 C++ 은 Account 패스워드 외에도 MASTER 패스워드가 있다. 마치 Mac 이나 Windows 의 keystore 와 같은 개념이다. Keystore 자체에 접근하기 위한 패스워드와 서비스를 사용하기 위한 패스워드가 다르듯이 말이다.

C++ Ethereum 은 Account 별 패스워드를 지정하지 않을 수 있다. 기본으로 생성된 Account 가 그렇다. MASTER 패스워드만 사용하려면 Account 를 만들 때 그냥 Enter 만 쳐주면 된다.

-----

술먹고 들어와서 쓰려니 눈이 스르르 감긴다. 체력이 바닥나고있는 관계로 나머지는 또 다음으로..^^




반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
지난번에 빌드환경 구성이 일단 끝났고, 이번에는 실제로 Build 를 해보겠다.

Dependency 다운로드가 끝났다면 이제 본격적으로 Visual Studio 용 솔루션과 세부 프로젝트들을 CMake 를 통해 Generate 해야한다.
Command Line 에서도 빌드할 수 있지만 Visual Studio 의 Debug 를 통해 Logic 을 디버깅 해야하는 경우가 생기므로 Visual Studio 용 프로젝트를 생성해본다.

▌Visual Studio Project 생성

이제 본격적으로 Visual Studio 의 Project 를 생성한다. 
/d/ethereum/project/webthree-umbrella/build
위 디렉토리를 만들고 들어간 후
[goodjoon webthree-umbrella]$  cd build/
[goodjoon build]$  cmake -DEVMJIT=0 -G "Visual Studio 12 2013 Win64" ..
위와 같이 VS2013 용 Project 를 Generate 한다.

빌드 후 디렉토리는 아래와 같다


이제 생성 된 cpp-ethereum.sln 파일을 Visual Studio 로 열어본다.

▌EVMJIT

EVMJIT(Ethereum Virtual Machine Just In Time Compiler) 는 libethereum 의 서브모듈 이다.
위에서 cmake 시에 -DEVMJIT=0 을 해주었는데, 이렇게 해서 EVMJIT 모듈은 설치하지 않는다.

evmjit 모듈은 LLVM 라이브러리 3.7.0 이상의 Dependency 가 걸려있고, 현재 기준으로 3.7.1 이 최신버전이다.
지난번 extdep 에서 download 받은 라이브러리들 중에는 LLVM 도 포함되어있으며, Release 와 Debug 모드 모두 다운로드 받는다.

그런데 다운로드받은 이 LLVM 라이브러리 의 Debug 버전은 Visual Studio 로 Link 걸고 빌드할 때 _ITERATOR_DEBUG_LEVEL 이 0으로 정의되어있다는 오류가 발생하고, 현재 빌드하려는 프로젝트 (evmjit) 는 이 값이 2 이기 때문에 충돌이 난다고 하며 에러를 수백개 뱉어낸다.

extdeps 로 다운받은 라이브러리만 그런지는 모르겠지만, 일단 Build 환경이 다른것으로 보인다. 이러한 오류 없이 빌드하려면 LLVM 라이브러리를 소스로 가져와 Visual Studio 로 빌드하고 이 빌드된 라이브러리들을 evmjit 의 참조 프로젝트로 또는 linker 의 옵션으로 넣어주어야 할 것이다.

EVMJIT 는 Solidity 와 Serpent 의 Smart Contract Code 를 Console 이나 RPC 를 통해 Bytecode 로 런타임에 컴파일해주는 기능으로, mix 와 같은 툴이나 온라인 IDE 로도 충분히 그 기능을 대체할 수 있으므로 그냥 EVMJIT 모듈을 포함하지 않도록 하겠다.

1.0.0 Frontier Release C++ eth 의 EVMJIT 는 XCode 를 통해 Mac 에서 빌드하는데에는 문제가 없었으나 실제 동작해보면 이 또한 JIT 컴파일이 지원되지 않는 버그를 볼 수 있어서 궂이 빌드하지 않도록 하는 두번째 이유가 된다.

▌빌드 하기

솔루션 파일을 열어보면, 아래 처럼 BUILD_ALL 프로젝트가 StartUp Project 로 설정되어있다.

향후에 코드 분석에 필요하니 일단 Debug 모드를 Active 로 두고 ALL_BUILD 프로젝트를 Build 를 해본다.
(처음에는 File 들을 Parsing 하고 Indexing 하느라고 시간이 좀 걸린다. 빌드하는데에는 상관 없으므로 바로 빌드 해보자)

99개 에러와 353개 경고가 보인다.

▌에러 수정

위 에러의 이유는 모두 소스파일의 Characterset Encoding 때문에 생긴것이다. 

위 밑줄친것과 같은 UTF-8 특수캐릭터들이 PoC7 버전때 부터인가 지속 추가되어 화면에 이쁘게(?) 출력하기 위한 이상한 짓을 많해 해놓고있는데 이게 CP949 기반인 한글 Windows 와 No-BOM UTF-8 만을 자동인식하는 Visual Studio 2013 의 컴파일러가 환상적으로(?) 결합되어 빚어내는 문제이다.


에러가 발생한 소스파일을 에러를 더블클리해서 Open 한 다음

File > Advanced Save Options ... 에서 

  1. Unicode (UTF-8 with signature) - Codepage 65001 를 선택한다.
  2. OK 를 누른 후, ctrl+S 로 파일을 저장해준다

(반드시 with Signature 로 해야한다. Visual Studio 2013 은 (2015도 마찬가지) BOM 없는 UTF-8 을 자동인식하지 않으며, 이를 강제하는 옵션도 발견하지 못했다.
한글 Windows 의 경우 OS 의 기본 Characterset 인 CP949 를 기본 Characterset 으로 지정하여 파싱한다.)

BlockHeader.cpp
Block.cpp
BlockQueue.cpp
BlockChain.cpp
ClientBase.cpp
State.cpp
TransactionQueue.cpp

위 파일들을 Advanced Save Options.. 로 Encoding 을 수정해수고 저장한다.

그리고 다시 Build 를 한다.
(Warning 은 무시한다. 대부분이 Character Encoding 해석이 안된다는 경고이다.)

failed 프로젝트가 없다면 성공한 것이다.



▌동작 테스트

AlethZero 나 mix 는 좀더 수정할 것들이 있어서 향후에 해보도록 하고, 일단 가장 중요한 Ethereum 의 CLI 인 eth 가 작동하는지 확인해보자.

MinGW 로 Bash 를 열고, .bash_profile 에 
export ETH_HOME=/d/ethereum
export ETH_BUILD=/d/ethereum/project/webthree-umbrella/build
위와같이 ETH_HOME 과 ETH_BUILD 환경변수를 추가해주었다.
내가 내부적으로 사용하기 위해서 추가한것이고, 이후 블로그에서는 이 환경변수를 기반으로 설명할것이다.

$ETH_BUILD/webthree/eth
디렉토리가 eth 프로젝트 디렉토리이며, 그 밑의 Debug 디렉토리에 좀전에 빌드한 eth.exe 실행파일이 위치하고있다.

버전 확인을 해본다.
[goodjoon Debug]$  ./eth --version
eth version 1.1.3
eth network protocol version: 63
Client database version: 12041
Build: Windows/msvc/int/Debug
1.1.3 버전임을 알 수 있다. (C++ 팀 리더가 바뀌면서 요즘 바짝 긴장을 했는지, 나흘전에 또 1.1.4가 릴리즈 되었다)

보면, Network Protocol Version 이 63 인것을 볼 수 있다. Client 가 다르더라도 저 PV 는 같은 버전이어야 함을 상기해야한다.
Frontier 가 릴리즈된 1.0.0 버전은 PV61 이다. 지금은 PV61,62,63 클라이언트들이 Frontier 에도 섞여있다.

일단 Frontier 에 붙어서 동작하는걸 확인해보겠다. 이왕이면 Mining 도 ON 시켜서 동작시켜보자.
또한 CLI JS Console 로 들어가는 옵션도 함께 넣어보자.
[goodjoon Debug]$  ./eth --mining on console
(++)Ethereum
 !   21:21:18.012|main  void __cdecl dev::eth::Client::init(class dev::p2p::Host *,const class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &,enum dev::WithExisting,class boost::multiprecision::number<struct boost::multiprecision::backends::cpp_int_backend<256,256,0,0,void>,0>) 18794 ms

Please enter a MASTER password to protect your key store (make it strong!): Error initializing key manager: D:\ethereum\project\webthree-umbrella\libweb3core\libdevcore\CommonIO.cpp(145): Throw in function class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl dev::getPassword(const class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &)
Dynamic exception type: class boost::exception_detail::clone_impl<struct dev::ExternalFunctionFailure>
std::exception::what: Unknown exception

 !   21:21:19.011|main  Stop worker 962 ms
[goodjoon Debug]$
실행 하자마자 에러이다. 

일단 옵션을 설명하면,
--mining on : 마이닝 기능을 켠다는 이야기이다
console : Javascript Console 모드로 들어가라는 이야기이다

그런데 바로 뒤에 에러가 난다. Key Manager 를 초기화 하다가 에러가 나는데, 원래는 "Please enter a MASTER password to protect your key store ..." 하고나서 패스워드를 물어보게 되어있다.
그리고 이 Master Password 를 입력하고나면 그 다음단계로 진행하는데, MinGW 환경이나 CygWin 환경에서는 에러가 난다. 똑같은 커맨드를 쳐도 Windows Command Prompt 상에서는 이후에 잘 진행되는것을 확인할 수 있다. 문제는 KeyManager 모듈이 load() 될 때 발생되는데, 이건 나중에 수정되어야 할 부분이다.

이 Master Password 는 예전 PoC 8 버전에서도 도입되지 않다가 Frontier 릴리즈와 함께 도입되었는데, Wallet 의 Private Key 관리의 보안상 허점이 많이 있기 때문에 이 부분의 보안강화를 위해 생겨났다. ethkey.exe 를 통해 향후 좀더 상세한 관리를 할 수 있고, 예전처럼 무식하게 config.rlp 에 Private Key 와 Public Key 를 넣어두지 않는다는점에 주의해야 한다.

Master Password 는 까먹으면 끝장이다. Wallet 의 모든 Key 들을 관리하기 위한 Key Store 의 Master Password 이며, Private Key 를 사용하기 전에 이 Master Key 패스워드를 입력해야 한다.

현재 MinGW 에서 CLI 로 interaction 하는때에 오류가 생기므로, 옵션을 추가하여 아예 Master Password 를 지정해주면서 시작하자.
[goodjoon Debug]$  ./eth --mining on console --master 1111
(++)Ethereum
Ethereum (++) 1.1.3
  Code by Gav Wood et al, (c) 2013, 2014, 2015.
Transaction Signer: XE602H4XB00HUY08LU416SCBGO3CS63H66 (1a7e55b0-3eb7-05ec-248e-8d901e268d76 - 0096bb98)
Mining Beneficiary: XE602H4XB00HUY08LU416SCBGO3CS63H66 (1a7e55b0-3eb7-05ec-248e-8d901e268d76 - 0096bb98)
Foundation: XE55PXQKKK4B9BYPBGT1XCYW6R5ELFAT6EM (00000000-0000-0000-0000-000000000000 - de0b2956)
  i  21:41:11.885|p2p  UPnP device: http://192.168.0.1:4112/etc/linuxigd/gatedesc.xml [st: urn:schemas-upnp-org:device:InternetGatewayDevice:1 ]
 !   21:41:11.963|main  void __cdecl dev::p2p::Host::start(void) 2216 ms
Node ID: enode://2ee2a7e6a73b3af8aa737ce8bf016322828bdfdc5249d1ce4454f9e570a5b1486d988fd1119dacb18f50759de52c0728e4b4d229c01d5fdaa52fdd498ee81b57@211.222.99.182:30303
JSONRPC Admin Session Key: gsIJYPwuntU=
  i  21:41:12.450|<unknown>  Loading full DAG of seedhash: #00000000…

위와같이 --master 옵션을 주고 1111 로 패스워드를 지정해주니 잘 진행이 된다.

그리고 Mining 을 위해 DAG file 을 생성하게 된다. Dagger Hashimoto 파일이라고 불리는데, 1GB 정도 크기의 2차원 배열 데이터를 갖는 파일이다. Mining 시에 적은 ASIC 을 사용한 마이닝을 방지하고 GPU 연산을 더 효율적으로 하고, Light Client 의 Verification 성능향상 등을 위해 Hashing 시 필요한 대규모의 Cache 를 만들어놓는것이다. 자세한 이야기는 다음에 더 하도록 하고, 일단 1GB 의 용량이 최소한 필요하다는것을 상기하자.

DAG 테이블을 모두 만들어내는데에는 수십분 정도 소요되니 바람이나 좀 쐬고 와도 된다.

막간을 이용해 eth 가 사용하는 디렉토리들을 잠깐 설명해보면,

%APPDATA%/Local/ethash - DAG 파일이 위치한다
%APPDATA%/Roaming/Ethereum/config.rlp - Address 가 저장된 파일이다. eth 가 사용하며, 예전에는 Private Key, Public Key 가 들어있었으나 지금은 Key 메커니즘이 복잡해졌고, 이는 향후에 설명한다.
%APPDATA%/Roaming/Ethereum/keys.info, keys.info.salt - 실제적인 Key 가 들어있는 파일이다. AlethZero 와 eth 가 공용으로 사용한다.
%APPDATA%/Roaming/Ethereum/.web3 - Webthree 가 사용하는 Key 에 대한 정보가 들어있다.
%APPDATA%/Roaming/Ethereum/<4바이트HEX값> - state Trie, extra 데이터, block 데이터 등이 저장되는 Level DB 가 있다

이제 1GB 가량의 DAG 파일이 생성이 완료되면, Full DAG loaded 라고 뜬다.


그런데 또 문제가 있다.

console 이 안뜬다 (원래는 이쁘게 '>') 모양과 함께 web3 라고 치면 web3.js 의 JavaScript 개체들이 주욱 나와야 하나 아예 Console 자체가 동작하지 않는다.

이 또한 Windows 에서의 eth 버그이다. 사실 이후에도 eth 의 Windows 에 대한 외면은 매우 많고 다양하다. 
가장 잘 돌아가는 환경은 Mac 과 Ubuntu 이다. Windows 버전은 그냥 울며 겨자먹기로 써야하는 상황이다.
그도 그럴것이, eth 는 Front-End-User 용이 아니다. Back-End 용으로 분류하고있으며, 그래서 Linux 환경에 대해서는 매우 신경을 많이쓰는 느낌이다.


▌Console Attach 하기

Console 이 안된다고해서 실망할 필요는 없다. eth 는 attach 기능을 통해, 기존에 동작하는 eth 인스턴스에 console 을 attach 할 수 있다. 물론 2개의 Terminal 창이 필요하긴 하지만, console 을 쓸 수 있다는게 어디인가? 

일단, 현재 실행중인 Process 는 죽인다. Console 이 동작 안하니 ctrl+C 를 눌러 break 시켜버리자. ctrl+C 로 안되면 작업관리자를 열어서 강제 종료 시켜버려도 된다.

그리고, MinGW Bash Shell 을 2개 띄우고, 하나의 Shell 에서는
[goodjoon Debug]$ ./eth --json-rpc --json-admin 0000 --mode full --mining on --master 1111 --verbosity 5 console
로 실행한다. 여기서 추가된 옵션만 설명하면,

--json-rpc : JSON-RPC 인터페이스를 사용하겠다는 이야기이다. 외부 eth 를 attach 모드로 실행한 후 JavaScript Console 로 명령을 날리면, Console 이 이 JavaScript API 를 JSON-RPC 를 통해 대상 프로세스에게 요청하도록 되어있다.
--json-admin : 옵션에서 --help 를 치면 --admin 이라고 되어있는데, 이건 오타이다. 이런 옵션은 없으며, --json-admin 을 사용해야한다. (이게 언제쩍 버그인데 여태 수정을 안하고있다) JSON-RPC 를 사용하려면 Session Key 를 주어야 하는데, 원래는 eth 가 실행될 때 로그 초반에 Session Key 라는게 출력될 때 랜덤하게 생성된 그 키를 복사에서 attach 할 프로세스에 session key 로 지정해주어야 한다. 불편함을 줄이기 위해 아예 이 값을 --json-admin 옵션으로 주도록 했다.
--mode full : 기본값이긴 한데, Full Node 로 작동하게 할것인지, Peer Node (피어들의 정보만을 제공하는 노드)로 동작시킬것인지를 지정한 것이다
--verbosity 5 : Log 출력의 Verbosity 를 지정해준다. 0~99 까지 줄 수 있는데 5만 주어도 로그가 넘쳐난다.
기본값이 Frontier Network 으로 Bootstrap 하게 되어있으므로 --frontier 옵션을 쓰지는 않았다.

시간이 조금 지나면 Peer 간에 Hello 메시지를 주고받으며 PING/PONG 을 하다가 Block 을 Import 하여 Sync 하기 시작하고, Validation 작업을 수행한다.

이제 두번째 터미널을 열고, Console 을 Attach 해보자
[goodjoon Debug]$  ./eth --session-key 0000 attach
> 

--session-key 는 JSON-RPC 의 --json-admin 옵션으로 준 Key 값을 준것이고, attach 를 통해 기본적인 localhost:8545 포트의 JSON-RPC 로 연결하게 된다.

이제 잘 attach 가 되었는지 확인해보자
> web3.version
{
  api: '0.15.1',
  node: '++eth-v1.1.3-0//Debug-Windows/msvc/int',
  getNode: [Function],
  network: '',
  getNetwork: [Function],
  ethereum: '0x3f',
  getEthereum: [Function],
  whisper: Error: METHOD_NOT_FOUND: The method being requested is not available on this server,
  getWhisper: [Function]
}
>
node: 는 Client 의 Node 식별을 위한 Full Name 이며, 별도의 옵션을 주지 않았으므로 ++eth-v1.1.3-0//Debug-Windows/msvc/int 와 같이 나온다
ethereum: 은 eth 프로토콜 버전이며 10진수로 변환하면 63 이 된다

> web3.eth.coinbase
'0x0096bb9802b14f72ba4cdbd105127fe57a1dafae'> web3.eth.blockNumber
24840
> web3.eth.getBlock('latest')
{
  transactions: [],
 receiptsRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
  hash'0xc88b3957581f72a2aa1f5e5bcad12898d1117ba492adc88398bdd4b2a6275b7c',
  seedHash: '0x0000000000000000000000000000000000000000000000000000000000000000',
  miner: '0x3f98e477a361f777da14611a7e419a75fd238b6b',
  uncles: [],
  extraData: '0x476574682f76312e302e302f6c696e75782f676f312e342e32',
  gasLimit: 5000, 
 transactionsRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',

  gasUsed: 0,
  size: 0,

  logsBloom: '0x000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000',
  totalDifficulty: 16505476021090676',
  number: 25657,
  parentHash: '
0xcb29677c43d3877bc401b578a64e2de7c7839a5080163b2bf3194b5fa5bdcc29',
  boundary: '
0x0000000000fa64ef32fc5b94d0c88ff91d9f142f5459c015652cd4e44bb3bc27',
  author: '
0x3f98e477a361f777da14611a7e419a75fd238b6b',
  stateRoot: '
0x429dd84e5a8e30f31a4442b7a0bc7aae79f459751ffcc57d2a2d6f699a38e532',
  difficulty: 1124127046574'
,
  nonce: '0xa8f99a70ac8ec05e',
  timestamp: 1438579639,
  mixHash: '0xf42a0dd21ec4fce0c20b21af14b661f6d43babc3c5bc215f1652a77f3fdc877b',
  sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347'
}
>

자신의 coinbase 와 가장 마지막 block 의 정보를 출력해봤다. 모두 의미있는 값이 나온다면 정상동작중인 것이다.

다음 부터는 Ethereum 의 사상에 대해서 조금씩 이야기를 정리해보기로 하겠다.
음.. 그전에 Blockchain 에 대한 기술적인 정리도 조금 할까..? 생각 중이다. 1.0  의 기술적인 개념부터 이해를 해야 Ethereum 의 개념도 이해가 갈테니 말이다.

그럼 오늘은 또 이만~


반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,