diff --git a/.github/workflows/alpine.build.sh b/.github/workflows/alpine.build.sh new file mode 100755 index 0000000000..56a9edb092 --- /dev/null +++ b/.github/workflows/alpine.build.sh @@ -0,0 +1,15 @@ +#!/bin/sh -l + +set -e + +pwd + +uname -a + +make + +./v --version + +du -s . + +echo "DONE" diff --git a/.github/workflows/alpine.test.sh b/.github/workflows/alpine.test.sh new file mode 100755 index 0000000000..32f611ac80 --- /dev/null +++ b/.github/workflows/alpine.test.sh @@ -0,0 +1,15 @@ +#!/bin/sh -l + +set -e + +pwd + +uname -a + +du -s . + +ls -lat + +./v test v + +echo "DONE" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 258961f736..0a039879ab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,6 +2,24 @@ name: CI on: [push, pull_request] jobs: + build-alpine-docker-musl-gcc: + name: Alpine/musl + runs-on: ubuntu-latest + steps: + + - name: Checkout + uses: actions/checkout@v1 + + - name: Build V + uses: spytheman/docker_alpine_v@v5.0 + with: + entrypoint: .github/workflows/alpine.build.sh + + - name: Test V + uses: spytheman/docker_alpine_v@v5.0 + with: + entrypoint: .github/workflows/alpine.test.sh + build-osx: runs-on: macOS-10.14 steps: @@ -123,3 +141,4 @@ jobs: ## v.js dosent work on windows #.\v.exe -o hi.js examples/hello_v_js.v #node hi.js + diff --git a/Dockerfile.alpine b/Dockerfile.alpine new file mode 100644 index 0000000000..3a78edffc5 --- /dev/null +++ b/Dockerfile.alpine @@ -0,0 +1,18 @@ +FROM alpine:3.10 + +LABEL maintainer="spytheman " + +WORKDIR /opt/vlang + +ENV VVV /opt/vlang +ENV PATH /opt/vlang:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + +RUN mkdir -p /opt/vlang && ln -s /opt/vlang/v /usr/bin/v + +RUN apk --no-cache add \ + git make upx gcc \ + musl-dev \ + openssl-dev sqlite-dev \ + libx11-dev glfw-dev freetype-dev + +RUN git clone https://github.com/vlang/v /opt/vlang && make && v --version diff --git a/README.md b/README.md index 03753ce47b..a25be69f64 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,15 @@ docker run --rm -it vlang:latest v ``` +### Docker with Alpine/musl: +```bash +git clone https://github.com/vlang/v +cd v +docker build -t vlang --file=Dockerfile.alpine . +docker run --rm -it vlang:latest +/usr/local/v/v +``` + ### Testing and running the examples Make sure V can compile itself: diff --git a/vlib/builtin/builtin.v b/vlib/builtin/builtin.v index 145ddf5c9f..8943fc2d8e 100644 --- a/vlib/builtin/builtin.v +++ b/vlib/builtin/builtin.v @@ -89,22 +89,13 @@ pub fn eprintln(s string) { if isnil(s.str) { panic('eprintln(NIL)') } - $if mac { + $if !windows { + C.fflush(stdout) + C.fflush(stderr) C.fprintf(stderr, '%.*s\n', s.len, s.str) C.fflush(stderr) return } - $if linux { - C.fprintf(stderr, '%.*s\n', s.len, s.str) - C.fflush(stderr) - return - } - $if freebsd { - C.fprintf(stderr, '%.*s\n', s.len, s.str) - C.fflush(stderr) - return - } - // TODO issues with stderr and cross compiling for Linux println(s) } diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index b15cb9954b..52acaf2658 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -124,6 +124,15 @@ pub fn (s string) cstr() byteptr { return clone.str } */ + +// cstring_to_vstring creates a copy of cstr and turns it into a v string +pub fn cstring_to_vstring(cstr byteptr) string { + slen := C.strlen(cstr) + mut s := byteptr( memdup(cstr, slen+1) ) + s[slen] = `\0` + return tos(s, slen) +} + pub fn (s string) replace_once(rep, with string) string { index := s.index(rep) if index != -1 { diff --git a/vlib/compiler/main.v b/vlib/compiler/main.v index be1ab2da73..a492d6339e 100644 --- a/vlib/compiler/main.v +++ b/vlib/compiler/main.v @@ -541,7 +541,6 @@ pub fn final_target_out_name(out_name string) string { 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 ============') } diff --git a/vlib/compiler/tests/repl/run.v b/vlib/compiler/tests/repl/run.v index 6578e359c5..18c3b14853 100644 --- a/vlib/compiler/tests/repl/run.v +++ b/vlib/compiler/tests/repl/run.v @@ -5,7 +5,8 @@ import log import benchmark fn main(){ - logger := &log.Log{log.DEBUG, 'terminal'} + mut logger := log.Log{} + logger.set_level(log.DEBUG) options := runner.new_options() mut bmark := benchmark.new_benchmark() diff --git a/vlib/compiler/tests/repl/runner/runner.v b/vlib/compiler/tests/repl/runner/runner.v index bb52ad6b23..2172b96122 100644 --- a/vlib/compiler/tests/repl/runner/runner.v +++ b/vlib/compiler/tests/repl/runner/runner.v @@ -10,6 +10,10 @@ pub: } pub fn full_path_to_v(dirs_in int) string { + vexe_from_env := os.getenv('VEXE') + if vexe_from_env.len > 0 { + return vexe_from_env + } vname := if os.user_os() == 'windows' { 'v.exe' } else { 'v' } mut path := os.executable() for i := 0; i < dirs_in; i++ { diff --git a/vlib/compiler/vtools.v b/vlib/compiler/vtools.v index 72429acbfe..fe8562dda2 100644 --- a/vlib/compiler/vtools.v +++ b/vlib/compiler/vtools.v @@ -13,7 +13,7 @@ pub fn launch_tool(tname string){ tool_args := oargs.join(' ') tool_command := '"$tool_exe" $tool_args' //println('Launching: "$tool_command" ...') - + mut tool_should_be_recompiled := false if !os.file_exists( tool_exe ) { // fresh checkout diff --git a/vlib/math/math_test.v b/vlib/math/math_test.v index e2393fd542..3f0cf1f2a7 100644 --- a/vlib/math/math_test.v +++ b/vlib/math/math_test.v @@ -46,7 +46,12 @@ fn test_erf() { fn test_gamma() { assert math.gamma(1) == 1 assert math.gamma(5) == 24 - assert math.log_gamma(4.5) == math.log(math.gamma(4.5)) + + sval := '2.453737' + assert math.log_gamma(4.5).str() == sval + assert math.log(math.gamma(4.5)).str() == sval + assert math.abs( math.log_gamma(4.5) - math.log(math.gamma(4.5)) ) < 0.000001 + // assert math.log_gamma(4.5) == math.log(math.gamma(4.5)) /* <-- fails on alpine/musl } fn test_mod() { diff --git a/vlib/os/os.v b/vlib/os/os.v index 397855d242..306c927c9c 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -64,7 +64,7 @@ mut: fn C.getline(voidptr, voidptr, voidptr) int fn C.ftell(fp voidptr) int -fn C.getenv(byteptr) byteptr +fn C.getenv(byteptr) &char fn C.sigaction(int, voidptr, int) @@ -76,15 +76,11 @@ pub fn (f File) read_bytes(size int) []byte { // read_bytes_at reads an amount of bytes at the given position in the file pub fn (f File) read_bytes_at(size, pos int) []byte { - mut data := malloc(size) - mut arr := [`0`].repeat(size) + mut arr := [`0`].repeat(size) C.fseek(f.cfile, pos, C.SEEK_SET) - C.fread(data, 1, size, f.cfile) + nreadbytes := C.fread(arr.data, 1, size, f.cfile) C.fseek(f.cfile, 0, C.SEEK_SET) - for e := 0; e < size; e++ { - arr[e] = data[e] - } - return arr + return arr.slice(0, nreadbytes) } pub fn read_bytes(path string) ?[]byte { @@ -96,16 +92,10 @@ pub fn read_bytes(path string) ?[]byte { fsize := C.ftell(fp) C.rewind(fp) println('fsize=$fsize') - mut data := malloc(fsize) - C.fread(data, fsize, 1, fp) - mut res := [`0`].repeat(fsize) - for i in 0..fsize { - res[i] = data[i] - } + mut res := [`0`].repeat(fsize) + nreadbytes := C.fread(res.data, fsize, 1, fp) C.fclose(fp) - //res := []byte(data, 10) // TODO can't `return []byte(data)` - //println('res0 = ' + res[0].str()) - return res + return res.slice(0, nreadbytes ) } // read_file reads the file in `path` and returns the contents. @@ -485,41 +475,37 @@ pub fn sigint_to_signal_name(si int) string { pub fn getenv(key string) string { $if windows { s := C._wgetenv(key.to_wide()) - if isnil(s) { + if s == 0 { return '' } return string_from_wide(s) } $else { - s := *byte(C.getenv(key.str)) - if isnil(s) { + s := C.getenv(key.str) + if s == 0 { return '' } - return string(s) + // NB: C.getenv *requires* that the result be copied. + return cstring_to_vstring( byteptr(s) ) } } pub fn setenv(name string, value string, overwrite bool) int { $if windows { format := '$name=$value' - if overwrite { return C._putenv(format.str) } - return -1 - } - $else { + } $else { return C.setenv(name.str, value.str, overwrite) } } pub fn unsetenv(name string) int { $if windows { - format := '${name}=' - + format := '${name}=' return C._putenv(format.str) - } - $else { + } $else { return C.unsetenv(name.str) } } @@ -759,31 +745,32 @@ fn C.readlink() int // process. pub fn executable() string { $if linux { - mut result := malloc(MAX_PATH) + mut result := calloc(MAX_PATH) count := C.readlink('/proc/self/exe', result, MAX_PATH) if count < 0 { - panic('error reading /proc/self/exe to get exe path') + eprintln('os.executable() failed at reading /proc/self/exe to get exe path') + return os.args[0] } - return string(result, count) + return string(result) } $if windows { max := 512 - mut result := &u16(malloc(max*2)) // MAX_PATH * sizeof(wchar_t) + mut result := &u16(calloc(max*2)) // MAX_PATH * sizeof(wchar_t) len := int(C.GetModuleFileName( 0, result, max )) return string_from_wide2(result, len) } $if mac { - mut result := malloc(MAX_PATH) + mut result := calloc(MAX_PATH) pid := C.getpid() ret := proc_pidpath (pid, result, MAX_PATH) if ret <= 0 { - println('os.executable() failed') - return '.' + eprintln('os.executable() failed at calling proc_pidpath with pid: $pid . proc_pidpath returned $ret ') + return os.args[0] } return string(result) } $if freebsd { - mut result := malloc(MAX_PATH) + mut result := calloc(MAX_PATH) mib := [1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1] size := MAX_PATH C.sysctl(mib.data, 4, result, &size, 0, 0) @@ -797,18 +784,20 @@ pub fn executable() string { $if solaris { } $if netbsd { - mut result := malloc(MAX_PATH) + mut result := calloc(MAX_PATH) count := int(C.readlink('/proc/curproc/exe', result, MAX_PATH )) if count < 0 { - panic('error reading /proc/curproc/exe to get exe path') + eprintln('os.executable() failed at reading /proc/curproc/exe to get exe path') + return os.args[0] } return string(result, count) } $if dragonfly { - mut result := malloc(MAX_PATH) + mut result := calloc(MAX_PATH) count := int(C.readlink('/proc/curproc/file', result, MAX_PATH )) if count < 0 { - panic('error reading /proc/curproc/file to get exe path') + eprintln('os.executable() failed at reading /proc/curproc/file to get exe path') + return os.args[0] } return string(result, count) } @@ -869,22 +858,20 @@ pub fn getwd() string { // and https://insanecoding.blogspot.com/2007/11/implementing-realpath-in-c.html // NB: this particular rabbit hole is *deep* ... pub fn realpath(fpath string) string { - mut fullpath := calloc( MAX_PATH ) - mut res := 0 + mut fullpath := calloc(MAX_PATH) + mut ret := *char(0) $if windows { - ret := C._fullpath(fullpath, fpath.str, MAX_PATH) + ret = C._fullpath(fullpath, fpath.str, MAX_PATH) if ret == 0 { return fpath } - return string(fullpath) - } - $else{ - ret := C.realpath(fpath.str, fullpath) + } $else { + ret = C.realpath(fpath.str, fullpath) if ret == 0 { return fpath } - return string(fullpath) } + return string(fullpath) } // walk_ext returns a recursive list of all file paths ending with `ext`.