diff --git a/bin/crystal b/bin/crystal index e8abdff30ee8..a1fddf1c58b4 100755 --- a/bin/crystal +++ b/bin/crystal @@ -196,7 +196,7 @@ esac if [ -x "$CRYSTAL_DIR/${CRYSTAL_BIN}" ]; then __warning_msg "Using compiled compiler at ${CRYSTAL_DIR#"$PWD/"}/${CRYSTAL_BIN}" exec "$CRYSTAL_DIR/${CRYSTAL_BIN}" "$@" -elif !($PARENT_CRYSTAL_EXISTS); then +elif (! $PARENT_CRYSTAL_EXISTS); then __error_msg 'You need to have a crystal executable in your path! or set CRYSTAL env variable' exit 1 else diff --git a/spec/compiler/loader/unix_spec.cr b/spec/compiler/loader/unix_spec.cr index 42a63b88e860..6adcb040148b 100644 --- a/spec/compiler/loader/unix_spec.cr +++ b/spec/compiler/loader/unix_spec.cr @@ -40,7 +40,11 @@ describe Crystal::Loader do exc = expect_raises(Crystal::Loader::LoadError, /no such file|not found|cannot open/i) do Crystal::Loader.parse(["-l", "foo/bar.o"], search_paths: [] of String) end - exc.message.should contain File.join(Dir.current, "foo", "bar.o") + {% if flag?(:openbsd) %} + exc.message.should contain "foo/bar.o" + {% else %} + exc.message.should contain File.join(Dir.current, "foo", "bar.o") + {% end %} end end diff --git a/spec/std/exception/call_stack_spec.cr b/spec/std/exception/call_stack_spec.cr index 7c6f5d746bdc..6df0741d2a7b 100644 --- a/spec/std/exception/call_stack_spec.cr +++ b/spec/std/exception/call_stack_spec.cr @@ -55,14 +55,19 @@ describe "Backtrace" do error.to_s.should contain("IndexError") end - it "prints crash backtrace to stderr", tags: %w[slow] do - sample = datapath("crash_backtrace_sample") + {% if flag?(:openbsd) %} + # FIXME: the segfault handler doesn't work on OpenBSD + pending "prints crash backtrace to stderr" + {% else %} + it "prints crash backtrace to stderr", tags: %w[slow] do + sample = datapath("crash_backtrace_sample") - _, output, error = compile_and_run_file(sample) + _, output, error = compile_and_run_file(sample) - output.to_s.should be_empty - error.to_s.should contain("Invalid memory access") - end + output.to_s.should be_empty + error.to_s.should contain("Invalid memory access") + end + {% end %} # Do not test this on platforms that cannot remove the current working # directory of the process: diff --git a/spec/std/io/io_spec.cr b/spec/std/io/io_spec.cr index 620a1d034d9f..1904940f4883 100644 --- a/spec/std/io/io_spec.cr +++ b/spec/std/io/io_spec.cr @@ -425,9 +425,9 @@ describe IO do str.read_fully?(slice).should be_nil end - # pipe(2) returns bidirectional file descriptors on FreeBSD and Solaris, + # pipe(2) returns bidirectional file descriptors on some platforms, # gate this test behind the platform flag. - {% unless flag?(:freebsd) || flag?(:solaris) %} + {% unless flag?(:freebsd) || flag?(:solaris) || flag?(:openbsd) %} it "raises if trying to read to an IO not opened for reading" do IO.pipe do |r, w| expect_raises(IO::Error, "File not open for reading") do @@ -574,9 +574,9 @@ describe IO do io.read_byte.should be_nil end - # pipe(2) returns bidirectional file descriptors on FreeBSD and Solaris, + # pipe(2) returns bidirectional file descriptors on some platforms, # gate this test behind the platform flag. - {% unless flag?(:freebsd) || flag?(:solaris) %} + {% unless flag?(:freebsd) || flag?(:solaris) || flag?(:openbsd) %} it "raises if trying to write to an IO not opened for writing" do IO.pipe do |r, w| # unless sync is used the flush on close triggers the exception again diff --git a/spec/std/kernel_spec.cr b/spec/std/kernel_spec.cr index f8e4ff1e8ae2..0a682af8381b 100644 --- a/spec/std/kernel_spec.cr +++ b/spec/std/kernel_spec.cr @@ -251,55 +251,60 @@ describe "at_exit" do end end -describe "hardware exception" do - it "reports invalid memory access", tags: %w[slow] do - status, _, error = compile_and_run_source <<-'CRYSTAL' - puts Pointer(Int64).null.value - CRYSTAL - - status.success?.should be_false - error.should contain("Invalid memory access") - error.should_not contain("Stack overflow") - end - - {% if flag?(:netbsd) %} - # FIXME: on netbsd the process crashes with SIGILL after receiving SIGSEGV - pending "detects stack overflow on the main stack" - pending "detects stack overflow on a fiber stack" - {% else %} - it "detects stack overflow on the main stack", tags: %w[slow] do - # This spec can take some time under FreeBSD where - # the default stack size is 0.5G. Setting a - # smaller stack size with `ulimit -s 8192` - # will address this. +{% if flag?(:openbsd) %} + # FIXME: the segfault handler doesn't work on OpenBSD + pending "hardware exception" +{% else %} + describe "hardware exception" do + it "reports invalid memory access", tags: %w[slow] do status, _, error = compile_and_run_source <<-'CRYSTAL' - def foo - y = StaticArray(Int8, 512).new(0) - foo - end - foo + puts Pointer(Int64).null.value CRYSTAL status.success?.should be_false - error.should contain("Stack overflow") + error.should contain("Invalid memory access") + error.should_not contain("Stack overflow") end - it "detects stack overflow on a fiber stack", tags: %w[slow] do - status, _, error = compile_and_run_source <<-'CRYSTAL' - def foo - y = StaticArray(Int8, 512).new(0) + {% if flag?(:netbsd) %} + # FIXME: on netbsd the process crashes with SIGILL after receiving SIGSEGV + pending "detects stack overflow on the main stack" + pending "detects stack overflow on a fiber stack" + {% else %} + it "detects stack overflow on the main stack", tags: %w[slow] do + # This spec can take some time under FreeBSD where + # the default stack size is 0.5G. Setting a + # smaller stack size with `ulimit -s 8192` + # will address this. + status, _, error = compile_and_run_source <<-'CRYSTAL' + def foo + y = StaticArray(Int8, 512).new(0) + foo + end foo - end + CRYSTAL - spawn do - foo - end + status.success?.should be_false + error.should contain("Stack overflow") + end - sleep 60.seconds - CRYSTAL + it "detects stack overflow on a fiber stack", tags: %w[slow] do + status, _, error = compile_and_run_source <<-'CRYSTAL' + def foo + y = StaticArray(Int8, 512).new(0) + foo + end - status.success?.should be_false - error.should contain("Stack overflow") - end - {% end %} -end + spawn do + foo + end + + sleep 60.seconds + CRYSTAL + + status.success?.should be_false + error.should contain("Stack overflow") + end + {% end %} + end +{% end %} diff --git a/spec/std/socket/addrinfo_spec.cr b/spec/std/socket/addrinfo_spec.cr index 109eb383562b..b1d6b459623d 100644 --- a/spec/std/socket/addrinfo_spec.cr +++ b/spec/std/socket/addrinfo_spec.cr @@ -24,8 +24,8 @@ describe Socket::Addrinfo, tags: "network" do end it "raises helpful message on getaddrinfo failure" do - expect_raises(Socket::Addrinfo::Error, "Hostname lookup for badhostname failed: ") do - Socket::Addrinfo.resolve("badhostname", 80, type: Socket::Type::DGRAM) + expect_raises(Socket::Addrinfo::Error, "Hostname lookup for badhostname.unknown failed: ") do + Socket::Addrinfo.resolve("badhostname.unknown", 80, type: Socket::Type::DGRAM) end end diff --git a/spec/std/socket/tcp_server_spec.cr b/spec/std/socket/tcp_server_spec.cr index ee3c861956b8..a7d85b8edeff 100644 --- a/spec/std/socket/tcp_server_spec.cr +++ b/spec/std/socket/tcp_server_spec.cr @@ -43,7 +43,7 @@ describe TCPServer, tags: "network" do end error.os_error.should eq({% if flag?(:win32) %} WinError::WSATYPE_NOT_FOUND - {% elsif flag?(:linux) && !flag?(:android) %} + {% elsif (flag?(:linux) && !flag?(:android)) || flag?(:openbsd) %} Errno.new(LibC::EAI_SERVICE) {% else %} Errno.new(LibC::EAI_NONAME) @@ -96,7 +96,7 @@ describe TCPServer, tags: "network" do # FIXME: Resolve special handling for win32. The error code handling should be identical. {% if flag?(:win32) %} [WinError::WSAHOST_NOT_FOUND, WinError::WSATRY_AGAIN].should contain err.os_error - {% elsif flag?(:android) || flag?(:netbsd) %} + {% elsif flag?(:android) || flag?(:netbsd) || flag?(:openbsd) %} err.os_error.should eq(Errno.new(LibC::EAI_NODATA)) {% else %} [Errno.new(LibC::EAI_NONAME), Errno.new(LibC::EAI_AGAIN)].should contain err.os_error @@ -110,7 +110,7 @@ describe TCPServer, tags: "network" do # FIXME: Resolve special handling for win32. The error code handling should be identical. {% if flag?(:win32) %} [WinError::WSAHOST_NOT_FOUND, WinError::WSATRY_AGAIN].should contain err.os_error - {% elsif flag?(:android) || flag?(:netbsd) %} + {% elsif flag?(:android) || flag?(:netbsd) || flag?(:openbsd) %} err.os_error.should eq(Errno.new(LibC::EAI_NODATA)) {% else %} [Errno.new(LibC::EAI_NONAME), Errno.new(LibC::EAI_AGAIN)].should contain err.os_error diff --git a/spec/std/socket/tcp_socket_spec.cr b/spec/std/socket/tcp_socket_spec.cr index 5ec3467362e0..0b3a381372bf 100644 --- a/spec/std/socket/tcp_socket_spec.cr +++ b/spec/std/socket/tcp_socket_spec.cr @@ -47,7 +47,7 @@ describe TCPSocket, tags: "network" do end error.os_error.should eq({% if flag?(:win32) %} WinError::WSATYPE_NOT_FOUND - {% elsif flag?(:linux) && !flag?(:android) %} + {% elsif (flag?(:linux) && !flag?(:android)) || flag?(:openbsd) %} Errno.new(LibC::EAI_SERVICE) {% else %} Errno.new(LibC::EAI_NONAME) @@ -79,7 +79,7 @@ describe TCPSocket, tags: "network" do # FIXME: Resolve special handling for win32. The error code handling should be identical. {% if flag?(:win32) %} [WinError::WSAHOST_NOT_FOUND, WinError::WSATRY_AGAIN].should contain err.os_error - {% elsif flag?(:android) || flag?(:netbsd) %} + {% elsif flag?(:android) || flag?(:netbsd) || flag?(:openbsd) %} err.os_error.should eq(Errno.new(LibC::EAI_NODATA)) {% else %} [Errno.new(LibC::EAI_NONAME), Errno.new(LibC::EAI_AGAIN)].should contain err.os_error @@ -93,7 +93,7 @@ describe TCPSocket, tags: "network" do # FIXME: Resolve special handling for win32. The error code handling should be identical. {% if flag?(:win32) %} [WinError::WSAHOST_NOT_FOUND, WinError::WSATRY_AGAIN].should contain err.os_error - {% elsif flag?(:android) || flag?(:netbsd) %} + {% elsif flag?(:android) || flag?(:netbsd) || flag?(:openbsd) %} err.os_error.should eq(Errno.new(LibC::EAI_NODATA)) {% else %} [Errno.new(LibC::EAI_NONAME), Errno.new(LibC::EAI_AGAIN)].should contain err.os_error diff --git a/spec/std/socket/udp_socket_spec.cr b/spec/std/socket/udp_socket_spec.cr index 9b624110fad9..dc66d8038036 100644 --- a/spec/std/socket/udp_socket_spec.cr +++ b/spec/std/socket/udp_socket_spec.cr @@ -88,6 +88,9 @@ describe UDPSocket, tags: "network" do elsif {{ flag?(:netbsd) }} && family == Socket::Family::INET6 # FIXME: fails with "setsockopt: EADDRNOTAVAIL" pending "joins and transmits to multicast groups" + elsif {{ flag?(:openbsd) }} + # FIXME: fails with "setsockopt: EINVAL (ipv4) or EADDRNOTAVAIL (ipv6)" + pending "joins and transmits to multicast groups" else it "joins and transmits to multicast groups" do udp = UDPSocket.new(family) diff --git a/src/compiler/crystal/compiler.cr b/src/compiler/crystal/compiler.cr index 6c7664bacc25..83509bf88392 100644 --- a/src/compiler/crystal/compiler.cr +++ b/src/compiler/crystal/compiler.cr @@ -500,6 +500,19 @@ module Crystal else link_flags = @link_flags || "" link_flags += " -rdynamic" + + if program.has_flag?("freebsd") || program.has_flag?("openbsd") + # pkgs are installed to usr/local/lib but it's not in LIBRARY_PATH by + # default; we declare it to ease linking on these platforms: + link_flags += " -L/usr/local/lib" + end + + if program.has_flag?("openbsd") + # OpenBSD requires Indirect Branch Tracking by default, but we're not + # compatible (yet), so we disable it for now: + link_flags += " -Wl,-znobtcfi" + end + {DEFAULT_LINKER, %(#{DEFAULT_LINKER} "${@}" -o #{Process.quote_posix(output_filename)} #{link_flags} #{program.lib_flags(@cross_compile)}), object_names} end end diff --git a/src/lib_c/x86_64-openbsd/c/netdb.cr b/src/lib_c/x86_64-openbsd/c/netdb.cr index be3c5f06ab2d..6dd1e6c8513f 100644 --- a/src/lib_c/x86_64-openbsd/c/netdb.cr +++ b/src/lib_c/x86_64-openbsd/c/netdb.cr @@ -13,6 +13,7 @@ lib LibC EAI_FAIL = -4 EAI_FAMILY = -6 EAI_MEMORY = -10 + EAI_NODATA = -5 EAI_NONAME = -2 EAI_SERVICE = -8 EAI_SOCKTYPE = -7