Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

compiling zig on windows without visual studio #528

Closed
pluto439 opened this issue Oct 9, 2017 · 27 comments
Closed

compiling zig on windows without visual studio #528

pluto439 opened this issue Oct 9, 2017 · 27 comments
Labels
enhancement Solving this issue will likely involve adding new logic or components to the codebase.
Milestone

Comments

@pluto439
Copy link

pluto439 commented Oct 9, 2017

I'd like to log progress on it somewhere. Can't wait to try out zig on windows.

Author intends to get zig working with visual studio first, and only then work on other compilers. But I can't get visual studio to work here, so I have to wait. But let's try working in parallel...

First, ci/appveyor/build_script.bat is pretty confusing. The most confusing part is getting three vars, which evaluate to this on my system:

ZIG_LIBC_LIB_DIR
C:/msys64/mingw32/i686-w64-mingw32/lib

ZIG_LIBC_INCLUDE_DIR
C:/msys64/mingw32/i686-w64-mingw32/include

ZIG_LIBC_STATIC_LIB_DIR
C:/msys64/mingw32/lib/gcc/i686-w64-mingw32/6.3.0

It looks like their purpose is locating crt1.o and crtbegin.o. Shouldn't it be possible to work without them? Support table says that compiling freestanding exe on windows already works.

Is it possible to make 4 build targets for windows instead of one?
32bit
32bit-freestanding
64bit
64bit-freestanding

@andrewrk
Copy link
Member

andrewrk commented Oct 9, 2017

I'd like to log progress on it somewhere. Can't wait to try out zig on windows.

Glad to hear that because I've been doing a lot of work on windows in the past couple weeks.

It looks like their purpose is locating crt1.o and crtbegin.o. Shouldn't it be possible to work without them? Support table says that compiling freestanding exe on windows already works.

It is possible to work without them. These are needed if you want to include libc .h files such as stdlib.h or if you want to link against libc (which you almost certainly will have to if you depend on any C libraries).

If you wanted to run the zig compiler tests you would need a working libc as well since some of the tests test libc integration.

Is it possible to make 4 build targets for windows instead of one?
32bit

--target-os windows --target-arch i386 --target-environ msvc

32bit-freestanding

--target-os freestanding --target-arch i386 --target-environ msvc

64bit

--target-os windows --target-arch x86_64 --target-environ msvc

64bit-freestanding

--target-os freestanding --target-arch x86_64 --target-environ msvc

If you want artifacts to have the mingw C ABI instead of msvc, change msvc to gnu.

I think we need to update the linker code in zig for --environ gnu to work on windows. We also might want to wait for llvm 6.0 which has a mingw environ target and LLD supports the mingw linker args.

However you can always use zig to create a mingw compatible .o file using --environ gnu and use the mingw linker (or just mingw clang) yourself.

We do have zig building successfully with mingw and it looks like most tests are passing, so you should be able to play with this.

@pluto439
Copy link
Author

pluto439 commented Oct 9, 2017

--target-os freestanding --target-arch i386 --target-environ msvc

Are those cmake arguments? If those are zig arguments, I need to get zig itself first. I asked you to modify ci/appveyor/build_script.bat , so that it doesn't have that weird bash magic. and just compiles.

Can you at least upload compiled zig for windows somewhere?

These are needed if you want to include libc .h files such as stdlib.h or if you want to link against libc (which you almost certainly will have to if you depend on any C libraries).

I don't depend on any C libraries. That's the whole point of freestanding exe files: only system provided dll. I'm a fan of demoscene, you see. Size matters, and all. I'll probably actually rewrite most of the libraries in zig, or at least those that I need.

If you wanted to run the zig compiler tests you would need a working libc as well since some of the tests test libc integration.

Can't care less about those tests, don't want to wait for them to pass. These are probably not necessary for me.

When I say "freestanding", I mean exe file that doesn't depend on C runtime, and only interacts with system provided dll directly. Is that the right use of that word? Or "freestanding" actually means just some object code that can't be even run by itself?

@andrewrk
Copy link
Member

andrewrk commented Oct 9, 2017

Can you at least upload compiled zig for windows somewhere?

I'm working on it as we speak. Here's the checklist I'm going through: #302

I don't depend on any C libraries. That's the whole point of freestanding exe files: only system provided dll. I'm a fan of demoscene, you see. Size matters, and all. I'll probably actually rewrite most of the libraries in zig, or at least those that I need.

