move v.v to cmd/v

pull/3700/head
lutherwenxu 2020-02-09 17:08:04 +08:00 committed by GitHub
parent 3f5e4c55b2
commit 9332a83ce6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
64 changed files with 1123 additions and 799 deletions

View File

@ -12,8 +12,8 @@ jobs:
echo "Changed files compared to origin/master are:" && git diff --name-status origin/master HEAD -- '*.v'
- name: Build v (there is no need for dependencies for fmt)
run: make -j4
- name: Build a production tools/vfmt
run: ./v -prod -d vfmt tools/vfmt.v
- name: Build a production cmd/tools/vfmt
run: ./v -prod -d vfmt cmd/tools/vfmt.v
- name: Run v fmt -diff on only the changed files. Does NOT fail for now.
run: git diff --name-status origin/master HEAD -- '*.v' |grep -v '^D'|rev|cut -f1|rev| xargs ./v fmt -noerror -diff
- name: Run v test-fmt
@ -28,12 +28,12 @@ jobs:
- name: Install dependencies
run: sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list; sudo apt-get update; sudo apt-get install --quiet -y libglfw3 libglfw3-dev libfreetype6-dev libssl-dev sqlite3 libsqlite3-dev libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libsdl2-image-dev
- name: Build v
run: echo $VFLAGS && make -j4 && ./v -cg -o v v.v
run: echo $VFLAGS && make -j4 && ./v -cg -o v cmd/v
- name: Test v->c
run: |
sudo ln -s /var/tmp/tcc/bin/tcc /usr/local/bin/tcc
tcc -version
./v -o v2 v.v # Make sure vtcc can build itself
./v -o v2 cmd/v # Make sure vtcc can build itself
./v -silent test-compiler
- name: Test v binaries
run: ./v -silent build-vbinaries
@ -71,9 +71,9 @@ jobs:
brew install freetype glfw openssl postgres sdl2 sdl2_ttf sdl2_mixer sdl2_image
export LIBRARY_PATH="$LIBRARY_PATH:/usr/local/opt/openssl/lib/"
- name: Build V
run: make -j4 && ./v -cg -o v v.v
run: make -j4 && ./v -cg -o v cmd/v
- name: Build V using V
run: ./v -o v2 v.v && ./v2 -o v3 v.v
run: ./v -o v2 cmd/v && ./v2 -o v3 cmd/v
- name: Test symlink
run: sudo ./v symlink
- name: Set up pg database
@ -89,7 +89,7 @@ jobs:
# - name: Test v->js
# run: ./v -o hi.js examples/hello_v_js.v && node hi.js
- name: Test symlink
run: ./v symlink && v -o v2 v.v
run: ./v symlink && v -o v2 cmd/v
- name: Test vsh
run: ./v examples/v_script.vsh
- name: Test vid
@ -107,7 +107,7 @@ jobs:
- name: Install dependencies
run: sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list; sudo apt-get update; sudo apt-get install --quiet -y postgresql libpq-dev libglfw3 libglfw3-dev libfreetype6-dev libssl-dev sqlite3 libsqlite3-dev libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libsdl2-image-dev
- name: Build V
run: make -j4 && ./v -cc gcc -o v v.v
run: make -j4 && ./v -cc gcc -o v cmd/v
- name: Test V
run: ./v -silent test-compiler
- name: Test v binaries
@ -122,13 +122,13 @@ jobs:
run: ./v -freestanding -o bare vlib/os/bare/bare_example_linux.v
- name: x64 machine code generation
run: |
./v -o vprod -prod v.v
cd tools
./v -o vprod -prod cmd/v
cd cmd/tools
echo "Generating a 1m line V file..."
../vprod gen1m.v
../../vprod gen1m.v
./gen1m > 1m.v
echo "Building it..."
../vprod -x64 -o 1m 1m.v
../../vprod -x64 -o 1m 1m.v
echo "Running it..."
ls
# ./1m
@ -191,7 +191,7 @@ jobs:
- name: Install dependencies
run: sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list; sudo apt-get update; sudo apt-get install --quiet -y musl musl-tools libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libsdl2-image-dev
- name: Build v
run: echo $VFLAGS && make -j4 && ./v -cg -o v v.v
run: echo $VFLAGS && make -j4 && ./v -cg -o v cmd/v
- name: Test v binaries
run: ./v -silent build-vbinaries
# - name: Test v->js

View File

@ -19,12 +19,12 @@ jobs:
sudo apt-get install --quiet -y sqlite3 libsqlite3-dev
sudo apt-get install --quiet -y libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libsdl2-image-dev
- name: Build v
run: echo $VFLAGS && make -j4 && ./v -cg -o v v.v
run: echo $VFLAGS && make -j4 && ./v -cg -o v cmd/v
- name: Test v->c
run: |
sudo ln -s /var/tmp/tcc/bin/tcc /usr/local/bin/tcc
tcc -version
./v -o v2 v.v # Make sure vtcc can build itself
./v -o v2 cmd/v # Make sure vtcc can build itself
- name: Run network tests
run: ./v -d network test vlib/

28
.gitignore vendored
View File

@ -7,20 +7,20 @@ fns.txt
/v.c
/v.*.c
/v.c.out
/tools/performance_compare
/tools/oldv
/tools/vrepl
/tools/vtest
/tools/vtest-compiler
/tools/vtest-fmt
/tools/vfmt
/tools/vbin2v
/tools/vup
/tools/vpm
/tools/vcreate
/tools/vbuild-examples
/tools/vbuild-tools
/tools/vbuild-vbinaries
/cmd/tools/performance_compare
/cmd/tools/oldv
/cmd/tools/vrepl
/cmd/tools/vtest
/cmd/tools/vtest-compiler
/cmd/tools/vtest-fmt
/cmd/tools/vfmt
/cmd/tools/vbin2v
/cmd/tools/vup
/cmd/tools/vpm
/cmd/tools/vcreate
/cmd/tools/vbuild-examples
/cmd/tools/vbuild-tools
/cmd/tools/vbuild-vbinaries
/v_g
/v_cg
/v_prod

View File

@ -3,7 +3,7 @@ FROM mstorsjo/llvm-mingw
LABEL maintainer="Vitaly Takmazov <vitalyster@gmail.com>"
COPY . .
RUN make
RUN ./v -os windows -o v.c v.v
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

View File

@ -42,8 +42,8 @@ endif
all: latest_vc latest_tcc
ifdef WIN32
$(CC) $(CFLAGS) -std=c99 -municode -w -o v2.exe $(TMPVC)/$(VCFILE) $(LDFLAGS)
./v2.exe -o v3.exe v.v
./v3.exe -o v.exe -prod v.v
./v2.exe -o v3.exe cmd/v
./v3.exe -o v.exe -prod cmd/v
rm -f v2.exe v3.exe
else
$(CC) $(CFLAGS) -std=gnu11 -w -o v $(TMPVC)/$(VCFILE) $(LDFLAGS) -lm
@ -92,10 +92,10 @@ $(TMPVC)/.git/config:
$(MAKE) fresh_vc
selfcompile:
./v -cg -o v v.v
./v -cg -o v cmd/v
selfcompile-static:
./v -cg -cflags '--static' -o v-static v.v
./v -cg -cflags '--static' -o v-static cmd/v
modules: module_builtin module_strings module_strconv
module_builtin:

View File

