crystal-lang / crystal

The Crystal Programming Language
https://crystal-lang.org
Apache License 2.0
19.45k stars 1.62k forks source link

Support Windows as a first class platform (note: not WSL or emulation) #26

Open xtagon opened 11 years ago

xtagon commented 11 years ago

Hi,

Crystal is an exciting project with lots of potential. I am interested in the possibility of a Crystal compiler for Windows. How feasible is that idea, and how much work would it be?

Specifically, I would like to be able to compile a Crystal program into a Windows .DLL file with exported C functions. I don't care if I run the actual Crystal compiler on a Linux or Windows machine, I just want to end up with a DLL library that will run on Windows.

I have knowledge of Ruby and some C, and I'm willing to dive into learning about LLVM if it means I can contribute here. I would be pleased if you could point me in the right direction.

Regards, Justin

asterite commented 11 years ago

Hi,

Thank you for your interest in Crystal!

Yes, it would be awesome to have Crystal running on Windows.

I don't think there is much to do on LLVM side to make it work, except having the necessary libraries to link to.

I read this the other day, it might be useful: http://www.phoronix.com/scan.php?page=news_item&px=MTQ1NjI

If you want to contribute, I think the path is the following:

Any doubts you have about how the compiler works, we can answer and help you :-)

Regards, Ary

xtagon commented 11 years ago

Thanks, Ary! I will give it a shot. On Sep 10, 2013 5:09 AM, "Ary Borenszweig" notifications@github.com wrote:

Hi,

Thank you for your interest in Crystal!

Yes, it would be awesome to have Crystal running on Windows.

I don't think there is much to do on LLVM side to make it work, except having the necessary libraries to link to.

I read this the other day, it might be useful: http://www.phoronix.com/scan.php?page=news_item&px=MTQ1NjI