Right. This is one of the main use cases of zig, so I am excited for you to try it out. In this case you do not need the ZIG_LIBC* configure arguments.

Can you try building with mingw without those configure arguments? It should work fine and then panic if you try to do anything with libc.

"freestanding" in zig lingo means that you are either compiling your own OS or targeting an OS that zig doesn't know about. (See the list output by zig.exe targets).

You're targeting Windows so you'll want to either compile natively (no --target-* arguments) or use --target-os windows. This has some effects on the code generated by LLVM, for example it will generate __chkstk calls if a stack frame is larger than a page, and it will mangle DLL calls by prepending an underscore, and do the stdcall mangling convention.

If you're doing demoscene stuff I'm guessing you want to avoid __chkstk as well as write your own startup code instead of relying on zig's startup code: https://github.com/zig-lang/zig/blob/a4310cf8b4f104802360cb854e2dcc48802301a6/std/special/bootstrap.zig#L34-L44

(actually now that I think of it, we should figure out how to tell LLVM to turn off __chkstk in release-fast mode)

And probably your own compiler-rt and memcpy/memset implementations instead of zig's compiler-rt and zig's memcpy/memset.

In this case I think you're right that freestanding is what you want. I've used freestanding to build an OS but I haven't tried to run freestanding code on windows yet and I'd like to do that before recommending something to you.

Perhaps you could live with zig's startup code and target windows for a little bit, then when you want to really optimize the last 1% we can move forward on this? Or play around with freestanding, hack on zig, sounds like you know what you're doing. I'm on IRC if you want to chat.

Don't forget to build with --release-fast to omit all the safety checks. ⚡

@andrewrk
Copy link
Member

andrewrk commented Oct 9, 2017

Size matters, and all.

One more thing. We currently have these build modes:

  • Debug (safety on, fast compilation, slow runtime performance, big binary)
  • ReleaseSafe (safety on, slow compilation, medium runtime performance, big binary)
  • ReleaseFast (safety off, slow compilation, fast runtime performance, big binary)

I'm considering adding

  • ReleaseSmall (safety off, slow compilation, medium-fast runtime performance, small binary)

Is this something you would be interested in?

@pluto439
Copy link
Author

pluto439 commented Oct 9, 2017

Ideally ReleaseFast and ReleaseSmall should be the same, don't see much reason in separating those. But until we get there, sure, why not.

I'll set CodeGen.libc_static_lib_dir to empty string and see if anything breaks. I'll also start rewriting build system in bat and makefiles, because I'm having troubles with understanding cmake.

@andrewrk
Copy link
Member

andrewrk commented Oct 9, 2017

Ideally ReleaseFast and ReleaseSmall should be the same, don't see much reason in separating those. But until we get there, sure, why not.

Here are a couple reasons:

  • SIMD instructions. Sometimes faster code using SIMD ends up being bigger.
  • Unrolling loops. Sometimes unrolling loops is faster and takes up more space in the binary.

This is the same reason GCC/clang have -O3 and -Os.

I'll also start rewriting build system in bat and makefiles, because I'm having troubles with understanding cmake.

ok. feel free to post an error log, I can probably tell you how to fix whatever happened.

@pluto439
Copy link
Author

pluto439 commented Oct 9, 2017

It sounds like it will also make simplier assembly. Then yes, it's a good idea, make ReleaseSmall.

@andrewrk
Copy link
Member

andrewrk commented Oct 9, 2017

Issue to track it: #531

@pluto439
Copy link
Author

How do you think, will zig build as a 32bit app? Or I must have it 64bit?

@andrewrk
Copy link
Member

Currently the zig compiler only works as 64-bit. We'll make it work as a 32-bit application when we self-host (See #89)

@pluto439
Copy link
Author

Ok, zig got built, and it actually works. Except it deadlocks on exit. Really weird.

I create this _.zig file next to zig.exe, with this content:

use @import("std").os.windows;

export fn WinMainCRTStartup() -> INT {
    _ = MessageBoxA(null, c"hello", c"title", 0);
    return 0;
}

and type this to compile it:

zig build-exe _.zig --target-os windows --target-arch i386 --target-environ gnu --release-fast -mwindows

It works nicely, result works, but zig itself never exits.

