diff --git a/doc/docs.md b/doc/docs.md index c9c0e2ab20..de5cefd3b7 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -1286,6 +1286,7 @@ Module { } ``` + * Add these lines to the top of your module: ```v #flag -I @VROOT/c @@ -1293,6 +1294,9 @@ Module { #include "header.h" ``` NB: @VROOT will be replaced by V with the *nearest parent folder, where there is a v.mod file*. +Any .v file beside or below the folder where the v.mod file is, can use #flag @VROOT/abc to refer to this folder. +The @VROOT folder is also *prepended* to the module lookup path, so you can *import* other +modules under your @VROOT, by just naming them. The instructions above will make V look for an compiled .o file in your module folder/c/implementation.o . If V finds it, the .o file will get linked to the main executable, that used the module. diff --git a/vlib/compiler/comptime.v b/vlib/compiler/comptime.v index 055200beac..8a2888c7f0 100644 --- a/vlib/compiler/comptime.v +++ b/vlib/compiler/comptime.v @@ -254,6 +254,11 @@ fn (p mut Parser) chash() { } flag = flag.replace('@VROOT', vmod_file_location.vmod_folder ) } + for deprecated in ['@VMOD', '@VMODULE', '@VPATH', '@VLIB_PATH'] { + if flag.contains(deprecated) { + p.error('${deprecated} had been deprecated, use @VROOT instead.') + } + } // p.log('adding flag "$flag"') _ = 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) diff --git a/vlib/compiler/modules.v b/vlib/compiler/modules.v index 7d59c14da5..2dadf6d6aa 100644 --- a/vlib/compiler/modules.v +++ b/vlib/compiler/modules.v @@ -182,9 +182,18 @@ fn (v mut V) set_module_lookup_paths() { } } -fn (p &Parser) find_module_path(mod string) ?string { +fn (p mut Parser) find_module_path(mod string) ?string { + vmod_file_location := p.v.mod_file_cacher.get( p.file_path_dir ) + mut module_lookup_paths := []string + if vmod_file_location.vmod_file.len != 0 { + if ! vmod_file_location.vmod_folder in p.v.module_lookup_paths { + module_lookup_paths << vmod_file_location.vmod_folder + } + } + module_lookup_paths << p.v.module_lookup_paths + mod_path := p.v.module_path(mod) - for lookup_path in p.v.module_lookup_paths { + for lookup_path in module_lookup_paths { try_path := filepath.join(lookup_path,mod_path) if p.v.pref.is_verbose { println(' >> trying to find $mod in $try_path ...') @@ -196,7 +205,7 @@ fn (p &Parser) find_module_path(mod string) ?string { return try_path } } - return error('module "$mod" not found in ${p.v.module_lookup_paths}') + return error('module "$mod" not found in ${module_lookup_paths}') } [inline] diff --git a/vlib/compiler/tests/project_with_modules_having_submodules/.gitignore b/vlib/compiler/tests/project_with_modules_having_submodules/.gitignore new file mode 100644 index 0000000000..93150b0578 --- /dev/null +++ b/vlib/compiler/tests/project_with_modules_having_submodules/.gitignore @@ -0,0 +1,2 @@ +/bin/main +/tests/submodule_test diff --git a/vlib/compiler/tests/project_with_modules_having_submodules/README.md b/vlib/compiler/tests/project_with_modules_having_submodules/README.md new file mode 100644 index 0000000000..306d2be23e --- /dev/null +++ b/vlib/compiler/tests/project_with_modules_having_submodules/README.md @@ -0,0 +1,16 @@ + +This projects demonstrates how v.mod lookup can be used so that +a project/module can be as selfcontained as possible. + +The programs under bin/ can find the modules mod1, +because the project has a 'v.mod' file, so v module lookup for +the programs under bin/ can still find the parent sibling folder +mod1/ through relation to the parent 'v.mod' file. + +Note also that mod1/ also has its own 'v.mod' file. +This allows mod1 submodules to find and import themselves +in relation to it too. + +Finally, there is a test/ folder, so you can put all your tests +in there, without cluttering your top level folder, or your module +folders if you so desire. diff --git a/vlib/compiler/tests/project_with_modules_having_submodules/bin/a_program_under_bin_can_find_mod1_test.v b/vlib/compiler/tests/project_with_modules_having_submodules/bin/a_program_under_bin_can_find_mod1_test.v new file mode 100644 index 0000000000..98a720d940 --- /dev/null +++ b/vlib/compiler/tests/project_with_modules_having_submodules/bin/a_program_under_bin_can_find_mod1_test.v @@ -0,0 +1,12 @@ +import mod1.submodule as m + +fn test_mod1_can_still_be_found_through_parent_project_vmod(){ + assert 1051 == m.f() +} + +/* +NB: this main program is under bin/ , but it still +can find mod1, because the parent project has v.mod, +so v module lookup for this program will find mod1 through +relation to the parent v.mod file +*/ diff --git a/vlib/compiler/tests/project_with_modules_having_submodules/bin/main.vsh b/vlib/compiler/tests/project_with_modules_having_submodules/bin/main.vsh new file mode 100755 index 0000000000..6470923aa2 --- /dev/null +++ b/vlib/compiler/tests/project_with_modules_having_submodules/bin/main.vsh @@ -0,0 +1,14 @@ +#!/usr/local/bin/v run +import mod1.submodule as m + +println('This script is located inside: ' + resource_abs_path('')) + +println('The result of calling m.f is: ' + m.f().str() ) + + +/* +NB: this main program v script is under bin/ , +but it *still* can find mod1, because the parent project has v.mod, +so v module lookup for this bin/main.vsh file will find mod1 through +relation to the parent ../v.mod file +*/ diff --git a/vlib/compiler/tests/project_with_modules_having_submodules/mod1/m.v b/vlib/compiler/tests/project_with_modules_having_submodules/mod1/m.v new file mode 100644 index 0000000000..18e701e5d3 --- /dev/null +++ b/vlib/compiler/tests/project_with_modules_having_submodules/mod1/m.v @@ -0,0 +1,5 @@ +module mod1 + +pub fn f() int { + return 1 +} diff --git a/vlib/compiler/tests/project_with_modules_having_submodules/mod1/mod11/m.v b/vlib/compiler/tests/project_with_modules_having_submodules/mod1/mod11/m.v new file mode 100644 index 0000000000..8ec5084ab3 --- /dev/null +++ b/vlib/compiler/tests/project_with_modules_having_submodules/mod1/mod11/m.v @@ -0,0 +1,5 @@ +module mod11 + +pub fn f() int { + return 11 +} diff --git a/vlib/compiler/tests/project_with_modules_having_submodules/mod1/mod12/m.v b/vlib/compiler/tests/project_with_modules_having_submodules/mod1/mod12/m.v new file mode 100644 index 0000000000..f6a683ab1f --- /dev/null +++ b/vlib/compiler/tests/project_with_modules_having_submodules/mod1/mod12/m.v @@ -0,0 +1,5 @@ +module mod12 + +pub fn f() int { + return 12 +} diff --git a/vlib/compiler/tests/project_with_modules_having_submodules/mod1/mod13/m.v b/vlib/compiler/tests/project_with_modules_having_submodules/mod1/mod13/m.v new file mode 100644 index 0000000000..ad04ce0c3e --- /dev/null +++ b/vlib/compiler/tests/project_with_modules_having_submodules/mod1/mod13/m.v @@ -0,0 +1,5 @@ +module mod13 + +pub fn f() int { + return 13 +} diff --git a/vlib/compiler/tests/project_with_modules_having_submodules/mod1/mod14/m.v b/vlib/compiler/tests/project_with_modules_having_submodules/mod1/mod14/m.v new file mode 100644 index 0000000000..25e7768240 --- /dev/null +++ b/vlib/compiler/tests/project_with_modules_having_submodules/mod1/mod14/m.v @@ -0,0 +1,7 @@ +module mod14 + +import math + +pub fn f() int { + return 14 + int(math.cos(0)) +} diff --git a/vlib/compiler/tests/project_with_modules_having_submodules/mod1/submodule/m.v b/vlib/compiler/tests/project_with_modules_having_submodules/mod1/submodule/m.v new file mode 100644 index 0000000000..2afa4b95d8 --- /dev/null +++ b/vlib/compiler/tests/project_with_modules_having_submodules/mod1/submodule/m.v @@ -0,0 +1,16 @@ +module submodule + +/* +This submodule just imports its sibling submodules. +Note that they are NOT under 'submodule' itself, +but are in its parent mod1 , and mod1 has a 'v.mod' file. +*/ + +import mod11 +import mod12 +import mod13 +import mod14 + +pub fn f() int { + return 1000 + mod11.f() + mod12.f() + mod13.f() + mod14.f() +} diff --git a/vlib/compiler/tests/project_with_modules_having_submodules/mod1/v.mod b/vlib/compiler/tests/project_with_modules_having_submodules/mod1/v.mod new file mode 100644 index 0000000000..cd35a03796 --- /dev/null +++ b/vlib/compiler/tests/project_with_modules_having_submodules/mod1/v.mod @@ -0,0 +1,7 @@ +#V Module# + +Module { + name: 'mod1', + description: 'A module with several submodules.', + dependencies: [] +} diff --git a/vlib/compiler/tests/project_with_modules_having_submodules/tests/submodule_test.v b/vlib/compiler/tests/project_with_modules_having_submodules/tests/submodule_test.v new file mode 100644 index 0000000000..9d914e3790 --- /dev/null +++ b/vlib/compiler/tests/project_with_modules_having_submodules/tests/submodule_test.v @@ -0,0 +1,11 @@ +import mod1 + +import mod1.submodule + +fn test_mod1(){ + assert 1 == mod1.f() +} + +fn test_mod1_submodule_can_find_and_use_all_its_sibling_submodules(){ + assert 1051 == submodule.f() +} diff --git a/vlib/compiler/tests/project_with_modules_having_submodules/v.mod b/vlib/compiler/tests/project_with_modules_having_submodules/v.mod new file mode 100644 index 0000000000..941d275c67 --- /dev/null +++ b/vlib/compiler/tests/project_with_modules_having_submodules/v.mod @@ -0,0 +1,7 @@ +#V Project# + +Module { + name: 'project_with_modules_having_submodules', + description: 'This project was created with `v create` to prevent regressions with the way V module import lookup works.', + dependencies: [] +} diff --git a/vlib/compiler/v_mod_cache.v b/vlib/compiler/v_mod_cache.v index b066294b82..f30e63a871 100644 --- a/vlib/compiler/v_mod_cache.v +++ b/vlib/compiler/v_mod_cache.v @@ -79,9 +79,6 @@ fn (mcache mut ModFileCacher) traverse(mfolder string) ([]string, ModFileAndFold mut folders_so_far := [cfolder] mut levels := 0 for { - $if debug { - eprintln('pdir2vmod mfolder: ${mfolder:-32s} | cfolder: ${cfolder:-20s} | levels: $levels') - } if levels > 255 { break } @@ -102,10 +99,6 @@ fn (mcache mut ModFileCacher) traverse(mfolder string) ([]string, ModFileAndFold // TODO: actually read the v.mod file and parse its contents to see // if its source folder is different res := ModFileAndFolder{ vmod_file: filepath.join( cfolder, 'v.mod'), vmod_folder: cfolder } - $if debug { - eprintln('FOUND v.mod:') - eprintln(' ModFileAndFolder{ vmod_file: $res.vmod_file , vmod_folder: $res.vmod_folder } ') - } return folders_so_far, res } if mcache.check_for_stop( cfolder, files ) {