If you want to contribute, I think the path is the following:

  • Checkout the project and try to compile a simple program. A very simple program is just this: "1" (just an integer literal). But Crystal automatically includes a "prelude" file that gives you Array, Hash, etc. So you should comment these two lines ( https://github.com/manastech/crystal/blob/master/lib/crystal/compiler.rb#L120-L121) so it will be easier to test. This point involves making LLVM work on Windows, specifically the ruby-llvm gem.
  • Once the previous point is working, you will need to make other programs work, mostly programs that depend on libc. For example you could try opening and writing a file with File.open("C:/foo.txt") { |file| file.write "Hello" }. If the API for opening and writing a file is different on Windows than on unix (and I'm sure it is), you will have to create separate files for Windows. For this there is a temporary solution: you can place an "if" after a require. Take a look at the first two lines of https://github.com/manastech/crystal/blob/master/std/time.cr

Any doubts you have about how the compiler works, we can answer and help you :-)

Regards, Ary

— Reply to this email directly or view it on GitHubhttps://github.com/manastech/crystal/issues/26#issuecomment-24154638 .

asterite commented 11 years ago

I forgot to mention there are thousands of specs, so if you manage to pass them all you will be very close.

Lexer, parser, normalization and type inference specs, except those involving macros, should pass right away. Codegen specs will be the tough ones. On Sep 10, 2013 9:29 AM, "Justin Workman" notifications@github.com wrote:

Thanks, Ary! I will give it a shot. On Sep 10, 2013 5:09 AM, "Ary Borenszweig" notifications@github.com wrote:

Hi,

Thank you for your interest in Crystal!

Yes, it would be awesome to have Crystal running on Windows.

I don't think there is much to do on LLVM side to make it work, except having the necessary libraries to link to.

I read this the other day, it might be useful: http://www.phoronix.com/scan.php?page=news_item&px=MTQ1NjI

If you want to contribute, I think the path is the following:

  • Checkout the project and try to compile a simple program. A very simple program is just this: "1" (just an integer literal). But Crystal automatically includes a "prelude" file that gives you Array, Hash, etc. So you should comment these two lines (

https://github.com/manastech/crystal/blob/master/lib/crystal/compiler.rb#L120-L121)

so it will be easier to test. This point involves making LLVM work on Windows, specifically the ruby-llvm gem.

  • Once the previous point is working, you will need to make other programs work, mostly programs that depend on libc. For example you could try opening and writing a file with File.open("C:/foo.txt") { |file| file.write "Hello" }. If the API for opening and writing a file is different on Windows than on unix (and I'm sure it is), you will have to create separate files for Windows. For this there is a temporary solution: you can place an "if" after a require. Take a look at the first two lines of https://github.com/manastech/crystal/blob/master/std/time.cr

Any doubts you have about how the compiler works, we can answer and help you :-)

Regards, Ary

— Reply to this email directly or view it on GitHub< https://github.com/manastech/crystal/issues/26#issuecomment-24154638> .

— Reply to this email directly or view it on GitHubhttps://github.com/manastech/crystal/issues/26#issuecomment-24155615 .

xtagon commented 10 years ago

I apologize for forgetting to follow up on this. I was able to compile LLVM on Windows (that was a "fun" task in itself) but failed to get ruby-llvm working with it and eventually gave up (for now).

The website says that the Crystal compiler is now written in Crystal itself. Does that carry any implications as to how one might get it running on Windows? Do you think a better pursuit would be to make Crystal cross-compile (compile on Linux, run on Windows)?

asterite commented 10 years ago

Well, if you get cross-compilation to work that would indeed be awesome and very, very useful.

If you are on Mac or Linux you can download a preocmpiled compiler that will let you compile new versions of the compiler. Since such compiler doesn't exist for Windows, you will need to create one, but I'm not sure how. There are the options:

  1. Checkout the tag "ruby" and make that compiler work (in Ruby). That would involve making 'ruby-llvm' work, I guess. It will also involve making the code written in Crystal to work in windows (currently the compiler relies on some commands like "uname" to determine the operating system, I'm not sure cygwin or the libc for windows that we'll use will have those).
  2. Make cross compilation work. This has the advantage of not having to deal with 'ruby-llvm' (the LLVM wrapper in Crystal is much thinner and it's easier to make it work). I would try first to cross compiler from linux to Mac or from Mac to linux (if you have those available) to understand what is needed for cross compiling, and then try to cross compile to Windows.

Maybe you can tell us what problem you had with ruby-llvm on Windows. If you make that work, point 1 would be the easiest, I think.

Thanks!

xtagon commented 10 years ago

ruby-llvm says it requires LLVM built with shared library enabled. However, the LLVM CMake doc says "Shared libraries are not supported on Windows and not recommended in the other OSes."

I don't know whether "not supported" means it's not possible, so I'll try rebuilding LLVM and find out.

xtagon commented 10 years ago

Here is what happens when I try to install ruby-llvm:

C:\Users\Justin>gem install ruby-llvm --no-rdoc --no-ri --platform=ruby
Temporarily enhancing PATH to include DevKit...
Building native extensions.  This could take a while...
ERROR:  Error installing ruby-llvm:
        ERROR: Failed to build gem native extension.

    "C:/Ruby200-x64/bin/ruby.exe" -rubygems C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/rake-0.9.6/bin/rake RUBYARCHDIR=C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/ruby
-llvm-3.0.0/lib RUBYLIBDIR=C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/ruby-llvm-3.0.0/lib
g++ -shared support.cpp -IC:/Users/Justin/beta/sandbox/crystal/llvm/include -IC:/Users/Justin/beta/sandbox/crystal/build/include  /DWIN32 /D_WINDOWS /W3 /GR /EH
sc   /MP -wd4275 -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_SCL_SECURE_NO_DEPRECATE -D_SCL_S
ECURE_NO_WARNINGS -wd4146 -wd4180 -wd4244 -wd4267 -wd4345 -wd4351 -wd4355 -wd4503 -wd4624 -wd4800 -wd4291 -w14062 -we4238 -D__STDC_CONSTANT_MACROS -D__STDC_FORM
AT_MACROS -D__STDC_LIMIT_MACROS -LC:/Users/Justin/beta/sandbox/crystal/build/lib/  /machine:X86   -lLLVMJIT -lLLVMOption -lLLVMIRReader -lLLVMAsmParser -lLLVMIn
terpreter -lLLVMInstrumentation -lLLVMDebugInfo -lLLVMMCJIT -lLLVMRuntimeDyld -lLLVMExecutionEngine -lLLVMTableGen -lLLVMLTO -lLLVMObjCARCOpts -lLLVMLinker -lLL
VMipo -lLLVMVectorize -lLLVMBitWriter -lLLVMBitReader -lLLVMXCoreDisassembler -lLLVMXCoreCodeGen -lLLVMXCoreDesc -lLLVMXCoreInfo -lLLVMXCoreAsmPrinter -lLLVMX86
Disassembler -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMX86Desc -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMSystemZDisassembler -lLLVMSystemZCodeGen -
lLLVMSystemZAsmParser -lLLVMSystemZDesc -lLLVMSystemZInfo -lLLVMSystemZAsmPrinter -lLLVMSparcCodeGen -lLLVMSparcDesc -lLLVMSparcInfo -lLLVMR600CodeGen -lLLVMR60
0Desc -lLLVMR600Info -lLLVMR600AsmPrinter -lLLVMPowerPCCodeGen -lLLVMPowerPCAsmParser -lLLVMPowerPCDesc -lLLVMPowerPCInfo -lLLVMPowerPCAsmPrinter -lLLVMNVPTXCod
eGen -lLLVMNVPTXDesc -lLLVMNVPTXInfo -lLLVMNVPTXAsmPrinter -lLLVMMSP430CodeGen -lLLVMMSP430Desc -lLLVMMSP430Info -lLLVMMSP430AsmPrinter -lLLVMMipsDisassembler -
lLLVMMipsCodeGen -lLLVMMipsAsmParser -lLLVMMipsDesc -lLLVMMipsInfo -lLLVMMipsAsmPrinter -lLLVMHexagonCodeGen -lLLVMHexagonAsmPrinter -lLLVMHexagonDesc -lLLVMHex
agonInfo -lLLVMCppBackendCodeGen -lLLVMCppBackendInfo -lLLVMARMDisassembler -lLLVMARMCodeGen -lLLVMARMAsmParser -lLLVMARMDesc -lLLVMARMInfo -lLLVMARMAsmPrinter
-lLLVMAArch64Disassembler -lLLVMAArch64CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMi
pa -lLLVMAnalysis -lLLVMTarget -lLLVMCore -lLLVMAArch64AsmParser -lLLVMMCParser -lLLVMAArch64Desc -lLLVMAArch64Info -lLLVMAArch64AsmPrinter -lLLVMAArch64Utils -
lLLVMMCDisassembler -lLLVMMC -lLLVMObject -lgtest_main -lgtest -lLLVMSupport  -o ../../lib/RubyLLVMSupport-3.0.0.dll
g++: error: /DWIN32: No such file or directory
g++: error: /D_WINDOWS: No such file or directory
g++: error: /W3: No such file or directory
g++: error: /GR: No such file or directory
g++: error: /EHsc: No such file or directory
g++: error: /MP: No such file or directory
g++: error: unrecognized command line option '-wd4275'
g++: error: unrecognized command line option '-wd4146'
g++: error: unrecognized command line option '-wd4180'
g++: error: unrecognized command line option '-wd4244'
g++: error: unrecognized command line option '-wd4267'
g++: error: unrecognized command line option '-wd4345'
g++: error: unrecognized command line option '-wd4351'
g++: error: unrecognized command line option '-wd4355'
g++: error: unrecognized command line option '-wd4503'
g++: error: unrecognized command line option '-wd4624'
g++: error: unrecognized command line option '-wd4800'
g++: error: unrecognized command line option '-wd4291'
g++: error: unrecognized command line option '-w14062'
g++: error: unrecognized command line option '-we4238'
g++: error: /machine:X86: No such file or directory
rake aborted!
Command failed with status (1): [g++ -shared support.cpp -IC:/Users/Justin/...]

Tasks: TOP => default => build => RubyLLVMSupport-3.0.0.dll
(See full trace by running task with --trace)

Gem files will remain installed in C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/ruby-llvm-3.0.0 for inspection.
Results logged to C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/ruby-llvm-3.0.0/ext/ruby-llvm-support/gem_make.out

Any ideas?

Windows 7 64-bit Ruby 2.0.0p353 (with DevKit) Rubygems 2.0.14

Kelet commented 10 years ago

Hello,

I've been watching the development of Crystal for a while now, and I've become interested in possibly contributing to the ecosystem.

I'm posting in this issue because Windows support is integral to my adoption of the language. I work on both Windows and Linux and need all of my tools to work on both.

I'll be busy for the next couple of weeks, but I should have some free time toward the end of the month. I'd like to try and get Crystal compiling on Windows if possible. Is this information up to date? Judging by some of the recent blog posts, it seems out of date.

asterite commented 10 years ago

Hi @Kelet,

First, thanks for wanting to help in the development of Crystal!

My last comment is still up-to-date, I think. But now I think the best thing to do is to cross-compile from mac/linux to Windows. We can start by making a very simple "Hello World" and try to run it on Windows. This will be the program:

# file: hello.cr
lib C
  fun puts(str : UInt8*) : Int32
end

class String
  def cstr
    pointerof(@c)
  end
end

C.puts "Hello World!"

We will compile it like this:

bin/crystal foo.cr --prelude=empty --single-module

The "--prelude=empty" tells the compiler to not include the file prelude.cr and instead use empty.cr. This just defines the main function, which will contain whatever is in your program.

The "--single-module" just makes it generate a single LLVM module, otherwise it generates one per class/module. So this way is simpler.

Then we bind to the C function puts, which I don't know if it exists in Windows. If not, it should be replaced by another one provided by Windows that does that (I don't know much about Windows, it seems it does exist)

Then the String#cstr method just gets a pointer to the first character in the String. This method is used to implicitly convert a String to UInt8* by the compiler (I guess that method should be built-in so we don't have to do this...). But it's not a big deal anyway.

Then if you run it like this:

DUMP=1 bin/crystal foo.cr --prelude=empty --single-module

you will see the generated LLVM code:

; ModuleID = 'main_module'

%String = type { i32, i32, i8 }

@symbol_table = global [0 x %String*] zeroinitializer
@str = private constant { i32, i32, [13 x i8] } { i32 1, i32 12, [13 x i8] c"Hello World!\00" }

define i32 @__crystal_main(i32 %argc, i8** %argv) {
alloca:
  br label %const

const:                                            ; preds = %alloca
  br label %entry

entry:                                            ; preds = %const
  %0 = call i8* @"*String#cstr<String>:UInt8*"(%String* bitcast ({ i32, i32, [13 x i8] }* @str to %String*))
  %1 = call i32 @puts(i8* %0)
  ret i32 %1
}

define i32 @main(i32 %argc, i8** %argv) {
alloca:
  %argc1 = alloca i32
  %argv2 = alloca i8**
  br label %entry

entry:                                            ; preds = %alloca
  store i32 %argc, i32* %argc1
  store i8** %argv, i8*** %argv2
  %0 = load i32* %argc1
  %1 = load i8*** %argv2
  %2 = call i32 @__crystal_main(i32 %0, i8** %1)
  ret i32 0
}

define internal i8* @"*String#cstr<String>:UInt8*"(%String* %self) {
alloca:
  br label %entry

entry:                                            ; preds = %alloca
  %0 = getelementptr %String* %self, i32 0, i32 2
  ret i8* %0
}

declare i32 @puts(i8*)

We can get that LLVM code, put it in a file "hello.ll" in Windows and try to compile it:

llc hello.ll
clang hello.s -o hello
./hello
# prints: Hello World!

Of course these last commands are in linux/mac, for Windows it will be similar. We are using LLVM 3.3 so the commands might be named like llc-3.3, clang-3.3 and so on.

I don't know if in Windows the main function is just "int main(int argc, char\ argv)" or you always need to use WinMain (I think that's for graphical stuff).

There's a simple way to do all of the above: we use the --cross-compile flag:

bin/crystal hello.cr --prelude=empty --single-module --cross-compile "windows"

This will genreate a hello.bc file (similar to ll file, but binary). The last command will also print this:

llc hello.bc  -o hello.s && clang hello.s -o hello

So you copy the "hello.bc" file to Windows and executing that command should generate an executable.

The "windows" part passed to the --cross-compile flag just passes "windows" as a flag to the compiler so when you use ifdef it will be true. In linux/mac these flags are obtained by executing uname -m -s, lowercased and split by spaces. In fact, right now you can pass "" to the --cross-compile flag, but once we start with more complex program it would be nice to separte all windows stuff with ifdef windows.

If you manage to compile a Crystal program in linux/mac, copy the ll/bc file to Windows, compile it in Windows, execute it and get "Hello World!" in the conosle, we'll be a bit closer to having a compiler in Windows :-)

The next steps would be trying to compile bigger programs until we reach the program that is the compiler itself :-P

If you make some progress with the above, please let us know and we can continue trying to make it work.

Again, thanks for your help!

Kelet commented 10 years ago

Excellent, I'll try this process when I find some time and report back to you!

Kelet commented 10 years ago

I tried it out real quick:

$ llc hello.bc -o hello.s && clang -v hello.s -o hello
clang version 3.4 (198054)
Target: i686-pc-mingw32
Thread model: posix
Selected GCC installation:
 "c:\TDM-GCC-32\bin\gcc.exe" -v -c -m32 -o "C:\\Users\\Kyle\\AppData\\Local\\Temp\\hello-d405d2.o" -x assembler hello.s
Using built-in specs.
COLLECT_GCC=c:\TDM-GCC-32\bin\gcc.exe
Target: mingw32
Configured with: ../../../src/gcc-4.8.1/configure --build=mingw32 --enable-languages=ada,c,c++,fortran,lto,objc,obj-c++ --enable-libgomp --enable-lto --enable-graphite --enable-libstdcxx-debug --enable-threads=posix --enable-version-specific-runtime-libs --enable-fully-dynamic-string --enable-libstdcxx-threads --enable-libstdcxx-time --with-gnu-ld --disable-werror --disable-nls --disable-win32-registry --disable-symvers --enable-cxx-flags='-fno-function-sections -fno-data-sections -DWINPTHREAD_STATIC' --prefix=/mingw32tdm --with-local-prefix=/mingw32tdm --with-pkgversion=tdm-2 --enable-sjlj-exceptions --with-bugurl=http://tdm-gcc.tdragon.net/bugs
Thread model: posix
gcc version 4.8.1 (tdm-2)
COLLECT_GCC_OPTIONS='-v' '-c' '-m32' '-o' 'C:\Users\Kyle\AppData\Local\Temp\hello-d405d2.o' '-mtune=generic' '-march=pentiumpro'
 c:/tdm-gcc-32/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/as.exe -v -o C:\Users\Kyle\AppData\Local\Temp\hello-d405d2.o hello.s
GNU assembler version 2.23.1 (mingw32) using BFD version (GNU Binutils) 2.23.1
hello.s: Assembler messages:
hello.s:18: Error: invalid character '"' before operand 1
hello.s:45: Error: junk at end of line, first unrecognized character is `"'
hello.s:50: Error: junk at end of line, first unrecognized character is `"'
clang.exe: error: assembler (via gcc) command failed with exit code 1 (use -v to see invocation)

hello.s

    .def     @feat.00;
    .scl    3;
    .type   0;
    .endef
    .globl  @feat.00
@feat.00 = 1
    .def     ___crystal_main;
    .scl    2;
    .type   32;
    .endef
    .text
    .globl  ___crystal_main
    .align  16, 0x90
___crystal_main:                        # @__crystal_main
# BB#0:                                 # %entry
    pushl   %eax
    movl    $L_str, (%esp)
    calll   "_*String#cstr<String>:UInt8*"
    movl    %eax, (%esp)
    calll   _puts
    popl    %edx
    ret

    .def     _main;
    .scl    2;
    .type   32;
    .endef
    .globl  _main
    .align  16, 0x90
_main:                                  # @main
# BB#0:                                 # %alloca
    subl    $16, %esp
    movl    24(%esp), %eax
    movl    20(%esp), %ecx
    movl    %ecx, 12(%esp)
    movl    %eax, 8(%esp)
    movl    12(%esp), %ecx
    movl    %eax, 4(%esp)
    movl    %ecx, (%esp)
    calll   ___crystal_main
    xorl    %eax, %eax
    addl    $16, %esp
    ret

    .def     "_*String#cstr<String>:UInt8*";
    .scl    3;
    .type   32;
    .endef
    .align  16, 0x90
"_*String#cstr<String>:UInt8*":         # @"*String#cstr<String>:UInt8*"
# BB#0:                                 # %alloca
    movl    4(%esp), %eax
    addl    $8, %eax
    ret

    .bss
    .globl  _symbol_table           # @symbol_table
    .align  4
_symbol_table:

    .section    .rdata,"r"
    .align  16                      # @str
L_str:
    .long   1                       # 0x1
    .long   12                      # 0xc
    .asciz  "Hello World!"
    .zero   3
asterite commented 10 years ago

Cool! That's progress.

It seems clang for windows doesn't like names like "_String#cstr:UInt8" for labels.

What happens if you change:

"_*String#cstr<String>:UInt8*"

to this:

String_cstr

in the hello.s file and try to execute clang -v hello.s -o hello again?

asterite commented 10 years ago

Or maybe to:

_String_cstr

(I see all .def in the file start with _... so just in case...)

Kelet commented 10 years ago

Both String_cstr and _String_cstr work like a charm and print out "Hello World!"

asterite commented 10 years ago

Awesome!! :-)