I tried to get callstack with x64dbg, here it is. Ignore everything that's not "Comment", read from bottom to top:

Address           To                From              Size              Comment                                            Party
000000000022F848  000007FEFD8A1420  000000007763C3EA  100               ntdll.000000007763C3EA                             System
000000000022F948  00000000773E06D0  000007FEFD8A1420  90                kernelbase.000007FEFD8A1420                        System
000000000022F9D8  0000000064941EAD  00000000773E06D0  60                kernel32.00000000773E06D0                          User
000000000022FA38  00000000649421A0  0000000064941EAD  80                libwinpthread-1.0000000064941EAD                   User
000000000022FAB8  0000000064942721  00000000649421A0  B0                libwinpthread-1.00000000649421A0                   User
000000000022FB68  000000006FCD8A7C  0000000064942721  30                libwinpthread-1.0000000064942721                   User
000000000022FB98  0000000070216BFB  000000006FCD8A7C  80                libstdc++-6.000000006FCD8A7C                       User
000000000022FC18  00000000701C11D7  0000000070216BFB  60                llvm.0000000070216BFB                              User
000000000022FC78  00000000701C12D8  00000000701C11D7  50                llvm.00000000701C11D7                              User
000000000022FCC8  0000000077612B31  00000000701C12D8  120               llvm.00000000701C12D8                              System
000000000022FDE8  0000000077612940  0000000077612B31  30                ntdll.0000000077612B31                             System
000000000022FE18  000007FEFDD499E2  0000000077612940  40                ntdll.0000000077612940                             System
000000000022FE58  00000000004014D5  000007FEFDD499E2  D0                msvcrt.000007FEFDD499E2                            User
000000000022FF28  000000000040152B  00000000004014D5  30                zig.00000000004014D5                               User
000000000022FF58  00000000773E59DD  000000000040152B  30                zig.000000000040152B                               System
000000000022FF88  000000007761A631  00000000773E59DD  50                kernel32.00000000773E59DD                          System
000000000022FFD8  0000000000000000  000000007761A631                    ntdll.000000007761A631                             User

ntdll kernel32 msvcrt ntdll kernelbase are system dlls, libstdc++-6 libwinpthread-1 are from mingw-w64 (for some reason they are added to every program compiled with mingw, unless they are linked statically), there is llvm, there is zig

What I understood from it, is that zig calls exit from msvcrt, then other system dlls, then for some reason control flow goes back into llvm, then libstdc++, it calls pthread_cond_wait from libwinpthread, then some other system dlls.

I guess pthread_cond_wait is the cause of this. I'm not sure why llvm code gets executed at closing program, that's some C++ magic right here.

@andrewrk
Copy link
Member

I'm not sure why llvm code gets executed at closing program, that's some C++ magic right here.

It doesn't happen with the msvc build, so it seems like a bug in mingw. Can probably work around by patching zig to call _exit (skips atexit handlers) instead of exit when built with mingw. Do you want to try it?

@pluto439
Copy link
Author

Replaced return EXIT_SUCCESS with _exit(EXIT_SUCCESS) and ExitProcess(EXIT_SUCCESS), no effect.

I replaced this one: https://github.com/zig-lang/zig/blob/8cfb0cfbcee8161c52f71bccc3cf1b8d988f83b0/src/main.cpp#L793

Linking is so slow here.

@PavelVozenilek
Copy link

PavelVozenilek commented Oct 16, 2017

Deadlock on application exit is often caused by invocation of user code in DllMain when the DLL is unloaded. Such code is subject of restrictions but few care.

This is the hammer to exit w/o notifying DLLs:

TerminateProcess(GetCurrentProcess(), EXIT_SUCCESS);

Alternatively, one may try to unload suspected DLL manually (by repeated calling FreeLibrary/FindLibrary) before termination.

@andrewrk andrewrk added the enhancement Solving this issue will likely involve adding new logic or components to the codebase. label Oct 16, 2017
@andrewrk andrewrk added this to the 0.2.0 milestone Oct 16, 2017
@andrewrk
Copy link
Member

I think we want to do this on Windows anyway. There is no point in calling a DLL unload code.

@pluto439
Copy link
Author

I'm new to git, how can I keep TerminateProcess in the code, but still get updates?

TerminateProcess worked nicely, now I don't have to open task manager every time.

