diff --git a/.github/workflows/win.yml b/.github/workflows/win.yml index 571e7624acde..3edaa3f89364 100644 --- a/.github/workflows/win.yml +++ b/.github/workflows/win.yml @@ -148,7 +148,7 @@ jobs: - name: Set up environment run: | - echo "::set-env name=CRYSTAL_PATH::src" + echo "::set-env name=CRYSTAL_PATH::$(pwd)\src" echo "::set-env name=LIB::${env:LIB};$(pwd)\libs" echo "::set-env name=TERM::dumb" echo "::set-env name=LLVM_CONFIG::$(pwd)\llvm\bin\llvm-config.exe" @@ -168,13 +168,14 @@ jobs: - name: Re-build Crystal run: | .\crystal-cross.exe build src/compiler/crystal.cr -Di_know_what_im_doing -Dwithout_playground --link-flags=/F10000000 + mv crystal.exe bin/ - - name: Gather Crystal executable + - name: Gather Crystal binaries run: | mkdir crystal - cp crystal.exe crystal/ + cp bin/crystal.exe crystal/ cp libs/* crystal/ - - name: Upload Crystal executable + - name: Upload Crystal binaries uses: actions/upload-artifact@v1 with: name: crystal @@ -182,7 +183,14 @@ jobs: - name: Build stdlib specs executable run: | - .\crystal.exe build spec/std_spec.cr --exclude-warnings spec/std -Dwithout_openssl -Di_know_what_im_doing + bin\crystal.exe build spec/std_spec.cr --exclude-warnings spec/std --exclude-warnings spec/compiler -Dwithout_openssl -Di_know_what_im_doing - name: Run stdlib specs run: | .\std_spec.exe + + - name: Build compiler specs executable + run: | + bin\crystal.exe build spec/compiler_spec.cr --exclude-warnings spec/std --exclude-warnings spec/compiler -Dwithout_playground -Di_know_what_im_doing + - name: Run compiler specs + run: | + .\compiler_spec.exe diff --git a/spec/compiler/codegen/extern_spec.cr b/spec/compiler/codegen/extern_spec.cr index e1f0e401e18a..6efd7a44c16b 100644 --- a/spec/compiler/codegen/extern_spec.cr +++ b/spec/compiler/codegen/extern_spec.cr @@ -427,7 +427,7 @@ describe "Codegen: extern struct" do ), &.to_i.should eq(30)) end - it "codegens proc that takes and returns an extern struct with sret" do + pending_win32 "codegens proc that takes and returns an extern struct with sret" do test_c( %( struct Struct { diff --git a/spec/compiler/codegen/lib_spec.cr b/spec/compiler/codegen/lib_spec.cr index e899bcf6d2cf..695a02d6fd6b 100644 --- a/spec/compiler/codegen/lib_spec.cr +++ b/spec/compiler/codegen/lib_spec.cr @@ -15,11 +15,11 @@ describe "Code gen: lib" do it "call to void function" do run(" lib LibC - fun srandom(x : UInt32) : Void + fun srand(x : UInt32) : Void end def foo - LibC.srandom(0_u32) + LibC.srand(0_u32) end foo diff --git a/spec/compiler/codegen/special_vars_spec.cr b/spec/compiler/codegen/special_vars_spec.cr index 280da6caaa98..14323c96d28e 100644 --- a/spec/compiler/codegen/special_vars_spec.cr +++ b/spec/compiler/codegen/special_vars_spec.cr @@ -2,7 +2,7 @@ require "../../spec_helper" describe "Codegen: special vars" do ["$~", "$?"].each do |name| - it "codegens #{name}" do + pending_win32 "codegens #{name}" do run(%( class Object; def not_nil!; self; end; end @@ -15,7 +15,7 @@ describe "Codegen: special vars" do )).to_string.should eq("hey") end - it "codegens #{name} with nilable (1)" do + pending_win32 "codegens #{name} with nilable (1)" do run(%( require "prelude" @@ -35,7 +35,7 @@ describe "Codegen: special vars" do )).to_string.should eq("ouch") end - it "codegens #{name} with nilable (2)" do + pending_win32 "codegens #{name} with nilable (2)" do run(%( require "prelude" @@ -74,7 +74,7 @@ describe "Codegen: special vars" do )).to_string.should eq("hey") end - it "works lazily" do + pending_win32 "works lazily" do run(%( require "prelude" @@ -145,7 +145,7 @@ describe "Codegen: special vars" do )).to_string.should eq("hey") end - it "codegens after block" do + pending_win32 "codegens after block" do run(%( require "prelude" diff --git a/spec/compiler/codegen/thread_local_spec.cr b/spec/compiler/codegen/thread_local_spec.cr index 09e40b159bf4..ea26bfe50fcc 100644 --- a/spec/compiler/codegen/thread_local_spec.cr +++ b/spec/compiler/codegen/thread_local_spec.cr @@ -2,7 +2,7 @@ require "../../spec_helper" {% if !flag?(:openbsd) %} describe "Codegen: thread local" do - it "works with class variables" do + pending_win32 "works with class variables" do run(%( require "prelude" diff --git a/spec/compiler/compiler_spec.cr b/spec/compiler/compiler_spec.cr index ce7c086f99ec..66d2ad7871aa 100644 --- a/spec/compiler/compiler_spec.cr +++ b/spec/compiler/compiler_spec.cr @@ -30,7 +30,7 @@ describe "Compiler" do it "treats all arguments post-filename as program arguments" do with_tempfile "args_test" do |path| - `bin/crystal '#{compiler_datapath}/args_test' -Dother_flag -- bar '#{path}'` + `bin/crystal #{Process.quote(File.join(compiler_datapath, "args_test"))} -Dother_flag -- bar #{Process.quote(path)}` File.read(path).should eq(<<-FILE) ["-Dother_flag", "--", "bar"] diff --git a/spec/compiler/crystal/tools/doc/project_info_spec.cr b/spec/compiler/crystal/tools/doc/project_info_spec.cr index f255d8ae72de..42191829968a 100644 --- a/spec/compiler/crystal/tools/doc/project_info_spec.cr +++ b/spec/compiler/crystal/tools/doc/project_info_spec.cr @@ -50,7 +50,7 @@ describe Crystal::Doc::ProjectInfo do it "git tagged version" do run_git "init" run_git "add shard.yml" - run_git "commit -m 'Initial commit' --no-gpg-sign" + run_git "commit -m \"Initial commit\" --no-gpg-sign" run_git "tag v3.0" assert_with_defaults(ProjectInfo.new(nil, nil), ProjectInfo.new("foo", "3.0", refname: "v3.0")) @@ -61,7 +61,7 @@ describe Crystal::Doc::ProjectInfo do it "git tagged version dirty" do run_git "init" run_git "add shard.yml" - run_git "commit -m 'Initial commit' --no-gpg-sign" + run_git "commit -m \"Initial commit\" --no-gpg-sign" run_git "tag v3.0" File.write("foo.txt", "bar") @@ -73,7 +73,7 @@ describe Crystal::Doc::ProjectInfo do it "git non-tagged commit" do run_git "init" run_git "add shard.yml" - run_git "commit -m 'Initial commit' --no-gpg-sign" + run_git "commit -m \"Initial commit\" --no-gpg-sign" commit_sha = `git rev-parse HEAD`.chomp assert_with_defaults(ProjectInfo.new(nil, nil), ProjectInfo.new("foo", "master", refname: commit_sha)) @@ -85,7 +85,7 @@ describe Crystal::Doc::ProjectInfo do it "git non-tagged commit dirty" do run_git "init" run_git "add shard.yml" - run_git "commit -m 'Initial commit' --no-gpg-sign" + run_git "commit -m \"Initial commit\" --no-gpg-sign" File.write("foo.txt", "bar") assert_with_defaults(ProjectInfo.new(nil, nil), ProjectInfo.new("foo", "master-dev", refname: nil)) @@ -109,7 +109,7 @@ describe Crystal::Doc::ProjectInfo do File.write("foo.txt", "bar") run_git "init" run_git "add foo.txt" - run_git "commit -m 'Remove shard.yml' --no-gpg-sign" + run_git "commit -m \"Remove shard.yml\" --no-gpg-sign" run_git "tag v4.0" assert_with_defaults(ProjectInfo.new(nil, nil), ProjectInfo.new(nil, "4.0", refname: "v4.0")) @@ -130,7 +130,7 @@ describe Crystal::Doc::ProjectInfo do # Non-tagged commit File.write("file.txt", "foo") run_git "add file.txt" - run_git "commit -m 'Initial commit' --no-gpg-sign" + run_git "commit -m \"Initial commit\" --no-gpg-sign" ProjectInfo.find_git_version.should eq "master" # Other branch diff --git a/spec/compiler/crystal/tools/format_spec.cr b/spec/compiler/crystal/tools/format_spec.cr index b8a1a8c753a8..d0b37e866e29 100644 --- a/spec/compiler/crystal/tools/format_spec.cr +++ b/spec/compiler/crystal/tools/format_spec.cr @@ -99,8 +99,8 @@ describe Crystal::Command::FormatCommand do format_command = Crystal::Command::FormatCommand.new([] of String, color: false, stdin: stdin, stdout: stdout, stderr: stderr) format_command.run format_command.status_code.should eq(0) - stdout.to_s.should contain("Format ./format.cr") - stdout.to_s.should_not contain("Format ./not_format.cr") + stdout.to_s.should contain("Format #{Path[".", "format.cr"]}") + stdout.to_s.should_not contain("Format #{Path[".", "not_format.cr"]}") stderr.to_s.empty?.should be_true File.read(File.join(path, "format.cr")).should eq("if true\n 1\nend\n") @@ -124,8 +124,8 @@ describe Crystal::Command::FormatCommand do format_command = Crystal::Command::FormatCommand.new(["dir"], color: false, stdin: stdin, stdout: stdout, stderr: stderr) format_command.run format_command.status_code.should eq(0) - stdout.to_s.should contain("Format ./dir/format.cr") - stdout.to_s.should_not contain("Format ./dir/not_format.cr") + stdout.to_s.should contain("Format #{Path[".", "dir", "format.cr"]}") + stdout.to_s.should_not contain("Format #{Path[".", "dir", "not_format.cr"]}") stderr.to_s.empty?.should be_true {stdout, stderr}.each &.clear @@ -133,10 +133,10 @@ describe Crystal::Command::FormatCommand do format_command = Crystal::Command::FormatCommand.new([] of String, color: false, stdin: stdin, stdout: stdout, stderr: stderr) format_command.run format_command.status_code.should eq(0) - stdout.to_s.should contain("Format ./format.cr") - stdout.to_s.should_not contain("Format ./not_format.cr") - stdout.to_s.should_not contain("Format ./dir/format.cr") - stdout.to_s.should_not contain("Format ./dir/not_format.cr") + stdout.to_s.should contain("Format #{Path[".", "format.cr"]}") + stdout.to_s.should_not contain("Format #{Path[".", "not_format.cr"]}") + stdout.to_s.should_not contain("Format #{Path[".", "dir", "format.cr"]}") + stdout.to_s.should_not contain("Format #{Path[".", "dir", "not_format.cr"]}") stderr.to_s.empty?.should be_true File.read(File.join(path, "format.cr")).should eq("if true\n 1\nend\n") @@ -160,9 +160,9 @@ describe Crystal::Command::FormatCommand do format_command = Crystal::Command::FormatCommand.new([] of String, color: false, stdin: stdin, stdout: stdout, stderr: stderr) format_command.run format_command.status_code.should eq(1) - stdout.to_s.should contain("Format ./format.cr") - stderr.to_s.should contain("syntax error in './syntax_error.cr:1:3': unexpected token: EOF") - stderr.to_s.should contain("file './invalid_byte_sequence_error.cr' is not a valid Crystal source file: Unexpected byte 0xff at position 1, malformed UTF-8") + stdout.to_s.should contain("Format #{Path[".", "format.cr"]}") + stderr.to_s.should contain("syntax error in '#{Path[".", "syntax_error.cr"]}:1:3': unexpected token: EOF") + stderr.to_s.should contain("file '#{Path[".", "invalid_byte_sequence_error.cr"]}' is not a valid Crystal source file: Unexpected byte 0xff at position 1, malformed UTF-8") File.read(File.join(path, "format.cr")).should eq("if true\n 1\nend\n") end @@ -182,7 +182,7 @@ describe Crystal::Command::FormatCommand do format_command = BuggyFormatCommand.new([] of String, color: false, stdin: stdin, stdout: stdout, stderr: stderr) format_command.run format_command.status_code.should eq(1) - stderr.to_s.should contain("there's a bug formatting './empty.cr', to show more information, please run:\n\n $ crystal tool format --show-backtrace './empty.cr'") + stderr.to_s.should contain("there's a bug formatting '#{Path[".", "empty.cr"]}', to show more information, please run:\n\n $ crystal tool format --show-backtrace '#{Path[".", "empty.cr"]}'") end end end @@ -201,7 +201,7 @@ describe Crystal::Command::FormatCommand do format_command.run format_command.status_code.should eq(1) stderr.to_s.should contain("format command test") - stderr.to_s.should contain("couldn't format './empty.cr', please report a bug including the contents of it: https://github.com/crystal-lang/crystal/issues") + stderr.to_s.should contain("couldn't format '#{Path[".", "empty.cr"]}', please report a bug including the contents of it: https://github.com/crystal-lang/crystal/issues") end end end @@ -224,9 +224,9 @@ describe Crystal::Command::FormatCommand do format_command.status_code.should eq(1) stdout.to_s.empty?.should be_true stderr.to_s.should_not contain("not_format.cr") - stderr.to_s.should contain("formatting './format.cr' produced changes") - stderr.to_s.should contain("syntax error in './syntax_error.cr:1:3': unexpected token: EOF") - stderr.to_s.should contain("file './invalid_byte_sequence_error.cr' is not a valid Crystal source file: Unexpected byte 0xff at position 1, malformed UTF-8") + stderr.to_s.should contain("formatting '#{Path[".", "format.cr"]}' produced changes") + stderr.to_s.should contain("syntax error in '#{Path[".", "syntax_error.cr"]}:1:3': unexpected token: EOF") + stderr.to_s.should contain("file '#{Path[".", "invalid_byte_sequence_error.cr"]}' is not a valid Crystal source file: Unexpected byte 0xff at position 1, malformed UTF-8") end end end @@ -286,7 +286,7 @@ describe Crystal::Command::FormatCommand do format_command.run format_command.status_code.should eq(1) stdout.to_s.empty?.should be_true - stderr.to_s.should contain("formatting './format.cr' produced changes") + stderr.to_s.should contain("formatting '#{Path[".", "format.cr"]}' produced changes") end end end diff --git a/spec/compiler/crystal/tools/init_spec.cr b/spec/compiler/crystal/tools/init_spec.cr index c16409e35dd1..7d59a6586282 100644 --- a/spec/compiler/crystal/tools/init_spec.cr +++ b/spec/compiler/crystal/tools/init_spec.cr @@ -280,7 +280,7 @@ module Crystal config.expanded_dir.should eq ::Path[Dir.current, "foo", "bar"] end - it "DIR (relative to home)" do + pending_win32 "DIR (relative to home)" do path = ::Path["~", "foo"].to_s config = Crystal::Init.parse_args(["lib", path]) config.name.should eq "foo" diff --git a/spec/compiler/crystal/tools/playground_spec.cr b/spec/compiler/crystal/tools/playground_spec.cr index 2e122ab8912c..4710f4fb0521 100644 --- a/spec/compiler/crystal/tools/playground_spec.cr +++ b/spec/compiler/crystal/tools/playground_spec.cr @@ -1,3 +1,5 @@ +{% skip_file if flag?(:without_playground) %} + require "../../../spec_helper" private def instrument(source) diff --git a/spec/compiler/crystal_path/crystal_path_spec.cr b/spec/compiler/crystal_path/crystal_path_spec.cr index cdcf5ba47256..390f91cd7c03 100644 --- a/spec/compiler/crystal_path/crystal_path_spec.cr +++ b/spec/compiler/crystal_path/crystal_path_spec.cr @@ -4,7 +4,7 @@ require "../../support/env" private def assert_finds(search, results, relative_to = nil, path = __DIR__, file = __FILE__, line = __LINE__) it "finds #{search.inspect}", file, line do crystal_path = Crystal::CrystalPath.new(path) - results = results.map { |result| File.join(__DIR__, result) } + results = results.map { |result| ::Path[__DIR__, result].normalize.to_s } Dir.cd(__DIR__) do matches = crystal_path.find search, relative_to: relative_to matches.should eq(results), file: file, line: line @@ -112,7 +112,7 @@ describe Crystal::CrystalPath do end it "overrides path with environment variable" do - with_env("CRYSTAL_PATH": "foo:bar") do + with_env("CRYSTAL_PATH": "foo#{Process::PATH_DELIMITER}bar") do crystal_path = Crystal::CrystalPath.new crystal_path.entries.should eq(%w(foo bar)) end diff --git a/spec/compiler/semantic/generic_class_spec.cr b/spec/compiler/semantic/generic_class_spec.cr index 93aac06adf11..3725488a727e 100644 --- a/spec/compiler/semantic/generic_class_spec.cr +++ b/spec/compiler/semantic/generic_class_spec.cr @@ -479,7 +479,7 @@ describe "Semantic: generic class" do "use a more specific type" end - it "errors on too nested generic instance" do + pending_win32 "errors on too nested generic instance" do assert_error %( class Foo(T) end @@ -493,7 +493,7 @@ describe "Semantic: generic class" do "generic type too nested" end - it "errors on too nested generic instance, with union type" do + pending_win32 "errors on too nested generic instance, with union type" do assert_error %( class Foo(T) end @@ -507,7 +507,7 @@ describe "Semantic: generic class" do "generic type too nested" end - it "errors on too nested tuple instance" do + pending_win32 "errors on too nested tuple instance" do assert_error %( def foo {typeof(foo)} diff --git a/spec/compiler/semantic/primitives_spec.cr b/spec/compiler/semantic/primitives_spec.cr index 9b9555b73363..fcf826540b96 100644 --- a/spec/compiler/semantic/primitives_spec.cr +++ b/spec/compiler/semantic/primitives_spec.cr @@ -224,7 +224,7 @@ describe "Semantic: primitives" do "method marked as Primitive must have an empty body" end - it "types va_arg primitive" do + pending_win32 "types va_arg primitive" do assert_type(%( struct VaList @[Primitive(:va_arg)] diff --git a/spec/std/exception/call_stack_spec.cr b/spec/std/exception/call_stack_spec.cr index ee42e4d77b5c..81ef86ad7333 100644 --- a/spec/std/exception/call_stack_spec.cr +++ b/spec/std/exception/call_stack_spec.cr @@ -1,7 +1,7 @@ require "../spec_helper" describe "Backtrace" do - it "prints file line:colunm" do + pending_win32 "prints file line:colunm" do source_file = datapath("backtrace_sample") # CallStack tries to make files relative to the current dir, @@ -34,7 +34,7 @@ describe "Backtrace" do error.to_s.should contain("IndexError") end - it "prints crash backtrace to stderr" do + pending_win32 "prints crash backtrace to stderr" do sample = datapath("crash_backtrace_sample") _, output, error = compile_and_run_file(sample) diff --git a/spec/std/io/file_descriptor_spec.cr b/spec/std/io/file_descriptor_spec.cr index 718a47acf5f6..b1ce0c33cdfd 100644 --- a/spec/std/io/file_descriptor_spec.cr +++ b/spec/std/io/file_descriptor_spec.cr @@ -1,7 +1,7 @@ require "../spec_helper" describe IO::FileDescriptor do - it "reopen STDIN with the right mode" do + pending_win32 "reopen STDIN with the right mode" do code = %q(puts "#{STDIN.blocking} #{STDIN.info.type}") compile_source(code) do |binpath| `#{Process.quote(binpath)} < #{Process.quote(binpath)}`.chomp.should eq("true File") diff --git a/spec/support/tempfile.cr b/spec/support/tempfile.cr index 42001785d1c8..036c161fcae4 100644 --- a/spec/support/tempfile.cr +++ b/spec/support/tempfile.cr @@ -28,7 +28,7 @@ def with_tempfile(*paths, file = __FILE__) ensure if SPEC_TEMPFILE_CLEANUP paths.each do |path| - FileUtils.rm_r(path) if File.exists?(path) + rm_rf(path) if File.exists?(path) end end end @@ -44,10 +44,15 @@ def with_temp_executable(name, file = __FILE__) end def with_temp_c_object_file(c_code, file = __FILE__) - with_tempfile("temp_c.c", "temp_c.o", file: file) do |c_filename, o_filename| + obj_ext = {{ flag?(:win32) ? ".obj" : ".o" }} + with_tempfile("temp_c.c", "temp_c#{obj_ext}", file: file) do |c_filename, o_filename| File.write(c_filename, c_code) - `#{ENV["CC"]? || "cc"} #{Process.quote(c_filename)} -c -o #{Process.quote(o_filename)}`.should be_truthy + {% if flag?(:win32) %} + `cl.exe /nologo /c #{Process.quote(c_filename)} #{Process.quote("/Fo#{o_filename}")}`.should be_truthy + {% else %} + `#{ENV["CC"]? || "cc"} #{Process.quote(c_filename)} -c -o #{Process.quote(o_filename)}`.should be_truthy + {% end %} yield o_filename end @@ -55,6 +60,24 @@ end if SPEC_TEMPFILE_CLEANUP at_exit do - FileUtils.rm_r(SPEC_TEMPFILE_PATH) if Dir.exists?(SPEC_TEMPFILE_PATH) + rm_rf(SPEC_TEMPFILE_PATH) if Dir.exists?(SPEC_TEMPFILE_PATH) + end +end + +private def rm_rf(path : String) : Nil + if Dir.exists?(path) && !File.symlink?(path) + Dir.each_child(path) do |entry| + src = File.join(path, entry) + rm_rf(src) + end + Dir.delete(path) + else + begin + File.delete(path) + rescue File::AccessDeniedError + # To be able to delete read-only files (e.g. ones under .git/) on Windows. + File.chmod(path, 0o666) + File.delete(path) + end end end diff --git a/spec/win32_std_spec.cr b/spec/win32_std_spec.cr index 2bc3be978063..e8b420a6dbf6 100644 --- a/spec/win32_std_spec.cr +++ b/spec/win32_std_spec.cr @@ -55,7 +55,7 @@ require "./std/ecr/ecr_spec.cr" require "./std/enum_spec.cr" require "./std/enumerable_spec.cr" require "./std/env_spec.cr" -# require "./std/exception/call_stack_spec.cr" +require "./std/exception/call_stack_spec.cr" require "./std/exception_spec.cr" require "./std/file/tempfile_spec.cr" require "./std/file_spec.cr" @@ -100,7 +100,7 @@ require "./std/io/argf_spec.cr" require "./std/io/buffered_spec.cr" require "./std/io/byte_format_spec.cr" require "./std/io/delimited_spec.cr" -# require "./std/io/file_descriptor_spec.cr" (failed codegen) +require "./std/io/file_descriptor_spec.cr" require "./std/io/hexdump_spec.cr" require "./std/io/io_spec.cr" require "./std/io/memory_spec.cr" diff --git a/src/empty.cr b/src/empty.cr index 8a78751e0f85..35f988afb583 100644 --- a/src/empty.cr +++ b/src/empty.cr @@ -1,5 +1,8 @@ require "primitives" +{% if flag?(:win32) %} + @[Link("libcmt")] # For `mainCRTStartup` +{% end %} lib LibCrystalMain @[Raises] fun __crystal_main(argc : Int32, argv : UInt8**)