diff --git a/spec/std/process_spec.cr b/spec/std/process_spec.cr index 4a36f1820014..519df8caacf0 100644 --- a/spec/std/process_spec.cr +++ b/spec/std/process_spec.cr @@ -2,6 +2,8 @@ require "spec" require "process" require "tempfile" +DIR_CURRENT = Dir.current + describe Process do it "runs true" do process = Process.new("true") @@ -215,7 +217,7 @@ describe Process do end describe "find_executable" do - pwd = Process::INITIAL_PWD + pwd = DIR_CURRENT crystal_path = File.join(pwd, "bin", "crystal") it "resolves absolute executable" do diff --git a/src/crystal/system/darwin/process.cr b/src/crystal/system/darwin/process.cr new file mode 100644 index 000000000000..0eb78a907815 --- /dev/null +++ b/src/crystal/system/darwin/process.cr @@ -0,0 +1,18 @@ +require "c/mach-o/dyld" + +module System + # nodoc + class Process + def self.executable_path_impl + buf = GC.malloc_atomic(LibC::PATH_MAX).as(UInt8*) + size = LibC::PATH_MAX.to_u32 + + if LibC._NSGetExecutablePath(buf, pointerof(size)) == -1 + buf = GC.malloc_atomic(size).as(UInt8*) + return nil if LibC._NSGetExecutablePath(buf, pointerof(size)) == -1 + end + + String.new(buf) + end + end +end diff --git a/src/crystal/system/freebsd/process.cr b/src/crystal/system/freebsd/process.cr new file mode 100644 index 000000000000..314c0304812e --- /dev/null +++ b/src/crystal/system/freebsd/process.cr @@ -0,0 +1,16 @@ +require "c/sysctl" + +module System + # nodoc + class Process + def self.executable_path_impl + mib = Int32[LibC::CTL_KERN, LibC::KERN_PROC, LibC::KERN_PROC_PATHNAME, -1] + buf = GC.malloc_atomic(LibC::PATH_MAX).as(UInt8*) + size = LibC::SizeT.new(LibC::PATH_MAX) + + if LibC.sysctl(mib, 4, buf, pointerof(size), nil, 0) == 0 + String.new(buf, size - 1) + end + end + end +end diff --git a/src/crystal/system/linux/process.cr b/src/crystal/system/linux/process.cr new file mode 100644 index 000000000000..e53446d8d093 --- /dev/null +++ b/src/crystal/system/linux/process.cr @@ -0,0 +1,8 @@ +module System + # nodoc + class Process + def self.executable_path_impl + "/proc/self/exe" + end + end +end diff --git a/src/crystal/system/process.cr b/src/crystal/system/process.cr new file mode 100644 index 000000000000..38bc8532b67b --- /dev/null +++ b/src/crystal/system/process.cr @@ -0,0 +1,30 @@ +module Crystal + # :nodoc: + module System + # :nodoc: + module Process + # Returns possible location of executable path + # def self.executable_path_impl + end + end +end + +{% if flag?(:darwin) %} + require "./darwin/process" +{% elsif flag?(:freebsd) %} + require "./freebsd/process" +{% elsif flag?(:linux) %} + require "./linux/process" +{% else %} + module System + # nodoc + class Process + INITIAL_PATH = ENV["PATH"]? + INITIAL_PWD = Dir.current + + def self.executable_path_impl + ::Process.find_executable(PROGRAM_NAME, INITIAL_PATH, INITIAL_PWD) + end + end + end +{% end %} diff --git a/src/lib_c/x86_64-macosx-darwin/c/mach-o/dyld.cr b/src/lib_c/x86_64-macosx-darwin/c/mach-o/dyld.cr new file mode 100644 index 000000000000..65f7a6aa017e --- /dev/null +++ b/src/lib_c/x86_64-macosx-darwin/c/mach-o/dyld.cr @@ -0,0 +1,4 @@ +lib LibC + PATH_MAX = 1024 + fun _NSGetExecutablePath(buf : Char*, bufsize : UInt32*) : Int +end diff --git a/src/process/executable_path.cr b/src/process/executable_path.cr index 5c8d6e140c45..9407b396b460 100644 --- a/src/process/executable_path.cr +++ b/src/process/executable_path.cr @@ -2,15 +2,11 @@ # - https://github.com/gpakosz/whereami/blob/master/src/whereami.c # - http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe +require "crystal/system/process" + class Process PATH_DELIMITER = {% if flag?(:windows) %} ';' {% else %} ':' {% end %} - # :nodoc: - INITIAL_PATH = ENV["PATH"]? - - # :nodoc: - INITIAL_PWD = Dir.current - # Returns an absolute path to the executable file of the currently running # program. This is in opposition to `PROGRAM_NAME` which may be a relative or # absolute path, just the executable file name or a symlink. @@ -20,7 +16,7 @@ class Process # # Returns `nil` if the file can't be found. def self.executable_path - if executable = executable_path_impl + if executable = System::Process.executable_path_impl begin File.real_path(executable) rescue Errno @@ -50,53 +46,3 @@ class Process nil end end - -{% if flag?(:darwin) %} - lib LibC - PATH_MAX = 1024 - fun _NSGetExecutablePath(buf : Char*, bufsize : UInt32*) : Int - end - - class Process - private def self.executable_path_impl - buf = GC.malloc_atomic(LibC::PATH_MAX).as(UInt8*) - size = LibC::PATH_MAX.to_u32 - - if LibC._NSGetExecutablePath(buf, pointerof(size)) == -1 - buf = GC.malloc_atomic(size).as(UInt8*) - return nil if LibC._NSGetExecutablePath(buf, pointerof(size)) == -1 - end - - String.new(buf) - end - end - -{% elsif flag?(:freebsd) %} - require "c/sysctl" - - class Process - private def self.executable_path_impl - mib = Int32[LibC::CTL_KERN, LibC::KERN_PROC, LibC::KERN_PROC_PATHNAME, -1] - buf = GC.malloc_atomic(LibC::PATH_MAX).as(UInt8*) - size = LibC::SizeT.new(LibC::PATH_MAX) - - if LibC.sysctl(mib, 4, buf, pointerof(size), nil, 0) == 0 - String.new(buf, size - 1) - end - end - end - -{% elsif flag?(:linux) %} - class Process - private def self.executable_path_impl - "/proc/self/exe" - end - end - -{% else %} # openbsd, ... - class Process - private def self.executable_path_impl - find_executable(PROGRAM_NAME, INITIAL_PATH, INITIAL_PWD) - end - end -{% end %}