@andrewrk
Copy link
Member

@pluto439

When you want an update:

git stash
git pull
git stash pop

Can you send me the diff so that I can merge it upstream? GitHub pull request is easiest for me but I don't mind if you just want to paste a diff.

@pluto439
Copy link
Author

It's a terrible thing to merge, it only works on windows, it only works for one combination of console commands. But it works for now.

Probably should recompile llvm instead, maybe they fixed it by now.

Also don't know how to make diff here.

@andrewrk
Copy link
Member

Also don't know how to make diff here.

git diff

It's a terrible thing to merge, it only works on windows, it only works for one combination of console commands. But it works for now.

ok

@andrewrk andrewrk modified the milestones: 0.2.0, 0.3.0 Oct 19, 2017
@pluto439
Copy link
Author

It takes 6 minutes to link zig.exe together. I need to decrease that time somehow if I want to get anywhere.

I suspect that adding -Wa,-mbig-obj to compiler flags might help. Need to add them somewhere in deps/lld/CMakeLists.txt. Where exactly should I add them?

https://stackoverflow.com/questions/16596876/object-file-has-too-many-sections

@andrewrk
Copy link
Member

deps/lld/CMakeLists.txt is ignored. All cmake stuff is in the root CMakeLists.txt. Search for LINK_FLAGS.

@pluto439
Copy link
Author

-Wa,-mbig-obj didn't work.

Built lld as dll, it worked, linking only takes 10 seconds. Object files were so odd, they had thousands of sections.

I replaced this:

    add_library(embedded_lld_lib ${EMBEDDED_LLD_LIB_SOURCES})
    add_library(embedded_lld_elf ${EMBEDDED_LLD_ELF_SOURCES})
    add_library(embedded_lld_coff ${EMBEDDED_LLD_COFF_SOURCES})

with this:

    add_library(embedded_lld_lib SHARED ${EMBEDDED_LLD_LIB_SOURCES})
    add_library(embedded_lld_elf SHARED ${EMBEDDED_LLD_ELF_SOURCES})
    add_library(embedded_lld_coff SHARED ${EMBEDDED_LLD_COFF_SOURCES})

    target_link_libraries(embedded_lld_coff ${LLVM_LIBRARIES} ${CLANG_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} embedded_lld_lib)
    target_link_libraries(embedded_lld_elf ${LLVM_LIBRARIES} ${CLANG_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} embedded_lld_lib)
    target_link_libraries(embedded_lld_lib ${LLVM_LIBRARIES} ${CLANG_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})

And to free myself from ninja install every time, changed this:

install(TARGETS zig DESTINATION bin)

to this:

install(TARGETS zig DESTINATION .)

@andrewrk
Copy link
Member

Ah if that improved link time, you night also improve link time by linking against libLLVM.so instead of individual libraries and the .so versions of clang libraries instead of .a

@andrewrk
Copy link
Member

You would edit cmake/Findllvm.cmake and cmake/Find clang.cmake

@pluto439
Copy link
Author

Yeah, I'm already linking to LLVM.dll that came with msys2, I didn't compile it myself. It's probably the reason why it deadlocks. It worked like that out of the box, without me editing findcmake files.

@pluto439
Copy link
Author

pluto439 commented Oct 30, 2017

Uploaded everything I said in this thread as a mingw.patch, since I now know how to do those. In a zip, github doesn't support .patch

mingw.zip

A few notes for me:

To create:
git diff > mingw.patch

To apply (made pa.bat for it):
git apply mingw.patch

To reverse (made pu.bat for it):
git apply -R mingw.patch

I guess I'll just keep unapplying and applying this patch every time I need to get newest version from git.

To actually compile, use this:

mkdir build
cd build
cmake -G"Ninja" .. -DCMAKE_INSTALL_PREFIX=.
ninja install

To get a short beep once it's done compiling, use this:

ninja install && python -c "print '\7'"

@andrewrk andrewrk modified the milestones: 0.3.0, 0.4.0 Feb 28, 2018
@andrewrk andrewrk modified the milestones: 0.4.0, 0.5.0 Sep 28, 2018
@emekoi
Copy link
Contributor

emekoi commented Jan 13, 2019

@andrewrk closed by #1542.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Solving this issue will likely involve adding new logic or components to the codebase.
Projects
None yet
Development

No branches or pull requests

4 participants