compiler: import modules relative to v.mod

pull/3907/head
Delyan Angelov 2020-03-01 16:49:39 +02:00 committed by GitHub
parent 615a4b3452
commit 1066ec5cd9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 133 additions and 10 deletions

View File

@ -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.

View File

@ -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)

View File

@ -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]

View File

@ -0,0 +1,2 @@
/bin/main
/tests/submodule_test

View File

@ -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.

View File

@ -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
*/

View File

@ -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
*/

View File

@ -0,0 +1,5 @@
module mod1
pub fn f() int {
return 1
}

View File

@ -0,0 +1,5 @@
module mod11
pub fn f() int {
return 11
}

View File

@ -0,0 +1,5 @@
module mod12
pub fn f() int {
return 12
}

View File

@ -0,0 +1,5 @@
module mod13
pub fn f() int {
return 13
}

View File

@ -0,0 +1,7 @@
module mod14
import math
pub fn f() int {
return 14 + int(math.cos(0))
}

View File

@ -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()
}

View File

@ -0,0 +1,7 @@
#V Module#
Module {
name: 'mod1',
description: 'A module with several submodules.',
dependencies: []
}

View File

@ -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()
}

View File

@ -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: []
}

View File

@ -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 ) {