{"id":21419367,"url":"https://github.com/konstantin8105/c4go","last_synced_at":"2025-04-05T16:11:00.858Z","repository":{"id":41541800,"uuid":"127093867","full_name":"Konstantin8105/c4go","owner":"Konstantin8105","description":"Transpiling C code to Go code","archived":false,"fork":false,"pushed_at":"2024-05-30T11:00:20.000Z","size":6278,"stargazers_count":363,"open_issues_count":23,"forks_count":37,"subscribers_count":18,"default_branch":"master","last_synced_at":"2024-07-31T20:51:51.312Z","etag":null,"topics":["c","c4go","convert","cpp","go","golang","transpiler"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Konstantin8105.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-03-28T06:24:57.000Z","updated_at":"2024-06-07T17:13:50.000Z","dependencies_parsed_at":"2024-01-08T15:03:04.900Z","dependency_job_id":"670d24f0-2047-4423-b824-68d1297842ff","html_url":"https://github.com/Konstantin8105/c4go","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Konstantin8105%2Fc4go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Konstantin8105%2Fc4go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Konstantin8105%2Fc4go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Konstantin8105%2Fc4go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Konstantin8105","download_url":"https://codeload.github.com/Konstantin8105/c4go/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247361695,"owners_count":20926643,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","c4go","convert","cpp","go","golang","transpiler"],"created_at":"2024-11-22T19:40:40.767Z","updated_at":"2025-04-05T16:11:00.836Z","avatar_url":"https://github.com/Konstantin8105.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Go Report Card](https://goreportcard.com/badge/github.com/Konstantin8105/c4go)](https://goreportcard.com/report/github.com/Konstantin8105/c4go)\n[![codecov](https://codecov.io/gh/Konstantin8105/c4go/branch/master/graph/badge.svg)](https://codecov.io/gh/Konstantin8105/c4go)\n[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/Konstantin8105/c4go/master/LICENSE)\n[![Go](https://github.com/Konstantin8105/c4go/actions/workflows/codecov.yml/badge.svg?branch=master)](https://github.com/Konstantin8105/c4go/actions/workflows/codecov.yml)\n[![Go Reference](https://pkg.go.dev/badge/github.com/Konstantin8105/c4go.svg)](https://pkg.go.dev/github.com/Konstantin8105/c4go)\n\n\nA tool for [transpiling](https://en.wikipedia.org/wiki/Source-to-source_compiler) C code to Go code.\n\nMilestones of the project:\n\n1. Transpiling project [GNU GSL](https://www.gnu.org/software/gsl/).\n2. Transpiling project [GTK+](https://www.gtk.org/).\n\nNotes:\n* This transpiler works on all linux machines. Most likely, it will work on Unix and MacOS as well. Feedback is most welcome.\n* Installing the `clang` compiler is a prerequisite. See [llvm download page](http://releases.llvm.org/download.html)\n\n\n\n# Installation\n\nUsing a terminal window, position into a working directory (E.g. $HOME/development). Then, execute the following shell commands:\n\n```bash\n# Create a local c4go repository and position into it.\ngit clone https://github.com/Konstantin8105/c4go\ncd c4go\n\n# Update the Go source files.\ngo generate ./...\n\n# Install the c4go executable in the standard Go bin directory: $HOME/go/bin.\ngo install\n\n# Make sure that $HOME/go/bin is in the path (good practice).\n# Then, verify that the c4go is available for use.\nc4go version\n```\n\nSample ```c4go``` version console output:\n```\nBuild time: May  4 20:41:31 2024 UTC\nGit hash:   \"c5400a76df0f5157f234547bef3ae8fb7b692685\"\n```\n\n# Usage example\n\n```bash\n# Change your location to the folder with examples:\ncd $GOPATH/src/github.com/Konstantin8105/c4go/examples/\n\n# Transpile one file from the C example folder:\nc4go transpile prime.c\n\n# Look at the result\nnano prime.go\n\n# Check the result:\ngo run prime.go\n# Enter a number\n# 13\n# The number is: 13\n# Prime number.\n```\n\nC code of file `prime.c`:\n```c\n#include \u003cstdio.h\u003e\n\nint main()\n{\n    int n, c;\n\n    printf(\"Enter a number\\n\");\n    // get value\n    scanf(\"%d\", \u0026n);\n    printf(\"The number is: %d\\n\", n);\n\n    // -------\n    if (n == 2)\n        printf(\"Prime number.\\n\");\n    else {\n        for (c = 2; c \u003c= n - 1; c++) {\n            if (n % c == 0)\n                break;\n        }\n        if (c != n)\n            printf(\"Not prime.\\n\");\n        else\n            printf(\"Prime number.\\n\");\n    }\n    return 0;\n}\n```\n\nGo code of file `prime.go`:\n```golang\n//\n//\tPackage - transpiled by c4go\n//\n//\tIf you have found any issues, please raise an issue at:\n//\thttps://github.com/Konstantin8105/c4go/\n//\n\npackage main\n\nimport \"unsafe\"\nimport \"github.com/Konstantin8105/c4go/noarch\"\nimport \"fmt\"\n\n// main - transpiled function from  C4GO/examples/prime.c:3\nfunc main() {\n\tvar n int32\n\tvar c int32\n\tfmt.Printf(\"Enter a number\\n\")\n\t// get value\n\tnoarch.Scanf([]byte(\"%d\\x00\"), c4goUnsafeConvert_int32(\u0026n))\n\tnoarch.Printf([]byte(\"The number is: %d\\n\\x00\"), n)\n\tif n == 2 {\n\t\t// -------\n\t\tfmt.Printf(\"Prime number.\\n\")\n\t} else {\n\t\tfor c = 2; c \u003c= n-1; c++ {\n\t\t\tif n%c == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif c != n {\n\t\t\tfmt.Printf(\"Not prime.\\n\")\n\t\t} else {\n\t\t\tfmt.Printf(\"Prime number.\\n\")\n\t\t}\n\t}\n\treturn\n}\n\n// c4goUnsafeConvert_int32 : created by c4go\nfunc c4goUnsafeConvert_int32(c4go_name *int32) []int32 {\n\treturn (*[1000000]int32)(unsafe.Pointer(c4go_name))[:]\n}\n```\n\n# Example with binding function\n\nC:\n\n```c\n#include \u003cmath.h\u003e\n#include \u003cstdio.h\u003e\n\nint main()\n{\n    int n;\n    double param = 8.0, result;\n    result = frexp(param, \u0026n);\n    printf(\"result = %5.2f\\n\", result);\n    printf(\"n      = %d\\n\", n);\n    return 0;\n}\n```\n\n`c4go` add automatically C binding for function without implementation:\n```golang\n//\n//\tPackage - transpiled by c4go\n//\n//\tIf you have found any issues, please raise an issue at:\n//\thttps://github.com/Konstantin8105/c4go/\n//\n\npackage main\n\n// #include \u003c/usr/include/math.h\u003e\nimport \"C\"\n\nimport \"github.com/Konstantin8105/c4go/noarch\"\nimport \"unsafe\"\n\n// main - transpiled function from  C4GO/examples/math.c:4\nfunc main() {\n\tvar n int32\n\tvar param float64 = 8\n\tvar result float64\n\tresult = frexp(param, c4goUnsafeConvert_int32(\u0026n))\n\tnoarch.Printf([]byte(\"result = %5.2f\\n\\x00\"), result)\n\tnoarch.Printf([]byte(\"n      = %d\\n\\x00\"), n)\n\treturn\n}\n\n// c4goUnsafeConvert_int32 : created by c4go\nfunc c4goUnsafeConvert_int32(c4go_name *int32) []int32 {\n\treturn (*[1000000]int32)(unsafe.Pointer(c4go_name))[:]\n}\n\n// frexp - add c-binding for implemention function\nfunc frexp(arg0 float64, arg1 []int32) float64 {\n \treturn float64(C.frexp(C.double(arg0), (*C.int)(unsafe.Pointer(\u0026arg1[0]))))\n}\n```\n\n# Example with C-pointers and C-arrays\n\n```c\n#include \u003cstdio.h\u003e\n\n// input argument - C-pointer\nvoid a(int* v1) { printf(\"a: %d\\n\", *v1); }\n\n// input argument - C-array\nvoid b(int v1[], int size)\n{\n    for (size--; size \u003e= 0; size--) {\n        printf(\"b: %d %d\\n\", size, v1[size]);\n    }\n}\n\nint main()\n{\n    // value\n    int i1 = 42;\n    a(\u0026i1);\n    b(\u0026i1, 1);\n\n    // C-array\n    int i2[] = { 11, 22 };\n    a(i2);\n    b(i2, 2);\n\n    // C-pointer from value\n    int* i3 = \u0026i1;\n    a(i3);\n    b(i3, 1);\n\n    // C-pointer from array\n    int* i4 = i2;\n    a(i4);\n    b(i4, 2);\n\n    // C-pointer from array\n    int* i5 = i2[1];\n    a(i5);\n    b(i5, 1);\n\n    return 0;\n}\n```\n\n```go\n//\n//\tPackage - transpiled by c4go\n//\n//\tIf you have found any issues, please raise an issue at:\n//\thttps://github.com/Konstantin8105/c4go/\n//\n\npackage main\n\nimport \"unsafe\"\nimport \"github.com/Konstantin8105/c4go/noarch\"\n\n// a - transpiled function from  C4GO/examples/ap.c:4\nfunc a(v1 []int32) {\n\t// input argument - C-pointer\n\tnoarch.Printf([]byte(\"a: %d\\n\\x00\"), v1[0])\n}\n\n// b - transpiled function from  C4GO/examples/ap.c:7\nfunc b(v1 []int32, size int32) {\n\t{\n\t\t// input argument - C-array\n\t\tfor size -= 1; size \u003e= 0; size-- {\n\t\t\tnoarch.Printf([]byte(\"b: %d %d\\n\\x00\"), size, v1[size])\n\t\t}\n\t}\n}\n\n// main - transpiled function from  C4GO/examples/ap.c:14\nfunc main() {\n\tvar i1 int32 = 42\n\t// value\n\ta(c4goUnsafeConvert_int32(\u0026i1))\n\tb(c4goUnsafeConvert_int32(\u0026i1), 1)\n\tvar i2 []int32 = []int32{11, 22}\n\t// C-array\n\ta(i2)\n\tb(i2, 2)\n\tvar i3 []int32 = c4goUnsafeConvert_int32(\u0026i1)\n\t// C-pointer from value\n\ta(i3)\n\tb(i3, 1)\n\tvar i4 []int32 = i2\n\t// C-pointer from array\n\ta(i4)\n\tb(i4, 2)\n\tvar i5 []int32 = i2[1:]\n\t// C-pointer from array\n\ta(i5)\n\tb(i5, 1)\n\n\treturn\n}\n\n// c4goUnsafeConvert_int32 : created by c4go\nfunc c4goUnsafeConvert_int32(c4go_name *int32) []int32 {\n\treturn (*[1000000]int32)(unsafe.Pointer(c4go_name))[:]\n}\n```\n\n# Example of transpilation [neatvi](https://github.com/aligrudi/neatvi).\n\n```bash\n# clone git repository\ngit clone https://github.com/aligrudi/neatvi.git\n\n# move in folder\ncd neatvi\n\n# look in Makefile\ncat Makefile\n```\nMakefile:\n```\nCC = cc\nCFLAGS = -Wall -O2\nLDFLAGS =\n\nOBJS = vi.o ex.o lbuf.o mot.o sbuf.o ren.o dir.o syn.o reg.o led.o \\\n\tuc.o term.o rset.o regex.o cmd.o conf.o\n\nall: vi\n\nconf.o: conf.h\n\n%.o: %.c\n\t$(CC) -c $(CFLAGS) $\u003c\nvi: $(OBJS)\n\t$(CC) -o $@ $(OBJS) $(LDFLAGS)\nclean:\nrm -f *.o vi\n```\nAs we see not need any specific, for example `-clang-flag`.\n\nLet's try transpile:\n```bash\nc4go transpile *.c\n```\nResult:\n```\npanic: clang failed: exit status 1:\n\n/temp/neatvi/reg.c:6:14: error: redefinition of 'bufs' with a different type: 'char *[256]' vs 'struct buf [8]'\nstatic char *bufs[256];\n             ^\n/temp/neatvi/ex.c:35:3: note: previous definition is here\n} bufs[8];\n  ^\n/temp/neatvi/reg.c:12:9: error: returning 'struct buf' from a function with incompatible result type 'char *'\n return bufs[c];\n        ^~~~~~~\n/temp/neatvi/reg.c:17:81: error: invalid operands to binary expression ('int' and 'struct buf')\n char *pre = ((*__ctype_b_loc ())[(int) ((c))] \u0026 (unsigned short int) _ISupper) \u0026\u0026 bufs[tolower(c)] ? bufs[tolower(c)] : \"\";\n             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^  ~~~~~~~~~~~~~~~~\n/temp/neatvi/reg.c:21:7: error: passing 'struct buf' to parameter of incompatible type 'void *'\n free(bufs[tolower(c)]);\n      ^~~~~~~~~~~~~~~~\n/usr/include/stdlib.h:483:25: note: passing argument to parameter '__ptr' here\nextern void free (void *__ptr) __attribute__ ((__nothrow__ ));\n                        ^\n/temp/neatvi/reg.c:22:19: error: assigning to 'struct buf' from incompatible type 'char *'\n bufs[tolower(c)] = buf;\n                  ^ ~~~\n/temp/neatvi/reg.c:43:8: error: passing 'struct buf' to parameter of incompatible type 'void *'\n  free(bufs[i]);\n       ^~~~~~~\n/usr/include/stdlib.h:483:25: note: passing argument to parameter '__ptr' here\nextern void free (void *__ptr) __attribute__ ((__nothrow__ ));\n                        ^\n/temp/neatvi/regex.c:98:12: error: static declaration of 'uc_len' follows non-static declaration\nstatic int uc_len(char *s)\n           ^\n/temp/neatvi/vi.h:83:5: note: previous declaration is here\nint uc_len(char *s);\n    ^\n/temp/neatvi/regex.c:200:14: error: static declaration of 'uc_beg' follows non-static declaration\nstatic char *uc_beg(char *beg, char *s)\n             ^\n/temp/neatvi/vi.h:101:7: note: previous declaration is here\nchar *uc_beg(char *beg, char *s);\n      ^\n/temp/neatvi/vi.c:635:12: error: redefinition of 'linecount'\nstatic int linecount(char *s)\n           ^\n/temp/neatvi/lbuf.c:124:12: note: previous definition is here\nstatic int linecount(char *s)\n           ^\n9 errors generated.\n\n\ngoroutine 1 [running]:\nmain.generateAstLines(0x1, 0x0, 0xc000010140, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, ...)\n\t/go/src/github.com/Konstantin8105/c4go/main.go:438 +0xd40\nmain.Start(0x1, 0x0, 0xc000010140, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, ...)\n\t/go/src/github.com/Konstantin8105/c4go/main.go:356 +0xa9\nmain.runCommand(0x0)\n\t/go/src/github.com/Konstantin8105/c4go/main.go:723 +0xa45\nmain.main()\n\t/go/src/github.com/Konstantin8105/c4go/main.go:556 +0x22\n```\nThat error is good and enought information for next step of transpilation.\nLet's clarify one of them - we see 2 function with same function name and\nif you open files and compare.\n```\n/temp/neatvi/vi.c:635:12: error: redefinition of 'linecount'\nstatic int linecount(char *s)\n\n/temp/neatvi/lbuf.c:124:12: note: previous definition is here\nstatic int linecount(char *s)\n```\nThis is 2 absolute identical function, so we can remove one of them.\nI choose remove function `linecount` from file `vi.c`, because in\naccording to error - it is duplicate.\n\nAlso remove next function in according to errors:\n* `vi.c` function `linecount`\n* `regex.c` function `uc_len`\n* `regex.c` function `uc_bed`\n\nNext error is about duplicate of variable names:\n```\n/temp/neatvi/reg.c:6:14: error: redefinition of 'bufs' with a different type: 'char *[256]' vs 'struct buf [8]'\nstatic char *bufs[256];\n             ^\n/temp/neatvi/ex.c:35:3: note: previous definition is here\n} bufs[8];\n```\nLet's replace variable name in file `reg.c` and run:\n```\nsed -i.bak 's/bufs/bufs_postfix/g' reg.c\n```\n\nNow, let's try again and output in file `vi.go`:\n```bash\nc4go transpile -o vi.go *.c\n```\nNow transpiled without `clang` error. Look the result:\n```bash\nless vi.go\n```\nWe see warning of lose some types:\n```\n// Warning (*ast.BinaryOperator):  /temp/neatvi/cmd.c:20 :Cannot transpile BinaryOperator with type 'int' : result type = {}. Error: operator is `=`. Cannot casting {__pid_t -\u003e int}. err = Cannot resolve type '__pid_t' : I couldn't find an appropriate Go type for the C type '__pid_t'.\n```\n\nFor fix that add flag `-s` for adding all type from C standard library:\n```bash\nc4go transpile -o vi.go -s *.c\n```\n\nNow, all is Ok. Look the result:\n```bash\nless vi.go\n```\n\n\n# C standard library implementation\n\n```\n            assert.h\t       1/1\t         100%\n             ctype.h\t     13/13\t         100%\n             errno.h\t       0/1\t           0%\n             float.h\t          \t    undefined\n            iso646.h\t          \t    undefined\n            limits.h\t          \t    undefined\n            locale.h\t       0/3\t           0%\n              math.h\t     22/22\t         100%\n            setjmp.h\t       0/3\t           0%\n            signal.h\t       3/3\t         100%\n            stdarg.h\t       4/4\t         100%\n            stddef.h\t       4/4\t         100%\n             stdio.h\t     37/41\t        90.2%\n            stdlib.h\t     31/37\t        83.8%\n            string.h\t     21/24\t        87.5%\n              time.h\t      1/15\t        6.67%\n             wchar.h\t      3/60\t           5%\n            wctype.h\t      0/21\t           0%\n```\n\n# Contributing\n\nFeel free to submit PRs or open issues.\nMain information from: [en.cppreference.com](http://en.cppreference.com/w/c)\n\n## Testing\n\nBy default, only unit tests are run with `go test`. You can also include\nall tests:\n\n```bash\ngo test ./...\n```\n\nFor tests work like this:\n\n1. `clang` compiles the C to a binary as normal.\n2. `c4go` converts the C file to Go.\n3. Both binaries are executed and the output is compared. All C files will\ncontain some output so the results can be verified.\n\n## Note\n\n### Use lastest version of clang.\n\nIf you use `Ubuntu`, then use command like next for choose `clang` version:\n\n```bash\nsudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-6.0 1000\n```\n\n### Performance\n\nMain time of transpilation takes `clang`, for example run:\n```bash\ngo test -run=Benchmark -bench=. -benchmem\n```\nResult looks for example:\n```\ngoos: linux\ngoarch: amd64\npkg: github.com/Konstantin8105/c4go\nBenchmarkTranspile/Full-6         \t       5\t 274922964 ns/op\t43046865 B/op\t  379676 allocs/op\nBenchmarkTranspile/GoCode-6       \t      20\t  86806808 ns/op\t36577533 B/op\t  308060 allocs/op\nPASS\n```\nSo, transpilation time is just 30% of full time. In my point of view\nno need of performance optimization, see [Amdahl's law](https://en.wikipedia.org/wiki/Amdahl%27s_law).\n\n### Example of performance analyse\n\nPlease run:\n\n```bash\n# Run cpuprofiling for sqlite transpilation example\ntime ./scripts/sqlite.sh \n\n# Example of output:\n#\n# % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current\n#                                 Dload  Upload   Total   Spent    Left  Speed\n#100 2217k  100 2217k    0     0   235k      0  0:00:09  0:00:09 --:--:--  357k\n#Archive:  /tmp/SQLITE/sqlite-amalgamation-3250200.zip\n#   creating: /tmp/SQLITE/sqlite-amalgamation-3250200/\n#  inflating: /tmp/SQLITE/sqlite-amalgamation-3250200/sqlite3ext.h  \n#  inflating: /tmp/SQLITE/sqlite-amalgamation-3250200/sqlite3.c  \n#  inflating: /tmp/SQLITE/sqlite-amalgamation-3250200/sqlite3.h  \n#  inflating: /tmp/SQLITE/sqlite-amalgamation-3250200/shell.c  \n#After transpiling shell.c and sqlite3.c together, have summary: 695 warnings.\n#In file sqlite.go summary : 3 warnings in go build.\n#Amount unsafe package using: 2902\n#\n#real\t0m18.434s\n#user\t0m14.212s\n#sys\t0m1.434s\n\n# Run profiler\ngo tool pprof ./testdata/cpu.out\n```\n\nFor more information, see [Profiling Go Programs](https://blog.golang.org/profiling-go-programs).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkonstantin8105%2Fc4go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkonstantin8105%2Fc4go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkonstantin8105%2Fc4go/lists"}