So our first step is to have a different mangling for functions, at least for Windows. I'll think of something. I don't think replacing all non-alphanumeric characters to underscore will work, but it need to be thought a bit to avoid conflicts between definitions.

I'll let you know when I do this. In the meantime you can try to do it. The method that mangles a name is here, just in case you wonder or want to try to change it too.

asterite commented 10 years ago

@Kelet, can I ask you to try something else?

What happens if you use _String.cstr instead of _String_cstr? I'm trying to find out which characters are allowed...

Kelet commented 10 years ago

Yep, it works. Dollar signs, periods, and underscores should work according to the manual.

Flaise commented 9 years ago

Any progress on this issue? Crystal looks like exactly the kind of language I'd like to begin using for new projects but the lack of Windows support is a dealbreaker for me - Windows is where you find paying customers and I can't be investing myself in something that locks me out of having an audience.

G4MR commented 9 years ago

@Flaise yeah I agree, I'd love to try this on windows.

bararchy commented 9 years ago

So, Trying to build the Windows branch using the instructions in: https://github.com/manastech/crystal/blob/windows/README_win32.md

Step 1 produces:

 bin/crystal build src/compiler/crystal.cr --cross-compile "windows x86" --single-module --target "i686-pc-win32-gnu" --release -o bin/crystal
