From 1d66076e1942374fdcda62493e70b2715b69df06 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 5 May 2016 14:56:21 -0400 Subject: [PATCH] implement `@static` macro for replacing osutils macros implements #5892 closes #6674 and #4233 --- base/LineEdit.jl | 6 +- base/REPLCompletions.jl | 4 +- base/Terminals.jl | 21 +-- base/c.jl | 10 +- base/client.jl | 19 ++- base/dSFMT.jl | 4 +- base/datafmt.jl | 2 +- base/deprecated.jl | 53 ++++++- base/docs/helpdb/Base.jl | 58 ------- base/env.jl | 83 +++++----- base/event.jl | 7 +- base/exports.jl | 14 +- base/file.jl | 145 ++++++++++-------- base/filesystem.jl | 4 +- base/initdefs.jl | 10 +- base/interactiveutil.jl | 81 +++++----- base/libc.jl | 60 +++++--- base/libdl.jl | 22 +-- base/libgit2/repository.jl | 2 +- base/managers.jl | 2 +- base/mmap.jl | 53 ++++--- base/multi.jl | 2 +- base/osutils.jl | 124 +++++++++------ base/path.jl | 91 ++++++----- base/pkg/cache.jl | 14 +- base/pkg/reqs.jl | 18 ++- base/poll.jl | 52 ++++--- base/process.jl | 2 +- base/profile.jl | 10 +- base/random.jl | 24 ++- base/sharedarray.jl | 37 ++--- base/socket.jl | 2 +- base/stream.jl | 58 ++++--- base/util.jl | 4 +- .../handling-operating-system-variation.rst | 34 ++-- doc/stdlib/base.rst | 36 ++--- doc/stdlib/constants.rst | 2 +- test/cmdlineargs.jl | 31 ++-- test/core.jl | 2 +- test/dates/conversions.jl | 6 +- test/examples.jl | 2 +- test/file.jl | 113 ++++++++------ test/libdl.jl | 2 +- test/misc.jl | 20 ++- test/parallel_exec.jl | 11 +- test/path.jl | 18 ++- test/perf/micro/perf.jl | 6 +- test/perf/perfutil.jl | 1 + test/pollfd.jl | 32 ++-- test/read.jl | 11 +- test/repl.jl | 10 +- test/replcompletions.jl | 8 +- test/runtests.jl | 2 +- test/socket.jl | 6 +- test/spawn.jl | 31 ++-- test/strings/basic.jl | 4 +- test/strings/io.jl | 4 +- 57 files changed, 824 insertions(+), 666 deletions(-) diff --git a/base/LineEdit.jl b/base/LineEdit.jl index 4106d354da24a..5e270761dbe2b 100644 --- a/base/LineEdit.jl +++ b/base/LineEdit.jl @@ -204,7 +204,7 @@ function refresh_multi_line(termbuf::TerminalBuffer, terminal::UnixTerminal, buf write_prompt(termbuf, prompt) prompt = prompt_string(prompt) # Count the '\n' at the end of the line if the terminal emulator does (specific to DOS cmd prompt) - miscountnl = @windows ? (isa(Terminals.pipe_reader(terminal), Base.TTY) && !Base.ispty(Terminals.pipe_reader(terminal))) : false + miscountnl = @static is_windows() ? (isa(Terminals.pipe_reader(terminal), Base.TTY) && !Base.ispty(Terminals.pipe_reader(terminal))) : false lindent = strwidth(prompt) # Now go through the buffer line by line @@ -1564,7 +1564,7 @@ function run_interface(terminal, m::ModalInterface) p = s.current_mode buf, ok, suspend = prompt!(terminal, m, s) while suspend - @unix_only ccall(:jl_repl_raise_sigtstp, Cint, ()) + @static if is_unix(); ccall(:jl_repl_raise_sigtstp, Cint, ()); end buf, ok, suspend = prompt!(terminal, m, s) end mode(state(s, s.current_mode)).on_done(s, buf, ok) @@ -1604,7 +1604,7 @@ function prompt!(term, prompt, s = init_state(term, prompt)) elseif state == :done return buffer(s), true, false elseif state == :suspend - @unix_only begin + if is_unix() return buffer(s), true, true end else diff --git a/base/REPLCompletions.jl b/base/REPLCompletions.jl index 4709cb07ffd4b..5890daa5483da 100644 --- a/base/REPLCompletions.jl +++ b/base/REPLCompletions.jl @@ -128,13 +128,13 @@ function complete_path(path::AbstractString, pos; use_envpath=false) if startswith(file, prefix) id = try isdir(joinpath(dir, file)) catch; false end # joinpath is not used because windows needs to complete with double-backslash - push!(matches, id ? file * (@windows? "\\\\" : "/") : file) + push!(matches, id ? file * (@static is_windows() ? "\\\\" : "/") : file) end end if use_envpath && length(dir) == 0 # Look for files in PATH as well - local pathdirs = split(ENV["PATH"], @unix? ":" : ";") + local pathdirs = split(ENV["PATH"], @static is_windows() ? ";" : ":") for pathdir in pathdirs local actualpath diff --git a/base/Terminals.jl b/base/Terminals.jl index 5e1483a5f5c1b..0a4bc09325f5c 100644 --- a/base/Terminals.jl +++ b/base/Terminals.jl @@ -116,7 +116,7 @@ cmove_line_up(t::UnixTerminal, n) = (cmove_up(t, n); cmove_col(t, 0)) cmove_line_down(t::UnixTerminal, n) = (cmove_down(t, n); cmove_col(t, 0)) cmove_col(t::UnixTerminal, n) = write(t.out_stream, "$(CSI)$(n)G") -@windows ? begin +if is_windows() function raw!(t::TTYTerminal,raw::Bool) check_open(t.in_stream) if Base.ispty(t.in_stream) @@ -132,7 +132,7 @@ cmove_col(t::UnixTerminal, n) = write(t.out_stream, "$(CSI)$(n)G") t.in_stream.handle, raw) != -1 end end -end : begin +else function raw!(t::TTYTerminal, raw::Bool) check_open(t.in_stream) ccall(:jl_tty_set_mode, Int32, (Ptr{Void},Int32), t.in_stream.handle, raw) != -1 @@ -151,14 +151,17 @@ clear(t::UnixTerminal) = write(t.out_stream, "\x1b[H\x1b[2J") clear_line(t::UnixTerminal) = write(t.out_stream, "\x1b[0G\x1b[0K") #beep(t::UnixTerminal) = write(t.err_stream,"\x7") -@unix_only function hascolor(t::TTYTerminal) - startswith(t.term_type, "xterm") && return true - try - return success(`tput setaf 0`) - catch - return false +if is_windows() + hascolor(t::TTYTerminal) = true +else + function hascolor(t::TTYTerminal) + startswith(t.term_type, "xterm") && return true + try + return success(`tput setaf 0`) + catch + return false + end end end -@windows_only hascolor(t::TTYTerminal) = true end # module diff --git a/base/c.jl b/base/c.jl index 00181e9c20b2b..09e77b6689722 100644 --- a/base/c.jl +++ b/base/c.jl @@ -95,10 +95,12 @@ convert(::Type{Cstring}, s::Symbol) = Cstring(unsafe_convert(Ptr{Cchar}, s)) # in string.jl: unsafe_convert(::Type{Cwstring}, s::WString) # FIXME: this should be handled by implicit conversion to Cwstring, but good luck with that -@windows_only function cwstring(s::AbstractString) - bytes = bytestring(s).data - 0 in bytes && throw(ArgumentError("embedded NULs are not allowed in C strings: $(repr(s))")) - return push!(utf8to16(bytes), 0) +if is_windows() + function cwstring(s::AbstractString) + bytes = bytestring(s).data + 0 in bytes && throw(ArgumentError("embedded NULs are not allowed in C strings: $(repr(s))")) + return push!(utf8to16(bytes), 0) + end end # conversions between UTF-8 and UTF-16 for Windows APIs diff --git a/base/client.jl b/base/client.jl index 31c8aa88ee423..969d00045ce4d 100644 --- a/base/client.jl +++ b/base/client.jl @@ -37,10 +37,13 @@ text_colors have_color = false default_color_warn = :red default_color_info = :blue -@unix_only default_color_input = :bold -@unix_only default_color_answer = :bold -@windows_only default_color_input = :normal -@windows_only default_color_answer = :normal +if is_windows() + default_color_input = :normal + default_color_answer = :normal +else + default_color_input = :bold + default_color_answer = :bold +end color_normal = text_colors[:normal] function repl_color(key, default) @@ -77,7 +80,7 @@ function repl_cmd(cmd, out) end cd(ENV["OLDPWD"]) else - cd(@windows? dir : readchomp(`$shell -c "echo $(shell_escape(dir))"`)) + cd(@static is_windows() ? dir : readchomp(`$shell -c "echo $(shell_escape(dir))"`)) end else cd() @@ -85,7 +88,7 @@ function repl_cmd(cmd, out) ENV["OLDPWD"] = new_oldpwd println(out, pwd()) else - run(ignorestatus(@windows? cmd : (isa(STDIN, TTY) ? `$shell -i -c "($(shell_escape(cmd))) && true"` : `$shell -c "($(shell_escape(cmd))) && true"`))) + run(ignorestatus(@static is_windows() ? cmd : (isa(STDIN, TTY) ? `$shell -i -c "($(shell_escape(cmd))) && true"` : `$shell -c "($(shell_escape(cmd))) && true"`))) end nothing end @@ -323,10 +326,10 @@ function _start() global active_repl_backend if repl if !isa(STDIN,TTY) - global is_interactive |= !isa(STDIN,Union{File,IOStream}) + global is_interactive |= !isa(STDIN, Union{File, IOStream}) color_set || (global have_color = false) else - term = Terminals.TTYTerminal(get(ENV,"TERM",@windows? "" : "dumb"),STDIN,STDOUT,STDERR) + term = Terminals.TTYTerminal(get(ENV, "TERM", @static is_windows() ? "" : "dumb"), STDIN, STDOUT, STDERR) global is_interactive = true color_set || (global have_color = Terminals.hascolor(term)) quiet || REPL.banner(term,term) diff --git a/base/dSFMT.jl b/base/dSFMT.jl index 2b4def10bbdc3..3430561c779f0 100644 --- a/base/dSFMT.jl +++ b/base/dSFMT.jl @@ -151,9 +151,9 @@ end ## Windows entropy -@windows_only begin +if is_windows() function win32_SystemFunction036!{T}(a::Array{T}) - ccall((:SystemFunction036,:Advapi32),stdcall,UInt8,(Ptr{Void},UInt32),a,sizeof(a)) + ccall((:SystemFunction036, :Advapi32), stdcall, UInt8, (Ptr{Void}, UInt32), a, sizeof(a)) end end diff --git a/base/datafmt.jl b/base/datafmt.jl index f9b3cb1e9ce72..ba03431325736 100644 --- a/base/datafmt.jl +++ b/base/datafmt.jl @@ -42,7 +42,7 @@ readdlm(input, dlm::Char, T::Type, eol::Char; opts...) = function readdlm_auto(input, dlm::Char, T::Type, eol::Char, auto::Bool; opts...) optsd = val_opts(opts) - use_mmap = get(optsd, :use_mmap, @windows ? false : true) + use_mmap = get(optsd, :use_mmap, is_windows() ? false : true) if isa(input, AbstractString) fsz = filesize(input) if use_mmap && fsz > 0 && fsz < typemax(Int) diff --git a/base/deprecated.jl b/base/deprecated.jl index 331e483161010..237cb9fcc3b7b 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -582,7 +582,7 @@ function msync end msync{T}(A::Array{T}) = msync(pointer(A), length(A)*sizeof(T)) msync(B::BitArray) = msync(pointer(B.chunks), length(B.chunks)*sizeof(UInt64)) -@unix_only begin +if is_unix() export mmap @noinline function mmap(len::Integer, prot::Integer, flags::Integer, fd, offset::Integer) depwarn("`mmap` is deprecated, use `Mmap.mmap(io, Array{T,N}, dims, offset)` instead to return an mmapped-array", :mmap) @@ -619,7 +619,7 @@ end end -@windows_only begin +if is_windows() @noinline function munmap(viewhandle::Ptr, mmaphandle::Ptr) depwarn("`munmap` is deprecated, `mmap` Arrays are automatically munmapped when finalized", :munmap) status = ccall(:UnmapViewOfFile, stdcall, Cint, (Ptr{Void},), viewhandle)!=0 @@ -639,9 +639,11 @@ end end -@unix_only @deprecate mmap_array{T,N}(::Type{T}, dims::NTuple{N,Integer}, s::IO, offset=position(s)) Mmap.mmap(s, Array{T,N}, dims, offset) +if is_unix() + @deprecate mmap_array{T,N}(::Type{T}, dims::NTuple{N,Integer}, s::IO, offset=position(s)) Mmap.mmap(s, Array{T,N}, dims, offset) +end -@windows_only begin +if is_windows() type SharedMemSpec name :: AbstractString readonly :: Bool @@ -1123,6 +1125,49 @@ end @deprecate_binding UTF8String String @deprecate_binding ByteString String +#6674 and #4233 +macro windows(qm,ex) + depwarn("`@windows` is deprecated, use `@static is_windows()` instead", Symbol("@windows")) + return @static is_windows() ? esc(ex.args[1]) : esc(ex.args[2]) +end +macro unix(qm,ex) + depwarn("`@unix` is deprecated, use `@static is_unix()` instead", Symbol("@unix")) + return @static is_unix() ? esc(ex.args[1]) : esc(ex.args[2]) +end +macro osx(qm,ex) + depwarn("`@osx` is deprecated, use `@static is_apple()` instead", Symbol("@osx")) + return @static is_apple() ? esc(ex.args[1]) : esc(ex.args[2]) +end +macro linux(qm,ex) + depwarn("`@linux` is deprecated, use `@static is_linux()` instead", Symbol("@linux")) + return @static is_linux() ? esc(ex.args[1]) : esc(ex.args[2]) +end +macro windows_only(ex) + depwarn("`@windows_only` is deprecated, use `@static is_windows()` instead", Symbol("@windows_only")) + return @static if is_windows() esc(ex) end +end +macro unix_only(ex) + depwarn("`@unix_only` is deprecated, use `@static is_unix()` instead", Symbol("@unix_only")) + return @static if is_unix() esc(ex) end +end +macro osx_only(ex) + depwarn("`@osx_only` is deprecated, use `@static is_apple()` instead", Symbol("@osx_only")) + return @static if is_apple() esc(ex) end +end +macro linux_only(ex) + depwarn("`@linux_only` is deprecated, use `@static is_linux()` instead", Symbol("@linux_only")) + return @static if is_linux() esc(ex) end +end +export + @windows, + @unix, + @osx, + @linux, + @windows_only, + @unix_only, + @osx_only, + @linux_only + # During the 0.5 development cycle, do not add any deprecations below this line # To be deprecated in 0.6 diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index 1e50a3993b4c7..63f7dfd640e9d 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -2055,36 +2055,6 @@ of a string. """ isdigit -""" - @windows - -Given `@windows? a : b`, do `a` on Windows and `b` elsewhere. See documentation in [Handling Operating System Variation](:ref:`Handling Operating System Variation `). -""" -:@windows - -""" - @unix - -Given `@unix? a : b`, do `a` on Unix systems (including Linux and OS X) and `b` elsewhere. -See documentation in [Handling Operating System Variation](:ref:`Handling Operating System Variation `). -""" -:@unix - -""" - @windows_only - -A macro that evaluates the given expression only on Windows systems. See documentation in [Handling Operating System Variation](:ref:`Handling Operating System Variation `). -""" -:@windows_only - -""" - @unix_only - -A macro that evaluates the given expression only on Unix systems (including Linux and OS X). See -documentation in [Handling Operating System Variation](:ref:`Handling Operating System Variation `). -""" -:@unix_only - """ num2hex(f) @@ -6407,20 +6377,6 @@ Returns the number of dimensions of `A`. """ ndims -""" - @osx - -Given `@osx? a : b`, do `a` on OS X and `b` elsewhere. See documentation in [Handling Operating System Variation](:ref:`Handling Operating System Variation `). -""" -:@osx - -""" - @osx_only - -A macro that evaluates the given expression only on OS X systems. See documentation in [Handling Operating System Variation](:ref:`Handling Operating System Variation `). -""" -:@osx_only - """ ishermitian(A) -> Bool @@ -8063,20 +8019,6 @@ Cumulative product of `A` along a dimension, storing the result in `B`. The dime """ cumprod! -""" - @linux - -Given `@linux? a : b`, do `a` on Linux and `b` elsewhere. See documentation [Handling Operating System Variation](:ref:`Handling Operating System Variation `). -""" -:@linux - -""" - @linux_only - -A macro that evaluates the given expression only on Linux systems. See documentation in [Handling Operating System Variation](:ref:`Handling Operating System Variation `). -""" -:@linux_only - """ complement(s) diff --git a/base/env.jl b/base/env.jl index 571a67835c757..286eb55350331 100644 --- a/base/env.jl +++ b/base/env.jl @@ -1,28 +1,6 @@ # This file is a part of Julia. License is MIT: http://julialang.org/license -@unix_only begin - -_getenv(var::AbstractString) = ccall(:getenv, Cstring, (Cstring,), var) -_hasenv(s::AbstractString) = _getenv(s) != C_NULL - -function access_env(onError::Function, var::AbstractString) - val = _getenv(var) - val == C_NULL ? onError(var) : bytestring(val) -end - -function _setenv(var::AbstractString, val::AbstractString, overwrite::Bool=true) - ret = ccall(:setenv, Int32, (Cstring,Cstring,Int32), var, val, overwrite) - systemerror(:setenv, ret != 0) -end - -function _unsetenv(var::AbstractString) - ret = ccall(:unsetenv, Int32, (Cstring,), var) - systemerror(:unsetenv, ret != 0) -end - -end # @unix_only - -@windows_only begin +if is_windows() const ERROR_ENVVAR_NOT_FOUND = UInt32(203) @@ -60,7 +38,26 @@ function _unsetenv(svar::AbstractString) systemerror(:setenv, ret == 0) end -end # @windows_only +else # !windows +_getenv(var::AbstractString) = ccall(:getenv, Cstring, (Cstring,), var) +_hasenv(s::AbstractString) = _getenv(s) != C_NULL + +function access_env(onError::Function, var::AbstractString) + val = _getenv(var) + val == C_NULL ? onError(var) : bytestring(val) +end + +function _setenv(var::AbstractString, val::AbstractString, overwrite::Bool=true) + ret = ccall(:setenv, Int32, (Cstring,Cstring,Int32), var, val, overwrite) + systemerror(:setenv, ret != 0) +end + +function _unsetenv(var::AbstractString) + ret = ccall(:unsetenv, Int32, (Cstring,), var) + systemerror(:unsetenv, ret != 0) +end + +end # os test ## ENV: hash interface ## @@ -79,25 +76,7 @@ delete!(::EnvHash, k::AbstractString, def) = haskey(ENV,k) ? delete!(ENV,k) : de setindex!(::EnvHash, v, k::AbstractString) = _setenv(k,string(v)) push!(::EnvHash, k::AbstractString, v) = setindex!(ENV, v, k) -@unix_only begin -start(::EnvHash) = 0 -done(::EnvHash, i) = (ccall(:jl_environ, Any, (Int32,), i) === nothing) - -function next(::EnvHash, i) - env = ccall(:jl_environ, Any, (Int32,), i) - if env === nothing - throw(BoundsError()) - end - env::String - m = match(r"^(.*?)=(.*)$"s, env) - if m === nothing - error("malformed environment entry: $env") - end - (Pair{String,String}(m.captures[1], m.captures[2]), i+1) -end -end - -@windows_only begin +if is_windows() start(hash::EnvHash) = (pos = ccall(:GetEnvironmentStringsW,stdcall,Ptr{UInt16},()); (pos,pos)) function done(hash::EnvHash, block::Tuple{Ptr{UInt16},Ptr{UInt16}}) if unsafe_load(block[1]) == 0 @@ -119,8 +98,26 @@ function next(hash::EnvHash, block::Tuple{Ptr{UInt16},Ptr{UInt16}}) end (Pair{String,String}(m.captures[1], m.captures[2]), (pos+len*2, blk)) end + +else # !windows +start(::EnvHash) = 0 +done(::EnvHash, i) = (ccall(:jl_environ, Any, (Int32,), i) === nothing) + +function next(::EnvHash, i) + env = ccall(:jl_environ, Any, (Int32,), i) + if env === nothing + throw(BoundsError()) + end + env::String + m = match(r"^(.*?)=(.*)$"s, env) + if m === nothing + error("malformed environment entry: $env") + end + (Pair{String,String}(m.captures[1], m.captures[2]), i+1) end +end # os-test + #TODO: Make these more efficent function length(::EnvHash) i = 0 diff --git a/base/event.jl b/base/event.jl index 69209a040eb63..e91849b40b11f 100644 --- a/base/event.jl +++ b/base/event.jl @@ -146,9 +146,10 @@ function wait() assert(false) end -function pause() - @unix_only ccall(:pause, Void, ()) - @windows_only ccall(:Sleep,stdcall, Void, (UInt32,), 0xffffffff) +if is_windows() + pause() = ccall(:Sleep, stdcall, Void, (UInt32,), 0xffffffff) +else + pause() = ccall(:pause, Void, ()) end diff --git a/base/exports.jl b/base/exports.jl index b1cba3ce80895..40d9a1736ac14 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -1391,14 +1391,12 @@ export @code_native, # platform-conditional code - @windows, - @unix, - @osx, - @linux, - @windows_only, - @unix_only, - @osx_only, - @linux_only, + @static, + is_windows, + is_linux, + is_apple, + is_bsd, + is_unix, # tasks @schedule, diff --git a/base/file.jl b/base/file.jl index fb06bd6aa7f74..51c0f401cb445 100644 --- a/base/file.jl +++ b/base/file.jl @@ -40,31 +40,37 @@ function cd(dir::AbstractString) end cd() = cd(homedir()) -@unix_only function cd(f::Function, dir::AbstractString) - fd = ccall(:open,Int32,(Cstring,Int32),:.,0) - systemerror(:open, fd == -1) - try - cd(dir) - f() - finally - systemerror(:fchdir, ccall(:fchdir,Int32,(Int32,),fd) != 0) - systemerror(:close, ccall(:close,Int32,(Int32,),fd) != 0) +if is_windows() + function cd(f::Function, dir::AbstractString) + old = pwd() + try + cd(dir) + f() + finally + cd(old) + end end -end -@windows_only function cd(f::Function, dir::AbstractString) - old = pwd() - try - cd(dir) - f() - finally - cd(old) +else + function cd(f::Function, dir::AbstractString) + fd = ccall(:open, Int32, (Cstring, Int32), :., 0) + systemerror(:open, fd == -1) + try + cd(dir) + f() + finally + systemerror(:fchdir, ccall(:fchdir, Int32, (Int32,), fd) != 0) + systemerror(:close, ccall(:close, Int32, (Int32,), fd) != 0) + end end end cd(f::Function) = cd(f, homedir()) function mkdir(path::AbstractString, mode::Unsigned=0o777) - @unix_only ret = ccall(:mkdir, Int32, (Cstring,UInt32), path, mode) - @windows_only ret = ccall(:_wmkdir, Int32, (Cwstring,), path) + @static if is_windows() + ret = ccall(:_wmkdir, Int32, (Cwstring,), path) + else + ret = ccall(:mkdir, Int32, (Cstring, UInt32), path, mode) + end systemerror(:mkdir, ret != 0; extrainfo=path) end @@ -92,7 +98,12 @@ mkpath(path::AbstractString, mode::Signed) = throw(ArgumentError("mode must be a function rm(path::AbstractString; force::Bool=false, recursive::Bool=false) if islink(path) || !isdir(path) try - @windows_only if (filemode(path) & 0o222) == 0; chmod(path, 0o777); end # is writable on windows actually means "is deletable" + @static if is_windows() + # is writable on windows actually means "is deletable" + if (filemode(path) & 0o222) == 0 + chmod(path, 0o777) + end + end unlink(path) catch err if force && isa(err, UVError) && err.code==Base.UV_ENOENT @@ -106,8 +117,11 @@ function rm(path::AbstractString; force::Bool=false, recursive::Bool=false) rm(joinpath(path, p), force=force, recursive=true) end end - @unix_only ret = ccall(:rmdir, Int32, (Cstring,), path) - @windows_only ret = ccall(:_wrmdir, Int32, (Cwstring,), path) + @static if is_windows() + ret = ccall(:_wrmdir, Int32, (Cwstring,), path) + else + ret = ccall(:rmdir, Int32, (Cstring,), path) + end systemerror(:rmdir, ret != 0, extrainfo=path) end end @@ -181,38 +195,7 @@ function touch(path::AbstractString) end end -@unix_only begin -# Obtain a temporary filename. -function tempname() - d = get(ENV, "TMPDIR", C_NULL) # tempnam ignores TMPDIR on darwin - p = ccall(:tempnam, Cstring, (Cstring,Cstring), d, :julia) - systemerror(:tempnam, p == C_NULL) - s = bytestring(p) - Libc.free(p) - return s -end - -# Obtain a temporary directory's path. -tempdir() = dirname(tempname()) - -# Create and return the name of a temporary file along with an IOStream -function mktemp(parent=tempdir()) - b = joinpath(parent, "tmpXXXXXX") - p = ccall(:mkstemp, Int32, (Cstring,), b) # modifies b - systemerror(:mktemp, p == -1) - return (b, fdio(p, true)) -end - -# Create and return the name of a temporary directory -function mktempdir(parent=tempdir()) - b = joinpath(parent, "tmpXXXXXX") - p = ccall(:mkdtemp, Cstring, (Cstring,), b) - systemerror(:mktempdir, p == C_NULL) - return bytestring(p) -end -end - -@windows_only begin +if is_windows() function tempdir() temppath = Array(UInt16,32767) lentemppath = ccall(:GetTempPathW,stdcall,UInt32,(UInt32,Ptr{UInt16}),length(temppath),temppath) @@ -254,8 +237,39 @@ function mktempdir(parent=tempdir()) seed += 1 end end + +else # !windows +# Obtain a temporary filename. +function tempname() + d = get(ENV, "TMPDIR", C_NULL) # tempnam ignores TMPDIR on darwin + p = ccall(:tempnam, Cstring, (Cstring,Cstring), d, :julia) + systemerror(:tempnam, p == C_NULL) + s = bytestring(p) + Libc.free(p) + return s end +# Obtain a temporary directory's path. +tempdir() = dirname(tempname()) + +# Create and return the name of a temporary file along with an IOStream +function mktemp(parent=tempdir()) + b = joinpath(parent, "tmpXXXXXX") + p = ccall(:mkstemp, Int32, (Cstring,), b) # modifies b + systemerror(:mktemp, p == -1) + return (b, fdio(p, true)) +end + +# Create and return the name of a temporary directory +function mktempdir(parent=tempdir()) + b = joinpath(parent, "tmpXXXXXX") + p = ccall(:mkdtemp, Cstring, (Cstring,), b) + systemerror(:mktempdir, p == C_NULL) + return bytestring(p) +end + +end # os-test + function mktemp(fn::Function, parent=tempdir()) (tmp_path, tmp_io) = mktemp(parent) try @@ -405,16 +419,27 @@ function sendfile(src::AbstractString, dst::AbstractString) end end -@windows_only const UV_FS_SYMLINK_JUNCTION = 0x0002 +if is_windows() + const UV_FS_SYMLINK_JUNCTION = 0x0002 +end function symlink(p::AbstractString, np::AbstractString) - @windows_only if Base.windows_version() < Base.WINDOWS_VISTA_VER - error("Windows XP does not support soft symlinks") + @static if is_windows() + if Base.windows_version() < Base.WINDOWS_VISTA_VER + error("Windows XP does not support soft symlinks") + end end flags = 0 - @windows_only if isdir(p); flags |= UV_FS_SYMLINK_JUNCTION; p = abspath(p); end + @static if is_windows() + if isdir(p) + flags |= UV_FS_SYMLINK_JUNCTION + p = abspath(p) + end + end err = ccall(:jl_fs_symlink, Int32, (Cstring, Cstring, Cint), p, np, flags) - @windows_only if err < 0 && !isdir(p) - Base.warn_once("Note: on Windows, creating file symlinks requires Administrator privileges.") + @static if is_windows() + if err < 0 && !isdir(p) + Base.warn_once("Note: on Windows, creating file symlinks requires Administrator privileges.") + end end uv_error("symlink",err) end diff --git a/base/filesystem.jl b/base/filesystem.jl index 0749b4b29205e..a6926e37f6421 100644 --- a/base/filesystem.jl +++ b/base/filesystem.jl @@ -45,7 +45,9 @@ import Base: skip, stat, unsafe_read, unsafe_write, utf16to8, utf8to16, uv_error, uvhandle, uvtype, write -@windows_only import Base: cwstring +if is_windows() + import Base: cwstring +end include("path.jl") include("stat.jl") diff --git a/base/initdefs.jl b/base/initdefs.jl index a64e134e0f852..7bf0a19afb8fe 100644 --- a/base/initdefs.jl +++ b/base/initdefs.jl @@ -18,12 +18,12 @@ const LOAD_PATH = String[] const LOAD_CACHE_PATH = String[] function init_load_path() vers = "v$(VERSION.major).$(VERSION.minor)" - if haskey(ENV,"JULIA_LOAD_PATH") - prepend!(LOAD_PATH, split(ENV["JULIA_LOAD_PATH"], @windows? ';' : ':')) + if haskey(ENV, "JULIA_LOAD_PATH") + prepend!(LOAD_PATH, split(ENV["JULIA_LOAD_PATH"], @static is_windows() ? ';' : ':')) end - push!(LOAD_PATH,abspath(JULIA_HOME,"..","local","share","julia","site",vers)) - push!(LOAD_PATH,abspath(JULIA_HOME,"..","share","julia","site",vers)) - push!(LOAD_CACHE_PATH,abspath(JULIA_HOME,"..","usr","lib","julia")) #TODO: fixme + push!(LOAD_PATH, abspath(JULIA_HOME, "..", "local", "share", "julia", "site", vers)) + push!(LOAD_PATH, abspath(JULIA_HOME, "..", "share", "julia", "site", vers)) + push!(LOAD_CACHE_PATH, abspath(JULIA_HOME, "..", "lib", "julia")) #TODO: fixme? end # initialize the local proc network address / port diff --git a/base/interactiveutil.jl b/base/interactiveutil.jl index e7638186c6cc6..9fa4e2dc8d7d4 100644 --- a/base/interactiveutil.jl +++ b/base/interactiveutil.jl @@ -82,16 +82,15 @@ less(file, line::Integer) = error("could not find source file for function") # clipboard copy and paste -@osx_only begin +if is_apple() function clipboard(x) open(pipeline(`pbcopy`, stderr=STDERR), "w") do io print(io, x) end end clipboard() = readstring(`pbpaste`) -end -@linux_only begin +elseif is_linux() _clipboardcmd = nothing function clipboardcmd() global _clipboardcmd @@ -117,9 +116,9 @@ end error("unexpected clipboard command: $c") readstring(pipeline(cmd, stderr=STDERR)) end -end -@windows_only begin # TODO: these functions leak memory and memory locks if they throw an error +elseif is_windows() + # TODO: these functions leak memory and memory locks if they throw an error function clipboard(x::AbstractString) if containsnul(x) throw(ArgumentError("Windows clipboard strings cannot contain NUL character")) @@ -155,10 +154,9 @@ end systemerror(:GlobalUnlock, 0==ccall((:GlobalUnlock, "kernel32"), stdcall, Cint, (Ptr{UInt16},), plock)) return s end -end -if !isdefined(:clipboard) - clipboard(x="") = error("clipboard functionality not implemented for $OS_NAME") +else + clipboard(x="") = error("`clipboard` function not implemented for $OS_NAME") end # system information @@ -179,12 +177,18 @@ function versioninfo(io::IO=STDOUT, verbose::Bool=false) println(io, " WORD_SIZE: ", Sys.WORD_SIZE) if verbose lsb = "" - @linux_only try lsb = readchomp(pipeline(`lsb_release -ds`, stderr=DevNull)) end - @windows_only try lsb = strip(readstring(`$(ENV["COMSPEC"]) /c ver`)) end + if is_linux() + try lsb = readchomp(pipeline(`lsb_release -ds`, stderr=DevNull)) end + end + if is_windows() + try lsb = strip(readstring(`$(ENV["COMSPEC"]) /c ver`)) end + end if lsb != "" println(io, " ", lsb) end - @unix_only println(io, " uname: ",readchomp(`uname -mprsv`)) + if is_unix() + println(io, " uname: ", readchomp(`uname -mprsv`)) + end println(io, "Memory: $(Sys.total_memory()/2^30) GB ($(Sys.free_memory()/2^20) MB free)") try println(io, "Uptime: $(Sys.uptime()) sec") end print(io, "Load Avg: ") @@ -427,37 +431,38 @@ end # file downloading downloadcmd = nothing -@unix_only function download(url::AbstractString, filename::AbstractString) - global downloadcmd - if downloadcmd === nothing - for checkcmd in (:curl, :wget, :fetch) - if success(pipeline(`which $checkcmd`, DevNull)) - downloadcmd = checkcmd - break +if is_windows() + function download(url::AbstractString, filename::AbstractString) + res = ccall((:URLDownloadToFileW,:urlmon),stdcall,Cuint, + (Ptr{Void},Cwstring,Cwstring,Cuint,Ptr{Void}),C_NULL,url,filename,0,C_NULL) + if res != 0 + error("automatic download failed (error: $res): $url") + end + filename + end +else + function download(url::AbstractString, filename::AbstractString) + global downloadcmd + if downloadcmd === nothing + for checkcmd in (:curl, :wget, :fetch) + if success(pipeline(`which $checkcmd`, DevNull)) + downloadcmd = checkcmd + break + end end end + if downloadcmd == :wget + run(`wget -O $filename $url`) + elseif downloadcmd == :curl + run(`curl -o $filename -L $url`) + elseif downloadcmd == :fetch + run(`fetch -f $filename $url`) + else + error("no download agent available; install curl, wget, or fetch") + end + filename end - if downloadcmd == :wget - run(`wget -O $filename $url`) - elseif downloadcmd == :curl - run(`curl -o $filename -L $url`) - elseif downloadcmd == :fetch - run(`fetch -f $filename $url`) - else - error("no download agent available; install curl, wget, or fetch") - end - filename -end - -@windows_only function download(url::AbstractString, filename::AbstractString) - res = ccall((:URLDownloadToFileW,:urlmon),stdcall,Cuint, - (Ptr{Void},Cwstring,Cwstring,Cuint,Ptr{Void}),C_NULL,url,filename,0,C_NULL) - if res != 0 - error("automatic download failed (error: $res): $url") - end - filename end - function download(url::AbstractString) filename = tempname() download(url, filename) diff --git a/base/libc.jl b/base/libc.jl index c061d8f52aba6..339fd1809beff 100644 --- a/base/libc.jl +++ b/base/libc.jl @@ -4,7 +4,9 @@ module Libc export FILE, TmStruct, strftime, strptime, getpid, gethostname, free, malloc, calloc, realloc, errno, strerror, flush_cstdio, systemsleep, time -@windows_only export GetLastError, FormatMessage +if is_windows() + export GetLastError, FormatMessage +end import Base: utf16to8 @@ -21,20 +23,22 @@ end Base.cconvert(::Type{Int32}, fd::RawFD) = fd.fd -dup(x::RawFD) = RawFD(ccall((@windows? :_dup : :dup),Int32,(Int32,),x.fd)) -dup(src::RawFD,target::RawFD) = systemerror("dup",-1== - ccall((@windows? :_dup2 : :dup2),Int32, - (Int32,Int32),src.fd,target.fd)) +dup(x::RawFD) = RawFD(ccall((@static is_windows() ? :_dup : :dup), Int32, (Int32,), x.fd)) +dup(src::RawFD, target::RawFD) = systemerror("dup", -1 == + ccall((@static is_windows() ? :_dup2 : :dup2), Int32, + (Int32, Int32), src.fd, target.fd)) # Wrapper for an OS file descriptor (for Windows) -@windows_only immutable WindowsRawSocket - handle::Ptr{Void} # On Windows file descriptors are HANDLE's and 64-bit on 64-bit Windows +if is_windows() + immutable WindowsRawSocket + handle::Ptr{Void} # On Windows file descriptors are HANDLE's and 64-bit on 64-bit Windows + end + Base.cconvert(::Type{Ptr{Void}}, fd::WindowsRawSocket) = fd.handle + _get_osfhandle(fd::RawFD) = WindowsRawSocket(ccall(:_get_osfhandle,Ptr{Void},(Cint,),fd.fd)) + _get_osfhandle(fd::WindowsRawSocket) = fd +else + _get_osfhandle(fd::RawFD) = fd end -@windows_only Base.cconvert(::Type{Ptr{Void}}, fd::WindowsRawSocket) = fd.handle - -@unix_only _get_osfhandle(fd::RawFD) = fd -@windows_only _get_osfhandle(fd::RawFD) = WindowsRawSocket(ccall(:_get_osfhandle,Ptr{Void},(Cint,),fd.fd)) -@windows_only _get_osfhandle(fd::WindowsRawSocket) = fd ## FILE (not auto-finalized) ## @@ -46,8 +50,7 @@ modestr(s::IO) = modestr(isreadable(s), iswritable(s)) modestr(r::Bool, w::Bool) = r ? (w ? "r+" : "r") : (w ? "w" : throw(ArgumentError("neither readable nor writable"))) function FILE(fd::RawFD, mode) - @unix_only FILEp = ccall(:fdopen, Ptr{Void}, (Cint, Cstring), fd, mode) - @windows_only FILEp = ccall(:_fdopen, Ptr{Void}, (Cint, Cstring), fd, mode) + FILEp = ccall((@static is_windows() ? :_fdopen : :fdopen), Ptr{Void}, (Cint, Cstring), fd, mode) systemerror("fdopen", FILEp == C_NULL) FILE(FILEp) end @@ -82,8 +85,16 @@ flush_cstdio() = ccall(:jl_flush_cstdio, Void, ()) ## time-related functions ## # TODO: check for usleep errors? -@unix_only systemsleep(s::Real) = ccall(:usleep, Int32, (UInt32,), round(UInt32,s*1e6)) -@windows_only systemsleep(s::Real) = (ccall(:Sleep, stdcall, Void, (UInt32,), round(UInt32,s*1e3)); return Int32(0)) +if is_unix() + systemsleep(s::Real) = ccall(:usleep, Int32, (UInt32,), round(UInt32, s*1e6)) +elseif is_windows() + function systemsleep(s::Real) + ccall(:Sleep, stdcall, Void, (UInt32,), round(UInt32, s * 1e3)) + return Int32(0) + end +else + error("systemsleep undefined for this OS") +end immutable TimeVal sec::Int64 @@ -148,7 +159,7 @@ function strftime(fmt::AbstractString, tm::TmStruct) if n == 0 return "" end - bytestring(pointer(timestr), n) + return bytestring(pointer(timestr), n) end """ @@ -174,14 +185,14 @@ function strptime(fmt::AbstractString, timestr::AbstractString) # TODO: better error message throw(ArgumentError("invalid arguments")) end - @osx_only begin + @static if is_apple() # if we didn't explicitly parse the weekday or year day, use mktime # to fill them in automatically. if !ismatch(r"([^%]|^)%(a|A|j|w|Ow)", fmt) ccall(:mktime, Int, (Ptr{TmStruct},), &tm) end end - tm + return tm end # system date in seconds @@ -202,10 +213,13 @@ getpid() = ccall(:jl_getpid, Int32, ()) function gethostname() hn = Array(UInt8, 256) - @unix_only err=ccall(:gethostname, Int32, (Ptr{UInt8}, UInt), hn, length(hn)) - @windows_only err=ccall(:gethostname, stdcall, Int32, (Ptr{UInt8}, UInt32), hn, length(hn)) + err = @static if is_windows() + ccall(:gethostname, stdcall, Int32, (Ptr{UInt8}, UInt32), hn, length(hn)) + else + ccall(:gethostname, Int32, (Ptr{UInt8}, UInt), hn, length(hn)) + end systemerror("gethostname", err != 0) - bytestring(pointer(hn)) + return bytestring(pointer(hn)) end ## system error handling ## @@ -245,7 +259,7 @@ Convert a Win32 system call error code to a descriptive string [only available o """ function FormatMessage end -@windows_only begin +if is_windows() GetLastError() = ccall(:GetLastError,stdcall,UInt32,()) function FormatMessage(e=GetLastError()) diff --git a/base/libdl.jl b/base/libdl.jl index 5bb0ddeee270d..0b90d7be41dcc 100644 --- a/base/libdl.jl +++ b/base/libdl.jl @@ -7,8 +7,10 @@ export DL_LOAD_PATH, RTLD_DEEPBIND, RTLD_FIRST, RTLD_GLOBAL, RTLD_LAZY, RTLD_LOC dlpath, find_library, dlext, dllist const DL_LOAD_PATH = String[] -@osx_only push!(DL_LOAD_PATH, "@loader_path/julia") -@osx_only push!(DL_LOAD_PATH, "@loader_path") +if is_apple() + push!(DL_LOAD_PATH, "@loader_path/julia") + push!(DL_LOAD_PATH, "@loader_path") +end # constants to match JL_RTLD_* in src/julia.h const RTLD_LOCAL = 0x00000001 @@ -121,7 +123,7 @@ find_library(libname::Union{Symbol,AbstractString}, extrapaths=String[]) = function dlpath(handle::Ptr{Void}) p = ccall(:jl_pathname_for_handle, Cstring, (Ptr{Void},), handle) s = bytestring(p) - @windows_only Libc.free(p) + is_windows() && Libc.free(p) return s end @@ -148,7 +150,7 @@ File extension for dynamic libraries (e.g. dll, dylib, so) on the current platfo """ dlext -@linux_only begin +if is_linux() immutable dl_phdr_info # Base address of object addr::Cuint @@ -172,18 +174,18 @@ dlext end return convert(Cint, 0)::Cint end -end #@linux_only +end # linux-only function dllist() - dynamic_libraries = Array(AbstractString,0) + dynamic_libraries = Array{AbstractString}(0) - @linux_only begin + @static if is_linux() const callback = cfunction(dl_phdr_info_callback, Cint, (Ref{dl_phdr_info}, Csize_t, Ref{Array{AbstractString,1}} )) ccall(:dl_iterate_phdr, Cint, (Ptr{Void}, Ref{Array{AbstractString,1}}), callback, dynamic_libraries) end - @osx_only begin + @static if is_apple() numImages = ccall(:_dyld_image_count, Cint, (), ) # start at 1 instead of 0 to skip self @@ -193,11 +195,11 @@ function dllist() end end - @windows_only begin + @static if is_windows() ccall(:jl_dllist, Cint, (Any,), dynamic_libraries) end - dynamic_libraries + return dynamic_libraries end end # module diff --git a/base/libgit2/repository.jl b/base/libgit2/repository.jl index 2a52114e12b5e..37ee2d17500bd 100644 --- a/base/libgit2/repository.jl +++ b/base/libgit2/repository.jl @@ -14,7 +14,7 @@ function GitRepo(path::AbstractString) end function GitRepoExt(path::AbstractString, flags::Cuint = Cuint(Consts.REPOSITORY_OPEN_DEFAULT)) - separator = @unix? ":" : ";" + separator = @static is_windows() ? ";" : ":" repo_ptr_ptr = Ref{Ptr{Void}}(C_NULL) err = ccall((:git_repository_open_ext, :libgit2), Cint, (Ptr{Ptr{Void}}, Cstring, Cuint, Cstring), diff --git a/base/managers.jl b/base/managers.jl index 5ea93cb24138e..c823bd5e6bfee 100644 --- a/base/managers.jl +++ b/base/managers.jl @@ -355,7 +355,7 @@ function socket_reuse_port() # TODO: Support OSX and change the above code to call setsockopt before bind once libuv provides # early access to a socket fd, i.e., before a bind call. - @linux_only begin + @static if is_linux() try rc = ccall(:jl_tcp_reuseport, Int32, (Ptr{Void}, ), s.handle) if rc > 0 # SO_REUSEPORT is unsupported, just return the ephemerally bound socket diff --git a/base/mmap.jl b/base/mmap.jl index 832fbcbff1648..ff490610d5b99 100644 --- a/base/mmap.jl +++ b/base/mmap.jl @@ -2,7 +2,7 @@ module Mmap -const PAGESIZE = Int(@unix ? ccall(:jl_getpagesize, Clong, ()) : ccall(:jl_getallocationgranularity, Clong, ())) +const PAGESIZE = Int(is_unix() ? ccall(:jl_getpagesize, Clong, ()) : ccall(:jl_getallocationgranularity, Clong, ())) # for mmaps not backed by files type Anonymous <: IO @@ -21,14 +21,14 @@ const INVALID_HANDLE_VALUE = -1 gethandle(io::Anonymous) = INVALID_HANDLE_VALUE # platform-specific mmap utilities -@unix_only begin +if is_unix() -const PROT_READ = convert(Cint,1) -const PROT_WRITE = convert(Cint,2) -const MAP_SHARED = convert(Cint,1) -const MAP_PRIVATE = convert(Cint,2) -const MAP_ANONYMOUS = convert(Cint, @osx? 0x1000 : 0x20) -const F_GETFL = convert(Cint,3) +const PROT_READ = Cint(1) +const PROT_WRITE = Cint(2) +const MAP_SHARED = Cint(1) +const MAP_PRIVATE = Cint(2) +const MAP_ANONYMOUS = Cint(is_apple() ? 0x1000 : 0x20) +const F_GETFL = Cint(3) gethandle(io::IO) = fd(io) @@ -64,9 +64,8 @@ function grow!(io::IO, offset::Integer, len::Integer) seek(io, pos) return end -end # @unix_only -@windows_only begin +elseif is_windows() typealias DWORD Culong @@ -89,7 +88,10 @@ end settings(sh::Anonymous) = sh.name, sh.readonly, sh.create settings(io::IO) = Ptr{Cwchar_t}(0), isreadonly(io), true -end # @windows_only + +else + error("mmap not defined for this OS") +end # os-test # core impelementation of mmap function mmap{T,N}(io::IO, @@ -114,15 +116,13 @@ function mmap{T,N}(io::IO, file_desc = gethandle(io) # platform-specific mmapping - @unix_only begin + @static if is_unix() prot, flags, iswrite = settings(file_desc, shared) iswrite && grow && grow!(io, offset, len) # mmap the file ptr = ccall(:jl_mmap, Ptr{Void}, (Ptr{Void}, Csize_t, Cint, Cint, Cint, Int64), C_NULL, mmaplen, prot, flags, file_desc, offset_page) systemerror("memory mapping failed", reinterpret(Int,ptr) == -1) - end # @unix_only - - @windows_only begin + else name, readonly, create = settings(io) szfile = convert(Csize_t, len + offset) readonly && szfile > filesize(io) && throw(ArgumentError("unable to increase file size to $szfile due to read-only permissions")) @@ -134,14 +134,17 @@ function mmap{T,N}(io::IO, ptr = ccall(:MapViewOfFile, stdcall, Ptr{Void}, (Ptr{Void}, DWORD, DWORD, DWORD, Csize_t), handle, readonly ? FILE_MAP_READ : FILE_MAP_WRITE, offset_page >> 32, offset_page & typemax(UInt32), (offset - offset_page) + len) ptr == C_NULL && error("could not create mapping view: $(Libc.FormatMessage())") - end # @windows_only + end # os-test # convert mmapped region to Julia Array at `ptr + (offset - offset_page)` since file was mapped at offset_page A = pointer_to_array(convert(Ptr{T}, UInt(ptr) + UInt(offset - offset_page)), dims) - @unix_only finalizer(A, x -> systemerror("munmap", ccall(:munmap,Cint,(Ptr{Void},Int),ptr,mmaplen) != 0)) - @windows_only finalizer(A, x -> begin - status = ccall(:UnmapViewOfFile, stdcall, Cint, (Ptr{Void},), ptr)!=0 - status |= ccall(:CloseHandle, stdcall, Cint, (Ptr{Void},), handle)!=0 - status || error("could not unmap view: $(Libc.FormatMessage())") + finalizer(A, function(x) + @static if is_unix() + systemerror("munmap", ccall(:munmap, Cint, (Ptr{Void}, Int), ptr, mmaplen) != 0) + else + status = ccall(:UnmapViewOfFile, stdcall, Cint, (Ptr{Void},), ptr)!=0 + status |= ccall(:CloseHandle, stdcall, Cint, (Ptr{Void},), handle)!=0 + status || error("could not unmap view: $(Libc.FormatMessage())") + end end) return A end @@ -206,9 +209,13 @@ const MS_SYNC = 4 function sync!{T}(m::Array{T}, flags::Integer=MS_SYNC) offset = rem(UInt(pointer(m)), PAGESIZE) ptr = pointer(m) - offset - @unix_only systemerror("msync", ccall(:msync, Cint, (Ptr{Void}, Csize_t, Cint), ptr, length(m)*sizeof(T), flags) != 0) - @windows_only systemerror("could not FlushViewOfFile: $(Libc.FormatMessage())", + @static if is_unix() + systemerror("msync", + ccall(:msync, Cint, (Ptr{Void}, Csize_t, Cint), ptr, length(m) * sizeof(T), flags) != 0) + else + systemerror("could not FlushViewOfFile: $(Libc.FormatMessage())", ccall(:FlushViewOfFile, stdcall, Cint, (Ptr{Void}, Csize_t), ptr, length(m)) == 0) + end end sync!(B::BitArray, flags::Integer=MS_SYNC) = sync!(B.chunks, flags) diff --git a/base/multi.jl b/base/multi.jl index b8c5b604cee84..4c6bd0fc9cd7c 100644 --- a/base/multi.jl +++ b/base/multi.jl @@ -1652,7 +1652,7 @@ end function disable_nagle(sock) # disable nagle on all OSes ccall(:uv_tcp_nodelay, Cint, (Ptr{Void}, Cint), sock.handle, 1) - @linux_only begin + @static if is_linux() # tcp_quickack is a linux only option if ccall(:jl_tcp_quickack, Cint, (Ptr{Void}, Cint), sock.handle, 1) < 0 warn_once("Parallel networking unoptimized ( Error enabling TCP_QUICKACK : ", Libc.strerror(Libc.errno()), " )") diff --git a/base/osutils.jl b/base/osutils.jl index 7155e2edc8438..f8c06ab80dd91 100644 --- a/base/osutils.jl +++ b/base/osutils.jl @@ -2,59 +2,95 @@ const OS_NAME = ccall(:jl_get_OS_NAME, Any, ()) -function is_unix(os::Symbol) - if (os==:Windows) return false; - elseif (os==:Linux) return true; - elseif (os==:FreeBSD) return true; - elseif (os==:Darwin) return true; - else throw(ArgumentError("unknown operating system, $(repr(os))")) - end -end +""" + is_unix([os]) -function _os_test(qm,ex,test) - @assert qm == :? - @assert isa(ex,Expr) - @assert ex.head == :(:) - @assert length(ex.args) == 2 - if test - return esc(ex.args[1]) +Predicate for testing if the OS provides a Unix-like interface. +See documentation :ref:`Handling Operating System Variation `\ . +""" +function is_unix(os::Symbol = OS_NAME) + if is_windows(os) + return false + elseif is_linux(os) || is_bsd(os) + return true else - return esc(ex.args[2]) + throw(ArgumentError("unknown operating system \"$os\"")) end end -macro windows(qm,ex) - _os_test(qm, ex, OS_NAME===:Windows) -end -macro unix(qm,ex) - _os_test(qm, ex, is_unix(OS_NAME)) -end -macro osx(qm,ex) - _os_test(qm, ex, OS_NAME===:Darwin) -end -macro linux(qm,ex) - _os_test(qm, ex, OS_NAME===:Linux) -end +""" + is_linux([os]) -macro windows_only(ex) - @windows? esc(ex) : nothing -end -macro unix_only(ex) - @unix? esc(ex) : nothing -end -macro osx_only(ex) - @osx? esc(ex) : nothing -end -macro linux_only(ex) - @linux? esc(ex) : nothing +Predicate for testing if the OS is a derivative of Linux. +See documentation :ref:`Handling Operating System Variation `\ . +""" +is_linux(os::Symbol = OS_NAME) = (os == :Linux) + +""" + is_bsd([os]) + +Predicate for testing if the OS is a derivative of BSD. +See documentation :ref:`Handling Operating System Variation `\ . +""" +is_bsd(os::Symbol = OS_NAME) = (os == :FreeBSD || os == :OpenBSD || os == :NetBSD || os == :Darwin) + +""" + is_windows([os]) + +Predicate for testing if the OS is a derivative of Microsoft Windows NT. +See documentation :ref:`Handling Operating System Variation `\ . +""" +is_windows(os::Symbol = OS_NAME) = (os == :Windows) + +""" + is_apple([os]) + +Predicate for testing if the OS is a derivative of Apple Macintosh OS X or Darwin. +See documentation :ref:`Handling Operating System Variation `\ . +""" +is_apple(os::Symbol = OS_NAME) = (os == :Darwin) + +""" + @static + +Partially evaluates an expression at parse time. + +For example, `@static is_windows() ? foo : bar` will evaluate `is_windows()` and insert either `foo` or `bar` into the expression. +This is useful in cases where a construct would be invalid on other platforms, +such as a ccall to a non-existant functions. +""" +macro static(ex) + if isa(ex, Expr) + if ex.head === :if + cond = eval(current_module(), ex.args[1]) + if cond + return esc(ex.args[2]) + elseif length(ex.args) == 3 + return esc(ex.args[3]) + else + return nothing + end + end + end + throw(ArgumentError("invalid @static macro")) end # Windows version macros -@windows_only function windows_version() - verinfo = ccall(:GetVersion, UInt32, ()) - (verinfo & 0xFF, (verinfo >> 8) & 0xFF) +if is_windows() + function windows_version() + verinfo = ccall(:GetVersion, UInt32, ()) + (Int(verinfo & 0xFF), Int((verinfo >> 8) & 0xFF)) + end +else + windows_version() = (0, 0) end -@unix_only windows_version() = (0,0) +""" + windows_version() + +Returns the version number for the Windows NT Kernel as a (major, minor) pair, +or (0, 0) if this is not running on Windows. +""" +windows_version -WINDOWS_VISTA_VER = (6,0) +const WINDOWS_VISTA_VER = (6, 0) diff --git a/base/path.jl b/base/path.jl index 4d54561f6a842..636a3445134c3 100644 --- a/base/path.jl +++ b/base/path.jl @@ -16,7 +16,7 @@ export splitdrive, splitext -@unix_only begin +if is_unix() const path_separator = "/" const path_separator_re = r"/+" const path_absolute_re = r"^/" @@ -26,8 +26,7 @@ export splitdrive(path::AbstractString) = ("",path) homedir() = ENV["HOME"] -end -@windows_only begin +elseif is_windows() const path_separator = "\\" const path_separator_re = r"[/\\]+" const path_absolute_re = r"^(?:\w+:)?[/\\]" @@ -40,6 +39,8 @@ end bytestring(m.captures[1]), bytestring(m.captures[2]) end homedir() = get(ENV,"HOME",string(ENV["HOMEDRIVE"],ENV["HOMEPATH"])) +else + error("path primitives for this OS need to be defined") end isabspath(path::AbstractString) = ismatch(path_absolute_re, path) @@ -124,51 +125,57 @@ normpath(a::AbstractString, b::AbstractString...) = normpath(joinpath(a,b...)) abspath(a::AbstractString) = normpath(isabspath(a) ? a : joinpath(pwd(),a)) abspath(a::AbstractString, b::AbstractString...) = abspath(joinpath(a,b...)) -@windows_only function realpath(path::AbstractString) - path = cwstring(path) - buf = zeros(UInt16, length(path)) - while true - n = ccall((:GetFullPathNameW, "kernel32"), stdcall, - UInt32, (Ptr{UInt16}, UInt32, Ptr{UInt16}, Ptr{Void}), - path, length(buf), buf, C_NULL) - systemerror(:realpath, n == 0) - x = n < length(buf) # is the buffer big enough? - resize!(buf, n) # shrink if x, grow if !x - x && return String(utf16to8(buf)) +if is_windows() + function realpath(path::AbstractString) + path = cwstring(path) + buf = zeros(UInt16, length(path)) + while true + n = ccall((:GetFullPathNameW, "kernel32"), stdcall, + UInt32, (Ptr{UInt16}, UInt32, Ptr{UInt16}, Ptr{Void}), + path, length(buf), buf, C_NULL) + systemerror(:realpath, n == 0) + x = n < length(buf) # is the buffer big enough? + resize!(buf, n) # shrink if x, grow if !x + x && return String(utf16to8(buf)) + end end -end -@windows_only function longpath(path::AbstractString) - path = cwstring(path) - buf = zeros(UInt16, length(path)) - while true - n = ccall((:GetLongPathNameW, "kernel32"), stdcall, - UInt32, (Ptr{UInt16}, Ptr{UInt16}, UInt32), - path, buf, length(buf)) - systemerror(:longpath, n == 0) - x = n < length(buf) # is the buffer big enough? - resize!(buf, n) # shrink if x, grow if !x - x && return String(utf16to8(buf)) + function longpath(path::AbstractString) + path = cwstring(path) + buf = zeros(UInt16, length(path)) + while true + n = ccall((:GetLongPathNameW, "kernel32"), stdcall, + UInt32, (Ptr{UInt16}, Ptr{UInt16}, UInt32), + path, buf, length(buf)) + systemerror(:longpath, n == 0) + x = n < length(buf) # is the buffer big enough? + resize!(buf, n) # shrink if x, grow if !x + x && return String(utf16to8(buf)) + end end -end -@unix_only function realpath(path::AbstractString) - p = ccall(:realpath, Ptr{UInt8}, (Cstring, Ptr{UInt8}), path, C_NULL) - systemerror(:realpath, p == C_NULL) - s = bytestring(p) - Libc.free(p) - return s +else + function realpath(path::AbstractString) + p = ccall(:realpath, Ptr{UInt8}, (Cstring, Ptr{UInt8}), path, C_NULL) + systemerror(:realpath, p == C_NULL) + s = bytestring(p) + Libc.free(p) + return s + end end -@windows_only expanduser(path::AbstractString) = path # on windows, ~ means "temporary file" -@unix_only function expanduser(path::AbstractString) - i = start(path) - c, i = next(path,i) - if c != '~' return path end - if done(path,i) return homedir() end - c, j = next(path,i) - if c == '/' return homedir()*path[i:end] end - throw(ArgumentError("~user tilde expansion not yet implemented")) +if is_windows() + expanduser(path::AbstractString) = path # on windows, ~ means "temporary file" +else + function expanduser(path::AbstractString) + i = start(path) + c, i = next(path,i) + if c != '~' return path end + if done(path,i) return homedir() end + c, j = next(path,i) + if c == '/' return homedir()*path[i:end] end + throw(ArgumentError("~user tilde expansion not yet implemented")) + end end function relpath(path::AbstractString, startpath::AbstractString = ".") diff --git a/base/pkg/cache.jl b/base/pkg/cache.jl index f41b2252170c1..6420378267743 100644 --- a/base/pkg/cache.jl +++ b/base/pkg/cache.jl @@ -18,13 +18,15 @@ function mkcachedir() return end - @unix_only if Dir.isversioned(pwd()) - rootcache = joinpath(realpath(".."), ".cache") - if !isdir(rootcache) - mkdir(rootcache) + @static if is_unix() + if Dir.isversioned(pwd()) + rootcache = joinpath(realpath(".."), ".cache") + if !isdir(rootcache) + mkdir(rootcache) + end + symlink(rootcache, cache) + return end - symlink(rootcache, cache) - return end mkdir(cache) end diff --git a/base/pkg/reqs.jl b/base/pkg/reqs.jl index 80f67a268031f..461e15b0abaf6 100644 --- a/base/pkg/reqs.jl +++ b/base/pkg/reqs.jl @@ -91,14 +91,16 @@ function parse(lines::Vector{Line}) if isa(line,Requirement) if !isempty(line.system) applies = false - @windows_only applies |= ("windows" in line.system) - @unix_only applies |= ("unix" in line.system) - @osx_only applies |= ("osx" in line.system) - @linux_only applies |= ("linux" in line.system) - @windows_only applies &= !("!windows" in line.system) - @unix_only applies &= !("!unix" in line.system) - @osx_only applies &= !("!osx" in line.system) - @linux_only applies &= !("!linux" in line.system) + if is_windows(); applies |= ("windows" in line.system); end + if is_unix(); applies |= ("unix" in line.system); end + if is_apple(); applies |= ("osx" in line.system); end + if is_linux(); applies |= ("linux" in line.system); end + if is_bsd(); applies |= ("bsd" in line.system); end + if is_windows(); applies &= !("!windows" in line.system); end + if is_unix(); applies &= !("!unix" in line.system); end + if is_apple(); applies &= !("!osx" in line.system); end + if is_linux(); applies &= !("!linux" in line.system); end + if is_bsd(); applies &= !("!bsd" in line.system); end applies || continue end reqs[line.package] = haskey(reqs, line.package) ? diff --git a/base/poll.jl b/base/poll.jl index 1914d32a872e4..7844ea7d268e3 100644 --- a/base/poll.jl +++ b/base/poll.jl @@ -13,7 +13,9 @@ export import Base: @handle_as, wait, close, uvfinalize, eventloop, notify_error, stream_wait, _sizeof_uv_poll, _sizeof_uv_fs_poll, _sizeof_uv_fs_event, _uv_hook_close, associate_julia_struct, disassociate_julia_struct -@windows_only import Base.WindowsRawSocket +if is_windows() + import Base.WindowsRawSocket +end # libuv file watching event flags const UV_RENAME = 1 @@ -106,8 +108,10 @@ type _FDWatcher this.refcount = (this.refcount[1] + Int(readable), this.refcount[2] + Int(writable)) return this end - @unix_only if ccall(:jl_uv_unix_fd_is_watched, Int32, (Int32, Ptr{Void}, Ptr{Void}), fd.fd, C_NULL, eventloop()) == 1 - throw(ArgumentError("file descriptor $(fd.fd) is already being watched by libuv")) + @static if is_unix() + if ccall(:jl_uv_unix_fd_is_watched, Int32, (Int32, Ptr{Void}, Ptr{Void}), fd.fd, C_NULL, eventloop()) == 1 + throw(ArgumentError("file descriptor $(fd.fd) is already being watched by libuv")) + end end handle = Libc.malloc(_sizeof_uv_poll) this = new(handle, (Int(readable), Int(writable)), Condition(), (false, false)) @@ -120,20 +124,22 @@ type _FDWatcher FDWatchers[fd.fd] = this return this end - @windows_only function _FDWatcher(fd::WindowsRawSocket, readable::Bool, writable::Bool) - if !readable && !writable - throw(ArgumentError("must specify at least one of readable or writable to create a FDWatcher")) - end - handle = Libc.malloc(_sizeof_uv_poll) - this = new(handle, (Int(readable), Int(writable)), Condition(), (false, false)) - associate_julia_struct(handle, this) - err = ccall(:uv_poll_init_socket,Int32,(Ptr{Void}, Ptr{Void}, Ptr{Void}), - eventloop(), handle, fd.handle) - if err != 0 - Libc.free(handle) - throw(UVError("FDWatcher",err)) + @static if is_windows() + function _FDWatcher(fd::WindowsRawSocket, readable::Bool, writable::Bool) + if !readable && !writable + throw(ArgumentError("must specify at least one of readable or writable to create a FDWatcher")) + end + handle = Libc.malloc(_sizeof_uv_poll) + this = new(handle, (Int(readable), Int(writable)), Condition(), (false, false)) + associate_julia_struct(handle, this) + err = ccall(:uv_poll_init_socket,Int32,(Ptr{Void}, Ptr{Void}, Ptr{Void}), + eventloop(), handle, fd.handle) + if err != 0 + Libc.free(handle) + throw(UVError("FDWatcher",err)) + end + return this end - return this end global close function close(t::_FDWatcher, readable::Bool, writable::Bool) @@ -171,10 +177,12 @@ type FDWatcher finalizer(this, close) return this end - @windows_only function FDWatcher(fd::WindowsRawSocket, readable::Bool, writable::Bool) - this = new(_FDWatcher(fd, readable, writable), readable, writable) - finalizer(this, close) - return this + @static if is_windows() + function FDWatcher(fd::WindowsRawSocket, readable::Bool, writable::Bool) + this = new(_FDWatcher(fd, readable, writable), readable, writable) + finalizer(this, close) + return this + end end end @@ -333,7 +341,7 @@ function wait(fd::RawFD; readable=false, writable=false) end end -@windows_only begin +if is_windows() function wait(socket::WindowsRawSocket; readable=false, writable=false) fdw = _FDWatcher(socket, readable, writable) try @@ -358,7 +366,7 @@ function wait(m::FileMonitor) return filename, events end -function poll_fd(s::Union{RawFD, @windows ? WindowsRawSocket : Union{}}, timeout_s::Real=-1; readable=false, writable=false) +function poll_fd(s::Union{RawFD, is_windows() ? WindowsRawSocket : Union{}}, timeout_s::Real=-1; readable=false, writable=false) wt = Condition() fdw = _FDWatcher(s, readable, writable) try diff --git a/base/process.jl b/base/process.jl index b5f97b1f65ba7..c210f0d563989 100644 --- a/base/process.jl +++ b/base/process.jl @@ -137,7 +137,7 @@ immutable FileRedirect filename::AbstractString append::Bool function FileRedirect(filename, append) - if lowercase(filename) == (@unix? "/dev/null" : "nul") + if lowercase(filename) == (@static is_windows() ? "nul" : "/dev/null") warn_once("for portability use DevNull instead of a file redirect") end new(filename, append) diff --git a/base/profile.jl b/base/profile.jl index 3865c60588955..dbb49823df2f8 100644 --- a/base/profile.jl +++ b/base/profile.jl @@ -53,7 +53,11 @@ end # init with default values # Use a max size of 1M profile samples, and fire timer every 1ms -@windows? (__init__() = init(1_000_000, 0.01)) : (__init__() = init(1_000_000, 0.001)) +if is_windows() + __init__() = init(1_000_000, 0.01) +else + __init__() = init(1_000_000, 0.001) +end """ clear() @@ -204,9 +208,7 @@ end # Number of backtrace "steps" that are triggered by taking the backtrace, e.g., inside profile_bt -# May be platform-specific? -#@unix_only const btskip = 2 -#@windows_only const btskip = 0 +# TODO: may be platform-specific? const btskip = 0 ## Print as a flat list diff --git a/base/random.jl b/base/random.jl index 81b147cd56247..fe781c07259a3 100644 --- a/base/random.jl +++ b/base/random.jl @@ -27,18 +27,7 @@ type Close1Open2 <: FloatInterval end ## RandomDevice -@unix_only begin - immutable RandomDevice <: AbstractRNG - file::IOStream - - RandomDevice(unlimited::Bool=true) = new(open(unlimited ? "/dev/urandom" : "/dev/random")) - end - - rand{ T<:Union{Bool, Base.BitInteger}}(rd::RandomDevice, ::Type{T}) = read( rd.file, T) - rand!{T<:Union{Bool, Base.BitInteger}}(rd::RandomDevice, A::Array{T}) = read!(rd.file, A) -end - -@windows_only begin +if is_windows() immutable RandomDevice <: AbstractRNG buffer::Vector{UInt128} @@ -51,7 +40,16 @@ end end rand!{T<:Union{Bool, Base.BitInteger}}(rd::RandomDevice, A::Array{T}) = (win32_SystemFunction036!(A); A) -end +else # !windows + immutable RandomDevice <: AbstractRNG + file::IOStream + + RandomDevice(unlimited::Bool=true) = new(open(unlimited ? "/dev/urandom" : "/dev/random")) + end + + rand{ T<:Union{Bool, Base.BitInteger}}(rd::RandomDevice, ::Type{T}) = read( rd.file, T) + rand!{T<:Union{Bool, Base.BitInteger}}(rd::RandomDevice, A::Array{T}) = read!(rd.file, A) +end # os-test rand(rng::RandomDevice, ::Type{Close1Open2}) = reinterpret(Float64, 0x3ff0000000000000 | rand(rng, UInt64) & 0x000fffffffffffff) diff --git a/base/sharedarray.jl b/base/sharedarray.jl index 3e0e5ad50e941..1e29d61cd7c00 100644 --- a/base/sharedarray.jl +++ b/base/sharedarray.jl @@ -477,8 +477,13 @@ complex(S1::SharedArray,S2::SharedArray) = convert(SharedArray, complex(S1.s, S2 function print_shmem_limits(slen) try - @linux_only pfx = "kernel" - @osx_only pfx = "kern.sysv" + if is_linux() + pfx = "kernel" + elseif is_apple() + pfx = "kern.sysv" + else + return + end shmmax_MB = div(parse(Int, split(readstring(`sysctl $(pfx).shmmax`))[end]), 1024*1024) page_size = parse(Int, split(readstring(`getconf PAGE_SIZE`))[end]) @@ -521,8 +526,18 @@ end # platform-specific code -@unix_only begin +if is_windows() +function _shm_mmap_array(T, dims, shm_seg_name, mode) + readonly = !((mode & JL_O_RDWR) == JL_O_RDWR) + create = (mode & JL_O_CREAT) == JL_O_CREAT + s = Mmap.Anonymous(shm_seg_name, readonly, create) + Mmap.mmap(s, Array{T,length(dims)}, dims, zero(Int64)) +end + +# no-op in windows +shm_unlink(shm_seg_name) = 0 +else # !windows function _shm_mmap_array(T, dims, shm_seg_name, mode) fd_mem = shm_open(shm_seg_name, mode, S_IRUSR | S_IWUSR) systemerror("shm_open() failed for " * shm_seg_name, fd_mem < 0) @@ -542,18 +557,4 @@ end shm_unlink(shm_seg_name) = ccall(:shm_unlink, Cint, (Cstring,), shm_seg_name) shm_open(shm_seg_name, oflags, permissions) = ccall(:shm_open, Cint, (Cstring, Cint, Cmode_t), shm_seg_name, oflags, permissions) -end # @unix_only - -@windows_only begin - -function _shm_mmap_array(T, dims, shm_seg_name, mode) - readonly = !((mode & JL_O_RDWR) == JL_O_RDWR) - create = (mode & JL_O_CREAT) == JL_O_CREAT - s = Mmap.Anonymous(shm_seg_name, readonly, create) - Mmap.mmap(s, Array{T,length(dims)}, dims, zero(Int64)) -end - -# no-op in windows -shm_unlink(shm_seg_name) = 0 - -end # @windows_only +end # os-test diff --git a/base/socket.jl b/base/socket.jl index 135d0dffb9ddc..181cdf821ab90 100644 --- a/base/socket.jl +++ b/base/socket.jl @@ -778,7 +778,7 @@ function getsockname(sock::Union{TCPServer,TCPSocket}) addrv4 = raddress[1:4] naddr = ntoh(unsafe_load(Ptr{Cuint}(pointer(addrv4)), 1)) addr = IPv4(naddr) - elseif rfamily[] == @windows? 23 : (@osx? 30 : 10) # AF_INET6 + elseif rfamily[] == @static is_windows() ? 23 : (@static is_apple() ? 30 : 10) # AF_INET6 naddr = ntoh(unsafe_load(Ptr{UInt128}(pointer(raddress)), 1)) addr = IPv6(naddr) else diff --git a/base/stream.jl b/base/stream.jl index bec5b1117e024..42c1655418cd4 100644 --- a/base/stream.jl +++ b/base/stream.jl @@ -1,7 +1,9 @@ # This file is a part of Julia. License is MIT: http://julialang.org/license import .Libc: RawFD, dup -@windows_only import .Libc: WindowsRawSocket +if is_windows() + import .Libc: WindowsRawSocket +end ## types ## typealias Callback Union{Function,Bool} @@ -164,7 +166,7 @@ type TTY <: LibuvStream sendbuf::Nullable{IOBuffer} lock::ReentrantLock throttle::Int - @windows_only ispty::Bool + @static if is_windows(); ispty::Bool; end function TTY(handle) tty = new( handle, @@ -175,8 +177,10 @@ type TTY <: LibuvStream false,Condition(), nothing, ReentrantLock(), DEFAULT_READ_BUFFER_SZ) - @windows_only tty.ispty = ccall(:jl_ispty, Cint, (Ptr{Void},), handle)!=0 - tty + @static if is_windows() + tty.ispty = ccall(:jl_ispty, Cint, (Ptr{Void},), handle) != 0 + end + return tty end end @@ -190,7 +194,7 @@ function TTY(fd::RawFD; readable::Bool = false) uv_error("TTY",ccall(:uv_tty_init,Int32,(Ptr{Void},Ptr{Void},Int32,Int32),eventloop(),handle,fd.fd,readable)) ret.status = StatusOpen ret.line_buffered = false - ret + return ret end show(io::IO,stream::LibuvServer) = print(io, typeof(stream), "(", uv_status_string(stream), ")") @@ -325,7 +329,7 @@ function close(stream::Union{LibuvStream, LibuvServer}) nothing end -@windows_only begin +if is_windows() ispty(s::TTY) = s.ispty ispty(s::IO) = false end @@ -340,15 +344,17 @@ function displaysize(io::TTY) local h::Int, w::Int default_size = displaysize() - @windows_only if ispty(io) - # io is actually a libuv pipe but a cygwin/msys2 pty - try - h, w = map(x -> parse(Int, x), split(readstring(open(Base.Cmd(String["stty", "size"]), "r", io)[1]))) - h > 0 || (h = default_size[1]) - w > 0 || (w = default_size[2]) - return h, w - catch - return default_size + @static if is_windows() + if ispty(io) + # io is actually a libuv pipe but a cygwin/msys2 pty + try + h, w = map(x -> parse(Int, x), split(readstring(open(Base.Cmd(String["stty", "size"]), "r", io)[1]))) + h > 0 || (h = default_size[1]) + w > 0 || (w = default_size[2]) + return h, w + catch + return default_size + end end end @@ -950,20 +956,28 @@ end connect(path::AbstractString) = connect(init_pipe!(PipeEndpoint(); readable=false, writable=false, julia_only=true),path) _fd(x::IOStream) = RawFD(fd(x)) -@unix_only _fd(x::LibuvStream) = RawFD(ccall(:jl_uv_handle,Int32,(Ptr{Void},),x.handle)) -@windows_only _fd(x::LibuvStream) = WindowsRawSocket( - ccall(:jl_uv_handle,Ptr{Void},(Ptr{Void},),x.handle)) +if is_windows() + _fd(x::LibuvStream) = WindowsRawSocket( + ccall(:jl_uv_handle, Ptr{Void}, (Ptr{Void},), x.handle)) +else + _fd(x::LibuvStream) = RawFD(ccall(:jl_uv_handle, Int32, (Ptr{Void},), x.handle)) +end -for (x,writable,unix_fd,c_symbol) in ((:STDIN,false,0,:jl_uv_stdin),(:STDOUT,true,1,:jl_uv_stdout),(:STDERR,true,2,:jl_uv_stderr)) +for (x, writable, unix_fd, c_symbol) in + ((:STDIN, false, 0, :jl_uv_stdin), + (:STDOUT, true, 1, :jl_uv_stdout), + (:STDERR, true, 2, :jl_uv_stderr)) f = Symbol("redirect_",lowercase(string(x))) _f = Symbol("_",f) @eval begin function ($_f)(stream) global $x - @windows? ( + @static if is_windows() ccall(:SetStdHandle,stdcall,Int32,(Int32,Ptr{Void}), - $(-10-unix_fd), Libc._get_osfhandle(_fd(stream)).handle) ) : ( - dup(_fd(stream), RawFD($unix_fd)) ) + $(-10 - unix_fd), Libc._get_osfhandle(_fd(stream)).handle) + else + dup(_fd(stream), RawFD($unix_fd)) + end $x = stream end function ($f)(handle::Union{LibuvStream,IOStream}) diff --git a/base/util.jl b/base/util.jl index 82a4396c581bc..6cce7d565cb07 100644 --- a/base/util.jl +++ b/base/util.jl @@ -255,7 +255,9 @@ function blas_set_num_threads(n::Integer) end # OSX BLAS looks at an environment variable - @osx_only ENV["VECLIB_MAXIMUM_THREADS"] = n + @static if is_apple() + ENV["VECLIB_MAXIMUM_THREADS"] = n + end return nothing end diff --git a/doc/manual/handling-operating-system-variation.rst b/doc/manual/handling-operating-system-variation.rst index aa81937a64dc6..6a37ea5e75a8c 100644 --- a/doc/manual/handling-operating-system-variation.rst +++ b/doc/manual/handling-operating-system-variation.rst @@ -6,33 +6,31 @@ When dealing with platform libraries, it is often necessary to provide special cases for various platforms. The variable ``OS_NAME`` can be used to write these special -cases. There are several macros intended to make this easier: ``@windows_only``, -``@unix_only``, ``@linux_only``, and ``@osx_only``. These may be used as follows:: +cases. There are several functions intended to make this easier: +``is_unix``, ``is_linux``, ``is_apple``, ``is_bsd``, and ``is_windows``. These may be used as follows:: - @windows_only begin + if is_windows() some_complicated_thing(a) end -Note that ``@linux_only`` and ``@osx_only`` are mutually exclusive subsets of ``@unix_only``\ . (This -similarly applies to ``@unix``\ .) -Additionally, there are:``@windows``, ``@unix``, ``@linux``, and ``@osx``. Their usage takes -the form of a ternary conditional operator, as demonstrated in the following examples. +Note that ``is_linux`` and ``is_apple`` are mutually exclusive subsets of ``is_unix``\ . +Additionally, there is a macro ``@static`` which makes it possible to +use these functions to conditionally hide invalid code, as demonstrated in the following examples. Simple blocks:: - ccall( (@windows? :_fopen : :fopen), ...) + ccall( (@static is_windows() ? :_fopen : :fopen), ...) Complex blocks:: - @linux? ( - begin - some_complicated_thing(a) - end - : begin - some_different_thing(a) - end - ) + @static if is_linux() + some_complicated_thing(a) + else + some_different_thing(a) + end -Chaining (parentheses optional, but recommended for readability):: +When chaining conditionals (including if/elseif/end), +the `@static` must be repeated for each level +(parentheses optional, but recommended for readability):: - @windows? :a : (@osx? :b : :c) + @static is_windows() ? :a : (@static is_apple() ? :b : :c) diff --git a/doc/stdlib/base.rst b/doc/stdlib/base.rst index 5d47c1f0f2dfa..24a3fc3a7f342 100644 --- a/doc/stdlib/base.rst +++ b/doc/stdlib/base.rst @@ -975,53 +975,43 @@ System Reference to the singleton ``EnvHash``, providing a dictionary interface to system environment variables. -.. function:: @unix +.. function:: is_unix([os]) .. Docstring generated from Julia source - Given ``@unix? a : b``\ , do ``a`` on Unix systems (including Linux and OS X) and ``b`` elsewhere. See documentation in :ref:`Handling Operating System Variation `\ . + Predicate for testing if the OS provides a Unix-like interface. See documentation :ref:``Handling Operating System Variation `` . -.. function:: @unix_only +.. function:: is_apple([os]) .. Docstring generated from Julia source - A macro that evaluates the given expression only on Unix systems (including Linux and OS X). See documentation in :ref:`Handling Operating System Variation `\ . + Predicate for testing if the OS is a derivative of Apple Macintosh OS X or Darwin. See documentation :ref:``Handling Operating System Variation `` . -.. function:: @osx +.. function:: is_linux([os]) .. Docstring generated from Julia source - Given ``@osx? a : b``\ , do ``a`` on OS X and ``b`` elsewhere. See documentation in :ref:`Handling Operating System Variation `\ . + Predicate for testing if the OS is a derivative of Linux. See documentation :ref:``Handling Operating System Variation `` . -.. function:: @osx_only +.. function:: is_bsd([os]) .. Docstring generated from Julia source - A macro that evaluates the given expression only on OS X systems. See documentation in :ref:`Handling Operating System Variation `\ . + Predicate for testing if the OS is a derivative of BSD. See documentation :ref:``Handling Operating System Variation `` . -.. function:: @linux +.. function:: windows_version() .. Docstring generated from Julia source - Given ``@linux? a : b``\ , do ``a`` on Linux and ``b`` elsewhere. See documentation :ref:`Handling Operating System Variation `\ . + Returns the version number for the Windows NT Kernel as a (major, minor) pair, or (0, 0) if this is not running on Windows. -.. function:: @linux_only +.. function:: @static .. Docstring generated from Julia source - A macro that evaluates the given expression only on Linux systems. See documentation in :ref:`Handling Operating System Variation `\ . + Partially evaluates an expression at parse time. -.. function:: @windows - - .. Docstring generated from Julia source - - Given ``@windows? a : b``\ , do ``a`` on Windows and ``b`` elsewhere. See documentation in :ref:`Handling Operating System Variation `\ . - -.. function:: @windows_only - - .. Docstring generated from Julia source - - A macro that evaluates the given expression only on Windows systems. See documentation in :ref:`Handling Operating System Variation `\ . + For example, ``@static is_windows() ? foo : bar`` will evaluate ``is_windows()`` and insert either ``foo`` or ``bar`` into the expression. This is useful in cases where a construct would be invalid on other platforms, such as a ccall to a non-existant functions. Errors ------ diff --git a/doc/stdlib/constants.rst b/doc/stdlib/constants.rst index 2ee60422d030a..5fd6fa7299500 100644 --- a/doc/stdlib/constants.rst +++ b/doc/stdlib/constants.rst @@ -12,7 +12,7 @@ Constants .. data:: OS_NAME A symbol representing the name of the operating system. Possible values - are ``:Linux``, ``:Darwin`` (OS X), or ``:Windows``. + include ``:Linux``, ``:Darwin`` (Apple OS X), and ``:Windows`` (NT). .. data:: PROGRAM_FILE diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index c5b8dcee08474..fffb51223f52c 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -58,11 +58,11 @@ let exename = `$(Base.julia_cmd()) --precompiled=yes` # --cpu-target # NOTE: this test only holds true when there is a sys.{dll,dylib,so} shared library present. - # The tests are also limited to unix platforms at the moment because loading the system image - # not turned on for Window's binary builds at the moment. - @unix_only if Libdl.dlopen_e(splitext(bytestring(Base.JLOptions().image_file))[1]) != C_NULL - @test !success(`$exename -C invalidtarget`) - @test !success(`$exename --cpu-target=invalidtarget`) + if Libdl.dlopen_e(splitext(bytestring(Base.JLOptions().image_file))[1]) != C_NULL + @test !success(`$exename -C invalidtarget --precompiled=yes`) + @test !success(`$exename --cpu-target=invalidtarget --precompiled=yes`) + else + warn("--cpu-target test not runnable") end # --procs @@ -165,23 +165,24 @@ let exename = `$(Base.julia_cmd()) --precompiled=yes` @test !success(`$exename -E "$code" --depwarn=error`) - # FIXME these should also be run on windows once the bug causing them to hang gets fixed - @unix_only let out = Pipe(), - proc = spawn(pipeline(`$exename -E "$code" --depwarn=yes`, stderr=out)) + let out = Pipe(), + proc = spawn(pipeline(`$exename -E "$code" --depwarn=yes`, stderr=out)), - wait(proc) + output_correct = (@async @test readchomp(out) == "WARNING: Foo.Deprecated is deprecated.\n likely near no file:5") close(out.in) + wait(proc) @test success(proc) - @test readchomp(out) == "WARNING: Foo.Deprecated is deprecated.\n likely near no file:5" + @test output_correct end - @unix_only let out = Pipe(), - proc = spawn(pipeline(`$exename -E "$code" --depwarn=no`, stderr=out)) + let out = Pipe(), + proc = spawn(pipeline(`$exename -E "$code" --depwarn=no`, stderr=out)) + output_correct = @async @test isempty(readstring(out)) wait(proc) close(out.in) @test success(proc) - @test isempty(readstring(out)) + @test output_correct end end @@ -252,7 +253,7 @@ let exename = `$(Base.julia_cmd()) --precompiled=yes` @test readchomp(`$exename -e 'println(ARGS);' ''`) == "String[\"\"]" # issue #12679 - extrapath = @windows? joinpath(JULIA_HOME,"..","Git","usr","bin")*";" : "" + extrapath = is_windows() ? joinpath(JULIA_HOME, "..", "Git", "usr", "bin") * ";" : "" withenv("PATH" => extrapath * ENV["PATH"]) do @test readchomp(pipeline(ignorestatus(`$exename -f --compile=yes -foo`),stderr=`cat`)) == "ERROR: unknown option `-o`" @test readchomp(pipeline(ignorestatus(`$exename -f -p`),stderr=`cat`)) == "ERROR: option `-p/--procs` is missing an argument" @@ -267,7 +268,7 @@ let exename = `$(Base.julia_cmd()) --precompiled=yes` @test !success(`$exename --compilecache=foo -e "exit(0)"`) # issue #12671, starting from a non-directory - @unix_only if VersionNumber(Base.libllvm_version) > v"3.3" + if VersionNumber(Base.libllvm_version) > v"3.3" testdir = mktempdir() cd(testdir) do rm(testdir) diff --git a/test/core.jl b/test/core.jl index bbc2af9db4d35..5fa12d4068563 100644 --- a/test/core.jl +++ b/test/core.jl @@ -2189,7 +2189,7 @@ let x = [1,2,3] end # sig 2 is SIGINT per the POSIX.1-1990 standard -@unix_only begin +if !is_windows() ccall(:jl_exit_on_sigint, Void, (Cint,), 0) @test_throws InterruptException begin ccall(:kill, Void, (Cint, Cint,), getpid(), 2) diff --git a/test/dates/conversions.jl b/test/dates/conversions.jl index 630207f4de063..3706c9ef96aa7 100644 --- a/test/dates/conversions.jl +++ b/test/dates/conversions.jl @@ -47,8 +47,10 @@ @test typeof(Dates.today()) <: Dates.Date @test typeof(Dates.now(Dates.UTC)) <: Dates.DateTime -@osx_only withenv("TZ" => "UTC") do - @test abs(Dates.now() - now(Dates.UTC)) < Dates.Second(1) +if is_apple() + withenv("TZ" => "UTC") do + @test abs(Dates.now() - now(Dates.UTC)) < Dates.Second(1) + end end @test abs(Dates.now() - now(Dates.UTC)) < Dates.Hour(16) diff --git a/test/examples.jl b/test/examples.jl index d074301bb10b9..223ad47c52561 100644 --- a/test/examples.jl +++ b/test/examples.jl @@ -36,7 +36,7 @@ include(joinpath(dir, "queens.jl")) # Different cluster managers do not play well together. Since # the test infrastructure already uses LocalManager, we will test the simple # cluster manager example through a new Julia session. -@unix_only begin +if is_unix() script = joinpath(dir, "clustermanager/simple/test_simple.jl") cmd = `$(Base.julia_cmd()) $script` if !success(pipeline(cmd; stdout=STDOUT, stderr=STDERR)) && ccall(:jl_running_on_valgrind,Cint,()) == 0 diff --git a/test/file.jl b/test/file.jl index 0b117f89a9be9..4e161066b29f7 100644 --- a/test/file.jl +++ b/test/file.jl @@ -24,7 +24,7 @@ let err = nothing end end -if @unix? true : (Base.windows_version() >= Base.WINDOWS_VISTA_VER) +if !is_windows() || Base.windows_version() >= Base.WINDOWS_VISTA_VER dirlink = joinpath(dir, "dirlink") symlink(subdir, dirlink) # relative link @@ -35,7 +35,7 @@ if @unix? true : (Base.windows_version() >= Base.WINDOWS_VISTA_VER) cd(pwd_) end -@unix_only begin +if !is_windows() link = joinpath(dir, "afilelink.txt") symlink(file, link) # relative link @@ -65,7 +65,7 @@ chmod(file, filemode(file) | 0o222) @test filemode(file) & 0o111 == 0 @test filesize(file) == 0 -@windows_only begin +if is_windows() permissions = 0o444 @test filemode(dir) & 0o777 != permissions @test filemode(subdir) & 0o777 != permissions @@ -75,8 +75,7 @@ chmod(file, filemode(file) | 0o222) @test filemode(subdir) & 0o777 == permissions @test filemode(file) & 0o777 == permissions chmod(dir, 0o666, recursive=true) # Reset permissions in case someone wants to use these later -end -@unix_only begin +else mktempdir() do tmpdir tmpfile=joinpath(tmpdir, "tempfile.txt") touch(tmpfile) @@ -102,8 +101,11 @@ end # On windows the filesize of a folder is the accumulation of all the contained # files and is thus zero in this case. -@windows_only @test filesize(dir) == 0 -@unix_only @test filesize(dir) > 0 +if is_windows() + @test filesize(dir) == 0 +else + @test filesize(dir) > 0 +end now = time() # Allow 10s skew in addition to the time it took us to actually execute this code let skew = 10 + (now - starttime) @@ -114,13 +116,15 @@ end #@test Int(time()) >= Int(mtime(file)) >= Int(mtime(dir)) >= 0 # 1 second accuracy should be sufficient # test links -@unix_only @test islink(link) == true -@unix_only @test readlink(link) == file +if is_unix() + @test islink(link) == true + @test readlink(link) == file +end -if @unix? true : (Base.windows_version() >= Base.WINDOWS_VISTA_VER) +if !is_windows() || Base.windows_version() >= Base.WINDOWS_VISTA_VER @test islink(dirlink) == true @test isdir(dirlink) == true - @test readlink(dirlink) == subdir * @windows? "\\" : "" + @test readlink(dirlink) == subdir * (is_windows() ? "\\" : "") end # rm recursive TODO add links @@ -156,23 +160,26 @@ rm(c_tmpdir, recursive=true) @test_throws Base.UVError rm(c_tmpdir, recursive=true) @test rm(c_tmpdir, force=true, recursive=true) === nothing -# chown will give an error if the user does not have permissions to change files -@unix_only if get(ENV, "USER", "") == "root" || get(ENV, "HOME", "") == "/root" - chown(file, -2, -1) # Change the file owner to nobody - @test stat(file).uid !=0 - chown(file, 0, -2) # Change the file group to nogroup (and owner back to root) - @test stat(file).gid !=0 - @test stat(file).uid ==0 - chown(file, -1, 0) - @test stat(file).gid ==0 - @test stat(file).uid ==0 +if !is_windows() + # chown will give an error if the user does not have permissions to change files + if get(ENV, "USER", "") == "root" || get(ENV, "HOME", "") == "/root" + chown(file, -2, -1) # Change the file owner to nobody + @test stat(file).uid !=0 + chown(file, 0, -2) # Change the file group to nogroup (and owner back to root) + @test stat(file).gid !=0 + @test stat(file).uid ==0 + chown(file, -1, 0) + @test stat(file).gid ==0 + @test stat(file).uid ==0 + else + @test_throws Base.UVError chown(file, -2, -1) # Non-root user cannot change ownership to another user + @test_throws Base.UVError chown(file, -1, -2) # Non-root user cannot change group to a group they are not a member of (eg: nogroup) + end else - @test_throws Base.UVError chown(file, -2, -1) # Non-root user cannot change ownership to another user - @test_throws Base.UVError chown(file, -1, -2) # Non-root user cannot change group to a group they are not a member of (eg: nogroup) + # test that chown doesn't cause any errors for Windows + @test chown(file, -2, -2) == nothing end -@windows_only @test chown(file, -2, -2) == nothing # chown shouldn't cause any errors for Windows - ####################################################################### # This section tests file watchers. # ####################################################################### @@ -279,8 +286,11 @@ my_tempdir = tempdir() path = tempname() # Issue #9053. -@unix_only @test ispath(path) == false -@windows_only @test ispath(path) == true +if is_windows() + @test ispath(path) == true +else + @test ispath(path) == false +end (p, f) = mktemp() print(f, "Here is some text") @@ -445,7 +455,7 @@ end # issue #10506 #10434 ## Tests for directories and links to directories -if @unix? true : (Base.windows_version() >= Base.WINDOWS_VISTA_VER) +if !is_windows() || Base.windows_version() >= Base.WINDOWS_VISTA_VER function setup_dirs(tmpdir) srcdir = joinpath(tmpdir, "src") hidden_srcdir = joinpath(tmpdir, ".hidden_srcdir") @@ -655,7 +665,7 @@ end # issue #10506 #10434 ## Tests for files and links to files as well as directories and links to directories -@unix_only begin +if !is_windows() function setup_files(tmpdir) srcfile = joinpath(tmpdir, "srcfile.txt") hidden_srcfile = joinpath(tmpdir, ".hidden_srcfile.txt") @@ -881,15 +891,19 @@ function test_LibcFILE(FILEp) close(FILEp) end -f = open(file, "w") -write(f, "Hello, world!") -close(f) -f = open(file, "r") -test_LibcFILE(convert(Libc.FILE, f)) -close(f) -@unix_only f = RawFD(ccall(:open, Cint, (Ptr{UInt8}, Cint), file, Base.Filesystem.JL_O_RDONLY)) -@windows_only f = RawFD(ccall(:_open, Cint, (Ptr{UInt8}, Cint), file, Base.Filesystem.JL_O_RDONLY)) -test_LibcFILE(Libc.FILE(f,Libc.modestr(true,false))) +let f = open(file, "w") + write(f, "Hello, world!") + close(f) + f = open(file, "r") + test_LibcFILE(convert(Libc.FILE, f)) + close(f) + if is_windows() + f = RawFD(ccall(:_open, Cint, (Ptr{UInt8}, Cint), file, Base.Filesystem.JL_O_RDONLY)) + else + f = RawFD(ccall(:open, Cint, (Ptr{UInt8}, Cint), file, Base.Filesystem.JL_O_RDONLY)) + end + test_LibcFILE(Libc.FILE(f, Libc.modestr(true, false))) +end # issue #10994: pathnames cannot contain embedded NUL chars for f in (mkdir, cd, Base.Filesystem.unlink, readlink, rm, touch, readdir, mkpath, stat, lstat, ctime, mtime, filemode, filesize, uperm, gperm, operm, touch, isblockdev, ischardev, isdir, isfifo, isfile, islink, ispath, issetgid, issetuid, issocket, issticky, realpath, watch_file, poll_file) @@ -899,7 +913,7 @@ end @test_throws ArgumentError open("ba\0d", "w") @test_throws ArgumentError cp(file, "ba\0d") @test_throws ArgumentError mv(file, "ba\0d") -if @unix? true : (Base.windows_version() >= Base.WINDOWS_VISTA_VER) +if !is_windows() || (Base.windows_version() >= Base.WINDOWS_VISTA_VER) @test_throws ArgumentError symlink(file, "ba\0d") else @test_throws ErrorException symlink(file, "ba\0d") @@ -921,7 +935,7 @@ cd(dirwalk) do touch(joinpath("sub_dir1", "file$i")) end touch(joinpath("sub_dir2", "file_dir2")) - has_symlinks = @unix? true : (Base.windows_version() >= Base.WINDOWS_VISTA_VER) + has_symlinks = !is_windows() || (Base.windows_version() >= Base.WINDOWS_VISTA_VER) follow_symlink_vec = has_symlinks ? [true, false] : [false] has_symlinks && symlink(abspath("sub_dir2"), joinpath("sub_dir1", "link")) for follow_symlinks in follow_symlink_vec @@ -1010,11 +1024,11 @@ rm(dirwalk, recursive=true) ############ # Clean up # ############ -@unix_only begin +if !is_windows() rm(link) rm(rellink) end -if @unix? true : (Base.windows_version() >= Base.WINDOWS_VISTA_VER) +if !is_windows() || (Base.windows_version() >= Base.WINDOWS_VISTA_VER) rm(dirlink) rm(relsubdirlink) end @@ -1023,9 +1037,14 @@ rm(subdir) rm(subdir2) rm(dir) -# The following fail on Windows with "stat: operation not permitted (EPERM)" -@unix_only @test !ispath(file) -@unix_only @test !ispath(dir) +if is_windows() + # The following fail on Windows with "stat: operation not permitted (EPERM)" + @test_throws Base.UVError !ispath(file) + @test_throws Base.UVError !ispath(dir) +else + @test !ispath(file) + @test !ispath(dir) +end # issue #9687 let n = tempname() @@ -1077,6 +1096,7 @@ test2_12992() # issue 13559 +if !is_windows() function test_13559() fn = tempname() run(`mkfifo $fn`) @@ -1094,4 +1114,5 @@ function test_13559() close(r) rm(fn) end -@unix_only test_13559() +test_13559() +end diff --git a/test/libdl.jl b/test/libdl.jl index 0b89589588de1..de196335ea839 100644 --- a/test/libdl.jl +++ b/test/libdl.jl @@ -5,7 +5,7 @@ dlls = Libdl.dllist() @test !isempty(dlls) @test length(dlls) > 3 # at a bare minimum, probably have some version of libstdc, libgcc, libjulia, ... -if @unix? true : (Base.windows_version() >= Base.WINDOWS_VISTA_VER) +if !is_windows() || Base.windows_version() >= Base.WINDOWS_VISTA_VER for dl in dlls if isfile(dl) && (Libdl.dlopen_e(dl) != C_NULL) @test Base.samefile(Libdl.dlpath(dl), dl) diff --git a/test/misc.jl b/test/misc.jl index 7b6cc4d8e0697..537fb54ba9b12 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -194,7 +194,11 @@ end @test Base.is_unix(:Darwin) @test Base.is_unix(:FreeBSD) @test_throws ArgumentError Base.is_unix(:BeOS) -@unix_only @test Base.windows_version() == (0,0) +if !is_windows() + @test Base.windows_version() === (0, 0) +else + @test (Base.windows_version()::Tuple{Int,Int})[1] > 0 +end # Issue 14173 module Tmp14173 @@ -373,11 +377,13 @@ for (X,Y,Z) in ((V16,V16,V16), (I16,V16,I16), (V16,I16,V16), (V16,V16,I16), (I16 end # clipboard functionality -@windows_only for str in ("Hello, world.","∀ x ∃ y","") - clipboard(str) - @test clipboard() == str +if is_windows() + for str in ("Hello, world.", "∀ x ∃ y", "") + clipboard(str) + @test clipboard() == str + end end -optstring = sprint(show,Base.JLOptions()) -@test startswith(optstring,"JLOptions(") -@test endswith(optstring,")") +optstring = sprint(show, Base.JLOptions()) +@test startswith(optstring, "JLOptions(") +@test endswith(optstring, ")") diff --git a/test/parallel_exec.jl b/test/parallel_exec.jl index df929bbbc7557..9d234deea7c0b 100644 --- a/test/parallel_exec.jl +++ b/test/parallel_exec.jl @@ -223,7 +223,7 @@ test_indexing(RemoteChannel(id_other)) dims = (20,20,20) -@linux_only begin +if is_linux() S = SharedArray(Int64, dims) @test startswith(S.segname, "/jl") @test !ispath("/dev/shm" * S.segname) @@ -354,7 +354,8 @@ read!(fn3, filedata) @test all(filedata[1:4] .== 0x01) @test all(filedata[5:end] .== 0x02) -@unix_only begin # these give unlink: operation not permitted (EPERM) on Windows +if !is_windows() + # these give unlink: operation not permitted (EPERM) on Windows rm(fn); rm(fn2); rm(fn3) end @@ -772,7 +773,7 @@ if DoFullTest fetch(@spawnat myid() myid()) end -@unix_only begin +if is_unix() # aka have ssh function test_n_remove_pids(new_pids) for p in new_pids w_in_remote = sort(remotecall_fetch(workers, p)) @@ -832,8 +833,8 @@ if DoFullTest end) @test length(new_pids) == num_workers test_n_remove_pids(new_pids) -end # @unix_only -end +end # unix-only +end # full-test # issue #7727 let A = [], B = [] diff --git a/test/path.jl b/test/path.jl index c9db47528c8f1..f6d795cb377aa 100644 --- a/test/path.jl +++ b/test/path.jl @@ -1,10 +1,20 @@ # This file is a part of Julia. License is MIT: http://julialang.org/license -@unix_only @test expanduser("~")[1] != ENV["HOME"] - -@unix_only @test isabspath("/") == true @test isabspath("~") == false -@unix_only @test isabspath(expanduser("~")) == true +@test isabspath("/") == !is_windows() +@test isabspath("A:/") == is_windows() +@test isabspath("B:\\") == is_windows() +@test isabspath("C:") == false +@test isabspath("α:/") == false +@test isabspath(".:/") == false +#@test isabspath("_:/") == false # FIXME! +@test isabspath("\\\\") == is_windows() +if is_unix() + @test isabspath(expanduser("~")) == true + @test startswith(expanduser("~"), homedir()) +else + @test expanduser("~") == "~" +end ############################################ # This section tests relpath computation. # diff --git a/test/perf/micro/perf.jl b/test/perf/micro/perf.jl index 57a915dee31ed..72d6c7b4c237a 100644 --- a/test/perf/micro/perf.jl +++ b/test/perf/micro/perf.jl @@ -138,11 +138,11 @@ end ## printfd ## -@unix_only begin +if is_unix() function printfd(n) - open("/dev/null","w") do io + open("/dev/null", "w") do io for i = 1:n - @printf(io,"%d %d\n",i,i+1) + @printf(io, "%d %d\n", i, i + 1) end end end diff --git a/test/perf/perfutil.jl b/test/perf/perfutil.jl index 1974c337c96b2..099f047829722 100644 --- a/test/perf/perfutil.jl +++ b/test/perf/perfutil.jl @@ -97,6 +97,7 @@ macro timeit_init(ex,init,name,desc,group...) end function maxrss(name) + # FIXME: call uv_getrusage instead here @linux_only begin rus = Array(Int64, div(144,8)) fill!(rus, 0x0) diff --git a/test/pollfd.jl b/test/pollfd.jl index 1c0a178fd737c..a151b42dd663a 100644 --- a/test/pollfd.jl +++ b/test/pollfd.jl @@ -13,10 +13,10 @@ intvls = [2, .2, .1, .005] pipe_fds = cell(n) for i in 1:n - @windows ? begin + @static if is_windows() pipe_fds[i] = Array(Libc.WindowsRawSocket, 2) 0 == ccall(:wsasocketpair, Cint, (Cint, Cuint, Cint, Ptr{Libc.WindowsRawSocket}), 1, 1, 6, pipe_fds[i]) || error(Libc.FormatMessage()) - end : begin + else pipe_fds[i] = Array(RawFD, 2) @test 0 == ccall(:pipe, Cint, (Ptr{RawFD},), pipe_fds[i]) end @@ -30,18 +30,18 @@ function pfd_tst_reads(idx, intvl) t_elapsed = toq() @test !evt.timedout @test evt.readable - @test @windows ? evt.writable : !evt.writable + @test is_windows() ? evt.writable : !evt.writable # println("Expected ", intvl, ", actual ", t_elapsed, ", diff ", t_elapsed - intvl) # Disabled since this assertion fails randomly, notably on build VMs (issue #12824) # @test t_elapsed <= (intvl + 1) dout = Array(UInt8, 1) - @windows ? ( + @static if is_windows() 1 == ccall(:recv, stdcall, Cint, (Ptr{Void}, Ptr{UInt8}, Cint, Cint), pipe_fds[idx][1], dout, 1, 0) || error(Libc.FormatMessage()) - ) : ( + else @test 1 == ccall(:read, Csize_t, (Cint, Ptr{UInt8}, Csize_t), pipe_fds[idx][1], dout, 1) - ) + end @test dout[1] == Int8('A') end @@ -57,8 +57,8 @@ function pfd_tst_timeout(idx, intvl) t_elapsed = toq() # Disabled since these assertions fail randomly, notably on build VMs (issue #12824) - # @unix_only @test (intvl <= t_elapsed) # TODO: enable this test on windows when the libuv version is bumped - # @test (t_elapsed <= (intvl + 1)) + # @test intvl <= t_elapsed + # @test t_elapsed <= (intvl + 1) end @@ -87,11 +87,11 @@ for (i, intvl) in enumerate(intvls) @test event.writable if isodd(idx) - @windows ? ( - 1 == ccall(:send, stdcall, Cint, (Ptr{Void}, Ptr{UInt8}, Cint, Cint), pipe_fds[idx][2], "A", 1, 0) || error(Libc.FormatMessage()) - ) : ( - @test 1 == ccall(:write, Csize_t, (Cint, Ptr{UInt8}, Csize_t), pipe_fds[idx][2], "A", 1) - ) + @static if is_windows() + 1 == ccall(:send, stdcall, Cint, (Ptr{Void}, Ptr{UInt8}, Cint, Cint), pipe_fds[idx][2], "A", 1, 0) || error(Libc.FormatMessage()) + else + @test 1 == ccall(:write, Csize_t, (Cint, Ptr{UInt8}, Csize_t), pipe_fds[idx][2], "A", 1) + end end end notify(ready_c, all=true) @@ -100,11 +100,11 @@ end for i in 1:n for j = 1:2 - @windows ? ( + @static if is_windows() 0 == ccall(:closesocket, stdcall, Cint, (Ptr{Void},), pipe_fds[i][j]) || error(Libc.FormatMessage()) - ) : ( + else @test 0 == ccall(:close, Cint, (Cint,), pipe_fds[i][j]) - ) + end end end diff --git a/test/read.jl b/test/read.jl index bf39dc23265c3..fb4a77625a321 100644 --- a/test/read.jl +++ b/test/read.jl @@ -83,7 +83,7 @@ push!(l, ("TCPSocket", io)) io = (text) -> begin a = "\\\\.\\pipe\\uv-test-$(randstring(6))" b = joinpath(dir, "socket-$(randstring(6))") - socketname = @windows ? a : b + socketname = is_windows() ? a : b srv = listen(socketname) run_test_server(srv, text) connect(socketname) @@ -98,7 +98,7 @@ push!(l, ("PipeEndpoint", io)) #FIXME See https://github.com/JuliaLang/julia/issues/14747 # Reading from open(::Command) seems to deadlock on Linux/Travis #= -@windows ? nothing : begin +if !is_windows() # Windows type command not working? # See "could not spawn `type 'C:\Users\appveyor\AppData\Local\Temp\1\jul3516.tmp\file.txt'`" @@ -107,7 +107,7 @@ push!(l, ("PipeEndpoint", io)) # Pipe io = (text) -> begin write(filename, text) - open(`$(@windows ? "type" : "cat") $filename`)[1] + open(`$(is_windows() ? "type" : "cat") $filename`)[1] # Was open(`echo -n $text`)[1] # See https://github.com/JuliaLang/julia/issues/14747 end @@ -411,13 +411,14 @@ rm(f) io = Base.Filesystem.open(f, Base.Filesystem.JL_O_WRONLY | Base.Filesystem.JL_O_CREAT | Base.Filesystem.JL_O_EXCL, 0o000) @test write(io, "abc") == 3 close(io) -@unix_only if get(ENV, "USER", "") != "root" && get(ENV, "HOME", "") != "/root" +if !is_windows() && get(ENV, "USER", "") != "root" && get(ENV, "HOME", "") != "/root" # msvcrt _wchmod documentation states that all files are readable, # so we don't test that it correctly set the umask on windows @test_throws SystemError open(f) @test_throws Base.UVError Base.Filesystem.open(f, Base.Filesystem.JL_O_RDONLY) else - warn("file permissions tests skipped due to running tests as root (not recommended)") + is_windows() || warn("file permissions tests skipped due to running tests as root (not recommended)") + close(open(f)) end chmod(f, 0o400) f1 = open(f) diff --git a/test/repl.jl b/test/repl.jl index 06834cfe0d753..b086d34104616 100644 --- a/test/repl.jl +++ b/test/repl.jl @@ -28,7 +28,7 @@ ccall(:jl_exit_on_sigint, Void, (Cint,), 0) # in the mix. If verification needs to be done, keep it to the bare minimum. Basically # this should make sure nothing crashes without depending on how exactly the control # characters are being used. -if @unix? true : (Base.windows_version() >= Base.WINDOWS_VISTA_VER) +if !is_windows() || Base.windows_version() >= Base.WINDOWS_VISTA_VER stdin_write, stdout_read, stderr_read, repl = fake_repl() repl.specialdisplay = Base.REPL.REPLDisplay(repl) @@ -398,7 +398,7 @@ begin LineEdit.enter_search(s, custom_histp, true) end # Simple non-standard REPL tests -if @unix? true : (Base.windows_version() >= Base.WINDOWS_VISTA_VER) +if !is_windows() || Base.windows_version() >= Base.WINDOWS_VISTA_VER stdin_write, stdout_read, stdout_read, repl = fake_repl() panel = LineEdit.Prompt("testπ"; prompt_prefix="\e[38;5;166m", @@ -443,7 +443,7 @@ ccall(:jl_exit_on_sigint, Void, (Cint,), 1) let exename = Base.julia_cmd() # Test REPL in dumb mode -@unix_only begin +if !is_windows() const O_RDWR = Base.Filesystem.JL_O_RDWR const O_NOCTTY = Base.Filesystem.JL_O_NOCTTY @@ -481,9 +481,9 @@ let exename = Base.julia_cmd() end # Test stream mode -if @unix? true : (Base.windows_version() >= Base.WINDOWS_VISTA_VER) +if !is_windows() || Base.windows_version() >= Base.WINDOWS_VISTA_VER outs, ins, p = readandwrite(`$exename --startup-file=no --quiet`) write(ins,"1\nquit()\n") @test readstring(outs) == "1\n" end -end +end # let exename diff --git a/test/replcompletions.jl b/test/replcompletions.jl index f446004fdccbd..8ca4a0e6c5ad8 100644 --- a/test/replcompletions.jl +++ b/test/replcompletions.jl @@ -438,7 +438,7 @@ c, r, res = test_scomplete(s) # which would raise an error in the repl code. @test (String[], 0:-1, false) == test_scomplete("\$a") -@unix_only begin +if is_unix() #Assume that we can rely on the existence and accessibility of /tmp # Tests path in Julia code and closing " if it's a file @@ -589,12 +589,12 @@ let #test that it can auto complete with spaces in file/path mkdir(dir) cd(path) do open(joinpath(space_folder, "space .file"),"w") do f - s = @windows? "rm $dir_space\\\\space" : "cd $dir_space/space" + s = is_windows() ? "rm $dir_space\\\\space" : "cd $dir_space/space" c,r = test_scomplete(s) @test r == endof(s)-4:endof(s) @test "space\\ .file" in c - s = @windows? "cd(\"β $dir_space\\\\space" : "cd(\"β $dir_space/space" + s = is_windows() ? "cd(\"β $dir_space\\\\space" : "cd(\"β $dir_space/space" c,r = test_complete(s) @test r == endof(s)-4:endof(s) @test "space\\ .file\"" in c @@ -612,7 +612,7 @@ end c,r = test_complete("cd(\"folder_do_not_exist_77/file") @test length(c) == 0 -@windows_only begin +if is_windows() tmp = tempname() path = dirname(tmp) file = basename(tmp) diff --git a/test/runtests.jl b/test/runtests.jl index 969c72ee53182..c43aaebf981d2 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -69,6 +69,6 @@ cd(dirname(@__FILE__)) do runtests("compile") end - @unix_only n > 1 && rmprocs(workers(), waitfor=5.0) + is_unix() && n > 1 && rmprocs(workers(), waitfor=5.0) println(" \033[32;1mSUCCESS\033[0m") end diff --git a/test/socket.jl b/test/socket.jl index 4ccf773eacf7b..23bce17a8cc18 100644 --- a/test/socket.jl +++ b/test/socket.jl @@ -90,7 +90,7 @@ wait(port) wait(tsk) mktempdir() do tmpdir - socketname = @windows ? ("\\\\.\\pipe\\uv-test-" * randstring(6)) : joinpath(tmpdir, "socket") + socketname = is_windows() ? ("\\\\.\\pipe\\uv-test-" * randstring(6)) : joinpath(tmpdir, "socket") c = Base.Condition() tsk = @async begin s = listen(socketname) @@ -171,7 +171,7 @@ begin close(a) close(b) end -if @unix? true : (Base.windows_version() >= Base.WINDOWS_VISTA_VER) +if !is_windows() || Base.windows_version() >= Base.WINDOWS_VISTA_VER a = UDPSocket() b = UDPSocket() bind(a, ip"::1", UInt16(port)) @@ -243,7 +243,7 @@ end # Local-machine broadcast let # (Mac OS X's loopback interface doesn't support broadcasts) - bcastdst = @osx ? ip"255.255.255.255" : ip"127.255.255.255" + bcastdst = is_apple() ? ip"255.255.255.255" : ip"127.255.255.255" function create_socket() s = UDPSocket() diff --git a/test/spawn.jl b/test/spawn.jl index 0818bdcbfaa39..8d55e1288a8f7 100644 --- a/test/spawn.jl +++ b/test/spawn.jl @@ -11,10 +11,12 @@ #TODO: # - Windows: # - Add a test whether coreutils are available and skip tests if not -@windows_only oldpath = ENV["PATH"] -@windows_only ENV["PATH"] = joinpath(JULIA_HOME,"..","Git","usr","bin")*";"*oldpath +if is_windows() + oldpath = ENV["PATH"] + ENV["PATH"] = joinpath(JULIA_HOME, "..", "Git", "usr", "bin") * ";" * oldpath +end -valgrind_off = ccall(:jl_running_on_valgrind,Cint,()) == 0 +valgrind_off = ccall(:jl_running_on_valgrind, Cint, ()) == 0 yes = `perl -le 'while (1) {print STDOUT "y"}'` @@ -32,7 +34,7 @@ out = readstring(`echo hello` & `echo world`) @test (run(`printf " \033[34m[stdio passthrough ok]\033[0m\n"`); true) # Test for SIGPIPE being treated as normal termination (throws an error if broken) -@unix_only @test (run(pipeline(yes,`head`,DevNull)); true) +is_unix() && run(pipeline(yes, `head`, DevNull)) begin a = Base.Condition() @@ -80,11 +82,11 @@ run(pipeline(`echo hello world`, file)) rm(file) # Stream Redirection -@unix_only begin +let r = Channel(1) @async begin port, server = listenany(2326) - put!(r,port) + put!(r, port) client = accept(server) @test readstring(pipeline(client, `cat`)) == "hello world\n" close(server) @@ -103,9 +105,12 @@ end readstring(`sh -c "echo \$TEST"`); end) == "Hello World\n" pathA = readchomp(setenv(`sh -c "pwd -P"`;dir="..")) pathB = readchomp(setenv(`sh -c "cd .. && pwd -P"`)) -@unix_only @test Base.samefile(pathA, pathB) -# on windows, sh returns posix-style paths that are not valid according to ispath -@windows_only @test pathA == pathB +if is_windows() + # on windows, sh returns posix-style paths that are not valid according to ispath + @test pathA == pathB +else + @test Base.samefile(pathA, pathB) +end # Here we test that if we close a stream with pending writes, we don't lose the writes. str = "" @@ -336,12 +341,16 @@ end @test_throws ErrorException collect(eachline(pipeline(`cat _doesnt_exist__111_`, stderr=DevNull))) # make sure windows_verbatim strips quotes -@windows_only readstring(`cmd.exe /c dir /b spawn.jl`) == readstring(Cmd(`cmd.exe /c dir /b "\"spawn.jl\""`, windows_verbatim=true)) +if is_windows() + readstring(`cmd.exe /c dir /b spawn.jl`) == readstring(Cmd(`cmd.exe /c dir /b "\"spawn.jl\""`, windows_verbatim=true)) +end # make sure Cmd is nestable @test string(Cmd(Cmd(`ls`, detach=true))) == "`ls`" -@windows_only ENV["PATH"] = oldpath +if is_windows() + ENV["PATH"] = oldpath +end # equality tests for Cmd diff --git a/test/strings/basic.jl b/test/strings/basic.jl index 2a6a3660f376a..07df1c09cc113 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -254,12 +254,12 @@ let s = "ba\0d" @test_throws ArgumentError Base.unsafe_convert(Cwstring, wstring(s)) end -cstrdup(s) = @windows? ccall(:_strdup, Cstring, (Cstring,), s) : ccall(:strdup, Cstring, (Cstring,), s) +cstrdup(s) = @static is_windows() ? ccall(:_strdup, Cstring, (Cstring,), s) : ccall(:strdup, Cstring, (Cstring,), s) let p = cstrdup("hello") @test bytestring(p) == "hello" == pointer_to_string(cstrdup(p), true) Libc.free(p) end -let p = @windows? ccall(:_wcsdup, Cwstring, (Cwstring,), "tést") : ccall(:wcsdup, Cwstring, (Cwstring,), "tést") +let p = @static is_windows() ? ccall(:_wcsdup, Cwstring, (Cwstring,), "tést") : ccall(:wcsdup, Cwstring, (Cwstring,), "tést") @test wstring(p) == "tést" Libc.free(p) end diff --git a/test/strings/io.jl b/test/strings/io.jl index eda49201b39a8..6ef38d97b5bee 100644 --- a/test/strings/io.jl +++ b/test/strings/io.jl @@ -136,11 +136,11 @@ end @test "\x0f" == unescape_string("\\x0f") @test "\x0F" == unescape_string("\\x0F") -extrapath = @windows? joinpath(JULIA_HOME,"..","Git","usr","bin")*";" : "" +extrapath = is_windows() ? joinpath(JULIA_HOME,"..","Git","usr","bin")*";" : "" withenv("PATH" => extrapath * ENV["PATH"]) do if !success(`iconv --version`) warn("iconv not found, skipping unicode tests!") - @windows_only warn("Use WinRPM.install(\"win_iconv\") to run these tests") + is_windows() && warn("Use WinRPM.install(\"win_iconv\") to run these tests") else # Create unicode test data directory unicodedir = mktempdir()