diff --git a/bin/crystal b/bin/crystal index ad5e3357c985..08df2485ee2c 100755 --- a/bin/crystal +++ b/bin/crystal @@ -186,6 +186,11 @@ case "$(uname -s)" in ;; esac +# CRYSTAL_EXEC_PATH determines the location of the `crystal` program for external +# compiler commands. +CRYSTAL_EXEC_PATH="$SCRIPT_ROOT" +export CRYSTAL_EXEC_PATH + if [ -x "$CRYSTAL_DIR/${CRYSTAL_BIN}" ]; then __warning_msg "Using compiled compiler at ${CRYSTAL_DIR#"$PWD/"}/${CRYSTAL_BIN}" exec "$CRYSTAL_DIR/${CRYSTAL_BIN}" "$@" diff --git a/spec/primitives/external_command_spec.cr b/spec/primitives/external_command_spec.cr index 91687f7c2d21..5e9b40a65dfb 100644 --- a/spec/primitives/external_command_spec.cr +++ b/spec/primitives/external_command_spec.cr @@ -4,31 +4,36 @@ require "../spec_helper" describe Crystal::Command do it "exec external commands", tags: %w[slow] do - with_temp_executable "crystal-external" do |path| + with_temp_executable "crystal-external" do |command_path| + compiler_path = File.expand_path(ENV["CRYSTAL_SPEC_COMPILER_BIN"]? || "bin/crystal") + with_tempfile "crystal-external.cr" do |source_file| File.write source_file, <<-CRYSTAL - puts ENV["CRYSTAL"]? + puts Process.find_executable("crystal") puts PROGRAM_NAME puts ARGV CRYSTAL - Process.run(ENV["CRYSTAL_SPEC_COMPILER_BIN"]? || "bin/crystal", ["build", source_file, "-o", path]) + Process.run(compiler_path, ["build", source_file, "-o", command_path]) end - File.exists?(path).should be_true + File.exists?(command_path).should be_true - process = Process.new(ENV["CRYSTAL_SPEC_COMPILER_BIN"]? || "bin/crystal", + process = Process.new(compiler_path, ["external", "foo", "bar"], output: :pipe, - env: {"PATH" => {ENV["PATH"], File.dirname(path)}.join(Process::PATH_DELIMITER)} + env: {"PATH" => {ENV["PATH"], File.dirname(command_path)}.join(Process::PATH_DELIMITER)} ) - output = process.output.gets_to_end + lines = process.output.gets_to_end.lines + status = process.wait status.success?.should be_true - lines = output.lines - lines[0].should match /crystal/ - lines[1].should match /crystal-external/ - lines[2].should eq %(["foo", "bar"]) + + lines.should eq [ + compiler_path, + command_path, + %(["foo", "bar"]), + ] end end end diff --git a/src/compiler/crystal/command.cr b/src/compiler/crystal/command.cr index 571c965352e0..7c1bf2ff0cb7 100644 --- a/src/compiler/crystal/command.cr +++ b/src/compiler/crystal/command.cr @@ -132,7 +132,19 @@ class Crystal::Command error "file '#{command}' does not exist" elsif external_command = Process.find_executable("crystal-#{command}") options.shift - Process.exec(external_command, options, env: {"CRYSTAL" => Process.executable_path}) + + crystal_exec_path = ENV["CRYSTAL_EXEC_PATH"]? + unless crystal_exec_path + if executable_path = Process.executable_path + crystal_exec_path = File.dirname(executable_path) + end + end + path = [crystal_exec_path, ENV["PATH"]?].compact!.join(Process::PATH_DELIMITER) + + Process.exec(external_command, options, env: { + "PATH" => path, + "CRYSTAL_EXEC_PATH" => crystal_exec_path, + }) else error "unknown command: #{command}" end diff --git a/src/compiler/crystal/command/spec.cr b/src/compiler/crystal/command/spec.cr index fd285b653432..69ebbad97caa 100644 --- a/src/compiler/crystal/command/spec.cr +++ b/src/compiler/crystal/command/spec.cr @@ -95,7 +95,12 @@ class Crystal::Command output_filename = Crystal.temp_executable "spec" - ENV["CRYSTAL_SPEC_COMPILER_BIN"] ||= Process.executable_path + ENV["CRYSTAL_SPEC_COMPILER_BIN"] ||= if crystal_exec_path = ENV["CRYSTAL_EXEC_PATH"]? + File.join(crystal_exec_path, "crystal") + else + Process.executable_path + end + compiler.compile sources, output_filename report_warnings execute output_filename, options, compiler, error_on_exit: warnings_fail_on_exit?