Error in ./src/file/stat.cr:81: undefined constant Stat

  fun stat(path : UInt8*, stat : Stat*) : Int32
                                 ^~~~
bararchy commented 9 years ago

Using @xwanderer fork from https://github.com/xwanderer/crystal/tree/win32 I get a similar issue regarding types

 bin/crystal build src/compiler/crystal.cr --cross-compile "windows x86" --single-module --target "i686-pc-win32-gnu" -o win32/crystal
Error while requiring "prelude"

in ./src/prelude.cr:17: while requiring "iterator"

require "iterator"
^

Syntax error in ./src/iterator.cr:194: type variables can only be single letters

  struct Zip(I1, I2, T1, T2)
             ^
rishavs commented 9 years ago

Just wanted to add my support to this. I really want to try out Crystal but not at the cost of my favored platform and environment.

david50407 commented 8 years ago

And I'm going to support on this, too. I'm trying to make the Crystal compiler run on Windows first, and go building std-lib on windows then.

refi64 commented 8 years ago

@david50407 Well, the compiler is written in Crystal, so you kind of need to do both at the same time...maybe Cygwin could help there?

david50407 commented 8 years ago

@kirbyfan64 I tried this way https://github.com/manastech/crystal/issues/26#issuecomment-40704994 , and run Hello world program well with LLVM 3.7 on Windows with TDM-GCC 5.1.0

Then I'm going to make Crystal compiler can be cross-compiled to Windows, for this, I will make a part of std-lib (core libs?) works that compiler needs.

EDIT: Or use Crystal to build LLVM code, use LLC to generate object file, but link with MSVC link works well, too.

ozra commented 8 years ago

So glad to see progress and interest on this front!

mverzilli commented 8 years ago

+1, it's great seeing someone brave enough to tackle this! <3

anilreddy commented 8 years ago

+1

nob-suz commented 8 years ago

+1 looking forward to see!, and there is recent LLVM Clang for MSVC&,NET http://www.theregister.co.uk/2015/10/21/microsoft_promises_clang_for_windows_in_november_visual_c_update/

david50407 commented 8 years ago

It is a problem that Windows doesn't provide some POSIX Process calls, like fork(), getsid(), ...etc.

I saw the solution in Ruby, it decide to raise NotImplementedError and tell user "the function is unimplemented on this machine". ( https://github.com/ruby/ruby/blob/trunk/process.c#L3690 )

Should I do the same behavior like Ruby (, throws an Exception), when I cannot find the solution on Windows? (like Process.fork()) I think this will keep std-lib in the same interface (, that is, making std-lib more platform indepedent), and let coder (who codes in Crystal) to check the document and catch the Exception by their own (without causing error on compile-time).

But I don't know if raising Exception on runtime is better than throwing error on compile-time or not. How about you guys think?

jhass commented 8 years ago

It should fail to compile IMO, either by calling raise in a macro or simply letting it run into an undefined call.

lowjoel commented 8 years ago

I think a compile-time error is more suitable, since Crystal is a compiled language, and we want to catch as many errors as early on as possible.

david50407 commented 8 years ago

@jhass , I think raising NotImplementedExecption is better than undefined error.

Many languages does this on runtime, like Ruby, Python, Java, C# (even have NotImplementedException and NotSupporttedException), etc., they throw exceptions to keep the spec (or I mean the interface) of libs generally. (And it also make document auto-generating more easier.)

But we don't have VM in Crystal (, means we need to compile every time when generating other platform's executable files) , so we can just raise execption on compile-time.

And std-libs are not just C/lib bindings, they should make Crystal has a good interface to make coders build more portable applications.

david50407 commented 8 years ago

I have one more problem when I'm trying to make compiler throws the exception on compile-time, does there any trick to show which method is 'not supported yet'?

for the code below:

macro raise_not_implement_yet_exception
  {% raise "Not Impl. yet" %}
end

class Foo
  def test
    raise_not_implement_yet_exception
  end
end

Foo.new.test

it's error like this:

Error in ./not_impl.cr:11: instantiating 'Foo#test()'

Foo.new.test
        ^~~~

in ./not_impl.cr:7: expanding macro

  raise_not_implement_yet_exception
  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

in ./not_impl.cr:2: can't expand macro: Not Impl. yet

 {% raise "Not Impl. yet" %}
    ^~~~~

I think it doesn't point out which method is 'Not Impl. yet' clearly, and it looks like it's just a macro expansion error.

bcardiff commented 8 years ago

@david50407 you can puts in compile time. It does looks a bit better. http://play.crystal-lang.org/#/r/ml8

[Regarding runtime vs compile time] If the unsupported operations do not compile then the specs won't compile as a whole. I would prefer to have a flag that shows a progress regarding how much of the stdlib is supported in windows. But, this might be more a issue of spec. Yet, as things are right now, I would vote for runtime exceptions for this case. In the long term a compilation errors sounds better.

lowjoel commented 8 years ago

I have not used much Crystal, but how about something radical -- put the platform-specific functionality in a library/module/include (sorry...) that needs to be explicitly imported? I gather most of these functionality that can't be implemented on Windows is due to it being Unix syscalls, and it's likely that this would be all implemented, or not implemented at all.

There are some edge cases, like OS X not supporting anonymous semaphores and stuff like that, but I think that's a little easier to deal with.

[I initially followed this because I was short on time, and also I wanted to try to get this to work so I can experiment with the language at my leisure, sorry for being uninformed.]

david50407 commented 8 years ago

@lowjoel, In Ruby, you still can call Process.fork() on Windows, but it will raise an exception; But in golang, it even don't have fork() call! The question is: how to divide out which is platform-independent method and which is platform-specific method? As I said, std-lib should be the interface that you and I can use the method without worrying about if this method is platform-independent or have to call in another way on different platform.

BTW, And Crystal seems to only compile the code we called not whole modules right now.

david50407 commented 8 years ago

@bcardiff @lowjoel How about making these not/un-supported methods warn (, or just showing some message for now,) on compile-time, and raise on runtime. Because we have spec written in Crystal, if we want to test the spec, we have to pass the compilation first, and check these methods raise normally.

refi64 commented 8 years ago

Well, Ruby isn't an error since nothing is an error until you try it...so it isn't the best example...

Honestly, it should be a compile-time error. I can't think of a single case that it would actually be desired.

david50407 commented 8 years ago

@kirbyfan64 which one you think is better? raise in macro or just let the method undefined?

rishavs commented 8 years ago

I would recommend not leaving it undefined.

ozra commented 8 years ago

If using unsupported functionality when compiling for a certain platform it should definitely error at compile time! And as many already mentioned, preferably with a more specific error "not implemented for this platform", rather than just "method missing".

ysbaddaden commented 8 years ago

Raising in macros is unsupported as of now. For now, please raise a specific exception at runtime eg: NotImplementedError). Specs will then show what needs to be implemented.

If a feature is impossible for a specific platform (eg: fork) then skip the method definition, so code won't compile. Please open an issue if it's not satisfactory —we could have @unsupported "message" just like it was proposed to have @deprecated "message", but that won't happen until we get near to 1.0

Also, please check the work by xwanderer on porting Crystal to windows, before restarting from scratch.

Last but not least, in order to avoid daily merge errors, it could be interesting to englob code, especially when the code is mostly about reimplementing than fixing for a platform:

# src/file.cr
ifdef windows
  require " windows/file"
else
# untouched source code
end
david50407 commented 8 years ago

@ysbaddaden I'm merging master into xwanderer's win32 branch and upgrading the exist code to 0.9.1, so these methods are in single file now.

I'm going to open an issue for @unsupported "message", it is a great solution for marking unsupported methods IMO.

And I'll try to divide out the platform-specific codes. Will Linux, Mac OS X, and other platform we may support later be in this form in the future?

EDIT: Or should I create a new branch based on master and add codes in that form? (not merging xwanderer's code directly)

ysbaddaden commented 8 years ago

Your call. A windows port is a long task. I proposed to make as minimal as possible changes to the current code that is likely to change often, so your work won't be hard, if not impossible, to merge eventually and during all the development process.

The current code may eventually follow the same pattern, or not. That depends if other platforms are very different or if it's mostly a Windows vs Unix thing — libc bindings will eventually be generated automatically by crystal_lib from C headers so there is no need to extract them for each Unix platform.

david50407 commented 8 years ago

We need SEH (Structured Exception Handling) for unwinding, and LLVM supported new intrinsics for windows from LLVM 3.8, but we are still using LLVM 3.5/3.6.

So we may wait for upgrading to 3.8/3.9 or I'll try other ways to use SEH. :cry: Or we can wait for the new compiler (#1824) to using 3.8 or above lol

asterite commented 8 years ago

Until we support Windows, it seems it's possible to run it in the Ubuntu bash inside Windows: https://www.reddit.com/r/crystal_programming/comments/4m9fjd/i_got_crystal_to_install_in_the_ubuntu_bash/

david50407 commented 8 years ago

@asterite :tada: But it seems that cannot use Windows API and creating some cool GUI applications :disappointed:

asterite commented 8 years ago

@david50407 True. That's why I don't understand why everyone wants Crystal for Windows. We'd need to bind the whole Windows API. I believe C# is a better language for that, as it also comes with Visual Studio and you have a visual editor, etc.

xtagon commented 8 years ago

I think what people really want is Ruby on Windows, but compiled instead of interpreted, so they look to Crystal.