-
-
Notifications
You must be signed in to change notification settings - Fork 42
feat: GO언어 바인딩 추가 #167
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: GO언어 바인딩 추가 #167
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -723,3 +723,65 @@ jobs: | |
| with: | ||
| name: nuget-packages | ||
| path: packages/dotnet/**/nupkg/*.nupkg | ||
|
|
||
| # go | ||
| go-test: | ||
| name: Go Test - ${{ matrix.platform }} | ||
| runs-on: ${{ matrix.runner }} | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| # Windows x64 | ||
| - runner: windows-latest | ||
| target: x86_64-pc-windows-gnu | ||
| platform: windows-amd64 | ||
| # Linux x64 | ||
| - runner: ubuntu-latest | ||
| target: x86_64-unknown-linux-gnu | ||
| platform: linux-amd64 | ||
| # Linux ARM64 | ||
| - runner: ubuntu-latest | ||
| target: aarch64-unknown-linux-gnu | ||
| platform: linux-arm64 | ||
| # macOS ARM64 | ||
| - runner: macos-14 | ||
| target: aarch64-apple-darwin | ||
| platform: darwin-arm64 | ||
| # macOS x64 | ||
| - runner: macos-13 | ||
| target: x86_64-apple-darwin | ||
| platform: darwin-amd64 | ||
| steps: | ||
| - uses: actions/checkout@v5 | ||
|
|
||
| - name: Setup Rust | ||
| uses: actions-rust-lang/setup-rust-toolchain@v1 | ||
| with: | ||
| toolchain: stable | ||
| target: ${{ matrix.target }} | ||
|
|
||
| - name: Install cross-compilation tools (Linux ARM64) | ||
| if: matrix.platform == 'linux-arm64' | ||
| run: | | ||
| sudo apt-get update | ||
| sudo apt-get install -y gcc-aarch64-linux-gnu | ||
|
|
||
| - uses: actions/setup-go@v5 | ||
| with: | ||
| go-version: '1.21' | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. latest 옵션이 없는지 확인이 필요합니다
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 좋은 의견 감사합니다. 확인해보니 actions/setup-go에서 stable alias를 지원하여 최신 안정 버전을 자동으로 사용하도록 변경하겠습니다. |
||
|
|
||
| - name: Build native library | ||
| run: cargo build --release --target ${{ matrix.target }} -p braillify-go | ||
| env: | ||
| CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc | ||
|
|
||
| - name: Copy native library | ||
| run: | | ||
| mkdir -p packages/go/libs/${{ matrix.platform }} | ||
| cp target/${{ matrix.target }}/release/libbraillify_go.a packages/go/libs/${{ matrix.platform }}/ | ||
| shell: bash | ||
|
|
||
| - name: Test | ||
| run: go test -v ./... | ||
| working-directory: packages/go | ||
|
Comment on lines
+785
to
+787
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. test 이후 배포까지 필요합니다
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 현재 Go 바인딩이 CGo(Rust 코드 재사용 위해)를 통해 Rust 정적 라이브러리(.a)를 링크하는 구조입니다. 이 경우 일반적인 Go 패키지처럼 go get만으로 사용하기가 어려워 GitHub Release Asset에 플랫폼별 .a 파일을 업로드하고 사용자가 다운로드하여 사용하는 방식이 있습니다.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 우선 로직을 분할 하는 것은 완전한 안티패턴입니다, 재구현은 안됩니다 저도 go를 조금 공부해보니 release에 태그로 업로드하는 것만으로도 패키지 매니저에 잡히는 것 같네요 모든 OS에 따른 정적라이브러리를 포함시킬지 아니면 별도 분리할지는 trend에 따라 다를 것 같긴한데, 이 부분에 대한 의견이 궁금합니다
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 말씀해주신 대로 Rust 코어 로직을 Go로 재구현하는 방향은 제외하겠습니다. 정적 라이브러리 포함 여부를 생각해봤을 때, Go는 별도의 패키지 저장소 없이 GitHub 저장소의 소스코드를 직접 가져옵니다. Release 태그에 .a 파일을 별도로 업로드할 경우, go get 명령어가 해당 바이너리를 자동으로 다운로드해주지 않아 두 방향이 있는 것 같습니다.
개인적으로는 현재 .a 파일 크기와 저장소 히스토리 관리 측면을 고려했을 때 2번 방식이 더 적합해보이는데, 이 방향으로 진행해도 괜찮을지 의견부탁드립니다!
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2번 방식에서 추가적인 별도의 다운로드스크립트를 진행하는 것이 어느정도의 불편함을 가져 오는지 확인할 필요가 있습니다 이 부분에 대하여 측정된 정보나 스크립트에 대한 정보가 있을까요?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 현재 cgo가 ${SRCDIR}/libs/... 경로를 기준으로 정적 라이브러리를 찾고 있는데, go get으로 받은 패키지는 Go module cache에 들어가며 이 경로가 읽기 전용이 됩니다. 그래서 Release에서 .a를 받아도 해당 위치에 배치하기 어렵고, 별도 writable 경로를 사용하려면 사용자가 환경변수를 추가로 설정해야 합니다. 그래서 2번 방식은 사용성 측면과 복잡성에서 좋지 않은 것 같습니다. 사용자 경험 측면에서 1번 방식이 더 적합해 보입니다.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 그러면 1번으로 진행을 하고, go 언어의 경우 CICD 단계에서 추가적인 커밋이 더 붙어서 빌드 후에 정적 라이브러리들이 커밋이 되도록 개선함이 어떨까 싶습니다
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 넵 해당 방향으로 진행해보겠습니다! |
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| *.test | ||
| *.exe | ||
| *.out | ||
| libs/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| [package] | ||
| name = "braillify-go" | ||
| version = "2.0.0" | ||
| edition = "2024" | ||
|
|
||
| [lib] | ||
| name = "braillify_go" | ||
| crate-type = ["cdylib", "staticlib"] | ||
|
|
||
| [dependencies] | ||
| braillify = { path = "../../libs/braillify", default-features = false } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package braillify | ||
|
|
||
| // Encode converts Korean text to braille byte representation. | ||
| func Encode(text string) ([]byte, error) { | ||
| return cEncode(text) | ||
| } | ||
|
|
||
| // EncodeToUnicode converts Korean text to braille Unicode string. | ||
| func EncodeToUnicode(text string) (string, error) { | ||
| return cEncodeToUnicode(text) | ||
| } | ||
|
|
||
| // EncodeToBrailleFont converts Korean text to braille font string. | ||
| func EncodeToBrailleFont(text string) (string, error) { | ||
| return cEncodeToBrailleFont(text) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| package braillify | ||
|
|
||
| import "testing" | ||
|
|
||
| func TestEncodeToUnicode(t *testing.T) { | ||
| tests := []struct { | ||
| input string | ||
| expected string | ||
| }{ | ||
| {"안녕하세요", "⠣⠒⠉⠻⠚⠠⠝⠬"}, | ||
| {"상상이상의", "⠇⠶⠇⠶⠕⠇⠶⠺"}, | ||
| {"1,000", "⠼⠁⠂⠚⠚⠚"}, | ||
| {"ATM", "⠠⠠⠁⠞⠍"}, | ||
| {"", ""}, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| result, err := EncodeToUnicode(tt.input) | ||
| if err != nil { | ||
| t.Errorf("EncodeToUnicode(%q): unexpected error: %v", tt.input, err) | ||
| continue | ||
| } | ||
| t.Logf("EncodeToUnicode(%q) = %q", tt.input, result) | ||
| if result != tt.expected { | ||
| t.Errorf("EncodeToUnicode(%q) = %q, want %q", tt.input, result, tt.expected) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| func TestEncode(t *testing.T) { | ||
| result, err := Encode("안녕") | ||
| if err != nil { | ||
| t.Fatalf("unexpected error: %v", err) | ||
| } | ||
| t.Logf("Encode(%q) = %v", "안녕", result) | ||
| if len(result) == 0 { | ||
| t.Error("expected non-empty byte slice") | ||
| } | ||
| } | ||
|
|
||
| func TestEncodeToBrailleFont(t *testing.T) { | ||
| result, err := EncodeToBrailleFont("안녕하세요") | ||
| if err != nil { | ||
| t.Fatalf("unexpected error: %v", err) | ||
| } | ||
| expected := "⠣⠒⠉⠻⠚⠠⠝⠬" | ||
| t.Logf("EncodeToBrailleFont(%q) = %q", "안녕하세요", result) | ||
| if result != expected { | ||
| t.Errorf("EncodeToBrailleFont = %q, want %q", result, expected) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| package braillify | ||
|
|
||
| /* | ||
| #cgo darwin,amd64 LDFLAGS: -L${SRCDIR}/libs/darwin-amd64 -lbraillify_go -lm -lpthread | ||
| #cgo darwin,arm64 LDFLAGS: -L${SRCDIR}/libs/darwin-arm64 -lbraillify_go -lm -lpthread | ||
| #cgo linux,amd64 LDFLAGS: -L${SRCDIR}/libs/linux-amd64 -lbraillify_go -lm -lpthread -ldl | ||
| #cgo linux,arm64 LDFLAGS: -L${SRCDIR}/libs/linux-arm64 -lbraillify_go -lm -lpthread -ldl | ||
| #cgo windows,amd64 LDFLAGS: -L${SRCDIR}/libs/windows-amd64 -lbraillify_go -lntdll -lws2_32 -lbcrypt -ladvapi32 -luserenv | ||
|
|
||
| #include <stdlib.h> | ||
| #include <stdint.h> | ||
| #include <stddef.h> | ||
|
|
||
| extern uint8_t* braillify_encode(const char* text, size_t* out_len); | ||
| extern char* braillify_encode_to_unicode(const char* text); | ||
| extern char* braillify_encode_to_braille_font(const char* text); | ||
| extern char* braillify_get_last_error(); | ||
| extern void braillify_free_string(char* ptr); | ||
| extern void braillify_free_bytes(uint8_t* ptr, size_t len); | ||
| */ | ||
| import "C" | ||
|
|
||
| import ( | ||
| "errors" | ||
| "runtime" | ||
| "unsafe" | ||
| ) | ||
|
|
||
| func cEncode(text string) ([]byte, error) { | ||
| runtime.LockOSThread() | ||
| defer runtime.UnlockOSThread() | ||
|
|
||
| cText := C.CString(text) | ||
| defer C.free(unsafe.Pointer(cText)) | ||
|
|
||
| var outLen C.size_t | ||
| result := C.braillify_encode(cText, &outLen) | ||
| if result == nil { | ||
| return nil, getLastError() | ||
| } | ||
| defer C.braillify_free_bytes(result, outLen) | ||
|
|
||
| return C.GoBytes(unsafe.Pointer(result), C.int(outLen)), nil | ||
| } | ||
|
|
||
| func cEncodeToUnicode(text string) (string, error) { | ||
| runtime.LockOSThread() | ||
| defer runtime.UnlockOSThread() | ||
|
|
||
| cText := C.CString(text) | ||
| defer C.free(unsafe.Pointer(cText)) | ||
|
|
||
| result := C.braillify_encode_to_unicode(cText) | ||
| if result == nil { | ||
| return "", getLastError() | ||
| } | ||
| defer C.braillify_free_string(result) | ||
|
|
||
| return C.GoString(result), nil | ||
| } | ||
|
|
||
| func cEncodeToBrailleFont(text string) (string, error) { | ||
| runtime.LockOSThread() | ||
| defer runtime.UnlockOSThread() | ||
|
|
||
| cText := C.CString(text) | ||
| defer C.free(unsafe.Pointer(cText)) | ||
|
|
||
| result := C.braillify_encode_to_braille_font(cText) | ||
| if result == nil { | ||
| return "", getLastError() | ||
| } | ||
| defer C.braillify_free_string(result) | ||
|
|
||
| return C.GoString(result), nil | ||
| } | ||
|
|
||
| func getLastError() error { | ||
| errPtr := C.braillify_get_last_error() | ||
| if errPtr == nil { | ||
| return errors.New("braillify: unknown error") | ||
| } | ||
| defer C.braillify_free_string(errPtr) | ||
| return errors.New(C.GoString(errPtr)) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| module github.com/dev-five-git/braillify/packages/go | ||
|
|
||
| go 1.21 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changepacks가 action에서 어떻게 돌아가는지 확인해보실 필요가 있을 것 같습니다
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
본 cicd에서는 deploy까지 포함되어야 합니다