Compare commits
No commits in common. "v0.0.12" and "master" have entirely different histories.
|
@ -0,0 +1,15 @@
|
|||
freebsd_instance:
|
||||
image_family: freebsd-13-0
|
||||
|
||||
freebsd_task:
|
||||
name: Code CI / freebsd
|
||||
install_script: pkg install -y git
|
||||
script: |
|
||||
echo 'Building V'
|
||||
git clone https://github.com/vlang/v
|
||||
cd v
|
||||
make
|
||||
##.github/workflows/freebsd_build_tcc.sh
|
||||
##tcc -v -v
|
||||
echo 'Build cmd/tools/fast'
|
||||
cd cmd/tools/fast && ../../../v fast.v && ./fast -clang
|
|
@ -0,0 +1,44 @@
|
|||
## TODO: support more precise struct/const/enum fields
|
||||
|
||||
--langdef=V
|
||||
--map-V=+.v
|
||||
--map-V=+.vv
|
||||
--map-V=+.vsh
|
||||
--kinddef-V=m,imodule,imported modules
|
||||
--kinddef-V=M,module,modules
|
||||
--kinddef-V=C,cfunction,cfunctions
|
||||
--kinddef-V=f,function,functions
|
||||
--kinddef-V=h,method,functions
|
||||
--kinddef-V=c,const,constants
|
||||
--kinddef-V=v,variable,variables
|
||||
--kinddef-V=s,struct,structs
|
||||
--kinddef-V=e,enum,enums
|
||||
--kinddef-V=i,interface,interfaces
|
||||
--kinddef-V=S,sfield,struct field
|
||||
--kinddef-V=E,efield,enum field
|
||||
--_roledef-V.m=imported,imported module
|
||||
--_roledef-V.M=declared,module declaration
|
||||
--regex-V=/^module[[:blank:]]+([0-9a-zA-Z]+)[[:blank:]]*$/\1/M/{_role=declared}{scope=push}
|
||||
--regex-V=/^import[[:blank:]]+(([0-9a-zA-Z]+)?|.*\.([a-zA-Z_][0-9a-zA-Z]+))[[:blank:]]*$/\2\3/m/{_role=imported}{scope=ref}
|
||||
--regex-V=/^[[:blank:]]*fn[[:blank:]]+C\.([a-zA-Z_][0-9a-zA-Z_]*)\(/C.\1/C/
|
||||
--regex-V=/^(pub)?[[:blank:]]*fn[[:blank:]]+([a-zA-Z_][0-9a-zA-Z_]*)\(/\2/f/
|
||||
--regex-V=/^(pub)?[[:blank:]]*fn[[:blank:]]+\(.*\)[[:blank:]]*([a-zA-Z_][0-9a-zA-Z_]*)\(/\2/h/
|
||||
--regex-V=/^(pub)?[[:blank:]]*struct[[:blank:]]+([a-zA-Z_][0-9a-zA-Z_]*)[[:blank:]]*\{/\2/s/{scope=push}
|
||||
--regex-V=/^(pub)?[[:blank:]]*enum[[:blank:]]+([a-zA-Z_][0-9a-zA-Z_]*)[[:blank:]]*\{/\2/e/{scope=push}
|
||||
--regex-V=/^(pub)?[[:blank:]]*interface[[:blank:]]+([a-zA-Z_][0-9a-zA-Z_]*)[[:blank:]]*\{/\2/i/{scope=push}
|
||||
--regex-V=/^[[:blank:]]*([a-zA-Z_][0-9a-zA-Z_]+)[[:blank:]]*(,)?[[:blank:]]*(\/\/.*)?$/\1/E/{scope=ref}
|
||||
--regex-V=/^[[:blank:]]*([a-zA-Z_][0-9a-zA-Z_]+)[[:blank:]]+\??\&?(\[[0-9]*\])?([a-zA-Z_][0-9a-zA-Z_.]+)[[:blank:]]*(\/\/.*)?$/\1/S/{scope=ref}
|
||||
--regex-V=/^[[:blank:]]*\}[[:blank:]]*$//{scope=pop}{placeholder}
|
||||
|
||||
## Variables:
|
||||
--regex-V=/^[[:blank:]]*(mut[[:blank:]]+)?([a-zA-Z_][0-9a-zA-Z_]+)[[:blank:]]*:=/\2/v/
|
||||
|
||||
## Consts:
|
||||
--regex-V=/^(pub)?[[:blank:]]*const[[:blank:]]+\([[:blank:]]*/const/c/{scope=push}
|
||||
##NB: the next variable regexp should work only inside const ( ), but currently works for ordinary assignments too:
|
||||
--regex-V=/^[[:blank:]]*([a-zA-Z_][0-9a-zA-Z_]+)[[:blank:]]*=/\1/v/{scope=ref}
|
||||
--regex-V=/^[[:blank:]]*\)[[:blank:]]*$//{scope=pop}{placeholder}
|
||||
|
||||
--extras=+q
|
||||
--extras=+r
|
||||
--fields=+r
|
|
@ -0,0 +1,29 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.v]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[*.{yml,yaml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
# lines that are too long will trigger an error in cmd/tools/vcheck-md.v
|
||||
# run v check-md [folder/file] to test markdown files
|
||||
# the longest normal line is specified with this constant:
|
||||
# `too_long_line_length_other = 100`
|
||||
max_line_length = 100
|
||||
|
||||
[*.{txt,out}]
|
||||
insert_final_newline = false
|
||||
|
||||
[{Makefile,GNUmakefile}]
|
||||
indent_style = tab
|
|
@ -1,2 +1,7 @@
|
|||
*.v linguist-language=Go
|
||||
website/* linguist-vendored
|
||||
*.v linguist-language=V text=auto eol=lf
|
||||
*.vv linguist-language=V text=auto eol=lf
|
||||
*.vsh linguist-language=V text=auto eol=lf
|
||||
**/v.mod linguist-language=V text=auto eol=lf
|
||||
*.bat text=auto eol=crlf
|
||||
Dockerfile.* linguist-language=Dockerfile
|
||||
*.toml text eol=lf
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
patreon: vlang
|
||||
github: [medvednikov]
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
name: Bug report for V
|
||||
about: Please use the appropriate label when submitting an issue: bug/feature request/question.
|
||||
title: "New issue"
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- You can use `v doctor` to fill up the next fields -->
|
||||
|
||||
#### V version:
|
||||
|
||||
#### OS:
|
||||
|
||||
#### C Compiler:
|
||||
|
||||
|
||||
## What did you do?
|
||||
|
||||
|
||||
### What did you expect to see?
|
||||
|
||||
|
||||
### What did you see instead?
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Bug report
|
||||
title: ''
|
||||
labels: 'Bug'
|
||||
assignees: ''
|
||||
# When updating, make sure to update the template in 'cmd/tools/vbug.v' too
|
||||
---
|
||||
|
||||
<!-- Please make sure to run `v up` before reporting any issues as it may have already been fixed.
|
||||
It's also advisable to update all relevant modules using `v outdated` and `v install` -->
|
||||
|
||||
<!-- You can use `v doctor` to fill up the next fields -->
|
||||
**V version:**
|
||||
**OS:**
|
||||
|
||||
<!-- Please include the standalone minimal reproducible code.
|
||||
If not, it may be closed by the administrators. -->
|
||||
**What did you do?**
|
||||
|
||||
|
||||
**What did you expect to see?**
|
||||
|
||||
|
||||
**What did you see instead?**
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: 'Feature Request'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
|
||||
<!--
|
||||
|
||||
Please title your PR as follows: `time: fix foo bar`.
|
||||
Always start with the thing you are fixing, then describe the fix.
|
||||
Don't use past tense (e.g. "fixed foo bar").
|
||||
|
||||
Explain what your PR does and why.
|
||||
|
||||
If you are adding a new function, please document it and add tests:
|
||||
|
||||
```
|
||||
// foo does foo and bar
|
||||
fn foo() {
|
||||
|
||||
// file_test.v
|
||||
fn test_foo() {
|
||||
assert foo() == ...
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
If you are fixing a bug, please add a test that covers it.
|
||||
|
||||
Before submitting a PR, please run `v test-all` .
|
||||
See also `TESTS.md`.
|
||||
|
||||
I try to process PRs as soon as possible. They should be handled within 24 hours.
|
||||
|
||||
Applying labels to PRs is not needed.
|
||||
|
||||
Thanks a lot for your contribution!
|
||||
|
||||
-->
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/sh -l
|
||||
|
||||
set -e
|
||||
|
||||
pwd
|
||||
|
||||
uname -a
|
||||
|
||||
make -j4
|
||||
|
||||
./v version
|
||||
|
||||
du -s .
|
||||
|
||||
echo "DONE"
|
|
@ -0,0 +1,24 @@
|
|||
#!/bin/sh -l
|
||||
|
||||
set -e
|
||||
|
||||
pwd
|
||||
|
||||
uname -a
|
||||
|
||||
du -s .
|
||||
|
||||
ls -lat
|
||||
|
||||
##./v test-all
|
||||
|
||||
## try running the known failing tests first to get faster feedback
|
||||
./v test vlib/builtin/string_test.v vlib/strings/builder_test.v
|
||||
|
||||
./v test-cleancode
|
||||
|
||||
./v test-self
|
||||
|
||||
./v build-vbinaries
|
||||
|
||||
echo "DONE"
|
|
@ -0,0 +1,67 @@
|
|||
#!/usr/bin/env -S v
|
||||
|
||||
module main
|
||||
|
||||
import os
|
||||
import vab.vxt
|
||||
import vab.android.ndk
|
||||
|
||||
fn main() {
|
||||
assert ndk.found()
|
||||
assert vxt.found()
|
||||
|
||||
work_dir := os.join_path(os.temp_dir(), 'android_cross_compile_test')
|
||||
os.rm(work_dir) or {}
|
||||
os.mkdir_all(work_dir) or { panic(err) }
|
||||
vexe := vxt.vexe()
|
||||
|
||||
examples_dir := os.join_path(vxt.home(), 'examples')
|
||||
v_example := os.join_path(examples_dir, 'toml.v')
|
||||
|
||||
ndk_version := ndk.default_version()
|
||||
|
||||
sysroot_path := ndk.sysroot_path(ndk_version) or { panic(err) }
|
||||
include_path := os.join_path(sysroot_path, 'usr', 'include')
|
||||
android_include_path := os.join_path(include_path, 'android')
|
||||
|
||||
//'-I"$include_path"'
|
||||
cflags := ['-I"$android_include_path"', '-Wno-unused-value', '-Wno-implicit-function-declaration',
|
||||
'-Wno-int-conversion']
|
||||
for arch in ndk.supported_archs {
|
||||
for level in ['min', 'max'] {
|
||||
compiler_api := match level {
|
||||
'min' {
|
||||
ndk.compiler_min_api(.c, ndk_version, arch) or { panic(err) }
|
||||
}
|
||||
'max' {
|
||||
ndk.compiler_max_api(.c, ndk_version, arch) or { panic(err) }
|
||||
}
|
||||
else {
|
||||
panic('invalid min/max level')
|
||||
}
|
||||
}
|
||||
|
||||
os.setenv('VCROSS_COMPILER_NAME', compiler_api, true)
|
||||
c_file := os.join_path(work_dir, arch + '-' + level + '.c')
|
||||
o_file := os.join_path(work_dir, arch + '-' + level + '.o')
|
||||
|
||||
// x.v -> x.c
|
||||
v_compile_cmd := '$vexe -o $c_file -os android -gc none $v_example'
|
||||
vres := os.execute(v_compile_cmd)
|
||||
if vres.exit_code != 0 {
|
||||
panic('"$v_compile_cmd" failed: $vres.output')
|
||||
}
|
||||
assert os.exists(c_file)
|
||||
|
||||
// x.c -> x.o
|
||||
compile_cmd := '$compiler_api ${cflags.join(' ')} -c $c_file -o $o_file'
|
||||
cres := os.execute(compile_cmd)
|
||||
if cres.exit_code != 0 {
|
||||
panic('"$compile_cmd" failed: $cres.output')
|
||||
}
|
||||
assert os.exists(o_file)
|
||||
compiler_exe_name := os.file_name(compiler_api)
|
||||
println('Compiled examples/toml.v successfully for ($level) $arch $compiler_exe_name')
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
name: Build binary artifacts
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- weekly.**
|
||||
- 0.**
|
||||
|
||||
jobs:
|
||||
|
||||
build-linux:
|
||||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
CC: gcc
|
||||
ZIPNAME: v_linux.zip
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Compile
|
||||
run: |
|
||||
make -j4
|
||||
./v -cc $CC -prod -o v cmd/v
|
||||
./v -cc $CC -prod cmd/tools/vup.v
|
||||
./v -cc $CC -prod cmd/tools/vdoctor.v
|
||||
- name: Remove excluded
|
||||
run: |
|
||||
rm -rf .git
|
||||
rm -rf vc/
|
||||
rm -rf v_old
|
||||
- name: Create ZIP archive
|
||||
run: |
|
||||
cd ..
|
||||
zip -r9 --symlinks $ZIPNAME v/
|
||||
mv $ZIPNAME v/
|
||||
cd v/
|
||||
- name: Create artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: linux
|
||||
path: v_linux.zip
|
||||
|
||||
build-macos:
|
||||
runs-on: macos-latest
|
||||
env:
|
||||
CC: clang
|
||||
ZIPNAME: v_macos.zip
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Compile
|
||||
run: |
|
||||
make -j4
|
||||
./v -cc $CC -prod -o v cmd/v
|
||||
./v -cc $CC -prod cmd/tools/vup.v
|
||||
./v -cc $CC -prod cmd/tools/vdoctor.v
|
||||
- name: Remove excluded
|
||||
run: |
|
||||
rm -rf .git
|
||||
rm -rf vc/
|
||||
rm -rf v_old
|
||||
- name: Create ZIP archive
|
||||
run: |
|
||||
cd ..
|
||||
zip -r9 --symlinks $ZIPNAME v/
|
||||
mv $ZIPNAME v/
|
||||
cd v/
|
||||
- name: Create artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: macos
|
||||
path: v_macos.zip
|
||||
|
||||
build-windows:
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
CC: msvc
|
||||
ZIPNAME: v_windows.zip
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: msys2/setup-msys2@v2
|
||||
- name: Compile
|
||||
run: |
|
||||
.\make.bat -tcc
|
||||
.\v.exe cmd\tools\vup.v
|
||||
.\v.exe cmd\tools\vdoctor.v
|
||||
- name: Remove excluded
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
rm -rf .git
|
||||
rm -rf vc/
|
||||
rm -rf v_old.exe
|
||||
- name: Create archive
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
cd ..
|
||||
powershell Compress-Archive v $ZIPNAME
|
||||
mv $ZIPNAME v/
|
||||
cd v/
|
||||
# NB: the powershell Compress-Archive line is from:
|
||||
# https://superuser.com/a/1336434/194881
|
||||
# It is needed, because `zip` is not installed by default :-|
|
||||
- name: Create artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: windows
|
||||
path: v_windows.zip
|
||||
|
||||
release:
|
||||
name: Create Github Release
|
||||
needs: [build-linux, build-windows, build-macos]
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Get short tag name
|
||||
uses: jungwinter/split@v1
|
||||
id: split
|
||||
with:
|
||||
msg: ${{ github.ref }}
|
||||
seperator: /
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tag: ${{ steps.split.outputs._2 }}
|
||||
name: ${{ steps.split.outputs._2 }}
|
||||
commit: ${{ github.sha }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
publish:
|
||||
needs: [release]
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
version: [linux, macos, windows]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Fetch artifacts
|
||||
uses: actions/download-artifact@v1
|
||||
with:
|
||||
name: ${{ matrix.version }}
|
||||
path: ./${{ matrix.version }}
|
||||
- name: Get short tag name
|
||||
uses: jungwinter/split@v1
|
||||
id: split
|
||||
with:
|
||||
msg: ${{ github.ref }}
|
||||
seperator: /
|
||||
- name: Get release
|
||||
id: get_release_info
|
||||
uses: leahlundqvist/get-release@v1.3.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
with:
|
||||
tag_name: ${{ steps.split.outputs._2 }}
|
||||
- name: Upload Release Asset
|
||||
id: upload-release-asset
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.get_release_info.outputs.upload_url }}
|
||||
asset_path: ${{ matrix.version }}/v_${{ matrix.version }}.zip
|
||||
asset_name: v_${{ matrix.version }}.zip
|
||||
asset_content_type: application/zip
|
|
@ -0,0 +1,56 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
V=$PWD/v
|
||||
|
||||
if [[ -x "$V" ]]
|
||||
then
|
||||
echo "The v executable exists."
|
||||
else
|
||||
echo "This script should be run from the top level folder of a V repository"
|
||||
echo "i.e. the folder where your V executable is."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BUILD=$PWD/vinix_build
|
||||
|
||||
echo "Creating $BUILD folder..."
|
||||
rm -rf $BUILD
|
||||
mkdir -p $BUILD
|
||||
|
||||
cd $BUILD
|
||||
echo "Clone current Vinix"
|
||||
git clone https://github.com/vlang/vinix.git --depth=1
|
||||
|
||||
cd $BUILD
|
||||
echo "Clone current mlibc"
|
||||
git clone https://github.com/managarm/mlibc.git --depth=1
|
||||
|
||||
cd $BUILD
|
||||
echo "Patch mlibc for Vinix"
|
||||
cd mlibc
|
||||
patch -p3 < ../vinix/patches/mlibc/mlibc.patch
|
||||
|
||||
cd $BUILD
|
||||
echo "Install mlibc headers"
|
||||
mkdir mlibc-build
|
||||
cd mlibc-build
|
||||
meson --cross-file ../vinix/cross_file.txt --prefix=/ -Dheaders_only=true ../mlibc
|
||||
ninja
|
||||
mkdir ../mlibc-headers
|
||||
DESTDIR=`realpath ../mlibc-headers` ninja install
|
||||
|
||||
cd $BUILD
|
||||
echo "Attempt to build the Vinix kernel (debug)"
|
||||
cd vinix/kernel
|
||||
make PROD=false CFLAGS="-D__vinix__ -O2 -g -pipe -I../../mlibc-headers/include"
|
||||
make clean
|
||||
|
||||
cd $BUILD
|
||||
echo "Attempt to build the Vinix kernel (prod)"
|
||||
cd vinix/kernel
|
||||
make PROD=true CFLAGS="-D__vinix__ -O2 -g -pipe -I../../mlibc-headers/include"
|
||||
make clean
|
||||
|
||||
rm -rf $BUILD
|
|
@ -0,0 +1,18 @@
|
|||
name: Cancel previous workflows
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Code CI"]
|
||||
types:
|
||||
- requested
|
||||
|
||||
jobs:
|
||||
cancel-previous-workflows:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: spaceface777/cancel-workflow-action@0.9.1
|
||||
# don't cancel CI for commits pushed to vlang/v#master (if ci is still too slow, this can be removed safely)
|
||||
if: ${{ github.event.workflow_run.head_repository.full_name != 'vlang/v' || github.event.workflow_run.head_branch != 'master' }}
|
||||
with:
|
||||
# workflow ids for `Code CI` and `Sanitized CI` (from https://api.github.com/repos/vlang/v/actions/workflows):
|
||||
workflow_id: 4577,7940868 # the other workflows finish quickly - no need to skip them
|
|
@ -0,0 +1,680 @@
|
|||
name: Code CI
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
concurrency:
|
||||
group: build-ci-${{ github.event.pull_request.number || github.sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
ubuntu-tcc:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 121
|
||||
env:
|
||||
VFLAGS: -cc tcc -no-retry-compilation
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --quiet -y libssl-dev sqlite3 libsqlite3-dev valgrind
|
||||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||
## The following is needed for examples/wkhtmltopdf.v
|
||||
wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb
|
||||
sudo apt-get install --quiet -y xfonts-75dpi xfonts-base
|
||||
sudo dpkg -i wkhtmltox_0.12.6-1.focal_amd64.deb
|
||||
- name: Build v
|
||||
run: |
|
||||
echo $VFLAGS
|
||||
make
|
||||
./v test-cleancode
|
||||
./v -d debug_malloc -d debug_realloc -o v cmd/v
|
||||
./v -cg -cstrict -o v cmd/v
|
||||
# Test v -realloc arena allocation
|
||||
./v -o vrealloc -prealloc cmd/v && ./vrealloc -o v3 cmd/v && ./v3 -o v4 cmd/v
|
||||
- name: Test v->c
|
||||
run: |
|
||||
thirdparty/tcc/tcc.exe -version
|
||||
./v -cg -o v cmd/v # Make sure vtcc can build itself twice
|
||||
# ./v test-all
|
||||
- name: v self compilation
|
||||
run: ./v -o v2 cmd/v && ./v2 -o v3 cmd/v && ./v3 -o v4 cmd/v
|
||||
- name: v self compilation with -skip-unused
|
||||
run: ./v -skip-unused -o v2 cmd/v && ./v2 -skip-unused -o v3 cmd/v && ./v3 -skip-unused -o v4 cmd/v
|
||||
- name: v doctor
|
||||
run: |
|
||||
./v doctor
|
||||
- name: Verify `v test` works
|
||||
run: |
|
||||
echo $VFLAGS
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
- name: All code is formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests
|
||||
run: ./v test-self
|
||||
# - name: Self tests (-cstrict)
|
||||
# run: V_CI_CSTRICT=1 ./v -cstrict test-self
|
||||
- name: Test time functions in a timezone UTC-12
|
||||
run: TZ=Etc/GMT+12 ./v test vlib/time/
|
||||
- name: Test time functions in a timezone UTC-3
|
||||
run: TZ=Etc/GMT+3 ./v test vlib/time/
|
||||
- name: Test time functions in a timezone UTC+3
|
||||
run: TZ=Etc/GMT-3 ./v test vlib/time/
|
||||
- name: Test time functions in a timezone UTC+12
|
||||
run: TZ=Etc/GMT-12 ./v test vlib/time/
|
||||
- name: Test time functions in a timezone using daylight saving (Europe/Paris)
|
||||
run: TZ=Europe/Paris ./v test vlib/time/
|
||||
- name: Build examples
|
||||
run: ./v -W build-examples
|
||||
- name: Test building v tools
|
||||
run: ./v -W build-tools
|
||||
- name: Test v binaries
|
||||
run: ./v build-vbinaries
|
||||
- name: Run a VSH script
|
||||
run: ./v run examples/v_script.vsh
|
||||
- name: Test v tutorials
|
||||
run: ./v tutorials/building_a_simple_web_blog_with_vweb/code/blog
|
||||
- name: Build cmd/tools/fast
|
||||
run: cd cmd/tools/fast && ../../../v fast.v && ./fast
|
||||
- name: V self compilation with -usecache
|
||||
run: |
|
||||
unset VFLAGS
|
||||
./v -usecache examples/hello_world.v && examples/hello_world
|
||||
./v -o v2 -usecache cmd/v
|
||||
./v2 -o v3 -usecache cmd/v
|
||||
./v3 version
|
||||
./v3 -o tetris -usecache examples/tetris/tetris.v
|
||||
|
||||
ubuntu-tcc-boehm-gc:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 121
|
||||
env:
|
||||
VFLAGS: -cc tcc -no-retry-compilation
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --quiet -y libssl-dev sqlite3 libsqlite3-dev valgrind
|
||||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||
sudo apt-get install --quiet -y libgc-dev
|
||||
## The following is needed for examples/wkhtmltopdf.v
|
||||
wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb
|
||||
sudo apt-get install --quiet -y xfonts-75dpi xfonts-base
|
||||
sudo dpkg -i wkhtmltox_0.12.6-1.focal_amd64.deb
|
||||
- name: Build v
|
||||
run: |
|
||||
echo $VFLAGS
|
||||
make
|
||||
- name: Test v->c
|
||||
run: |
|
||||
thirdparty/tcc/tcc.exe -version
|
||||
./v -cg -o v cmd/v # Make sure vtcc can build itself twice
|
||||
- name: v self compilation with -gc boehm
|
||||
run: |
|
||||
./v -gc boehm -o v2 cmd/v && ./v2 -gc boehm -o v3 cmd/v && ./v3 -gc boehm -o v4 cmd/v
|
||||
mv v4 v
|
||||
- name: v doctor
|
||||
run: |
|
||||
./v doctor
|
||||
- name: Verify `v -gc boehm test` works
|
||||
run: |
|
||||
./v -gc boehm cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
- name: All code is formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests with `-gc boehm` with V compiler using Boehm-GC itself
|
||||
run: ./v -gc boehm test-self
|
||||
- name: Test leak detector
|
||||
run: |
|
||||
./v -gc boehm_leak -o testcase_leak vlib/v/tests/testcase_leak.vv
|
||||
./testcase_leak 2>leaks.txt
|
||||
grep "Found 1 leaked object" leaks.txt && grep -P ", sz=\s?1000," leaks.txt
|
||||
- name: Test leak detector not being active for `-gc boehm`
|
||||
run: |
|
||||
./v -gc boehm -o testcase_leak vlib/v/tests/testcase_leak.vv
|
||||
./testcase_leak 2>leaks.txt
|
||||
[ "$(stat -c %s leaks.txt)" = "0" ]
|
||||
- name: Test leak detector not being active for normal compile
|
||||
run: |
|
||||
./v -o testcase_leak vlib/v/tests/testcase_leak.vv
|
||||
./testcase_leak 2>leaks.txt
|
||||
[ "$(stat -c %s leaks.txt)" = "0" ]
|
||||
|
||||
macos:
|
||||
runs-on: macOS-12
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 121
|
||||
env:
|
||||
VFLAGS: -cc clang
|
||||
PKG_CONFIG_PATH: /usr/local/opt/openssl@3/lib/pkgconfig
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
##brew install libpq openssl freetype ### these are *already installed* on Catalina ...
|
||||
brew uninstall --ignore-dependencies libpq ## libpq is a dependency of PHP
|
||||
brew install postgresql openssl
|
||||
export LIBRARY_PATH="$LIBRARY_PATH:/usr/local/opt/openssl/lib/"
|
||||
echo "PKG_CONFIG_PATH is '$PKG_CONFIG_PATH'"
|
||||
- name: Build V
|
||||
run: make -j4 && ./v -cg -cstrict -o v cmd/v
|
||||
- name: Run sanitizers
|
||||
run: |
|
||||
./v -o v2 cmd/v -cflags -fsanitize=undefined
|
||||
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./v2 -o v.c cmd/v
|
||||
- name: Build V using V
|
||||
run: ./v -o v2 cmd/v && ./v2 -o v3 cmd/v
|
||||
- name: Test symlink
|
||||
run: ./v symlink
|
||||
# - name: Set up pg database
|
||||
# run: |
|
||||
# pg_ctl -D /usr/local/var/postgres -l /usr/local/var/postgres/server.log start
|
||||
# psql -d postgres -c 'select rolname from pg_roles'
|
||||
# psql -d postgres -c 'create database customerdb;'
|
||||
# psql -d customerdb -f examples/database/pg/mydb.sql
|
||||
# - name: Test v->c
|
||||
# run: ./v test-all
|
||||
# - name: Test v binaries
|
||||
# run: ./v build-vbinaries
|
||||
## - name: Test v->js
|
||||
## run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
||||
- name: Verify `v test` works
|
||||
run: |
|
||||
echo $VFLAGS
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
- name: All code is formatted
|
||||
run: VJOBS=1 ./v test-cleancode
|
||||
- name: Self tests
|
||||
run: VJOBS=1 ./v test-self
|
||||
- name: Build examples
|
||||
run: ./v build-examples
|
||||
- name: Build examples with -autofree
|
||||
run: |
|
||||
./v -autofree -o tetris examples/tetris/tetris.v
|
||||
./v -autofree -o blog tutorials/building_a_simple_web_blog_with_vweb/code/blog
|
||||
- name: v doctor
|
||||
run: |
|
||||
./v doctor
|
||||
- name: Test ved
|
||||
run: |
|
||||
git clone --depth 1 https://github.com/vlang/ved
|
||||
cd ved && ../v -o ved .
|
||||
../v -autofree .
|
||||
cd ..
|
||||
# - name: Test c2v
|
||||
# run: |
|
||||
# git clone --depth 1 https://github.com/vlang/c2v
|
||||
# cd c2v && ../v -o c2v .
|
||||
# ../v .
|
||||
# ../v run tests/run_tests.vsh
|
||||
# ../v -experimental -w c2v_test.v
|
||||
# cd ..
|
||||
- name: Build V UI examples
|
||||
run: |
|
||||
git clone --depth 1 https://github.com/vlang/ui
|
||||
cd ui
|
||||
mkdir -p ~/.vmodules
|
||||
ln -s $(pwd) ~/.vmodules/ui
|
||||
../v examples/rectangles.v
|
||||
## ../v run examples/build_examples.vsh
|
||||
- name: V self compilation with -usecache
|
||||
run: |
|
||||
unset VFLAGS
|
||||
./v -usecache examples/hello_world.v && examples/hello_world
|
||||
./v -o v2 -usecache cmd/v
|
||||
./v2 -o v3 -usecache cmd/v
|
||||
./v3 version
|
||||
./v3 -o tetris -usecache examples/tetris/tetris.v
|
||||
|
||||
ubuntu:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 121
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --quiet -y postgresql libpq-dev libssl-dev sqlite3 libsqlite3-dev valgrind
|
||||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||
- name: Build V
|
||||
run: make -j4 && ./v -cc gcc -cg -cstrict -o v cmd/v
|
||||
- name: Valgrind v.c
|
||||
run: valgrind --error-exitcode=1 ./v -o v.c cmd/v
|
||||
- name: Run sanitizers
|
||||
run: |
|
||||
./v -o v2 cmd/v -cflags -fsanitize=thread
|
||||
./v -o v3 cmd/v -cflags "-fsanitize=undefined -fno-sanitize=alignment"
|
||||
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./v2 -o v.c cmd/v
|
||||
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./v3 -o v.c cmd/v
|
||||
# - name: Test V
|
||||
# run: ./v test-all
|
||||
# - name: Test v binaries
|
||||
# run: ./v build-vbinaries
|
||||
## - name: Test v->js
|
||||
## run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
||||
# - name: Build Vorum
|
||||
# run: git clone --depth 1 https://github.com/vlang/vorum && cd vorum && ../v . && cd ..
|
||||
- name: Build vpm
|
||||
run: git clone --depth 1 https://github.com/vlang/vpm && cd vpm && ../v . && cd ..
|
||||
- name: Freestanding
|
||||
run: ./v -freestanding run vlib/os/bare/bare_example_linux.v
|
||||
- name: V self compilation
|
||||
run: ./v -o v2 cmd/v && ./v2 -o v3 cmd/v && ./v3 -o v4 cmd/v
|
||||
- name: V self compilation with -usecache
|
||||
run: |
|
||||
unset VFLAGS
|
||||
./v -usecache examples/hello_world.v && examples/hello_world
|
||||
./v -o v2 -usecache cmd/v
|
||||
./v2 -o v3 -usecache cmd/v
|
||||
./v3 version
|
||||
./v3 -o tetris -usecache examples/tetris/tetris.v
|
||||
- name: Verify `v test` works
|
||||
run: |
|
||||
echo $VFLAGS
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
- name: All code is formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests
|
||||
run: ./v test-self
|
||||
- name: Self tests (-prod)
|
||||
run: ./v -o vprod -prod cmd/v && ./vprod test-self
|
||||
- name: Self tests (-cstrict)
|
||||
run: VTEST_JUST_ESSENTIAL=1 V_CI_CSTRICT=1 ./v -cc gcc -cstrict test-self
|
||||
- name: Build examples
|
||||
run: ./v build-examples
|
||||
- name: Build tetris.v with -autofree
|
||||
run: ./v -autofree -experimental -o tetris examples/tetris/tetris.v
|
||||
- name: Build option_test.v with -autofree
|
||||
run: ./v -autofree vlib/v/tests/option_test.v
|
||||
- name: Build modules
|
||||
run: |
|
||||
./v build-module vlib/os
|
||||
./v build-module vlib/builtin
|
||||
./v build-module vlib/strconv
|
||||
./v build-module vlib/time
|
||||
./v build-module vlib/term
|
||||
./v build-module vlib/math
|
||||
./v build-module vlib/strings
|
||||
./v build-module vlib/v/token
|
||||
./v build-module vlib/v/ast
|
||||
./v build-module vlib/v/parser
|
||||
./v build-module vlib/v/gen/c
|
||||
./v build-module vlib/v/depgraph
|
||||
./v build-module vlib/os/cmdline
|
||||
- name: native machine code generation
|
||||
run: |
|
||||
exit
|
||||
./v -o vprod -prod cmd/v
|
||||
cd cmd/tools
|
||||
echo "Generating a 1m line V file..."
|
||||
../../vprod gen1m.v
|
||||
./gen1m > 1m.v
|
||||
echo "Building it..."
|
||||
../../vprod -backend native -o 1m 1m.v
|
||||
echo "Running it..."
|
||||
ls
|
||||
|
||||
# ./1m
|
||||
# run: echo "TODO" #cd examples/native && ../../v -native hello_world.v && ./hello_world
|
||||
# - name: Coveralls GitHub Action
|
||||
# uses: coverallsapp/github-action@v1.0.1
|
||||
# with:
|
||||
# github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
ubuntu-clang:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 121
|
||||
env:
|
||||
VFLAGS: -cc clang
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --quiet -y postgresql libpq-dev libssl-dev sqlite3 libsqlite3-dev valgrind
|
||||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||
sudo apt-get install --quiet -y clang
|
||||
- name: Build V
|
||||
run: make -j4 && ./v -cc clang -cg -cstrict -o v cmd/v
|
||||
- name: Valgrind
|
||||
run: valgrind --error-exitcode=1 ./v -o v.c cmd/v
|
||||
- name: Run sanitizers
|
||||
run: |
|
||||
./v -o v2 cmd/v -cflags -fsanitize=memory
|
||||
./v -o v3 cmd/v -cflags -fsanitize=thread
|
||||
./v -o v4 cmd/v -cflags -fsanitize=undefined
|
||||
./v -o v5 cmd/v -cflags -fsanitize=address,pointer-compare,pointer-subtract
|
||||
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./v2 -o v.c cmd/v
|
||||
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./v3 -o v.c cmd/v
|
||||
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./v4 -o v.c cmd/v
|
||||
ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./v5 -o v.c cmd/v
|
||||
- name: v self compilation
|
||||
run: ./v -o v2 cmd/v && ./v2 -o v3 cmd/v && ./v3 -o v4 cmd/v
|
||||
- name: v self compilation with -usecache
|
||||
run: |
|
||||
unset VFLAGS
|
||||
./v -usecache examples/hello_world.v && examples/hello_world
|
||||
./v -o v2 -usecache cmd/v
|
||||
./v2 -o v3 -usecache cmd/v
|
||||
./v3 version
|
||||
./v3 -o tetris -usecache examples/tetris/tetris.v
|
||||
- name: Verify `v test` works
|
||||
run: |
|
||||
echo $VFLAGS
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
- name: All code is formatted
|
||||
run: ./v test-cleancode
|
||||
|
||||
- name: Self tests
|
||||
run: ./v test-self
|
||||
- name: Self tests (vprod)
|
||||
run: |
|
||||
./v -o vprod -prod cmd/v
|
||||
./vprod test-self
|
||||
- name: Self tests (-cstrict)
|
||||
run: VTEST_JUST_ESSENTIAL=1 V_CI_CSTRICT=1 ./vprod -cstrict test-self
|
||||
|
||||
- name: Build examples
|
||||
run: ./v build-examples
|
||||
- name: Build examples with -autofree
|
||||
run: |
|
||||
./v -autofree -experimental -o tetris examples/tetris/tetris.v
|
||||
- name: Build modules
|
||||
run: |
|
||||
./v build-module vlib/os
|
||||
./v build-module vlib/builtin
|
||||
./v build-module vlib/strconv
|
||||
./v build-module vlib/time
|
||||
./v build-module vlib/term
|
||||
./v build-module vlib/math
|
||||
./v build-module vlib/strings
|
||||
./v build-module vlib/v/token
|
||||
./v build-module vlib/v/ast
|
||||
./v build-module vlib/v/parser
|
||||
./v build-module vlib/v/gen/c
|
||||
./v build-module vlib/v/depgraph
|
||||
./v build-module vlib/os/cmdline
|
||||
- name: native machine code generation
|
||||
run: |
|
||||
exit
|
||||
./v -o vprod -prod cmd/v
|
||||
cd cmd/tools
|
||||
echo "Generating a 1m line V file..."
|
||||
../../vprod gen1m.v
|
||||
./gen1m > 1m.v
|
||||
echo "Building it..."
|
||||
../../vprod -backend native -o 1m 1m.v
|
||||
echo "Running it..."
|
||||
ls
|
||||
|
||||
windows-gcc:
|
||||
runs-on: windows-2019
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 121
|
||||
env:
|
||||
VFLAGS: -cc gcc
|
||||
VERBOSE_MAKE: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
- name: Build
|
||||
run: |
|
||||
gcc --version
|
||||
.\make.bat -gcc
|
||||
- name: Test new v.c
|
||||
run: |
|
||||
.\v.exe -o v.c cmd/v
|
||||
gcc -Werror -municode -w v.c
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
.\v.exe setup-freetype
|
||||
.\.github\workflows\windows-install-sqlite.bat
|
||||
- name: v doctor
|
||||
run: |
|
||||
./v doctor
|
||||
- name: Verify `v test` works
|
||||
run: |
|
||||
echo $VFLAGS
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
- name: All code is formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests
|
||||
run: .\v.exe test-self
|
||||
# - name: Test
|
||||
# run: .\v.exe test-all
|
||||
- name: Test time functions in a timezone UTC-12
|
||||
run: |
|
||||
tzutil /s "Dateline Standard Time"
|
||||
./v test vlib/time/
|
||||
- name: Test time functions in a timezone UTC-3
|
||||
run: |
|
||||
tzutil /s "Greenland Standard Time"
|
||||
./v test vlib/time/
|
||||
- name: Test time functions in a timezone UTC+3
|
||||
run: |
|
||||
tzutil /s "Russian Standard Time"
|
||||
./v test vlib/time/
|
||||
- name: Test time functions in a timezone UTC+12
|
||||
run: |
|
||||
tzutil /s "New Zealand Standard Time"
|
||||
./v test vlib/time/
|
||||
- name: Test v->js
|
||||
run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
||||
- name: Test v binaries
|
||||
run: ./v build-vbinaries
|
||||
- name: Build examples
|
||||
run: ./v build-examples
|
||||
- name: v2 self compilation
|
||||
run: .\v.exe -o v2.exe cmd/v && .\v2.exe -o v3.exe cmd/v
|
||||
|
||||
windows-msvc:
|
||||
runs-on: windows-2019
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 121
|
||||
env:
|
||||
VFLAGS: -cc msvc
|
||||
VERBOSE_MAKE: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
- name: Build
|
||||
run: |
|
||||
echo %VFLAGS%
|
||||
echo $VFLAGS
|
||||
.\make.bat -msvc
|
||||
.\v.exe -cflags /WX self
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
.\v.exe setup-freetype
|
||||
.\.github\workflows\windows-install-sqlite.bat
|
||||
- name: v doctor
|
||||
run: |
|
||||
./v doctor
|
||||
- name: Verify `v test` works
|
||||
run: |
|
||||
echo $VFLAGS
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
### TODO: test-cleancode fails with msvc. Investigate why???
|
||||
## - name: All code is formatted
|
||||
## run: ./v test-cleancode
|
||||
- name: Self tests
|
||||
run: |
|
||||
./v -cg cmd\tools\vtest-self.v
|
||||
./v test-self
|
||||
# - name: Test
|
||||
# run: .\v.exe test-all
|
||||
- name: Test v->js
|
||||
run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
||||
- name: Test v binaries
|
||||
run: ./v build-vbinaries
|
||||
- name: Build examples
|
||||
run: ./v build-examples
|
||||
- name: v2 self compilation
|
||||
run: .\v.exe -o v2.exe cmd/v && .\v2.exe -o v3.exe cmd/v
|
||||
|
||||
windows-tcc:
|
||||
runs-on: windows-2019
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 121
|
||||
env:
|
||||
VFLAGS: -cc tcc -no-retry-compilation
|
||||
VJOBS: 1
|
||||
VTEST_SHOW_START: 1
|
||||
VERBOSE_MAKE: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
- name: Build with make.bat -tcc
|
||||
run: |
|
||||
.\make.bat -tcc
|
||||
- name: Test new v.c
|
||||
run: |
|
||||
.\v.exe -o v.c cmd/v
|
||||
.\thirdparty\tcc\tcc.exe -Werror -w -ladvapi32 -bt10 v.c
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
.\v.exe setup-freetype
|
||||
.\.github\workflows\windows-install-sqlite.bat
|
||||
- name: v doctor
|
||||
run: |
|
||||
./v doctor
|
||||
- name: Verify `v test` works
|
||||
run: |
|
||||
.\v.exe cmd/tools/test_if_v_test_system_works.v
|
||||
.\cmd\tools\test_if_v_test_system_works.exe
|
||||
- name: Verify `v vlib/v/gen/c/coutput_test.v` works
|
||||
run: |
|
||||
.\v.exe vlib/v/gen/c/coutput_test.v
|
||||
- name: Make sure running TCC64 instead of TCC32
|
||||
run: ./v test .github\workflows\make_sure_ci_run_with_64bit_compiler_test.v
|
||||
- name: Test ./v doc -v clipboard *BEFORE building tools*
|
||||
run: ./v doc -v clipboard
|
||||
- name: Test v build-tools
|
||||
run: ./v -W build-tools
|
||||
- name: All code is formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests
|
||||
run: ./v test-self
|
||||
- name: Test v->js
|
||||
run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
||||
- name: Test v binaries
|
||||
run: ./v build-vbinaries
|
||||
- name: Build examples
|
||||
run: ./v build-examples
|
||||
- name: v2 self compilation
|
||||
run: .\v.exe -o v2.exe cmd/v && .\v2.exe -o v3.exe cmd/v && .\v3.exe -o v4.exe cmd/v
|
||||
- name: v2 self compilation with -gc boehm
|
||||
run: .\v.exe -o v2.exe -gc boehm cmd/v && .\v2.exe -o v3.exe -gc boehm cmd/v && .\v3.exe -o v4.exe -gc boehm cmd/v
|
||||
|
||||
## ## tcc32
|
||||
## - name: Build with make.bat -tcc32
|
||||
## run: |
|
||||
## Remove-Item -Recurse -Force .\thirdparty\tcc
|
||||
## .\v.exe wipe-cache
|
||||
## .\make.bat -tcc32
|
||||
## - name: Test new v.c
|
||||
## run: .\v.exe -o v.c cmd/v && .\thirdparty\tcc\tcc.exe -Werror -g -w -ladvapi32 -bt10 v.c
|
||||
## - name: v doctor
|
||||
## run: ./v doctor
|
||||
##
|
||||
## - name: Verify `v test` works
|
||||
## run: |
|
||||
## .\v.exe cmd/tools/test_if_v_test_system_works.v
|
||||
## .\cmd\tools\test_if_v_test_system_works.exe
|
||||
##
|
||||
## - name: Verify `v vlib/v/gen/c/coutput_test.v` works
|
||||
## run: |
|
||||
## .\v.exe vlib/v/gen/c/coutput_test.v
|
||||
##
|
||||
## - name: Make sure running TCC32 instead of TCC64
|
||||
## run: ./v -stats .github\workflows\make_sure_ci_run_with_32bit_compiler_test.v
|
||||
##
|
||||
## - name: Test v build-tools
|
||||
## run: ./v -W build-tools
|
||||
##
|
||||
## - name: Test ./v doc clipboard
|
||||
## run: ./v doc clipboard
|
||||
##
|
||||
## - name: Self tests
|
||||
## run: ./v test-self
|
||||
## - name: Test v->js
|
||||
## run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
||||
## - name: Test v binaries
|
||||
## run: ./v build-vbinaries
|
||||
## - name: Build examples
|
||||
## run: ./v build-examples
|
||||
## - name: v2 self compilation
|
||||
## run: .\v.exe -o v2.exe cmd/v && .\v2.exe -o v3.exe cmd/v
|
||||
|
||||
|
||||
# ubuntu-autofree-selfcompile:
|
||||
# runs-on: ubuntu-20.04
|
||||
# if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
# timeout-minutes: 121
|
||||
# env:
|
||||
# VFLAGS: -cc gcc
|
||||
# steps:
|
||||
# - uses: actions/checkout@v2
|
||||
# - name: Build V
|
||||
# run: make -j4
|
||||
# - name: V self compilation with -autofree
|
||||
# run: ./v -o v2 -autofree cmd/v && ./v2 -o v3 -autofree cmd/v && ./v3 -o v4 -autofree cmd/v
|
||||
|
||||
|
||||
# ubuntu-musl:
|
||||
# runs-on: ubuntu-20.04
|
||||
# if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
# timeout-minutes: 121
|
||||
# env:
|
||||
# VFLAGS: -cc musl-gcc
|
||||
# V_CI_MUSL: 1
|
||||
# steps:
|
||||
# - uses: actions/checkout@v2
|
||||
# - uses: actions/setup-node@v1
|
||||
# with:
|
||||
# node-version: 12.x
|
||||
# - name: Install dependencies
|
||||
# run: |
|
||||
# sudo apt-get install --quiet -y musl musl-tools libssl-dev sqlite3 libsqlite3-dev valgrind
|
||||
# - name: Build v
|
||||
# run: echo $VFLAGS && make -j4 && ./v -cg -o v cmd/v
|
||||
# # - name: Test v binaries
|
||||
# # run: ./v build-vbinaries
|
||||
# ## - name: Test v->js
|
||||
# ## run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
||||
# - name: quick debug
|
||||
# run: ./v -stats vlib/strconv/format_test.v
|
||||
# - name: Self tests
|
||||
# run: ./v test-self
|
|
@ -0,0 +1,79 @@
|
|||
name: Bootstraping works
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
jobs:
|
||||
ubuntu:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
VFLAGS: -cc tcc -no-retry-compilation
|
||||
B_CFLAGS: -g -std=gnu11 -w
|
||||
B_LFLAGS: -lm -lpthread
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Build v
|
||||
run: make
|
||||
|
||||
- name: v.c can be compiled and run with -os cross (bootstrapping works)
|
||||
run: |
|
||||
ls -la v vc/v.c
|
||||
./v -os cross -o vc/v.c cmd/v
|
||||
gcc $B_CFLAGS -o v_from_vc vc/v.c $B_LFLAGS
|
||||
ls -lart v_from_vc
|
||||
./v_from_vc version
|
||||
./v_from_vc run examples/hello_world.v
|
||||
./v_from_vc -o v_from_vc_produced_native_v cmd/v
|
||||
./v_from_vc_produced_native_v run examples/hello_world.v
|
||||
make local=1
|
||||
ls -la v vc/v.c v_from_vc v_from_vc_produced_native_v
|
||||
|
||||
- name: Ensure v up works
|
||||
run: |
|
||||
./v cmd/tools/oldv.v
|
||||
./cmd/tools/oldv -v HEAD^^^^^
|
||||
cd ~/.cache/oldv/v_at_HEAD_____/
|
||||
./v version
|
||||
./v -v up
|
||||
./v version
|
||||
./v -o v2 cmd/v
|
||||
./v2 -o v3 cmd/v
|
||||
|
||||
macos:
|
||||
runs-on: macos-11
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
VFLAGS: -cc clang
|
||||
B_CFLAGS: -g -std=gnu11 -w
|
||||
B_LFLAGS: -lm -lpthread
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Build V
|
||||
run: make && ./v -cg -cstrict -o v cmd/v
|
||||
|
||||
- name: v.c can be compiled and run with -os cross (bootstrapping works)
|
||||
run: |
|
||||
ls -la v vc/v.c
|
||||
./v -os cross -o vc/v.c cmd/v
|
||||
cc $B_CFLAGS -o v_from_vc vc/v.c $B_LFLAGS
|
||||
ls -lart v_from_vc
|
||||
./v_from_vc version
|
||||
./v_from_vc run examples/hello_world.v
|
||||
./v_from_vc -o v_from_vc_produced_native_v cmd/v
|
||||
./v_from_vc_produced_native_v run examples/hello_world.v
|
||||
### the next make invocation will simulate building V from scratch,
|
||||
### using this commit
|
||||
make local=1
|
||||
ls -la v vc/v.c v_from_vc v_from_vc_produced_native_v
|
|
@ -0,0 +1,111 @@
|
|||
name: Cross CI
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
jobs:
|
||||
|
||||
macos-cross:
|
||||
runs-on: macOS-latest
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 25
|
||||
env:
|
||||
VFLAGS: -cc clang
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 10
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
brew install mingw-w64
|
||||
export LIBRARY_PATH="$LIBRARY_PATH:/usr/local/opt/openssl/lib/"
|
||||
|
||||
- name: Build V
|
||||
run: make
|
||||
|
||||
- name: Test symlink
|
||||
run: ./v symlink
|
||||
|
||||
- name: Cross-compilation to Linux
|
||||
run: |
|
||||
./v -os linux cmd/v
|
||||
# TODO: fix this: ./v -os linux examples/2048/2048.v
|
||||
|
||||
- name: Cross-compilation to Windows
|
||||
run: |
|
||||
./v -os windows cmd/v
|
||||
./v -os windows examples/2048/2048.v
|
||||
|
||||
linux-cross:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 25
|
||||
env:
|
||||
VFLAGS: -cc tcc -no-retry-compilation
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
## sudo dpkg --add-architecture i386
|
||||
sudo apt update
|
||||
sudo apt-get install --quiet -y libssl-dev sqlite3 libsqlite3-dev
|
||||
sudo apt-get install --quiet -y mingw-w64 wine-stable winetricks
|
||||
## sudo apt-get install --quiet -y wine32
|
||||
|
||||
- name: Turn off the wine crash dialog
|
||||
run: winetricks nocrashdialog
|
||||
|
||||
- name: Build v
|
||||
run: make
|
||||
|
||||
- name: v.c can be compiled and run with -os cross
|
||||
run: |
|
||||
./v -os cross -o /tmp/v.c cmd/v
|
||||
gcc -g -std=gnu11 -w -o v_from_vc /tmp/v.c -lm -lpthread
|
||||
ls -lart v_from_vc
|
||||
./v_from_vc version
|
||||
|
||||
- name: v_win.c can be compiled and run with -os windows
|
||||
run: |
|
||||
./v -cc msvc -os windows -o /tmp/v_win.c cmd/v
|
||||
x86_64-w64-mingw32-gcc /tmp/v_win.c -std=c99 -w -municode -o v_from_vc.exe
|
||||
ls -lart v_from_vc.exe
|
||||
wine64 ./v_from_vc.exe version
|
||||
|
||||
- name: hello_world.v can be cross compiled to hello_world.exe
|
||||
run: |
|
||||
./v -os windows examples/hello_world.v
|
||||
ls -lart examples/hello_world.exe
|
||||
wine64 examples/hello_world.exe
|
||||
|
||||
- name: 2048.v can be cross compiled to 2048.exe
|
||||
run: |
|
||||
./v -os windows examples/2048/2048.v
|
||||
ls -lart examples/2048/2048.exe
|
||||
|
||||
windows-cross:
|
||||
runs-on: windows-2019
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 25
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: |
|
||||
echo %VFLAGS%
|
||||
echo $VFLAGS
|
||||
.\make.bat -msvc
|
||||
- name: TODO v_win.c can be compiled and run with -os windows
|
||||
run: |
|
||||
.\v.exe -os windows -cc msvc -showcc -o v2.exe cmd\v
|
||||
.\v.exe -os windows -cc msvc -o v_win.c cmd\v
|
||||
dir v2.exe
|
||||
dir v_win.c
|
||||
.\v2.exe version
|
|
@ -0,0 +1,256 @@
|
|||
name: Sanitized CI
|
||||
|
||||
## Running these jobs is slow (over ~1 hour, sometimes even 2)
|
||||
## so we run them only when there is a chance that the generated
|
||||
## C code could have changed, or for some critical vlib modules,
|
||||
## like `builtin`, `os`, `sync`, where they have demonstrated
|
||||
## their usefulness by catching actual very hard to find bugs.
|
||||
## The cost of this selective running is delayed feedback when
|
||||
## there are bugs in other V modules.
|
||||
## The positive is *much faster CI runs* for most V contributors,
|
||||
## that make PRs that are not concerning V itself, or the critical
|
||||
## V modules.
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '!**'
|
||||
- 'cmd/tools/vtest*'
|
||||
- 'cmd/tools/builders/**.v'
|
||||
- 'vlib/builtin/**.v'
|
||||
- 'vlib/strconv/**.v'
|
||||
- 'vlib/strings/**.v'
|
||||
- 'vlib/math/**.v'
|
||||
- 'vlib/math/big/**.v'
|
||||
- 'vlib/arrays/**.v'
|
||||
- 'vlib/datatypes/**.v'
|
||||
- 'vlib/os/**.v'
|
||||
- 'vlib/sync/**.v'
|
||||
- 'vlib/v/tests/**.v'
|
||||
- 'vlib/v/ast/**.v'
|
||||
- 'vlib/v/scanner/**.v'
|
||||
- 'vlib/v/parser/**.v'
|
||||
- 'vlib/v/checker/**.v'
|
||||
- 'vlib/v/gen/c/**.v'
|
||||
- 'vlib/v/builder/**.v'
|
||||
- 'vlib/v/cflag/**.v'
|
||||
- 'vlib/v/live/**.v'
|
||||
- 'vlib/v/util/**.v'
|
||||
- 'vlib/v/markused/**.v'
|
||||
- 'vlib/v/preludes/**.v'
|
||||
- 'vlib/v/embed_file/**.v'
|
||||
pull_request:
|
||||
paths:
|
||||
- '!**'
|
||||
- 'cmd/tools/vtest*'
|
||||
- 'cmd/tools/builders/**.v'
|
||||
- 'vlib/builtin/**.v'
|
||||
- 'vlib/strconv/**.v'
|
||||
- 'vlib/strings/**.v'
|
||||
- 'vlib/math/**.v'
|
||||
- 'vlib/math/big/**.v'
|
||||
- 'vlib/arrays/**.v'
|
||||
- 'vlib/datatypes/**.v'
|
||||
- 'vlib/os/**.v'
|
||||
- 'vlib/sync/**.v'
|
||||
- 'vlib/v/tests/**.v'
|
||||
- 'vlib/v/ast/**.v'
|
||||
- 'vlib/v/scanner/**.v'
|
||||
- 'vlib/v/parser/**.v'
|
||||
- 'vlib/v/checker/**.v'
|
||||
- 'vlib/v/gen/c/**.v'
|
||||
- 'vlib/v/builder/**.v'
|
||||
- 'vlib/v/cflag/**.v'
|
||||
- 'vlib/v/live/**.v'
|
||||
- 'vlib/v/util/**.v'
|
||||
- 'vlib/v/markused/**.v'
|
||||
- 'vlib/v/preludes/**.v'
|
||||
- 'vlib/v/embed_file/**.v'
|
||||
|
||||
concurrency:
|
||||
group: build-sanitized-${{ github.event.pull_request.number || github.sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
tests-sanitize-undefined-clang:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 180
|
||||
env:
|
||||
VFLAGS: -cc clang
|
||||
VJOBS: 1
|
||||
VTEST_SHOW_START: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --quiet -y postgresql libpq-dev libssl-dev sqlite3 libsqlite3-dev valgrind
|
||||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||
sudo apt-get install clang
|
||||
- name: Build V
|
||||
run: make && ./v -cg -cstrict -o v cmd/v
|
||||
- name: Ensure code is well formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests (-fsanitize=undefined)
|
||||
run: ./v -cflags "-fsanitize=undefined" -o v2 cmd/v && ./v2 -cflags -fsanitize=undefined test-self
|
||||
- name: Build examples (V compiled with -fsanitize=undefined)
|
||||
run: ./v2 build-examples
|
||||
|
||||
tests-sanitize-undefined-gcc:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 180
|
||||
env:
|
||||
VFLAGS: -cc gcc
|
||||
VJOBS: 1
|
||||
VTEST_SHOW_START: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt-get install --quiet -y postgresql libpq-dev libssl-dev sqlite3 libsqlite3-dev valgrind
|
||||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||
- name: Build V
|
||||
run: make && ./v -cg -cstrict -o v cmd/v
|
||||
- name: Ensure code is well formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests (-fsanitize=undefined)
|
||||
run: ./v -cflags "-fsanitize=undefined" -o v2 cmd/v && ./v2 -cflags -fsanitize=undefined test-self
|
||||
- name: Build examples (V compiled with -fsanitize=undefined)
|
||||
run: ./v2 build-examples
|
||||
|
||||
tests-sanitize-address-clang:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 180
|
||||
env:
|
||||
VFLAGS: -cc clang
|
||||
VJOBS: 1
|
||||
VTEST_SHOW_START: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt-get install --quiet -y postgresql libpq-dev libssl-dev sqlite3 libsqlite3-dev valgrind
|
||||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||
sudo apt-get install clang
|
||||
- name: Build V
|
||||
run: make && ./v -cg -cstrict -o v cmd/v
|
||||
- name: Ensure code is well formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests (-fsanitize=address)
|
||||
run: ASAN_OPTIONS=detect_leaks=0 ./v -cflags "-fsanitize=address,pointer-compare,pointer-subtract" test-self
|
||||
- name: Self tests (V compiled with -fsanitize=address)
|
||||
run:
|
||||
./v -cflags -fsanitize=address -o v cmd/v &&
|
||||
ASAN_OPTIONS=detect_leaks=0 ./v -cc tcc test-self -asan-compiler
|
||||
- name: Build examples (V compiled with -fsanitize=address)
|
||||
run: ASAN_OPTIONS=detect_leaks=0 ./v build-examples
|
||||
|
||||
tests-sanitize-address-msvc:
|
||||
runs-on: windows-2019
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 180
|
||||
env:
|
||||
VFLAGS: -cc msvc
|
||||
VJOBS: 1
|
||||
VTEST_SHOW_START: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
- name: Build
|
||||
run: |
|
||||
echo %VFLAGS%
|
||||
echo $VFLAGS
|
||||
.\make.bat -msvc
|
||||
.\v.exe self
|
||||
- name: Ensure code is well formatted
|
||||
run: |
|
||||
.\v.exe fmt -verify vlib/builtin/ vlib/v/scanner/ vlib/v/parser/ vlib/v/gen/
|
||||
## TODO: check to see why `v test-cleancode` does not work with msvc on windows
|
||||
|
||||
## - name: Install dependencies
|
||||
## run: |
|
||||
## .\v.exe setup-freetype
|
||||
## .\.github\workflows\windows-install-sqlite.bat
|
||||
## - name: Self tests (TODO: /fsanitize=address)
|
||||
## run: |
|
||||
## .\v.exe -cflags "/fsanitize=address" test-self
|
||||
|
||||
tests-sanitize-address-gcc:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 180
|
||||
env:
|
||||
VFLAGS: -cc gcc
|
||||
VJOBS: 1
|
||||
VTEST_SHOW_START: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt-get install --quiet -y postgresql libpq-dev libssl-dev sqlite3 libsqlite3-dev valgrind
|
||||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||
sudo apt-get install clang
|
||||
- name: Build V
|
||||
run: make && ./v -cg -cstrict -o v cmd/v
|
||||
- name: Ensure code is well formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests (-fsanitize=address)
|
||||
run: ASAN_OPTIONS=detect_leaks=0 ./v -cflags -fsanitize=address test-self
|
||||
- name: Self tests (V compiled with -fsanitize=address)
|
||||
run:
|
||||
./v -cflags -fsanitize=address,pointer-compare,pointer-subtract -o v cmd/v &&
|
||||
ASAN_OPTIONS=detect_leaks=0 ./v -cc tcc test-self -asan-compiler
|
||||
- name: Build examples (V compiled with -fsanitize=address)
|
||||
run: ASAN_OPTIONS=detect_leaks=0 ./v build-examples
|
||||
|
||||
tests-sanitize-memory-clang:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 180
|
||||
env:
|
||||
VFLAGS: -cc clang -gc none
|
||||
VJOBS: 1
|
||||
VTEST_SHOW_START: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt-get install --quiet -y postgresql libpq-dev libssl-dev sqlite3 libsqlite3-dev valgrind
|
||||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||
sudo apt-get install clang
|
||||
- name: Build V
|
||||
run: make && ./v -cc clang -cg -cstrict -o v cmd/v
|
||||
- name: Ensure code is well formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests (-fsanitize=memory)
|
||||
run: ./v -cflags -fsanitize=memory test-self
|
||||
- name: Self tests (V compiled with -fsanitize=memory)
|
||||
run: |
|
||||
./v -cflags -fsanitize=memory -o v cmd/v
|
||||
./v -cc tcc test-self -msan-compiler
|
||||
- name: Build examples (V compiled with -fsanitize=memory)
|
||||
run: ./v build-examples
|
|
@ -0,0 +1,36 @@
|
|||
name: vlang benchmarks
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
jobs:
|
||||
run:
|
||||
name: Run
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Install google benchmark
|
||||
run: |
|
||||
git clone https://github.com/google/benchmark.git
|
||||
cd benchmark
|
||||
cmake -E make_directory "build"
|
||||
cmake -E chdir "build" cmake -DBENCHMARK_DOWNLOAD_DEPENDENCIES=on -DCMAKE_BUILD_TYPE=Release ../
|
||||
sudo cmake --build "build" --config Release --target install
|
||||
- name: Run V benchmark
|
||||
run: |
|
||||
make
|
||||
sudo ./v symlink
|
||||
git clone https://github.com/vincenzopalazzo/benchmarks.git
|
||||
cd benchmarks
|
||||
make vdep && make v
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: vlang-benchmark
|
||||
path: benchmarks/vlang/*.json
|
|
@ -0,0 +1,82 @@
|
|||
name: Containers CI
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
concurrency:
|
||||
group: build-containers-${{ github.event.pull_request.number || github.sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
|
||||
alpine-docker-musl-gcc:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 181
|
||||
container:
|
||||
# Alpine docker pre-built container
|
||||
image: thevlang/vlang:alpine-build
|
||||
env:
|
||||
V_CI_MUSL: 1
|
||||
VFLAGS: -cc gcc
|
||||
volumes:
|
||||
- ${{github.workspace}}:/opt/vlang
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Show Environment
|
||||
run: |
|
||||
echo "PWD:"
|
||||
pwd
|
||||
echo "ENVIRONMENT:"
|
||||
env
|
||||
echo "C Compiler:"
|
||||
gcc --version
|
||||
|
||||
- name: Build V
|
||||
run: CC=gcc make
|
||||
|
||||
- name: All code is formatted
|
||||
run: ./v test-cleancode
|
||||
|
||||
- name: Run only essential tests
|
||||
run: VTEST_JUST_ESSENTIAL=1 ./v test-self
|
||||
|
||||
ubuntu-docker-musl:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 121
|
||||
container:
|
||||
image: thevlang/vlang:ubuntu-build
|
||||
env:
|
||||
V_CI_MUSL: 1
|
||||
V_CI_UBUNTU_MUSL: 1
|
||||
VFLAGS: -cc musl-gcc -gc none
|
||||
volumes:
|
||||
- ${{github.workspace}}:/opt/vlang
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Build V
|
||||
run: |
|
||||
echo $VFLAGS && make -j4 && ./v -cg -o v cmd/v
|
||||
- name: Verify `v test` works
|
||||
run: |
|
||||
echo $VFLAGS
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
|
||||
- name: All code is formatted
|
||||
run: ./v test-cleancode
|
||||
|
||||
- name: Test V fixed tests
|
||||
run: ./v test-self
|
|
@ -0,0 +1,46 @@
|
|||
name: Debug CI
|
||||
|
||||
on: [workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
|
||||
debug-msvc:
|
||||
runs-on: windows-2019
|
||||
timeout-minutes: 121
|
||||
env:
|
||||
VFLAGS: -cc msvc
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
- name: Build
|
||||
run: |
|
||||
echo %VFLAGS%
|
||||
echo $VFLAGS
|
||||
.\make.bat -msvc
|
||||
.\v.exe -cflags /WX self
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
.\v.exe setup-freetype
|
||||
.\.github\workflows\windows-install-sqlite.bat
|
||||
- name: v doctor
|
||||
run: ./v doctor
|
||||
- name: Verify `v test` works
|
||||
run: |
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
- name: All code is formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests
|
||||
run: |
|
||||
./v -cg cmd\tools\vtest-self.v
|
||||
./v test-self
|
||||
- name: Test v->js
|
||||
run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
||||
- name: Test v binaries
|
||||
run: ./v build-vbinaries
|
||||
- name: Build examples
|
||||
run: ./v build-examples
|
||||
- name: v2 self compilation
|
||||
run: .\v.exe -o v2.exe cmd/v && .\v2.exe -o v3.exe cmd/v
|
|
@ -0,0 +1,38 @@
|
|||
name: Docs CI
|
||||
|
||||
### Run on *EVERY* commit. The documentation *SHOULD* stay valid, and
|
||||
### the developers should receive early warning if they break it.
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
check-markdown:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build V
|
||||
run: make
|
||||
- name: Check markdown line length & code examples
|
||||
run: ./v check-md -hide-warnings .
|
||||
## NB: -hide-warnings is used here, so that the output is less noisy,
|
||||
## thus real errors are easier to spot.
|
||||
|
||||
report-missing-fn-doc:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 5
|
||||
env:
|
||||
MOPTIONS: --relative-paths --exclude /vlib/v/ --exclude /builtin/linux_bare/ --exclude /testdata/ --exclude /tests/
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build V
|
||||
run: make
|
||||
|
||||
- name: Checkout previous v
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: vlang/v
|
||||
path: pv
|
||||
|
||||
- name: Check against parent commit
|
||||
run: |
|
||||
./v missdoc --diff $MOPTIONS pv/vlib vlib
|
|
@ -0,0 +1,33 @@
|
|||
#!/usr/local/bin/bash
|
||||
|
||||
## should be run in V's main repo folder!
|
||||
|
||||
rm -rf tinycc/
|
||||
rm -rf thirdparty/tcc/
|
||||
|
||||
pushd .
|
||||
|
||||
git clone git://repo.or.cz/tinycc.git
|
||||
cd tinycc
|
||||
|
||||
export CC=clang
|
||||
|
||||
./configure \
|
||||
--cc=clang \
|
||||
--prefix=thirdparty/tcc \
|
||||
--bindir=thirdparty/tcc \
|
||||
--crtprefix=thirdparty/tcc/lib:/usr/lib \
|
||||
--libpaths=thirdparty/tcc/lib:/usr/lib:/lib:/usr/local/lib \
|
||||
--debug
|
||||
gmake
|
||||
gmake install
|
||||
|
||||
popd
|
||||
|
||||
mv tinycc/thirdparty/tcc thirdparty/tcc
|
||||
mv thirdparty/tcc/tcc thirdparty/tcc/tcc.exe
|
||||
|
||||
sudo ln -s $(pwd)/thirdparty/tcc/tcc.exe /usr/local/bin/tcc
|
||||
|
||||
thirdparty/tcc/tcc.exe -v -v
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
name: VC gen
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
jobs:
|
||||
build-vc:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
env:
|
||||
VREPO: github.com/vlang/vc.git
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build V
|
||||
run: make
|
||||
- name: Regenerate v.c and v_win.c
|
||||
run: |
|
||||
git config --global user.email "vlang-bot@users.noreply.github.com"
|
||||
git config --global user.name "vlang-bot"
|
||||
|
||||
COMMIT_HASH=$(git rev-parse --short HEAD)
|
||||
COMMIT_MSG=$(git log -1 --oneline --pretty='%s' HEAD)
|
||||
|
||||
rm -rf vc
|
||||
git clone --depth=1 \
|
||||
https://vlang-bot:${{ secrets.VLANG_BOT_SECRET }}@$VREPO
|
||||
|
||||
rm -rf vc/v.c vc/v_win.c
|
||||
|
||||
./v -o vc/v.c -os cross cmd/v
|
||||
./v -o vc/v_win.c -os windows -cc msvc cmd/v
|
||||
|
||||
sed -i "1s/^/#define V_COMMIT_HASH \"$COMMIT_HASH\"\n/" vc/v.c
|
||||
sed -i "1s/^/#define V_COMMIT_HASH \"$COMMIT_HASH\"\n/" vc/v_win.c
|
||||
|
||||
# ensure the C files are over 5000 lines long, as a safety measure
|
||||
[ $(wc -l < vc/v.c) -gt 5000 ]
|
||||
[ $(wc -l < vc/v_win.c) -gt 5000 ]
|
||||
|
||||
git -C vc add v.c v_win.c
|
||||
git -C vc commit -m "[v:master] $COMMIT_HASH - $COMMIT_MSG"
|
||||
|
||||
# in case there are recent commits:
|
||||
git -C vc pull --rebase origin master
|
||||
git -C vc push
|
|
@ -0,0 +1,54 @@
|
|||
name: Graphics CI
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
jobs:
|
||||
gg-regressions:
|
||||
runs-on: ubuntu-18.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
VFLAGS: -cc tcc
|
||||
DISPLAY: :99
|
||||
steps:
|
||||
- name: Checkout V
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Build local v
|
||||
run: make
|
||||
|
||||
- uses: openrndr/setup-opengl@v1.1
|
||||
|
||||
- name: Setup dependencies
|
||||
run: |
|
||||
# imagemagick : convert, mogrify
|
||||
# xvfb : xvfb (installed by openrndr/setup-opengl@v1.1)
|
||||
# openimageio-tools : idiff
|
||||
# libxcursor-dev libxi-dev : V gfx deps
|
||||
# mesa-common-dev : For headless rendering
|
||||
# freeglut3-dev : Fixes graphic apps compilation with tcc
|
||||
sudo apt-get update
|
||||
sudo apt-get install imagemagick openimageio-tools mesa-common-dev libxcursor-dev libxi-dev freeglut3-dev
|
||||
wget https://raw.githubusercontent.com/tremby/imgur.sh/c98345d/imgur.sh
|
||||
git clone https://github.com/Larpon/gg-regression-images gg-regression-images
|
||||
chmod +x ./imgur.sh
|
||||
|
||||
- name: Sample and compare
|
||||
id: compare
|
||||
continue-on-error: true
|
||||
run: |
|
||||
Xvfb $DISPLAY -screen 0 1280x1024x24 &
|
||||
./v gret -t ./gg-regression-images/vgret.v_examples.toml -v ./gg-sample_images ./gg-regression-images
|
||||
|
||||
- name: Upload regression to imgur
|
||||
if: steps.compare.outcome != 'success'
|
||||
run: |
|
||||
./imgur.sh /tmp/fail.png
|
||||
./imgur.sh /tmp/diff.png
|
||||
exit 1
|
|
@ -0,0 +1,5 @@
|
|||
fn test_ci_run_with_32bit_compiler() {
|
||||
$if x64 {
|
||||
assert false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
fn test_ci_run_with_64bit_compiler() {
|
||||
$if x32 {
|
||||
assert false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
name: vlib modules CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build-module-docs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build V
|
||||
run: make
|
||||
- name: Build module documentation
|
||||
run: ./v doc -m -f html vlib/
|
||||
- name: Deploy docs to vercel
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
run: npx vercel --confirm --prod --name vmodules --token ${{ secrets.VERCEL_TOKEN }} vlib/_docs/ || true
|
|
@ -0,0 +1,36 @@
|
|||
name: native backend CI
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
concurrency:
|
||||
group: native-backend-ci-${{ github.event.pull_request.number || github.sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
native-backend:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-18.04, ubuntu-20.04, macos-10.15, macos-11, macos-12, windows-2016, windows-2019, windows-2022]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Build V with make.bat
|
||||
if: ${{ startsWith(matrix.os, 'windows') }}
|
||||
run: |
|
||||
.\make.bat
|
||||
.\v.exe symlink -githubci
|
||||
- name: Build V with make
|
||||
if: ${{ !startsWith(matrix.os, 'windows') }}
|
||||
run: |
|
||||
make
|
||||
./v symlink -githubci
|
||||
|
||||
- name: Test the native backend
|
||||
run: v test vlib/v/gen/native/
|
|
@ -0,0 +1,153 @@
|
|||
name: Other CI
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
concurrency:
|
||||
group: build-other-${{ github.event.pull_request.number || github.sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
no-gpl-by-accident:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: No GPL licensed code, should be added accidentally
|
||||
run: |
|
||||
! grep -r --exclude="*.yml" "a GPL license" .
|
||||
|
||||
code-formatting:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 15
|
||||
env:
|
||||
VFLAGS: -cc gcc
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Environment info
|
||||
run: echo $VFLAGS $GITHUB_SHA $GITHUB_REF
|
||||
- name: Build local v
|
||||
run: make -j4
|
||||
- name: v test-cleancode
|
||||
run: ./v test-cleancode
|
||||
- name: v test-fmt
|
||||
run: ./v test-fmt
|
||||
|
||||
performance-regressions:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 15
|
||||
env:
|
||||
VFLAGS: -cc gcc
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Environment info
|
||||
run: echo $VFLAGS $GITHUB_SHA $GITHUB_REF
|
||||
- name: Build local v
|
||||
run: make -j4
|
||||
- name: Clone & Build previous vmaster/v
|
||||
run: |
|
||||
git clone --depth=1 https://github.com/vlang/v vmaster/
|
||||
(cd vmaster; make -j4)
|
||||
- name: V versions
|
||||
run: ./v version && ./vmaster/v version
|
||||
- name: Build the repeat tool
|
||||
run: ./v cmd/tools/repeat.v
|
||||
- name: Repeat -o hw.c examples/hello_world.v
|
||||
run: cmd/tools/repeat --max_time 251 --series 3 --count 20 --nmins 2 --nmaxs 5 --warmup 3 --fail_percent 10 -t 'cd {T} ; ./v -show-timings -o hw.c examples/hello_world.v' . ./vmaster
|
||||
- name: Repeat -o v.c cmd/v
|
||||
run: cmd/tools/repeat --max_time 1501 --series 3 --count 20 --nmins 2 --nmaxs 5 --warmup 3 --fail_percent 10 -t 'cd {T} ; ./v -show-timings -o v.c cmd/v' . ./vmaster
|
||||
|
||||
misc-tooling:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 121
|
||||
env:
|
||||
VFLAGS: -cc tcc -no-retry-compilation
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 10
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --quiet -y libsodium-dev libssl-dev sqlite3 libsqlite3-dev postgresql libpq-dev valgrind
|
||||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev xfonts-75dpi xfonts-base
|
||||
sudo apt-get install --quiet -y g++-9
|
||||
|
||||
- name: Build v
|
||||
run: make
|
||||
|
||||
- name: g++ version
|
||||
run: g++-9 --version
|
||||
- name: V self compilation with g++
|
||||
run: ./v -cc g++-9 -no-std -cflags -std=c++11 -o v2 cmd/v && ./v2 -cc g++-9 -no-std -cflags -std=c++11 -o v3 cmd/v
|
||||
## - name: Running tests with g++
|
||||
## run: ./v -cc g++-9 test-self
|
||||
|
||||
- name: Ensure V can be compiled with -autofree
|
||||
run: ./v -autofree -o v2 cmd/v ## NB: this does not mean it runs, but at least keeps it from regressing
|
||||
|
||||
- name: Shader examples can be build
|
||||
run: |
|
||||
wget https://github.com/floooh/sokol-tools-bin/raw/33d2e4cc26088c6c28eaef5467990f8940d15aab/bin/linux/sokol-shdc
|
||||
chmod +x ./sokol-shdc
|
||||
for f in examples/sokol/02_cubes_glsl/cube_glsl \
|
||||
examples/sokol/03_march_tracing_glsl/rt_glsl \
|
||||
examples/sokol/04_multi_shader_glsl/rt_glsl_puppy \
|
||||
examples/sokol/04_multi_shader_glsl/rt_glsl_march \
|
||||
examples/sokol/05_instancing_glsl/rt_glsl_instancing \
|
||||
examples/sokol/06_obj_viewer/gouraud \
|
||||
; do \
|
||||
echo "compiling shader $f.glsl ..."; \
|
||||
./sokol-shdc --input $f.glsl --output $f.h --slang glsl330 ; \
|
||||
done
|
||||
./v should-compile-all examples/sokol/*.v examples/sokol/0?*/*.v
|
||||
|
||||
parser-silent:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 121
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install zzuf
|
||||
run: sudo apt install -qq zzuf
|
||||
- name: Build local v
|
||||
run: |
|
||||
make -j4
|
||||
./v -g cmd/tools/vtest-parser.v
|
||||
- name: Run test-parser
|
||||
run: |
|
||||
./v test-parser -S examples/hello_world.v
|
||||
./v test-parser -S examples/hanoi.v
|
||||
./v test-parser -S examples/fibonacci.v
|
||||
./v test-parser -S examples/cli.v
|
||||
./v test-parser -S examples/json.v
|
||||
./v test-parser -S examples/vmod.v
|
||||
./v test-parser -S examples/regex/regex_example.v
|
||||
./v test-parser -S examples/2048/2048.v
|
||||
|
||||
- name: Run test-parser over fuzzed files
|
||||
run: |
|
||||
zzuf -R '\x00-\x20\x7f-\xff' -r0.01 < examples/hello_world.v > examples/hello_world_fuzz.v
|
||||
zzuf -R '\x00-\x20\x7f-\xff' -r0.01 < examples/hanoi.v > examples/hanoi_fuzz.v
|
||||
zzuf -R '\x00-\x20\x7f-\xff' -r0.01 < examples/fibonacci.v > examples/fibonacci_fuzz.v
|
||||
zzuf -R '\x00-\x20\x7f-\xff' -r0.01 < examples/cli.v > examples/cli_fuzz.v
|
||||
zzuf -R '\x00-\x20\x7f-\xff' -r0.01 < examples/json.v > examples/json_fuzz.v
|
||||
zzuf -R '\x00-\x20\x7f-\xff' -r0.01 < examples/vmod.v > examples/vmod_fuzz.v
|
||||
zzuf -R '\x00-\x20\x7f-\xff' -r0.01 < examples/regex/regex_example.v > examples/regex_example_fuzz.v
|
||||
zzuf -R '\x00-\x20\x7f-\xff' -r0.01 < examples/2048/2048.v > examples/2048/2048_fuzz.v
|
||||
./v test-parser -S examples/hello_world_fuzz.v
|
||||
./v test-parser -S examples/hanoi_fuzz.v
|
||||
./v test-parser -S examples/cli_fuzz.v
|
||||
./v test-parser -S examples/regex_example_fuzz.v
|
||||
./v test-parser -S examples/2048/2048_fuzz.v
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
name: Path Testing CI
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
concurrency:
|
||||
group: build-paths-${{ github.event.pull_request.number || github.sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
|
||||
space-paths-linux:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
MY_V_PATH: '你好 my $path, @с интервали'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
path: ${{env.MY_V_PATH}}
|
||||
- name: Build V
|
||||
run: |
|
||||
echo '${{env.MY_V_PATH}}'
|
||||
ls -la
|
||||
cd '${{env.MY_V_PATH}}'
|
||||
ls -la
|
||||
make
|
||||
- name: v doctor
|
||||
run: |
|
||||
cd '${{env.MY_V_PATH}}'
|
||||
./v doctor
|
||||
- name: v tests
|
||||
run: |
|
||||
cd '${{env.MY_V_PATH}}'
|
||||
./v test vlib/builtin vlib/os
|
||||
|
||||
space-paths-macos:
|
||||
runs-on: macOS-latest
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
MY_V_PATH: '你好 my $path, @с интервали'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
path: ${{env.MY_V_PATH}}
|
||||
- name: Build V
|
||||
run: |
|
||||
echo '${{env.MY_V_PATH}}'
|
||||
ls -la
|
||||
cd '${{env.MY_V_PATH}}'
|
||||
ls -la
|
||||
make
|
||||
## prebuild cmd/tools/builders/js_builder, to minimise the
|
||||
## chances of a sporadic "Killed" when running the tests later
|
||||
./v -b js run examples/hello_world.v
|
||||
- name: v doctor
|
||||
run: |
|
||||
cd '${{env.MY_V_PATH}}'
|
||||
./v doctor
|
||||
- name: v tests
|
||||
run: |
|
||||
cd '${{env.MY_V_PATH}}'
|
||||
./v test vlib/builtin vlib/os
|
||||
|
||||
space-paths-windows:
|
||||
runs-on: windows-2022
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
MY_V_PATH: 'path with some $punctuation, and some spaces'
|
||||
|
||||
## NB: the following paths do not work for now:
|
||||
##### MY_V_PATH: '你好 my $path, @с интервали'
|
||||
##### MY_V_PATH: 'path with some $punctuation, and some spaces '
|
||||
## tcc has a problem interpreting paths with non latin letters in them,
|
||||
## by default, but that can be solved with passing -Bthirdparty/tcc
|
||||
## but after that V fails self building with:
|
||||
####### builder error: cannot write to folder
|
||||
####### D:\a\v\v\你好 my $path, @с интервали: No such file or directory
|
||||
## and that happens even for gcc builds, not just tcc ones
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
path: ${{env.MY_V_PATH}}
|
||||
- name: Build V
|
||||
run: |
|
||||
echo '${{env.MY_V_PATH}}'
|
||||
dir
|
||||
cd '${{env.MY_V_PATH}}'
|
||||
dir
|
||||
.\make.bat -tcc
|
||||
- name: v doctor
|
||||
run: |
|
||||
cd '${{env.MY_V_PATH}}'
|
||||
./v doctor
|
||||
- name: v tests
|
||||
run: |
|
||||
cd '${{env.MY_V_PATH}}'
|
||||
./v test vlib/builtin vlib/os
|
|
@ -0,0 +1,57 @@
|
|||
name: Periodic
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 */6 * * *'
|
||||
|
||||
jobs:
|
||||
network-tests-ubuntu:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
V_CI_PERIODIC: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install dependencies 1
|
||||
run: sudo apt-get install --quiet -y libssl-dev sqlite3 libsqlite3-dev
|
||||
- name: Build v
|
||||
run: make
|
||||
- name: Symlink V
|
||||
run: sudo ./v symlink
|
||||
## - name: Run network tests
|
||||
## run: ./v -d network test vlib/net
|
||||
|
||||
|
||||
network-tests-macos:
|
||||
runs-on: macOS-latest
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
V_CI_PERIODIC: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup openssl library path
|
||||
run: export LIBRARY_PATH="$LIBRARY_PATH:/usr/local/opt/openssl/lib/"
|
||||
- name: Build V
|
||||
run: make
|
||||
- name: Symlink V
|
||||
run: sudo ./v symlink
|
||||
- name: Ensure thirdparty/cJSON/cJSON.o is compiled, before running tests.
|
||||
run: ./v examples/json.v
|
||||
## - name: Run network tests
|
||||
## run: ./v -d network test vlib/net
|
||||
|
||||
network-windows-msvc:
|
||||
runs-on: windows-2019
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
V_CI_PERIODIC: 1
|
||||
VFLAGS: -cc msvc
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: |
|
||||
echo %VFLAGS%
|
||||
echo $VFLAGS
|
||||
.\make.bat -msvc
|
||||
## - name: Run network tests
|
||||
## run: .\v.exe -d network test vlib/net
|
|
@ -0,0 +1,62 @@
|
|||
name: Test prebuilt binaries
|
||||
on:
|
||||
release:
|
||||
types: [edited, published]
|
||||
jobs:
|
||||
ubuntu:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --quiet -y postgresql libpq-dev libglfw3 libglfw3-dev libfreetype6-dev libssl-dev sqlite3 libsqlite3-dev valgrind
|
||||
## sudo apt-get install --quiet -y libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libsdl2-image-dev
|
||||
- name: Download V
|
||||
run: |
|
||||
tag=${GITHUB_REF##*/}
|
||||
wget https://github.com/vlang/v/releases/download/$tag/v_linux.zip
|
||||
unzip v_linux.zip
|
||||
cd v
|
||||
./v -version
|
||||
- name: Test V
|
||||
run: |
|
||||
cd v
|
||||
./v run examples/hello_world.v
|
||||
|
||||
macos:
|
||||
runs-on: macOS-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
brew install freetype glfw openssl
|
||||
# brew install sdl2 sdl2_ttf sdl2_mixer sdl2_image
|
||||
export LIBRARY_PATH="$LIBRARY_PATH:/usr/local/opt/openssl/lib/"
|
||||
- name: Download V
|
||||
run: |
|
||||
tag=${GITHUB_REF##*/}
|
||||
wget https://github.com/vlang/v/releases/download/$tag/v_macos.zip
|
||||
unzip v_macos.zip
|
||||
cd v
|
||||
./v -version
|
||||
- name: Test V
|
||||
run: |
|
||||
cd v
|
||||
./v run examples/hello_world.v
|
||||
|
||||
windows:
|
||||
runs-on: windows-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Download V
|
||||
run: |
|
||||
Set-Variable -Name "tag" -Value $env:GITHUB_REF.split("/", 3)[-1]
|
||||
& curl -L https://github.com/vlang/v/releases/download/$tag/v_windows.zip -o v_windows.zip
|
||||
& unzip .\v_windows.zip
|
||||
& cd v
|
||||
& .\v.exe -version
|
||||
- name: Test V
|
||||
run: |
|
||||
& cd v
|
||||
& .\v.exe run .\examples\hello_world.v
|
|
@ -0,0 +1,48 @@
|
|||
name: sdl CI
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
jobs:
|
||||
v-compiles-sdl-examples:
|
||||
runs-on: ubuntu-18.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
VFLAGS: -cc tcc
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build V
|
||||
run: make && sudo ./v symlink
|
||||
|
||||
- name: Clone sdl into .vmodules
|
||||
run: |
|
||||
git clone --depth 1 https://github.com/vlang/sdl
|
||||
cd sdl
|
||||
mkdir -p ~/.vmodules
|
||||
ln -s $(pwd) ~/.vmodules/sdl
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --quiet -y libsdl2-dev libsdl2-ttf-dev
|
||||
sudo apt-get install --quiet -y libsdl2-mixer-dev libsdl2-image-dev
|
||||
|
||||
- name: Run tests
|
||||
run: ./v test sdl
|
||||
|
||||
- name: Build sdl shared
|
||||
run: ./v -shared -g sdl
|
||||
|
||||
- name: Build sdl examples
|
||||
run: |
|
||||
v shader sdl/examples/sdl_opengl_and_sokol
|
||||
for example in sdl/examples/*; do
|
||||
echo "v $example"
|
||||
v "$example";
|
||||
done
|
|
@ -0,0 +1,73 @@
|
|||
name: toml CI
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
jobs:
|
||||
toml-module-pass-external-test-suites:
|
||||
runs-on: ubuntu-18.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
TOML_BS_TESTS_PATH: vlib/toml/tests/testdata/burntsushi/toml-test
|
||||
TOML_BS_TESTS_PINNED_COMMIT: 4634fdf
|
||||
TOML_IARNA_TESTS_PATH: vlib/toml/tests/testdata/iarna/toml-test
|
||||
TOML_IARNA_TESTS_PINNED_COMMIT: 1880b1a
|
||||
TOML_AC_TESTS_PATH: vlib/toml/tests/testdata/alexcrichton/toml-test
|
||||
TOML_AC_TESTS_PINNED_COMMIT: 499e8c4
|
||||
VTEST_TOML_DO_LARGE_FILES: 1
|
||||
VTEST_TOML_DO_YAML_CONVERSION: 1
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --quiet -y jq libgc-dev
|
||||
- name: Build V
|
||||
run: make -j2 && ./v -cc gcc -o v cmd/v
|
||||
|
||||
- name: Show JQ Version
|
||||
run: jq --version
|
||||
|
||||
- name: Run local TOML tests
|
||||
run: ./v test vlib/toml
|
||||
|
||||
# Tests found at https://github.com/BurntSushi/toml-test
|
||||
- name: Clone BurntSushi/toml-test
|
||||
run: |
|
||||
git clone -n https://github.com/BurntSushi/toml-test.git $TOML_BS_TESTS_PATH
|
||||
git -C $TOML_BS_TESTS_PATH checkout $TOML_BS_TESTS_PINNED_COMMIT
|
||||
|
||||
- name: Run BurntSushi TOML tests
|
||||
run: ./v vlib/toml/tests/burntsushi.toml-test_test.v
|
||||
|
||||
# Tests found at gist
|
||||
- name: Get large_toml_file_test.toml
|
||||
run: wget https://gist.githubusercontent.com/Larpon/89b0e3d94c6903851ff15559e5df7a05/raw/62a1f87a4e37bf157f2e0bfb32d85d840c98e422/large_toml_file_test.toml -O vlib/toml/tests/testdata/large_toml_file_test.toml
|
||||
|
||||
- name: Run large TOML file tests
|
||||
run: ./v vlib/toml/tests/large_toml_file_test.v
|
||||
|
||||
# Tests found at https://github.com/iarna/toml-spec-tests
|
||||
- name: Clone iarna/toml-spec-tests
|
||||
run: |
|
||||
git clone -n https://github.com/iarna/toml-spec-tests.git $TOML_IARNA_TESTS_PATH
|
||||
git -C $TOML_IARNA_TESTS_PATH checkout $TOML_IARNA_TESTS_PINNED_COMMIT
|
||||
|
||||
- name: Run iarna TOML tests
|
||||
run: ./v -gc boehm vlib/toml/tests/iarna.toml-spec-tests_test.v
|
||||
|
||||
# Tests found at https://github.com/alexcrichton/toml-rs
|
||||
- name: Clone alexcrichton/toml-rs
|
||||
run: |
|
||||
git clone -n https://github.com/alexcrichton/toml-rs.git $TOML_AC_TESTS_PATH
|
||||
git -C $TOML_AC_TESTS_PATH checkout $TOML_AC_TESTS_PINNED_COMMIT
|
||||
|
||||
- name: Run alexcrichton TOML tests
|
||||
run: ./v vlib/toml/tests/alexcrichton.toml-rs-tests_test.v
|
|
@ -0,0 +1,137 @@
|
|||
name: V Apps and Modules
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
concurrency:
|
||||
group: build-v-apps-and-modules-${{ github.event.pull_request.number || github.sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
v-apps-compile:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 121
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build V
|
||||
run: make && sudo ./v symlink
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --quiet -y libgc-dev libsodium-dev libssl-dev sqlite3 libsqlite3-dev valgrind libfreetype6-dev libxi-dev libxcursor-dev libgl-dev xfonts-75dpi xfonts-base
|
||||
sudo apt-get install --quiet -y --no-install-recommends gfortran liblapacke-dev libopenblas-dev
|
||||
|
||||
- name: Build V Language Server (VLS)
|
||||
run: |
|
||||
echo "Clone VLS"
|
||||
git clone --depth 1 https://github.com/vlang/vls /tmp/vls
|
||||
echo "Build VLS"
|
||||
v /tmp/vls/cmd/vls
|
||||
echo "Build VLS with -prod"
|
||||
v -prod /tmp/vls/cmd/vls
|
||||
echo "Build VLS with -gc boehm -skip-unused"
|
||||
v -gc boehm -skip-unused /tmp/vls/cmd/vls
|
||||
|
||||
- name: Build V Coreutils
|
||||
run: |
|
||||
echo "Clone Coreutils"
|
||||
git clone --depth 1 https://github.com/vlang/coreutils /tmp/coreutils
|
||||
echo "Build Coreutils"
|
||||
cd /tmp/coreutils; make
|
||||
|
||||
- name: Build VAB
|
||||
run: |
|
||||
echo "Install VAB"
|
||||
v install vab
|
||||
echo "Build vab"
|
||||
v ~/.vmodules/vab
|
||||
echo "Build vab with -gc boehm -skip-unused"
|
||||
v -gc boehm -skip-unused ~/.vmodules/vab
|
||||
|
||||
- name: Build Gitly
|
||||
run: |
|
||||
echo "Install markdown"
|
||||
v install markdown
|
||||
echo "Clone Gitly"
|
||||
git clone https://github.com/vlang/gitly /tmp/gitly
|
||||
echo "Build Gitly"
|
||||
v /tmp/gitly
|
||||
echo "Build Gitly with -autofree"
|
||||
v -autofree /tmp/gitly
|
||||
echo "Run first_run.v"
|
||||
v run /tmp/gitly/tests/first_run.v
|
||||
# /tmp/gitly/gitly -ci_run
|
||||
|
||||
- name: Build libsodium
|
||||
run: |
|
||||
echo "Install the libsodium wrapper"
|
||||
v install libsodium
|
||||
echo "Test libsodium"
|
||||
VJOBS=1 v test ~/.vmodules/libsodium
|
||||
|
||||
- name: Build VEX
|
||||
run: |
|
||||
echo "Install Vex"
|
||||
v install nedpals.vex
|
||||
echo "Compile all of the Vex examples"
|
||||
v should-compile-all ~/.vmodules/nedpals/vex/examples
|
||||
echo "Compile the simple Vex example with -gc boehm -skip-unused"
|
||||
v -gc boehm -skip-unused ~/.vmodules/nedpals/vex/examples/simple_example.v
|
||||
echo "Run Vex Tests"
|
||||
v test ~/.vmodules/nedpals/vex
|
||||
|
||||
- name: Build go2v
|
||||
run: |
|
||||
echo "Clone Go2V"
|
||||
git clone --depth=1 https://github.com/vlang/go2v /tmp/go2v/
|
||||
echo "Build Go2V"
|
||||
v /tmp/go2v/
|
||||
echo "Run Go2V tests"
|
||||
VJOBS=1 v -stats test /tmp/go2v/
|
||||
|
||||
- name: Build vlang/pdf
|
||||
run: |
|
||||
v install pdf
|
||||
echo "PDF examples should compile"
|
||||
v should-compile-all ~/.vmodules/pdf/examples
|
||||
|
||||
- name: Install UI through VPM
|
||||
run: |
|
||||
echo "Official VPM modules should be installable"
|
||||
v install ui
|
||||
echo "Examples of UI should compile"
|
||||
v ~/.vmodules/ui/examples/build_examples.vsh
|
||||
|
||||
- name: Build VSL
|
||||
run: |
|
||||
echo "Install VSL"
|
||||
v install vsl
|
||||
echo "Execute Tests using Pure V Backend"
|
||||
~/.vmodules/vsl/bin/test
|
||||
echo "Execute Tests using Pure V Backend with Pure V Math"
|
||||
~/.vmodules/vsl/bin/test --use-cblas
|
||||
echo "Execute Tests using Pure V Backend and Garbage Collection enabled"
|
||||
~/.vmodules/vsl/bin/test --use-gc boehm
|
||||
echo "Execute Tests using Pure V Backend with Pure V Math and Garbage Collection enabled"
|
||||
~/.vmodules/vsl/bin/test --use-cblas --use-gc boehm
|
||||
|
||||
- name: Build VTL
|
||||
run: |
|
||||
echo "Install VTL"
|
||||
v install vtl
|
||||
echo "Install dependencies"
|
||||
echo "Execute Tests using Pure V Backend"
|
||||
~/.vmodules/vtl/bin/test
|
||||
echo "Execute Tests using Pure V Backend with Pure V Math"
|
||||
~/.vmodules/vtl/bin/test --use-cblas
|
||||
echo "Execute Tests using Pure V Backend and Garbage Collection enabled"
|
||||
~/.vmodules/vtl/bin/test --use-gc boehm
|
||||
echo "Execute Tests using Pure V Backend with Pure V Math and Garbage Collection enabled"
|
||||
~/.vmodules/vtl/bin/test --use-cblas --use-gc boehm
|
|
@ -0,0 +1,74 @@
|
|||
name: vab CI
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
jobs:
|
||||
vab-compiles-v-examples:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 121
|
||||
env:
|
||||
VAB_FLAGS: --api 30 --build-tools 29.0.0 -v 3
|
||||
steps:
|
||||
- uses: actions/setup-java@v2
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: 8
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build V
|
||||
run: make && sudo ./v symlink
|
||||
|
||||
- name: Install vab
|
||||
run: |
|
||||
v install vab
|
||||
v -g ~/.vmodules/vab
|
||||
sudo ln -s ~/.vmodules/vab/vab /usr/local/bin/vab
|
||||
|
||||
- name: Run tests
|
||||
run: v test ~/.vmodules/vab
|
||||
|
||||
- name: Run vab --help
|
||||
run: vab --help
|
||||
|
||||
- name: Run vab doctor
|
||||
run: vab doctor
|
||||
|
||||
- name: Build graphical V examples as APK
|
||||
run: |
|
||||
declare -a v_examples=('flappylearning' '2048' 'fireworks' 'tetris' 'sokol/particles' 'sokol/drawing.v' 'sokol/freetype_raven.v' 'gg/polygons.v' 'gg/raven_text_rendering.v' 'gg/rectangles.v' 'gg/stars.v' 'gg/worker_thread.v')
|
||||
mkdir apks
|
||||
for example in "${v_examples[@]}"; do
|
||||
safe_name=$(echo "$example" | sed 's%/%-%' | sed 's%\.%-%' )
|
||||
vab examples/$example -o apks/$safe_name.apk
|
||||
done
|
||||
|
||||
v-compiles-os-android:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build V
|
||||
run: make && sudo ./v symlink
|
||||
|
||||
- name: Install vab
|
||||
run: |
|
||||
v install vab
|
||||
v -g ~/.vmodules/vab
|
||||
sudo ln -s ~/.vmodules/vab/vab /usr/local/bin/vab
|
||||
|
||||
- name: Run vab --help
|
||||
run: vab --help
|
||||
|
||||
- name: Run vab doctor
|
||||
run: vab doctor
|
||||
|
||||
- name: Check `v -os android` *without* -apk flag
|
||||
run: .github/workflows/android_cross_compile.vsh
|
|
@ -0,0 +1,37 @@
|
|||
name: Build Vinix kernel
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
jobs:
|
||||
vinix-build:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
env:
|
||||
VFLAGS: -gc none
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install build-essential meson -y
|
||||
|
||||
- name: Build V
|
||||
run: make
|
||||
|
||||
- name: Clone current Vinix
|
||||
run: git clone https://github.com/vlang/vinix.git
|
||||
|
||||
- name: Attempt to build the Vinix kernel (debug)
|
||||
run: cd vinix/kernel && make PROD=false CFLAGS="-D__vinix__ -O2 -g -pipe" V="../../v" && make clean
|
||||
|
||||
- name: Attempt to build the Vinix kernel (prod)
|
||||
run: cd vinix/kernel && make PROD=true CFLAGS="-D__vinix__ -O2 -g -pipe" V="../../v" && make clean
|
|
@ -0,0 +1,91 @@
|
|||
name: Websockets CI
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
jobs:
|
||||
websocket_tests:
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||
timeout-minutes: 121
|
||||
env:
|
||||
VFLAGS: -cc tcc -no-retry-compilation
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install --quiet -y libssl-dev
|
||||
- name: Build v
|
||||
run: |
|
||||
echo $VFLAGS
|
||||
sudo ln -s $PWD/thirdparty/tcc/tcc.exe /usr/local/bin/tcc ## TODO: remove
|
||||
make -j4
|
||||
./v -g -o v cmd/v
|
||||
- name: v doctor
|
||||
run: ./v doctor
|
||||
- name: Run websockets tests
|
||||
run: ./v -g test vlib/net/websocket/
|
||||
|
||||
## Autobahn integrations tests
|
||||
- name: Run autobahn services
|
||||
run: docker-compose -f ${{github.workspace}}/vlib/net/websocket/tests/autobahn/docker-compose.yml up -d
|
||||
|
||||
- name: Wait for the service to start
|
||||
run: sleep 10s
|
||||
|
||||
- name: Build client test
|
||||
run: docker exec autobahn_client "/src/v" "/src/vlib/net/websocket/tests/autobahn/autobahn_client.v"
|
||||
- name: Run client test
|
||||
run: docker exec autobahn_client "/src/vlib/net/websocket/tests/autobahn/autobahn_client"
|
||||
|
||||
- name: Build client wss test
|
||||
run: docker exec autobahn_client "/src/v" "/src/vlib/net/websocket/tests/autobahn/autobahn_client_wss.v"
|
||||
|
||||
- name: Run client wss test
|
||||
run: docker exec autobahn_client "/src/vlib/net/websocket/tests/autobahn/autobahn_client_wss"
|
||||
- name: Run server test
|
||||
run: docker exec autobahn_server "wstest" "-m" "fuzzingclient" "-s" "/config/fuzzingclient.json"
|
||||
|
||||
- name: Copy reports
|
||||
run: docker cp autobahn_server:/reports ${{github.workspace}}/reports
|
||||
- name: Copy reports wss
|
||||
run: docker cp autobahn_server_wss:/reports ${{github.workspace}}/reports_wss
|
||||
- name: Test success
|
||||
run: docker exec autobahn_server "python" "/check_results.py"
|
||||
- name: Test success WSS
|
||||
run: docker exec autobahn_server_wss "python" "/check_results.py"
|
||||
|
||||
- name: Publish all reports
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: full report
|
||||
path: ${{github.workspace}}/reports
|
||||
|
||||
- name: Publish report client
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: client
|
||||
path: ${{github.workspace}}/reports/clients/index.html
|
||||
|
||||
- name: Publish report server
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: server
|
||||
path: ${{github.workspace}}/reports/servers/index.html
|
||||
|
||||
- name: Publish all reports WSS
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: full report wss
|
||||
path: ${{github.workspace}}/reports_wss
|
||||
|
||||
- name: Publish report client wss
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: client wss
|
||||
path: ${{github.workspace}}/reports_wss/clients/index.html
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
@echo off
|
||||
|
||||
curl -L https://www.libsdl.org/release/SDL2-devel-2.0.10-VC.zip -o SDL2.zip
|
||||
curl -L https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-devel-2.0.15-VC.zip -o SDL2_ttf.zip
|
||||
curl -L https://www.libsdl.org/projects/SDL_image/release/SDL2_image-devel-2.0.5-VC.zip -o SDL2_image.zip
|
||||
curl -L https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-devel-2.0.4-VC.zip -o SDL2_mixer.zip
|
||||
|
||||
unzip SDL2.zip -d thirdparty/
|
||||
unzip SDL2_ttf.zip -d thirdparty/
|
||||
unzip SDL2_image.zip -d thirdparty/
|
||||
unzip SDL2_mixer.zip -d thirdparty/
|
||||
|
||||
move /y thirdparty/SDL2-2.0.10 thirdparty/SDL2
|
||||
move /y thirdparty/SDL2_ttf-2.0.15 thirdparty/SDL2_ttf
|
||||
move /y thirdparty/SDL2_image-2.0.5 thirdparty/SDL2_image
|
||||
move /y thirdparty/SDL2_mixer-2.0.4 thirdparty/SDL2_mixer
|
|
@ -0,0 +1,11 @@
|
|||
@echo off
|
||||
|
||||
curl -L https://www.sqlite.org/2022/sqlite-amalgamation-3380200.zip -o sqlite-amalgamation-3380200.zip
|
||||
|
||||
unzip sqlite-amalgamation-3380200.zip -d thirdparty\
|
||||
|
||||
del thirdparty\sqlite-amalgamation-3380200\shell.c
|
||||
|
||||
move /y thirdparty\sqlite-amalgamation-3380200 thirdparty\sqlite
|
||||
|
||||
dir thirdparty\sqlite
|
|
@ -0,0 +1,107 @@
|
|||
# ignore sub-level build binaries and v binary
|
||||
*/**/*
|
||||
v
|
||||
v.exe
|
||||
v2
|
||||
v2.exe
|
||||
vdbg
|
||||
vdbg.exe
|
||||
!*/
|
||||
!*.*
|
||||
*.exe
|
||||
*.o
|
||||
*.so
|
||||
.*.c
|
||||
*.tmp.c
|
||||
*.obj
|
||||
*.exp
|
||||
*.ilk
|
||||
*.pdb
|
||||
*.dll
|
||||
*.lib
|
||||
*.bak
|
||||
*.dylib
|
||||
a.out
|
||||
.noprefix.vrepl_temp
|
||||
|
||||
# ignore v build files
|
||||
/vc
|
||||
/v.c
|
||||
/v.*.c
|
||||
/v.c.out
|
||||
/v_old
|
||||
/v_old.exe
|
||||
.vrepl_temp.v
|
||||
fns.txt
|
||||
.noprefix.vrepl_temp.v
|
||||
|
||||
# ignore temp directories
|
||||
/temp
|
||||
/tmp
|
||||
|
||||
# unignore special files without extension
|
||||
!.github/PULL_REQUEST_TEMPLATE
|
||||
!.editorconfig
|
||||
!.gitattributes
|
||||
!.gitignore
|
||||
!BSDmakefile
|
||||
!Dockerfile
|
||||
!Dockerfile.alpine
|
||||
!Dockerfile.cross
|
||||
!LICENSE
|
||||
!Makefile
|
||||
!GNUmakefile
|
||||
|
||||
# ignore editor files
|
||||
.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
.vscode/
|
||||
*.code-workspace
|
||||
*~
|
||||
*.swp
|
||||
*.swo
|
||||
*.swn
|
||||
.env
|
||||
|
||||
# ignore debugger files
|
||||
cachegrind.out.*
|
||||
.gdb_history
|
||||
*.dSYM
|
||||
*.def
|
||||
|
||||
# ignore system files
|
||||
.DS_Store
|
||||
._*
|
||||
thumbs.db
|
||||
/.symlink
|
||||
/.bin
|
||||
|
||||
_docs
|
||||
|
||||
# ignore vs databases
|
||||
*.suo
|
||||
*.VC.db
|
||||
*.rsp
|
||||
|
||||
# ignore cmd/tools/.disable_autorecompilation, which some package managers use.
|
||||
cmd/tools/.disable_autorecompilation
|
||||
|
||||
test.bin
|
||||
|
||||
# ignore codespace env
|
||||
.venv/
|
||||
.direnv/
|
||||
shell.nix
|
||||
default.nix
|
||||
flake.nix
|
||||
.envrc
|
||||
|
||||
thirdparty/stdatomic/nix/cpp/*.h
|
||||
|
||||
# ignore VLS log
|
||||
vls.log
|
|
@ -0,0 +1,61 @@
|
|||
platform: 'linux/amd64'
|
||||
branches: ['master']
|
||||
|
||||
pipeline:
|
||||
gen-vc:
|
||||
# This is what the official CI uses as well
|
||||
image: 'ubuntu:latest'
|
||||
secrets:
|
||||
- deploy_key
|
||||
commands:
|
||||
# Install necessary dependencies
|
||||
- apt-get update -y && apt-get install openssh-client git build-essential -y
|
||||
# Build the compiler
|
||||
- make
|
||||
# Run ssh-agent
|
||||
- eval $(ssh-agent -s)
|
||||
# Add ssh key
|
||||
- echo "$DEPLOY_KEY" | tr -d '\r' | ssh-add -
|
||||
# Create ssh dir with proper permissions
|
||||
- mkdir -p ~/.ssh
|
||||
- chmod 700 ~/.ssh
|
||||
# Configure git credentials
|
||||
- git config --global user.email 'vbot@rustybever.be'
|
||||
- git config --global user.name 'vbot'
|
||||
# Verify SSH keys
|
||||
- ssh-keyscan git.rustybever.be > ~/.ssh/known_hosts
|
||||
|
||||
# The following is copied over from the official repo's CI
|
||||
# https://github.com/vlang/v/blob/master/.github/workflows/gen_vc.yml
|
||||
- export "COMMIT_HASH=$(git rev-parse --short HEAD)"
|
||||
- export "COMMIT_MSG=$(git log -1 --oneline --pretty='%s' HEAD)"
|
||||
- rm -rf vc
|
||||
- git clone --depth=1 'git@git.rustybever.be:vieter/vc.git'
|
||||
- rm -rf vc/v.c vc/v_win.c
|
||||
- ./v -o vc/v.c -os cross cmd/v
|
||||
- ./v -o vc/v_win.c -os windows -cc msvc cmd/v
|
||||
- sed -i "1s/^/#define V_COMMIT_HASH \"$COMMIT_HASH\"\n/" vc/v.c
|
||||
- sed -i "1s/^/#define V_COMMIT_HASH \"$COMMIT_HASH\"\n/" vc/v_win.c
|
||||
# ensure the C files are over 5000 lines long, as a safety measure
|
||||
- '[ $(wc -l < vc/v.c) -gt 5000 ]'
|
||||
- '[ $(wc -l < vc/v_win.c) -gt 5000 ]'
|
||||
- git -C vc add v.c v_win.c
|
||||
- 'git -C vc commit -m "[v:master] $COMMIT_HASH - $COMMIT_MSG"'
|
||||
# in case there are recent commits:
|
||||
- git -C vc pull --rebase origin main
|
||||
- git -C vc push
|
||||
when:
|
||||
event: push
|
||||
|
||||
publish:
|
||||
image: woodpeckerci/plugin-docker-buildx
|
||||
secrets: [ docker_username, docker_password ]
|
||||
settings:
|
||||
repo: chewingbever/vlang
|
||||
tag: latest
|
||||
dockerfile: Dockerfile.builder
|
||||
platforms: [ linux/arm64/v8, linux/amd64 ]
|
||||
# The build can run every time, because we should only push when there's
|
||||
# actual changes
|
||||
when:
|
||||
event: push
|
|
@ -0,0 +1,32 @@
|
|||
matrix:
|
||||
PLATFORM:
|
||||
- 'linux/amd64'
|
||||
- 'linux/arm64'
|
||||
|
||||
platform: ${PLATFORM}
|
||||
branches: ['master']
|
||||
depends_on:
|
||||
- 'vc'
|
||||
|
||||
pipeline:
|
||||
build:
|
||||
image: 'menci/archlinuxarm:base-devel'
|
||||
commands:
|
||||
# Update packages
|
||||
- pacman -Syu --noconfirm
|
||||
# Create non-root user to perform build & switch to their home
|
||||
- groupadd -g 1000 builder
|
||||
- useradd -mg builder builder
|
||||
- chown -R builder:builder "$PWD"
|
||||
- "echo 'builder ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers"
|
||||
- su builder
|
||||
# Build the package
|
||||
- makepkg -s --noconfirm --needed
|
||||
|
||||
publish:
|
||||
image: 'curlimages/curl'
|
||||
secrets:
|
||||
- 'vieter_api_key'
|
||||
commands:
|
||||
# Publish the package
|
||||
- 'for pkg in $(ls -1 *.pkg*); do curl -f -XPOST -T "$pkg" -H "X-API-KEY: $VIETER_API_KEY" https://arch.r8r.be/vieter/publish; done'
|
|
@ -0,0 +1,18 @@
|
|||
platform: 'linux/amd64'
|
||||
branches: ['master']
|
||||
depends_on:
|
||||
- 'vc'
|
||||
|
||||
pipeline:
|
||||
build-publish:
|
||||
image: 'woodpeckerci/plugin-docker-buildx'
|
||||
secrets: [ docker_username, docker_password ]
|
||||
settings:
|
||||
repo: chewingbever/vlang
|
||||
tag: latest
|
||||
dockerfile: Dockerfile.builder
|
||||
platforms: [ linux/arm64/v8, linux/amd64 ]
|
||||
# The build can run every time, because we should only push when there's
|
||||
# actual changes
|
||||
when:
|
||||
event: push
|
|
@ -0,0 +1,48 @@
|
|||
platform: 'linux/amd64'
|
||||
branches: ['master']
|
||||
|
||||
pipeline:
|
||||
gen-vc:
|
||||
# This is what the official CI uses as well
|
||||
image: 'ubuntu:latest'
|
||||
secrets:
|
||||
- deploy_key
|
||||
commands:
|
||||
# Install necessary dependencies
|
||||
- apt-get update -y && apt-get install openssh-client git build-essential -y
|
||||
# Build the compiler
|
||||
- make
|
||||
# Run ssh-agent
|
||||
- eval $(ssh-agent -s)
|
||||
# Add ssh key
|
||||
- echo "$DEPLOY_KEY" | tr -d '\r' | ssh-add -
|
||||
# Create ssh dir with proper permissions
|
||||
- mkdir -p ~/.ssh
|
||||
- chmod 700 ~/.ssh
|
||||
# Configure git credentials
|
||||
- git config --global user.email 'vbot@rustybever.be'
|
||||
- git config --global user.name 'vbot'
|
||||
# Verify SSH keys
|
||||
- ssh-keyscan git.rustybever.be > ~/.ssh/known_hosts
|
||||
|
||||
# The following is copied over from the official repo's CI
|
||||
# https://github.com/vlang/v/blob/master/.github/workflows/gen_vc.yml
|
||||
- export "COMMIT_HASH=$(git rev-parse --short HEAD)"
|
||||
- export "COMMIT_MSG=$(git log -1 --oneline --pretty='%s' HEAD)"
|
||||
- rm -rf vc
|
||||
- git clone --depth=1 'git@git.rustybever.be:vieter-v/vc.git'
|
||||
- rm -rf vc/v.c vc/v_win.c
|
||||
- ./v -o vc/v.c -os cross cmd/v
|
||||
- ./v -o vc/v_win.c -os windows -cc msvc cmd/v
|
||||
- sed -i "1s/^/#define V_COMMIT_HASH \"$COMMIT_HASH\"\n/" vc/v.c
|
||||
- sed -i "1s/^/#define V_COMMIT_HASH \"$COMMIT_HASH\"\n/" vc/v_win.c
|
||||
# ensure the C files are over 5000 lines long, as a safety measure
|
||||
- '[ $(wc -l < vc/v.c) -gt 5000 ]'
|
||||
- '[ $(wc -l < vc/v_win.c) -gt 5000 ]'
|
||||
- git -C vc add v.c v_win.c
|
||||
- 'git -C vc commit -m "[v:master] $COMMIT_HASH - $COMMIT_MSG"'
|
||||
# in case there are recent commits:
|
||||
- git -C vc pull --rebase origin main
|
||||
- git -C vc push
|
||||
when:
|
||||
event: push
|
|
@ -0,0 +1,493 @@
|
|||
-## V 0.2.5
|
||||
-*Not yet released, changelog is not full*
|
||||
- Introduce `isize` and `usize` types, deprecate `size_t` in favor of `usize`.
|
||||
- Add `datatypes` and `datatypes.fsm` modules.
|
||||
- Add `compile_error` and `compile_warn` comptime functions.
|
||||
|
||||
-## V 0.2.4
|
||||
-*Not yet released, changelog is not full*
|
||||
- Bare metal support. Vinix OS kernel is now being developed in V.
|
||||
- Builtin web framework vweb is now multithreaded, all CPU cores are used.
|
||||
- String interpolation and struct stringers are now implemented in pure V
|
||||
with a much cleaner and faster implementation. Previously libc's `sprintf`
|
||||
was used.
|
||||
- Improved `unused variable` warning. Assigning to a variable no longer marks it as used.
|
||||
|
||||
## V 0.2.2 - 0.2.3
|
||||
*22 Jan 2021*
|
||||
- Allow interfaces to define fields, not just methods.
|
||||
- `vweb` now uses struct embedding: `app.vweb.text('hello') => app.text('hello')`.
|
||||
- Consts can now be declared outside of `const()` blocks: `const x = 0`.
|
||||
- Overloading of `>`, `<`, `!=`, `==`, `<=` and `>=` operators.
|
||||
- New struct updating syntax: `User{ ...u, name: 'new' }` to replace `{ u | name: 'new' }`.
|
||||
- `byte.str()` has been fixed and works like all other numbers. `byte.ascii_str()` has been added.
|
||||
- Smart cast in for loops: `for mut x is string {}`.
|
||||
- `[noinit]` struct attribute to disallow direct struct initialization with `Foo{}`.
|
||||
- Array decompose: `[1, 2, 3]...` is now `...[1, 2, 3]`
|
||||
- Treating `enum` as `int` and operations on `enum` except `==` and `!=` are removed for strict type checking.
|
||||
- Support `[manualfree] fn f1(){}` and `[manualfree] module m1`, for functions doing their own memory management.
|
||||
- Allow usage of `<` and `>` operators for struct in `.sort` method for arrays, i.e. `arr.sort(a < b)`.
|
||||
- Auto generate assignment operators like `+=`, `-=`, `*=`, `/=` and `%=` if the operators are defined.
|
||||
- Colorize and improve failing tests output.
|
||||
- Fix `go` with a generic function: `go test<string>(c, 'abcd')`.
|
||||
- Add comptime `x := $embed_file('v.png') println(x.len) println(ptr_str(x.data()))`, for embedding files into binaries.
|
||||
- Advanced vdoc search on mobile layout.
|
||||
- string's `left()`/`right` were removed in favor of slicing syntax: `str[..pos]`.
|
||||
- gg: native graphics mode on macOS/iOS (using Cocoa Drawing API).
|
||||
- Full path to consts must be specified everywhere. This makes it easy to distinguish them
|
||||
from local variables.
|
||||
- `__offsetof` for low level needs (works like `offsetof` in C).
|
||||
- vfmt now preserves empty lines, like gofmt.
|
||||
- Support for compile time environment variables via `$env('ENV_VAR')`.
|
||||
- Allow method declaration of `==` and `<` operators and auto generate `!=`, `>`, `<=` and `>=`.
|
||||
- support `dump(expr)`, i.e. tracing of both the location, name and value of an expression
|
||||
- deprecate os.exec in favour of os.executable() which does *NOT* return an option, when the command was not found
|
||||
|
||||
## V 0.2.1
|
||||
*30 Dec 2020*
|
||||
- Hashmap bootstrapping fixes.
|
||||
- Array decomposition to varargs: `fn sum(i ...int) int` => `a := [2,3,4] println(sum(a...))`
|
||||
- HTML module docs generated by vdoc now have global search.
|
||||
|
||||
## V 0.2
|
||||
*22 Dec 2020*
|
||||
- Compile-time memory management via `-autofree`. [Video demonstration](https://www.youtube.com/watch?v=gmB8ea8uLsM).
|
||||
It will be enabled by default in 0.3
|
||||
- Channels and locks.
|
||||
- Thread safe typed arrays via keyword `shared`.
|
||||
- Struct embedding.
|
||||
- IO streams.
|
||||
- A powerful websocket module that conforms to RFC 6455 and passes the Autobahn test suite (498 client tests and 249 server tests).
|
||||
- The `net` module is now non blocking and is more feature complete providing similar API to Go.
|
||||
- V's graphics module now uses Metal/DirectX/OpenGL instead of just OpenGL.
|
||||
- V can now run in the browser via WASM and execute V code by translating it to JavaScript:
|
||||
https://v-wasm.now.sh
|
||||
- V binaries for Linux/Windows/macOS are now built and deployed automatically via GitHub Actions.
|
||||
- Smart casting for sumtypes and interfaces, including complex expressions: `if x.expr is int { println(x.expr + 1) }`.
|
||||
- Clean and easy way to sort arrays: `users.sort(a.name > b.name)`.
|
||||
- A huge amount of `vfmt` fixes and improvements. It has now reached a point where it can be safely used on any V source file.
|
||||
- A new CI job that runs `v fmt -verify` on the entire code base, a new command that makes sure the file/directory
|
||||
has been vfmt'ed. This ensures that all code submitted to the V project is formatted.
|
||||
- A new tool `v vet` for analyzing the project and finding potential bugs and errors.
|
||||
- A new `term.ui` module for building dynamic terminal UIs with an example editor written in it.
|
||||
- Early iOS and Android support.
|
||||
- All missing ORM features from the old backend were brought back.
|
||||
- Magic `it` variable has been replaced with smart casts (the change is completely handled by vfmt).
|
||||
- Cross-compiling to Windows and Linux brought back.
|
||||
- C2V can now generate wrappers. Example: https://github.com/medvednikov/libsodium. (C2V will be released by 0.3)
|
||||
- C++ compiler support: code, generated by the C backend can now by compiled by C++ compilers.
|
||||
- Short generics syntax: `foo(5)` instead of `foo<int>(5)`.
|
||||
- Cached modules via `-usecache`. Faster compilation due to not needing to rebuild the entire vlib for
|
||||
each program. Will be enabled by default in 0.2.1.
|
||||
- New improved sum types implementation.
|
||||
- Lots of errors that happen often during the development cycle were turned into warnings to increase
|
||||
development speed. They are still errors in production builds.
|
||||
- Labeled `break` and `continue`.
|
||||
- Lots of documentation. The official language documentation grew 3 times in size.
|
||||
- `modules.vlang.io` is now generated automatically on every commit.
|
||||
- Builtin compile-time JSON serializer now supports `time.Time`.
|
||||
- Fixes in type aliases, to make them behave just like the types they alias.
|
||||
- `array.contains(element)` is now generic.
|
||||
- Lots of improvements in the JS backend and its type system.
|
||||
- Simpler and more constinent function arg syntax: `foo(a int, b int, c string)` instead of `foo(a, b int, c string)`
|
||||
- Lots of fixes and optimizations in the hashmap.
|
||||
- Lots of missing checks in the type checker were added (for example, checking the correct usage of public struct fields).
|
||||
- Mutability bug fixes
|
||||
- Taking the address of a map value is no longer allowed, like in Go.
|
||||
- Matrix multiplication.
|
||||
- A new `#pkgconfig` flag to provide platform independent way to get compilation flags for C libraries/packages.
|
||||
- Explicit parentheses requirement in complex boolean expressions.
|
||||
- `println` was made even smarter, and can now handle complex types.
|
||||
- Precompiled text templates can now be used outside of vweb via `$tmpl()`.
|
||||
- Gitly, a big web application written in vweb has been released: https://github.com/vlang/gitly
|
||||
- `['/:arg1/:arg2/action']` vweb action attribute for easily getting query parameters assigned to method arguments.
|
||||
- Improved performance of text rendering, `gg.text_width()`.
|
||||
- Webview module in V UI.
|
||||
- Binary enum flags.
|
||||
- `[export]` attribute to change exported function name (for example for calling from a C library).
|
||||
- `unsafe` fixes and improvements.
|
||||
- Improvements to rand: `rand.ulid()`, `rand.uuid()`, a unified customizable PRNG API.
|
||||
- Hundreds of other fixes, features, and tests (from now on the changelog will be updated
|
||||
right away as the feature/bug fix lands).
|
||||
|
||||
|
||||
## V 0.1.27
|
||||
*5 May 2020*
|
||||
|
||||
- vfmt has been re-written from scratch using the new AST parser.
|
||||
It's much faster, cleaner, and can format
|
||||
files with compilation errors.
|
||||
- `strconv`, `sprintf`, and `printf` in native V, without any libc calls.
|
||||
- Interfaces are now a lot more stable and have all expected features.
|
||||
- Lots of x64 backend improvements: function calls, if expressions, for loops, local variables.
|
||||
- `map()` and `filter()` methods can now be chained.
|
||||
- New `[]int{cap:cap, len:len}` syntax for initializing array length and capacity.
|
||||
- New `is` keyword for checking the type of sum types and interfaces.
|
||||
- `as` can now be used to cast interfaces and sum types.
|
||||
- Profiling with `-profile`. Prints a nice table with details about every single function call:
|
||||
number of calls, average time per call, total time per function
|
||||
- `import(xxx)` syntax has been removed in favor of `import xxx` for simplicity and greppability.
|
||||
- Lots of fixes and improvements in the type checker.
|
||||
- `time.StopWatch`
|
||||
- `dl` module for dynamic loading.
|
||||
- Automatic `str()` method generation for every single type, including all arrays.
|
||||
- Short struct initialization syntax for imitating named function args: `foo(bar:0, baz:1)`.
|
||||
- New operator `!in`.
|
||||
- Performance improvements in critical parts of the builtin data structures (array, map).
|
||||
- High order functions improvements (functions can now be returned etc).
|
||||
- Anonymous functions that can be defined inside other functions.
|
||||
- Built-in JSON module is back.
|
||||
- Lots and lots of new tests added, including output tests that test error messages.
|
||||
- Multiple errors are now printed, the compiler no longer stops after the first error.
|
||||
- The new JS backend using the AST parser (almost complete).
|
||||
- Variadic functions.
|
||||
- `net.websocket` module (early stage).
|
||||
- `vlib` is now memory leak free, lots of `autofree` improvements.
|
||||
- Simplified and cleaned up `cmd/v`, `v.builder`.
|
||||
- V UI was updated to work with the new backend.
|
||||
|
||||
|
||||
## V 0.1.25
|
||||
*1 Apr 2020*
|
||||
|
||||
- The entire compiler has been re-written with an AST parser.
|
||||
The code is now a lot cleaner and more maintainable.
|
||||
~15k lines of old compiler code were removed.
|
||||
|
||||
## V 0.1.24
|
||||
*31 Dec 2019*
|
||||
|
||||
- A new parser/generator built on top of an AST that simplifies code greatly
|
||||
and allows to implement new backends much faster.
|
||||
- Sum types (`type Expr = IfExpr | MatchExpr | IntegerLiteral`).
|
||||
- B-tree map (sped up the V compiler by ~10%).
|
||||
- `v fmt -w`.
|
||||
- The entire code base has been formatted with vfmt.
|
||||
- Generic structs.
|
||||
- SDL module.
|
||||
- Arrays of pointers.
|
||||
- os: `is_link()`, `is_dir()`, `exists()`.
|
||||
- Ranging through fixed size arrays.
|
||||
- Lots of fixes in ORM and vweb.
|
||||
- The first tutorial: [building a simple web application with vweb](https://github.com/vlang/v/blob/master/tutorials/building_a_simple_web_blog_with_vweb/README.md)
|
||||
- Match expressions now must be exhaustive.
|
||||
- freestanding: `malloc()`/`free()`.
|
||||
- `++` is now required instead of `+= 1` for consistency.
|
||||
- Interpolated strings now allow function calls: `println('val = $get_val()')`.
|
||||
- `string.replace_each([])` for an efficient replacement of multiple values.
|
||||
- More utf8 helper functions.
|
||||
- `-prealloc` option for block allocations.
|
||||
- `type` aliases.
|
||||
- Running `v` with an unknown command will result in an error.
|
||||
- `atof` implementation in pure V.
|
||||
- Enums can now have negative values.
|
||||
- New `filepath` module.
|
||||
- `math.factorial`.
|
||||
- `ftp` module.
|
||||
- New syntax for casting: `val as Type`.
|
||||
- Fewer libc functions used (soon V will have no dependency on libc).
|
||||
|
||||
|
||||
## V 0.1.23
|
||||
*30 Nov 2019*
|
||||
|
||||
- [Direct x64 machine code generation](https://github.com/vlang/v/issues/2849).
|
||||
Hello world being built in 3 milliseconds.
|
||||
- Bare metal support via the `-freestanding` flag, to build programs without linking to libc.
|
||||
- Prebuilt V packages for Linux, macOS, and Windows.
|
||||
- `string.index()` now returns `?int` instead of `int/-1`.
|
||||
- Lots of fixes in Generics.
|
||||
- vweb framework for developing web applications is back.
|
||||
- Vorum, the forum/blogging software written in vweb, can now be compiled and has been added to CI.
|
||||
- REPL, `v up` have been split up into separate applications to keep the core V compiler small.
|
||||
- V now enforces short enum syntax (`.green` instead of `Color.green`) when it's enough.
|
||||
- V UI for macOS.
|
||||
- Interfaces have been rewritten. `[]interface` support.
|
||||
- `os.cp()` for copying files and directores.
|
||||
- Additional compile-time flags: `$if clang, msvc, mingw, x32, x64, big_endian, little_endian {`.
|
||||
- All C functions now have to be declared, all missing C functions have been defined.
|
||||
- Global variables (only with the `-enable-globals` flag)
|
||||
for low level applications like kernels and drivers.
|
||||
- Nothing can be cast to bool (previously code like `if bool(1) {` worked).
|
||||
- `<<` and `>>` now work with all integer types.
|
||||
- V detects Cygwin and shows an error (V supports Windows natively).
|
||||
- Improved type checking of some operators (`%, |, &` etc).
|
||||
- Windows 7 support.
|
||||
- `println(true)` now prints `true` instead of `1`.
|
||||
- `os.exec()` now uses `CreateProcess` on Windows.
|
||||
- fast.vlang.io website for monitoring the performance of V after every commit.
|
||||
- On Windows Visual Studio is now used automatically if GCC is not installed.
|
||||
- vfmt!
|
||||
- Lots of cleaning up in the compiler code.
|
||||
- Multi-level pointers in unsafe code (`****int`).
|
||||
- MSVC backtrace.
|
||||
- `$if os {` blocks are now skipped on a different OS.
|
||||
- C string literals (`c'hello'`).
|
||||
- AlpineLinux/musl fixes + added to CI.
|
||||
- Inline assembly.
|
||||
- Clipboard module (Windows, macOS, X).
|
||||
- `foo()?` syntax for error propagation.
|
||||
- Docs have been migrated from HTML to `doc/docs.md`.
|
||||
- `eventbus` module.
|
||||
- Haiku OS support.
|
||||
- `malloc/free` on bare metal.
|
||||
- `utf8` helper functions (`to_lower()`, `to_upper()`, etc).
|
||||
- Optimization of `for c in str {`.
|
||||
- `string/array.left/right/slice/substr` were removed (use `[a..b]` slicing syntax instead).
|
||||
|
||||
|
||||
|
||||
## V 0.1.22
|
||||
*28 Oct 2019*
|
||||
|
||||
- Generic functions (`fn foo<T>(bar T) T {`) with varargs support.
|
||||
- `array[start..end]` and `string[start..end]` slicing syntax.
|
||||
- Optimized `array.filter()` and `array.map()`.
|
||||
- `sqlite` module.
|
||||
- Cached modules for faster compilation.
|
||||
- Dramatic compilation optimizations: [V now compiles itself in 0.10 - 0.30 seconds](https://github.com/vlang/v/wiki/The-V-language-now-compiles-itself-in-0.09-seconds)
|
||||
- V scripts (simpler and cross-platform alternative to Bash).
|
||||
- Infinite multi-dimensional arrays (`[][][]int`).
|
||||
- `unsafe`.
|
||||
- `[deprecated]` attribute.
|
||||
- `[if]` function attributes for compile time function exclusion for performance.
|
||||
- `switch` has been completely removed from the language and replaced by
|
||||
`match` everywhere.
|
||||
- `pub struct` and `pub const`, previously all structs and consts were public
|
||||
by default.
|
||||
- `musl` support (V can now run on, for example, Alpine Linux).
|
||||
- Module header generation. V now supports closed source modules, which are still
|
||||
used in some industries.
|
||||
- Constants were added to typo suggestions.
|
||||
- `color in [.green, .red, .blue]` now works without specifying `Color.green`.
|
||||
- V compiler is now a module that can be used by other programs.
|
||||
- Backtraces now have source lines on Linux.
|
||||
- `runtime.nr_cpus()`.
|
||||
- `fn init()` for module initialization.
|
||||
- `a in [1, 2, 3]` optimization: no array gets allocated.
|
||||
- Raw strings: `s := r'hello\nworld'`.
|
||||
- `if a := func() { }` syntax for handling optionals.
|
||||
- f32/f64 comparison now uses machine epsilon by default.
|
||||
|
||||
|
||||
## V 0.1.21
|
||||
*30 Sep 2019*
|
||||
|
||||
- `none` keyword for optionals.
|
||||
- Solaris support.
|
||||
- All table lookup functions now use `none`.
|
||||
- varargs: `fn foo(bar int, params ...string) {`.
|
||||
- Double quotes (`"`) can now also be used to denote strings.
|
||||
- GitHub Actions CI in addition to Travis.
|
||||
- `-compress` option. The V binary built with `-compress` is only ~90 KB!
|
||||
- More memory management.
|
||||
- Unused modules result in an error.
|
||||
- "Unused variable/module" errors are now warnings in non-production builds.
|
||||
- Duplicate methods with the same name can no longer be defined.
|
||||
- Struct names must be capitalized, variable/function names must use snake_case.
|
||||
- Error messages are now even nicer!
|
||||
- Lots of fixes in automatic `.str()` method generation for structs and arrays.
|
||||
- ~30% faster parser (files are no longer parsed separately for each pass).
|
||||
- `_` is no longer a variable, but an actual syntax construct to skip unused values, like in Go.
|
||||
- Multiple returns (`fn foo() (int, string) {`).
|
||||
- `!` can now only be used with booleans.
|
||||
|
||||
|
||||
## V 0.1.20
|
||||
*17 Sep 2019*
|
||||
|
||||
- JavaScript backend!
|
||||
- Hundreds of C warnings were fixed. `gcc v.c` now builds without
|
||||
any warnings.
|
||||
- The mutability check now applies to function args (mutable
|
||||
receivers that are not modified result in a compilation error).
|
||||
- V tests now show how long each test took.
|
||||
- Official Android support (only console applications via Termux for now).
|
||||
- Typo check. If a variable/function/module etc is misspelled,
|
||||
V will suggest the correct name.
|
||||
- Lots of Microsoft C fixes, and a separate Travis instance for
|
||||
this backend.
|
||||
- Bitwise operators `|`, `^`, `&` no longer work with booleans.
|
||||
|
||||
|
||||
## V 0.1.19
|
||||
*12 Sep 2019*
|
||||
|
||||
- Lots of refactoring, simplifications, and optimizations in the compiler.
|
||||
- Experimental memory management at compilation (only for the V compiler itself for now).
|
||||
- Lots of ORM fixes.
|
||||
- Functions can now be inlined via the `[inline]` attribute.
|
||||
- New `mysql` module.
|
||||
- Better error format that is supported by all major editors (go to error).
|
||||
- Error messages now point to the actual place where the error happened.
|
||||
- Custom json field names: `struct User { last_name string [json:lastName] }`.
|
||||
- Raw json fields via the `[raw]` attribute.
|
||||
- All C code was removed from the `freetype` module.
|
||||
- `gg` module can now render all Unicode characters.
|
||||
- `[typedef]` attribute for imported C struct typedefs.
|
||||
- Support of Objective C interfaces (primarily for using Cocoa).
|
||||
- REPL: clear command and custom functions.
|
||||
- REPL tests (which are also used for testing certain compiler errors).
|
||||
- Syntax bug fixed: `foo[0] += 10` is now possible.
|
||||
- http: support plain HTTP protocol and follow redirects.
|
||||
- http: header data is now processed correctly.
|
||||
- net: basic UDP support.
|
||||
- `import const` was removed from the language.
|
||||
- `array.contains()` was removed from the language (`in` should be used instead).
|
||||
- `[0; len]` syntax was removed (replaced with a simpler `[0].repeat(len)`)
|
||||
- Primitive aliases were removed to simplify the language.
|
||||
- GitHub supports V now!
|
||||
- Backtraces are now printed on panics.
|
||||
- A new awesome `readline` module.
|
||||
- V.c is now regenerated automatically after every commit.
|
||||
- A bug with struct ordering was fixed, now structs can be declared in any order.
|
||||
- V modules can now be built with `v build module`.
|
||||
- `@FILE, @LINE, @FN, @COLUMN` for debugging.
|
||||
|
||||
|
||||
## V 0.1.18
|
||||
*16 Aug 2019*
|
||||
|
||||
- Built-in ORM (`uk_customers = db.select from Customer where country == 'uk' && nr_orders > 0`).
|
||||
- Map initialization syntax: `m := { ‘foo’: ‘bar’, ‘baz’: ‘foo’ }`.
|
||||
- `map.delete(key)`.
|
||||
- `libcurl` dependency was removed from the `http` module.
|
||||
- All function arguments are now immutable by default (previously they could be
|
||||
modifed inside the function).
|
||||
- `http` functions now return optionals.
|
||||
- `sync.WaitGroup`.
|
||||
- `vweb` static files serving.
|
||||
- `crypto.rand` module.
|
||||
- `v up` to update V.
|
||||
- SChannel support on Windows.
|
||||
- `net.urllib` module.
|
||||
- vpm package manager, `v install`.
|
||||
- `()` are now required in complex bool expressions: `(a && b) || c` instead of `a && b || c`.
|
||||
- All arrays now have a default `.str()` method.
|
||||
- Bootstrapping V with MSVC.
|
||||
- Experimental `≠` etc support.
|
||||
- `encoding.csv` module.
|
||||
- `$if debug {` for running code in debug mode only.
|
||||
- Map struct fields are now initialized automatically, just like arrays.
|
||||
- Maps now support array values.
|
||||
- `json` functions can no longer be used if the `json` module is not imported.
|
||||
|
||||
|
||||
## V 0.1.17
|
||||
*29 Jul 2019*
|
||||
- `vweb` module for developing web apps in V.
|
||||
- vtalk, open source V forum software.
|
||||
- Generics (very limited right now, but they will be gradually improved).
|
||||
- Comptime codegen (`foo.$method()` where `method` is a string).
|
||||
- @ for escaping keywords (e.g. `struct Foo { @type string }`).
|
||||
- Windows Unicode fixes (V can now work with non-ASCII paths etc on Windows).
|
||||
- Fix mutable args bugs + don't allow primitive arguments to be modified.
|
||||
- Declaring a mutable variable and never modifying it results in a compilation error.
|
||||
- Interactive debugging support.
|
||||
- `sync` module for Windows.
|
||||
- `#!` support on Unix systems (V scripts).
|
||||
- Lots of Visual Studio fixes.
|
||||
- `crypto.aes` and `crypto.rc4` modules.
|
||||
- Internal modules.
|
||||
|
||||
|
||||
## V 0.1.16
|
||||
*23 Jul 2019*
|
||||
- V can now be used with Visual Studio!
|
||||
- Hot code reloading now works with graphical applications (e.g. graph.v, bounce.v).
|
||||
- Compile time memory management for arrays.
|
||||
- High order functions.
|
||||
- `match` expression (replacing `switch`).
|
||||
- Import cycle detection.
|
||||
- `crypto/md5`, `crypto/sha256`, and `crypro/sha512` modules.
|
||||
- `os.executable()` - a cross platform function that returns full path to current executable.
|
||||
- `~/.vlang` and `VROOT` were removed entirely. The installation is a lot cleaner now.
|
||||
- V can now be packaged for all Linux distros.
|
||||
- Arch Linux package.
|
||||
- `string(bytes_buffer, len)`, `string(bytes_array)` casts.
|
||||
- Multiple `defer`s.
|
||||
- `key in map` syntax (replacing `map.exists(key)`).
|
||||
|
||||
|
||||
## V 0.1.15
|
||||
*15 Jul 2019*
|
||||
- FreeBSD, OpenBSD, NetBSD, DragonFly support.
|
||||
- Hot reloading now works with graphical applications: [bounce.v](examples/hot_reload/bounce.v)
|
||||
- VROOT was removed, the installation process is now much simpler.
|
||||
- `defer` statement.
|
||||
- map.v was re-written. It's now much faster.
|
||||
- `for key, val in map` syntax.
|
||||
- `flag` module for parsing command line arguments.
|
||||
- `zip` module.
|
||||
- `crypto/sha1` module.
|
||||
- Submodules and module aliases (`import encoding.base64 as b64`).
|
||||
|
||||
|
||||
## V 0.1.14
|
||||
*12 Jul 2019*
|
||||
- `gg` module Windows support, V Tetris runs on Windows.
|
||||
- Compile `glad` and `cJSON` only once. Programs using `gg` or `json` compile a bit faster.
|
||||
- `v.c` has been cleaned up and minimized (~16k => ~10k lines of code).
|
||||
- `type` aliases can now have methods.
|
||||
- Const overflow check during compilation (`byte(1000)` will no longer compile).
|
||||
|
||||
|
||||
## V 0.1.13
|
||||
*10 Jul 2019*
|
||||
- New enum syntax (`token == .name`), enum values are no longer global consts.
|
||||
- Submodules (`import encoding.base64`).
|
||||
- Hot code reloading.
|
||||
- Special `err` variable for getting error values.
|
||||
- Complex numbers.
|
||||
- `<<` can now append arrays (`numbers << [1, 2, 3]`).
|
||||
- Lots of Windows fixes (Windows still needs some work).
|
||||
- Lots of REPL improvements (e.g. `>> 2 + 3` works now, no `println` required).
|
||||
- The website was made easily translatable, it's now partially available in several languages.
|
||||
|
||||
|
||||
## V 0.1.12
|
||||
*4 Jul 2019*
|
||||
- V can finally compile itself on Windows (https://github.com/vlang/v#mingw-w64).
|
||||
- `os` module now uses optionals in all functions that return `File`.
|
||||
- Lots of bugs with optionals were fixed.
|
||||
- `println` was optimized. It no longer results in allocations.
|
||||
Now it also works correctly with all integer types.
|
||||
- Lots of `vfmt` fixes, it will be enabled tomorrow.
|
||||
- New `strings` module.
|
||||
- Lots of other fixes and improvements, thanks to all the contributors.
|
||||
|
||||
|
||||
## V 0.1.11
|
||||
*1 Jul 2019*
|
||||
- Cross compilation for Windows!
|
||||
- Lots of Windows fixes.
|
||||
- socket.v.
|
||||
- maps fixed.
|
||||
|
||||
|
||||
## V 0.1.9 - 0.1.10
|
||||
*29 Jun 2019*
|
||||
- Windows support via MinGW-w64. Pre-built Windows binary.
|
||||
- File structure has been simplified: all vlib modules were moved to the vlib/ directory,
|
||||
makefile was moved to the root.
|
||||
- One single archive with pre-built binaries for all operating systems.
|
||||
- `mut var := val` was fixed (previously `mut var = val` was allowed as well).
|
||||
|
||||
|
||||
## V 0.1.8
|
||||
*28 Jun 2019*
|
||||
- Single file programs without `fn main` now work as expected.
|
||||
- REPL has been fixed: it now supports imports, consts, function definitions, etc.
|
||||
|
||||
|
||||
## V 0.1.7
|
||||
*27 Jun 2019*
|
||||
- All C code in the compiler and vlib has been replaced with V.
|
||||
- `#` syntax for embedding C code has been removed.
|
||||
- Exported functions now need to be marked with `pub`, all public vlib functions have been updated.
|
||||
- CI has been set up (Travis + Azure). On every commit and PR it is made sure that V
|
||||
can compile itself, all tests pass, and all examples compile.
|
||||
- More tests have been uploaded.
|
||||
- Cleaner bytes to string conversion: `tos2(bytes)` => `string(bytes)`.
|
||||
- The home page has 3 more examples next to 'hello world' that show the features of the language.
|
||||
- Lots of bugs and issues fixed.
|
|
@ -0,0 +1,4 @@
|
|||
# Code of Conduct
|
||||
|
||||
Be nice and respectful.
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
## Code Structure
|
||||
|
||||
I tried to make the code of the compiler and vlib as simple and readable as
|
||||
possible. One of V's goals is to be open to developers with different levels
|
||||
of experience in compiler development. Compilers don't need to be black boxes
|
||||
full of magic that only few people understand.
|
||||
|
||||
The V compiler is modular, and can be used by other applications. It is located
|
||||
in `cmd/v/` and `vlib/v/`.
|
||||
|
||||
The most important and useful command to remember when working on the V compiler
|
||||
is `v self`.
|
||||
It rebuilds the V compiler.
|
||||
|
||||
Be careful, if you introduce a breaking change and rebuild V, you will no longer
|
||||
be able to use V to build itself. So it's a good idea to make a backup copy of a
|
||||
working compiler executable.
|
||||
|
||||
But don't worry, you can always simply run `make` (or `make.bat`), it will
|
||||
download the C version of the compiler and rebuild it from scratch.
|
||||
|
||||
The architecture of the compiler is very simple and has three distinct steps:
|
||||
|
||||
Parse/generate AST (`v.parser`) => Check types (`v.checker`)
|
||||
=> Generate C/JavaScript/machine code (`v.gen`)
|
||||
|
||||
|
||||
The main files are:
|
||||
|
||||
1. `cmd/v/v.v` The entry point.
|
||||
|
||||
- V figures out the build mode.
|
||||
- Constructs the compiler object (`struct V`).
|
||||
- Creates a list of .v files that need to be parsed.
|
||||
- Creates a parser object for each file and runs `parse()` on them.
|
||||
- The correct backend is called (C, JS, native), and a binary is compiled.
|
||||
|
||||
2. `vlib/v/scanner` The scanner's job is to parse a list of characters and convert
|
||||
them to tokens.
|
||||
|
||||
3. `vlib/v/token` This is simply a list of all tokens, their string values, and a
|
||||
couple of helper functions.
|
||||
|
||||
4. `vlib/v/parser` The parser. It converts a list of tokens into an AST.
|
||||
In V, objects can be used before declaration, so unknown types are marked as
|
||||
unresolved. They are resolved later in the type checker.
|
||||
|
||||
5. `vlib/v/table` V creates one table object that is shared by all parsers. It
|
||||
contains all types, consts, and functions, as well as several helpers to search
|
||||
for objects by name, register new objects, modify types' fields, etc.
|
||||
|
||||
6. `vlib/v/checker` Type checker and resolver. It processes the AST and makes sure
|
||||
the types are correct. Unresolved types are resolved, type information is added
|
||||
to the AST.
|
||||
|
||||
7. `vlib/v/gen/c` C backend. It simply walks the AST and generates C code that can be
|
||||
compiled with Clang, GCC, Visual Studio, and TCC.
|
||||
|
||||
8. `vlib/v/gen/js` JavaScript backend. It simply walks the AST and generates JS code that can be
|
||||
executed on the browser or in NodeJS/Deno.
|
||||
|
||||
9. `vlib/v/gen/c/json.v` defines the json code generation. This file will be removed once V
|
||||
supports comptime code generation, and it will be possible to do this using the
|
||||
language's tools.
|
||||
|
||||
10. `vlib/v/gen/native` is the directory with all the machine code generation logic. It
|
||||
defines a set of functions that translate assembly instructions to machine code
|
||||
and build the binary from scratch byte by byte. It manually builds all headers,
|
||||
segments, sections, symtable, relocations, etc. Right now it only has basic
|
||||
support of the native platform (ELF, MACHO format).
|
||||
|
||||
The rest of the directories are vlib modules: `builtin/` (strings, arrays,
|
||||
maps), `time/`, `os/`, etc. Their documentation is pretty clear.
|
||||
|
||||
## Example Workflow for Contributing
|
||||
(provided by [@spytheman](https://github.com/spytheman))
|
||||
|
||||
(If you don't already have a GitHub account, please create one. Your GitHub
|
||||
username will be referred to later as 'YOUR_GITHUB_USERNAME'. Change it
|
||||
accordingly in the steps below.)
|
||||
|
||||
1. Fork https://github.com/vlang/v using GitHub's interface to your own account.
|
||||
Let's say that the forked repository is at
|
||||
`https://github.com/YOUR_GITHUB_USERNAME/v` .
|
||||
2. Clone the main v repository https://github.com/vlang/v to a local folder on
|
||||
your computer, say named nv/ (`git clone https://github.com/vlang/v nv`)
|
||||
3. `cd nv`
|
||||
4. `git remote add pullrequest https://github.com/YOUR_GITHUB_USERNAME/v`
|
||||
NB: the remote named `pullrequest` should point to YOUR own forked repo, not the
|
||||
main v repository! After this, your local cloned repository is prepared for
|
||||
making pullrequests, and you can just do normal git operations such as:
|
||||
`git pull` `git status` and so on.
|
||||
|
||||
5. When finished with a feature/bugfix/change, you can:
|
||||
`git checkout -b fix_alabala`
|
||||
- Don't forget to keep formatting standards, run `v fmt -w YOUR_MODIFIED_FILES` before committing
|
||||
6. `git push pullrequest` # (NOTE: the `pullrequest` remote was setup on step 4)
|
||||
7. On GitHub's web interface, go to: https://github.com/vlang/v/pulls
|
||||
|
||||
Here the UI shows a dialog with a button to make a new pull request based on
|
||||
the new pushed branch.
|
||||
(Example dialog: https://url4e.com/gyazo/images/364edc04.png)
|
||||
|
||||
8. After making your pullrequest (aka, PR), you can continue to work on the
|
||||
branch `fix_alabala` ... just do again `git push pullrequest` when you have more
|
||||
commits.
|
||||
|
||||
9. If there are merge conflicts, or a branch lags too much behind V's master,
|
||||
you can do the following:
|
||||
|
||||
1. `git pull --rebase origin master` # solve conflicts and do
|
||||
`git rebase --continue`
|
||||
2. `git push pullrequest -f` # this will overwrite your current remote branch
|
||||
with the updated version of your changes.
|
||||
|
||||
The point of doing the above steps, is to never directly push to the main V
|
||||
repository, *only to your own fork*. Since your local `master` branch tracks the
|
||||
main V repository's master, then `git checkout master`, as well as
|
||||
`git pull --rebase origin master` will continue to work as expected
|
||||
(these are actually used by `v up`) and git can always do it cleanly.
|
||||
|
||||
Git is very flexible, so there are other ways to accomplish the same thing.
|
||||
See the [GitHub flow](https://guides.github.com/introduction/git-handbook/#github), for more information.
|
||||
|
||||
## Using Github's hub CLI tool
|
||||
|
||||
You can download the `hub` tool from https://hub.github.com/ . Using
|
||||
`hub`, you will not need to go through the (sometimes) slow website
|
||||
to make PRs. Most remote operations can be done through the `hub` CLI
|
||||
command.
|
||||
|
||||
NB: You still need to have a GitHub account.
|
||||
|
||||
### Preparation:
|
||||
(steps 1..3 need to be done just *once*):
|
||||
|
||||
1. `hub clone vlang/v my_v`
|
||||
2. `cd my_v`
|
||||
3. `hub fork --remote-name pullrequest`
|
||||
|
||||
4. `git checkout -b my_cool_feature` # Step 4 is better done *once per each new
|
||||
feature/bugfix* that you make.
|
||||
|
||||
### Improve V by making commits:
|
||||
|
||||
5. `git commit -am "math: add a new function copysign"`
|
||||
|
||||
### Testing your commits locally:
|
||||
You can test locally whether your changes have not broken something by
|
||||
running: `v test-all`. See `TESTS.md` for more details.
|
||||
|
||||
### Publishing your commits to GitHub:
|
||||
|
||||
6. `git push pullrequest`
|
||||
|
||||
### Making a PR with `hub`:
|
||||
(so that your changes can be merged to the main V repository)
|
||||
|
||||
7. `hub pull-request`
|
||||
|
||||
Optionally, you can track the status of your PR CI tests with:
|
||||
|
||||
8. `hub ci-status --verbose`
|
||||
|
||||
### Fixing failing tests:
|
||||
If everything is OK, after 5-10 minutes, the CI tests should pass for
|
||||
all platforms. If not, visit the URLs for the failing CI jobs, see
|
||||
which tests have failed and then fix them by making more changes. Just use
|
||||
`git push pullrequest` to publish your changes. The CI tests will
|
||||
run with your updated code. Use `hub ci-status --verbose` to monitor
|
||||
their status.
|
||||
|
||||
## Flags
|
||||
|
||||
V allows you to pass custom flags using `-d my_flag` that can then be checked
|
||||
at compile time (see the documentation about
|
||||
[compile-time if](https://github.com/vlang/v/blob/master/doc/docs.md#compile-time-if)).
|
||||
There are numerous flags that can be passed when building the compiler
|
||||
with `v self` or when creating a copy of the compiler, that will help
|
||||
you when debugging.
|
||||
|
||||
Beware that the flags must be passed when building the compiler,
|
||||
not the program, so do for example: `v -d time_parsing cmd/v` or
|
||||
`v -d trace_checker self`.
|
||||
Some flags can make the compiler very verbose, so it is recommended
|
||||
to create a copy of the compiler rather than replacing it with `v self`.
|
||||
|
||||
| Flag | Usage |
|
||||
|------|-------|
|
||||
| `debugscanner` | Prints debug information during the scanning phase |
|
||||
| `debug_codegen` | Prints automatically generated V code during the scanning phase |
|
||||
| `debug_interface_table` | Prints generated interfaces during C generation |
|
||||
| `debug_interface_type_implements` | Prints debug information when checking that a type implements in interface |
|
||||
| `print_vweb_template_expansions` | Prints vweb compiled HTML files |
|
||||
| `time_checking` | Prints the time spent checking files and other related information |
|
||||
| `time_parsing` | Prints the time spent parsing files and other related information |
|
||||
| `trace_autofree` | Prints details about how/when -autofree puts free() calls |
|
||||
| `trace_autostr` | Prints details about `.str()` method auto-generated by the compiler during C generation |
|
||||
| `trace_ccoptions` | Prints options passed down to the C compiler |
|
||||
| `trace_checker` | Prints details about the statements being checked |
|
||||
| `trace_gen` | Prints strings written to the generated C file. Beware, this flag is very verbose |
|
||||
| `trace_parser` | Prints details about parsed statements and expressions |
|
||||
| `trace_thirdparty_obj_files` | Prints details about built thirdparty obj files |
|
||||
| `trace_usecache` | Prints details when -usecache is used |
|
||||
| `trace_embed_file` | Prints details when $embed_file is used |
|
||||
| `embed_only_metadata` | Embed only the metadata for the file(s) with `$embed_file('somefile')`; faster; for development, *not* distribution |
|
|
@ -0,0 +1,27 @@
|
|||
#same container that golang use
|
||||
FROM buildpack-deps:buster-curl
|
||||
|
||||
LABEL maintainer="ANAGO Ronnel <anagoandy@gmail.com>"
|
||||
WORKDIR /opt/vlang
|
||||
|
||||
ARG USE_LOCAL
|
||||
|
||||
RUN apt-get update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends gcc clang make git && \
|
||||
apt-get clean && rm -rf /var/cache/apt/archives/* && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY . /vlang-local
|
||||
|
||||
RUN if [ -z "${USE_LOCAL}" ] ; then \
|
||||
git clone https://github.com/vlang/v/ /opt/vlang && \
|
||||
rm -rf /vlang-local ; \
|
||||
else \
|
||||
mv /vlang-local/* . && \
|
||||
rm -rf /vlang-local ; \
|
||||
fi
|
||||
|
||||
RUN make && \
|
||||
ln -s /opt/vlang/v /usr/local/bin/v
|
||||
|
||||
CMD [ "v" ]
|
|
@ -0,0 +1,34 @@
|
|||
FROM alpine:3.12
|
||||
|
||||
LABEL maintainer="spytheman <spytheman@bulsynt.org>"
|
||||
|
||||
WORKDIR /opt/vlang
|
||||
|
||||
ENV VVV /opt/vlang
|
||||
ENV PATH /opt/vlang:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
ENV VFLAGS -cc gcc
|
||||
|
||||
RUN mkdir -p /opt/vlang && ln -s /opt/vlang/v /usr/bin/v
|
||||
|
||||
ARG USE_LOCAL
|
||||
|
||||
RUN apk --no-cache add \
|
||||
git make upx gcc bash \
|
||||
musl-dev \
|
||||
openssl-dev sqlite-dev \
|
||||
libx11-dev glfw-dev freetype-dev
|
||||
|
||||
## RUN apk --no-cache add --virtual sdl2deps sdl2-dev sdl2_ttf-dev sdl2_mixer-dev sdl2_image-dev
|
||||
COPY . /vlang-local
|
||||
|
||||
RUN if [[ -z "${USE_LOCAL}" ]] ; then \
|
||||
git clone https://github.com/vlang/v/ /opt/vlang && \
|
||||
rm -rf /vlang-local ; \
|
||||
else \
|
||||
mv /vlang-local/* . && \
|
||||
rm -rf /vlang-local ; \
|
||||
fi
|
||||
|
||||
RUN make && v -version
|
||||
|
||||
CMD ["v"]
|
|
@ -0,0 +1,33 @@
|
|||
FROM alpine:3.16
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
WORKDIR /opt/vlang
|
||||
|
||||
ENV VVV /opt/vlang
|
||||
ENV PATH /opt/vlang:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
ENV VFLAGS -cc gcc -gc none
|
||||
ENV V_PATH /opt/vlang/v
|
||||
|
||||
RUN ln -s /opt/vlang/v /usr/bin/v && \
|
||||
apk --no-cache add \
|
||||
git make gcc curl openssl \
|
||||
musl-dev \
|
||||
openssl-libs-static openssl-dev \
|
||||
zlib-static bzip2-static xz-dev expat-static zstd-static lz4-static \
|
||||
sqlite-static sqlite-dev \
|
||||
libx11-dev glfw-dev freetype-dev \
|
||||
libarchive-static libarchive-dev \
|
||||
diffutils \
|
||||
mandoc
|
||||
|
||||
RUN git clone https://git.rustybever.be/vieter/v /opt/vlang && \
|
||||
make && \
|
||||
v -version
|
||||
|
||||
RUN if [ "$TARGETPLATFORM" = 'linux/amd64' ]; then \
|
||||
wget -O /usr/local/bin/mc https://dl.min.io/client/mc/release/linux-amd64/mc && \
|
||||
chmod +x /usr/local/bin/mc ; \
|
||||
fi
|
||||
|
||||
CMD ["v"]
|
|
@ -0,0 +1,10 @@
|
|||
FROM mstorsjo/llvm-mingw
|
||||
|
||||
LABEL maintainer="Delyan Angelov <delian66@gmail.com>"
|
||||
COPY . .
|
||||
RUN make
|
||||
RUN ./v -os windows -o v.c cmd/v
|
||||
RUN x86_64-w64-mingw32-gcc v.c -std=c99 -w -municode -o v.exe
|
||||
RUN file v.exe
|
||||
|
||||
CMD [ "bash" ]
|
|
@ -0,0 +1,171 @@
|
|||
CC ?= cc
|
||||
CFLAGS ?=
|
||||
LDFLAGS ?=
|
||||
TMPDIR ?= /tmp
|
||||
VROOT ?= .
|
||||
VC ?= ./vc
|
||||
V ?= ./v
|
||||
VCREPO ?= https://git.rustybever.be/vieter/vc
|
||||
TCCREPO ?= https://github.com/vlang/tccbin
|
||||
|
||||
VCFILE := v.c
|
||||
TMPTCC := $(VROOT)/thirdparty/tcc
|
||||
TCCOS := unknown
|
||||
TCCARCH := unknown
|
||||
GITCLEANPULL := git clean -xf && git pull --quiet
|
||||
GITFASTCLONE := git clone --depth 1 --quiet --single-branch
|
||||
|
||||
#### Platform detections and overrides:
|
||||
_SYS := $(shell uname 2>/dev/null || echo Unknown)
|
||||
_SYS := $(patsubst MSYS%,MSYS,$(_SYS))
|
||||
_SYS := $(patsubst MINGW%,MinGW,$(_SYS))
|
||||
|
||||
ifneq ($(filter $(_SYS),MSYS MinGW),)
|
||||
WIN32 := 1
|
||||
V:=./v.exe
|
||||
endif
|
||||
|
||||
ifeq ($(_SYS),Linux)
|
||||
LINUX := 1
|
||||
TCCOS := linux
|
||||
ifneq ($(shell ldd /bin/ls | grep musl),)
|
||||
TCCOS := linuxmusl
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(_SYS),Darwin)
|
||||
MAC := 1
|
||||
TCCOS := macos
|
||||
endif
|
||||
|
||||
ifeq ($(_SYS),FreeBSD)
|
||||
TCCOS := freebsd
|
||||
LDFLAGS += -lexecinfo
|
||||
endif
|
||||
|
||||
ifeq ($(_SYS),NetBSD)
|
||||
TCCOS := netbsd
|
||||
LDFLAGS += -lexecinfo
|
||||
endif
|
||||
|
||||
ifdef ANDROID_ROOT
|
||||
ANDROID := 1
|
||||
undefine LINUX
|
||||
TCCOS := android
|
||||
endif
|
||||
#####
|
||||
|
||||
ifdef WIN32
|
||||
TCCOS := windows
|
||||
VCFILE := v_win.c
|
||||
endif
|
||||
|
||||
TCCARCH := $(shell uname -m 2>/dev/null || echo unknown)
|
||||
|
||||
ifeq ($(TCCARCH),x86_64)
|
||||
TCCARCH := amd64
|
||||
else
|
||||
ifneq ($(filter x86%,$(TCCARCH)),)
|
||||
TCCARCH := i386
|
||||
else
|
||||
ifeq ($(TCCARCH),arm64)
|
||||
TCCARCH := arm64
|
||||
else
|
||||
ifneq ($(filter arm%,$(TCCARCH)),)
|
||||
TCCARCH := arm
|
||||
# otherwise, just use the arch name
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
.PHONY: all clean check fresh_vc fresh_tcc check_for_working_tcc
|
||||
|
||||
ifdef prod
|
||||
VFLAGS+=-prod
|
||||
endif
|
||||
|
||||
all: latest_vc latest_tcc
|
||||
ifdef WIN32
|
||||
$(CC) $(CFLAGS) -std=c99 -municode -w -o v1.exe $(VC)/$(VCFILE) $(LDFLAGS)
|
||||
v1.exe -no-parallel -o v2.exe $(VFLAGS) cmd/v
|
||||
v2.exe -o $(V) $(VFLAGS) cmd/v
|
||||
del v1.exe
|
||||
del v2.exe
|
||||
else
|
||||
$(CC) $(CFLAGS) -std=gnu99 -w -o v1.exe $(VC)/$(VCFILE) -lm -lpthread $(LDFLAGS)
|
||||
./v1.exe -no-parallel -o v2.exe $(VFLAGS) cmd/v
|
||||
./v2.exe -o $(V) $(VFLAGS) cmd/v
|
||||
rm -rf v1.exe v2.exe
|
||||
endif
|
||||
@$(V) run cmd/tools/detect_tcc.v
|
||||
@echo "V has been successfully built"
|
||||
@$(V) -version
|
||||
|
||||
clean:
|
||||
rm -rf $(TMPTCC)
|
||||
rm -rf $(VC)
|
||||
|
||||
ifndef local
|
||||
latest_vc: $(VC)/.git/config
|
||||
cd $(VC) && $(GITCLEANPULL)
|
||||
else
|
||||
latest_vc:
|
||||
@echo "Using local vc"
|
||||
endif
|
||||
|
||||
check_for_working_tcc:
|
||||
@$(TMPTCC)/tcc.exe --version > /dev/null 2> /dev/null || echo "The executable '$(TMPTCC)/tcc.exe' does not work."
|
||||
|
||||
fresh_vc:
|
||||
rm -rf $(VC)
|
||||
$(GITFASTCLONE) $(VCREPO) $(VC)
|
||||
|
||||
ifndef local
|
||||
latest_tcc: $(TMPTCC)/.git/config
|
||||
cd $(TMPTCC) && $(GITCLEANPULL)
|
||||
@$(MAKE) --quiet check_for_working_tcc 2> /dev/null
|
||||
else
|
||||
latest_tcc:
|
||||
@echo "Using local tcc"
|
||||
@$(MAKE) --quiet check_for_working_tcc 2> /dev/null
|
||||
endif
|
||||
|
||||
fresh_tcc:
|
||||
rm -rf $(TMPTCC)
|
||||
ifndef local
|
||||
# Check wether a TCC branch exists for the user's system configuration.
|
||||
ifneq (,$(findstring thirdparty-$(TCCOS)-$(TCCARCH), $(shell git ls-remote --heads $(TCCREPO) | sed 's/^[a-z0-9]*\trefs.heads.//')))
|
||||
$(GITFASTCLONE) --branch thirdparty-$(TCCOS)-$(TCCARCH) $(TCCREPO) $(TMPTCC)
|
||||
@$(MAKE) --quiet check_for_working_tcc 2> /dev/null
|
||||
else
|
||||
@echo 'Pre-built TCC not available for thirdparty-$(TCCOS)-$(TCCARCH) at $(TCCREPO), will use the system compiler: $(CC)'
|
||||
$(GITFASTCLONE) --branch thirdparty-unknown-unknown $(TCCREPO) $(TMPTCC)
|
||||
@$(MAKE) --quiet check_for_working_tcc 2> /dev/null
|
||||
endif
|
||||
else
|
||||
@echo "Using local tccbin"
|
||||
@$(MAKE) --quiet check_for_working_tcc 2> /dev/null
|
||||
endif
|
||||
|
||||
$(TMPTCC)/.git/config:
|
||||
$(MAKE) fresh_tcc
|
||||
|
||||
$(VC)/.git/config:
|
||||
$(MAKE) fresh_vc
|
||||
|
||||
asan:
|
||||
$(MAKE) all CFLAGS='-fsanitize=address,undefined'
|
||||
|
||||
selfcompile:
|
||||
$(V) -cg -o v cmd/v
|
||||
|
||||
selfcompile-static:
|
||||
$(V) -cg -cflags '--static' -o v-static cmd/v
|
||||
|
||||
### NB: Please keep this Makefile and make.bat simple.
|
||||
install:
|
||||
@echo 'Please use `sudo ./v symlink` instead.'
|
||||
|
||||
check:
|
||||
$(V) test-all
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 Alexander Medvednikov
|
||||
Copyright (c) 2019-2021 Alexander Medvednikov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
CC ?= cc
|
||||
VFLAGS ?=
|
||||
CFLAGS ?=
|
||||
LDFLAGS ?=
|
||||
|
||||
.PHONY: all check
|
||||
|
||||
all:
|
||||
rm -rf vc/
|
||||
git clone --depth 1 --quiet https://git.rustybever.be/vieter/vc
|
||||
$(CC) $(CFLAGS) -std=gnu11 -w -o v1 vc/v.c -lm -lexecinfo -lpthread $(LDFLAGS)
|
||||
./v1 -no-parallel -o v2 $(VFLAGS) cmd/v
|
||||
./v2 -o v $(VFLAGS) cmd/v
|
||||
rm -rf v1 v2 vc/
|
||||
@echo "V has been successfully built"
|
||||
./v run ./cmd/tools/detect_tcc.v
|
||||
|
||||
check:
|
||||
./v test-all
|
|
@ -0,0 +1,54 @@
|
|||
# Maintainer: Jef Roosens
|
||||
# This PKGBUILD is mostly copied over from the AUR
|
||||
# https://aur.archlinux.org/packages/vlang-git
|
||||
|
||||
pkgname=vieter-v
|
||||
pkgver=0.2.2.r796.gfbc02cbc5
|
||||
pkgrel=1
|
||||
pkgdesc='Simple, fast, safe, compiled language for developing maintainable software'
|
||||
arch=('x86_64' 'aarch64')
|
||||
url='https://vlang.io'
|
||||
license=('MIT')
|
||||
depends=('glibc')
|
||||
makedepends=('git')
|
||||
optdepends=('glfw: Needed for graphics support'
|
||||
'freetype2: Needed for graphics support'
|
||||
'openssl: Needed for http support')
|
||||
provides=('vlang')
|
||||
conflicts=('v' 'vlang' 'vlang-bin')
|
||||
source=('vlang::git+https://git.rustybever.be/Chewing_Bever/v')
|
||||
sha256sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/vlang"
|
||||
# Weekly tags are considered older than semantic tags that are older than
|
||||
# them, so to prevent version resolution problems we exclude weekly tags.
|
||||
git describe --long --tags --exclude "weekly*" | sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g'
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/vlang"
|
||||
# We don't require optimizations when compiling the bootstrap executable and
|
||||
# -O2 actually breaks `./v self` (resulting in "cgen error:"), so we empty
|
||||
# CFLAGS and LDFLAGS to ensure successful compilation.
|
||||
CFLAGS="" LDFLAGS="" prod=1 make
|
||||
|
||||
# vpm and vdoc fail to compile with "unsupported linker option" when LDFLAGS
|
||||
# is set
|
||||
LDFLAGS="" ./v build-tools
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/vlang"
|
||||
install -d "$pkgdir/usr/lib/vlang" "$pkgdir/usr/share/vlang" "$pkgdir/usr/bin"
|
||||
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
|
||||
install -Dm755 v "$pkgdir/usr/lib/vlang"
|
||||
cp -a cmd "$pkgdir/usr/lib/vlang/"
|
||||
cp -a examples "$pkgdir/usr/share/vlang/"
|
||||
cp -a thirdparty "$pkgdir/usr/lib/vlang/"
|
||||
cp -a vlib "$pkgdir/usr/lib/vlang/"
|
||||
cp v.mod "$pkgdir/usr/lib/vlang/"
|
||||
ln -s /usr/lib/vlang/v "$pkgdir/usr/bin/v"
|
||||
|
||||
touch "$pkgdir/usr/lib/vlang/cmd/tools/.disable_autorecompilation"
|
||||
}
|
305
README.md
305
README.md
|
@ -1,10 +1,305 @@
|
|||
# The V Programming Language
|
||||
<div align="center">
|
||||
<p>
|
||||
<img width="80" src="https://raw.githubusercontent.com/vlang/v-logo/master/dist/v-logo.svg?sanitize=true">
|
||||
</p>
|
||||
<h1>The V Programming Language</h1>
|
||||
|
||||
V is going to be released on June 20, 2019. The source will be released on June 22, 2019.
|
||||
[vlang.io](https://vlang.io) | [Docs](https://github.com/vlang/v/blob/master/doc/docs.md) | [Changelog](https://github.com/vlang/v/blob/master/CHANGELOG.md) | [Speed](https://fast.vlang.io/) | [Contributing & compiler design](https://github.com/vlang/v/blob/master/CONTRIBUTING.md)
|
||||
|
||||
https://vlang.io
|
||||
</div>
|
||||
<div align="center">
|
||||
|
||||
Documentation: https://vlang.io/docs
|
||||
<!--
|
||||
[![Build Status][WorkflowBadge]][WorkflowUrl]
|
||||
-->
|
||||
[![Sponsor][SponsorBadge]][SponsorUrl]
|
||||
[![Patreon][PatreonBadge]][PatreonUrl]
|
||||
[![Discord][DiscordBadge]][DiscordUrl]
|
||||
[![Twitter][TwitterUrl]][TwitterBadge]
|
||||
|
||||
Twitter: https://twitter.com/v_language
|
||||
</div>
|
||||
|
||||
## Key Features of V
|
||||
|
||||
- Simplicity: the language can be learned in less than an hour
|
||||
- Fast compilation: ≈110k loc/s with a Clang backend,
|
||||
≈1 million loc/s with native and tcc backends *(Intel i5-7500, SSD, no optimization)* ([demo video](https://www.youtube.com/watch?v=pvP6wmcl_Sc))
|
||||
- Easy to develop: V compiles itself in less than a second
|
||||
- Performance: as fast as C (V's main backend compiles to human-readable C)
|
||||
- Safety: no null, no globals, no undefined behavior, immutability by default
|
||||
- C to V translation ([Translating DOOM demo video](https://www.youtube.com/watch?v=6oXrz3oRoEg))
|
||||
- Hot code reloading
|
||||
- [Innovative memory management](https://vlang.io/#memory) ([demo video](https://www.youtube.com/watch?v=gmB8ea8uLsM))
|
||||
- [Cross-platform UI library](https://github.com/vlang/ui)
|
||||
- Built-in graphics library
|
||||
- Easy cross-compilation
|
||||
- REPL
|
||||
- [Built-in ORM](https://github.com/vlang/v/blob/master/doc/docs.md#orm)
|
||||
- [Built-in web framework](https://github.com/vlang/v/blob/master/vlib/vweb/README.md)
|
||||
- C and JavaScript backends
|
||||
- Great for writing low-level software ([Vinix OS](https://github.com/vlang/vinix))
|
||||
|
||||
## Stability guarantee and future changes
|
||||
|
||||
Despite being at an early development stage, the V language is relatively stable and has
|
||||
backwards compatibility guarantee, meaning that the code you write today is guaranteed
|
||||
to work a month, a year, or five years from now.
|
||||
|
||||
There still may be minor syntax changes before the 1.0 release, but they will be handled
|
||||
automatically via `vfmt`, as has been done in the past.
|
||||
|
||||
The V core APIs (primarily the `os` module) will still have minor changes until
|
||||
they are stabilized in V 1.0. Of course the APIs will grow after that, but without breaking
|
||||
existing code.
|
||||
|
||||
Unlike many other languages, V is not going to be always changing, with new features
|
||||
being introduced and old features modified. It is always going to be a small and simple
|
||||
language, very similar to the way it is right now.
|
||||
|
||||
## Installing V - from source *(preferred method)*
|
||||
|
||||
### Linux, macOS, Windows, *BSD, Solaris, WSL, Android, etc.
|
||||
|
||||
Usually installing V is quite simple if you have an environment that already has a
|
||||
functional `git` installation.
|
||||
|
||||
* *(* ***PLEASE NOTE:*** *If you run into any trouble or you have a different operating
|
||||
system or Linux distribution that doesn't install or work immediately, please see
|
||||
[Installation Issues](https://github.com/vlang/v/discussions/categories/installation-issues)
|
||||
and search for your OS and problem. If you can't find your problem, please add it to an
|
||||
existing discussion if one exists for your OS, or create a new one if a main discussion
|
||||
doesn't yet exist for your OS.)*
|
||||
|
||||
|
||||
To get started, simply try to execute the following in your terminal/shell:
|
||||
```bash
|
||||
git clone https://github.com/vlang/v
|
||||
cd v
|
||||
make
|
||||
# HINT: Using Windows?: run make.bat in the cmd.exe shell
|
||||
```
|
||||
|
||||
That should be it and you should find your V executable at `[path to V repo]/v`.
|
||||
`[path to V repo]` can be anywhere.
|
||||
|
||||
(As in the hint above, on Windows `make` means running `make.bat`, so make sure you use
|
||||
the `cmd.exe` terminal.)
|
||||
|
||||
Now you can try `./v run examples/hello_world.v` (`v.exe` on Windows).
|
||||
|
||||
* *Trouble? Please see the note above and link to
|
||||
[Installation Issues](https://github.com/vlang/v/discussions/categories/installation-issues) for help.*
|
||||
|
||||
V is constantly being updated. To update V, simply run:
|
||||
|
||||
```bash
|
||||
v up
|
||||
```
|
||||
|
||||
### C compiler
|
||||
|
||||
It's recommended to use Clang, GCC, or Visual Studio.
|
||||
If you are doing development, you most likely already have one of those installed.
|
||||
|
||||
Otherwise, follow these instructions:
|
||||
|
||||
- [Installing a C compiler on Linux and macOS](https://github.com/vlang/v/wiki/Installing-a-C-compiler-on-Linux-and-macOS)
|
||||
|
||||
- [Installing a C compiler on Windows](https://github.com/vlang/v/wiki/Installing-a-C-compiler-on-Windows)
|
||||
|
||||
However, if none is found when running `make` on Linux or Windows,
|
||||
TCC is downloaded as the default C backend.
|
||||
It's very lightweight (several MB) so this shouldn't take too long.
|
||||
|
||||
### Symlinking
|
||||
|
||||
NB: it is *highly recommended*, that you put V on your PATH. That saves
|
||||
you the effort to type in the full path to your v executable every time.
|
||||
V provides a convenience `v symlink` command to do that more easily.
|
||||
|
||||
On Unix systems, it creates a `/usr/local/bin/v` symlink to your
|
||||
executable. To do that, run:
|
||||
|
||||
```bash
|
||||
sudo ./v symlink
|
||||
```
|
||||
|
||||
On Windows, start a new shell with administrative privileges, for
|
||||
example by <kbd>Windows Key</kbd>, then type `cmd.exe`, right-click on its menu
|
||||
entry, and choose `Run as administrator`. In the new administrative
|
||||
shell, cd to the path, where you have compiled v.exe, then type:
|
||||
|
||||
```bat
|
||||
.\v.exe symlink
|
||||
```
|
||||
|
||||
That will make V available everywhere, by adding it to your PATH.
|
||||
Please restart your shell/editor after that, so that it can pick
|
||||
the new PATH variable.
|
||||
|
||||
NB: there is no need to run `v symlink` more than once - v will
|
||||
continue to be available, even after `v up`, restarts, and so on.
|
||||
You only need to run it again, if you decide to move the V repo
|
||||
folder somewhere else.
|
||||
|
||||
### Docker
|
||||
|
||||
<details><summary>Expand Docker instructions</summary>
|
||||
|
||||
```bash
|
||||
git clone https://github.com/vlang/v
|
||||
cd v
|
||||
docker build -t vlang .
|
||||
docker run --rm -it vlang:latest
|
||||
```
|
||||
|
||||
### Docker with Alpine/musl
|
||||
|
||||
```bash
|
||||
git clone https://github.com/vlang/v
|
||||
cd v
|
||||
docker build -t vlang --file=Dockerfile.alpine .
|
||||
docker run --rm -it vlang:latest
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Testing and running the examples
|
||||
|
||||
Make sure V can compile itself:
|
||||
|
||||
```bash
|
||||
v self
|
||||
```
|
||||
|
||||
```bash
|
||||
$ v
|
||||
V 0.2.x
|
||||
Use Ctrl-C or `exit` to exit
|
||||
|
||||
>>> println('hello world')
|
||||
hello world
|
||||
>>>
|
||||
```
|
||||
|
||||
```bash
|
||||
cd examples
|
||||
v hello_world.v && ./hello_world # or simply
|
||||
v run hello_world.v # this builds the program and runs it right away
|
||||
|
||||
v run word_counter/word_counter.v word_counter/cinderella.txt
|
||||
v run news_fetcher.v
|
||||
v run tetris/tetris.v
|
||||
```
|
||||
|
||||
<img src='https://raw.githubusercontent.com/vlang/v/master/examples/tetris/screenshot.png' width=300>
|
||||
|
||||
NB: In order to build Tetris or 2048 (or anything else using `sokol` or `gg` graphics modules)
|
||||
on some Linux systems, you need to install `libxi-dev` and `libxcursor-dev` .
|
||||
|
||||
## V net.http, net.websocket, `v install`
|
||||
If you plan to use the net.http module, or the net.websocket module, you also need to install
|
||||
OpenSSL on non-Windows systems:
|
||||
|
||||
```bash
|
||||
macOS:
|
||||
brew install openssl
|
||||
|
||||
Debian/Ubuntu:
|
||||
sudo apt install libssl-dev
|
||||
|
||||
Arch/Manjaro:
|
||||
openssl is installed by default
|
||||
|
||||
Fedora:
|
||||
sudo dnf install openssl-devel
|
||||
```
|
||||
|
||||
## V sync
|
||||
V's `sync` module and channel implementation uses libatomic.
|
||||
It is most likely already installed on your system, but if not,
|
||||
you can install it, by doing the following:
|
||||
```bash
|
||||
MacOS: already installed
|
||||
|
||||
Debian/Ubuntu:
|
||||
sudo apt install libatomic1
|
||||
|
||||
Fedora/CentOS/RH:
|
||||
sudo dnf install libatomic-static
|
||||
```
|
||||
|
||||
## V UI
|
||||
|
||||
<a href="https://github.com/vlang/ui">
|
||||
<img src='https://raw.githubusercontent.com/vlang/ui/master/examples/screenshot.png' width=712>
|
||||
</a>
|
||||
|
||||
https://github.com/vlang/ui
|
||||
|
||||
<!---
|
||||
## JavaScript backend
|
||||
|
||||
[examples/hello_v_js.v](examples/hello_v_js.v):
|
||||
|
||||
```v
|
||||
fn main() {
|
||||
for i in 0 .. 3 {
|
||||
println('Hello from V.js')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
v -o hi.js examples/hello_v_js.v && node hi.js
|
||||
Hello from V.js
|
||||
Hello from V.js
|
||||
Hello from V.js
|
||||
```
|
||||
-->
|
||||
|
||||
## Android graphical apps
|
||||
|
||||
With V's `vab` tool, building V UI and graphical apps for Android can become as easy as:
|
||||
|
||||
```
|
||||
./vab /path/to/v/examples/2048
|
||||
```
|
||||
|
||||
[https://github.com/vlang/vab](https://github.com/vlang/vab).
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/768942/107622846-c13f3900-6c58-11eb-8a66-55db12979b73.png">
|
||||
|
||||
## Developing web applications
|
||||
|
||||
Check out the [Building a simple web blog](https://github.com/vlang/v/blob/master/tutorials/building_a_simple_web_blog_with_vweb/README.md)
|
||||
tutorial and Gitly, a light and fast alternative to GitHub/GitLab:
|
||||
|
||||
https://github.com/vlang/gitly
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/687996/85933714-b195fe80-b8da-11ea-9ddd-09cadc2103e4.png">
|
||||
|
||||
## Vinix, an OS/kernel written in V
|
||||
|
||||
V is great for writing low-level software like drivers and kernels.
|
||||
Vinix is an OS/kernel that already runs bash, GCC, V, and nano.
|
||||
|
||||
https://github.com/vlang/vinix
|
||||
|
||||
<img src="https://github.com/vlang/vinix/raw/main/screenshot.png?raw=true">
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
Please see the [Troubleshooting](https://github.com/vlang/v/wiki/Troubleshooting) section on our [wiki page](https://github.com/vlang/v/wiki)
|
||||
|
||||
[WorkflowBadge]: https://github.com/vlang/v/workflows/CI/badge.svg
|
||||
[DiscordBadge]: https://img.shields.io/discord/592103645835821068?label=Discord&logo=discord&logoColor=white
|
||||
[PatreonBadge]: https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Dvlang%26type%3Dpledges
|
||||
[SponsorBadge]: https://camo.githubusercontent.com/da8bc40db5ed31e4b12660245535b5db67aa03ce/68747470733a2f2f696d672e736869656c64732e696f2f7374617469632f76313f6c6162656c3d53706f6e736f72266d6573736167653d254532253944254134266c6f676f3d476974487562
|
||||
[TwitterBadge]: https://twitter.com/v_language
|
||||
|
||||
[WorkflowUrl]: https://github.com/vlang/v/commits/master
|
||||
[DiscordUrl]: https://discord.gg/vlang
|
||||
[PatreonUrl]: https://patreon.com/vlang
|
||||
[SponsorUrl]: https://github.com/sponsors/medvednikov
|
||||
[TwitterUrl]: https://img.shields.io/twitter/follow/v_language.svg?style=flatl&label=Follow&logo=twitter&logoColor=white&color=1da1f2
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
## [Version 0.3](https://github.com/vlang/v/projects/5)
|
||||
- [ ] [make `-autofree` the default](https://github.com/vlang/v/issues/6989)
|
||||
- [x] [gc option]
|
||||
- [ ] [coroutines](https://github.com/vlang/v/discussions/11582)
|
||||
- [x] channels
|
||||
- [x] lock{}
|
||||
- [x] thread safe arrays
|
||||
- [ ] [thread safe maps](https://github.com/vlang/v/discussions/11729)
|
||||
- [ ] [C2V translator](https://github.com/vlang/v/issues/6985)
|
||||
- [ ] doom.v
|
||||
- [x] rune type
|
||||
- [x] replace `ustring` with `[]rune`
|
||||
- [x] fix `byte.str()`
|
||||
- [x] maps with non-string keys
|
||||
- [x] iOS/Android support
|
||||
- [ ] parallel parser
|
||||
- [ ] parallel checker
|
||||
- [x] parallel cgen
|
||||
- [ ] parallel C compilation
|
||||
- [ ] `recover()` from panics
|
||||
- [x] IO streams
|
||||
- [x] struct embedding
|
||||
- [x] interface embedding
|
||||
- [x] interfaces: allow struct fields (not just methods)
|
||||
- [ ] vfmt: fix common errors automatically (make vars mutable and vice versa, add missing imports)
|
||||
- [ ] method expressions with an explicit receiver as the first argument
|
||||
- [x] short generics syntax (`foo(5)` instead of `foo<int>(5)`)
|
||||
- [ ] fix all remaining generics issues
|
||||
- [ ] merge v.c and v_win.c
|
||||
- [x] more advanced errors, not just `error('message')`
|
||||
- [ ] VLS for autocomplete, refactoring, go to definition etc
|
||||
- [ ] Recursive structs via optionals: `struct Node { next ?Node }`
|
||||
- [ ] Remove `foo = 0` for `&Foo`
|
||||
- [ ] Handle function pointers safely, remove `if function == 0 {`
|
|
@ -0,0 +1,177 @@
|
|||
# Automated tests
|
||||
|
||||
TLDR: do run `v test-all` locally, after making your changes,
|
||||
and before submitting PRs.
|
||||
|
||||
Tip: use `v -cc tcc` when compiling tests, because TCC is much faster,
|
||||
compared to most other C compilers like clang/gcc/msvc. Most test commands
|
||||
will use the V compiler and the V tools many times, potentially
|
||||
hundreds/thousands of times.
|
||||
|
||||
## `v test-all`
|
||||
|
||||
Test and build *everything*. Usefull to verify *locally*, that the CI will
|
||||
most likely pass. Slowest, but most comprehensive.
|
||||
|
||||
It works, by running these in succession:
|
||||
* `v test-cleancode`
|
||||
* `v test-self`
|
||||
* `v test-fmt`
|
||||
* `v build-tools`
|
||||
* `v build-examples`
|
||||
* `v check-md -hide-warnings .`
|
||||
* `v install nedpals.args`
|
||||
|
||||
# Details:
|
||||
In the `v` repo there are many tests. The main types are:
|
||||
|
||||
## `_test.v` tests - these are the normal V test files.
|
||||
All `test_` functions in these files, will be ran automatically by
|
||||
V's test framework.
|
||||
|
||||
NB 1: You can run test files one by one, with:
|
||||
`v file_test.v` - this will run the test_ functions in file_test.v,
|
||||
and will exit with a 0 exit code, if they all had 0 failing assertions.
|
||||
|
||||
`v -stats file_test.v` - this will run the test_ functions, and show a
|
||||
report about how much time it took to run each of them too.
|
||||
|
||||
NB 2: You can also run many test files at once (in parallel, depending on
|
||||
how many cores you have), with:
|
||||
`v test folder` - this will run *all* `_test.v` files in `folder`,
|
||||
recursively.
|
||||
|
||||
`v -stats test folder` - same, but will also produce timing reports
|
||||
about how fast each test_ function in each _test.v file ran.
|
||||
|
||||
|
||||
## `v test vlib/v/tests`:
|
||||
|
||||
This folder contains _test.v files, testing the different features of the V
|
||||
compiler. Each of them will be compiled, and all the features in them have
|
||||
to work (verified by assertions).
|
||||
|
||||
## `v vlib/v/tests/inout/compiler_test.v`
|
||||
|
||||
This is a *test runner*, that checks whether the output of running a V program,
|
||||
matches an expected .out file. You can also check for code that does panic
|
||||
using this test runner - just paste the start of the `panic()` output in the
|
||||
corresponding .out file.
|
||||
|
||||
NB: these tests, expect to find a pair of `.vv` and `.out` files, in the folder:
|
||||
vlib/v/tests/inout
|
||||
|
||||
The test runner will run each `.vv` file, and will check that its output, matches
|
||||
the contents of the `.out` file with the same base name. This is particularly useful
|
||||
for checking that errors and panics are printed.
|
||||
|
||||
## `v vlib/v/gen/c/coutput_test.v`
|
||||
|
||||
coutput_test.v is a *test runner*, that checks whether the generated C source
|
||||
code matches *all* expectations, specified in *.c.must_have files, in the
|
||||
folder vlib/v/gen/c/testdata/ .
|
||||
|
||||
Each `.c.must_have` file, *has* to have a corresponding `.vv` file.
|
||||
|
||||
Each `.c.must_have` file, consists of multiple lines. Each of these
|
||||
lines, *should* be present *at least once* in the output, when the .vv
|
||||
file is compiled with `-o -` .
|
||||
|
||||
## `v vlib/v/tests/run_project_folders_test.v`
|
||||
This *test runner*, checks whether whole project folders, can be compiled, and run.
|
||||
|
||||
NB: Each project in these folders, should finish with an exit code of 0,
|
||||
and it should output `OK` as its last stdout line.
|
||||
|
||||
## `v vlib/v/tests/known_errors/known_errors_test.v`
|
||||
This *test runner*, checks whether a known program, that was expected to compile,
|
||||
but did NOT, due to a buggy checker, parser or cgen, continues to fail.
|
||||
The negative programs are collected in the `vlib/v/tests/known_errors/testdata/` folder.
|
||||
Each of them should FAIL to compile, due to a known/confirmed compiler bug/limitation.
|
||||
|
||||
The intended use of this, is for providing samples, that currently do NOT compile,
|
||||
but that a future compiler improvement WILL be able to compile, and to
|
||||
track, whether they were not fixed incidentally, due to an unrelated
|
||||
change/improvement. For example, code that triggers generating invalid C code can go here,
|
||||
and later when a bug is fixed, can be moved to a proper _test.v or .vv/.out pair, outside of
|
||||
the `vlib/v/tests/known_errors/testdata/` folder.
|
||||
|
||||
|
||||
## Test building of actual V programs (examples, tools, V itself)
|
||||
|
||||
* `v build-tools`
|
||||
* `v build-examples`
|
||||
* `v build-vbinaries`
|
||||
|
||||
## Formatting tests
|
||||
|
||||
In `vlib/v/fmt/` there are:
|
||||
|
||||
* `v vlib/v/fmt/fmt_test.v`
|
||||
|
||||
This checks `.out` tests.
|
||||
|
||||
* `v vlib/v/fmt/fmt_keep_test.v`
|
||||
|
||||
This verifies that all `_keep.vv` files in the `vlib/v/fmt/tests/` folder,
|
||||
would be unchanged by `v fmt -w`, i.e. that the v source code formatter,
|
||||
generates a stable source output, that does not change, once it is already
|
||||
formatted once.
|
||||
|
||||
* `v vlib/v/fmt/fmt_vlib_test.v`
|
||||
|
||||
This checks that all V source files are formatted, and prints a summary.
|
||||
This is not required.
|
||||
|
||||
* `v test-cleancode`
|
||||
|
||||
Check that most .v files, are invariant of `v fmt` runs.
|
||||
|
||||
* `v test-fmt`
|
||||
|
||||
This tests that all .v files in the current folder are already formatted.
|
||||
It is useful for adding to CI jobs, to guarantee, that future contributions
|
||||
will keep the existing source nice and clean.
|
||||
|
||||
## Markdown/documentation checks:
|
||||
|
||||
* `v check-md -hide-warnings .`
|
||||
|
||||
Ensure that all .md files in the project are formatted properly,
|
||||
and that the V code block examples in them can be compiled/formatted too.
|
||||
|
||||
## `v test-self`
|
||||
|
||||
Run `vlib` module tests, *including* the compiler tests.
|
||||
|
||||
## `v vlib/v/compiler_errors_test.v`
|
||||
|
||||
This runs tests for:
|
||||
* `vlib/v/scanner/tests/*.vv`
|
||||
* `vlib/v/checker/tests/*.vv`
|
||||
* `vlib/v/parser/tests/*.vv`
|
||||
|
||||
NB: there are special folders, that compiler_errors_test.v will try to
|
||||
run/compile with specific options:
|
||||
|
||||
vlib/v/checker/tests/globals_run/ - `-enable-globals run`;
|
||||
results stored in `.run.out` files, matching the .vv ones.
|
||||
|
||||
NB 2: in case you need to modify many .out files, run *twice* in a row:
|
||||
`VAUTOFIX=1 ./v vlib/v/compiler_errors_test.v`
|
||||
This will fail the first time, but it will record the new output for each
|
||||
.vv file, and store it into the corresponding .out file. The second run
|
||||
should be now successfull, and so you can inspect the difference, and
|
||||
commit the new .out files with minimum manual effort.
|
||||
|
||||
NB 3: To run only some of the tests, use:
|
||||
`VTEST_ONLY=mismatch ./v vlib/v/compiler_errors_test.v`
|
||||
This will check only the .vv files, whose paths match the given filter.
|
||||
|
||||
## `.github/workflows/ci.yml`
|
||||
|
||||
This is a Github Actions configuration file, that runs various CI
|
||||
tests in the main V repository, for example:
|
||||
|
||||
* `v vet vlib/v` - run a style checker.
|
||||
* `v test-self` (run self tests) in various compilation modes.
|
|
@ -1,49 +0,0 @@
|
|||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
module base64
|
||||
|
||||
const (
|
||||
Index = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
62, 63, 62, 62, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 63, 0, 26, 27, 28, 29,
|
||||
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
|
||||
47, 48, 49, 50, 51]
|
||||
)
|
||||
|
||||
fn decode(data string) string {
|
||||
p := data.cstr()
|
||||
len := data.len
|
||||
mut pad := 0
|
||||
if len > 0 && (len % 4 != 0 || p[len - 1] == `=`) {
|
||||
pad = 1
|
||||
}
|
||||
L := ((len + 3) / 4 - pad) * 4
|
||||
str_len := L / 4 * 3 + pad
|
||||
mut str := malloc(str_len + 2)
|
||||
mut j := 0
|
||||
for i := 0; i < L; i += 4 {
|
||||
n := (Index[p[i]] << 18) | (Index[p[i + 1]] << 12) |
|
||||
(Index[p[i + 2]] << 6) | (Index[p[i + 3]])
|
||||
str[j] = n >> 16
|
||||
j++
|
||||
str[j] = n >> 8 & 0xff
|
||||
j++
|
||||
str[j] = n & 0xff
|
||||
j++
|
||||
}
|
||||
if pad > 0 {
|
||||
mut nn := (Index[p[L]] << 18) | (Index[p[L + 1]] << 12)
|
||||
str[str_len - 1] = nn >> 16
|
||||
if len > L + 2 && p[L + 2] != `=` {
|
||||
nn = nn | (Index[p[L + 2]] << 6)
|
||||
str[str_len] = nn >> 8 & 0xff
|
||||
}
|
||||
}
|
||||
str[str_len + 1] = `\0`
|
||||
return string(str)
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
import base64
|
||||
|
||||
fn test_decode() {
|
||||
assert base64.decode('TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=')
|
||||
== 'Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.'
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
module main
|
||||
|
||||
import hash.fnv1a
|
||||
import hash as wyhash
|
||||
import rand
|
||||
import benchmark
|
||||
|
||||
fn main() {
|
||||
rand.seed([u32(42), 0])
|
||||
sample_size := 10000000
|
||||
min_str_len := 20
|
||||
max_str_len := 40
|
||||
println('Generating $sample_size strings between $min_str_len - $max_str_len chars long...')
|
||||
mut checksum := u64(0)
|
||||
mut start_pos := 0
|
||||
mut bgenerating := benchmark.start()
|
||||
mut bytepile := []u8{}
|
||||
for _ in 0 .. sample_size * max_str_len {
|
||||
bytepile << u8(rand.int_in_range(40, 125) or { 40 })
|
||||
}
|
||||
mut str_lens := []int{}
|
||||
for _ in 0 .. sample_size {
|
||||
str_lens << rand.int_in_range(min_str_len, max_str_len) or { min_str_len }
|
||||
}
|
||||
bgenerating.measure('generating strings')
|
||||
println('Hashing each of the generated strings...')
|
||||
//
|
||||
mut bhashing_1 := benchmark.start()
|
||||
start_pos = 0
|
||||
checksum = 0
|
||||
for len in str_lens {
|
||||
end_pos := start_pos + len
|
||||
checksum ^= wyhash.wyhash_c(unsafe { &u8(bytepile.data) + start_pos }, u64(len),
|
||||
1)
|
||||
start_pos = end_pos
|
||||
}
|
||||
bhashing_1.measure('wyhash.wyhash_c | checksum: ${checksum:22}')
|
||||
mut bhashing_2 := benchmark.start()
|
||||
start_pos = 0
|
||||
checksum = 0
|
||||
for len in str_lens {
|
||||
end_pos := start_pos + len
|
||||
checksum ^= wyhash.sum64(bytepile[start_pos..end_pos], 1)
|
||||
start_pos = end_pos
|
||||
}
|
||||
bhashing_2.measure('wyhash.sum64 | checksum: ${checksum:22}')
|
||||
mut bhashing_3 := benchmark.start()
|
||||
start_pos = 0
|
||||
checksum = 0
|
||||
for len in str_lens {
|
||||
end_pos := start_pos + len
|
||||
checksum ^= fnv1a.sum64(bytepile[start_pos..end_pos])
|
||||
start_pos = end_pos
|
||||
}
|
||||
bhashing_3.measure('fnv1a.sum64 | checksum: ${checksum:22}')
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
module main
|
||||
|
||||
import v.builder.cbuilder
|
||||
|
||||
// TODO: change bootstrapping to use the C code generated from
|
||||
// `VEXE=v cmd/tools/builders/c_builder -os cross -o c.c cmd/tools/builders/c_builder.v`
|
||||
// See also `cmd/v/v.v`
|
||||
|
||||
fn main() {
|
||||
cbuilder.start()
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
module main
|
||||
|
||||
import v.builder.interpreterbuilder
|
||||
|
||||
fn main() {
|
||||
interpreterbuilder.start()
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
module main
|
||||
|
||||
import v.builder.jsbuilder
|
||||
|
||||
fn main() {
|
||||
jsbuilder.start()
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
module main
|
||||
|
||||
import v.builder.nativebuilder
|
||||
|
||||
fn main() {
|
||||
nativebuilder.start()
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
module main
|
||||
|
||||
import os
|
||||
import v.util
|
||||
import v.util.diff
|
||||
import v.pref
|
||||
import v.builder
|
||||
import v.builder.cbuilder
|
||||
import v.ast
|
||||
import rand
|
||||
import term
|
||||
|
||||
const (
|
||||
base_os = 'linux'
|
||||
os_names = ['linux', 'macos', 'windows']
|
||||
skip_modules = [
|
||||
'builtin.bare',
|
||||
'builtin.linux_bare.old',
|
||||
'builtin.js',
|
||||
'strconv',
|
||||
'strconv.ftoa',
|
||||
'hash',
|
||||
'strings',
|
||||
'crypto.rand',
|
||||
'os.bare',
|
||||
'os2',
|
||||
'picohttpparser',
|
||||
'picoev',
|
||||
'szip',
|
||||
'v.eval',
|
||||
]
|
||||
)
|
||||
|
||||
struct App {
|
||||
diff_cmd string
|
||||
is_verbose bool
|
||||
modules []string
|
||||
mut:
|
||||
api_differences map[string]int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
vexe := pref.vexe_path()
|
||||
vroot := os.dir(vexe)
|
||||
util.set_vroot_folder(vroot)
|
||||
os.chdir(vroot)?
|
||||
cmd := diff.find_working_diff_command() or { '' }
|
||||
mut app := App{
|
||||
diff_cmd: cmd
|
||||
is_verbose: os.getenv('VERBOSE').len > 0
|
||||
modules: if os.args.len > 1 { os.args[1..] } else { all_vlib_modules() }
|
||||
}
|
||||
for mname in app.modules {
|
||||
if !app.is_verbose {
|
||||
eprintln('Checking module: $mname ...')
|
||||
}
|
||||
api_base := app.gen_api_for_module_in_os(mname, base_os)
|
||||
for oname in os_names {
|
||||
if oname == base_os {
|
||||
continue
|
||||
}
|
||||
api_os := app.gen_api_for_module_in_os(mname, oname)
|
||||
app.compare_api(api_base, api_os, mname, base_os, oname)
|
||||
}
|
||||
}
|
||||
howmany := app.api_differences.len
|
||||
if howmany > 0 {
|
||||
eprintln(term.header('Found $howmany modules with different APIs', '='))
|
||||
for m in app.api_differences.keys() {
|
||||
eprintln('Module: $m')
|
||||
}
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
fn all_vlib_modules() []string {
|
||||
mut vlib_v_files := os.walk_ext('vlib', '.v')
|
||||
mut vmodulesmap := map[string]int{}
|
||||
for f in vlib_v_files {
|
||||
if f.contains('/tests/') || f.ends_with('_test.v') {
|
||||
continue
|
||||
}
|
||||
vmodulename := os.dir(f).replace('/', '.').replace('vlib.', '')
|
||||
if vmodulename in skip_modules {
|
||||
continue
|
||||
}
|
||||
vmodulesmap[vmodulename] = vmodulesmap[vmodulename] + 1
|
||||
}
|
||||
mut modules := vmodulesmap.keys()
|
||||
modules.sort()
|
||||
return modules
|
||||
}
|
||||
|
||||
fn (app App) gen_api_for_module_in_os(mod_name string, os_name string) string {
|
||||
if app.is_verbose {
|
||||
eprintln('Checking module: ${mod_name:-30} for OS: ${os_name:-10} ...')
|
||||
}
|
||||
mpath := os.join_path('vlib', mod_name.replace('.', '/'))
|
||||
tmpname := '/tmp/${mod_name}_${os_name}.c'
|
||||
prefs, _ := pref.parse_args([], ['-os', os_name, '-o', tmpname, '-shared', mpath])
|
||||
mut b := builder.new_builder(prefs)
|
||||
cbuilder.compile_c(mut b)
|
||||
mut res := []string{}
|
||||
for f in b.parsed_files {
|
||||
for s in f.stmts {
|
||||
if s is ast.FnDecl {
|
||||
if s.is_pub {
|
||||
fn_signature := s.stringify(b.table, mod_name, map[string]string{})
|
||||
fn_mod := s.modname()
|
||||
if fn_mod == mod_name {
|
||||
fline := '$fn_mod: $fn_signature'
|
||||
res << fline
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
res.sort()
|
||||
return res.join('\n')
|
||||
}
|
||||
|
||||
fn (mut app App) compare_api(api_base string, api_os string, mod_name string, os_base string, os_target string) {
|
||||
res := diff.color_compare_strings(app.diff_cmd, rand.ulid(), api_base, api_os)
|
||||
if res.len > 0 {
|
||||
summary := 'Different APIs found for module: `$mod_name`, between OS base: `$os_base` and OS: `$os_target`'
|
||||
eprintln(term.header(summary, '-'))
|
||||
eprintln(res)
|
||||
eprintln(term.h_divider('-'))
|
||||
app.api_differences[mod_name] = 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
fn main() {
|
||||
$if tinyc {
|
||||
println('Your `tcc` is working. Good - it is much faster at compiling C source code.')
|
||||
exit(0)
|
||||
}
|
||||
|
||||
$if !macos {
|
||||
println('
|
||||
Note: `tcc` was not used, so unless you install it yourself, your backend
|
||||
C compiler will be `cc`, which is usually either `clang`, `gcc` or `msvc`.
|
||||
|
||||
These C compilers, are several times slower at compiling C source code,
|
||||
compared to `tcc`. They do produce more optimised executables, but that
|
||||
is done at the cost of compilation speed.
|
||||
')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
fast
|
||||
index.html
|
||||
table.html
|
||||
v.c
|
||||
v2
|
|
@ -0,0 +1,200 @@
|
|||
// Copyright (c) 2019-2022 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
import os
|
||||
import time
|
||||
|
||||
const voptions = ' -usecache -skip-unused -show-timings -stats '
|
||||
|
||||
const exe = os.executable()
|
||||
|
||||
const fast_dir = os.dir(exe)
|
||||
|
||||
const vdir = @VEXEROOT
|
||||
|
||||
fn main() {
|
||||
dump(fast_dir)
|
||||
dump(vdir)
|
||||
os.chdir(fast_dir)?
|
||||
if !os.exists('$vdir/v') && !os.is_dir('$vdir/vlib') {
|
||||
println('fast.html generator needs to be located in `v/cmd/tools/fast`')
|
||||
}
|
||||
println('fast.html generator\n')
|
||||
if !os.args.contains('-noupdate') {
|
||||
println('Fetching updates...')
|
||||
ret := os.system('$vdir/v up')
|
||||
if ret != 0 {
|
||||
println('failed to update V')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// fetch the last commit's hash
|
||||
commit := exec('git rev-parse HEAD')[..8]
|
||||
if !os.exists('table.html') {
|
||||
os.create('table.html')?
|
||||
}
|
||||
mut table := os.read_file('table.html')?
|
||||
if os.exists('website/index.html') {
|
||||
uploaded_index := os.read_file('website/index.html')?
|
||||
if uploaded_index.contains('>$commit<') {
|
||||
println('nothing to benchmark')
|
||||
exit(1)
|
||||
return
|
||||
}
|
||||
}
|
||||
message := exec('git log --pretty=format:"%s" -n1 $commit')
|
||||
println('\nBenchmarking commit $commit "$message"')
|
||||
|
||||
// build an optimized V
|
||||
println(' Building vprod...')
|
||||
os.chdir(vdir)?
|
||||
if os.args.contains('-noprod') {
|
||||
exec('./v -o vprod cmd/v') // for faster debugging
|
||||
} else {
|
||||
exec('./v -o vprod -prod -prealloc cmd/v')
|
||||
}
|
||||
|
||||
// cache vlib modules
|
||||
exec('$vdir/v wipe-cache')
|
||||
exec('$vdir/v -o v2 -prod cmd/v')
|
||||
|
||||
// measure
|
||||
diff1 := measure('$vdir/vprod $voptions -o v.c cmd/v', 'v.c')
|
||||
mut tcc_path := 'tcc'
|
||||
$if freebsd {
|
||||
tcc_path = '/usr/local/bin/tcc'
|
||||
if vdir.contains('/tmp/cirrus-ci-build') {
|
||||
tcc_path = 'clang'
|
||||
}
|
||||
}
|
||||
if os.args.contains('-clang') {
|
||||
tcc_path = 'clang'
|
||||
}
|
||||
|
||||
diff2 := measure('$vdir/vprod $voptions -cc $tcc_path -o v2 cmd/v', 'v2')
|
||||
diff3 := 0 // measure('$vdir/vprod -native $vdir/cmd/tools/1mil.v', 'native 1mil')
|
||||
diff4 := measure('$vdir/vprod -usecache $voptions -cc clang examples/hello_world.v',
|
||||
'hello.v')
|
||||
vc_size := os.file_size('v.c') / 1000
|
||||
scan, parse, check, cgen, vlines := measure_steps(vdir)
|
||||
|
||||
commit_date := exec('git log -n1 --pretty="format:%at" $commit')
|
||||
date := time.unix(commit_date.int())
|
||||
|
||||
os.chdir(fast_dir)?
|
||||
mut out := os.create('table.html')?
|
||||
|
||||
// place the new row on top
|
||||
html_message := message.replace_each(['<', '<', '>', '>'])
|
||||
table =
|
||||
' <tr>
|
||||
<td>$date.format()</td>
|
||||
<td><a target=_blank href="https://github.com/vlang/v/commit/$commit">$commit</a></td>
|
||||
<td>$html_message</td>
|
||||
<td>${diff1}ms</td>
|
||||
<td>${diff2}ms</td>
|
||||
<td>${diff3}ms</td>
|
||||
<td>${diff4}ms</td>
|
||||
<td>$vc_size KB</td>
|
||||
<td>${parse}ms</td>
|
||||
<td>${check}ms</td>
|
||||
<td>${cgen}ms</td>
|
||||
<td>${scan}ms</td>
|
||||
<td>$vlines</td>
|
||||
<td>${int(f64(vlines) / f64(diff1) * 1000.0)}</td>
|
||||
</tr>\n' +
|
||||
table.trim_space()
|
||||
out.writeln(table)?
|
||||
out.close()
|
||||
|
||||
// regenerate index.html
|
||||
header := os.read_file('header.html')?
|
||||
footer := os.read_file('footer.html')?
|
||||
mut res := os.create('index.html')?
|
||||
res.writeln(header)?
|
||||
res.writeln(table)?
|
||||
res.writeln(footer)?
|
||||
res.close()
|
||||
|
||||
// upload the result to github pages
|
||||
if os.args.contains('-upload') {
|
||||
println('uploading...')
|
||||
os.chdir('website')?
|
||||
os.execute_or_exit('git checkout gh-pages')
|
||||
os.cp('../index.html', 'index.html')?
|
||||
os.rm('../index.html')?
|
||||
os.system('git commit -am "update benchmark"')
|
||||
os.system('git push origin gh-pages')
|
||||
}
|
||||
}
|
||||
|
||||
fn exec(s string) string {
|
||||
e := os.execute_or_exit(s)
|
||||
return e.output.trim_right('\r\n')
|
||||
}
|
||||
|
||||
// measure returns milliseconds
|
||||
fn measure(cmd string, description string) int {
|
||||
println(' Measuring $description')
|
||||
println(' Warming up...')
|
||||
println(cmd)
|
||||
for _ in 0 .. 3 {
|
||||
exec(cmd)
|
||||
}
|
||||
println(' Building...')
|
||||
mut runs := []int{}
|
||||
for r in 0 .. 5 {
|
||||
println(' Sample ${r + 1}/5')
|
||||
sw := time.new_stopwatch()
|
||||
exec(cmd)
|
||||
runs << int(sw.elapsed().milliseconds())
|
||||
}
|
||||
// discard lowest and highest time
|
||||
runs.sort()
|
||||
runs = runs[1..4]
|
||||
mut sum := 0
|
||||
for run in runs {
|
||||
sum += run
|
||||
}
|
||||
return int(sum / 3)
|
||||
}
|
||||
|
||||
fn measure_steps(vdir string) (int, int, int, int, int) {
|
||||
resp := os.execute_or_exit('$vdir/vprod $voptions -o v.c cmd/v')
|
||||
|
||||
mut scan, mut parse, mut check, mut cgen, mut vlines := 0, 0, 0, 0, 0
|
||||
lines := resp.output.split_into_lines()
|
||||
if lines.len == 3 {
|
||||
parse = lines[0].before('.').int()
|
||||
check = lines[1].before('.').int()
|
||||
cgen = lines[2].before('.').int()
|
||||
} else {
|
||||
ms_lines := lines.map(it.split(' ms '))
|
||||
for line in ms_lines {
|
||||
if line.len == 2 {
|
||||
if line[1] == 'SCAN' {
|
||||
scan = line[0].int()
|
||||
}
|
||||
if line[1] == 'PARSE' {
|
||||
parse = line[0].int()
|
||||
}
|
||||
if line[1] == 'CHECK' {
|
||||
check = line[0].int()
|
||||
}
|
||||
if line[1] == 'C GEN' {
|
||||
cgen = line[0].int()
|
||||
}
|
||||
} else {
|
||||
// fetch number of V lines
|
||||
if line[0].contains('V') && line[0].contains('source') && line[0].contains('size') {
|
||||
start := line[0].index(':') or { 0 }
|
||||
end := line[0].index('lines,') or { 0 }
|
||||
s := line[0][start + 1..end]
|
||||
vlines = s.trim_space().int()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return scan, parse, check, cgen, vlines
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) 2019-2022 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
import os
|
||||
import time
|
||||
|
||||
// A job that runs in the background, checks for repo updates,
|
||||
// runs fast.v, pushes the HTML result to the fast.vlang.io GH pages repo.
|
||||
fn main() {
|
||||
println(time.now())
|
||||
if !os.exists('website') {
|
||||
println('cloning the website repo...')
|
||||
os.system('git clone git@github.com:/vlang/website.git')
|
||||
}
|
||||
if !os.exists('fast') {
|
||||
println('"fast" binary (built with `v fast.v`) was not found')
|
||||
return
|
||||
}
|
||||
for {
|
||||
res_pull := os.execute('git pull --rebase')
|
||||
if res_pull.exit_code != 0 {
|
||||
println('failed to git pull. uncommitted changes?')
|
||||
return
|
||||
}
|
||||
// println('running ./fast')
|
||||
resp := os.execute('./fast -upload')
|
||||
if resp.exit_code < 0 {
|
||||
println(resp.output)
|
||||
return
|
||||
}
|
||||
if resp.exit_code != 0 {
|
||||
println('resp != 0, skipping')
|
||||
println(resp.output)
|
||||
}
|
||||
time.sleep(180 * time.second)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
const delta = 18;
|
||||
|
||||
(function () {
|
||||
var table = document.querySelector("table");
|
||||
var isTbody = table.children[0].nodeName == "TBODY";
|
||||
var trs = isTbody
|
||||
? table.children[0].querySelectorAll("tr")
|
||||
: table.querySelectorAll("tr");
|
||||
trs.forEach(function (tr, idx) {
|
||||
if (idx != 0 && idx + 1 < trs.length) {
|
||||
var vc = 3, vv = 4, vf = 5, vh = 6;
|
||||
var textContent = {
|
||||
vc: tr.children[vc].textContent,
|
||||
vv: tr.children[vv].textContent,
|
||||
vf: tr.children[vf].textContent,
|
||||
vh: tr.children[vh].textContent
|
||||
};
|
||||
var currentData = {
|
||||
vc: int(textContent.vc.slice(0, -2)),
|
||||
vv: int(textContent.vv.slice(0, -2)),
|
||||
vf: int(textContent.vf.slice(0, -2)),
|
||||
vh: int(textContent.vh.slice(0, -2))
|
||||
};
|
||||
var prevData = {
|
||||
vc: int(trs[idx + 1].children[vc].textContent.slice(0, -2)),
|
||||
vv: int(trs[idx + 1].children[vv].textContent.slice(0, -2)),
|
||||
vf: int(trs[idx + 1].children[vf].textContent.slice(0, -2)),
|
||||
vh: int(trs[idx + 1].children[vh].textContent.slice(0, -2))
|
||||
};
|
||||
var result = {
|
||||
vc: currentData.vc - prevData.vc,
|
||||
vv: currentData.vv - prevData.vv,
|
||||
vf: currentData.vf - prevData.vf,
|
||||
vh: currentData.vh - prevData.vh
|
||||
};
|
||||
if (Math.abs(result.vc) > delta)
|
||||
tr.children[vc].appendChild(createElement(result.vc));
|
||||
if (Math.abs(result.vv) > delta * 2)
|
||||
tr.children[vv].appendChild(createElement(result.vv));
|
||||
if (Math.abs(result.vf) > delta * 2)
|
||||
tr.children[vf].appendChild(createElement(result.vf));
|
||||
if (Math.abs(result.vh) > delta * 2)
|
||||
tr.children[vh].appendChild(createElement(result.vh));
|
||||
}
|
||||
});
|
||||
function int(src) {
|
||||
return src - 0;
|
||||
}
|
||||
function getClassName(x) {
|
||||
if (x == 0)
|
||||
return "equal";
|
||||
return x < 0 ? "plus" : "minus";
|
||||
}
|
||||
function createElement(result) {
|
||||
var el = document.createElement("span");
|
||||
var parsedResult = parseResult(result);
|
||||
el.classList.add("diff");
|
||||
el.classList.add(getClassName(result));
|
||||
el.textContent = parsedResult;
|
||||
return el;
|
||||
}
|
||||
function parseResult(x) {
|
||||
if (x == 0)
|
||||
return "0";
|
||||
return x > 0 ? "+" + x : x;
|
||||
}
|
||||
})();
|
|
@ -0,0 +1,4 @@
|
|||
</table>
|
||||
<script src="main.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,65 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Is V still fast?</title>
|
||||
<style>
|
||||
*, body {
|
||||
font-family: Menlo, Monospace, 'Courier New';
|
||||
}
|
||||
table {
|
||||
width: 1800px;
|
||||
}
|
||||
table, td {
|
||||
border-collapse: collapse;
|
||||
border: 1px solid #dfdfdf;
|
||||
}
|
||||
td {
|
||||
padding: 5px;
|
||||
position: relative;
|
||||
}
|
||||
.diff {
|
||||
border-radius: 2.5px;
|
||||
color: #ffffff;
|
||||
padding: 0 5px 0 5px;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
}
|
||||
.minus {
|
||||
background-color: rgb(195, 74, 104);
|
||||
}
|
||||
.plus {
|
||||
background-color: #8BC34A;
|
||||
}
|
||||
.equal {
|
||||
background-color: rgb(113, 68, 172);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Is V still fast?</h2>
|
||||
|
||||
Monitoring compilation speed for each commit. <br><br>
|
||||
Running on a free tier AWS t2.micro instance (1 vCPU). Typical desktop hardware is 2-3 times faster. <br><br>
|
||||
Source code: <a target=blank href='https://github.com/vlang/v/blob/master/cmd/tools/fast/fast.v'>fast.v</a> <br><br>
|
||||
|
||||
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td style='width:180px'>timestamp</td>
|
||||
<td style='width:85px'>commit</td>
|
||||
<td>commit message</td>
|
||||
<td style='width:120px'>v -o v.c</td>
|
||||
<td style='width:120px'>v -o v</td>
|
||||
<td style='width:130px'>v -native 1mil.v</td>
|
||||
<td style='width:120px'>v hello.v</td>
|
||||
<td style='width:85px'>v.c size</td>
|
||||
<td style='width:55px'>parse</td>
|
||||
<td style='width:55px'>check</td>
|
||||
<td style='width:55px'>cgen</td>
|
||||
<td style='width:55px'>scan</td>
|
||||
<td style='width:80px'>V lines</td>
|
||||
<td style='width:95px'>V lines/s</td>
|
||||
</tr>
|
|
@ -0,0 +1,18 @@
|
|||
#!/bin/sh
|
||||
|
||||
cores=$(nproc --all)
|
||||
|
||||
echo Number of cores: $cores
|
||||
echo Compiling...
|
||||
./v -cc clang -o cmd/tools/fuzz/map_fuzz cmd/tools/fuzz/map_fuzz.v -prod -cflags "-fsanitize=memory"
|
||||
|
||||
echo Fuzzing:
|
||||
while true
|
||||
do
|
||||
for ((i=1;i<=cores;++i))
|
||||
do
|
||||
sleep 0.001
|
||||
./cmd/tools/fuzz/map_fuzz &
|
||||
done
|
||||
wait
|
||||
done
|
|
@ -0,0 +1,144 @@
|
|||
import rand
|
||||
import time
|
||||
|
||||
fn generate_strings(str_len int, arr_len int) []string {
|
||||
mut arr := []string{len: arr_len}
|
||||
for i in 0 .. arr_len {
|
||||
arr[i] = rand.string(str_len)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
fn fuzz1() {
|
||||
amount := 200000 - rand.intn(100000) or { 0 }
|
||||
amount2 := 200000 - rand.intn(100000) or { 0 }
|
||||
len := 25 - rand.intn(10) or { 0 }
|
||||
arr := generate_strings(len, amount)
|
||||
arr2 := generate_strings(len, amount2)
|
||||
mut m := map[string]int{}
|
||||
for i in 0 .. amount {
|
||||
m[arr[i]] = i
|
||||
assert i == m[arr[i]]
|
||||
}
|
||||
for i in 0 .. amount {
|
||||
assert i == m[arr[i]]
|
||||
}
|
||||
for i in 0 .. amount2 {
|
||||
assert 0 == m[arr2[i]]
|
||||
}
|
||||
unsafe {
|
||||
m.free()
|
||||
arr.free()
|
||||
}
|
||||
}
|
||||
|
||||
fn fuzz2() {
|
||||
mut m := map[string]int{}
|
||||
amount := rand.intn(500000) or { 0 } + 1
|
||||
len := 25 - rand.intn(10) or { 0 }
|
||||
arr := generate_strings(len, amount)
|
||||
for i, x in arr {
|
||||
m[x] = i
|
||||
}
|
||||
mut i := 0
|
||||
for key, val in m {
|
||||
assert key == arr[i]
|
||||
assert val == i
|
||||
i++
|
||||
}
|
||||
unsafe {
|
||||
m.free()
|
||||
arr.free()
|
||||
}
|
||||
}
|
||||
|
||||
fn fuzz3() {
|
||||
mut m := map[string]int{}
|
||||
amount := rand.intn(500000) or { 0 } + 1
|
||||
len := 25 - rand.intn(10) or { 0 }
|
||||
arr := generate_strings(len, amount)
|
||||
for i, x in arr {
|
||||
if (i % 10000) == 0 {
|
||||
keys := m.keys()
|
||||
assert keys.len == i
|
||||
assert keys == arr[0..i]
|
||||
}
|
||||
m[x] = i
|
||||
}
|
||||
assert m.keys() == arr
|
||||
assert m.keys().len == amount
|
||||
unsafe {
|
||||
m.free()
|
||||
arr.free()
|
||||
}
|
||||
}
|
||||
|
||||
fn fuzz4() {
|
||||
amount := rand.intn(500000) or { 0 }
|
||||
len := 25 - rand.intn(10) or { 0 }
|
||||
arr := generate_strings(len, amount)
|
||||
mut m := map[string]int{}
|
||||
for i in 0 .. amount {
|
||||
m[arr[i]] = i
|
||||
}
|
||||
for i in 0 .. amount {
|
||||
m.delete(arr[i])
|
||||
assert m[arr[i]] == 0
|
||||
}
|
||||
assert m.len == 0
|
||||
unsafe {
|
||||
m.free()
|
||||
arr.free()
|
||||
}
|
||||
}
|
||||
|
||||
fn fuzz5() {
|
||||
amount := rand.intn(500000) or { 0 } + 1
|
||||
arr := generate_strings(20, amount)
|
||||
mut m := map[string]int{}
|
||||
for i in 0 .. amount {
|
||||
m[arr[i]] = i
|
||||
assert (arr[i] in m) == true
|
||||
}
|
||||
for i in 0 .. amount {
|
||||
m.delete(arr[i])
|
||||
assert (arr[i] !in m) == true
|
||||
assert m.len == amount - i - 1
|
||||
}
|
||||
assert m.len == 0
|
||||
unsafe {
|
||||
m.free()
|
||||
arr.free()
|
||||
}
|
||||
}
|
||||
|
||||
fn fuzz6() {
|
||||
mut m := map[string]int{}
|
||||
amount := rand.intn(500000) or { 0 } + 1
|
||||
len := 25 - rand.intn(10) or { 0 }
|
||||
arr := generate_strings(len, amount)
|
||||
for i, x in arr {
|
||||
m[x]++
|
||||
m[x] += i
|
||||
assert m[x] == i + 1
|
||||
}
|
||||
for i, x in arr {
|
||||
assert m[x] == i + 1
|
||||
}
|
||||
unsafe {
|
||||
m.free()
|
||||
arr.free()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
seed := u32(time.ticks())
|
||||
println('seed: $seed.hex()')
|
||||
rand.seed([seed, seed])
|
||||
fuzz1()
|
||||
fuzz2()
|
||||
fuzz3()
|
||||
fuzz4()
|
||||
fuzz5()
|
||||
fuzz6()
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
fn main() {
|
||||
for i in 0 .. 100000 {
|
||||
println('
|
||||
fn foo${i}() {
|
||||
x := $i
|
||||
mut a := 1 + x
|
||||
a += 2
|
||||
print(a)
|
||||
a = 0
|
||||
a = 1
|
||||
}
|
||||
')
|
||||
}
|
||||
// println('fn main() {foo1()} ')
|
||||
println('fn main() { println("1m DONE") } ')
|
||||
}
|
|
@ -0,0 +1,370 @@
|
|||
module main
|
||||
|
||||
import os
|
||||
import log
|
||||
import flag
|
||||
import time
|
||||
import vweb
|
||||
import net.urllib
|
||||
|
||||
// This tool regenerates V's bootstrap .c files
|
||||
// every time the V master branch is updated.
|
||||
// if run with the --serve flag it will run in webhook
|
||||
// server mode awaiting a request to http://host:port/genhook
|
||||
// available command line flags:
|
||||
// --work-dir gen_vc's working directory
|
||||
// --purge force purge the local repositories
|
||||
// --serve run in webhook server mode
|
||||
// --port port for http server to listen on
|
||||
// --log-to either 'file' or 'terminal'
|
||||
// --log-file path to log file used when --log-to is 'file'
|
||||
// --dry-run dont push anything to remote repo
|
||||
// --force force update even if already up to date
|
||||
|
||||
// git credentials
|
||||
const (
|
||||
git_username = os.getenv('GITUSER')
|
||||
git_password = os.getenv('GITPASS')
|
||||
)
|
||||
|
||||
// repository
|
||||
const (
|
||||
// git repo
|
||||
git_repo_v = 'github.com/vlang/v'
|
||||
git_repo_vc = 'github.com/vlang/vc'
|
||||
// local repo directories
|
||||
git_repo_dir_v = 'v'
|
||||
git_repo_dir_vc = 'vc'
|
||||
)
|
||||
|
||||
// gen_vc
|
||||
const (
|
||||
// name
|
||||
app_name = 'gen_vc'
|
||||
// version
|
||||
app_version = '0.1.2'
|
||||
// description
|
||||
app_description = "This tool regenerates V's bootstrap .c files every time the V master branch is updated."
|
||||
// assume something went wrong if file size less than this
|
||||
too_short_file_limit = 5000
|
||||
// create a .c file for these os's
|
||||
vc_build_oses = [
|
||||
'nix',
|
||||
// all nix based os
|
||||
'windows',
|
||||
]
|
||||
)
|
||||
|
||||
// default options (overridden by flags)
|
||||
const (
|
||||
// gen_vc working directory
|
||||
work_dir = '/tmp/gen_vc'
|
||||
// dont push anything to remote repo
|
||||
dry_run = false
|
||||
// server port
|
||||
server_port = 7171
|
||||
// log file
|
||||
log_file = '$work_dir/log.txt'
|
||||
// log_to is either 'file' or 'terminal'
|
||||
log_to = 'terminal'
|
||||
)
|
||||
|
||||
// errors
|
||||
const (
|
||||
err_msg_build = 'error building'
|
||||
err_msg_make = 'make failed'
|
||||
err_msg_gen_c = 'failed to generate .c file'
|
||||
err_msg_cmd_x = 'error running cmd'
|
||||
)
|
||||
|
||||
struct GenVC {
|
||||
// logger
|
||||
// flag options
|
||||
options FlagOptions
|
||||
mut:
|
||||
logger &log.Log
|
||||
// true if error was experienced running generate
|
||||
gen_error bool
|
||||
}
|
||||
|
||||
// webhook server
|
||||
struct WebhookServer {
|
||||
vweb.Context
|
||||
mut:
|
||||
gen_vc &GenVC = 0 // initialized in init_server
|
||||
}
|
||||
|
||||
// storage for flag options
|
||||
struct FlagOptions {
|
||||
work_dir string
|
||||
purge bool
|
||||
serve bool
|
||||
port int
|
||||
log_to string
|
||||
log_file string
|
||||
dry_run bool
|
||||
force bool
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut fp := flag.new_flag_parser(os.args.clone())
|
||||
fp.application(app_name)
|
||||
fp.version(app_version)
|
||||
fp.description(app_description)
|
||||
fp.skip_executable()
|
||||
show_help := fp.bool('help', 0, false, 'Show this help screen\n')
|
||||
flag_options := parse_flags(mut fp)
|
||||
if show_help {
|
||||
println(fp.usage())
|
||||
exit(0)
|
||||
}
|
||||
fp.finalize() or {
|
||||
eprintln(err)
|
||||
println(fp.usage())
|
||||
return
|
||||
}
|
||||
// webhook server mode
|
||||
if flag_options.serve {
|
||||
vweb.run<WebhookServer>(&WebhookServer{}, flag_options.port)
|
||||
} else {
|
||||
// cmd mode
|
||||
mut gen_vc := new_gen_vc(flag_options)
|
||||
gen_vc.init()
|
||||
gen_vc.generate()
|
||||
}
|
||||
}
|
||||
|
||||
// new GenVC
|
||||
fn new_gen_vc(flag_options FlagOptions) &GenVC {
|
||||
mut logger := &log.Log{}
|
||||
logger.set_level(.debug)
|
||||
if flag_options.log_to == 'file' {
|
||||
logger.set_full_logpath(flag_options.log_file)
|
||||
}
|
||||
return &GenVC{
|
||||
options: flag_options
|
||||
logger: logger
|
||||
}
|
||||
}
|
||||
|
||||
// WebhookServer init
|
||||
pub fn (mut ws WebhookServer) init_server() {
|
||||
mut fp := flag.new_flag_parser(os.args.clone())
|
||||
flag_options := parse_flags(mut fp)
|
||||
ws.gen_vc = new_gen_vc(flag_options)
|
||||
ws.gen_vc.init()
|
||||
// ws.gen_vc = new_gen_vc(flag_options)
|
||||
}
|
||||
|
||||
pub fn (mut ws WebhookServer) index() {
|
||||
eprintln('WebhookServer.index() called')
|
||||
}
|
||||
|
||||
// gen webhook
|
||||
pub fn (mut ws WebhookServer) genhook() {
|
||||
// request data
|
||||
// println(ws.vweb.req.data)
|
||||
// TODO: parse request. json or urlencoded
|
||||
// json.decode or net.urllib.parse
|
||||
ws.gen_vc.generate()
|
||||
// error in generate
|
||||
if ws.gen_vc.gen_error {
|
||||
ws.json('{status: "failed"}')
|
||||
return
|
||||
}
|
||||
ws.json('{status: "ok"}')
|
||||
}
|
||||
|
||||
pub fn (ws &WebhookServer) reset() {
|
||||
}
|
||||
|
||||
// parse flags to FlagOptions struct
|
||||
fn parse_flags(mut fp flag.FlagParser) FlagOptions {
|
||||
return FlagOptions{
|
||||
serve: fp.bool('serve', 0, false, 'run in webhook server mode')
|
||||
work_dir: fp.string('work-dir', 0, work_dir, 'gen_vc working directory')
|
||||
purge: fp.bool('purge', 0, false, 'force purge the local repositories')
|
||||
port: fp.int('port', 0, server_port, 'port for web server to listen on')
|
||||
log_to: fp.string('log-to', 0, log_to, "log to is 'file' or 'terminal'")
|
||||
log_file: fp.string('log-file', 0, log_file, "log file to use when log-to is 'file'")
|
||||
dry_run: fp.bool('dry-run', 0, dry_run, 'when specified dont push anything to remote repo')
|
||||
force: fp.bool('force', 0, false, 'force update even if already up to date')
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut gen_vc GenVC) init() {
|
||||
// purge repos if flag is passed
|
||||
if gen_vc.options.purge {
|
||||
gen_vc.purge_repos()
|
||||
}
|
||||
}
|
||||
|
||||
// regenerate
|
||||
fn (mut gen_vc GenVC) generate() {
|
||||
// set errors to false
|
||||
gen_vc.gen_error = false
|
||||
// check if gen_vc dir exists
|
||||
if !os.is_dir(gen_vc.options.work_dir) {
|
||||
// try create
|
||||
os.mkdir(gen_vc.options.work_dir) or { panic(err) }
|
||||
// still dosen't exist... we have a problem
|
||||
if !os.is_dir(gen_vc.options.work_dir) {
|
||||
gen_vc.logger.error('error creating directory: $gen_vc.options.work_dir')
|
||||
gen_vc.gen_error = true
|
||||
return
|
||||
}
|
||||
}
|
||||
// cd to gen_vc dir
|
||||
os.chdir(gen_vc.options.work_dir) or {}
|
||||
// if we are not running with the --serve flag (webhook server)
|
||||
// rather than deleting and re-downloading the repo each time
|
||||
// first check to see if the local v repo is behind master
|
||||
// if it isn't behind theres no point continuing further
|
||||
if !gen_vc.options.serve && os.is_dir(git_repo_dir_v) {
|
||||
gen_vc.cmd_exec('git -C $git_repo_dir_v checkout master')
|
||||
// fetch the remote repo just in case there are newer commits there
|
||||
gen_vc.cmd_exec('git -C $git_repo_dir_v fetch')
|
||||
git_status := gen_vc.cmd_exec('git -C $git_repo_dir_v status')
|
||||
if !git_status.contains('behind') && !gen_vc.options.force {
|
||||
gen_vc.logger.warn('v repository is already up to date.')
|
||||
return
|
||||
}
|
||||
}
|
||||
// delete repos
|
||||
gen_vc.purge_repos()
|
||||
// clone repos
|
||||
gen_vc.cmd_exec('git clone --depth 1 https://$git_repo_v $git_repo_dir_v')
|
||||
gen_vc.cmd_exec('git clone --depth 1 https://$git_repo_vc $git_repo_dir_vc')
|
||||
// get output of git log -1 (last commit)
|
||||
git_log_v := gen_vc.cmd_exec('git -C $git_repo_dir_v log -1 --format="commit %H%nDate: %ci%nDate Unix: %ct%nSubject: %s"')
|
||||
git_log_vc := gen_vc.cmd_exec('git -C $git_repo_dir_vc log -1 --format="Commit %H%nDate: %ci%nDate Unix: %ct%nSubject: %s"')
|
||||
// date of last commit in each repo
|
||||
ts_v := git_log_v.find_between('Date:', '\n').trim_space()
|
||||
ts_vc := git_log_vc.find_between('Date:', '\n').trim_space()
|
||||
// parse time as string to time.Time
|
||||
last_commit_time_v := time.parse(ts_v) or { panic(err) }
|
||||
last_commit_time_vc := time.parse(ts_vc) or { panic(err) }
|
||||
// git dates are in users local timezone and v time.parse does not parse
|
||||
// timezones at the moment, so for now get unix timestamp from output also
|
||||
t_unix_v := git_log_v.find_between('Date Unix:', '\n').trim_space().int()
|
||||
t_unix_vc := git_log_vc.find_between('Date Unix:', '\n').trim_space().int()
|
||||
// last commit hash in v repo
|
||||
last_commit_hash_v := git_log_v.find_between('commit', '\n').trim_space()
|
||||
last_commit_hash_v_short := last_commit_hash_v[..7]
|
||||
// subject
|
||||
last_commit_subject := git_log_v.find_between('Subject:', '\n').trim_space().replace("'",
|
||||
'"')
|
||||
// log some info
|
||||
gen_vc.logger.debug('last commit time ($git_repo_v): ' + last_commit_time_v.format_ss())
|
||||
gen_vc.logger.debug('last commit time ($git_repo_vc): ' + last_commit_time_vc.format_ss())
|
||||
gen_vc.logger.debug('last commit hash ($git_repo_v): $last_commit_hash_v')
|
||||
gen_vc.logger.debug('last commit subject ($git_repo_v): $last_commit_subject')
|
||||
// if vc repo already has a newer commit than the v repo, assume it's up to date
|
||||
if t_unix_vc >= t_unix_v && !gen_vc.options.force {
|
||||
gen_vc.logger.warn('vc repository is already up to date.')
|
||||
return
|
||||
}
|
||||
// try build v for current os (linux in this case)
|
||||
gen_vc.cmd_exec('make -C $git_repo_dir_v')
|
||||
v_exec := '$git_repo_dir_v/v'
|
||||
// check if make was successful
|
||||
gen_vc.assert_file_exists_and_is_not_too_short(v_exec, err_msg_make)
|
||||
// build v.c for each os
|
||||
for os_name in vc_build_oses {
|
||||
c_file := if os_name == 'nix' { 'v.c' } else { 'v_win.c' }
|
||||
v_flags := if os_name == 'nix' { '-os cross' } else { '-os $os_name' }
|
||||
// try generate .c file
|
||||
gen_vc.cmd_exec('$v_exec $v_flags -o $c_file $git_repo_dir_v/cmd/v')
|
||||
// check if the c file seems ok
|
||||
gen_vc.assert_file_exists_and_is_not_too_short(c_file, err_msg_gen_c)
|
||||
// embed the latest v commit hash into the c file
|
||||
gen_vc.cmd_exec('sed -i \'1s/^/#define V_COMMIT_HASH "$last_commit_hash_v_short"\\n/\' $c_file')
|
||||
// move to vc repo
|
||||
gen_vc.cmd_exec('mv $c_file $git_repo_dir_vc/$c_file')
|
||||
// add new .c file to local vc repo
|
||||
gen_vc.cmd_exec('git -C $git_repo_dir_vc add $c_file')
|
||||
}
|
||||
// check if the vc repo actually changed
|
||||
git_status := gen_vc.cmd_exec('git -C $git_repo_dir_vc status')
|
||||
if git_status.contains('nothing to commit') {
|
||||
gen_vc.logger.error('no changes to vc repo: something went wrong.')
|
||||
gen_vc.gen_error = true
|
||||
}
|
||||
// commit changes to local vc repo
|
||||
gen_vc.cmd_exec_safe("git -C $git_repo_dir_vc commit -m '[v:master] $last_commit_hash_v_short - $last_commit_subject'")
|
||||
// push changes to remote vc repo
|
||||
gen_vc.cmd_exec_safe('git -C $git_repo_dir_vc push https://${urllib.query_escape(git_username)}:${urllib.query_escape(git_password)}@$git_repo_vc master')
|
||||
}
|
||||
|
||||
// only execute when dry_run option is false, otherwise just log
|
||||
fn (mut gen_vc GenVC) cmd_exec_safe(cmd string) string {
|
||||
return gen_vc.command_execute(cmd, gen_vc.options.dry_run)
|
||||
}
|
||||
|
||||
// always execute command
|
||||
fn (mut gen_vc GenVC) cmd_exec(cmd string) string {
|
||||
return gen_vc.command_execute(cmd, false)
|
||||
}
|
||||
|
||||
// execute command
|
||||
fn (mut gen_vc GenVC) command_execute(cmd string, dry bool) string {
|
||||
// if dry is true then dont execute, just log
|
||||
if dry {
|
||||
return gen_vc.command_execute_dry(cmd)
|
||||
}
|
||||
gen_vc.logger.info('cmd: $cmd')
|
||||
r := os.execute(cmd)
|
||||
if r.exit_code < 0 {
|
||||
gen_vc.logger.error('$err_msg_cmd_x: "$cmd" could not start.')
|
||||
gen_vc.logger.error(r.output)
|
||||
// something went wrong, better start fresh next time
|
||||
gen_vc.purge_repos()
|
||||
gen_vc.gen_error = true
|
||||
return ''
|
||||
}
|
||||
if r.exit_code != 0 {
|
||||
gen_vc.logger.error('$err_msg_cmd_x: "$cmd" failed.')
|
||||
gen_vc.logger.error(r.output)
|
||||
// something went wrong, better start fresh next time
|
||||
gen_vc.purge_repos()
|
||||
gen_vc.gen_error = true
|
||||
return ''
|
||||
}
|
||||
return r.output
|
||||
}
|
||||
|
||||
// just log cmd, dont execute
|
||||
fn (mut gen_vc GenVC) command_execute_dry(cmd string) string {
|
||||
gen_vc.logger.info('cmd (dry): "$cmd"')
|
||||
return ''
|
||||
}
|
||||
|
||||
// delete repo directories
|
||||
fn (mut gen_vc GenVC) purge_repos() {
|
||||
// delete old repos (better to be fully explicit here, since these are destructive operations)
|
||||
mut repo_dir := '$gen_vc.options.work_dir/$git_repo_dir_v'
|
||||
if os.is_dir(repo_dir) {
|
||||
gen_vc.logger.info('purging local repo: "$repo_dir"')
|
||||
gen_vc.cmd_exec('rm -rf $repo_dir')
|
||||
}
|
||||
repo_dir = '$gen_vc.options.work_dir/$git_repo_dir_vc'
|
||||
if os.is_dir(repo_dir) {
|
||||
gen_vc.logger.info('purging local repo: "$repo_dir"')
|
||||
gen_vc.cmd_exec('rm -rf $repo_dir')
|
||||
}
|
||||
}
|
||||
|
||||
// check if file size is too short
|
||||
fn (mut gen_vc GenVC) assert_file_exists_and_is_not_too_short(f string, emsg string) {
|
||||
if !os.exists(f) {
|
||||
gen_vc.logger.error('$err_msg_build: $emsg .')
|
||||
gen_vc.gen_error = true
|
||||
return
|
||||
}
|
||||
fsize := os.file_size(f)
|
||||
if fsize < too_short_file_limit {
|
||||
gen_vc.logger.error('$err_msg_build: $f exists, but is too short: only $fsize bytes.')
|
||||
gen_vc.gen_error = true
|
||||
return
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
import os
|
||||
import time
|
||||
import v.ast
|
||||
import v.pref
|
||||
import v.parser
|
||||
import v.errors
|
||||
import v.scanner
|
||||
|
||||
fn main() {
|
||||
files := os.args#[1..]
|
||||
if files.len > 0 && files[0].starts_with('@') {
|
||||
lst_path := files[0].all_after('@')
|
||||
listed_files := os.read_file(lst_path)?.split('\n')
|
||||
process_files(listed_files)?
|
||||
return
|
||||
}
|
||||
process_files(files)?
|
||||
}
|
||||
|
||||
fn process_files(files []string) ? {
|
||||
mut table := ast.new_table()
|
||||
mut pref := pref.new_preferences()
|
||||
pref.is_fmt = true
|
||||
pref.skip_warnings = true
|
||||
pref.output_mode = .silent
|
||||
mut sw := time.new_stopwatch()
|
||||
mut total_us := i64(0)
|
||||
mut total_bytes := i64(0)
|
||||
mut total_tokens := i64(0)
|
||||
for f in files {
|
||||
if f == '' {
|
||||
continue
|
||||
}
|
||||
if f.ends_with('_test.v') {
|
||||
continue
|
||||
}
|
||||
// do not measure the scanning, but only the parsing:
|
||||
mut p := new_parser(f, .skip_comments, table, pref)
|
||||
///
|
||||
sw.restart()
|
||||
_ := p.parse()
|
||||
f_us := sw.elapsed().microseconds()
|
||||
///
|
||||
total_us += f_us
|
||||
total_bytes += p.scanner.text.len
|
||||
total_tokens += p.scanner.all_tokens.len
|
||||
println('${f_us:10}us ${p.scanner.all_tokens.len:10} ${p.scanner.text.len:10} ${(f64(p.scanner.text.len) / p.scanner.all_tokens.len):7.3} ${p.errors.len:4} $f')
|
||||
}
|
||||
println('${total_us:10}us ${total_tokens:10} ${total_bytes:10} ${(f64(total_tokens) / total_bytes):7.3} | speed: ${(f64(total_bytes) / total_us):2.5f} MB/s')
|
||||
}
|
||||
|
||||
fn new_parser(path string, comments_mode scanner.CommentsMode, table &ast.Table, pref &pref.Preferences) &parser.Parser {
|
||||
mut p := &parser.Parser{
|
||||
scanner: scanner.new_scanner_file(path, comments_mode, pref) or { panic(err) }
|
||||
comments_mode: comments_mode
|
||||
table: table
|
||||
pref: pref
|
||||
scope: &ast.Scope{
|
||||
start_pos: 0
|
||||
parent: table.global_scope
|
||||
}
|
||||
errors: []errors.Error{}
|
||||
warnings: []errors.Warning{}
|
||||
}
|
||||
p.set_path(path)
|
||||
return p
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
import os
|
||||
import time
|
||||
import v.scanner
|
||||
import v.pref
|
||||
|
||||
fn main() {
|
||||
files := os.args#[1..]
|
||||
if files.len > 0 && files[0].starts_with('@') {
|
||||
lst_path := files[0].all_after('@')
|
||||
listed_files := os.read_file(lst_path)?.split('\n')
|
||||
process_files(listed_files)?
|
||||
return
|
||||
}
|
||||
process_files(files)?
|
||||
}
|
||||
|
||||
fn process_files(files []string) ? {
|
||||
mut pref := pref.new_preferences()
|
||||
pref.is_fmt = true
|
||||
pref.skip_warnings = true
|
||||
pref.output_mode = .silent
|
||||
mut sw := time.new_stopwatch()
|
||||
mut total_us := i64(0)
|
||||
mut total_bytes := i64(0)
|
||||
mut total_tokens := i64(0)
|
||||
for f in files {
|
||||
if f == '' {
|
||||
continue
|
||||
}
|
||||
if f.ends_with('_test.v') {
|
||||
continue
|
||||
}
|
||||
sw.restart()
|
||||
s := scanner.new_scanner_file(f, .skip_comments, pref)?
|
||||
f_us := sw.elapsed().microseconds()
|
||||
total_us += f_us
|
||||
total_bytes += s.text.len
|
||||
total_tokens += s.all_tokens.len
|
||||
println('${f_us:10}us ${s.all_tokens.len:10} ${s.text.len:10} ${(f64(s.text.len) / s.all_tokens.len):7.3f} $f')
|
||||
}
|
||||
println('${total_us:10}us ${total_tokens:10} ${total_bytes:10} ${(f64(total_tokens) / total_bytes):7.3f} | speed: ${(f64(total_bytes) / total_us):2.5f} MB/s')
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
module scripting
|
||||
|
||||
import os
|
||||
import term
|
||||
import time
|
||||
|
||||
const (
|
||||
term_colors = term.can_show_color_on_stdout()
|
||||
)
|
||||
|
||||
pub fn set_verbose(on bool) {
|
||||
// setting a global here would be the obvious solution,
|
||||
// but V does not have globals normally.
|
||||
if on {
|
||||
os.setenv('VERBOSE', '1', true)
|
||||
} else {
|
||||
os.unsetenv('VERBOSE')
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cprint(omessage string) {
|
||||
mut message := omessage
|
||||
if scripting.term_colors {
|
||||
message = term.cyan(message)
|
||||
}
|
||||
print(message)
|
||||
flush_stdout()
|
||||
}
|
||||
|
||||
pub fn cprint_strong(omessage string) {
|
||||
mut message := omessage
|
||||
if scripting.term_colors {
|
||||
message = term.bright_green(message)
|
||||
}
|
||||
print(message)
|
||||
flush_stdout()
|
||||
}
|
||||
|
||||
pub fn cprintln(omessage string) {
|
||||
cprint(omessage)
|
||||
println('')
|
||||
flush_stdout()
|
||||
}
|
||||
|
||||
pub fn cprintln_strong(omessage string) {
|
||||
cprint_strong(omessage)
|
||||
println('')
|
||||
flush_stdout()
|
||||
}
|
||||
|
||||
pub fn verbose_trace(label string, message string) {
|
||||
if os.getenv('VERBOSE').len > 0 {
|
||||
slabel := '$time.now().format_ss_milli() $label'
|
||||
cprintln('# ${slabel:-43s} : $message')
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verbose_trace_strong(label string, omessage string) {
|
||||
if os.getenv('VERBOSE').len > 0 {
|
||||
slabel := '$time.now().format_ss_milli() $label'
|
||||
mut message := omessage
|
||||
if scripting.term_colors {
|
||||
message = term.bright_green(message)
|
||||
}
|
||||
cprintln('# ${slabel:-43s} : $message')
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verbose_trace_exec_result(x os.Result) {
|
||||
if os.getenv('VERBOSE').len > 0 {
|
||||
cprintln('# cmd.exit_code : ${x.exit_code.str():-4s} cmd.output:')
|
||||
mut lnum := 1
|
||||
lines := x.output.split_into_lines()
|
||||
for oline in lines {
|
||||
mut line := oline
|
||||
if scripting.term_colors {
|
||||
line = term.bright_green(line)
|
||||
}
|
||||
cprintln('# ${lnum:3d}: $line')
|
||||
lnum++
|
||||
}
|
||||
cprintln('# ----------------------------------------------------------------------')
|
||||
}
|
||||
}
|
||||
|
||||
fn modfn(mname string, fname string) string {
|
||||
return '${mname}.$fname'
|
||||
}
|
||||
|
||||
pub fn chdir(path string) {
|
||||
verbose_trace_strong(modfn(@MOD, @FN), 'cd $path')
|
||||
os.chdir(path) or {
|
||||
verbose_trace(modfn(@MOD, @FN), '## failed.')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mkdir(path string) ? {
|
||||
verbose_trace_strong(modfn(@MOD, @FN), 'mkdir $path')
|
||||
os.mkdir(path) or {
|
||||
verbose_trace(modfn(@MOD, @FN), '## failed.')
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mkdir_all(path string) ? {
|
||||
verbose_trace_strong(modfn(@MOD, @FN), 'mkdir -p $path')
|
||||
os.mkdir_all(path) or {
|
||||
verbose_trace(modfn(@MOD, @FN), '## failed.')
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rmrf(path string) {
|
||||
verbose_trace_strong(modfn(@MOD, @FN), 'rm -rf $path')
|
||||
if os.exists(path) {
|
||||
if os.is_dir(path) {
|
||||
os.rmdir_all(path) or { panic(err) }
|
||||
} else {
|
||||
os.rm(path) or { panic(err) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// execute a command, and return a result, or an error, if it failed in any way.
|
||||
pub fn exec(cmd string) ?os.Result {
|
||||
verbose_trace_strong(modfn(@MOD, @FN), cmd)
|
||||
x := os.execute(cmd)
|
||||
if x.exit_code != 0 {
|
||||
verbose_trace(modfn(@MOD, @FN), '## failed.')
|
||||
return error(x.output)
|
||||
}
|
||||
verbose_trace_exec_result(x)
|
||||
return x
|
||||
}
|
||||
|
||||
// run a command, tracing its results, and returning ONLY its output
|
||||
pub fn run(cmd string) string {
|
||||
verbose_trace_strong(modfn(@MOD, @FN), cmd)
|
||||
x := os.execute(cmd)
|
||||
if x.exit_code < 0 {
|
||||
verbose_trace(modfn(@MOD, @FN), '## failed.')
|
||||
return ''
|
||||
}
|
||||
verbose_trace_exec_result(x)
|
||||
if x.exit_code == 0 {
|
||||
return x.output.trim_right('\r\n')
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
pub fn exit_0_status(cmd string) bool {
|
||||
verbose_trace_strong(modfn(@MOD, @FN), cmd)
|
||||
x := os.execute(cmd)
|
||||
if x.exit_code < 0 {
|
||||
verbose_trace(modfn(@MOD, @FN), '## failed.')
|
||||
return false
|
||||
}
|
||||
verbose_trace_exec_result(x)
|
||||
if x.exit_code == 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
pub fn tool_must_exist(toolcmd string) {
|
||||
verbose_trace(modfn(@MOD, @FN), toolcmd)
|
||||
if exit_0_status('type $toolcmd') {
|
||||
return
|
||||
}
|
||||
eprintln('Missing tool: $toolcmd')
|
||||
eprintln('Please try again after you install it.')
|
||||
exit(1)
|
||||
}
|
||||
|
||||
pub fn used_tools_must_exist(tools []string) {
|
||||
for t in tools {
|
||||
tool_must_exist(t)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show_sizes_of_files(files []string) {
|
||||
for f in files {
|
||||
size := os.file_size(f)
|
||||
println('$size $f') // println('${size:10d} $f')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,602 @@
|
|||
module testing
|
||||
|
||||
import os
|
||||
import time
|
||||
import term
|
||||
import benchmark
|
||||
import sync.pool
|
||||
import v.pref
|
||||
import v.util.vtest
|
||||
import runtime
|
||||
|
||||
pub const github_job = os.getenv('GITHUB_JOB')
|
||||
|
||||
pub const show_start = os.getenv('VTEST_SHOW_START') == '1'
|
||||
|
||||
pub const hide_skips = os.getenv('VTEST_HIDE_SKIP') == '1'
|
||||
|
||||
pub const hide_oks = os.getenv('VTEST_HIDE_OK') == '1'
|
||||
|
||||
pub const fail_fast = os.getenv('VTEST_FAIL_FAST') == '1'
|
||||
|
||||
pub const fail_flaky = os.getenv('VTEST_FAIL_FLAKY') == '1'
|
||||
|
||||
pub const test_only = os.getenv('VTEST_ONLY').split_any(',')
|
||||
|
||||
pub const test_only_fn = os.getenv('VTEST_ONLY_FN').split_any(',')
|
||||
|
||||
pub const is_node_present = os.execute('node --version').exit_code == 0
|
||||
|
||||
pub const all_processes = os.execute('ps ax').output.split_any('\r\n')
|
||||
|
||||
pub struct TestSession {
|
||||
pub mut:
|
||||
files []string
|
||||
skip_files []string
|
||||
vexe string
|
||||
vroot string
|
||||
vtmp_dir string
|
||||
vargs string
|
||||
fail_fast bool
|
||||
benchmark benchmark.Benchmark
|
||||
rm_binaries bool = true
|
||||
silent_mode bool
|
||||
progress_mode bool
|
||||
root_relative bool // used by CI runs, so that the output is stable everywhere
|
||||
nmessages chan LogMessage // many publishers, single consumer/printer
|
||||
nmessage_idx int // currently printed message index
|
||||
nprint_ended chan int // read to block till printing ends, 1:1
|
||||
failed_cmds shared []string
|
||||
}
|
||||
|
||||
enum MessageKind {
|
||||
ok
|
||||
fail
|
||||
skip
|
||||
info
|
||||
sentinel
|
||||
}
|
||||
|
||||
struct LogMessage {
|
||||
message string
|
||||
kind MessageKind
|
||||
}
|
||||
|
||||
pub fn (mut ts TestSession) add_failed_cmd(cmd string) {
|
||||
lock ts.failed_cmds {
|
||||
ts.failed_cmds << cmd
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut ts TestSession) show_list_of_failed_tests() {
|
||||
for i, cmd in ts.failed_cmds {
|
||||
eprintln(term.failed('Failed command ${i + 1}:') + ' $cmd')
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut ts TestSession) append_message(kind MessageKind, msg string) {
|
||||
ts.nmessages <- LogMessage{
|
||||
message: msg
|
||||
kind: kind
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut ts TestSession) print_messages() {
|
||||
empty := term.header(' ', ' ')
|
||||
mut print_msg_time := time.new_stopwatch()
|
||||
for {
|
||||
// get a message from the channel of messages to be printed:
|
||||
mut rmessage := <-ts.nmessages
|
||||
if rmessage.kind == .sentinel {
|
||||
// a sentinel for stopping the printing thread
|
||||
if !ts.silent_mode && ts.progress_mode {
|
||||
eprintln('')
|
||||
}
|
||||
ts.nprint_ended <- 0
|
||||
return
|
||||
}
|
||||
if rmessage.kind != .info {
|
||||
ts.nmessage_idx++
|
||||
}
|
||||
msg := rmessage.message.replace_each([
|
||||
'TMP1',
|
||||
'${ts.nmessage_idx:1d}',
|
||||
'TMP2',
|
||||
'${ts.nmessage_idx:2d}',
|
||||
'TMP3',
|
||||
'${ts.nmessage_idx:3d}',
|
||||
'TMP4',
|
||||
'${ts.nmessage_idx:4d}',
|
||||
])
|
||||
is_ok := rmessage.kind == .ok
|
||||
//
|
||||
time_passed := print_msg_time.elapsed().seconds()
|
||||
if time_passed > 10 && ts.silent_mode && is_ok {
|
||||
// Even if OK tests are suppressed,
|
||||
// show *at least* 1 result every 10 seconds,
|
||||
// otherwise the CI can seem stuck ...
|
||||
eprintln(msg)
|
||||
print_msg_time.restart()
|
||||
continue
|
||||
}
|
||||
if ts.progress_mode {
|
||||
// progress mode, the last line is rewritten many times:
|
||||
if is_ok && !ts.silent_mode {
|
||||
print('\r$empty\r$msg')
|
||||
flush_stdout()
|
||||
} else {
|
||||
// the last \n is needed, so SKIP/FAIL messages
|
||||
// will not get overwritten by the OK ones
|
||||
eprint('\r$empty\r$msg\n')
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !ts.silent_mode || !is_ok {
|
||||
// normal expanded mode, or failures in -silent mode
|
||||
eprintln(msg)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_test_session(_vargs string, will_compile bool) TestSession {
|
||||
mut skip_files := []string{}
|
||||
if will_compile {
|
||||
$if msvc {
|
||||
skip_files << 'vlib/v/tests/const_comptime_eval_before_vinit_test.v' // _constructor used
|
||||
}
|
||||
$if solaris {
|
||||
skip_files << 'examples/gg/gg2.v'
|
||||
skip_files << 'examples/pico/pico.v'
|
||||
skip_files << 'examples/sokol/fonts.v'
|
||||
skip_files << 'examples/sokol/drawing.v'
|
||||
}
|
||||
$if macos {
|
||||
skip_files << 'examples/database/mysql.v'
|
||||
skip_files << 'examples/database/orm.v'
|
||||
skip_files << 'examples/database/psql/customer.v'
|
||||
}
|
||||
$if windows {
|
||||
skip_files << 'examples/database/mysql.v'
|
||||
skip_files << 'examples/database/orm.v'
|
||||
skip_files << 'examples/smtp/mail.v' // requires OpenSSL
|
||||
skip_files << 'examples/websocket/ping.v' // requires OpenSSL
|
||||
skip_files << 'examples/websocket/client-server/client.v' // requires OpenSSL
|
||||
skip_files << 'examples/websocket/client-server/server.v' // requires OpenSSL
|
||||
$if tinyc {
|
||||
skip_files << 'examples/database/orm.v' // try fix it
|
||||
}
|
||||
}
|
||||
$if windows {
|
||||
// TODO: remove when closures on windows are supported
|
||||
skip_files << 'examples/pendulum-simulation/animation.v'
|
||||
skip_files << 'examples/pendulum-simulation/full.v'
|
||||
skip_files << 'examples/pendulum-simulation/parallel.v'
|
||||
skip_files << 'examples/pendulum-simulation/parallel_with_iw.v'
|
||||
skip_files << 'examples/pendulum-simulation/sequential.v'
|
||||
}
|
||||
if testing.github_job != 'sokol-shaders-can-be-compiled' {
|
||||
// These examples need .h files that are produced from the supplied .glsl files,
|
||||
// using by the shader compiler tools in https://github.com/floooh/sokol-tools-bin/archive/pre-feb2021-api-changes.tar.gz
|
||||
skip_files << 'examples/sokol/simple_shader_glsl/simple_shader.v'
|
||||
skip_files << 'examples/sokol/02_cubes_glsl/cube_glsl.v'
|
||||
skip_files << 'examples/sokol/03_march_tracing_glsl/rt_glsl.v'
|
||||
skip_files << 'examples/sokol/04_multi_shader_glsl/rt_glsl.v'
|
||||
skip_files << 'examples/sokol/05_instancing_glsl/rt_glsl.v'
|
||||
// Skip obj_viewer code in the CI
|
||||
skip_files << 'examples/sokol/06_obj_viewer/show_obj.v'
|
||||
}
|
||||
if testing.github_job != 'ubuntu-tcc' {
|
||||
skip_files << 'examples/c_interop_wkhtmltopdf.v' // needs installation of wkhtmltopdf from https://github.com/wkhtmltopdf/packaging/releases
|
||||
skip_files << 'examples/call_v_from_python/test.v' // the example only makes sense to be compiled, when python is installed
|
||||
// the ttf_test.v is not interactive, but needs X11 headers to be installed, which is done only on ubuntu-tcc for now
|
||||
skip_files << 'vlib/x/ttf/ttf_test.v'
|
||||
skip_files << 'vlib/vweb/vweb_app_test.v' // imports the `sqlite` module, which in turn includes sqlite3.h
|
||||
}
|
||||
if testing.github_job != 'audio-examples' {
|
||||
skip_files << 'examples/sokol/sounds/melody.v'
|
||||
skip_files << 'examples/sokol/sounds/wav_player.v'
|
||||
skip_files << 'examples/sokol/sounds/simple_sin_tones.v'
|
||||
}
|
||||
}
|
||||
vargs := _vargs.replace('-progress', '').replace('-progress', '')
|
||||
vexe := pref.vexe_path()
|
||||
vroot := os.dir(vexe)
|
||||
new_vtmp_dir := setup_new_vtmp_folder()
|
||||
if term.can_show_color_on_stderr() {
|
||||
os.setenv('VCOLORS', 'always', true)
|
||||
}
|
||||
return TestSession{
|
||||
vexe: vexe
|
||||
vroot: vroot
|
||||
skip_files: skip_files
|
||||
fail_fast: testing.fail_fast
|
||||
vargs: vargs
|
||||
vtmp_dir: new_vtmp_dir
|
||||
silent_mode: _vargs.contains('-silent')
|
||||
progress_mode: _vargs.contains('-progress')
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut ts TestSession) init() {
|
||||
ts.files.sort()
|
||||
ts.benchmark = benchmark.new_benchmark_no_cstep()
|
||||
}
|
||||
|
||||
pub fn (mut ts TestSession) add(file string) {
|
||||
ts.files << file
|
||||
}
|
||||
|
||||
pub fn (mut ts TestSession) test() {
|
||||
// Ensure that .tmp.c files generated from compiling _test.v files,
|
||||
// are easy to delete at the end, *without* affecting the existing ones.
|
||||
current_wd := os.getwd()
|
||||
if current_wd == os.wd_at_startup && current_wd == ts.vroot {
|
||||
ts.root_relative = true
|
||||
}
|
||||
//
|
||||
ts.init()
|
||||
mut remaining_files := []string{}
|
||||
for dot_relative_file in ts.files {
|
||||
file := os.real_path(dot_relative_file)
|
||||
$if windows {
|
||||
if file.contains('sqlite') || file.contains('httpbin') {
|
||||
continue
|
||||
}
|
||||
}
|
||||
$if !macos {
|
||||
if file.contains('customer') {
|
||||
continue
|
||||
}
|
||||
}
|
||||
$if msvc {
|
||||
if file.contains('asm') {
|
||||
continue
|
||||
}
|
||||
}
|
||||
remaining_files << dot_relative_file
|
||||
}
|
||||
remaining_files = vtest.filter_vtest_only(remaining_files, fix_slashes: false)
|
||||
ts.files = remaining_files
|
||||
ts.benchmark.set_total_expected_steps(remaining_files.len)
|
||||
mut njobs := runtime.nr_jobs()
|
||||
if remaining_files.len < njobs {
|
||||
njobs = remaining_files.len
|
||||
}
|
||||
ts.benchmark.njobs = njobs
|
||||
mut pool_of_test_runners := pool.new_pool_processor(callback: worker_trunner)
|
||||
// for handling messages across threads
|
||||
ts.nmessages = chan LogMessage{cap: 10000}
|
||||
ts.nprint_ended = chan int{cap: 0}
|
||||
ts.nmessage_idx = 0
|
||||
go ts.print_messages()
|
||||
pool_of_test_runners.set_shared_context(ts)
|
||||
pool_of_test_runners.work_on_pointers(unsafe { remaining_files.pointers() })
|
||||
ts.benchmark.stop()
|
||||
ts.append_message(.sentinel, '') // send the sentinel
|
||||
_ := <-ts.nprint_ended // wait for the stop of the printing thread
|
||||
eprintln(term.h_divider('-'))
|
||||
// cleanup generated .tmp.c files after successful tests:
|
||||
if ts.benchmark.nfail == 0 {
|
||||
if ts.rm_binaries {
|
||||
os.rmdir_all(ts.vtmp_dir) or {}
|
||||
}
|
||||
}
|
||||
ts.show_list_of_failed_tests()
|
||||
}
|
||||
|
||||
fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
|
||||
mut ts := &TestSession(p.get_shared_context())
|
||||
if ts.fail_fast {
|
||||
if ts.failed_cmds.len > 0 {
|
||||
return pool.no_result
|
||||
}
|
||||
}
|
||||
tmpd := ts.vtmp_dir
|
||||
show_stats := '-stats' in ts.vargs.split(' ')
|
||||
// tls_bench is used to format the step messages/timings
|
||||
mut tls_bench := &benchmark.Benchmark(p.get_thread_context(idx))
|
||||
if isnil(tls_bench) {
|
||||
tls_bench = benchmark.new_benchmark_pointer()
|
||||
tls_bench.set_total_expected_steps(ts.benchmark.nexpected_steps)
|
||||
p.set_thread_context(idx, tls_bench)
|
||||
}
|
||||
tls_bench.no_cstep = true
|
||||
tls_bench.njobs = ts.benchmark.njobs
|
||||
mut relative_file := os.real_path(p.get_item<string>(idx))
|
||||
mut cmd_options := [ts.vargs]
|
||||
mut run_js := false
|
||||
|
||||
is_fmt := ts.vargs.contains('fmt')
|
||||
is_vet := ts.vargs.contains('vet')
|
||||
produces_file_output := !(is_fmt || is_vet)
|
||||
|
||||
if relative_file.ends_with('js.v') {
|
||||
if produces_file_output {
|
||||
cmd_options << ' -b js'
|
||||
run_js = true
|
||||
}
|
||||
}
|
||||
|
||||
if relative_file.contains('global') && !is_fmt {
|
||||
cmd_options << ' -enable-globals'
|
||||
}
|
||||
if ts.root_relative {
|
||||
relative_file = relative_file.replace(ts.vroot + os.path_separator, '')
|
||||
}
|
||||
file := os.real_path(relative_file)
|
||||
normalised_relative_file := relative_file.replace('\\', '/')
|
||||
// Ensure that the generated binaries will be stored in the temporary folder.
|
||||
// Remove them after a test passes/fails.
|
||||
fname := os.file_name(file)
|
||||
generated_binary_fname := if os.user_os() == 'windows' && !run_js {
|
||||
fname.replace('.v', '.exe')
|
||||
} else if !run_js {
|
||||
fname.replace('.v', '')
|
||||
} else {
|
||||
fname.replace('.v', '')
|
||||
}
|
||||
generated_binary_fpath := os.join_path_single(tmpd, generated_binary_fname)
|
||||
if produces_file_output {
|
||||
if os.exists(generated_binary_fpath) {
|
||||
if ts.rm_binaries {
|
||||
os.rm(generated_binary_fpath) or {}
|
||||
}
|
||||
}
|
||||
|
||||
cmd_options << ' -o ${os.quoted_path(generated_binary_fpath)}'
|
||||
}
|
||||
cmd := '${os.quoted_path(ts.vexe)} ' + cmd_options.join(' ') + ' ${os.quoted_path(file)}'
|
||||
ts.benchmark.step()
|
||||
tls_bench.step()
|
||||
if relative_file.replace('\\', '/') in ts.skip_files {
|
||||
ts.benchmark.skip()
|
||||
tls_bench.skip()
|
||||
if !testing.hide_skips {
|
||||
ts.append_message(.skip, tls_bench.step_message_skip(normalised_relative_file))
|
||||
}
|
||||
return pool.no_result
|
||||
}
|
||||
if show_stats {
|
||||
ts.append_message(.ok, term.h_divider('-'))
|
||||
mut status := os.system(cmd)
|
||||
if status != 0 {
|
||||
details := get_test_details(file)
|
||||
os.setenv('VTEST_RETRY_MAX', '$details.retry', true)
|
||||
for retry := 1; retry <= details.retry; retry++ {
|
||||
ts.append_message(.info, ' [stats] retrying $retry/$details.retry of $relative_file ; known flaky: $details.flaky ...')
|
||||
os.setenv('VTEST_RETRY', '$retry', true)
|
||||
status = os.system(cmd)
|
||||
if status == 0 {
|
||||
unsafe {
|
||||
goto test_passed_system
|
||||
}
|
||||
}
|
||||
time.sleep(500 * time.millisecond)
|
||||
}
|
||||
if details.flaky && !testing.fail_flaky {
|
||||
ts.append_message(.info, ' *FAILURE* of the known flaky test file $relative_file is ignored, since VTEST_FAIL_FLAKY is 0 . Retry count: $details.retry .')
|
||||
unsafe {
|
||||
goto test_passed_system
|
||||
}
|
||||
}
|
||||
ts.benchmark.fail()
|
||||
tls_bench.fail()
|
||||
ts.add_failed_cmd(cmd)
|
||||
return pool.no_result
|
||||
} else {
|
||||
test_passed_system:
|
||||
ts.benchmark.ok()
|
||||
tls_bench.ok()
|
||||
}
|
||||
} else {
|
||||
if testing.show_start {
|
||||
ts.append_message(.info, ' starting $relative_file ...')
|
||||
}
|
||||
mut r := os.execute(cmd)
|
||||
if r.exit_code < 0 {
|
||||
ts.benchmark.fail()
|
||||
tls_bench.fail()
|
||||
ts.append_message(.fail, tls_bench.step_message_fail(normalised_relative_file))
|
||||
ts.add_failed_cmd(cmd)
|
||||
return pool.no_result
|
||||
}
|
||||
if r.exit_code != 0 {
|
||||
details := get_test_details(file)
|
||||
os.setenv('VTEST_RETRY_MAX', '$details.retry', true)
|
||||
for retry := 1; retry <= details.retry; retry++ {
|
||||
ts.append_message(.info, ' retrying $retry/$details.retry of $relative_file ; known flaky: $details.flaky ...')
|
||||
os.setenv('VTEST_RETRY', '$retry', true)
|
||||
r = os.execute(cmd)
|
||||
if r.exit_code == 0 {
|
||||
unsafe {
|
||||
goto test_passed_execute
|
||||
}
|
||||
}
|
||||
}
|
||||
if details.flaky && !testing.fail_flaky {
|
||||
ts.append_message(.info, ' *FAILURE* of the known flaky test file $relative_file is ignored, since VTEST_FAIL_FLAKY is 0 . Retry count: $details.retry .')
|
||||
unsafe {
|
||||
goto test_passed_execute
|
||||
}
|
||||
}
|
||||
ts.benchmark.fail()
|
||||
tls_bench.fail()
|
||||
ending_newline := if r.output.ends_with('\n') { '\n' } else { '' }
|
||||
ts.append_message(.fail, tls_bench.step_message_fail('$normalised_relative_file\n$r.output.trim_space()$ending_newline'))
|
||||
ts.add_failed_cmd(cmd)
|
||||
} else {
|
||||
test_passed_execute:
|
||||
ts.benchmark.ok()
|
||||
tls_bench.ok()
|
||||
if !testing.hide_oks {
|
||||
ts.append_message(.ok, tls_bench.step_message_ok(normalised_relative_file))
|
||||
}
|
||||
}
|
||||
}
|
||||
if produces_file_output && os.exists(generated_binary_fpath) && ts.rm_binaries {
|
||||
os.rm(generated_binary_fpath) or {}
|
||||
}
|
||||
return pool.no_result
|
||||
}
|
||||
|
||||
pub fn vlib_should_be_present(parent_dir string) {
|
||||
vlib_dir := os.join_path_single(parent_dir, 'vlib')
|
||||
if !os.is_dir(vlib_dir) {
|
||||
eprintln('$vlib_dir is missing, it must be next to the V executable')
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prepare_test_session(zargs string, folder string, oskipped []string, main_label string) TestSession {
|
||||
vexe := pref.vexe_path()
|
||||
parent_dir := os.dir(vexe)
|
||||
vlib_should_be_present(parent_dir)
|
||||
vargs := zargs.replace(vexe, '')
|
||||
eheader(main_label)
|
||||
if vargs.len > 0 {
|
||||
eprintln('v compiler args: "$vargs"')
|
||||
}
|
||||
mut session := new_test_session(vargs, true)
|
||||
files := os.walk_ext(os.join_path_single(parent_dir, folder), '.v')
|
||||
mut mains := []string{}
|
||||
mut skipped := oskipped.clone()
|
||||
next_file: for f in files {
|
||||
fnormalised := f.replace('\\', '/')
|
||||
// Note: a `testdata` folder, is the preferred name of a folder, containing V code,
|
||||
// that you *do not want* the test framework to find incidentally for various reasons,
|
||||
// for example module import tests, or subtests, that are compiled/run by other parent tests
|
||||
// in specific configurations, etc.
|
||||
if fnormalised.contains('testdata/') || fnormalised.contains('modules/')
|
||||
|| fnormalised.contains('preludes/') {
|
||||
continue
|
||||
}
|
||||
$if windows {
|
||||
// skip pico and process/command examples on windows
|
||||
if fnormalised.ends_with('examples/pico/pico.v')
|
||||
|| fnormalised.ends_with('examples/process/command.v') {
|
||||
continue
|
||||
}
|
||||
}
|
||||
c := os.read_file(f) or { panic(err) }
|
||||
maxc := if c.len > 500 { 500 } else { c.len }
|
||||
start := c[0..maxc]
|
||||
if start.contains('module ') && !start.contains('module main') {
|
||||
skipped_f := f.replace(os.join_path_single(parent_dir, ''), '')
|
||||
skipped << skipped_f
|
||||
}
|
||||
for skip_prefix in oskipped {
|
||||
skip_folder := skip_prefix + '/'
|
||||
if fnormalised.starts_with(skip_folder) {
|
||||
continue next_file
|
||||
}
|
||||
}
|
||||
mains << f
|
||||
}
|
||||
session.files << mains
|
||||
session.skip_files << skipped
|
||||
return session
|
||||
}
|
||||
|
||||
pub type FnTestSetupCb = fn (mut session TestSession)
|
||||
|
||||
pub fn v_build_failing_skipped(zargs string, folder string, oskipped []string, cb FnTestSetupCb) bool {
|
||||
main_label := 'Building $folder ...'
|
||||
finish_label := 'building $folder'
|
||||
mut session := prepare_test_session(zargs, folder, oskipped, main_label)
|
||||
cb(mut session)
|
||||
session.test()
|
||||
eprintln(session.benchmark.total_message(finish_label))
|
||||
return session.failed_cmds.len > 0
|
||||
}
|
||||
|
||||
pub fn build_v_cmd_failed(cmd string) bool {
|
||||
res := os.execute(cmd)
|
||||
if res.exit_code < 0 {
|
||||
return true
|
||||
}
|
||||
if res.exit_code != 0 {
|
||||
eprintln('')
|
||||
eprintln(res.output)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
pub fn building_any_v_binaries_failed() bool {
|
||||
eheader('Building V binaries...')
|
||||
eprintln('VFLAGS is: "' + os.getenv('VFLAGS') + '"')
|
||||
vexe := pref.vexe_path()
|
||||
parent_dir := os.dir(vexe)
|
||||
vlib_should_be_present(parent_dir)
|
||||
os.chdir(parent_dir) or { panic(err) }
|
||||
mut failed := false
|
||||
v_build_commands := ['$vexe -o v_g -g cmd/v', '$vexe -o v_prod_g -prod -g cmd/v',
|
||||
'$vexe -o v_cg -cg cmd/v', '$vexe -o v_prod_cg -prod -cg cmd/v',
|
||||
'$vexe -o v_prod -prod cmd/v']
|
||||
mut bmark := benchmark.new_benchmark()
|
||||
for cmd in v_build_commands {
|
||||
bmark.step()
|
||||
if build_v_cmd_failed(cmd) {
|
||||
bmark.fail()
|
||||
failed = true
|
||||
eprintln(bmark.step_message_fail('command: $cmd . See details above ^^^^^^^'))
|
||||
eprintln('')
|
||||
continue
|
||||
}
|
||||
bmark.ok()
|
||||
if !testing.hide_oks {
|
||||
eprintln(bmark.step_message_ok('command: $cmd'))
|
||||
}
|
||||
}
|
||||
bmark.stop()
|
||||
eprintln(term.h_divider('-'))
|
||||
eprintln(bmark.total_message('building v binaries'))
|
||||
return failed
|
||||
}
|
||||
|
||||
pub fn eheader(msg string) {
|
||||
eprintln(term.header_left(msg, '-'))
|
||||
}
|
||||
|
||||
pub fn header(msg string) {
|
||||
println(term.header_left(msg, '-'))
|
||||
flush_stdout()
|
||||
}
|
||||
|
||||
pub fn setup_new_vtmp_folder() string {
|
||||
now := time.sys_mono_now()
|
||||
new_vtmp_dir := os.join_path(os.temp_dir(), 'v', 'test_session_$now')
|
||||
os.mkdir_all(new_vtmp_dir) or { panic(err) }
|
||||
os.setenv('VTMP', new_vtmp_dir, true)
|
||||
return new_vtmp_dir
|
||||
}
|
||||
|
||||
pub struct TestDetails {
|
||||
pub mut:
|
||||
retry int
|
||||
flaky bool // when flaky tests fail, the whole run is still considered successfull, unless VTEST_FAIL_FLAKY is 1
|
||||
}
|
||||
|
||||
pub fn get_test_details(file string) TestDetails {
|
||||
mut res := TestDetails{}
|
||||
lines := os.read_lines(file) or { [] }
|
||||
for line in lines {
|
||||
if line.starts_with('// vtest retry:') {
|
||||
res.retry = line.all_after(':').trim_space().int()
|
||||
}
|
||||
if line.starts_with('// vtest flaky:') {
|
||||
res.flaky = line.all_after(':').trim_space().bool()
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn find_started_process(pname string) ?string {
|
||||
for line in testing.all_processes {
|
||||
if line.contains(pname) {
|
||||
return line
|
||||
}
|
||||
}
|
||||
return error('could not find process matching $pname')
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
module vgit
|
||||
|
||||
import os
|
||||
import flag
|
||||
import scripting
|
||||
|
||||
pub fn check_v_commit_timestamp_before_self_rebuilding(v_timestamp int) {
|
||||
if v_timestamp >= 1561805697 {
|
||||
return
|
||||
}
|
||||
eprintln('##################################################################')
|
||||
eprintln('# WARNING: v self rebuilding, before 5b7a1e8 (2019-06-29 12:21) #')
|
||||
eprintln('# required the v executable to be built *inside* #')
|
||||
eprintln('# the toplevel compiler/ folder. #')
|
||||
eprintln('# #')
|
||||
eprintln('# That is not supported by this tool. #')
|
||||
eprintln('# You will have to build it manually there. #')
|
||||
eprintln('##################################################################')
|
||||
}
|
||||
|
||||
pub fn validate_commit_exists(commit string) {
|
||||
if commit.len == 0 {
|
||||
return
|
||||
}
|
||||
cmd := "git cat-file -t '$commit' "
|
||||
if !scripting.exit_0_status(cmd) {
|
||||
eprintln('Commit: "$commit" does not exist in the current repository.')
|
||||
exit(3)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn line_to_timestamp_and_commit(line string) (int, string) {
|
||||
parts := line.split(' ')
|
||||
return parts[0].int(), parts[1]
|
||||
}
|
||||
|
||||
pub fn normalized_workpath_for_commit(workdir string, commit string) string {
|
||||
nc := 'v_at_' + commit.replace('^', '_').replace('-', '_').replace('/', '_')
|
||||
return os.real_path(workdir + os.path_separator + nc)
|
||||
}
|
||||
|
||||
fn get_current_folder_commit_hash() string {
|
||||
vline := scripting.run('git rev-list -n1 --timestamp HEAD')
|
||||
_, v_commithash := line_to_timestamp_and_commit(vline)
|
||||
return v_commithash
|
||||
}
|
||||
|
||||
pub fn prepare_vc_source(vcdir string, cdir string, commit string) (string, string) {
|
||||
scripting.chdir(cdir)
|
||||
// Building a historic v with the latest vc is not always possible ...
|
||||
// It is more likely, that the vc *at the time of the v commit*,
|
||||
// or slightly before that time will be able to build the historic v:
|
||||
vline := scripting.run('git rev-list -n1 --timestamp "$commit" ')
|
||||
v_timestamp, v_commithash := line_to_timestamp_and_commit(vline)
|
||||
scripting.verbose_trace(@FN, 'v_timestamp: $v_timestamp | v_commithash: $v_commithash')
|
||||
check_v_commit_timestamp_before_self_rebuilding(v_timestamp)
|
||||
scripting.chdir(vcdir)
|
||||
scripting.run('git checkout --quiet master')
|
||||
//
|
||||
mut vccommit := ''
|
||||
vcbefore_subject_match := scripting.run('git rev-list HEAD -n1 --timestamp --grep=${v_commithash[0..7]} ')
|
||||
scripting.verbose_trace(@FN, 'vcbefore_subject_match: $vcbefore_subject_match')
|
||||
if vcbefore_subject_match.len > 3 {
|
||||
_, vccommit = line_to_timestamp_and_commit(vcbefore_subject_match)
|
||||
} else {
|
||||
scripting.verbose_trace(@FN, 'the v commit did not match anything in the vc log; try --timestamp instead.')
|
||||
vcbefore := scripting.run('git rev-list HEAD -n1 --timestamp --before=$v_timestamp ')
|
||||
_, vccommit = line_to_timestamp_and_commit(vcbefore)
|
||||
}
|
||||
scripting.verbose_trace(@FN, 'vccommit: $vccommit')
|
||||
scripting.run('git checkout --quiet "$vccommit" ')
|
||||
scripting.run('wc *.c')
|
||||
scripting.chdir(cdir)
|
||||
return v_commithash, vccommit
|
||||
}
|
||||
|
||||
pub fn clone_or_pull(remote_git_url string, local_worktree_path string) {
|
||||
// Note: after clone_or_pull, the current repo branch is === HEAD === master
|
||||
if os.is_dir(local_worktree_path) && os.is_dir(os.join_path_single(local_worktree_path, '.git')) {
|
||||
// Already existing ... Just pulling in this case is faster usually.
|
||||
scripting.run('git -C "$local_worktree_path" checkout --quiet master')
|
||||
scripting.run('git -C "$local_worktree_path" pull --quiet ')
|
||||
} else {
|
||||
// Clone a fresh
|
||||
scripting.run('git clone --quiet "$remote_git_url" "$local_worktree_path" ')
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VGitContext {
|
||||
pub:
|
||||
cc string = 'cc' // what compiler to use
|
||||
workdir string = '/tmp' // the base working folder
|
||||
commit_v string = 'master' // the commit-ish that needs to be prepared
|
||||
path_v string // where is the local working copy v repo
|
||||
path_vc string // where is the local working copy vc repo
|
||||
v_repo_url string // the remote v repo URL
|
||||
vc_repo_url string // the remote vc repo URL
|
||||
pub mut:
|
||||
// these will be filled by vgitcontext.compile_oldv_if_needed()
|
||||
commit_v__hash string // the git commit of the v repo that should be prepared
|
||||
commit_vc_hash string // the git commit of the vc repo, corresponding to commit_v__hash
|
||||
vexename string // v or v.exe
|
||||
vexepath string // the full absolute path to the prepared v/v.exe
|
||||
vvlocation string // v.v or compiler/ or cmd/v, depending on v version
|
||||
make_fresh_tcc bool // whether to do 'make fresh_tcc' before compiling an old V.
|
||||
}
|
||||
|
||||
pub fn (mut vgit_context VGitContext) compile_oldv_if_needed() {
|
||||
vgit_context.vexename = if os.user_os() == 'windows' { 'v.exe' } else { 'v' }
|
||||
vgit_context.vexepath = os.real_path(os.join_path_single(vgit_context.path_v, vgit_context.vexename))
|
||||
mut command_for_building_v_from_c_source := ''
|
||||
mut command_for_selfbuilding := ''
|
||||
if 'windows' == os.user_os() {
|
||||
command_for_building_v_from_c_source = '$vgit_context.cc -std=c99 -I ./thirdparty/stdatomic/win -municode -w -o cv.exe "$vgit_context.path_vc/v_win.c" '
|
||||
command_for_selfbuilding = './cv.exe -o $vgit_context.vexename {SOURCE}'
|
||||
} else {
|
||||
command_for_building_v_from_c_source = '$vgit_context.cc -std=gnu11 -I ./thirdparty/stdatomic/nix -w -o cv "$vgit_context.path_vc/v.c" -lm -lpthread'
|
||||
command_for_selfbuilding = './cv -o $vgit_context.vexename {SOURCE}'
|
||||
}
|
||||
scripting.chdir(vgit_context.workdir)
|
||||
clone_or_pull(vgit_context.v_repo_url, vgit_context.path_v)
|
||||
clone_or_pull(vgit_context.vc_repo_url, vgit_context.path_vc)
|
||||
scripting.chdir(vgit_context.path_v)
|
||||
scripting.run('git checkout --quiet $vgit_context.commit_v')
|
||||
if os.is_dir(vgit_context.path_v) && os.exists(vgit_context.vexepath) {
|
||||
// already compiled, so no need to compile v again
|
||||
vgit_context.commit_v__hash = get_current_folder_commit_hash()
|
||||
return
|
||||
}
|
||||
v_commithash, vccommit_before := prepare_vc_source(vgit_context.path_vc, vgit_context.path_v,
|
||||
'HEAD')
|
||||
vgit_context.commit_v__hash = v_commithash
|
||||
vgit_context.commit_vc_hash = vccommit_before
|
||||
if os.exists('cmd/v') {
|
||||
vgit_context.vvlocation = 'cmd/v'
|
||||
} else {
|
||||
vgit_context.vvlocation = if os.exists('v.v') { 'v.v' } else { 'compiler' }
|
||||
}
|
||||
if os.is_dir(vgit_context.path_v) && os.exists(vgit_context.vexepath) {
|
||||
// already compiled, so no need to compile v again
|
||||
return
|
||||
}
|
||||
// Recompilation is needed. Just to be sure, clean up everything first.
|
||||
scripting.run('git clean -xf')
|
||||
if vgit_context.make_fresh_tcc {
|
||||
scripting.run('make fresh_tcc')
|
||||
}
|
||||
scripting.run(command_for_building_v_from_c_source)
|
||||
build_cmd := command_for_selfbuilding.replace('{SOURCE}', vgit_context.vvlocation)
|
||||
scripting.run(build_cmd)
|
||||
// At this point, there exists a file vgit_context.vexepath
|
||||
// which should be a valid working V executable.
|
||||
}
|
||||
|
||||
pub struct VGitOptions {
|
||||
pub mut:
|
||||
workdir string // the working folder (typically /tmp), where the tool will write
|
||||
v_repo_url string // the url of the V repository. It can be a local folder path, if you want to eliminate network operations...
|
||||
vc_repo_url string // the url of the vc repository. It can be a local folder path, if you want to eliminate network operations...
|
||||
show_help bool // whether to show the usage screen
|
||||
verbose bool // should the tool be much more verbose
|
||||
}
|
||||
|
||||
pub fn add_common_tool_options(mut context VGitOptions, mut fp flag.FlagParser) []string {
|
||||
tdir := os.temp_dir()
|
||||
context.workdir = os.real_path(fp.string('workdir', `w`, context.workdir, 'A writable base folder. Default: $tdir'))
|
||||
context.v_repo_url = fp.string('vrepo', 0, context.v_repo_url, 'The url of the V repository. You can clone it locally too. See also --vcrepo below.')
|
||||
context.vc_repo_url = fp.string('vcrepo', 0, context.vc_repo_url, 'The url of the vc repository. You can clone it
|
||||
${flag.space}beforehand, and then just give the local folder
|
||||
${flag.space}path here. That will eliminate the network ops
|
||||
${flag.space}done by this tool, which is useful, if you want
|
||||
${flag.space}to script it/run it in a restrictive vps/docker.
|
||||
')
|
||||
context.show_help = fp.bool('help', `h`, false, 'Show this help screen.')
|
||||
context.verbose = fp.bool('verbose', `v`, false, 'Be more verbose.')
|
||||
if context.show_help {
|
||||
println(fp.usage())
|
||||
exit(0)
|
||||
}
|
||||
if context.verbose {
|
||||
scripting.set_verbose(true)
|
||||
}
|
||||
if os.is_dir(context.v_repo_url) {
|
||||
context.v_repo_url = os.real_path(context.v_repo_url)
|
||||
}
|
||||
if os.is_dir(context.vc_repo_url) {
|
||||
context.vc_repo_url = os.real_path(context.vc_repo_url)
|
||||
}
|
||||
commits := fp.finalize() or {
|
||||
eprintln('Error: $err')
|
||||
exit(1)
|
||||
}
|
||||
for commit in commits {
|
||||
validate_commit_exists(commit)
|
||||
}
|
||||
return commits
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
module vhelp
|
||||
|
||||
import os
|
||||
|
||||
pub fn show_topic(topic string) {
|
||||
vexe := os.real_path(os.getenv('VEXE'))
|
||||
vroot := os.dir(vexe)
|
||||
target_topic := os.join_path(vroot, 'cmd', 'v', 'help', '${topic}.txt')
|
||||
content := os.read_file(target_topic) or {
|
||||
eprintln('Unknown topic: $topic')
|
||||
exit(1)
|
||||
}
|
||||
println(content)
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
import os
|
||||
import flag
|
||||
import scripting
|
||||
import vgit
|
||||
|
||||
const (
|
||||
tool_version = '0.0.3'
|
||||
tool_description = ' Checkout an old V and compile it as it was on specific commit.
|
||||
| This tool is useful, when you want to discover when something broke.
|
||||
| It is also useful, when you just want to experiment with an older historic V.
|
||||
|
|
||||
| The VCOMMIT argument can be a git commitish like HEAD or master and so on.
|
||||
| When oldv is used with git bisect, you probably want to give HEAD. For example:
|
||||
| git bisect start
|
||||
| git bisect bad
|
||||
| git checkout known_good_commit
|
||||
| git bisect good
|
||||
| ## Now git will automatically checkout a middle commit between the bad and the good
|
||||
| cmd/tools/oldv --bisect --command="run commands in oldv folder, to verify if the commit is good or bad"
|
||||
| ## See what the result is, and either do: ...
|
||||
| git bisect good
|
||||
| ## ... or do:
|
||||
| git bisect bad
|
||||
| ## Now you just repeat the above steps, each time running oldv with the same command, then mark the result as good or bad,
|
||||
| ## until you find the commit, where the problem first occurred.
|
||||
| ## When you finish, do not forget to do:
|
||||
| git bisect reset'.strip_margin()
|
||||
)
|
||||
|
||||
struct Context {
|
||||
mut:
|
||||
vgo vgit.VGitOptions
|
||||
vgcontext vgit.VGitContext
|
||||
commit_v string = 'master' // the commit from which you want to produce a working v compiler (this may be a commit-ish too)
|
||||
commit_v_hash string // this will be filled from the commit-ish commit_v using rev-list. It IS a commit hash.
|
||||
path_v string // the full path to the v folder inside workdir.
|
||||
path_vc string // the full path to the vc folder inside workdir.
|
||||
cmd_to_run string // the command that you want to run *in* the oldv repo
|
||||
cc string = 'cc' // the C compiler to use for bootstrapping.
|
||||
cleanup bool // should the tool run a cleanup first
|
||||
use_cache bool // use local cached copies for --vrepo and --vcrepo in
|
||||
fresh_tcc bool // do use `make fresh_tcc`
|
||||
is_bisect bool // bisect mode; usage: `cmd/tools/oldv -b -c './v run bug.v'`
|
||||
}
|
||||
|
||||
fn (mut c Context) compile_oldv_if_needed() {
|
||||
c.vgcontext = vgit.VGitContext{
|
||||
workdir: c.vgo.workdir
|
||||
v_repo_url: c.vgo.v_repo_url
|
||||
vc_repo_url: c.vgo.vc_repo_url
|
||||
cc: c.cc
|
||||
commit_v: c.commit_v
|
||||
path_v: c.path_v
|
||||
path_vc: c.path_vc
|
||||
make_fresh_tcc: c.fresh_tcc
|
||||
}
|
||||
c.vgcontext.compile_oldv_if_needed()
|
||||
c.commit_v_hash = c.vgcontext.commit_v__hash
|
||||
if !os.exists(c.vgcontext.vexepath) && c.cmd_to_run.len > 0 {
|
||||
// Note: 125 is a special code, that git bisect understands as 'skip this commit'.
|
||||
// it is used to inform git bisect that the current commit leads to a build failure.
|
||||
exit(125)
|
||||
}
|
||||
}
|
||||
|
||||
const cache_oldv_folder = os.join_path(os.cache_dir(), 'oldv')
|
||||
|
||||
const cache_oldv_folder_v = os.join_path(cache_oldv_folder, 'v')
|
||||
|
||||
const cache_oldv_folder_vc = os.join_path(cache_oldv_folder, 'vc')
|
||||
|
||||
fn sync_cache() {
|
||||
scripting.verbose_trace(@FN, 'start')
|
||||
if !os.exists(cache_oldv_folder) {
|
||||
scripting.verbose_trace(@FN, 'creating $cache_oldv_folder')
|
||||
scripting.mkdir_all(cache_oldv_folder) or {
|
||||
scripting.verbose_trace(@FN, '## failed.')
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
scripting.chdir(cache_oldv_folder)
|
||||
for reponame in ['v', 'vc'] {
|
||||
repofolder := os.join_path(cache_oldv_folder, reponame)
|
||||
if !os.exists(repofolder) {
|
||||
scripting.verbose_trace(@FN, 'cloning to $repofolder')
|
||||
scripting.exec('git clone --quiet https://github.com/vlang/$reponame $repofolder') or {
|
||||
scripting.verbose_trace(@FN, '## error during clone: $err')
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
scripting.chdir(repofolder)
|
||||
scripting.exec('git pull --quiet') or {
|
||||
scripting.verbose_trace(@FN, 'pulling to $repofolder')
|
||||
scripting.verbose_trace(@FN, '## error during pull: $err')
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
scripting.verbose_trace(@FN, 'done')
|
||||
}
|
||||
|
||||
fn main() {
|
||||
scripting.used_tools_must_exist(['git', 'cc'])
|
||||
//
|
||||
// Resetting VEXE here allows for `v run cmd/tools/oldv.v'.
|
||||
// the parent V would have set VEXE, which later will
|
||||
// affect the V's run from the tool itself.
|
||||
os.setenv('VEXE', '', true)
|
||||
//
|
||||
mut context := Context{}
|
||||
context.vgo.workdir = cache_oldv_folder
|
||||
mut fp := flag.new_flag_parser(os.args)
|
||||
fp.application(os.file_name(os.executable()))
|
||||
fp.version(tool_version)
|
||||
fp.description(tool_description)
|
||||
fp.arguments_description('VCOMMIT')
|
||||
fp.skip_executable()
|
||||
context.use_cache = fp.bool('cache', `u`, true, 'Use a cache of local repositories for --vrepo and --vcrepo in \$HOME/.cache/oldv/')
|
||||
if context.use_cache {
|
||||
context.vgo.v_repo_url = cache_oldv_folder_v
|
||||
context.vgo.vc_repo_url = cache_oldv_folder_vc
|
||||
} else {
|
||||
context.vgo.v_repo_url = 'https://github.com/vlang/v'
|
||||
context.vgo.vc_repo_url = 'https://github.com/vlang/vc'
|
||||
}
|
||||
should_sync := fp.bool('cache-sync', `s`, false, 'Update the local cache')
|
||||
context.is_bisect = fp.bool('bisect', `b`, false, 'Bisect mode. Use the current commit in the repo where oldv is.')
|
||||
if !should_sync && !context.is_bisect {
|
||||
fp.limit_free_args(1, 1)?
|
||||
}
|
||||
////
|
||||
context.cleanup = fp.bool('clean', 0, false, 'Clean before running (slower).')
|
||||
context.fresh_tcc = fp.bool('fresh_tcc', 0, true, 'Do `make fresh_tcc` when preparing a V compiler.')
|
||||
context.cmd_to_run = fp.string('command', `c`, '', 'Command to run in the old V repo.\n')
|
||||
commits := vgit.add_common_tool_options(mut context.vgo, mut fp)
|
||||
if should_sync {
|
||||
sync_cache()
|
||||
exit(0)
|
||||
}
|
||||
if context.use_cache {
|
||||
if !os.is_dir(cache_oldv_folder_v) || !os.is_dir(cache_oldv_folder_vc) {
|
||||
sync_cache()
|
||||
}
|
||||
}
|
||||
if commits.len > 0 {
|
||||
context.commit_v = commits[0]
|
||||
if context.is_bisect {
|
||||
eprintln('In bisect mode, you should not pass any commits, since oldv will use the current one.')
|
||||
exit(2)
|
||||
}
|
||||
} else {
|
||||
context.commit_v = scripting.run('git rev-list -n1 HEAD')
|
||||
}
|
||||
scripting.cprintln('################# context.commit_v: $context.commit_v #####################')
|
||||
context.path_v = vgit.normalized_workpath_for_commit(context.vgo.workdir, context.commit_v)
|
||||
context.path_vc = vgit.normalized_workpath_for_commit(context.vgo.workdir, 'vc')
|
||||
if !os.is_dir(context.vgo.workdir) {
|
||||
eprintln('Work folder: $context.vgo.workdir , does not exist.')
|
||||
exit(2)
|
||||
}
|
||||
ecc := os.getenv('CC')
|
||||
if ecc != '' {
|
||||
context.cc = ecc
|
||||
}
|
||||
if context.cleanup {
|
||||
scripting.rmrf(context.path_v)
|
||||
scripting.rmrf(context.path_vc)
|
||||
}
|
||||
context.compile_oldv_if_needed()
|
||||
scripting.chdir(context.path_v)
|
||||
shorter_hash := context.commit_v_hash[0..10]
|
||||
scripting.cprintln('# v commit hash: $shorter_hash | folder: $context.path_v')
|
||||
if context.cmd_to_run.len > 0 {
|
||||
scripting.cprintln_strong('# command: ${context.cmd_to_run:-34s}')
|
||||
cmdres := os.execute_or_exit(context.cmd_to_run)
|
||||
if cmdres.exit_code != 0 {
|
||||
scripting.cprintln_strong('# exit code: ${cmdres.exit_code:-4d}')
|
||||
}
|
||||
scripting.cprint_strong('# result: ')
|
||||
print(cmdres.output)
|
||||
if !cmdres.output.ends_with('\n') {
|
||||
println('')
|
||||
}
|
||||
exit(cmdres.exit_code)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
import os
|
||||
import flag
|
||||
import scripting
|
||||
import vgit
|
||||
|
||||
const (
|
||||
tool_version = '0.0.5'
|
||||
tool_description = " Compares V executable size and performance,
|
||||
| between 2 commits from V's local git history.
|
||||
| When only one commit is given, it is compared to master.
|
||||
| ".strip_margin()
|
||||
)
|
||||
|
||||
struct Context {
|
||||
cwd string // current working folder
|
||||
mut:
|
||||
vgo vgit.VGitOptions
|
||||
a string // the full path to the 'after' folder inside workdir
|
||||
b string // the full path to the 'before' folder inside workdir
|
||||
vc string // the full path to the vc folder inside workdir. It is used during bootstrapping v from the C source.
|
||||
commit_before string // the git commit for the 'before' state
|
||||
commit_after string // the git commit for the 'after' state
|
||||
warmups int // how many times to execute a command before gathering stats
|
||||
hyperfineopts string // use for additional CLI options that will be given to the hyperfine command
|
||||
vflags string // other v options to pass to compared v commands
|
||||
}
|
||||
|
||||
fn new_context() Context {
|
||||
return Context{
|
||||
cwd: os.getwd()
|
||||
commit_after: 'master'
|
||||
warmups: 4
|
||||
}
|
||||
}
|
||||
|
||||
fn (c Context) compare_versions() {
|
||||
// Input is validated at this point...
|
||||
// Cleanup artifacts from previous runs of this tool:
|
||||
scripting.chdir(c.vgo.workdir)
|
||||
scripting.run('rm -rf "$c.a" "$c.b" "$c.vc" ')
|
||||
// clone the VC source *just once per comparison*, and reuse it:
|
||||
scripting.run('git clone --quiet "$c.vgo.vc_repo_url" "$c.vc" ')
|
||||
println('Comparing V performance of commit $c.commit_before (before) vs commit $c.commit_after (after) ...')
|
||||
c.prepare_v(c.b, c.commit_before)
|
||||
c.prepare_v(c.a, c.commit_after)
|
||||
scripting.chdir(c.vgo.workdir)
|
||||
if c.vflags.len > 0 {
|
||||
os.setenv('VFLAGS', c.vflags, true)
|
||||
}
|
||||
// The first is the baseline, against which all the others will be compared.
|
||||
// It is the fastest, since hello_world.v has only a single println in it,
|
||||
mut perf_files := []string{}
|
||||
perf_files << c.compare_v_performance('source_hello', [
|
||||
'vprod @DEBUG@ -o source.c examples/hello_world.v',
|
||||
'vprod -o source.c examples/hello_world.v',
|
||||
'v @DEBUG@ -o source.c examples/hello_world.v',
|
||||
'v -o source.c examples/hello_world.v',
|
||||
])
|
||||
perf_files << c.compare_v_performance('source_v', [
|
||||
'vprod @DEBUG@ -o source.c @COMPILER@',
|
||||
'vprod -o source.c @COMPILER@',
|
||||
'v @DEBUG@ -o source.c @COMPILER@',
|
||||
'v -o source.c @COMPILER@',
|
||||
])
|
||||
perf_files << c.compare_v_performance('binary_hello', [
|
||||
'vprod -o hello examples/hello_world.v',
|
||||
'v -o hello examples/hello_world.v',
|
||||
])
|
||||
perf_files << c.compare_v_performance('binary_v', [
|
||||
'vprod -o binary @COMPILER@',
|
||||
'v -o binary @COMPILER@',
|
||||
])
|
||||
println('All performance files:')
|
||||
for f in perf_files {
|
||||
println(' $f')
|
||||
}
|
||||
}
|
||||
|
||||
fn (c &Context) prepare_v(cdir string, commit string) {
|
||||
mut cc := os.getenv('CC')
|
||||
if cc == '' {
|
||||
cc = 'cc'
|
||||
}
|
||||
mut vgit_context := vgit.VGitContext{
|
||||
cc: cc
|
||||
commit_v: commit
|
||||
path_v: cdir
|
||||
path_vc: c.vc
|
||||
workdir: c.vgo.workdir
|
||||
v_repo_url: c.vgo.v_repo_url
|
||||
vc_repo_url: c.vgo.vc_repo_url
|
||||
}
|
||||
vgit_context.compile_oldv_if_needed()
|
||||
scripting.chdir(cdir)
|
||||
println('Making a v compiler in $cdir')
|
||||
scripting.run('./v -cc $cc -o v $vgit_context.vvlocation')
|
||||
println('Making a vprod compiler in $cdir')
|
||||
scripting.run('./v -cc $cc -prod -o vprod $vgit_context.vvlocation')
|
||||
println('Stripping and compressing cv v and vprod binaries in $cdir')
|
||||
scripting.run('cp cv cv_stripped')
|
||||
scripting.run('cp v v_stripped')
|
||||
scripting.run('cp vprod vprod_stripped')
|
||||
scripting.run('strip *_stripped')
|
||||
scripting.run('cp cv_stripped cv_stripped_upxed')
|
||||
scripting.run('cp v_stripped v_stripped_upxed')
|
||||
scripting.run('cp vprod_stripped vprod_stripped_upxed')
|
||||
scripting.run('upx -qqq --lzma cv_stripped_upxed')
|
||||
scripting.run('upx -qqq --lzma v_stripped_upxed')
|
||||
scripting.run('upx -qqq --lzma vprod_stripped_upxed')
|
||||
scripting.show_sizes_of_files(['$cdir/cv', '$cdir/cv_stripped', '$cdir/cv_stripped_upxed'])
|
||||
scripting.show_sizes_of_files(['$cdir/v', '$cdir/v_stripped', '$cdir/v_stripped_upxed'])
|
||||
scripting.show_sizes_of_files(['$cdir/vprod', '$cdir/vprod_stripped',
|
||||
'$cdir/vprod_stripped_upxed'])
|
||||
vversion := scripting.run('$cdir/v -version')
|
||||
vcommit := scripting.run('git rev-parse --short --verify HEAD')
|
||||
println('V version is: $vversion , local source commit: $vcommit')
|
||||
if vgit_context.vvlocation == 'cmd/v' {
|
||||
if os.exists('vlib/v/ast/ast.v') {
|
||||
println('Source lines of the compiler: ' +
|
||||
scripting.run('find cmd/v/ vlib/v/ -name "*.v" | grep -v /tests/ | xargs wc | tail -n -1'))
|
||||
} else {
|
||||
println('Source lines of the compiler: ' +
|
||||
scripting.run('wc cmd/v/*.v vlib/compiler/*.v | tail -n -1'))
|
||||
}
|
||||
} else if vgit_context.vvlocation == 'v.v' {
|
||||
println('Source lines of the compiler: ' +
|
||||
scripting.run('wc v.v vlib/compiler/*.v | tail -n -1'))
|
||||
} else {
|
||||
println('Source lines of the compiler: ' + scripting.run('wc compiler/*.v | tail -n -1'))
|
||||
}
|
||||
}
|
||||
|
||||
fn (c Context) compare_v_performance(label string, commands []string) string {
|
||||
println('---------------------------------------------------------------------------------')
|
||||
println('Compare v performance when doing the following commands ($label):')
|
||||
mut source_location_a := ''
|
||||
mut source_location_b := ''
|
||||
if os.exists('$c.a/cmd/v') {
|
||||
source_location_a = 'cmd/v'
|
||||
} else {
|
||||
source_location_a = if os.exists('$c.a/v.v') { 'v.v ' } else { 'compiler/ ' }
|
||||
}
|
||||
if os.exists('$c.b/cmd/v') {
|
||||
source_location_b = 'cmd/v'
|
||||
} else {
|
||||
source_location_b = if os.exists('$c.b/v.v') { 'v.v ' } else { 'compiler/ ' }
|
||||
}
|
||||
timestamp_a, _ := vgit.line_to_timestamp_and_commit(scripting.run('cd $c.a/ ; git rev-list -n1 --timestamp HEAD'))
|
||||
timestamp_b, _ := vgit.line_to_timestamp_and_commit(scripting.run('cd $c.b/ ; git rev-list -n1 --timestamp HEAD'))
|
||||
debug_option_a := if timestamp_a > 1570877641 { '-cg ' } else { '-debug ' }
|
||||
debug_option_b := if timestamp_b > 1570877641 { '-cg ' } else { '-debug ' }
|
||||
mut hyperfine_commands_arguments := []string{}
|
||||
for cmd in commands {
|
||||
println(cmd)
|
||||
}
|
||||
for cmd in commands {
|
||||
hyperfine_commands_arguments << ' \'cd ${c.b:-34s} ; ./$cmd \' '.replace_each([
|
||||
'@COMPILER@',
|
||||
source_location_b,
|
||||
'@DEBUG@',
|
||||
debug_option_b,
|
||||
])
|
||||
}
|
||||
for cmd in commands {
|
||||
hyperfine_commands_arguments << ' \'cd ${c.a:-34s} ; ./$cmd \' '.replace_each([
|
||||
'@COMPILER@',
|
||||
source_location_a,
|
||||
'@DEBUG@',
|
||||
debug_option_a,
|
||||
])
|
||||
}
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
cmd_stats_file := os.real_path([c.vgo.workdir, 'v_performance_stats_${label}.json'].join(os.path_separator))
|
||||
comparison_cmd := 'hyperfine $c.hyperfineopts ' + '--export-json $cmd_stats_file ' +
|
||||
'--time-unit millisecond ' + '--style full --warmup $c.warmups ' +
|
||||
hyperfine_commands_arguments.join(' ')
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
if c.vgo.verbose {
|
||||
println(comparison_cmd)
|
||||
}
|
||||
os.system(comparison_cmd)
|
||||
println('The detailed performance comparison report was saved to: $cmd_stats_file .')
|
||||
println('')
|
||||
return cmd_stats_file
|
||||
}
|
||||
|
||||
fn main() {
|
||||
scripting.used_tools_must_exist(['cp', 'rm', 'strip', 'make', 'git', 'upx', 'cc', 'wc', 'tail',
|
||||
'find', 'xargs', 'hyperfine'])
|
||||
mut context := new_context()
|
||||
mut fp := flag.new_flag_parser(os.args)
|
||||
fp.application(os.file_name(os.executable()))
|
||||
fp.version(tool_version)
|
||||
fp.description(tool_description)
|
||||
fp.arguments_description('COMMIT_BEFORE [COMMIT_AFTER]')
|
||||
fp.skip_executable()
|
||||
fp.limit_free_args(1, 2)?
|
||||
context.vflags = fp.string('vflags', 0, '', 'Additional options to pass to the v commands, for example "-cc tcc"')
|
||||
context.hyperfineopts = fp.string('hyperfine_options', 0, '', 'Additional options passed to hyperfine.
|
||||
${flag.space}For example on linux, you may want to pass:
|
||||
$flag.space--hyperfine_options "--prepare \'sync; echo 3 | sudo tee /proc/sys/vm/drop_caches\'"
|
||||
')
|
||||
commits := vgit.add_common_tool_options(mut context.vgo, mut fp)
|
||||
context.commit_before = commits[0]
|
||||
if commits.len > 1 {
|
||||
context.commit_after = commits[1]
|
||||
}
|
||||
context.b = vgit.normalized_workpath_for_commit(context.vgo.workdir, context.commit_before)
|
||||
context.a = vgit.normalized_workpath_for_commit(context.vgo.workdir, context.commit_after)
|
||||
context.vc = vgit.normalized_workpath_for_commit(context.vgo.workdir, 'vc')
|
||||
if !os.is_dir(context.vgo.workdir) {
|
||||
msg := 'Work folder: ' + context.vgo.workdir + ' , does not exist.'
|
||||
eprintln(msg)
|
||||
exit(2)
|
||||
}
|
||||
context.compare_versions()
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
import os
|
||||
import term
|
||||
import flag
|
||||
|
||||
const tools_folder = os.real_path(os.dir(os.executable()))
|
||||
|
||||
const oldvexe = fullpath(tools_folder, 'oldv')
|
||||
|
||||
const oldv_source = fullpath(tools_folder, 'oldv.v')
|
||||
|
||||
const vroot = os.real_path(os.dir(os.dir(tools_folder)))
|
||||
|
||||
const vexe = fullpath(vroot, 'v')
|
||||
|
||||
fn fullpath(folder string, fname string) string {
|
||||
return os.real_path(os.join_path_single(folder, exename(fname)))
|
||||
}
|
||||
|
||||
fn exename(n string) string {
|
||||
if n.ends_with('.v') || os.user_os() != 'windows' {
|
||||
return n
|
||||
}
|
||||
return '${n}.exe'
|
||||
}
|
||||
|
||||
struct Context {
|
||||
mut:
|
||||
old_commit string
|
||||
new_commit string
|
||||
command string
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut fp := flag.new_flag_parser(os.args)
|
||||
mut context := Context{}
|
||||
fp.application(os.file_name(os.executable()))
|
||||
fp.version('0.0.2')
|
||||
fp.description('\n Find at what commit a regression occurred.
|
||||
To find when a regression happened (regression_bug.v should fail on master):
|
||||
./v run cmd/tools/regress.v --old a7019ac --command " ./v run /abs/path/to/regression_bug.v"
|
||||
To find when a feature was implemented (feature.v should succeed on master):
|
||||
./v run cmd/tools/regress.v --old a7019ac --command "! ./v run /abs/path/to/feature.v"')
|
||||
fp.skip_executable()
|
||||
//
|
||||
context.new_commit = fp.string('new', `n`, 'master', 'The new commit, by default: master.')
|
||||
context.old_commit = fp.string('old', `o`, '', 'A known old commit, required (for it, COMMAND should exit with 0).')
|
||||
context.command = fp.string('command', `c`, '', 'A command to execute. Should exit with 0 for the *old* commits.')
|
||||
fp.finalize() or {}
|
||||
if context.old_commit == '' {
|
||||
eprintln('--old COMMIT is required')
|
||||
exit(1)
|
||||
}
|
||||
if context.command == '' {
|
||||
eprintln('--command "COMMAND" is required')
|
||||
exit(2)
|
||||
}
|
||||
if !os.exists(oldvexe) {
|
||||
if 0 != execute('${os.quoted_path(vexe)} -o ${os.quoted_path(oldvexe)} ${os.quoted_path(oldv_source)}') {
|
||||
panic('can not compile $oldvexe')
|
||||
}
|
||||
}
|
||||
os.execute('git checkout master')
|
||||
os.execute('git bisect reset')
|
||||
os.execute('git checkout $context.new_commit')
|
||||
os.execute('git bisect start')
|
||||
os.execute('git bisect new')
|
||||
os.execute('git checkout $context.old_commit')
|
||||
os.execute('git bisect old')
|
||||
println(term.colorize(term.bright_yellow, term.header('', '-')))
|
||||
execute('git bisect run ${os.quoted_path(oldvexe)} --bisect -c "$context.command"')
|
||||
println(term.colorize(term.bright_yellow, term.header('', '-')))
|
||||
os.execute('git bisect reset')
|
||||
os.execute('git checkout master')
|
||||
}
|
||||
|
||||
fn execute(cmd string) int {
|
||||
eprintln('### $cmd')
|
||||
return os.system(cmd)
|
||||
}
|
|
@ -0,0 +1,379 @@
|
|||
module main
|
||||
|
||||
import os
|
||||
import flag
|
||||
import time
|
||||
import term
|
||||
import math
|
||||
import scripting
|
||||
|
||||
struct CmdResult {
|
||||
mut:
|
||||
runs int
|
||||
cmd string
|
||||
icmd int
|
||||
outputs []string
|
||||
oms map[string][]int
|
||||
summary map[string]Aints
|
||||
timings []int
|
||||
atiming Aints
|
||||
}
|
||||
|
||||
struct Context {
|
||||
mut:
|
||||
count int
|
||||
series int
|
||||
warmup int
|
||||
show_help bool
|
||||
show_output bool
|
||||
use_newline bool // use \n instead of \r, so the last line is not overwritten
|
||||
fail_on_regress_percent int
|
||||
fail_on_maxtime int // in ms
|
||||
verbose bool
|
||||
commands []string
|
||||
results []CmdResult
|
||||
cmd_template string // {T} will be substituted with the current command
|
||||
cmd_params map[string][]string
|
||||
cline string // a terminal clearing line
|
||||
cgoback string
|
||||
nmins int // number of minimums to discard
|
||||
nmaxs int // number of maximums to discard
|
||||
}
|
||||
|
||||
[unsafe]
|
||||
fn (mut result CmdResult) free() {
|
||||
unsafe {
|
||||
result.cmd.free()
|
||||
result.outputs.free()
|
||||
result.oms.free()
|
||||
result.summary.free()
|
||||
result.timings.free()
|
||||
result.atiming.free()
|
||||
}
|
||||
}
|
||||
|
||||
[unsafe]
|
||||
fn (mut context Context) free() {
|
||||
unsafe {
|
||||
context.commands.free()
|
||||
context.results.free()
|
||||
context.cmd_template.free()
|
||||
context.cmd_params.free()
|
||||
context.cline.free()
|
||||
context.cgoback.free()
|
||||
}
|
||||
}
|
||||
|
||||
struct Aints {
|
||||
values []int
|
||||
mut:
|
||||
imin int
|
||||
imax int
|
||||
average f64
|
||||
stddev f64
|
||||
nmins int // number of discarded fastest results
|
||||
nmaxs int // number of discarded slowest results
|
||||
}
|
||||
|
||||
[unsafe]
|
||||
fn (mut a Aints) free() {
|
||||
unsafe { a.values.free() }
|
||||
}
|
||||
|
||||
fn new_aints(ovals []int, extreme_mins int, extreme_maxs int) Aints {
|
||||
mut res := Aints{
|
||||
values: ovals // remember the original values
|
||||
nmins: extreme_mins
|
||||
nmaxs: extreme_maxs
|
||||
}
|
||||
mut sum := i64(0)
|
||||
mut imin := math.max_i32
|
||||
mut imax := -math.max_i32
|
||||
// discard the extremes:
|
||||
mut vals := []int{}
|
||||
for x in ovals {
|
||||
vals << x
|
||||
}
|
||||
vals.sort()
|
||||
if vals.len > extreme_mins + extreme_maxs {
|
||||
vals = vals[extreme_mins..vals.len - extreme_maxs].clone()
|
||||
} else {
|
||||
vals = []
|
||||
}
|
||||
// statistical processing of the remaining values:
|
||||
for i in vals {
|
||||
sum += i
|
||||
if i < imin {
|
||||
imin = i
|
||||
}
|
||||
if i > imax {
|
||||
imax = i
|
||||
}
|
||||
}
|
||||
res.imin = imin
|
||||
res.imax = imax
|
||||
if vals.len > 0 {
|
||||
res.average = sum / f64(vals.len)
|
||||
}
|
||||
//
|
||||
mut devsum := f64(0.0)
|
||||
for i in vals {
|
||||
x := f64(i) - res.average
|
||||
devsum += (x * x)
|
||||
}
|
||||
res.stddev = math.sqrt(devsum / f64(vals.len))
|
||||
// eprintln('\novals: $ovals\n vals: $vals\n vals.len: $vals.len | res.imin: $res.imin | res.imax: $res.imax | res.average: $res.average | res.stddev: $res.stddev')
|
||||
return res
|
||||
}
|
||||
|
||||
fn bold(s string) string {
|
||||
return term.colorize(term.bold, s)
|
||||
}
|
||||
|
||||
fn (a Aints) str() string {
|
||||
return bold('${a.average:6.2f}') +
|
||||
'ms ± σ: ${a.stddev:4.1f}ms, min: ${a.imin:4}ms, max: ${a.imax:4}ms, runs:${a.values.len:3}, nmins:${a.nmins:2}, nmaxs:${a.nmaxs:2}'
|
||||
}
|
||||
|
||||
const (
|
||||
max_fail_percent = 100 * 1000
|
||||
max_time = 60 * 1000 // ms
|
||||
performance_regression_label = 'Performance regression detected, failing since '
|
||||
)
|
||||
|
||||
fn main() {
|
||||
mut context := Context{}
|
||||
context.parse_options()?
|
||||
context.run()
|
||||
context.show_diff_summary()
|
||||
}
|
||||
|
||||
fn (mut context Context) parse_options() ? {
|
||||
mut fp := flag.new_flag_parser(os.args)
|
||||
fp.application(os.file_name(os.executable()))
|
||||
fp.version('0.0.1')
|
||||
fp.description('Repeat command(s) and collect statistics. Note: you have to quote each command, if it contains spaces.')
|
||||
fp.arguments_description('CMD1 CMD2 ...')
|
||||
fp.skip_executable()
|
||||
fp.limit_free_args_to_at_least(1)?
|
||||
context.count = fp.int('count', `c`, 10, 'Repetition count.')
|
||||
context.series = fp.int('series', `s`, 2, 'Series count. `-s 2 -c 4 a b` => aaaabbbbaaaabbbb, while `-s 3 -c 2 a b` => aabbaabbaabb.')
|
||||
context.warmup = fp.int('warmup', `w`, 2, 'Warmup runs. These are done *only at the start*, and are ignored.')
|
||||
context.show_help = fp.bool('help', `h`, false, 'Show this help screen.')
|
||||
context.use_newline = fp.bool('newline', `n`, false, 'Use \\n, do not overwrite the last line. Produces more output, but easier to diagnose.')
|
||||
context.show_output = fp.bool('output', `O`, false, 'Show command stdout/stderr in the progress indicator for each command. Note: slower, for verbose commands.')
|
||||
context.verbose = fp.bool('verbose', `v`, false, 'Be more verbose.')
|
||||
context.fail_on_maxtime = fp.int('max_time', `m`, max_time, 'Fail with exit code 2, when first cmd takes above M milliseconds (regression).')
|
||||
context.fail_on_regress_percent = fp.int('fail_percent', `f`, max_fail_percent, 'Fail with exit code 3, when first cmd is X% slower than the rest (regression).')
|
||||
context.cmd_template = fp.string('template', `t`, '{T}', 'Command template. {T} will be substituted with the current command.')
|
||||
cmd_params := fp.string_multi('parameter', `p`, 'A parameter substitution list. `{p}=val1,val2,val2` means that {p} in the template, will be substituted with each of val1, val2, val3.')
|
||||
context.nmins = fp.int('nmins', `i`, 0, 'Ignore the BOTTOM X results (minimum execution time). Makes the results more robust to performance flukes.')
|
||||
context.nmaxs = fp.int('nmaxs', `a`, 1, 'Ignore the TOP X results (maximum execution time). Makes the results more robust to performance flukes.')
|
||||
for p in cmd_params {
|
||||
parts := p.split(':')
|
||||
if parts.len > 1 {
|
||||
context.cmd_params[parts[0]] = parts[1].split(',')
|
||||
}
|
||||
}
|
||||
if context.show_help {
|
||||
println(fp.usage())
|
||||
exit(0)
|
||||
}
|
||||
if context.verbose {
|
||||
scripting.set_verbose(true)
|
||||
}
|
||||
commands := fp.finalize() or {
|
||||
eprintln('Error: $err')
|
||||
exit(1)
|
||||
}
|
||||
context.commands = context.expand_all_commands(commands)
|
||||
context.results = []CmdResult{len: context.commands.len, cap: 20, init: CmdResult{
|
||||
outputs: []string{cap: 500}
|
||||
timings: []int{cap: 500}
|
||||
}}
|
||||
if context.use_newline {
|
||||
context.cline = '\n'
|
||||
context.cgoback = '\n'
|
||||
} else {
|
||||
context.cline = '\r' + term.h_divider('')
|
||||
context.cgoback = '\r'
|
||||
}
|
||||
}
|
||||
|
||||
fn flushed_print(s string) {
|
||||
print(s)
|
||||
flush_stdout()
|
||||
}
|
||||
|
||||
fn (mut context Context) clear_line() {
|
||||
flushed_print(context.cline)
|
||||
}
|
||||
|
||||
fn (mut context Context) expand_all_commands(commands []string) []string {
|
||||
mut all_commands := []string{}
|
||||
for cmd in commands {
|
||||
maincmd := context.cmd_template.replace('{T}', cmd)
|
||||
mut substituted_commands := []string{}
|
||||
substituted_commands << maincmd
|
||||
for paramk, paramlist in context.cmd_params {
|
||||
for paramv in paramlist {
|
||||
mut new_substituted_commands := []string{}
|
||||
for cscmd in substituted_commands {
|
||||
scmd := cscmd.replace(paramk, paramv)
|
||||
new_substituted_commands << scmd
|
||||
}
|
||||
for sc in new_substituted_commands {
|
||||
substituted_commands << sc
|
||||
}
|
||||
}
|
||||
}
|
||||
for sc in substituted_commands {
|
||||
all_commands << sc
|
||||
}
|
||||
}
|
||||
mut unique := map[string]int{}
|
||||
for x in all_commands {
|
||||
if x.contains('{') && x.contains('}') {
|
||||
continue
|
||||
}
|
||||
unique[x] = 1
|
||||
}
|
||||
return unique.keys()
|
||||
}
|
||||
|
||||
fn (mut context Context) run() {
|
||||
mut run_warmups := 0
|
||||
for si in 1 .. context.series + 1 {
|
||||
for icmd, cmd in context.commands {
|
||||
mut runs := 0
|
||||
mut duration := 0
|
||||
mut sum := 0
|
||||
mut oldres := ''
|
||||
println('Series: ${si:4}/${context.series:-4}, command: $cmd')
|
||||
if context.warmup > 0 && run_warmups < context.commands.len {
|
||||
for i in 1 .. context.warmup + 1 {
|
||||
flushed_print('${context.cgoback}warming up run: ${i:4}/${context.warmup:-4} for ${cmd:-50s} took ${duration:6} ms ...')
|
||||
mut sw := time.new_stopwatch()
|
||||
res := os.execute(cmd)
|
||||
if res.exit_code != 0 {
|
||||
continue
|
||||
}
|
||||
duration = int(sw.elapsed().milliseconds())
|
||||
}
|
||||
run_warmups++
|
||||
}
|
||||
context.clear_line()
|
||||
for i in 1 .. (context.count + 1) {
|
||||
avg := f64(sum) / f64(i)
|
||||
flushed_print('${context.cgoback}Average: ${avg:9.3f}ms | run: ${i:4}/${context.count:-4} | took ${duration:6} ms')
|
||||
if context.show_output {
|
||||
flushed_print(' | result: ${oldres:s}')
|
||||
}
|
||||
mut sw := time.new_stopwatch()
|
||||
res := scripting.exec(cmd) or { continue }
|
||||
duration = int(sw.elapsed().milliseconds())
|
||||
if res.exit_code != 0 {
|
||||
eprintln('${i:10} non 0 exit code for cmd: $cmd')
|
||||
continue
|
||||
}
|
||||
trimed_output := res.output.trim_right('\r\n')
|
||||
trimed_normalized := trimed_output.replace('\r\n', '\n')
|
||||
lines := trimed_normalized.split('\n')
|
||||
for line in lines {
|
||||
context.results[icmd].outputs << line
|
||||
}
|
||||
context.results[icmd].timings << duration
|
||||
sum += duration
|
||||
runs++
|
||||
oldres = res.output.replace('\n', ' ')
|
||||
}
|
||||
context.results[icmd].cmd = cmd
|
||||
context.results[icmd].icmd = icmd
|
||||
context.results[icmd].runs += runs
|
||||
context.results[icmd].atiming = new_aints(context.results[icmd].timings, context.nmins,
|
||||
context.nmaxs)
|
||||
context.clear_line()
|
||||
flushed_print(context.cgoback)
|
||||
mut m := map[string][]int{}
|
||||
ioutputs := context.results[icmd].outputs
|
||||
for o in ioutputs {
|
||||
x := o.split(':')
|
||||
if x.len > 1 {
|
||||
k := x[0]
|
||||
v := x[1].trim_left(' ').int()
|
||||
m[k] << v
|
||||
}
|
||||
}
|
||||
mut summary := map[string]Aints{}
|
||||
for k, v in m {
|
||||
// show a temporary summary for the current series/cmd cycle
|
||||
s := new_aints(v, context.nmins, context.nmaxs)
|
||||
println(' $k: $s')
|
||||
summary[k] = s
|
||||
}
|
||||
// merge current raw results to the previous ones
|
||||
old_oms := context.results[icmd].oms.move()
|
||||
mut new_oms := map[string][]int{}
|
||||
for k, v in m {
|
||||
if old_oms[k].len == 0 {
|
||||
new_oms[k] = v
|
||||
} else {
|
||||
new_oms[k] << old_oms[k]
|
||||
new_oms[k] << v
|
||||
}
|
||||
}
|
||||
context.results[icmd].oms = new_oms.move()
|
||||
// println('')
|
||||
}
|
||||
}
|
||||
// create full summaries, taking account of all runs
|
||||
for icmd in 0 .. context.results.len {
|
||||
mut new_full_summary := map[string]Aints{}
|
||||
for k, v in context.results[icmd].oms {
|
||||
new_full_summary[k] = new_aints(v, context.nmins, context.nmaxs)
|
||||
}
|
||||
context.results[icmd].summary = new_full_summary.move()
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut context Context) show_diff_summary() {
|
||||
context.results.sort_with_compare(fn (a &CmdResult, b &CmdResult) int {
|
||||
if a.atiming.average < b.atiming.average {
|
||||
return -1
|
||||
}
|
||||
if a.atiming.average > b.atiming.average {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
})
|
||||
println('Summary (commands are ordered by ascending mean time), after $context.series series of $context.count repetitions:')
|
||||
base := context.results[0].atiming.average
|
||||
mut first_cmd_percentage := f64(100.0)
|
||||
mut first_marker := ''
|
||||
for i, r in context.results {
|
||||
first_marker = ' '
|
||||
cpercent := (r.atiming.average / base) * 100 - 100
|
||||
if r.icmd == 0 {
|
||||
first_marker = bold('>')
|
||||
first_cmd_percentage = cpercent
|
||||
}
|
||||
println(' $first_marker${(i + 1):3} | ${cpercent:5.1f}% slower | ${r.cmd:-57s} | $r.atiming')
|
||||
}
|
||||
$if debugcontext ? {
|
||||
println('context: $context')
|
||||
}
|
||||
if int(base) > context.fail_on_maxtime {
|
||||
flushed_print(performance_regression_label)
|
||||
println('average time: ${base:6.1f} ms > $context.fail_on_maxtime ms threshold.')
|
||||
exit(2)
|
||||
}
|
||||
if context.fail_on_regress_percent == max_fail_percent || context.results.len < 2 {
|
||||
return
|
||||
}
|
||||
fail_threshold_max := f64(context.fail_on_regress_percent)
|
||||
if first_cmd_percentage > fail_threshold_max {
|
||||
flushed_print(performance_regression_label)
|
||||
println('${first_cmd_percentage:5.1f}% > ${fail_threshold_max:5.1f}% threshold.')
|
||||
exit(3)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
module main
|
||||
|
||||
// This program verifies that `v test` propagates errors
|
||||
// and that it exits with code 1, when at least 1 FAIL happen.
|
||||
import os
|
||||
import rand
|
||||
|
||||
const (
|
||||
vexe = get_vexe_path()
|
||||
vroot = os.dir(vexe)
|
||||
tdir = new_tdir()
|
||||
)
|
||||
|
||||
fn get_vexe_path() string {
|
||||
env_vexe := os.getenv('VEXE')
|
||||
if env_vexe != '' {
|
||||
return env_vexe
|
||||
}
|
||||
me := os.executable()
|
||||
eprintln('me: $me')
|
||||
mut vexe_ := os.join_path(os.dir(os.dir(os.dir(me))), 'v')
|
||||
if os.user_os() == 'windows' {
|
||||
vexe_ += '.exe'
|
||||
}
|
||||
return vexe_
|
||||
}
|
||||
|
||||
fn new_tdir() string {
|
||||
tdir_ := os.join_path(os.temp_dir(), rand.ulid())
|
||||
if os.exists(tdir_) {
|
||||
os.rmdir(tdir_) or { panic(err) }
|
||||
}
|
||||
os.mkdir(tdir_) or { panic(err) }
|
||||
C.atexit(cleanup_tdir)
|
||||
return tdir_
|
||||
}
|
||||
|
||||
fn cleanup_tdir() {
|
||||
println('... removing tdir: $tdir')
|
||||
os.rmdir_all(tdir) or { eprintln(err) }
|
||||
}
|
||||
|
||||
fn create_test(tname string, tcontent string) ?string {
|
||||
tpath := os.join_path(tdir, tname)
|
||||
os.write_file(tpath, tcontent)?
|
||||
eprintln('>>>>>>>> tpath: $tpath | tcontent: $tcontent')
|
||||
return tpath
|
||||
}
|
||||
|
||||
fn main() {
|
||||
defer {
|
||||
os.chdir(os.wd_at_startup) or {}
|
||||
}
|
||||
println('> vroot: $vroot | vexe: $vexe | tdir: $tdir')
|
||||
ok_fpath := create_test('a_single_ok_test.v', 'fn test_ok(){ assert true }')?
|
||||
check_ok('"$vexe" "$ok_fpath"')
|
||||
check_ok('"$vexe" test "$ok_fpath"')
|
||||
check_ok('"$vexe" test "$tdir"')
|
||||
fail_fpath := create_test('a_single_failing_test.v', 'fn test_fail(){ assert 1 == 2 }')?
|
||||
check_fail('"$vexe" "$fail_fpath"')
|
||||
check_fail('"$vexe" test "$fail_fpath"')
|
||||
check_fail('"$vexe" test "$tdir"')
|
||||
rel_dir := os.join_path(tdir, rand.ulid())
|
||||
os.mkdir(rel_dir)?
|
||||
os.chdir(rel_dir)?
|
||||
check_ok('"$vexe" test "..${os.path_separator + os.base(ok_fpath)}"')
|
||||
println('> all done')
|
||||
}
|
||||
|
||||
fn check_ok(cmd string) string {
|
||||
println('> check_ok cmd: $cmd')
|
||||
res := os.execute(cmd)
|
||||
if res.exit_code != 0 {
|
||||
eprintln('> check_ok failed.\n$res.output')
|
||||
exit(1)
|
||||
}
|
||||
return res.output
|
||||
}
|
||||
|
||||
fn check_fail(cmd string) string {
|
||||
println('> check_fail cmd: $cmd')
|
||||
res := os.execute(cmd)
|
||||
if res.exit_code == 0 {
|
||||
eprintln('> check_fail succeeded, but it should have failed.\n$res.output')
|
||||
exit(1)
|
||||
}
|
||||
return res.output
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
module main
|
||||
|
||||
import os
|
||||
import time
|
||||
import os.cmdline
|
||||
|
||||
enum Target {
|
||||
both
|
||||
stderr
|
||||
stdout
|
||||
alternate
|
||||
}
|
||||
|
||||
fn s2target(s string) Target {
|
||||
return match s {
|
||||
'both' { Target.both }
|
||||
'stderr' { Target.stderr }
|
||||
'alternate' { Target.alternate }
|
||||
else { Target.stdout }
|
||||
}
|
||||
}
|
||||
|
||||
struct Context {
|
||||
mut:
|
||||
timeout_ms int
|
||||
period_ms int
|
||||
exitcode int
|
||||
target Target
|
||||
omode Target
|
||||
is_verbose bool
|
||||
}
|
||||
|
||||
fn (mut ctx Context) println(s string) {
|
||||
if ctx.target == .alternate {
|
||||
ctx.omode = if ctx.omode == .stderr { Target.stdout } else { Target.stderr }
|
||||
}
|
||||
if ctx.target in [.both, .stdout] || ctx.omode == .stdout {
|
||||
println('stdout, $s')
|
||||
}
|
||||
if ctx.target in [.both, .stderr] || ctx.omode == .stderr {
|
||||
eprintln('stderr, $s')
|
||||
}
|
||||
}
|
||||
|
||||
fn do_timeout(c &Context) {
|
||||
mut ctx := unsafe { c }
|
||||
time.sleep(ctx.timeout_ms * time.millisecond)
|
||||
exit(ctx.exitcode)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut ctx := Context{}
|
||||
args := os.args[1..]
|
||||
if '-h' in args || '--help' in args {
|
||||
println("Usage:
|
||||
test_os_process [-v] [-h] [-target stderr/stdout/both/alternate] [-exitcode 0] [-timeout_ms 200] [-period_ms 50]
|
||||
Prints lines periodically (-period_ms), to stdout/stderr (-target).
|
||||
After a while (-timeout_ms), exit with (-exitcode).
|
||||
This program is useful for platform independent testing
|
||||
of child process/standart input/output control.
|
||||
It is used in V's `os` module tests.
|
||||
")
|
||||
return
|
||||
}
|
||||
ctx.is_verbose = '-v' in args
|
||||
ctx.target = s2target(cmdline.option(args, '-target', 'both'))
|
||||
ctx.exitcode = cmdline.option(args, '-exitcode', '0').int()
|
||||
ctx.timeout_ms = cmdline.option(args, '-timeout_ms', '200').int()
|
||||
ctx.period_ms = cmdline.option(args, '-period_ms', '50').int()
|
||||
if ctx.target == .alternate {
|
||||
ctx.omode = .stdout
|
||||
}
|
||||
if ctx.is_verbose {
|
||||
eprintln('> args: $args | context: $ctx')
|
||||
}
|
||||
go do_timeout(&ctx)
|
||||
for i := 1; true; i++ {
|
||||
ctx.println('$i')
|
||||
time.sleep(ctx.period_ms * time.millisecond)
|
||||
}
|
||||
time.sleep(100 * time.second)
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) 2019-2022 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license that can be found in the LICENSE file.
|
||||
module main
|
||||
|
||||
import os
|
||||
import v.util
|
||||
|
||||
const vexe = os.getenv('VEXE')
|
||||
|
||||
fn main() {
|
||||
vmodules := os.vmodules_dir()
|
||||
c2v_dir := os.join_path(vmodules, 'c2v')
|
||||
mut c2v_bin := os.join_path(c2v_dir, 'c2v')
|
||||
$if windows {
|
||||
c2v_bin += '.exe'
|
||||
}
|
||||
// Git clone c2v
|
||||
if !os.exists(c2v_dir) {
|
||||
println('C2V is not installed. Cloning C2V to $c2v_dir ...')
|
||||
os.chdir(vmodules)?
|
||||
res := os.execute('git clone https://github.com/vlang/c2v')
|
||||
if res.exit_code != 0 {
|
||||
eprintln('Failed to download C2V.')
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
// Compile c2v
|
||||
if !os.exists(c2v_bin) {
|
||||
os.chdir(c2v_dir)?
|
||||
println('Compiling c2v ...')
|
||||
res2 := os.execute('${os.quoted_path(vexe)} -o ${os.quoted_path(c2v_bin)} -keepc -g -experimental .')
|
||||
if res2.exit_code != 0 {
|
||||
eprintln(res2.output)
|
||||
eprintln('Failed to compile C2V. This should not happen. Please report it via GitHub.')
|
||||
exit(2)
|
||||
}
|
||||
}
|
||||
if os.args.len < 3 {
|
||||
eprintln('Wrong number of arguments. Use `v translate file.c` .')
|
||||
exit(3)
|
||||
}
|
||||
passed_args := util.args_quote_paths(os.args[2..])
|
||||
// println(passed_args)
|
||||
os.chdir(os.wd_at_startup)?
|
||||
res := os.system('$c2v_bin $passed_args')
|
||||
if res != 0 {
|
||||
eprintln('C2V failed to translate the C files. Please report it via GitHub.')
|
||||
exit(4)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
module main
|
||||
|
||||
import json
|
||||
|
||||
struct UseJson {
|
||||
x int
|
||||
}
|
||||
|
||||
fn suppress_json_warning() {
|
||||
json.encode(UseJson{})
|
||||
}
|
||||
|
||||
// struct C.cJSON {}
|
||||
fn C.cJSON_CreateObject() &C.cJSON
|
||||
|
||||
fn C.cJSON_CreateArray() &C.cJSON
|
||||
|
||||
// fn C.cJSON_CreateBool(bool) &C.cJSON
|
||||
fn C.cJSON_CreateTrue() &C.cJSON
|
||||
|
||||
fn C.cJSON_CreateFalse() &C.cJSON
|
||||
|
||||
fn C.cJSON_CreateNull() &C.cJSON
|
||||
|
||||
// fn C.cJSON_CreateNumber() &C.cJSON
|
||||
// fn C.cJSON_CreateString() &C.cJSON
|
||||
fn C.cJSON_CreateRaw(&u8) &C.cJSON
|
||||
|
||||
fn C.cJSON_IsInvalid(voidptr) bool
|
||||
|
||||
fn C.cJSON_IsFalse(voidptr) bool
|
||||
|
||||
// fn C.cJSON_IsTrue(voidptr) bool
|
||||
fn C.cJSON_IsBool(voidptr) bool
|
||||
|
||||
fn C.cJSON_IsNull(voidptr) bool
|
||||
|
||||
fn C.cJSON_IsNumber(voidptr) bool
|
||||
|
||||
fn C.cJSON_IsString(voidptr) bool
|
||||
|
||||
fn C.cJSON_IsArray(voidptr) bool
|
||||
|
||||
fn C.cJSON_IsObject(voidptr) bool
|
||||
|
||||
fn C.cJSON_IsRaw(voidptr) bool
|
||||
|
||||
fn C.cJSON_AddItemToObject(voidptr, &u8, voidptr)
|
||||
|
||||
fn C.cJSON_AddItemToArray(voidptr, voidptr)
|
||||
|
||||
fn C.cJSON_Delete(voidptr)
|
||||
|
||||
fn C.cJSON_Print(voidptr) &u8
|
||||
|
||||
[inline]
|
||||
fn create_object() &C.cJSON {
|
||||
return C.cJSON_CreateObject()
|
||||
}
|
||||
|
||||
[inline]
|
||||
fn create_array() &C.cJSON {
|
||||
return C.cJSON_CreateArray()
|
||||
}
|
||||
|
||||
[inline]
|
||||
fn create_string(val string) &C.cJSON {
|
||||
return C.cJSON_CreateString(val.str)
|
||||
}
|
||||
|
||||
[inline]
|
||||
fn create_number(val f64) &C.cJSON {
|
||||
return C.cJSON_CreateNumber(val)
|
||||
}
|
||||
|
||||
[inline]
|
||||
fn create_bool(val bool) &C.cJSON {
|
||||
return C.cJSON_CreateBool(val)
|
||||
}
|
||||
|
||||
[inline]
|
||||
fn create_true() &C.cJSON {
|
||||
return C.cJSON_CreateTrue()
|
||||
}
|
||||
|
||||
[inline]
|
||||
fn create_false() &C.cJSON {
|
||||
return C.cJSON_CreateFalse()
|
||||
}
|
||||
|
||||
[inline]
|
||||
fn create_null() &C.cJSON {
|
||||
return C.cJSON_CreateNull()
|
||||
}
|
||||
|
||||
[inline]
|
||||
fn delete(b voidptr) {
|
||||
C.cJSON_Delete(b)
|
||||
}
|
||||
|
||||
[inline]
|
||||
fn add_item_to_object(obj &C.cJSON, key string, item &C.cJSON) {
|
||||
C.cJSON_AddItemToObject(obj, key.str, item)
|
||||
}
|
||||
|
||||
[inline]
|
||||
fn add_item_to_array(obj &C.cJSON, item &C.cJSON) {
|
||||
C.cJSON_AddItemToArray(obj, item)
|
||||
}
|
||||
|
||||
fn json_print(json &C.cJSON) string {
|
||||
s := C.cJSON_Print(json)
|
||||
return unsafe { tos3(s) }
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
demo.json
|
|
@ -0,0 +1,131 @@
|
|||
// usage test: v ast path_to_v/cmd/tools/vast/test/demo.v
|
||||
// will generate demo.json
|
||||
|
||||
// comment for module
|
||||
module main
|
||||
|
||||
// import module
|
||||
import os
|
||||
import math
|
||||
import time { Time, now }
|
||||
|
||||
// const decl
|
||||
const (
|
||||
a = 1
|
||||
b = 3
|
||||
c = 'c'
|
||||
)
|
||||
|
||||
// struct decl
|
||||
struct Point {
|
||||
x int
|
||||
mut:
|
||||
y int
|
||||
pub:
|
||||
z int
|
||||
pub mut:
|
||||
name string
|
||||
}
|
||||
|
||||
// method of Point
|
||||
pub fn (p Point) get_x() int {
|
||||
return p.x
|
||||
}
|
||||
|
||||
// embed struct
|
||||
struct MyPoint {
|
||||
Point
|
||||
title string
|
||||
}
|
||||
|
||||
// enum type
|
||||
enum Color {
|
||||
red
|
||||
green
|
||||
blue
|
||||
}
|
||||
|
||||
// type alias
|
||||
type Myint = int
|
||||
|
||||
// sum type
|
||||
type MySumType = bool | int | string
|
||||
|
||||
// function type
|
||||
type Myfn = fn (int) int
|
||||
|
||||
// interface type
|
||||
interface Myinterfacer {
|
||||
add(int, int) int
|
||||
sub(int, int) int
|
||||
}
|
||||
|
||||
// main funciton
|
||||
fn main() {
|
||||
add(1, 3)
|
||||
println(add(1, 2))
|
||||
println('ok') // comment println
|
||||
arr := [1, 3, 5, 7]
|
||||
for a in arr {
|
||||
println(a)
|
||||
add(1, 3)
|
||||
}
|
||||
color := Color.red
|
||||
println(color)
|
||||
println(os.args)
|
||||
m := math.max(1, 3)
|
||||
println(m)
|
||||
println(now())
|
||||
t := Time{}
|
||||
println(t)
|
||||
p := Point{
|
||||
x: 1
|
||||
y: 2
|
||||
z: 3
|
||||
}
|
||||
println(p)
|
||||
my_point := MyPoint{
|
||||
// x: 1
|
||||
// y: 3
|
||||
// z: 5
|
||||
}
|
||||
println(my_point.get_x())
|
||||
}
|
||||
|
||||
// normal function
|
||||
fn add(x int, y int) int {
|
||||
return x + y
|
||||
}
|
||||
|
||||
// function with defer stmt
|
||||
fn defer_fn() {
|
||||
mut x := 1
|
||||
println('start fn')
|
||||
defer {
|
||||
println('in defer block')
|
||||
println(x)
|
||||
}
|
||||
println('end fn')
|
||||
}
|
||||
|
||||
// generic function
|
||||
fn g_fn<T>(p T) T {
|
||||
return p
|
||||
}
|
||||
|
||||
// generic struct
|
||||
struct GenericStruct<T> {
|
||||
point Point
|
||||
mut:
|
||||
model T
|
||||
}
|
||||
|
||||
// generic interface
|
||||
interface Gettable<T> {
|
||||
get() T
|
||||
}
|
||||
|
||||
// generic sumtype
|
||||
struct None {}
|
||||
|
||||
type MyOption<T> = Error | None | T
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,146 @@
|
|||
module main
|
||||
|
||||
import os
|
||||
import flag
|
||||
import strings
|
||||
|
||||
const (
|
||||
tool_version = '0.0.4'
|
||||
tool_description = 'Converts a list of arbitrary files into a single v module file.'
|
||||
)
|
||||
|
||||
struct Context {
|
||||
mut:
|
||||
files []string
|
||||
prefix string
|
||||
show_help bool
|
||||
module_name string
|
||||
write_file string
|
||||
}
|
||||
|
||||
fn (context Context) header() string {
|
||||
mut header_s := ''
|
||||
header_s += 'module $context.module_name\n'
|
||||
header_s += '\n'
|
||||
allfiles := context.files.join(' ')
|
||||
mut options := []string{}
|
||||
if context.prefix.len > 0 {
|
||||
options << '-p $context.prefix'
|
||||
}
|
||||
if context.module_name.len > 0 {
|
||||
options << '-m $context.module_name'
|
||||
}
|
||||
if context.write_file.len > 0 {
|
||||
options << '-w $context.write_file'
|
||||
}
|
||||
soptions := options.join(' ')
|
||||
header_s += '// File generated by:\n'
|
||||
header_s += '// v bin2v $allfiles $soptions\n'
|
||||
header_s += '// Please, do not edit this file.\n'
|
||||
header_s += '// Your changes may be overwritten.\n'
|
||||
header_s += 'const (\n'
|
||||
return header_s
|
||||
}
|
||||
|
||||
fn (context Context) footer() string {
|
||||
return ')\n'
|
||||
}
|
||||
|
||||
fn (context Context) file2v(bname string, fbytes []u8, bn_max int) string {
|
||||
mut sb := strings.new_builder(1000)
|
||||
bn_diff_len := bn_max - bname.len
|
||||
sb.write_string('\t${bname}_len' + ' '.repeat(bn_diff_len - 4) + ' = $fbytes.len\n')
|
||||
fbyte := fbytes[0]
|
||||
bnmae_line := '\t$bname' + ' '.repeat(bn_diff_len) + ' = [u8($fbyte), '
|
||||
sb.write_string(bnmae_line)
|
||||
mut line_len := bnmae_line.len + 3
|
||||
for i := 1; i < fbytes.len; i++ {
|
||||
b := int(fbytes[i]).str()
|
||||
if line_len > 94 {
|
||||
sb.go_back(1)
|
||||
sb.write_string('\n\t\t')
|
||||
line_len = 8
|
||||
}
|
||||
if i == fbytes.len - 1 {
|
||||
sb.write_string(b)
|
||||
line_len += b.len
|
||||
} else {
|
||||
sb.write_string('$b, ')
|
||||
line_len += b.len + 2
|
||||
}
|
||||
}
|
||||
sb.write_string(']!\n')
|
||||
return sb.str()
|
||||
}
|
||||
|
||||
fn (context Context) bname_and_bytes(file string) ?(string, []u8) {
|
||||
fname := os.file_name(file)
|
||||
fname_escaped := fname.replace_each(['.', '_', '-', '_'])
|
||||
byte_name := '$context.prefix$fname_escaped'.to_lower()
|
||||
fbytes := os.read_bytes(file) or { return error('Error: $err.msg()') }
|
||||
return byte_name, fbytes
|
||||
}
|
||||
|
||||
fn (context Context) max_bname_len(bnames []string) int {
|
||||
mut max := 0
|
||||
for n in bnames {
|
||||
if n.len > max {
|
||||
max = n.len
|
||||
}
|
||||
}
|
||||
// Add 4 to max due to "_len" suffix
|
||||
return max + 4
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut context := Context{}
|
||||
mut fp := flag.new_flag_parser(os.args[1..])
|
||||
fp.application('v bin2v')
|
||||
fp.version(tool_version)
|
||||
fp.description(tool_description)
|
||||
fp.arguments_description('FILE [FILE]...')
|
||||
context.show_help = fp.bool('help', `h`, false, 'Show this help screen.')
|
||||
context.module_name = fp.string('module', `m`, 'binary', 'Name of the generated module.')
|
||||
context.prefix = fp.string('prefix', `p`, '', 'A prefix put before each resource name.')
|
||||
context.write_file = fp.string('write', `w`, '', 'Write directly to a file with the given name.')
|
||||
if context.show_help {
|
||||
println(fp.usage())
|
||||
exit(0)
|
||||
}
|
||||
files := fp.finalize() or {
|
||||
eprintln('Error: $err.msg()')
|
||||
exit(1)
|
||||
}
|
||||
real_files := files.filter(it != 'bin2v')
|
||||
if real_files.len == 0 {
|
||||
println(fp.usage())
|
||||
exit(0)
|
||||
}
|
||||
context.files = real_files
|
||||
if context.write_file != '' && os.file_ext(context.write_file) !in ['.vv', '.v'] {
|
||||
context.write_file += '.v'
|
||||
}
|
||||
mut file_byte_map := map[string][]u8{}
|
||||
for file in real_files {
|
||||
bname, fbytes := context.bname_and_bytes(file) or {
|
||||
eprintln(err.msg())
|
||||
exit(1)
|
||||
}
|
||||
file_byte_map[bname] = fbytes
|
||||
}
|
||||
max_bname := context.max_bname_len(file_byte_map.keys())
|
||||
if context.write_file.len > 0 {
|
||||
mut out_file := os.create(context.write_file)?
|
||||
out_file.write_string(context.header())?
|
||||
for bname, fbytes in file_byte_map {
|
||||
out_file.write_string(context.file2v(bname, fbytes, max_bname))?
|
||||
}
|
||||
out_file.write_string(context.footer())?
|
||||
} else {
|
||||
print(context.header())
|
||||
for bname, fbytes in file_byte_map {
|
||||
print(context.file2v(bname, fbytes, max_bname))
|
||||
}
|
||||
print(context.footer())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
import net.urllib
|
||||
import os
|
||||
import readline
|
||||
|
||||
const vroot = @VMODROOT
|
||||
|
||||
// get output from `v doctor`
|
||||
fn get_vdoctor_output(is_verbose bool) string {
|
||||
vexe := os.getenv('VEXE')
|
||||
verbose_flag := if is_verbose { '-v' } else { '' }
|
||||
result := os.execute('${os.quoted_path(vexe)} $verbose_flag doctor')
|
||||
if result.exit_code != 0 {
|
||||
eprintln('unable to get `v doctor` output: $result.output')
|
||||
return ''
|
||||
}
|
||||
return result.output
|
||||
}
|
||||
|
||||
// get ouput from `v -g -o vdbg cmd/v && vdbg file.v`
|
||||
fn get_v_build_output(is_verbose bool, is_yes bool, file_path string) string {
|
||||
mut vexe := os.getenv('VEXE')
|
||||
// prepare a V compiler with -g to have better backtraces if possible
|
||||
wd := os.getwd()
|
||||
os.chdir(vroot) or {}
|
||||
verbose_flag := if is_verbose { '-v' } else { '' }
|
||||
vdbg_path := $if windows { '$vroot/vdbg.exe' } $else { '$vroot/vdbg' }
|
||||
vdbg_compilation_cmd := '${os.quoted_path(vexe)} $verbose_flag -g -o ${os.quoted_path(vdbg_path)} cmd/v'
|
||||
vdbg_result := os.execute(vdbg_compilation_cmd)
|
||||
os.chdir(wd) or {}
|
||||
if vdbg_result.exit_code == 0 {
|
||||
vexe = vdbg_path
|
||||
} else {
|
||||
eprintln('unable to compile V in debug mode: $vdbg_result.output\ncommand: $vdbg_compilation_cmd\n')
|
||||
}
|
||||
//
|
||||
mut result := os.execute('${os.quoted_path(vexe)} $verbose_flag ${os.quoted_path(file_path)}')
|
||||
defer {
|
||||
os.rm(vdbg_path) or {
|
||||
if is_verbose {
|
||||
eprintln('unable to delete `vdbg`: $err')
|
||||
}
|
||||
}
|
||||
}
|
||||
if result.exit_code == 0 {
|
||||
defer {
|
||||
mut generated_file := file_path.all_before_last('.')
|
||||
$if windows {
|
||||
generated_file += '.exe'
|
||||
}
|
||||
os.rm(generated_file) or {
|
||||
if is_verbose {
|
||||
eprintln('unable to delete generated file: $err')
|
||||
}
|
||||
}
|
||||
}
|
||||
run := is_yes
|
||||
|| ask('It looks like the compilation went well, do you want to run the file?')
|
||||
if run {
|
||||
result = os.execute('${os.quoted_path(vexe)} $verbose_flag run ${os.quoted_path(file_path)}')
|
||||
if result.exit_code == 0 && !is_yes {
|
||||
confirm_or_exit('It looks like the file ran correctly as well, are you sure you want to continue?')
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.output
|
||||
}
|
||||
|
||||
fn ask(msg string) bool {
|
||||
prompt := os.input_opt('$msg [Y/n] ') or { 'y' }
|
||||
return prompt == '' || prompt[0].ascii_str().to_lower() != 'n'
|
||||
}
|
||||
|
||||
fn confirm_or_exit(msg string) {
|
||||
if !ask(msg) {
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut file_path := ''
|
||||
mut is_verbose := false
|
||||
mut is_yes := false
|
||||
for arg in os.args[2..] {
|
||||
match arg {
|
||||
'-v' {
|
||||
is_verbose = true
|
||||
}
|
||||
'-y' {
|
||||
is_yes = true
|
||||
}
|
||||
else {
|
||||
if !arg.ends_with('.v') && !arg.ends_with('.vsh') && !arg.ends_with('.vv') {
|
||||
eprintln('unknown argument: `$arg`')
|
||||
exit(1)
|
||||
}
|
||||
if file_path != '' {
|
||||
eprintln('only one V file can be submitted')
|
||||
exit(1)
|
||||
}
|
||||
file_path = arg
|
||||
}
|
||||
}
|
||||
}
|
||||
if file_path == '' {
|
||||
eprintln('v bug: no v file listed to report')
|
||||
exit(1)
|
||||
}
|
||||
os.unsetenv('VCOLORS')
|
||||
// collect error information
|
||||
// output from `v doctor`
|
||||
vdoctor_output := get_vdoctor_output(is_verbose)
|
||||
// file content
|
||||
file_content := os.read_file(file_path) or {
|
||||
eprintln('unable to get file "$file_path" content: $err')
|
||||
''
|
||||
}
|
||||
// output from `v -g -o vdbg cmd/v && vdbg file.v`
|
||||
build_output := get_v_build_output(is_verbose, is_yes, file_path)
|
||||
// ask the user if he wants to submit even after an error
|
||||
if !is_yes && (vdoctor_output == '' || file_content == '' || build_output == '') {
|
||||
confirm_or_exit('An error occurred retrieving the information, do you want to continue?')
|
||||
}
|
||||
|
||||
expected_result := readline.read_line('What did you expect to see? ') or {
|
||||
// Ctrl-C was pressed
|
||||
eprintln('\nCanceled')
|
||||
exit(1)
|
||||
}
|
||||
// open prefilled issue creation page, or print link as a fallback
|
||||
|
||||
if !is_yes && vdoctor_output.contains('behind V master') {
|
||||
confirm_or_exit('It looks like your installation of V is outdated, we advise you to run `v up` before submitting an issue. Are you sure you want to continue?')
|
||||
}
|
||||
|
||||
// When updating this template, make sure to update `.github/ISSUE_TEMPLATE/bug_report.md` too
|
||||
raw_body := '<!-- It is advisable to update all relevant modules using `v outdated` and `v install` -->
|
||||
**V doctor:**
|
||||
```
|
||||
$vdoctor_output
|
||||
```
|
||||
|
||||
**What did you do?**
|
||||
`v -g -o vdbg cmd/v && vdbg $file_path`
|
||||
{file_content}
|
||||
|
||||
**What did you expect to see?**
|
||||
|
||||
$expected_result
|
||||
|
||||
**What did you see instead?**
|
||||
```
|
||||
$build_output```'
|
||||
mut encoded_body := urllib.query_escape(raw_body.replace_once('{file_content}', '```v\n$file_content\n```'))
|
||||
mut generated_uri := 'https://github.com/vlang/v/issues/new?labels=Bug&body=$encoded_body'
|
||||
if generated_uri.len > 8192 {
|
||||
// GitHub doesn't support URLs longer than 8192 characters
|
||||
encoded_body = urllib.query_escape(raw_body.replace_once('{file_content}', 'See attached file `$file_path`'))
|
||||
generated_uri = 'https://github.com/vlang/v/issues/new?labels=Bug&body=$encoded_body'
|
||||
println('Your file is too big to be submitted. Head over to the following URL and attach your file.')
|
||||
println(generated_uri)
|
||||
} else {
|
||||
os.open_uri(generated_uri) or {
|
||||
if is_verbose {
|
||||
eprintln(err)
|
||||
}
|
||||
println(generated_uri)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
module main
|
||||
|
||||
import os
|
||||
import testing
|
||||
|
||||
const vroot = @VMODROOT
|
||||
|
||||
const efolders = [
|
||||
'examples/viewer',
|
||||
]
|
||||
|
||||
fn main() {
|
||||
args_string := os.args[1..].join(' ')
|
||||
params := args_string.all_before('build-examples')
|
||||
skip_prefixes := efolders.map(os.real_path(os.join_path_single(vroot, it)).replace('\\',
|
||||
'/'))
|
||||
res := testing.v_build_failing_skipped(params, 'examples', skip_prefixes, fn (mut session testing.TestSession) {
|
||||
for x in efolders {
|
||||
pathsegments := x.split_any('/')
|
||||
session.add(os.real_path(os.join_path(vroot, ...pathsegments)))
|
||||
}
|
||||
})
|
||||
if res {
|
||||
exit(1)
|
||||
}
|
||||
if testing.v_build_failing_skipped(params + '-live', os.join_path_single('examples',
|
||||
'hot_reload'), skip_prefixes, fn (mut session testing.TestSession) {})
|
||||
{
|
||||
exit(1)
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue