ci: fix `v check-md tutorials/`
parent
1b87a4770c
commit
436081a9f5
|
@ -1,6 +1,8 @@
|
||||||
In this tutorial I'll demonstrate C2V, a fully automatic C to V source code translator, that has just been released.
|
In this tutorial I'll demonstrate C2V, a fully automatic C to V source code translator,
|
||||||
|
that has just been released.
|
||||||
|
|
||||||
We'll run some simple examples and then translate the entire original DOOM, the legendary shooter, the first ever 3D game released in 1993 and open sourced in 1997.
|
We'll run some simple examples and then translate the entire original DOOM,
|
||||||
|
the legendary shooter, the first ever 3D game released in 1993 and open sourced in 1997.
|
||||||
|
|
||||||
A video version of this tutorial is available on YouTube:
|
A video version of this tutorial is available on YouTube:
|
||||||
|
|
||||||
|
@ -8,8 +10,10 @@ https://www.youtube.com/watch?v=6oXrz3oRoEg
|
||||||
|
|
||||||
Let's start.
|
Let's start.
|
||||||
|
|
||||||
First, We have a simple C program that prints prime numbers. It's a small program, but it has some of the most widely used language features:
|
First, We have a simple C program that prints prime numbers. It's a small program,
|
||||||
function definitions, control flow via for loops and if conditions, a libc function call, and various expressions.
|
but it has some of the most widely used language features:
|
||||||
|
function definitions, control flow via for loops and if conditions, a libc function call,
|
||||||
|
and various expressions.
|
||||||
|
|
||||||
|
|
||||||
```c
|
```c
|
||||||
|
@ -45,7 +49,7 @@ It will create `primes.v` with the following contents:
|
||||||
|
|
||||||
```v
|
```v
|
||||||
fn is_prime(x int) bool {
|
fn is_prime(x int) bool {
|
||||||
for i := 2 ; i <= sqrt(x) + 1 ; i ++ {
|
for i := 2; i <= x / 2; i++ {
|
||||||
if x % i == 0 {
|
if x % i == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -54,7 +58,7 @@ fn is_prime(x int) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
for i := 2 ; i < 100 ; i ++ {
|
for i := 2; i < 100; i++ {
|
||||||
if is_prime(i) {
|
if is_prime(i) {
|
||||||
C.printf(c'%i\n', i)
|
C.printf(c'%i\n', i)
|
||||||
}
|
}
|
||||||
|
@ -65,21 +69,25 @@ fn main() {
|
||||||
|
|
||||||
This is a valid V program, and running it will give us the same result.
|
This is a valid V program, and running it will give us the same result.
|
||||||
|
|
||||||
This code is pretty similar to the original, you can notice one major difference. C allows one statement code blocks without brackets, and V doesn't, so in the translated code all blocks
|
This code is pretty similar to the original, you can notice one major difference.
|
||||||
are explicitely marked with brackets.
|
C allows one statement code blocks without brackets, and V doesn't, so in the
|
||||||
|
translated code all blocks are explicitely marked with brackets.
|
||||||
|
|
||||||
C2V successfully converts C's bool type to V's bool.
|
C2V successfully converts C's bool type to V's bool.
|
||||||
|
|
||||||
|
|
||||||
C2V also has a wrapper generation mode.
|
C2V also has a wrapper generation mode.
|
||||||
|
|
||||||
For many projects it would make more sense not to translate the entire C code base, but just to generate V wrappers on top of C APIs.
|
For many projects it would make more sense not to translate the entire C code base,
|
||||||
|
but just to generate V wrappers on top of C APIs.
|
||||||
|
|
||||||
For example, let's say you have some complicated crypto or networking library in C with lots of functions and types, and you don't want to manually type their definitions in V.
|
For example, let's say you have some complicated crypto or networking library in C
|
||||||
|
with lots of functions and types, and you don't want to manually type their definitions in V.
|
||||||
|
|
||||||
For this C2V has a wrapper mode.
|
For this C2V has a wrapper mode.
|
||||||
|
|
||||||
We have a simple file `usersapi.h`. By running `v translate -wrapper usersapi.c` we get `usersapi.v` with just the function definitions. Function bodies are skipped.
|
We have a simple file `usersapi.h`. By running `v translate -wrapper usersapi.c`
|
||||||
|
we get `usersapi.v` with just the function definitions. Function bodies are skipped.
|
||||||
|
|
||||||
```c
|
```c
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -111,30 +119,44 @@ pub fn f get_number_of_users() int {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
C doesn't have modules, so in most C libraries all functions start with the same prefix, the name of the virtual module. C2V helpfully strips those prefixes and generates nice clean wrapper functions that can be called with `usersapi.create_user()` instead of `usersapi.usersapi_create_user()`
|
C doesn't have modules, so in most C libraries all functions start with the same prefix,
|
||||||
|
the name of the virtual module. C2V helpfully strips those prefixes and generates nice
|
||||||
|
clean wrapper functions that can be called with `usersapi.create_user()` instead of
|
||||||
|
`usersapi.usersapi_create_user()`
|
||||||
|
|
||||||
Perhaps in the future C2V will translate C strings (char pointers) to V strings as well.
|
Perhaps in the future C2V will translate C strings (char pointers) to V strings as well.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All right, this works, and it's nice, but these are very trivial examples. Let's try something a lot more fun, like the DOOM game.
|
All right, this works, and it's nice, but these are very trivial examples.
|
||||||
|
Let's try something a lot more fun, like the DOOM game.
|
||||||
|
|
||||||
|
|
||||||
We think it's very important to have large functioning examples to demonstrate the power of the tools but also to have something to test via CI to avoid regressions. During V's release we had lots of various examples, now for C2V we have DOOM. This is the primary test of C2V.
|
We think it's very important to have large functioning examples to demonstrate the power
|
||||||
|
of the tools but also to have something to test via CI to avoid regressions.
|
||||||
|
During V's release we had lots of various examples, now for C2V we have DOOM.
|
||||||
|
This is the primary test of C2V.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DOOM is a very complex project that uses some really tricky elements of the C language. And making sure C2V can always handle DOOM not only serves as a good C2V test but also as a test of the V compiler itself, since it can run entire DOOM in pure V.
|
DOOM is a very complex project that uses some really tricky elements of the C language.
|
||||||
|
And making sure C2V can always handle DOOM not only serves as a good C2V test but also
|
||||||
|
as a test of the V compiler itself, since it can run entire DOOM in pure V.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
First let's download the DOOM source and build it to make sure everything works.
|
First let's download the DOOM source and build it to make sure everything works.
|
||||||
The original 1997 open source release doesn't work nicely on modern OSs, so the community has been working on different forks. I'll be using Chocolate Doom, it's one of the most popular forks, and its goal is to be as close to the original as possible (they even keep the original bugs).
|
The original 1997 open source release doesn't work nicely on modern OSs, so the community
|
||||||
|
has been working on different forks. I'll be using Chocolate Doom, it's one of the most
|
||||||
|
popular forks, and its goal is to be as close to the original as possible
|
||||||
|
(they even keep the original bugs).
|
||||||
|
|
||||||
The main difference in this fork is using SDL for cross platform rendering, so we'll need to install SDL2 before we can build it.
|
The main difference in this fork is using SDL for cross platform rendering, so we'll need
|
||||||
|
to install SDL2 before we can build it.
|
||||||
|
|
||||||
A great thing about DOOM is that it has a very simple structure and is easy to build.
|
A great thing about DOOM is that it has a very simple structure and is easy to build.
|
||||||
It's just a bunch of C files that are compiled into object files and are later linked into a single executable.
|
It's just a bunch of C files that are compiled into object files and are later linked
|
||||||
|
into a single executable.
|
||||||
|
|
||||||
To build the C version:
|
To build the C version:
|
||||||
|
|
||||||
|
@ -145,7 +167,8 @@ cmake .
|
||||||
make chocolate-doom
|
make chocolate-doom
|
||||||
```
|
```
|
||||||
|
|
||||||
We'll also need a freely distributed shareware doom1.wad with game resources and the first free levels.
|
We'll also need a freely distributed shareware doom1.wad with game resources and
|
||||||
|
the first free levels.
|
||||||
|
|
||||||
Now let's run the compiled game
|
Now let's run the compiled game
|
||||||
|
|
||||||
|
@ -156,7 +179,8 @@ Now let's run the compiled game
|
||||||
Great, as expected, it all works, now let's translate it to V and try to build that.
|
Great, as expected, it all works, now let's translate it to V and try to build that.
|
||||||
|
|
||||||
|
|
||||||
In the previous example we translated a single file, this time we'll translate an entire directory.
|
In the previous example we translated a single file, this time we'll translate
|
||||||
|
an entire directory.
|
||||||
|
|
||||||
```
|
```
|
||||||
v translate src/doom
|
v translate src/doom
|
||||||
|
@ -170,7 +194,8 @@ And we can use any name we want, there's a c2v configuration file.
|
||||||
|
|
||||||
It has a bunch of files translated from C to V.
|
It has a bunch of files translated from C to V.
|
||||||
|
|
||||||
We can open any file, for example g_game.c and verify that it is indeed DOOM code translated from C to V. It's also been nicely formatted by vfmt.
|
We can open any file, for example g_game.c and verify that it is indeed DOOM code
|
||||||
|
translated from C to V. It's also been nicely formatted by vfmt.
|
||||||
|
|
||||||
|
|
||||||
Now let's build it.
|
Now let's build it.
|
||||||
|
@ -192,9 +217,11 @@ I'll explain what we have in the shell script a bit later.
|
||||||
|
|
||||||
But first let's run the translated code!
|
But first let's run the translated code!
|
||||||
|
|
||||||
The script compiles into the `src/doom/doomv` binary. Everything works. We have the music, we can watch the demo, go to the settings, start the game, walk around and shoot enemies.
|
The script compiles into the `src/doom/doomv` binary. Everything works. We have the music,
|
||||||
|
we can watch the demo, go to the settings, start the game, walk around and shoot enemies.
|
||||||
|
|
||||||
There's a slight rendering bug at the bottom, but it can be cleaned up by pressing tab twice and forcing a re-render.
|
There's a slight rendering bug at the bottom, but it can be cleaned up by pressing tab twice
|
||||||
|
and forcing a re-render.
|
||||||
|
|
||||||
There's a bug somewhere in C2V, it has just been released and needs some fixes.
|
There's a bug somewhere in C2V, it has just been released and needs some fixes.
|
||||||
|
|
||||||
|
@ -211,7 +238,8 @@ C2V doesn't understand makefiles yet, so we have to do things manually.
|
||||||
In the future making such scripts won't be necessary.
|
In the future making such scripts won't be necessary.
|
||||||
|
|
||||||
|
|
||||||
Since doom uses C libraries like textscreen, pcsound, and opl, and we are only translating doom itself, we need to build doom.o and then link it with the rest of object files.
|
Since doom uses C libraries like textscreen, pcsound, and opl, and we are only translating
|
||||||
|
doom itself, we need to build doom.o and then link it with the rest of object files.
|
||||||
|
|
||||||
`build_doom_v.sh`:
|
`build_doom_v.sh`:
|
||||||
|
|
||||||
|
@ -232,30 +260,38 @@ cc -o doomv \
|
||||||
```
|
```
|
||||||
|
|
||||||
The first line compiles all V files in `doom_v/` directory into a single doom.o object file.
|
The first line compiles all V files in `doom_v/` directory into a single doom.o object file.
|
||||||
`-translated` tells V that the code was translated from C, so the compiler is less strict. For example it allows using `i++` as an expression (in V it always must be a statement). In the future C2V will be able to translate such C expressions into valid V code, and `-translated` will be removed entirely.
|
`-translated` tells V that the code was translated from C, so the compiler is less strict.
|
||||||
|
For example it allows using `i++` as an expression (in V it always must be a statement).
|
||||||
|
In the future C2V will be able to translate such C expressions into valid V code,
|
||||||
|
and `-translated` will be removed entirely.
|
||||||
|
|
||||||
After generating doom.o, we can compile the entire project.
|
After generating doom.o, we can compile the entire project.
|
||||||
|
|
||||||
|
|
||||||
The second line links it with the rest of the object files.
|
The second line links it with the rest of the object files.
|
||||||
|
|
||||||
Here we have the shared library used by other games in the chocolate doom project: Hexen, Heretic, and Strife.
|
Here we have the shared library used by other games in the chocolate doom project:
|
||||||
|
Hexen, Heretic, and Strife.
|
||||||
|
|
||||||
Then textscreen, pcsound, and opl.
|
Then textscreen, pcsound, and opl.
|
||||||
|
|
||||||
|
|
||||||
In the near future we'll also translate all these C libraries DOOM depends on, and this shell script and interacting with the C compiler won't be needed. The entire project will be runnable with a simple `v translate src/doom && v .`
|
In the near future we'll also translate all these C libraries DOOM depends on, and this
|
||||||
|
shell script and interacting with the C compiler won't be needed. The entire project will
|
||||||
|
be runnable with a simple `v translate src/doom && v .`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
One other thing I wanted to do is to show you that it actually is V code we are running.
|
One other thing I wanted to do is to show you that it actually is V code we are running.
|
||||||
|
|
||||||
Let's go to `p_enemy.v` and modify the `P_Move` function. We can add a simple println with some V specific code, like a reversed V array.
|
Let's go to `p_enemy.v` and modify the `P_Move` function. We can add a simple println with
|
||||||
|
some V specific code, like a reversed V array.
|
||||||
|
|
||||||
|
|
||||||
`println([1, 2, 3, 4, 5].reverse())`
|
`println([1, 2, 3, 4, 5].reverse())`
|
||||||
|
|
||||||
Let's rebuild it and run again. As expected, we're getting our array printed every time an enemy moves.
|
Let's rebuild it and run again. As expected, we're getting our array printed every time an
|
||||||
|
enemy moves.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -264,11 +300,16 @@ Let's rebuild it and run again. As expected, we're getting our array printed eve
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
We translated the entire project. But sometimes it may be better to do more gradual transition from C to V. For example, if you want to move your project from C to V, you might prefer doing it slowly and carefully, file by file. After each file migration you can run tests and see if your application runs correctly.
|
We translated the entire project. But sometimes it may be better to do more gradual transition
|
||||||
|
from C to V. For example, if you want to move your project from C to V, you might prefer doing
|
||||||
|
it slowly and carefully, file by file. After each file migration you can run tests and see if
|
||||||
|
your application runs correctly.
|
||||||
|
|
||||||
You can do that with c2v. All you need to do is just translate a single file, generate an object file, and replace your current C object file with the new V object file.
|
You can do that with c2v. All you need to do is just translate a single file, generate an object
|
||||||
|
file, and replace your current C object file with the new V object file.
|
||||||
|
|
||||||
We can do this with DOOM too. In fact that's how we made the entire thing work. We were doing it for every single file, one by one, fixing compilation errors, bugs in C2V, and runtime bugs.
|
We can do this with DOOM too. In fact that's how we made the entire thing work. We were doing it
|
||||||
|
for every single file, one by one, fixing compilation errors, bugs in C2V, and runtime bugs.
|
||||||
|
|
||||||
```
|
```
|
||||||
c2v -o p_enemy.o p_enemy.v
|
c2v -o p_enemy.o p_enemy.v
|
||||||
|
@ -278,21 +319,29 @@ make chocolate-doom
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
It is actually amazing how well it all works considering there have been two translation processes. From C to V via C2V and then From V back to C again via the V compiler.
|
It is actually amazing how well it all works considering there have been two translation
|
||||||
|
processes. From C to V via C2V and then From V back to C again via the V compiler.
|
||||||
|
|
||||||
In fact we can actually look at the generated C code after all the translation and compare it to the original. Very clean and barely changed:
|
In fact we can actually look at the generated C code after all the translation and compare it
|
||||||
|
to the original. Very clean and barely changed:
|
||||||
|
|
||||||
Both C2V and V generate clean human readable code.
|
Both C2V and V generate clean human readable code.
|
||||||
|
|
||||||
https://twitter.com/v_language/status/1531816534011682821
|
https://twitter.com/v_language/status/1531816534011682821
|
||||||
|
|
||||||
The comments and C defines are missing right now, that's obviously something very nice to have, so they will be translated as well.
|
The comments and C defines are missing right now, that's obviously something very nice to have,
|
||||||
|
so they will be translated as well.
|
||||||
|
|
||||||
|
|
||||||
C2V has just been released on June 22th 2022, so it's going to mature with the help of the community.
|
C2V has just been released on June 22th 2022, so it's going to mature with the help of
|
||||||
With bug fixes and new C features supported, it should support the entire C standard soon. Luckily C is a relatively small language. Any kind of software written in C will be translatable to V fully automatically.
|
the community. With bug fixes and new C features supported, it should support the
|
||||||
|
entire C standard soon.
|
||||||
|
Luckily C is a relatively small language. Any kind of software written in C will be
|
||||||
|
translatable to V fully automatically.
|
||||||
|
|
||||||
I will also be publishing the same demo with Sqlite and Quake translation.
|
I will also be publishing the same demo with Sqlite and Quake translation.
|
||||||
|
|
||||||
It's a huge milestone for V and gives V developers access to huge amounts of software written in C.
|
It's a huge milestone for V and gives V developers access to huge amounts of software
|
||||||
|
written in C.
|
||||||
|
|
||||||
We're very excited about this release.
|
We're very excited about this release.
|
||||||
|
|
Loading…
Reference in New Issue