@ -11,9 +11,9 @@ import (
fn main() {
exe := os.executable()
dir := filepath.dir(exe)
vdir := filepath.dir(filepath.dir(dir))
vdir := filepath.dir(filepath.dir(filepath.dir(dir)))
if !os.exists('$vdir/v') && !os.is_dir('$vdir/vlib') {
println('fast.html generator needs to be located in `v/tools/fast/`')
println('fast.html generator needs to be located in `v/cmd/tools/fast`')
}
println('fast.html generator\n')
// Fetch the last commit's hash
@ -36,11 +36,11 @@ fn main() {
}
// Build an optimized V
println('Building vprod...')
exec('v -o $vdir/vprod -prod $vdir/v.v')
exec('v -o $vdir/vprod -prod $vdir/cmd/v')
println('Measuring...')
diff1 := measure('$vdir/vprod -cc clang -o v.c $vdir/v.v')
diff2 := measure('$vdir/vprod -cc clang -o v2 $vdir/v.v')
diff3 := measure('$vdir/vprod -x64 $vdir/tools/1mil.v')
diff1 := measure('$vdir/vprod -cc clang -o v.c $vdir/cmd/v')
diff2 := measure('$vdir/vprod -cc clang -o v2 $vdir/cmd/v')
diff3 := measure('$vdir/vprod -x64 $vdir/cmd/tools/1mil.v')
diff4 := measure('$vdir/vprod -cc clang $vdir/examples/hello_world.v')
//println('Building V took ${diff}ms')
commit_date := exec('git log -n1 --pretty="format:%at"')

View File

@ -38,7 +38,7 @@ td {
<h2>Is V still fast?</h2>
Monitoring compilation speed for each commit. <br><br>
Source code: <a target=blank href='https://github.com/vlang/v/blob/master/tools/fast/fast.v'>fast.v</a> <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>

View File

@ -291,7 +291,7 @@ fn (gen_vc mut GenVC) generate() {
v_flags := if os_name == 'nix' { '-output-cross-platform-c' } else { '-os $os_name' }
c_file := 'v${vc_suffix}.c'
// try generate .c file
gen_vc.cmd_exec('$v_exec $v_flags -o $c_file $git_repo_dir_v/v.v')
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

View File

@ -39,7 +39,7 @@ pub fn new_test_session(vargs string) TestSession {
pub fn vexe_path() string {
// NB: tools extracted from v require that the VEXE
// environment variable contains the path to the v executable location.
// They are usually launched by vlib/compiler/vtools.v,
// They are usually launched by cmd/v/simple_tool.v,
// launch_tool/1 , which provides it.
return os.getenv('VEXE')
}
@ -238,11 +238,11 @@ pub fn building_any_v_binaries_failed() bool {
testing.vlib_should_be_present(parent_dir)
os.chdir(parent_dir)
mut failed := false
v_build_commands := ['$vexe -o v_g -g v.v',
'$vexe -o v_prod_g -prod -g v.v',
'$vexe -o v_cg -cg v.v',
'$vexe -o v_prod_cg -prod -cg v.v',
'$vexe -o v_prod -prod v.v',
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 {

View File

@ -92,7 +92,7 @@ pub mut:
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/ , depending on v version
vvlocation string // v.v or compiler/ or cmd/v, depending on v version
}
pub fn (vgit_context mut VGitContext) compile_oldv_if_needed() {
@ -117,7 +117,11 @@ pub fn (vgit_context mut VGitContext) compile_oldv_if_needed() {
v_commithash,vccommit_before := vgit.prepare_vc_source(vgit_context.path_vc, vgit_context.path_v, vgit_context.commit_v)
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

View File

@ -19,7 +19,7 @@ const (
git checkout known_good_commit
git bisect good
## Now git will automatically checkout a middle commit between the bad and the good
tools/oldv HEAD --command="run commands in oldv folder, to verify if the commit is good or bad"
cmd/tools/oldv HEAD --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:

View File

@ -126,7 +126,9 @@ fn (c &Context) prepare_v(cdir string, commit string) {
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 == 'v.v' {
if vgit_context.vvlocation == 'cmd/v' {
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'))
@ -136,8 +138,18 @@ fn (c &Context) prepare_v(cdir string, commit string) {
fn (c Context) compare_v_performance(label string, commands []string) string {
println('---------------------------------------------------------------------------------')
println('Compare v performance when doing the following commands ($label):')
source_location_a := if os.exists('$c.a/v.v') { 'v.v ' } else { 'compiler/ ' }
source_location_b := if os.exists('$c.b/v.v') { 'v.v ' } else { 'compiler/ ' }
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 { '-g ' } else { '-debug ' }

View File

@ -1,28 +1,28 @@
# V preludes:
The tools/preludes/ contains small v code snippets, that V uses when
The cmd/tools/preludes/ contains small v code snippets, that V uses when
compiling certain v programs. V adds the files below automatically itself.
Each file is used in different situations (see below).
NB: preludes are *NOT* intended to be used by user programs/modules.
The folder tools/preludes/ is *NOT* a v module.
The folder cmd/tools/preludes/ is *NOT* a v module.
## Details:
### tools/preludes/live_main.v
### cmd/tools/preludes/live_main.v
Used when compiling live programs. This file is used by the main executable
live program, that starts the file change monitoring thread. Each live program
needs module `os` and module `time`, in order for the background file change
monitoring thread to work properly.
### tools/preludes/live_shared.v
### cmd/tools/preludes/live_shared.v
Used when compiling live programs, for the shared library portion of the live
programs, that is reloaded each time the code is changed.
### tools/preludes/tests_assertions.v
### cmd/tools/preludes/tests_assertions.v
Used when compiling `_test.v` programs.
It specifies how failed assertions will look.
### tools/preludes/tests_with_stats.v
### cmd/tools/preludes/tests_with_stats.v
Used when compiling `_test.v` programs with -stats option.
It specifies how the result will appear ('assert' vs 'asserts' and so on).

View File

@ -8,7 +8,7 @@ import (
fn main() {
args := os.args
args_string := args[1..].join(' ')
if testing.v_build_failing(args_string.all_before('build-tools'), 'tools') {
if testing.v_build_failing(args_string.all_before('build-tools'), 'cmd/tools') {
exit(1)
}
}

View File

@ -8,6 +8,7 @@ import (
os.cmdline
filepath
compiler
v.pref
)
struct FormatOptions {
@ -35,8 +36,8 @@ const (
fn main() {
toolexe := os.executable()
compiler.set_vroot_folder(filepath.dir(filepath.dir(toolexe)))
args := compiler.env_vflags_and_os_args()
compiler.set_vroot_folder(filepath.dir(filepath.dir(filepath.dir(toolexe))))
args := join_flags_and_argument()
foptions := FormatOptions{
is_c: '-c' in args
is_l: '-l' in args
@ -134,10 +135,10 @@ fn main() {
fn (foptions &FormatOptions) format_file(file string) {
tmpfolder := os.tmpdir()
mut compiler_params := []string
mut compiler_params := &pref.Preferences{}
target_os := file_to_target_os(file)
if target_os != '' {
compiler_params << ['-os', target_os]
compiler_params.os = pref.os_from_string(target_os)
}
mut cfile := file
mut mod_folder_parent := tmpfolder
@ -158,7 +159,7 @@ fn (foptions &FormatOptions) format_file(file string) {
}
os.write_file(main_program_file, main_program_content)
cfile = main_program_file
compiler_params << ['-user_mod_path', mod_folder_parent]
compiler_params.user_mod_path = mod_folder_parent
}
if !is_test_file && mod_name == 'main' {
// NB: here, file is guaranted to be a main. We do not know however
@ -166,7 +167,10 @@ fn (foptions &FormatOptions) format_file(file string) {
// project, like vorum or vid.
cfile = get_compile_name_of_potential_v_project(cfile)
}
compiler_params << cfile
compiler_params.path = cfile
compiler_params.mod = mod_name
compiler_params.is_test = is_test_file
compiler_params.is_script = file.ends_with('.v') || file.ends_with('.vsh')
if foptions.is_verbose {
eprintln('vfmt format_file: file: $file')
eprintln('vfmt format_file: cfile: $cfile')
@ -176,9 +180,15 @@ fn (foptions &FormatOptions) format_file(file string) {
eprintln('vfmt format_file: mod_folder: $mod_folder')
eprintln('vfmt format_file: mod_folder_parent: $mod_folder_parent')
eprintln('vfmt format_file: use_tmp_main_program: $use_tmp_main_program')
eprintln('vfmt format_file: compiler_params: $compiler_params')
eprintln('vfmt format_file: compiler_params: ')
print_compiler_options( compiler_params )
eprintln('-------------------------------------------')
}
compiler_params.fill_with_defaults()
if foptions.is_verbose {
eprintln('vfmt format_file: compiler_params: AFTER fill_with_defaults() ')
print_compiler_options( compiler_params )
}
formatted_file_path := foptions.compile_file(file, compiler_params)
if use_tmp_main_program {
if !foptions.is_debug {
@ -188,6 +198,22 @@ fn (foptions &FormatOptions) format_file(file string) {
eprintln('${FORMATTED_FILE_TOKEN}${formatted_file_path}')
}
fn print_compiler_options( compiler_params &pref.Preferences ) {
eprintln(' os: ' + compiler_params.os.str() )
eprintln(' ccompiler: $compiler_params.ccompiler' )
eprintln(' mod: $compiler_params.mod ')
eprintln(' path: $compiler_params.path ')
eprintln(' out_name: $compiler_params.out_name ')
eprintln(' vroot: $compiler_params.vroot ')
eprintln(' vpath: $compiler_params.vpath ')
eprintln(' vlib_path: $compiler_params.vlib_path ')
eprintln(' out_name: $compiler_params.out_name ')
eprintln(' umpath: $compiler_params.user_mod_path ')
eprintln(' cflags: $compiler_params.cflags ')
eprintln(' is_test: $compiler_params.is_test ')
eprintln(' is_script: $compiler_params.is_script ')
}
fn (foptions &FormatOptions) post_process_file(file string, formatted_file_path string) {
if formatted_file_path.len == 0 {
return
@ -238,7 +264,7 @@ fn (foptions &FormatOptions) post_process_file(file string, formatted_file_path
}
fn usage() {
print('Usage: tools/vfmt [flags] fmt path_to_source.v [path_to_other_source.v]
print('Usage: cmd/tools/vfmt [flags] fmt path_to_source.v [path_to_other_source.v]
Formats the given V source files, and prints their formatted source to stdout.
Options:
-c check if file is already formatted.
@ -261,12 +287,13 @@ fn find_working_diff_command() ?string {
return error('no working diff command found')
}
fn (foptions &FormatOptions) compile_file(file string, compiler_params []string) string {
fn (foptions &FormatOptions) compile_file(file string, compiler_params &pref.Preferences) string {
if foptions.is_verbose {
eprintln('> new_v_compiler_with_args file: ' + file)
eprintln('> new_v_compiler_with_args compiler_params: ' + compiler_params.join(' '))
eprintln('> new_v_compiler_with_args file: $file')
eprintln('> new_v_compiler_with_args compiler_params:')
print_compiler_options( compiler_params )
}
mut v := compiler.new_v_compiler_with_args(compiler_params)
mut v := compiler.new_v(compiler_params)
v.v_fmt_file = file
if foptions.is_all {
v.v_fmt_all = true
@ -360,3 +387,28 @@ fn get_compile_name_of_potential_v_project(file string) string {
}
return pfolder
}
//TODO Move join_flags_and_argument() and non_empty() into `cmd/internal` when v.mod work correctly
//to prevent code duplication with `cmd/v` (cmd/v/flag.v)
fn join_flags_and_argument() []string {
vosargs := os.getenv('VOSARGS')
if vosargs != '' {
return non_empty(vosargs.split(' '))
}
mut args := []string
vflags := os.getenv('VFLAGS')
if vflags != '' {
args << os.args[0]
args << vflags.split(' ')
if os.args.len > 1 {
args << os.args[1..]
}
return non_empty(args)
}
return non_empty(os.args)
}
fn non_empty(arg []string) []string {
return arg.filter(it != '')
}

View File

@ -6,6 +6,7 @@ import (
strings
filepath
compiler
v.pref
)
const (
@ -32,7 +33,11 @@ fn analyze_v_file(file string) {
println('$hash $file $hash')
// main work:
mut v := compiler.new_v_compiler_with_args([file])
mut pref := &pref.Preferences{
path: file
}
pref.fill_with_defaults()
mut v := compiler.new_v(pref)
v.add_v_files_to_compile()
for f in v.files { v.parse(f, .decl) }
fi := v.get_file_parser_index( file ) or { panic(err) }
@ -51,7 +56,7 @@ fn analyze_v_file(file string) {
fn main(){
toolexe := os.executable()
compiler.set_vroot_folder( filepath.dir(filepath.dir(toolexe)) )
compiler.set_vroot_folder(filepath.dir(filepath.dir(filepath.dir(toolexe))))
mut fp := flag.new_flag_parser(os.args)
fp.application(filepath.filename(toolexe))

View File

@ -33,8 +33,8 @@ fn v_test_compiler(vargs string) {
// Make sure v.c can be compiled without warnings
$if macos {
if os.exists('/v.v') {
os.system('$vexe -o v.c v.v')
if os.exists('/cmd/v') {
os.system('$vexe -o v.c cmd/v')
if os.system('cc -Werror v.c') != 0 {
eprintln('cc failed to build v.c without warnings')
exit(1)
@ -42,7 +42,7 @@ fn v_test_compiler(vargs string) {
eprintln('v.c can be compiled without warnings. This is good :)')
}
}
building_tools_failed := testing.v_build_failing(vargs, 'tools')
building_tools_failed := testing.v_build_failing(vargs, 'cmd/tools')
eprintln('')
testing.eheader('Testing all _test.v files...')
mut compiler_test_session := testing.new_test_session(vargs)

View File

@ -7,14 +7,14 @@ import (
const (
known_failing_exceptions = ['./examples/vweb/vweb_example.v',
'./tools/gen_vc.v',
'./tools/modules/vgit/vgit.v', // generics
'./tools/preludes/live_main.v',
'./tools/preludes/live_shared.v',
'./tools/preludes/tests_assertions.v',
'./tools/preludes/tests_with_stats.v',
'./tools/performance_compare.v', // generics
'./tools/oldv.v', // generics
'./cmd/tools/gen_vc.v',
'./cmd/tools/modules/vgit/vgit.v', // generics
'./cmd/tools/preludes/live_main.v',
'./cmd/tools/preludes/live_shared.v',
'./cmd/tools/preludes/tests_assertions.v',
'./cmd/tools/preludes/tests_with_stats.v',
'./cmd/tools/performance_compare.v', // generics
'./cmd/tools/oldv.v', // generics
'./tutorials/code/blog/article.v',
'./tutorials/code/blog/blog.v',
'./vlib/arrays/arrays.v',

67
cmd/v/compile.v 100644
View File

@ -0,0 +1,67 @@
// Copyright (c) 2019-2020 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 (
benchmark
os
os.cmdline
)
fn compile(command string, args []string) {
// Construct the V object from command line arguments
mut v := new_v(args)
if v.pref.is_verbose {
println(args)
}
if command == 'run' {
// always recompile for now, too error prone to skip recompilation otherwise
// for example for -repl usage, especially when piping lines to v
v.compile()
run_compiled_executable_and_exit(v, args)
}
mut tmark := benchmark.new_benchmark()
if v.pref.x64 {
v.compile_x64()
}
else if v.pref.v2 {
v.compile2()
}
else {
v.compile()
}
if v.pref.is_stats {
tmark.stop()
println('compilation took: ' + tmark.total_duration().str() + 'ms')
}
if v.pref.is_test {
run_compiled_executable_and_exit(v, args)
}
v.finalize_compilation()
}
pub fn run_compiled_executable_and_exit(v &compiler.V, args []string) {
if v.pref.is_verbose {
println('============ running $v.pref.out_name ============')
}
mut cmd := '"${v.pref.out_name}"'
args_after_no_options := cmdline.only_non_options( cmdline.after(args,['run','test']) )
if args_after_no_options.len > 1 {
cmd += ' ' + args_after_no_options[1..].join(' ')
}
if v.pref.is_test {
ret := os.system(cmd)
if ret != 0 {
exit(1)
}
}
if v.pref.is_run {
ret := os.system(cmd)
// TODO: make the runner wrapping as transparent as possible
// (i.e. use execve when implemented). For now though, the runner
// just returns the same exit code as the child process.
exit(ret)
}
exit(0)
}

View File

@ -0,0 +1,229 @@
// Copyright (c) 2019-2020 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 (
compiler
filepath
os
os.cmdline
v.pref
)
//TODO Cleanup this file. This file ended up like a dump for functions that do not belong in `compiler`.
//Maybe restructure the functions below into different V files
pub fn new_v(args []string) &compiler.V {
// Create modules dirs if they are missing
if !os.is_dir(compiler.v_modules_path) {
os.mkdir(compiler.v_modules_path)or{
panic(err)
}
os.mkdir('$compiler.v_modules_path${os.path_separator}cache')or{
panic(err)
}
}
vroot := filepath.dir(vexe_path())
// optional, custom modules search path
user_mod_path := cmdline.option(args, '-user_mod_path', '')
vlib_path := cmdline.option(args, '-vlib-path', '')
vpath := cmdline.option(args, '-vpath', '')
target_os := cmdline.option(args, '-os', '')
if target_os == 'msvc' {
// notice that `-os msvc` became `-cc msvc`
println('V error: use the flag `-cc msvc` to build using msvc')
os.flush_stdout()
exit(1)
}
mut out_name := cmdline.option(args, '-o', '')
mut dir := args.last()
if 'run' in args {
args_after_run := cmdline.only_non_options( cmdline.after(args,['run']) )
dir = if args_after_run.len>0 { args_after_run[0] } else { '' }
}
if dir == 'v.v' {
println('looks like you are trying to build V with an old command')
println('use `v -o v cmd/v` instead of `v -o v v.v`')
exit(1)
}
if dir.ends_with(os.path_separator) {
dir = dir.all_before_last(os.path_separator)
}
if dir.starts_with('.$os.path_separator') {
dir = dir[2..]
}
if args.len < 2 {
dir = ''
}
// build mode
mut build_mode := pref.BuildMode.default_mode
mut mod := ''
joined_args := args.join(' ')
if joined_args.contains('build module ') {
build_mode = .build_module
os.chdir(vroot)
// v build module ~/v/os => os.o
mod_path := if dir.contains('vlib') { dir.all_after('vlib' + os.path_separator) } else if dir.starts_with('.\\') || dir.starts_with('./') { dir[2..] } else if dir.starts_with(os.path_separator) { dir.all_after(os.path_separator) } else { dir }
mod = mod_path.replace(os.path_separator, '.')
println('Building module "${mod}" (dir="$dir")...')
// out_name = '$TmpPath/vlib/${base}.o'
if !out_name.ends_with('.c') {
out_name = mod
}
// Cross compiling? Use separate dirs for each os
/*
if target_os != os.user_os() {
os.mkdir('$TmpPath/vlib/$target_os') or { panic(err) }
out_name = '$TmpPath/vlib/$target_os/${base}.o'
println('target_os=$target_os user_os=${os.user_os()}')
println('!Cross compiling $out_name')
}
*/
}
// `v -o dir/exec`, create "dir/" if it doesn't exist
if out_name.contains(os.path_separator) {
d := out_name.all_before_last(os.path_separator)
if !os.is_dir(d) {
println('creating a new directory "$d"')
os.mkdir(d)or{
panic(err)
}
}
}
// println('VROOT=$vroot')
cflags := cmdline.many_values(args, '-cflags').join(' ')
defines := cmdline.many_values(args, '-d')
compile_defines, compile_defines_all := parse_defines( defines )
rdir := os.realpath(dir)
rdir_name := filepath.filename(rdir)
if '-bare' in args {
println('V error: use -freestanding instead of -bare')
os.flush_stdout()
exit(1)
}
is_repl := '-repl' in args
ccompiler := cmdline.option(args, '-cc', '')
mut pref := &pref.Preferences{
os: pref.os_from_string(target_os)
is_so: '-shared' in args
is_solive: '-solive' in args
is_prod: '-prod' in args
is_verbose: '-verbose' in args || '--verbose' in args
is_debug: '-g' in args || '-cg' in args
is_vlines: '-g' in args && !('-cg' in args)
is_keep_c: '-keep_c' in args
is_pretty_c: '-pretty_c' in args
is_cache: '-cache' in args
is_stats: '-stats' in args
obfuscate: '-obf' in args
is_prof: '-prof' in args
is_live: '-live' in args
sanitize: '-sanitize' in args
// nofmt: '-nofmt' in args
show_c_cmd: '-show_c_cmd' in args
translated: 'translated' in args
is_run: 'run' in args
autofree: '-autofree' in args
compress: '-compress' in args
enable_globals: '--enable-globals' in args
fast: '-fast' in args
is_bare: '-freestanding' in args
x64: '-x64' in args
output_cross_c: '-output-cross-platform-c' in args
prealloc: '-prealloc' in args
is_repl: is_repl
build_mode: build_mode
cflags: cflags
ccompiler: ccompiler
building_v: !is_repl && (rdir_name == 'compiler' || rdir_name == 'v.v' || rdir_name == 'vfmt.v' || rdir_name == 'cmd/v' || dir.contains('vlib'))
// is_fmt: comptime_define == 'vfmt'
user_mod_path: user_mod_path
vlib_path: vlib_path
vpath: vpath
v2: '-v2' in args
vroot: vroot
out_name: out_name
path: dir
compile_defines: compile_defines
compile_defines_all: compile_defines_all
mod: mod
}
if pref.is_verbose || pref.is_debug {
println('C compiler=$pref.ccompiler')
}
$if !linux {
if pref.is_bare && !out_name.ends_with('.c') {
println('V error: -freestanding only works on Linux for now')
os.flush_stdout()
exit(1)
}
}
pref.fill_with_defaults()
// v.exe's parent directory should contain vlib
if !os.is_dir(pref.vlib_path) || !os.is_dir(pref.vlib_path + os.path_separator + 'builtin') {
// println('vlib not found, downloading it...')
/*
ret := os.system('git clone --depth=1 https://github.com/vlang/v .')
if ret != 0 {
println('failed to `git clone` vlib')
println('make sure you are online and have git installed')
exit(1)
}
*/
println('vlib not found. It should be next to the V executable.')
println('Go to https://vlang.io to install V.')
println('(os.executable=${os.executable()} vlib_path=$pref.vlib_path vexe_path=${vexe_path()}')
exit(1)
}
if pref.is_script && !os.exists(dir) {
println('`$dir` does not exist')
exit(1)
}
return compiler.new_v(pref)
}
fn find_c_compiler_thirdparty_options(args []string) string {
mut cflags := cmdline.many_values(args,'-cflags')
$if !windows {
cflags << '-fPIC'
}
if '-m32' in args {
cflags << '-m32'
}
return cflags.join(' ')
}
fn parse_defines(defines []string) ([]string,[]string) {
// '-d abc -d xyz=1 -d qwe=0' should produce:
// compile_defines: ['abc','xyz']
// compile_defines_all ['abc','xyz','qwe']
mut compile_defines := []string
mut compile_defines_all := []string
for dfn in defines {
dfn_parts := dfn.split('=')
if dfn_parts.len == 1 {
compile_defines << dfn
compile_defines_all << dfn
continue
}
if dfn_parts.len == 2 {
compile_defines_all << dfn_parts[0]
if dfn_parts[1] == '1' {
compile_defines << dfn_parts[0]
}
}
}
return compile_defines, compile_defines_all
}

78
cmd/v/flag.v 100644
View File

@ -0,0 +1,78 @@
// Copyright (c) 2019-2020 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
const (
//list_of_flags contains a list of flags where an argument is expected past it.
list_of_flags = [
'-o', '-os', '-cc', '-cflags', '-d'
]
)
fn get_basic_command_and_option(args []string) (string, []string) {
mut option := []string
for i, arg in args {
if i == 0 {
//Skip executable
continue
}
if arg == '--' {
//End of list of options. The next one is the command.
if i+1 < os.args.len {
return os.args[i+1], option
}
//There's no option past this
return '', option
}
if arg in list_of_flags {
i++
continue
}
if arg[0] == `-` {
option << arg
continue
}
//It's not a flag. We did not skip it. It's a command.
return arg, option
}
//There's no arguments that were not part of a flag.
return '', option
}
fn non_empty(arg []string) []string {
return arg.filter(it != '')
}
fn join_flags_and_argument() []string {
vosargs := os.getenv('VOSARGS')
if vosargs != '' {
return non_empty(vosargs.split(' '))
}
mut args := []string
vflags := os.getenv('VFLAGS')
if vflags != '' {
args << os.args[0]
args << vflags.split(' ')
if os.args.len > 1 {
args << os.args[1..]
}
return non_empty(args)
}
return non_empty(os.args)
}
fn vexe_path() string {
vexe := os.getenv('VEXE')
if vexe != '' {
return vexe
}
real_vexe_path := os.realpath(os.executable())
os.setenv('VEXE', real_vexe_path, true)
return real_vexe_path
}

View File

@ -1,8 +1,16 @@
module compiler
module main
pub const (
const (
help_text = 'Usage: v [options/commands] [file.v | directory]
To run V in REPL mode, run V without any arguments.
To compile a directory/file, pass it as the only argument.
To run a directory/file, use `v run [file.v | directory]`. V will compile and run it for you.
This help message is only intended to be a quick start guide. For a comprehensive help message, use `v help --verbose`.'
verbose_help_text = 'Usage: v [options/commands] [file.v | directory]
When V is run without any arguments, it is run in REPL mode.
When given a .v file, it will be compiled. The executable will have the

View File

@ -1,23 +1,27 @@
module compiler
// Copyright (c) 2019-2020 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
compiler
filepath
os
)
pub fn launch_tool(tname string, cmdname string) {
is_verbose := '-verbose' in os.args || '--verbose' in os.args
fn launch_tool(is_verbose bool, tname string, cmdname string) {
vexe := vexe_path()
vroot := filepath.dir(vexe)
set_vroot_folder( vroot ) // needed by tools to find back v
compiler.set_vroot_folder(vroot)
mut tname_index := os.args.index(cmdname)
if tname_index == -1 {
tname_index = os.args.len
}
mut compilation_options := os.args[1..tname_index].clone()
tool_args := os.args[1..].join(' ')
tool_exe := os.realpath('$vroot/tools/$tname')
tool_source := os.realpath('$vroot/tools/${tname}.v')
tool_exe := os.realpath('$vroot/cmd/tools/$tname')
tool_source := os.realpath('$vroot/cmd/tools/${tname}.v')
tool_command := '"$tool_exe" $tool_args'
if is_verbose {
eprintln('launch_tool vexe : $vroot')
@ -25,28 +29,29 @@ pub fn launch_tool(tname string, cmdname string) {
eprintln('launch_tool tool_args : $tool_args')
eprintln('launch_tool tool_command: $tool_command')
}
mut tool_should_be_recompiled := false
mut should_compile := false
if !os.exists(tool_exe) {
// fresh checkout
tool_should_be_recompiled = true
should_compile = true
} else {
if os.file_last_mod_unix(tool_exe) <= os.file_last_mod_unix(vexe) {
// v was recompiled, maybe after v up ...
// rebuild the tool too just in case
tool_should_be_recompiled = true
should_compile = true
}
if os.file_last_mod_unix(tool_exe) <= os.file_last_mod_unix(tool_source) {
// the user changed the source code of the tool
tool_should_be_recompiled = true
should_compile = true
}
}
if is_verbose {
eprintln('launch_tool tool_should_be_recompiled: $tool_should_be_recompiled')
eprintln('launch_tool should_compile: $should_compile')
}
if tool_should_be_recompiled {
if tname == 'vfmt' { compilation_options << ['-d', 'vfmt'] }
if should_compile {
if tname == 'vfmt' {
compilation_options << ['-d', 'vfmt']
}
compilation_args := compilation_options.join(' ')
compilation_command := '"$vexe" $compilation_args "$tool_source"'
if is_verbose {

31
cmd/v/symlink.v 100644
View File

@ -0,0 +1,31 @@
// Copyright (c) 2019-2020 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
fn create_symlink() {
$if windows {
return
}
vexe := vexe_path()
mut link_path := '/usr/local/bin/v'
mut ret := os.exec('ln -sf $vexe $link_path') or { panic(err) }
if ret.exit_code == 0 {
println('Symlink "$link_path" has been created')
}
else if os.system('uname -o | grep -q \'[A/a]ndroid\'') == 0 {
println('Failed to create symlink "$link_path". Trying again with Termux path for Android.')
link_path = '/data/data/com.termux/files/usr/bin/v'
ret = os.exec('ln -sf $vexe $link_path') or { panic(err) }
if ret.exit_code == 0 {
println('Symlink "$link_path" has been created')
} else {
println('Failed to create symlink "$link_path". Try again with sudo.')
}
} else {
println('Failed to create symlink "$link_path". Try again with sudo.')
}
}

88
cmd/v/v.v 100644
View File

@ -0,0 +1,88 @@
// Copyright (c) 2019-2020 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 (
compiler
os
)
const (
simple_cmd = [
'fmt',
'up',
'create',
'test', 'test-fmt', 'test-compiler',
'bin2v',
'repl',
'build-tools', 'build-examples', 'build-vbinaries'
]
)
fn main() {
arg := join_flags_and_argument()
command, option := get_basic_command_and_option(arg)
is_verbose := '-verbose' in arg || '--verbose' in arg
if '-v' in option || '--version' in option || command == 'version' {
// Print the version and exit.
version_hash := compiler.vhash()
println('V $compiler.Version $version_hash')
return
}
if '-h' in option || '--help' in option || command == 'help' {
if is_verbose {
println(verbose_help_text)
} else {
println(help_text)
}
return
}
if is_verbose {
eprintln('v args: $arg')
eprintln('v command: $command')
eprintln('v options: $option')
}
if command in simple_cmd {
//External tools
launch_tool(is_verbose, 'v' + command, command)
return
}
if command == 'run' || command == 'build' || command.ends_with('.v') || os.exists(command) {
compile(command, arg)
return
}
match command {
'', '-' {
if arg.len == 1 {
println('Running REPL as no arguments are provided. For usage information, use `v help`.')
}
launch_tool(is_verbose, 'vrepl', '')
}
'translate' {
println('Translating C to V will be available in V 0.3 (January)')
}
'search', 'install', 'update', 'remove' {
launch_tool(is_verbose, 'vpm', command)
}
'get' {
println('Use `v install` to install modules from vpm.vlang.io.')
}
'symlink' {
create_symlink()
}
'doc' {
println('Currently unimplemented')
}
else {
eprintln('v $command: unknown command\nRun "v help" for usage.')
exit(1)
}
}
}

View File

@ -35,8 +35,8 @@ if %ERRORLEVEL% NEQ 0 (
)
echo Now using V to build V...
v2.exe -o v3.exe v.v
v3.exe -o v.exe -prod v.v
v2.exe -o v3.exe cmd/v
v3.exe -o v.exe -prod cmd/v
if %ERRORLEVEL% NEQ 0 (
echo v.exe failed to compile itself - Create an issue at 'https://github.com/vlang'
exit /b 1
@ -77,8 +77,8 @@ if %ERRORLEVEL% NEQ 0 (
)
echo rebuild from source (twice, in case of C definitions changes)
v2.exe -cc msvc -o v3.exe v.v
v3.exe -cc msvc -o v -prod v.v
v2.exe -cc msvc -o v3.exe cmd/v
v3.exe -cc msvc -o v -prod cmd/v
if %ERRORLEVEL% NEQ 0 (
echo V failed to build itself with error %ERRORLEVEL%
goto :compileerror

140
v.v
View File

@ -1,140 +0,0 @@
// Copyright (c) 2019-2020 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 (
compiler
benchmark
os
filepath
// v.types
// time
)
const (
known_commands = ['run', 'build', 'version', 'doc']
simple_tools = ['fmt',
'up',
'create',
'test', 'test-fmt', 'test-compiler',
'bin2v',
'repl',
'build-tools', 'build-examples', 'build-vbinaries']
)
fn main() {
is_verbose := '-verbose' in os.args || '--verbose' in os.args
// t := time.ticks()
// defer { println(time.ticks() - t) }
args := compiler.env_vflags_and_os_args()
options,command := compiler.get_v_options_and_main_command(args)
if is_verbose {
eprintln('v args: $args')
eprintln('v command: $command')
eprintln('v options: $options')
}
// external tool
if command in simple_tools {
compiler.launch_tool('v' + command, command)
return
}
// v run, v doc, etc
if !command.starts_with('-') && !command.ends_with('.v') && !os.exists(command) {
v_command(command, args)
}
// Print the version and exit.
if '-v' in options || '--version' in options {
version_hash := compiler.vhash()
println('V $compiler.Version $version_hash')
return
}
else if '-h' in options || '--help' in options {
println(compiler.help_text)
return
}
// No args? REPL
else if command == '' || (args.len == 2 && args[1] == '-') {
compiler.launch_tool('vrepl', '')
return
}
// Construct the V object from command line arguments
mut v := compiler.new_v(args)
if v.pref.is_verbose {
println(args)
}
if command == 'run' {
// always recompile for now, too error prone to skip recompilation otherwise
// for example for -repl usage, especially when piping lines to v
v.compile()
v.run_compiled_executable_and_exit()
}
mut tmark := benchmark.new_benchmark()
if v.pref.x64 {
v.compile_x64()
}
else if v.pref.v2 {
v.compile2()
}
else {
v.compile()
}
if v.pref.is_stats {
tmark.stop()
println('compilation took: ' + tmark.total_duration().str() + 'ms')
}
if v.pref.is_test {
v.run_compiled_executable_and_exit()
}
v.finalize_compilation()
}
fn v_command(command string, args []string) {
match command {
'', '.', 'run', 'build' {
// handled later in vlib/compiler/main.v
return
}
'version' {
println('V $compiler.Version $compiler.vhash()')
}
'help' {
println(compiler.help_text)
}
'translate' {
println('Translating C to V will be available in V 0.3 (January)')
}
'search', 'install', 'update', 'remove' {
compiler.launch_tool('vpm', command)
}
'get' {
println('use `v install` to install modules from vpm.vlang.io ')
}
'symlink' {
compiler.create_symlink()
}
'runrepl' {
// TODO: remove this after 2020/02/01
eprintln('`v runrepl` has been deprecated. Please use `v repl` instead.')
compiler.launch_tool('vrepl', 'runrepl')
}
'doc' {
vexe := os.executable()
vdir := filepath.dir(os.executable())
os.chdir(vdir)
mod := args.last()
os.system('$vexe build module vlib$os.path_separator' + args.last())
vhfile := filepath.join(compiler.v_modules_path,'vlib','${mod}.vh')
txt := os.read_file(vhfile) or {
panic(err)
}
println(txt)
// v.gen_doc_html_for_module(args.last())
}
else {
eprintln('v $command: unknown command\nRun "v help" for usage.')
exit(1)
}
}
exit(0)
}

View File

@ -166,8 +166,8 @@ fn (v mut V) new_parser_from_file(path string) Parser {
}
}
if v.compile_defines.len > 0 {
for cdefine in v.compile_defines {
if v.pref.compile_defines.len > 0 {
for cdefine in v.pref.compile_defines {
custom_path_ending := '_d_${cdefine}.v'
if path.ends_with(custom_path_ending){
path_platform = custom_path_ending
@ -215,8 +215,8 @@ fn (v mut V) new_parser(scanner &Scanner) Parser {
cgen: v.cgen
//x64: v.x64
pref: v.pref
os: v.os
vroot: v.vroot
os: v.pref.os
vroot: v.pref.vroot
local_vars: [Var{
}].repeat(MaxLocalVars)
import_table: new_import_table()
@ -443,7 +443,7 @@ fn (p mut Parser) parse(pass Pass) {
//
p.fgen_nl()
p.cgen.nogen = false
if p.pref.build_mode == .build_module && p.mod != p.v.mod {
if p.pref.build_mode == .build_module && p.mod != p.v.pref.mod {
// println('skipping $p.mod (v.mod = $p.v.mod)')
p.cgen.nogen = true
// defer { p.cgen.nogen = false }
@ -453,7 +453,7 @@ fn (p mut Parser) parse(pass Pass) {
p.can_chash = p.mod in ['gg2', 'ui', 'uiold', 'darwin', 'clipboard', 'webview'] // TODO tmp remove
// Import pass - the first and the smallest pass that only analyzes imports
// if we are a building module get the full module name from v.mod
fq_mod := if p.pref.build_mode == .build_module && p.v.mod.ends_with(p.mod) { p.v.mod }
fq_mod := if p.pref.build_mode == .build_module && p.v.pref.mod.ends_with(p.mod) { p.v.pref.mod }
// fully qualify the module name, eg base64 to encoding.base64
else { p.table.qualify_module(p.mod, p.file_path) }
p.table.register_module(fq_mod)

View File

@ -5,9 +5,9 @@ module compiler
import (
os
os.cmdline
time
filepath
v.pref
)
fn todo() {
@ -34,8 +34,8 @@ fn (v mut V) cc() {
vdir := filepath.dir(vexe)
// Just create a C/JavaScript file and exit
// for example: `v -o v.c compiler`
ends_with_c := v.out_name.ends_with('.c')
ends_with_js := v.out_name.ends_with('.js')
ends_with_c := v.pref.out_name.ends_with('.c')
ends_with_js := v.pref.out_name.ends_with('.js')
if v.pref.is_pretty_c && !ends_with_js {
format_result := os.exec('clang-format -i -style=file "$v.out_name_c"') or {
@ -59,7 +59,7 @@ fn (v mut V) cc() {
println('V.js compiler not found, building...')
// Build V.js. Specifying `-os js` makes V include
// only _js.v files and ignore _c.v files.
ret := os.system('$vexe -o $vjs_path -os js $vdir/v.v')
ret := os.system('$vexe -o $vjs_path -os js $vdir/cmd/v')
if ret == 0 {
println('Done.')
}
@ -68,21 +68,21 @@ fn (v mut V) cc() {
exit(1)
}
}
ret := os.system('$vjs_path -o $v.out_name $v.dir')
ret := os.system('$vjs_path -o $v.pref.out_name $v.pref.path')
if ret == 0 {
println('Done. Run it with `node $v.out_name`')
println('Done. Run it with `node $v.pref.out_name`')
println('JS backend is at a very early stage.')
}
}
}
// v.out_name_c may be on a different partition than v.out_name
os.mv_by_cp(v.out_name_c, v.out_name)or{
os.mv_by_cp(v.out_name_c, v.pref.out_name)or{
panic(err)
}
exit(0)
}
// Cross compiling for Windows
if v.os == .windows {
if v.pref.os == .windows {
$if !windows {
v.cc_windows_cross()
return
@ -136,29 +136,29 @@ fn (v mut V) cc() {
if !v.pref.is_so
&& v.pref.build_mode != .build_module
&& os.user_os() == 'windows'
&& !v.out_name.ends_with('.exe')
&& !v.pref.out_name.ends_with('.exe')
{
v.out_name += '.exe'
v.pref.out_name += '.exe'
}
// linux_host := os.user_os() == 'linux'
v.log('cc() isprod=$v.pref.is_prod outname=$v.out_name')
v.log('cc() isprod=$v.pref.is_prod outname=$v.pref.out_name')
if v.pref.is_so {
a << '-shared -fPIC ' // -Wl,-z,defs'
v.out_name = v.out_name + '.so'
v.pref.out_name += '.so'
}
if v.pref.is_bare {
a << '-fno-stack-protector -static -ffreestanding -nostdlib'
}
if v.pref.build_mode == .build_module {
// Create the modules & out directory if it's not there.
mut out_dir := if v.dir.starts_with('vlib') { '$v_modules_path${os.path_separator}cache${os.path_separator}$v.dir' } else { '$v_modules_path${os.path_separator}$v.dir' }
mut out_dir := if v.pref.path.starts_with('vlib') { '$v_modules_path${os.path_separator}cache${os.path_separator}$v.pref.path' } else { '$v_modules_path${os.path_separator}$v.pref.path' }
pdir := out_dir.all_before_last(os.path_separator)
if !os.is_dir(pdir) {
os.mkdir_all(pdir)
}
v.out_name = '${out_dir}.o' // v.out_name
println('Building ${v.out_name}...')
v.pref.out_name = '${out_dir}.o' // v.out_name
println('Building ${v.pref.out_name}...')
}
debug_mode := v.pref.is_debug
mut debug_options := '-g'
@ -198,7 +198,7 @@ fn (v mut V) cc() {
if debug_mode && os.user_os() != 'windows' {
a << ' -rdynamic ' // needed for nicer symbolic backtraces
}
if v.pref.ccompiler != 'msvc' && v.os != .freebsd {
if v.pref.ccompiler != 'msvc' && v.pref.os != .freebsd {
a << '-Werror=implicit-function-declaration'
}
for f in v.generate_hotcode_reloading_compiler_flags() {
@ -269,24 +269,24 @@ fn (v mut V) cc() {
// Cross compiling windows
//
// Output executable name
a << '-o "$v.out_name"'
if os.is_dir(v.out_name) {
verror("\'$v.out_name\' is a directory")
a << '-o "$v.pref.out_name"'
if os.is_dir(v.pref.out_name) {
verror("\'$v.pref.out_name\' is a directory")
}
// macOS code can include objective C TODO remove once objective C is replaced with C
if v.os == .mac {
if v.pref.os == .mac {
a << '-x objective-c'
}
// The C file we are compiling
a << '"$v.out_name_c"'
if v.os == .mac {
if v.pref.os == .mac {
a << '-x none'
}
// Min macos version is mandatory I think?
if v.os == .mac {
if v.pref.os == .mac {
a << '-mmacosx-version-min=10.7'
}
if v.os == .windows {
if v.pref.os == .windows {
a << '-municode'
}
cflags := v.get_os_cflags()
@ -297,18 +297,18 @@ fn (v mut V) cc() {
a << libs
// Without these libs compilation will fail on Linux
// || os.user_os() == 'linux'
if !v.pref.is_bare && v.pref.build_mode != .build_module && v.os in [.linux, .freebsd, .openbsd, .netbsd, .dragonfly, .solaris, .haiku] {
if !v.pref.is_bare && v.pref.build_mode != .build_module && v.pref.os in [.linux, .freebsd, .openbsd, .netbsd, .dragonfly, .solaris, .haiku] {
a << '-lm -lpthread '
// -ldl is a Linux only thing. BSDs have it in libc.
if v.os == .linux {
if v.pref.os == .linux {
a << ' -ldl '
}
if v.os == .freebsd {
if v.pref.os == .freebsd {
// FreeBSD: backtrace needs execinfo library while linking
a << ' -lexecinfo '
}
}
if !v.pref.is_bare && v.os == .js && os.user_os() == 'linux' {
if !v.pref.is_bare && v.pref.os == .js && os.user_os() == 'linux' {
a << '-lm'
}
args := a.join(' ')
@ -351,6 +351,18 @@ start:
}
if v.pref.is_debug {
println(res.output)
verror("
==================
C error. This should never happen.
V compiler version: V $Version $vhash()
Host OS: ${pref.get_host_os().str()}
Target OS: $v.pref.os.str()
If you were not working with C interop and are not sure about what's happening,
please put the whole output in a pastebin and contact us through the following ways with a link to the pastebin:
- Raise an issue on GitHub: https://github.com/vlang/v/issues/new/choose
- Ask a question in #help on Discord: https://discord.gg/vlang")
}
else {
if res.output.len < 30 {
@ -359,11 +371,19 @@ start:
q := res.output.all_after('error: ').limit(150)
println('==================')
println(q)
println('...')
println('==================')
println('...\n(Use `v -cg` to print the entire error message)\n')
println('(Use `v -cg` to print the entire error message)\n')
}
verror("C error.
Please make sure that:
- You have all V dependencies installed.
- You did not declare a C function that was not included. (Try commenting your code that involves C interop)
- You are running the latest version of V. (Try running `v up` and rerunning your command)
If you're confident that all of the above is true, please try running V with the `-cg` option which enables more debugging capabilities.\n")
}
verror('C error. This should never happen. ' + '\nPlease create a GitHub issue: https://github.com/vlang/v/issues/new/choose')
}
diff := time.ticks() - ticks
// Print the C command
@ -402,16 +422,16 @@ start:
println('-compress does not work on Windows for now')
return
}
ret := os.system('strip $v.out_name')
ret := os.system('strip $v.pref.out_name')
if ret != 0 {
println('strip failed')
return
}
// NB: upx --lzma can sometimes fail with NotCompressibleException
// See https://github.com/vlang/v/pull/3528
mut ret2 := os.system('upx --lzma -qqq $v.out_name')
mut ret2 := os.system('upx --lzma -qqq $v.pref.out_name')
if ret2 != 0 {
ret2 = os.system('upx -qqq $v.out_name')
ret2 = os.system('upx -qqq $v.pref.out_name')
}
if ret2 != 0 {
println('upx failed')
@ -430,10 +450,10 @@ start:
fn (c mut V) cc_windows_cross() {
println('Cross compiling for Windows...')
if !c.out_name.ends_with('.exe') {
c.out_name = c.out_name + '.exe'
if !c.pref.out_name.ends_with('.exe') {
c.pref.out_name += '.exe'
}
mut args := '-o $c.out_name -w -L. '
mut args := '-o $c.pref.out_name -w -L. '
cflags := c.get_os_cflags()
// -I flags
args += if c.pref.ccompiler == 'msvc' { cflags.c_options_before_target_msvc() } else { cflags.c_options_before_target() }
@ -509,65 +529,12 @@ fn (c &V) build_thirdparty_obj_files() {
build_thirdparty_obj_file_with_msvc(flag.value, rest_of_module_flags)
}
else {
build_thirdparty_obj_file(flag.value, rest_of_module_flags)
c.build_thirdparty_obj_file(flag.value, rest_of_module_flags)
}
}
}
}
fn find_c_compiler() string {
args := env_vflags_and_os_args()
defaultcc := find_c_compiler_default()
return cmdline.option(args, '-cc', defaultcc)
}
fn find_c_compiler_default() string {
// fast_clang := '/usr/local/Cellar/llvm/8.0.0/bin/clang'
// if os.exists(fast_clang) {
// return fast_clang
// }
// TODO fix $if after 'string'
$if windows {
return 'gcc'
}
return 'cc'
}
fn find_c_compiler_thirdparty_options() string {
fullargs := env_vflags_and_os_args()
mut cflags := cmdline.many_values(fullargs,'-cflags')
$if !windows {
cflags << '-fPIC'
}
if '-m32' in fullargs {
cflags << '-m32'
}
return cflags.join(' ')
}
fn parse_defines(defines []string) ([]string,[]string) {
// '-d abc -d xyz=1 -d qwe=0' should produce:
// compile_defines: ['abc','xyz']
// compile_defines_all ['abc','xyz','qwe']
mut compile_defines := []string
mut compile_defines_all := []string
for dfn in defines {
dfn_parts := dfn.split('=')
if dfn_parts.len == 1 {
compile_defines << dfn
compile_defines_all << dfn
continue
}
if dfn_parts.len == 2 {
compile_defines_all << dfn_parts[0]
if dfn_parts[1] == '1' {
compile_defines << dfn_parts[0]
}
}
}
return compile_defines, compile_defines_all
}
fn missing_compiler_info() string {
$if windows {
return 'https://github.com/vlang/v/wiki/Installing-a-C-compiler-on-Windows'

View File

@ -20,12 +20,12 @@ pub fn (c &CFlag) str() string {
fn (v &V) get_os_cflags() []CFlag {
mut flags := []CFlag
mut ctimedefines := []string
if v.compile_defines.len > 0 {
ctimedefines << v.compile_defines
if v.pref.compile_defines.len > 0 {
ctimedefines << v.pref.compile_defines
}
for flag in v.table.cflags {
if flag.os == '' || (flag.os == 'linux' && v.os == .linux) || (flag.os == 'darwin' && v.os == .mac) || (flag.os == 'freebsd' && v.os == .freebsd) || (flag.os == 'windows' && v.os == .windows) {
if flag.os == '' || (flag.os == 'linux' && v.pref.os == .linux) || (flag.os == 'darwin' && v.pref.os == .mac) || (flag.os == 'freebsd' && v.pref.os == .freebsd) || (flag.os == 'windows' && v.pref.os == .windows) {
flags << flag
}
if flag.os in ctimedefines {

View File

@ -43,7 +43,7 @@ mut:
cut_pos int
}
fn new_cgen(out_name_c string) &CGen {
pub fn new_cgen(out_name_c string) &CGen {
path := out_name_c
out := os.create(path)or{
println('failed to create $path')
@ -272,7 +272,7 @@ fn (g mut CGen) add_to_main(s string) {
g.fn_main = g.fn_main + s
}
fn build_thirdparty_obj_file(path string, moduleflags []CFlag) {
fn (v &V) build_thirdparty_obj_file(path string, moduleflags []CFlag) {
obj_path := os.realpath(path)
if os.exists(obj_path) {
return
@ -288,11 +288,9 @@ fn build_thirdparty_obj_file(path string, moduleflags []CFlag) {
cfiles += '"' + os.realpath(parent + os.path_separator + file) + '" '
}
}
cc := find_c_compiler()
cc_thirdparty_options := find_c_compiler_thirdparty_options()
btarget := moduleflags.c_options_before_target()
atarget := moduleflags.c_options_after_target()
cmd := '$cc $cc_thirdparty_options $btarget -c -o "$obj_path" $cfiles $atarget '
cmd := '$v.pref.ccompiler $v.pref.third_party_option $btarget -c -o "$obj_path" $cfiles $atarget '
res := os.exec(cmd)or{
println('failed thirdparty object build cmd: $cmd')
verror(err)

View File

@ -112,7 +112,7 @@ fn (p mut Parser) comp_time() {
else if name == 'clang' {
p.comptime_if_block('__clang__', not)
}
else if p.v.compile_defines_all.len > 0 && name in p.v.compile_defines_all {
else if p.v.pref.compile_defines_all.len > 0 && name in p.v.pref.compile_defines_all {
// Support for *optional* custom compile defines, i.e.:
//
// `[if custom]` => custom should be defined
@ -249,7 +249,7 @@ fn (p mut Parser) chash() {
flag = flag.replace('@VLIB_PATH', p.pref.vlib_path)
flag = flag.replace('@VMOD', v_modules_path)
// p.log('adding flag "$flag"')
_ = p.table.parse_cflag(flag, p.mod, p.v.compile_defines_all ) or {
_ = p.table.parse_cflag(flag, p.mod, p.v.pref.compile_defines_all ) or {
p.error_with_token_index(err, p.cur_tok_index() - 1)
return
}

View File

@ -510,7 +510,7 @@ fn (p mut Parser) fn_decl() {
}
if p.first_pass() && p.attr == 'live' && !(is_live || is_solive) {
println('INFO: run `v -live $p.v.dir `, if you want to use [live] function $f.name .')
println('INFO: run `v -live $p.v.pref.path `, if you want to use [live] function $f.name .')
}
if p.is_vh || p.first_pass() || is_live || is_fn_header || skip_main_in_test {
@ -774,7 +774,7 @@ fn (p mut Parser) verify_fn_before_call(f &Fn) {
// p.tok == fn_name
fn (p mut Parser) fn_call(f mut Fn, method_ph int, receiver_var, receiver_type string) {
p.verify_fn_before_call(f)
is_comptime_define := f.comptime_define != '' && !(f.comptime_define in p.v.compile_defines )
is_comptime_define := f.comptime_define != '' && !(f.comptime_define in p.v.pref.compile_defines )
if is_comptime_define {
p.cgen.nogen = true
}

View File

@ -10,10 +10,10 @@ fn (v &V) generate_hotcode_reloading_compiler_flags() []string {
mut a := []string
if v.pref.is_live || v.pref.is_so {
// See 'man dlopen', and test running a GUI program compiled with -live
if (v.os == .linux || os.user_os() == 'linux') {
if (v.pref.os == .linux || os.user_os() == 'linux') {
a << '-rdynamic'
}
if (v.os == .mac || os.user_os() == 'mac') {
if (v.pref.os == .mac || os.user_os() == 'mac') {
a << '-flat_namespace'
}
}
@ -22,7 +22,7 @@ fn (v &V) generate_hotcode_reloading_compiler_flags() []string {
fn (v &V) generate_hotcode_reloading_declarations() {
mut cgen := v.cgen
if v.os != .windows {
if v.pref.os != .windows {
if v.pref.is_so {
cgen.genln('pthread_mutex_t live_fn_mutex;')
}
@ -55,8 +55,8 @@ fn (v &V) generate_hotcode_reloading_main_caller() {
// We are in live code reload mode, so start the .so loader in the background
mut cgen := v.cgen
cgen.genln('')
file_base := filepath.filename(v.dir).replace('.v', '')
if v.os != .windows {
file_base := filepath.filename(v.pref.path).replace('.v', '')
if v.pref.os != .windows {
// unix:
so_name := file_base + '.so'
cgen.genln(' char *live_library_name = "$so_name";')
@ -79,7 +79,7 @@ fn (v &V) generate_hot_reload_code() {
mut cgen := v.cgen
// Hot code reloading
if v.pref.is_live {
mut file := os.realpath(v.dir)
mut file := os.realpath(v.pref.path)
file_base := filepath.filename(file).replace('.v', '')
so_name := file_base + '.so'
// Need to build .so file before building the live application
@ -115,7 +115,7 @@ void lfnmutex_print(char *s){
}
}
')
if v.os != .windows {
if v.pref.os != .windows {
cgen.genln('
void* live_lib=0;
int load_so(byteptr path) {

View File

@ -5,7 +5,6 @@ module compiler
import (
os
os.cmdline
strings
filepath
v.pref
@ -35,21 +34,15 @@ enum Pass {
main
}
struct V {
pub struct V {
pub mut:
os pref.OS // the OS to build for
out_name_c string // name of the temporary C file
files []string // all V files that need to be parsed and compiled
dir string // directory (or file) being compiled (TODO rename to path?)
compiled_dir string // contains os.realpath() of the dir of the final file beeing compiled, or the dir itself when doing `v .`
table &Table // table with types, vars, functions etc
cgen &CGen // C code generator
//x64 &x64.Gen
pref &pref.Preferences // all the preferences and settings extracted to a struct for reusability
lang_dir string // "~/code/v"
out_name string // "program.exe"
vroot string
mod string // module being built with -lib
parsers []Parser // file parsers
vgen_buf strings.Builder // temporary buffer for generated V code (.str() etc)
file_parser_idx map[string]int // map absolute file path to v.parsers index
@ -57,15 +50,33 @@ pub mut:
cached_mods []string
module_lookup_paths []string
// -d vfmt and -d another=0 for `$if vfmt { will execute }` and `$if another { will NOT get here }`
compile_defines []string // just ['vfmt']
compile_defines_all []string // contains both: ['vfmt','another']
v_fmt_all bool // << input set by tools/vfmt.v
v_fmt_file string // << file given by the user from tools/vfmt.v
v_fmt_all bool // << input set by cmd/tools/vfmt.v
v_fmt_file string // << file given by the user from cmd/tools/vfmt.v
v_fmt_file_result string // >> file with formatted output generated by vlib/compiler/vfmt.v
}
pub fn new_v(pref &pref.Preferences) &V {
rdir := os.realpath(pref.path)
mut out_name_c := get_vtmp_filename(pref.out_name, '.tmp.c')
if pref.is_so {
out_name_c = get_vtmp_filename(pref.out_name, '.tmp.so.c')
}
mut vgen_buf := strings.new_builder(1000)
vgen_buf.writeln('module vgen\nimport strings')
return &V{
compiled_dir: if os.is_dir(rdir) { rdir } else { filepath.dir(rdir) }
table: new_table(pref.obfuscate)
out_name_c: out_name_c
cgen: new_cgen(out_name_c)
//x64: x64.new_gen(out_name)
pref: pref
vgen_buf: vgen_buf
}
}
// Should be called by main at the end of the compilation process, to cleanup
pub fn (v &V) finalize_compilation() {
// TODO remove
@ -166,7 +177,7 @@ pub fn (v mut V) compile() {
if v.pref.prealloc {
cgen.genln('#define VPREALLOC (1)')
}
if v.os == .js {
if v.pref.os == .js {
cgen.genln('#define _VJS (1) ')
}
v_hash := vhash()
@ -189,11 +200,11 @@ pub fn (v mut V) compile() {
cgen.genln('#include <stdint.h>')
}
if v.compile_defines_all.len > 0 {
if v.pref.compile_defines_all.len > 0 {
cgen.genln('')
cgen.genln('// All custom defines : ' + v.compile_defines_all.join(','))
cgen.genln('// Turned ON custom defines: ' + v.compile_defines.join(','))
for cdefine in v.compile_defines {
cgen.genln('// All custom defines : ' + v.pref.compile_defines_all.join(','))
cgen.genln('// Turned ON custom defines: ' + v.pref.compile_defines.join(','))
for cdefine in v.pref.compile_defines {
cgen.genln('#define CUSTOM_DEFINE_${cdefine}')
}
cgen.genln('//')
@ -234,7 +245,7 @@ pub fn (v mut V) compile() {
if '-debug_alloc' in os.args {
cgen.genln('#define DEBUG_ALLOC 1')
}
if v.pref.is_live && v.os != .windows {
if v.pref.is_live && v.pref.os != .windows {
cgen.includes << '#include <dlfcn.h>'
}
// cgen.genln('/*================================== FNS =================================*/')
@ -261,7 +272,7 @@ pub fn (v mut V) compile() {
vgen_parser.parse(.main)
// Generate .vh if we are building a module
if v.pref.build_mode == .build_module {
generate_vh(v.dir)
generate_vh(v.pref.path)
}
// All definitions
mut def := strings.new_builder(10000) // Avoid unnecessary allocations
@ -319,7 +330,7 @@ pub fn (v mut V) compile2() {
println(v.files)
}
mut b := v.new_v2()
b.build_c(v.files, v.out_name)
b.build_c(v.files, v.pref.out_name)
v.cc()
}
@ -329,18 +340,18 @@ pub fn (v mut V) compile_x64() {
println('You are not on a Linux system, so you will not ' + 'be able to run the resulting executable')
}
//v.files << v.v_files_from_dir(filepath.join(v.pref.vlib_path,'builtin','bare'))
v.files << v.dir
v.files << v.pref.path
v.set_module_lookup_paths()
mut b := v.new_v2()
// move all this logic to v2
b.build_x64(v.files, v.out_name)
b.build_x64(v.files, v.pref.out_name)
}
// make v2 from v1
fn (v &V) new_v2() builder.Builder {
mut b := builder.new_builder(v.pref)
b = { b|
os: v.os,
os: v.pref.os,
module_path: v_modules_path,
compiled_dir: v.compiled_dir,
module_search_paths: v.module_lookup_paths
@ -356,7 +367,7 @@ fn (v mut V) generate_init() {
nogen := v.cgen.nogen
v.cgen.nogen = false
consts_init_body := v.cgen.consts_init.join_lines()
init_fn_name := mod_gen_name(v.mod) + '__init_consts'
init_fn_name := mod_gen_name(v.pref.mod) + '__init_consts'
v.cgen.genln('void ${init_fn_name}();\nvoid ${init_fn_name}() {\n$consts_init_body\n}')
v.cgen.nogen = nogen
}
@ -482,7 +493,7 @@ pub fn (v mut V) generate_main() {
// Generate a C `main`, which calls every single test function
v.gen_main_start(false)
if v.pref.is_stats {
cgen.genln('BenchedTests bt = main__start_testing(${test_fn_names.len},tos3("$v.dir"));')
cgen.genln('BenchedTests bt = main__start_testing(${test_fn_names.len},tos3("$v.pref.path"));')
}
for tfname in test_fn_names {
if v.pref.is_stats {
@ -513,7 +524,7 @@ pub fn (v mut V) generate_main() {
}
pub fn (v mut V) gen_main_start(add_os_args bool) {
if v.os == .windows {
if v.pref.os == .windows {
if 'glfw' in v.table.imports {
// GUI application
v.cgen.genln('int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, LPWSTR cmd_line, int show_cmd) { ')
@ -531,7 +542,7 @@ pub fn (v mut V) gen_main_start(add_os_args bool) {
}
v.cgen.genln(' init();')
if add_os_args && 'os' in v.table.imports {
if v.os == .windows {
if v.pref.os == .windows {
v.cgen.genln(' os__args = os__init_os_args_wide(argc, argv);')
} else {
v.cgen.genln(' os__args = os__init_os_args(argc, (byteptr*)argv);')
@ -547,45 +558,12 @@ pub fn (v mut V) gen_main_end(return_statement string) {
v.cgen.genln('}')
}
pub fn final_target_out_name(out_name string) string {
$if windows {
return out_name.replace('/', '\\') + '.exe'
}
return if out_name.starts_with('/') { out_name } else { './' + out_name }
}
pub fn (v V) run_compiled_executable_and_exit() {
args := env_vflags_and_os_args()
if v.pref.is_verbose {
println('============ running $v.out_name ============')
}
mut cmd := '"' + final_target_out_name(v.out_name).replace('.exe', '') + '"'
args_after_no_options := cmdline.only_non_options( cmdline.after(args,['run','test']) )
if args_after_no_options.len > 1 {
cmd += ' ' + args_after_no_options[1..].join(' ')
}
if v.pref.is_test {
ret := os.system(cmd)
if ret != 0 {
exit(1)
}
}
if v.pref.is_run {
ret := os.system(cmd)
// TODO: make the runner wrapping as transparent as possible
// (i.e. use execve when implemented). For now though, the runner
// just returns the same exit code as the child process.
exit(ret)
}
exit(0)
}
pub fn (v &V) v_files_from_dir(dir string) []string {
mut res := []string
if !os.exists(dir) {
if dir == 'compiler' && os.is_dir('vlib') {
println('looks like you are trying to build V with an old command')
println('use `v -o v v.v` instead of `v -o v compiler`')
println('use `v -o v cmd/v` instead of `v -o v compiler`')
}
verror("$dir doesn't exist")
}
@ -606,27 +584,27 @@ pub fn (v &V) v_files_from_dir(dir string) []string {
if file.ends_with('_test.v') {
continue
}
if (file.ends_with('_win.v') || file.ends_with('_windows.v')) && v.os != .windows {
if (file.ends_with('_win.v') || file.ends_with('_windows.v')) && v.pref.os != .windows {
continue
}
if (file.ends_with('_lin.v') || file.ends_with('_linux.v')) && v.os != .linux {
if (file.ends_with('_lin.v') || file.ends_with('_linux.v')) && v.pref.os != .linux {
continue
}
if (file.ends_with('_mac.v') || file.ends_with('_darwin.v')) && v.os != .mac {
if (file.ends_with('_mac.v') || file.ends_with('_darwin.v')) && v.pref.os != .mac {
continue
}
if file.ends_with('_nix.v') && v.os == .windows {
if file.ends_with('_nix.v') && v.pref.os == .windows {
continue
}
if file.ends_with('_js.v') && v.os != .js {
if file.ends_with('_js.v') && v.pref.os != .js {
continue
}
if file.ends_with('_c.v') && v.os == .js {
if file.ends_with('_c.v') && v.pref.os == .js {
continue
}
if v.compile_defines_all.len > 0 && file.contains('_d_') {
if v.pref.compile_defines_all.len > 0 && file.contains('_d_') {
mut allowed := false
for cdefine in v.compile_defines {
for cdefine in v.pref.compile_defines {
file_postfix := '_d_${cdefine}.v'
if file.ends_with(file_postfix) {
allowed = true
@ -740,15 +718,15 @@ pub fn (v &V) get_builtin_files() []string {
// get user files
pub fn (v &V) get_user_files() []string {
mut dir := v.dir
mut dir := v.pref.path
v.log('get_v_files($dir)')
// Need to store user files separately, because they have to be added after
// libs, but we dont know which libs need to be added yet
mut user_files := []string
// See tools/preludes/README.md for more info about what preludes are
// See cmd/tools/preludes/README.md for more info about what preludes are
vroot := filepath.dir(vexe_path())
preludes_path := filepath.join(vroot,'tools','preludes')
preludes_path := filepath.join(vroot,'cmd','tools','preludes')
if v.pref.is_live {
user_files << filepath.join(preludes_path,'live_main.v')
}
@ -858,284 +836,6 @@ pub fn (v &V) log(s string) {
println(s)
}
pub fn new_v(args []string) &V {
// Create modules dirs if they are missing
if !os.is_dir(v_modules_path) {
os.mkdir(v_modules_path)or{
panic(err)
}
os.mkdir('$v_modules_path${os.path_separator}cache')or{
panic(err)
}
}
// optional, custom modules search path
user_mod_path := cmdline.option(args, '-user_mod_path', '')
// Location of all vlib files
vroot := filepath.dir(vexe_path())
vlib_path := cmdline.option(args, '-vlib-path', filepath.join(vroot,'vlib'))
vpath := cmdline.option(args, '-vpath', v_modules_path)
mut vgen_buf := strings.new_builder(1000)
vgen_buf.writeln('module vgen\nimport strings')
target_os := cmdline.option(args, '-os', '')
mut out_name := cmdline.option(args, '-o', 'a.out')
mut dir := args.last()
if 'run' in args {
args_after_run := cmdline.only_non_options( cmdline.after(args,['run']) )
dir = if args_after_run.len>0 { args_after_run[0] } else { '' }
}
if dir.ends_with(os.path_separator) {
dir = dir.all_before_last(os.path_separator)
}
if dir.starts_with('.$os.path_separator') {
dir = dir[2..]
}
if args.len < 2 {
dir = ''
}
// build mode
mut build_mode := pref.BuildMode.default_mode
mut mod := ''
joined_args := args.join(' ')
if joined_args.contains('build module ') {
build_mode = .build_module
os.chdir(vroot)
// v build module ~/v/os => os.o
mod_path := if dir.contains('vlib') { dir.all_after('vlib' + os.path_separator) } else if dir.starts_with('.\\') || dir.starts_with('./') { dir[2..] } else if dir.starts_with(os.path_separator) { dir.all_after(os.path_separator) } else { dir }
mod = mod_path.replace(os.path_separator, '.')
println('Building module "${mod}" (dir="$dir")...')
// out_name = '$TmpPath/vlib/${base}.o'
if !out_name.ends_with('.c') {
out_name = mod
}
// Cross compiling? Use separate dirs for each os
/*
if target_os != os.user_os() {
os.mkdir('$TmpPath/vlib/$target_os') or { panic(err) }
out_name = '$TmpPath/vlib/$target_os/${base}.o'
println('target_os=$target_os user_os=${os.user_os()}')
println('!Cross compiling $out_name')
}
*/
}
is_test := dir.ends_with('_test.v')
is_script := dir.ends_with('.v') || dir.ends_with('.vsh')
if is_script && !os.exists(dir) {
println('`$dir` does not exist')
exit(1)
}
// No -o provided? foo.v => foo
if out_name == 'a.out' && dir.ends_with('.v') && dir != '.v' {
out_name = dir[..dir.len - 2]
// Building V? Use v2, since we can't overwrite a running
// executable on Windows + the precompiled V is more
// optimized.
if out_name == 'v' && os.is_dir('vlib/compiler') {
println('Saving the resulting V executable in `./v2`')
println('Use `v -o v v.v` if you want to replace current ' + 'V executable.')
out_name = 'v2'
}
}
// if we are in `/foo` and run `v .`, the executable should be `foo`
if dir == '.' && out_name == 'a.out' {
base := os.getwd().all_after(os.path_separator)
out_name = base.trim_space()
}
// `v -o dir/exec`, create "dir/" if it doesn't exist
if out_name.contains(os.path_separator) {
d := out_name.all_before_last(os.path_separator)
if !os.is_dir(d) {
println('creating a new directory "$d"')
os.mkdir(d)or{
panic(err)
}
}
}
mut _os := pref.OS.mac
// No OS specifed? Use current system
if target_os == '' {
$if linux {
_os = .linux
}
$if macos {
_os = .mac
}
$if windows {
_os = .windows
}
$if freebsd {
_os = .freebsd
}
$if openbsd {
_os = .openbsd
}
$if netbsd {
_os = .netbsd
}
$if dragonfly {
_os = .dragonfly
}
$if solaris {
_os = .solaris
}
$if haiku {
_os = .haiku
}
}
else {
_os = os_from_string(target_os)
}
// println('VROOT=$vroot')
// v.exe's parent directory should contain vlib
if !os.is_dir(vlib_path) || !os.is_dir(vlib_path + os.path_separator + 'builtin') {
// println('vlib not found, downloading it...')
/*
ret := os.system('git clone --depth=1 https://github.com/vlang/v .')
if ret != 0 {
println('failed to `git clone` vlib')
println('make sure you are online and have git installed')
exit(1)
}
*/
println('vlib not found. It should be next to the V executable.')
println('Go to https://vlang.io to install V.')
println('(os.executable=${os.executable()} vlib_path=$vlib_path vexe_path=${vexe_path()}')
exit(1)
}
mut out_name_c := get_vtmp_filename(out_name, '.tmp.c')
cflags := cmdline.many_values(args, '-cflags').join(' ')
defines := cmdline.many_values(args, '-d')
compile_defines, compile_defines_all := parse_defines( defines )
rdir := os.realpath(dir)
rdir_name := filepath.filename(rdir)
if '-bare' in args {
verror('use -freestanding instead of -bare')
}
obfuscate := '-obf' in args
is_repl := '-repl' in args
pref := &pref.Preferences{
is_test: is_test
is_script: is_script
is_so: '-shared' in args
is_solive: '-solive' in args
is_prod: '-prod' in args
is_verbose: '-verbose' in args || '--verbose' in args
is_debug: '-g' in args || '-cg' in args
is_vlines: '-g' in args && !('-cg' in args)
is_keep_c: '-keep_c' in args
is_pretty_c: '-pretty_c' in args
is_cache: '-cache' in args
is_stats: '-stats' in args
obfuscate: obfuscate
is_prof: '-prof' in args
is_live: '-live' in args
sanitize: '-sanitize' in args
// nofmt: '-nofmt' in args
show_c_cmd: '-show_c_cmd' in args
translated: 'translated' in args
is_run: 'run' in args
autofree: '-autofree' in args
compress: '-compress' in args
enable_globals: '--enable-globals' in args
fast: '-fast' in args
is_bare: '-freestanding' in args
x64: '-x64' in args
output_cross_c: '-output-cross-platform-c' in args
prealloc: '-prealloc' in args
is_repl: is_repl
build_mode: build_mode
cflags: cflags
ccompiler: find_c_compiler()
building_v: !is_repl && (rdir_name == 'compiler' || rdir_name == 'v.v' || rdir_name == 'vfmt.v' || dir.contains('vlib'))
// is_fmt: comptime_define == 'vfmt'
user_mod_path: user_mod_path
vlib_path: vlib_path
vpath: vpath
v2: '-v2' in args
}
if pref.is_verbose || pref.is_debug {
println('C compiler=$pref.ccompiler')
}
if pref.is_so {
out_name_c = get_vtmp_filename(out_name, '.tmp.so.c')
}
$if !linux {
if pref.is_bare && !out_name.ends_with('.c') {
verror('-freestanding only works on Linux for now')
}
}
return &V{
os: _os
out_name: out_name
dir: dir
compiled_dir: if os.is_dir(rdir) { rdir } else { filepath.dir(rdir) }
lang_dir: vroot
table: new_table(obfuscate)
out_name_c: out_name_c
cgen: new_cgen(out_name_c)
//x64: x64.new_gen(out_name)
vroot: vroot
pref: pref
mod: mod
vgen_buf: vgen_buf
compile_defines: compile_defines
compile_defines_all: compile_defines_all
}
}
fn non_empty(a []string) []string {
return a.filter(it.len != 0)
}
pub fn env_vflags_and_os_args() []string {
vosargs := os.getenv('VOSARGS')
if '' != vosargs {
return non_empty(vosargs.split(' '))
}
mut args := []string
vflags := os.getenv('VFLAGS')
if '' != vflags {
args << os.args[0]
args << vflags.split(' ')
if os.args.len > 1 {
args << os.args[1..]
}
}
else {
args << os.args
}
return non_empty(args)
}
pub fn create_symlink() {
$if windows {
return
}
vexe := vexe_path()
mut link_path := '/usr/local/bin/v'
mut ret := os.exec('ln -sf $vexe $link_path') or { panic(err) }
if ret.exit_code == 0 {
println('Symlink "$link_path" has been created')
}
else if os.system('uname -o | grep -q \'[A/a]ndroid\'') == 0 {
println('Failed to create symlink "$link_path". Trying again with Termux path for Android.')
link_path = '/data/data/com.termux/files/usr/bin/v'
ret = os.exec('ln -sf $vexe $link_path') or { panic(err) }
if ret.exit_code == 0 {
println('Symlink "$link_path" has been created')
} else {
println('Failed to create symlink "$link_path". Try again with sudo.')
}
} else {
println('Failed to create symlink "$link_path". Try again with sudo.')
}
}
pub fn vexe_path() string {
vexe := os.getenv('VEXE')
if '' != vexe {
@ -1223,12 +923,3 @@ pub fn set_vroot_folder(vroot_path string) {
vname := if os.user_os() == 'windows' { 'v.exe' } else { 'v' }
os.setenv('VEXE', os.realpath([vroot_path, vname].join(os.path_separator)), true)
}
pub fn new_v_compiler_with_args(args []string) &V {
vexe := vexe_path()
mut allargs := [vexe]
allargs << args
os.setenv('VOSARGS', allargs.join(' '), true)
return new_v(allargs)
}

View File

@ -7,6 +7,7 @@ import (
strings
os
filepath
v.pref
)
/*
.vh generation logic.
@ -52,7 +53,11 @@ fn generate_vh(mod string) {
filtered := vfiles.filter(it.ends_with('.v') && !it.ends_with('test.v') && !it.ends_with('_windows.v') && !it.ends_with('_win.v') && !it.ends_with('_lin.v') && !it.contains('${os.path_separator}examples') && !it.contains('_js.v') && !it.contains('_bare.v') && !it.contains('${os.path_separator}js')) // TODO merge once filter allows it
// println('f:')
// println(filtered)
mut v := new_v(['foo.v'])
mut pref := &pref.Preferences {
path: 'foo.v'
}
pref.fill_with_defaults()
mut v := new_v(pref)
// v.pref.generating_vh = true
mut g := VhGen{
consts: strings.new_builder(1000)
@ -166,4 +171,3 @@ fn (g mut VhGen) generate_type() {
// g.i = old
// g.i--
}

View File

@ -3,11 +3,14 @@
// that can be found in the LICENSE file.
module compiler
import os
import filepath
import (
filepath
os
v.pref
)
pub const (
v_modules_path = os.home_dir() + '.vmodules'
v_modules_path = pref.default_module_path
)
// Holds import information scoped to the parsed file
struct ImportTable {

View File

@ -206,16 +206,16 @@ pub fn (v mut V) cc_msvc() {
a << '/MDd'
}
if v.pref.is_so {
if !v.out_name.ends_with('.dll') {
v.out_name = v.out_name + '.dll'
if !v.pref.out_name.ends_with('.dll') {
v.pref.out_name += '.dll'
}
// Build dll
a << '/LD'
}
else if !v.out_name.ends_with('.exe') {
v.out_name = v.out_name + '.exe'
else if !v.pref.out_name.ends_with('.exe') {
v.pref.out_name += '.exe'
}
v.out_name = os.realpath(v.out_name)
v.pref.out_name = os.realpath(v.pref.out_name)
// alibs := []string // builtin.o os.o http.o etc
if v.pref.build_mode == .build_module {
// Compile only
@ -263,7 +263,7 @@ pub fn (v mut V) cc_msvc() {
a << real_libs.join(' ')
a << '/link'
a << '/NOLOGO'
a << '/OUT:"$v.out_name"'
a << '/OUT:"$v.pref.out_name"'
a << '/LIBPATH:"$r.ucrt_lib_path"'
a << '/LIBPATH:"$r.um_lib_path"'
a << '/LIBPATH:"$r.vs_lib_path"'

View File

@ -6,7 +6,7 @@ module compiler
import os
import filepath
pub fn get_vtmp_folder() string {
fn get_vtmp_folder() string {
vtmp := filepath.join(os.tmpdir(),'v')
if !os.is_dir(vtmp) {
os.mkdir(vtmp)or{
@ -16,7 +16,7 @@ pub fn get_vtmp_folder() string {
return vtmp
}
pub fn get_vtmp_filename(base_file_name string, postfix string) string {
fn get_vtmp_filename(base_file_name string, postfix string) string {
vtmp := get_vtmp_folder()
return os.realpath(filepath.join(vtmp,filepath.filename(os.realpath(base_file_name)) + postfix))
}

View File

@ -11,7 +11,7 @@
// branch prediction hints. the C version will be
// removed once the perfomance is matched.
// you can test performance by running:
// `v run tools/bench/wyhash.v`
// `v run cmd/tools/bench/wyhash.v`
// try running with and without the `-prod` flag
module wyhash

View File

@ -102,7 +102,7 @@ pub fn (b &Builder) v_files_from_dir(dir string) []string {
if !os.exists(dir) {
if dir == 'compiler' && os.is_dir('vlib') {
println('looks like you are trying to build V with an old command')
println('use `v -o v v.v` instead of `v -o v compiler`')
println('use `v -o v cmd/v` instead of `v -o v compiler`')
}
verror("$dir doesn't exist")
}

View File

@ -0,0 +1,78 @@
// Copyright (c) 2019-2020 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 pref
import (
filepath
os
)
pub const (
default_module_path = os.home_dir() + '.vmodules'
)
pub fn (p mut Preferences) fill_with_defaults() {
if p.vroot == '' {
// Location of all vlib files
p.vroot = filepath.dir(vexe_path())
}
if p.vlib_path == '' {
p.vlib_path = filepath.join(p.vroot,'vlib')
}
if p.vpath == '' {
p.vpath = default_module_path
}
if p.out_name == ''{
rpath := os.realpath(p.path)
filename := filepath.filename(rpath).trim_space()
mut base := filename.all_before_last('.')
if base == '' {
// The file name is just `.v` or `.vsh` or `.*`
base = filename
}
target_dir := if os.is_dir(rpath) { rpath } else { filepath.dir(rpath) }
p.out_name = filepath.join(target_dir, base)
if rpath == '$p.vroot/cmd/v' && os.is_dir('vlib/compiler') {
// Building V? Use v2, since we can't overwrite a running
// executable on Windows + the precompiled V is more
// optimized.
println('Saving the resulting V executable in `./v2`')
println('Use `v -o v cmd/v` if you want to replace current ' + 'V executable.')
p.out_name = 'v2'
}
}
if p.os == ._auto {
// No OS specifed? Use current system
p.os = get_host_os()
}
if p.ccompiler == '' {
p.ccompiler = default_c_compiler()
}
p.is_test = p.path.ends_with('_test.v')
p.is_script = p.path.ends_with('.v') || p.path.ends_with('.vsh')
}
fn default_c_compiler() string {
// fast_clang := '/usr/local/Cellar/llvm/8.0.0/bin/clang'
// if os.exists(fast_clang) {
// return fast_clang
// }
// TODO fix $if after 'string'
$if windows {
return 'gcc'
}
return 'cc'
}
//TODO Remove code duplication
fn vexe_path() string {
vexe := os.getenv('VEXE')
if vexe != '' {
return vexe
}
real_vexe_path := os.realpath(os.executable())
os.setenv('VEXE', real_vexe_path, true)
return real_vexe_path
}

147
vlib/v/pref/os.v 100644
View File

@ -0,0 +1,147 @@
// Copyright (c) 2019-2020 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 pref
pub enum OS {
_auto // Reserved so .mac cannot be misunderstood as auto
mac
linux
windows
freebsd
openbsd
netbsd
dragonfly
js // TODO
android
solaris
haiku
}
// Helper function to convert string names to OS enum
pub fn os_from_string(os_str string) OS {
match os_str {
'linux' {
return .linux
}
'windows' {
return .windows
}
'mac' {
return .mac
}
'macos' {
return .mac
}
'freebsd' {
return .freebsd
}
'openbsd' {
return .openbsd
}
'netbsd' {
return .netbsd
}
'dragonfly' {
return .dragonfly
}
'js' {
return .js
}
'solaris' {
return .solaris
}
'android' {
return .android
}
'haiku' {
return .haiku
}
'linux_or_macos' {
return .linux
}
'' {
return ._auto
}
else {
panic('bad os $os_str')
}
}
}
pub fn (o OS) str() string {
match o {
._auto {
return 'RESERVED: AUTO'
}
.mac {
return 'MacOS'
}
.linux {
return 'Linux'
}
.windows {
return 'Windows'
}
.freebsd {
return 'FreeBSD'
}
.openbsd {
return 'OpenBSD'
}
.netbsd {
return 'NetBSD'
}
.dragonfly {
return 'Dragonfly'
}
.js {
return 'JavaScript'
}
.android {
return 'Android'
}
.solaris {
return 'Solaris'
}
.haiku {
return 'Haiku'
}
else {
//TODO Remove when V is smart enough to know that there's no other possibilities
//should never be reached as all enum types have been enumerated
panic('unknown OS enum type: $o')
}
}
}
pub fn get_host_os() OS {
$if linux {
return .linux
}
$if macos {
return .mac
}
$if windows {
return .windows
}
$if freebsd {
return .freebsd
}
$if openbsd {
return .openbsd
}
$if netbsd {
return .netbsd
}
$if dragonfly {
return .dragonfly
}
$if solaris {
return .solaris
}
$if haiku {
return .haiku
}
panic('unknown host OS')
}

View File

@ -12,22 +12,9 @@ pub enum BuildMode {
build_module
}
pub enum OS {
mac
linux
windows
freebsd
openbsd
netbsd
dragonfly
js // TODO
android
solaris
haiku
}
pub struct Preferences {
pub mut:
os OS // the OS to compile for
build_mode BuildMode
// nofmt bool // disable vfmt
is_test bool // `v test string_test.v`
@ -58,6 +45,7 @@ pub mut:
// You could pass several -cflags XXX arguments. They will be merged with each other.
// You can also quote several options at the same time: -cflags '-Os -fno-inline-small-functions'.
ccompiler string // the name of the used C compiler
third_party_option string
building_v bool
autofree bool
compress bool
@ -77,4 +65,13 @@ pub mut:
output_cross_c bool
prealloc bool
v2 bool
vroot string
out_name string
path string // Path to file/folder to compile
// -d vfmt and -d another=0 for `$if vfmt { will execute }` and `$if another { will NOT get here }`
compile_defines []string // just ['vfmt']
compile_defines_all []string // contains both: ['vfmt','another']
mod string
}