
Una herramienta para transparir el código C para ir al código.
Hitos del proyecto:
Notas:
clang es un requisito previo. Ver LLVM Página de descargaUsando una ventana de terminal, coloque en un directorio de trabajo (por ejemplo, $ hogar/desarrollo). Luego, ejecute los siguientes comandos de shell:
# Create a local c4go repository and position into it.
git clone https://github.com/Konstantin8105/c4go
cd c4go
# Update the Go source files.
go generate ./...
# Install the c4go executable in the standard Go bin directory: $HOME/go/bin.
go install
# Make sure that $HOME/go/bin is in the path (good practice).
# Then, verify that the c4go is available for use.
c4go version Muestra de salida de consola de versión c4go :
Build time: May 4 20:41:31 2024 UTC
Git hash: "c5400a76df0f5157f234547bef3ae8fb7b692685"
# Change your location to the folder with examples:
cd $GOPATH /src/github.com/Konstantin8105/c4go/examples/
# Transpile one file from the C example folder:
c4go transpile prime.c
# Look at the result
nano prime.go
# Check the result:
go run prime.go
# Enter a number
# 13
# The number is: 13
# Prime number. C Código de archivo prime.c :
#include <stdio.h>
int main ()
{
int n , c ;
printf ( "Enter a numbern" );
// get value
scanf ( "%d" , & n );
printf ( "The number is: %dn" , n );
// -------
if ( n == 2 )
printf ( "Prime number.n" );
else {
for ( c = 2 ; c <= n - 1 ; c ++ ) {
if ( n % c == 0 )
break ;
}
if ( c != n )
printf ( "Not prime.n" );
else
printf ( "Prime number.n" );
}
return 0 ;
} Go Code of File prime.go :
//
// Package - transpiled by c4go
//
// If you have found any issues, please raise an issue at:
// https://github.com/Konstantin8105/c4go/
//
package main
import "unsafe"
import "github.com/Konstantin8105/c4go/noarch"
import "fmt"
// main - transpiled function from C4GO/examples/prime.c:3
func main () {
var n int32
var c int32
fmt . Printf ( "Enter a number n " )
// get value
noarch . Scanf ([] byte ( "%d x00 " ), c4goUnsafeConvert_int32 ( & n ))
noarch . Printf ([] byte ( "The number is: %d n x00 " ), n )
if n == 2 {
// -------
fmt . Printf ( "Prime number. n " )
} else {
for c = 2 ; c <= n - 1 ; c ++ {
if n % c == 0 {
break
}
}
if c != n {
fmt . Printf ( "Not prime. n " )
} else {
fmt . Printf ( "Prime number. n " )
}
}
return
}
// c4goUnsafeConvert_int32 : created by c4go
func c4goUnsafeConvert_int32 ( c4go_name * int32 ) [] int32 {
return ( * [ 1000000 ] int32 )( unsafe . Pointer ( c4go_name ))[:]
}DO:
#include <math.h>
#include <stdio.h>
int main ()
{
int n ;
double param = 8.0 , result ;
result = frexp ( param , & n );
printf ( "result = %5.2fn" , result );
printf ( "n = %dn" , n );
return 0 ;
} c4go agregue automáticamente el enlace C para la función sin implementación:
//
// Package - transpiled by c4go
//
// If you have found any issues, please raise an issue at:
// https://github.com/Konstantin8105/c4go/
//
package main
// #include </usr/include/math.h>
import "C"
import "github.com/Konstantin8105/c4go/noarch"
import "unsafe"
// main - transpiled function from C4GO/examples/math.c:4
func main () {
var n int32
var param float64 = 8
var result float64
result = frexp ( param , c4goUnsafeConvert_int32 ( & n ))
noarch . Printf ([] byte ( "result = %5.2f n x00 " ), result )
noarch . Printf ([] byte ( "n = %d n x00 " ), n )
return
}
// c4goUnsafeConvert_int32 : created by c4go
func c4goUnsafeConvert_int32 ( c4go_name * int32 ) [] int32 {
return ( * [ 1000000 ] int32 )( unsafe . Pointer ( c4go_name ))[:]
}
// frexp - add c-binding for implemention function
func frexp ( arg0 float64 , arg1 [] int32 ) float64 {
return float64 ( C . frexp ( C . double ( arg0 ), ( * C . int )( unsafe . Pointer ( & arg1 [ 0 ]))))
} #include <stdio.h>
// input argument - C-pointer
void a ( int * v1 ) { printf ( "a: %dn" , * v1 ); }
// input argument - C-array
void b ( int v1 [], int size )
{
for ( size -- ; size >= 0 ; size -- ) {
printf ( "b: %d %dn" , size , v1 [ size ]);
}
}
int main ()
{
// value
int i1 = 42 ;
a ( & i1 );
b ( & i1 , 1 );
// C-array
int i2 [] = { 11 , 22 };
a ( i2 );
b ( i2 , 2 );
// C-pointer from value
int * i3 = & i1 ;
a ( i3 );
b ( i3 , 1 );
// C-pointer from array
int * i4 = i2 ;
a ( i4 );
b ( i4 , 2 );
// C-pointer from array
int * i5 = i2 [ 1 ];
a ( i5 );
b ( i5 , 1 );
return 0 ;
} //
// Package - transpiled by c4go
//
// If you have found any issues, please raise an issue at:
// https://github.com/Konstantin8105/c4go/
//
package main
import "unsafe"
import "github.com/Konstantin8105/c4go/noarch"
// a - transpiled function from C4GO/examples/ap.c:4
func a ( v1 [] int32 ) {
// input argument - C-pointer
noarch . Printf ([] byte ( "a: %d n x00 " ), v1 [ 0 ])
}
// b - transpiled function from C4GO/examples/ap.c:7
func b ( v1 [] int32 , size int32 ) {
{
// input argument - C-array
for size -= 1 ; size >= 0 ; size -- {
noarch . Printf ([] byte ( "b: %d %d n x00 " ), size , v1 [ size ])
}
}
}
// main - transpiled function from C4GO/examples/ap.c:14
func main () {
var i1 int32 = 42
// value
a ( c4goUnsafeConvert_int32 ( & i1 ))
b ( c4goUnsafeConvert_int32 ( & i1 ), 1 )
var i2 [] int32 = [] int32 { 11 , 22 }
// C-array
a ( i2 )
b ( i2 , 2 )
var i3 [] int32 = c4goUnsafeConvert_int32 ( & i1 )
// C-pointer from value
a ( i3 )
b ( i3 , 1 )
var i4 [] int32 = i2
// C-pointer from array
a ( i4 )
b ( i4 , 2 )
var i5 [] int32 = i2 [ 1 :]
// C-pointer from array
a ( i5 )
b ( i5 , 1 )
return
}
// c4goUnsafeConvert_int32 : created by c4go
func c4goUnsafeConvert_int32 ( c4go_name * int32 ) [] int32 {
return ( * [ 1000000 ] int32 )( unsafe . Pointer ( c4go_name ))[:]
} # clone git repository
git clone https://github.com/aligrudi/neatvi.git
# move in folder
cd neatvi
# look in Makefile
cat MakefileMakefile:
CC = cc
CFLAGS = -Wall -O2
LDFLAGS =
OBJS = vi.o ex.o lbuf.o mot.o sbuf.o ren.o dir.o syn.o reg.o led.o
uc.o term.o rset.o regex.o cmd.o conf.o
all: vi
conf.o: conf.h
%.o: %.c
$(CC) -c $(CFLAGS) $<
vi: $(OBJS)
$(CC) -o $@ $(OBJS) $(LDFLAGS)
clean:
rm -f *.o vi
Como vemos que no necesitan ningún tipo específico, por ejemplo, -clang-flag .
Probemos el transpilo:
c4go transpile * .cResultado:
panic: clang failed: exit status 1:
/temp/neatvi/reg.c:6:14: error: redefinition of 'bufs' with a different type: 'char *[256]' vs 'struct buf [8]'
static char *bufs[256];
^
/temp/neatvi/ex.c:35:3: note: previous definition is here
} bufs[8];
^
/temp/neatvi/reg.c:12:9: error: returning 'struct buf' from a function with incompatible result type 'char *'
return bufs[c];
^~~~~~~
/temp/neatvi/reg.c:17:81: error: invalid operands to binary expression ('int' and 'struct buf')
char *pre = ((*__ctype_b_loc ())[(int) ((c))] & (unsigned short int) _ISupper) && bufs[tolower(c)] ? bufs[tolower(c)] : "";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~
/temp/neatvi/reg.c:21:7: error: passing 'struct buf' to parameter of incompatible type 'void *'
free(bufs[tolower(c)]);
^~~~~~~~~~~~~~~~
/usr/include/stdlib.h:483:25: note: passing argument to parameter '__ptr' here
extern void free (void *__ptr) __attribute__ ((__nothrow__ ));
^
/temp/neatvi/reg.c:22:19: error: assigning to 'struct buf' from incompatible type 'char *'
bufs[tolower(c)] = buf;
^ ~~~
/temp/neatvi/reg.c:43:8: error: passing 'struct buf' to parameter of incompatible type 'void *'
free(bufs[i]);
^~~~~~~
/usr/include/stdlib.h:483:25: note: passing argument to parameter '__ptr' here
extern void free (void *__ptr) __attribute__ ((__nothrow__ ));
^
/temp/neatvi/regex.c:98:12: error: static declaration of 'uc_len' follows non-static declaration
static int uc_len(char *s)
^
/temp/neatvi/vi.h:83:5: note: previous declaration is here
int uc_len(char *s);
^
/temp/neatvi/regex.c:200:14: error: static declaration of 'uc_beg' follows non-static declaration
static char *uc_beg(char *beg, char *s)
^
/temp/neatvi/vi.h:101:7: note: previous declaration is here
char *uc_beg(char *beg, char *s);
^
/temp/neatvi/vi.c:635:12: error: redefinition of 'linecount'
static int linecount(char *s)
^
/temp/neatvi/lbuf.c:124:12: note: previous definition is here
static int linecount(char *s)
^
9 errors generated.
goroutine 1 [running]:
main.generateAstLines(0x1, 0x0, 0xc000010140, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/go/src/github.com/Konstantin8105/c4go/main.go:438 +0xd40
main.Start(0x1, 0x0, 0xc000010140, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/go/src/github.com/Konstantin8105/c4go/main.go:356 +0xa9
main.runCommand(0x0)
/go/src/github.com/Konstantin8105/c4go/main.go:723 +0xa45
main.main()
/go/src/github.com/Konstantin8105/c4go/main.go:556 +0x22
Ese error es bueno y suficiente información para el siguiente paso de transpilación. Aclaremos uno de ellos: vemos 2 funciones con el mismo nombre de función y si abre archivos y compara.
/temp/neatvi/vi.c:635:12: error: redefinition of 'linecount'
static int linecount(char *s)
/temp/neatvi/lbuf.c:124:12: note: previous definition is here
static int linecount(char *s)
Esta es 2 función idéntica absoluta, por lo que podemos eliminar una de ellas. Elijo eliminar la función linecount del archivo vi.c , porque según el error, es duplicado.
También elimine la siguiente función en los errores:
vi.c Función linecountregex.c función uc_lenregex.c función uc_bedEl siguiente error es sobre duplicado de nombres de variables:
/temp/neatvi/reg.c:6:14: error: redefinition of 'bufs' with a different type: 'char *[256]' vs 'struct buf [8]'
static char *bufs[256];
^
/temp/neatvi/ex.c:35:3: note: previous definition is here
} bufs[8];
Reemplacemos el nombre de la variable en el archivo reg.c y ejecutar:
sed -i.bak 's/bufs/bufs_postfix/g' reg.c
Ahora, intentemos nuevamente y salgamos en el archivo vi.go :
c4go transpile -o vi.go * .c Ahora se transpiló sin error clang . Mira el resultado:
less vi.goVemos advertencia de perder algunos tipos:
// Warning (*ast.BinaryOperator): /temp/neatvi/cmd.c:20 :Cannot transpile BinaryOperator with type 'int' : result type = {}. Error: operator is `=`. Cannot casting {__pid_t -> int}. err = Cannot resolve type '__pid_t' : I couldn't find an appropriate Go type for the C type '__pid_t'.
Para Fix That Agregar Flag -s para agregar todo tipo de la biblioteca estándar C:
c4go transpile -o vi.go -s * .cAhora todo está bien. Mira el resultado:
less vi.go assert.h 1/1 100%
ctype.h 13/13 100%
errno.h 0/1 0%
float.h undefined
iso646.h undefined
limits.h undefined
locale.h 0/3 0%
math.h 22/22 100%
setjmp.h 0/3 0%
signal.h 3/3 100%
stdarg.h 4/4 100%
stddef.h 4/4 100%
stdio.h 37/41 90.2%
stdlib.h 31/37 83.8%
string.h 21/24 87.5%
time.h 1/15 6.67%
wchar.h 3/60 5%
wctype.h 0/21 0%
No dude en enviar PRS o problemas abiertos. Información principal de: en.cppreference.com
Por defecto, solo las pruebas unitarias se ejecutan con go test . También puede incluir todas las pruebas:
go test ./...Para las pruebas funcionan como esta:
clang recopila la C a un binario como normal.c4go convierte el archivo C para ir. Si usa Ubuntu , use el comando como Siguiente para elegir la versión clang :
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-6.0 1000 El tiempo principal de transpilación toma clang , por ejemplo, ejecutar:
go test -run=Benchmark -bench=. -benchmemEl resultado se ve por ejemplo:
goos: linux
goarch: amd64
pkg: github.com/Konstantin8105/c4go
BenchmarkTranspile/Full-6 5 274922964 ns/op 43046865 B/op 379676 allocs/op
BenchmarkTranspile/GoCode-6 20 86806808 ns/op 36577533 B/op 308060 allocs/op
PASS
Entonces, el tiempo de transpilación es solo el 30% de tiempo completo. En mi punto de vista, no hay necesidad de optimización del rendimiento, ver la ley de Amdahl.
Por favor, ejecute:
# Run cpuprofiling for sqlite transpilation example
time ./scripts/sqlite.sh
# Example of output:
#
# % Total % Received % Xferd Average Speed Time Time Time Current
# Dload Upload Total Spent Left Speed
# 100 2217k 100 2217k 0 0 235k 0 0:00:09 0:00:09 --:--:-- 357k
# Archive: /tmp/SQLITE/sqlite-amalgamation-3250200.zip
# creating: /tmp/SQLITE/sqlite-amalgamation-3250200/
# inflating: /tmp/SQLITE/sqlite-amalgamation-3250200/sqlite3ext.h
# inflating: /tmp/SQLITE/sqlite-amalgamation-3250200/sqlite3.c
# inflating: /tmp/SQLITE/sqlite-amalgamation-3250200/sqlite3.h
# inflating: /tmp/SQLITE/sqlite-amalgamation-3250200/shell.c
# After transpiling shell.c and sqlite3.c together, have summary: 695 warnings.
# In file sqlite.go summary : 3 warnings in go build.
# Amount unsafe package using: 2902
#
# real 0m18.434s
# user 0m14.212s
# sys 0m1.434s
# Run profiler
go tool pprof ./testdata/cpu.outPara obtener más información, consulte Profiles GO Programas.