Closed geelen closed 4 years ago
Unfortunately it is not possible to link .dylib files to Emscripten. The reason for that is that the .dylibs already contain native machine code for x86/x64, and Emscripten cannot "go back" and get that to LLVM IR form again. What one would have to do is implement the standard library for Swift and compile that in. The unrecognized struct value errors sounds like something unrelated to this linking issue.
Perhaps it might be possible to stub in those standard library functions with your own implementation?
Interesting, I suspected as much, but had hoped dylibs might have llvm bitcode in there.
I'll take a look to see how much of the Swift standard library source is available to compile from, but I fear it won't be enough.
Appreciate the response, thanks!
On Saturday, June 14, 2014, juj notifications@github.com wrote:
Unfortunately it is not possible to link .dylib files to Emscripten. The reason for that is that the .dylibs already contain native machine code for x86/x64, and Emscripten cannot "go back" and get that to LLVM IR form again. What one would have to do is implement the standard library for Swift and compile that in. The unrecognized struct value errors sounds like something unrelated to this linking issue.
Perhaps it might be possible to stub in those standard library functions with your own implementation?
— Reply to this email directly or view it on GitHub https://github.com/kripken/emscripten/issues/2427#issuecomment-46086938.
What if we implement our own standard lib, according to http://practicalswift.com/2014/06/14/the-swift-standard-library-list-of-built-in-functions there are just 74 functions
If the println
command was omitted, would this work? (it didn't for me, I still got the same result, but I'm very ignorant) Then one could create a library and just call it from js without it depending on anything.
Also, an update, the commands in the first post seem deprecated, here is what I tried:
Versions
$ xcrun swiftc --version
Swift version 1.0 (swift-600.0.45.3.2)
Target: x86_64-apple-darwin13.2.0
$ emcc --version
emcc (Emscripten GCC-like replacement) 1.25.0 ()
Copyright (C) 2014 the Emscripten authors (see AUTHORS.txt)
This is free and open source software under the MIT license.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
The file to compile:
$ cat f.swift
var message = 1
The IR
$ xcrun swiftc -emit-ir f.swift
; ModuleID = '-'
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-darwin13.2.0"
%Si = type <{ i64 }>
@_Tv1f7messageSi = global %Si zeroinitializer, align 8
define internal void @top_level_code() {
entry:
store i64 1, i64* getelementptr inbounds (%Si* @_Tv1f7messageSi, i32 0, i32 0), align 8
ret void
}
define i32 @main(i32 %argc, i8** %argv) {
entry:
%0 = call i8* @_TFSsa6C_ARGCVSs5Int32()
%1 = bitcast i8* %0 to i32*
store i32 %argc, i32* %1
%2 = call i8* @_TFSsa6C_ARGVGVSs20UnsafeMutablePointerGS_VSs4Int8__()
%3 = bitcast i8* %2 to i8***
store i8** %argv, i8*** %3
call void @top_level_code()
ret i32 0
}
declare i8* @_TFSsa6C_ARGCVSs5Int32()
declare i8* @_TFSsa6C_ARGVGVSs20UnsafeMutablePointerGS_VSs4Int8__()
!llvm.module.flags = !{!0, !1, !2, !5, !6, !7, !8}
!0 = metadata !{i32 2, metadata !"Dwarf Version", i32 3}
!1 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
!2 = metadata !{i32 6, metadata !"Linker Options", metadata !3}
!3 = metadata !{metadata !4}
!4 = metadata !{metadata !"-lswiftCore"}
!5 = metadata !{i32 1, metadata !"Objective-C Version", i32 2}
!6 = metadata !{i32 1, metadata !"Objective-C Image Info Version", i32 0}
!7 = metadata !{i32 1, metadata !"Objective-C Image Info Section", metadata !"__DATA, __objc_imageinfo, regular, no_dead_strip"}
!8 = metadata !{i32 4, metadata !"Objective-C Garbage Collection", i32 0}
The SIL (IDK if it's useful, but can't hurt):
$ xcrun swiftc -emit-sil f.swift
sil_stage canonical
import Builtin
import Swift
import SwiftShims
var message: Int
// top_level_code
sil private @top_level_code : $@thin () -> () {
bb0:
%0 = global_addr #message : $*Int // user: %3
%1 = integer_literal $Builtin.Word, 1 // user: %2
%2 = struct $Int (%1 : $Builtin.Word) // user: %3
store %2 to %0 : $*Int // id: %3
%4 = tuple () // user: %5
return %4 : $() // id: %5
}
// Swift.Int._convertFromBuiltinIntegerLiteral (Swift.Int.Type)(Builtin.Int2048) -> Swift.Int
sil public_external [transparent] @_TFSi33_convertFromBuiltinIntegerLiteralfMSiFBi2048_Si : $@thin (Builtin.Int2048, @thin Int.Type) -> Int {
bb0(%0 : $Builtin.Int2048, %1 : $@thin Int.Type):
%2 = builtin_function_ref "s_to_s_checked_trunc_Int2048_Word" : $@thin (Builtin.Int2048) -> (Builtin.Word, Builtin.Int1) // user: %3
%3 = apply %2(%0) : $@thin (Builtin.Int2048) -> (Builtin.Word, Builtin.Int1) // user: %4
%4 = tuple_extract %3 : $(Builtin.Word, Builtin.Int1), 0 // user: %5
%5 = struct $Int (%4 : $Builtin.Word) // user: %6
return %5 : $Int // id: %6
}
Trying to compile with emcc:
$ xcrun swiftc -emit-bc f.swift -o f.bc
$ emcc f.bc
WARNING: Linking two modules of different data layouts: '/Users/josh/.emscripten_cache/libc.bc' is 'e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-p:32:32:32-v128:32:128-n32-S128' whereas '/Users/josh/deleteme/swift-play/f.bc' is 'e-m:o-i64:64-f80:128-n8:16:32:64-S128'
WARNING: Linking two modules of different target triples: /Users/josh/.emscripten_cache/libc.bc' is 'asmjs-unknown-emscripten' whereas '/Users/josh/deleteme/swift-play/f.bc' is 'x86_64-apple-darwin13.2.0'
Unknown specifier in datalayout string
UNREACHABLE executed at /Users/clb/emscripten-fastcomp/lib/IR/DataLayout.cpp:300!
0 opt 0x00000001086d04ae llvm::sys::PrintStackTrace(__sFILE*) + 46
1 opt 0x00000001086d07bb PrintStackTraceSignalHandler(void*) + 27
2 opt 0x00000001086d0b4c SignalHandler(int) + 412
3 libsystem_platform.dylib 0x00007fff8b0e35aa _sigtramp + 26
4 libsystem_platform.dylib 0x00007fff6492d380 _sigtramp + 3649347056
5 opt 0x00000001086d07eb raise + 27
6 opt 0x00000001086d08a2 abort + 18
7 opt 0x000000010865a7a6 llvm::llvm_unreachable_internal(char const*, char const*, unsigned int) + 198
8 opt 0x0000000108416b74 llvm::DataLayout::parseSpecifier(llvm::StringRef) + 2804
9 opt 0x0000000108415c57 llvm::DataLayout::init(llvm::StringRef) + 471
10 opt 0x000000010749b47e llvm::DataLayout::DataLayout(llvm::StringRef) + 158
11 opt 0x0000000107482ba5 llvm::DataLayout::DataLayout(llvm::StringRef) + 37
12 opt 0x000000010747943c main + 3756
13 libdyld.dylib 0x00007fff8a2865fd start + 1
Stack dump:
0. Program arguments: /Users/josh/code/emsdk_portable/clang/e1.25.0_64bit/opt /var/folders/7g/mbft22555w3_2nqs_h1kbglw0000gn/T/tmp93OFuV/a.out.bc -strip-debug -internalize -internalize-public-api-list=main,malloc,free -globaldce -pnacl-abi-simplify-preopt -pnacl-abi-simplify-postopt -enable-emscripten-cxx-exceptions -o /var/folders/7g/mbft22555w3_2nqs_h1kbglw0000gn/T/tmp93OFuV/a.out.bc.opt.bc
Traceback (most recent call last):
File "/Users/josh/code/emsdk_portable/emscripten/1.25.0/emcc", line 1224, in <module>
shared.Building.llvm_opt(final, link_opts)
File "/Users/josh/code/emsdk_portable/emscripten/1.25.0/tools/shared.py", line 1357, in llvm_opt
assert os.path.exists(target), 'Failed to run llvm optimizations: ' + output
AssertionError: Failed to run llvm optimizations:
If anyone can look at the above and give me an idea of what specifically it's missing, ie "it's trying to link stdlib.swift" and a link to somewhere that someone documents how they solved a similar problem, then I'll put a few hours into trying to get it. If there's any reasonable progress in that time, I'll report it here and probably keep at it.
Right now I'm just so ignorant that I don't even know what what the problem is or what to look for in terms of resolving it. But I have like 50 options I'm considering for my project, including things like Elm which I've already put a few days into playing with, so I need some guidance to not wander in circles for a months.
The targets need to match. As the IR shows, the swift frontend emits
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-darwin13.2.0"
Emscripten uses its own triple (asmjs-unknown-emscripten
). You might be able to force the frontend to use it? If not, you might be able to just edit the LLVM IR file in text format to fix it (create one using emcc, to see the right values for those two lines). But, this is risky, as the triple affects stuff that is baked into the output in various places...
So, I'm ignorant enough that I don't know how to interpret "the targets need to match" (I don't know what "target" means, or what a "triple" is -- kinda sounds like a fixed-length set of memory, like a "tuple" in a functional language). So it's unclear to me if it's something that I fucked up (e.g. did I compile it wrong, or with my own version of some binary, since emscripten uses its own set of binaries -- e.g. python2
was not in the PATH, and I couldn't find it in the emsdk_portable
, so I just made a bash script named python2
that then invoked python
and forwarded the args. Seemed reasonable since I had Python 2.7.5 installed, which the readme alleged was compatible https://github.com/kripken/emscripten/blob/06961a0ef6e3d8d92d5e36ff904262fefec62bec/tests/python/readme.md, and xcrun
is some binary that I don't understand, which is just sort of generally available, but didn't come from emscripten) or is it some issue caused by Swift being overly zealous about an OSX environment, or is it some flag to find to tell it to chill the fuck out and forget about being execuatble and just compile as if some other program will load it and deal with all the integration stuff? I mean, you'll notice all I do in this script is declare a variable and assign it the value 1
, so what is it trying to dynamically load? And does that have anything to do with the "targets" not matching?
I'll create the file using emcc and diff them and spend an hour poring over the differences, confused and trying and failing repeatedly, to figure out what I need to do, but I don't know how. The bc
format si the only one I've found so far that emcc will even consider trying to compile.
The reality is that I have no particularly good model for figuring out how this stuff works. I once spent 8 hours getting a C program to compile and load a library I was interested in, that's about the extent of my experience. Code that operates at this level operates under a model that I am simply ignorant of, so while we're in this domain, it's reasonable to me like I've never programmed before.
I'm actually pretty good at guessing and cursing repeatedly trying and failing and guessing and cursing again, but I need some sort of model or context to iterate upon. And there's a sufficiently large amount of information available out there, that I need someone who's familiar with this domain to clue me in, and imply to me that this isn't a giant waste of my time (b/c, lets be honest, I could just suck it up and write my shit in JavaScript).
A target is what clang/LLVM is emitting code for. When you build normally, on OSX your target triple is something like darwin-intel-apple
or some other combo that contains the information that you are building for intel hardware, to run on a darwin kernel on an apple userspace. This affects codegen in various ways, and the LLVM IR is not portable because of it.
Emscripten has its own target, and emcc tells clang and LLVM to use it, -triple=asmjs-unknown-emscripten
or something like that.
Hmm. Guess I thought LLVM was the target.
Anyway, asmjs-unknown-emscripten looks correct:
$ ag asmjs-unknown-emscripten | wc -l
115
-triple isn't the correct flag, apparently, and it tells me the wrong help file:
$ xcrun swiftc -Xllvm "-triple=asmjs-unknown-emscripten" -emit-bc f.swift -o f.bc
swift (LLVM option parsing): Unknown command line argument '-triple=asmjs-unknown-emscripten'. Try: 'swift (LLVM option parsing) -help'
swift (LLVM option parsing): Did you mean '-spiller=asmjs-unknown-emscripten'?
$ swift '(LLVM option parsing)' -help
fish: Unknown command 'swift'
$ xcrun swift '(LLVM option parsing)' -help
<unknown>:0: error: no such file or directory: '(LLVM option parsing)'
$ xcrun swift 'LLVM option parsing' -help
<unknown>:0: error: no such file or directory: 'LLVM option parsing'
$ xcrun swift 'option parsing' -help
<unknown>:0: error: no such file or directory: 'option parsing'
llvm isn't a binary, but tab-complete suggestions include llvm-gcc and llvm-g++, their help screens don't mention a triple, but do talk about a --target
, but that doesn't work either. Which is strange, because it's listed in the help output, so it seems like the error should be something about using it wrong, rather than "Unknown command line argument", so maybe this isn't the binary that it invokes for llvm:
$ xcrun swiftc -Xllvm "--target=asmjs-unknown-emscripten" -emit-bc f.swift -o f.bc
swift (LLVM option parsing): Unknown command line argument '--target=asmjs-unknown-emscripten'. Try: 'swift (LLVM option parsing) -help'
swift (LLVM option parsing): Did you mean '-stats=asmjs-unknown-emscripten'?
# same output for each of these potential variations:
$ xcrun swiftc -Xllvm "--target=asmjs-unknown-emscripten" -emit-bc f.swift -o f.bc
$ xcrun swiftc -Xllvm "--target asmjs-unknown-emscripten" -emit-bc f.swift -o f.bc
$ xcrun swiftc -Xllvm "-target asmjs-unknown-emscripten" -emit-bc f.swift -o f.bc
$ xcrun swiftc -Xllvm "-target=asmjs-unknown-emscripten" -emit-bc f.swift -o f.bc
$ xcrun swiftc -Xllvm "--target" -Xllvm "asmjs-unknown-emscripten" -emit-bc f.swift -o f.bc
# for that last one, it says "swift (LLVM option parsing): Did you mean '-stats'?"
# so lets verify that llvm-gcc is the right binary by seeing if `-stats` is one of its options:
$ llvm-gcc --help | grep stats
# ...nope, what the fuck is llvm?
# searching implies its binary is named "clang" for some reason,
# but no dice here either:
$ clang --help | grep stats
# man pages have any ideas?
$ man llvm-gcc
No manual entry for llvm-gcc
$ man llvm-g++
No manual entry for llvm-g++
$ man clang # this one works!
# After looking through this man page, I try -arch, which doesn't do shit
# was going to try setting MACOSX_DEPLOYMENT_TARGET env var
# but then I realized there's some way to search all man pages for "-stats"
# some stupid searching (man man) eventually I figure out:
$ man -K stats
# go through this list, and `gcc-4.8` shows up, so maybe llvm is just gcc? *shrug* lets try it
# it turns out to be fruitless
# at this point, I'm considering trying to find in the emscripten code where they invoke it
# figure I'll try googling a bit, find some docs for `llc`, which isn't a binary on my system, but does have a `-mtriple` flag, so lets try that:
$ xcrun swiftc -Xllvm "-mtriple=asmjs-unknown-emscripten" -emit-bc f.swift -o f.bc
# run the gamut of possible ways that I'm supposed to pass this thing
# (why can't I find a fucking example of how to do this?)
# eventually, one of the options suggests "-spiller" as a correction possibility
$ man -K spiller # ...just some thing about crypto
At this point, documenting in code would add another hour, but many searches, fancy -k
and -K
uses of the man
flag. A google search for llvm -spiller and -stats takes me back to that llc page, look through it a second time, this time notice that they have two dashes before them, even though the suggestion when I got it wrong only has 1 dash. So, try the permutations of possible ways to pass an argument to -Xllvm with two dashes. None of them work.
Get pissed, internet search like the fourth time for an example of how to use -Xllvm
flag, no results, cd to xcode and search for the string 'Xllvm', nothing. Try emsdk_portable
, nothing.
Look one more time at llvm-gcc, llvm-g++, lldb, apropos llvm
, clang, nothing.
Decide to go see if I can find where this happens in emsdk_portable
, looks like the makefiles set a build_triple
but never use it. Probably some makefile magic, and I don't feel like reading a book about makefiles just to find out how this gets persisted. Notice some of the files use LLVM_TARGET
, I don't know Python, maybe that's an env var, so try compiling with that set env LLVM_TARGET=asmjs-unknown-emscripten xcrun swiftc -emit-bc f.swift -o f.bc
, but it doesn't do anything (triple is still set to "x86_64-apple-darwin13.2.0"), remember the clang man pages had an env var that seemed like it had potential, so env MACOSX_DEPLOYMENT_TARGET=asmjs-unknown-emscripten xcrun swiftc -emit-bc f.swift -o f.bc
. Nope.
So, I'm like 3 hours in, and literally no further than when I started. Looks like someone got Rust compiling to asm.js, maybe that's a better choice. Someone got Go compiling directly to JavaScript. Might be sufficient. Could go suffer through the Elm type system for another week or two (it was basically like this: hours of slamming myself into the wall, but I kept at it for like 3 times longer), or maybe write the thing in C, since that at least compiles, but some part of me thinks that's masochism. If I did it in Opal, I wouldn't have to learn a new language... but that's part of the appeal, and I'm not sure it'll be able to scale in directions I might want to go with my project.
Going to go for a drink and weigh the shittiness of C as a language against the fact that I'll almost certainly succeed.
I was able to get very, very simple programs to build with the 6.3 beta at least. Unfortunately even something as simple as a string literal will not work, and regardless the resulting file has a bunch of missing symbols. Some of the symbols (swift_once
) are defined in libswiftCore.dylib, so it's likely using Swift will be impossible until the standard library is open sourced.
So, luckily, this will help later on: https://developer.apple.com/swift/blog/?id=29
So I was trying to do the same thing, and I just stumbled upon this Issue. So glad that I won't waste my time again.
By the way did you try again with XCode 7 and the swiftc
tool??
Since Apple now supports LLVM Bitcode, would that enable including dylibs that contain it?
LLVM bitcode is not portable. Bitcode for the App Store would be specific to Apple's hardware and OS.
Thanks, that makes sense. In case anyone is interested in more details as I was, LLVM FAQ: Can I compile C or C++ code to platform-independent LLVM bitcode?
It's been 18 months since I started this issue and I still really want this to happen. With Swift going open-source today let's hope that means it's now possible!
This will definitely make it a lot easier! :)
Ok, to move forward here, we need to do the following:
asmjs-unknown-emscripten
triple.Swift does have a fork of LLVM at apple/swift-llvm. Not sure what changes they have made.
the swift-cli has a bunch of handy options to output just the llvm byte code etc.
Let me know what I can help with would love to have something working!
Thanks for the info @Gaelan. Ok, if they have their own fork, then the best workflow would probably be:
The first step is to upstream our triple, which is already partially there (due to nacl upstreamings), so it's a small patch and probably not controversial. What we need to send is basically this:
https://gist.github.com/kripken/0b7ba068faf21d5449a3
Anyone interested to help upstream that?
It looks like Apple's llvm clone is pretty strict about changes being made upstream unless they are specifically swift-related. See: https://swift.org/contributing/#llvm-and-swift
Could open an issue in the Swift LLVM github to ask them for changes
I think that reduces to asking them to merge the changes in themselves, which is against their policy. The patch would have to be submitted directly to llvm by someone here.
I have no familiarity with the llvm community, so I don't know how they would feel about, for example, introducing asmjs
as an architecture. Anyone else have thoughts?
This is very exciting @kripken! In theory, should we be able to make these modifications locally and try things out using the swift LLVM clone? I modified the relevant files in the swift LLVM clone, according to your patch - here is the diff of the changes I made: https://gist.github.com/sberan/43bc5fbff78ea47658f0
Unfortunately I don't see a new target for asmjs in the swift recompiled LLVM:
./build/Ninja-DebugAssert/llvm-macosx-x86_64/bin/llc --version
LLVM (http://llvm.org/):
LLVM version 3.8.0svn
DEBUG build with assertions.
Built Dec 6 2015 (19:49:40).
Default target: x86_64-apple-macosx10.9
Host CPU: haswell
Registered Targets:
aarch64 - AArch64 (little endian)
aarch64_be - AArch64 (big endian)
arm - ARM
arm64 - ARM64 (little endian)
armeb - ARM (big endian)
thumb - Thumb
thumbeb - Thumb (big endian)
x86 - 32-bit X86: Pentium-Pro and above
x86-64 - 64-bit X86: EM64T and AMD64
Maybe more work needs to be done here in order to register asmjs as a target? Forgive me if this is a noob question, I'm very new to llvm and emscripten, just very excited to try swift in the browser :smile:
I'd be happy to try and push these changes upstream, but I'd like to verify that they'll work first! :laughing:
I'll try to give it a go when I get a chance!
I think you might not see a target because you can't build a full executable for js. But you should be able to build with -target asmjs-unknown-emscripten -emit-llvm
and it should emit llvm for that specific target triple.
There is another possible path here. Upstream LLVM has a WebAssembly triple now. It is almost identical to our asm.js triple. It should be possible for swift to build to the wasm-wasm-wasm triple, then import that bitcode into emscripten which can compile it to asm.js.
(We would still need to make sure it's the same LLVM version, or close enough, to avoid e.g. debug info changes. But emscripten merges upstream every week or two now, so that should be easy, if someone tells me what is a good time to merge for Swift, i.e., when Swift merges.)
Note that the wasm triple is still experimental, so you need to build LLVM with it enabled, from the list of experimental targets.
@kripken - This is an overview of the release process for Swift https://swift.org/blog/swift-2-2-release-process/
Swift uses llvm 3.8.0. They have their branch and not exactly sure their policy but once they finish swift 2.2, they'll probably merge their branch to upstream trunk.
3.8.0 already has wasm as kripken said, so I was able to build swift-llvm with wasm64 enabled and pass basic tests, but struggling to build swift with llvm-wasm and build swift stdlibs with with llvm-wasm + emscripten, main reason is that their build system is huge but not so flexible. (There're lots places that have hard-coded config like `if system==darwin then build for Mac, else build linux kind of thing) But I'm new for their build system so I may miss something.
I just wanted to make sure the process I'm doing is in the right course.
@naan:
emcc
does that automatically, by replacing normal system headers with emscripten's portable headers.@kripken Thank you for the followup.
So, #4 is sounds a bit challenging with their build system for me... I need to research more about the build system itself first, but it might be easier to use emcc toolchains to build swift-stdlibs if it automatically does header swap? I guess emscripten-fastcomp is still llvm 3.7.0 base, but once it gets synced with 3.8.0, I assume I can use that to build swift-stdlibs with actual asmjs target.
If it helps, emscripten's incoming branch is already at 3.9.0 (svn)
.
Any updates on this?
+1 On Thu, Mar 3, 2016 at 6:51 PM Dan Appel notifications@github.com wrote:
Any updates on this?
— Reply to this email directly or view it on GitHub https://github.com/kripken/emscripten/issues/2427#issuecomment-192071228 .
Sent from my iPhone
+1
I'm also super interested to hear about progress here!
@naan I was peripherally involved in the SwiftAndroid port and we had to do the same things there. Basically we change the sysroot to the one provided by the Android NDK - this makes the swift build tool look at the necessary headers and binaries from that point and not from the host machine's toolchain. I haven't used emscripten before in a real project, but I imagine it works in much the same way.
There are three open pull requests / discussions that will be instrumental in getting Swift working with Emscripten:
[RFC] Port to Android #1442 - check this out for changing the sysroot Enable cross-compiling #1398 - this allows us to compile e.g. OSX --> Linux, not sure if it's needed but good to know that it's being worked on. Flag to statically link Swift standard library #730 - the first issue that came up in this thread was that libSwiftCore is dynamically linked by default. Reliably building a statically linked version will be vital to continuing here.
I won't have time to work on this for at least another month or so, but I'm interested to keep track and answer any questions if I can in the meantime.
@ephemer
Thank you for the info! That's really good to know. I have been in another project for a while and didn't have much time looking into this since last month. I hope I can make time for this soon.
Flag to statically link Swift standard library #730 is resolved & waiting for review.
Hello All, I tried using clang 3.9.0 to emit the llvm ir with -target wasm32-wasm32-wasm32, but end up getting warning for different data layout and target triple. The question is if llvm WebAssembly target is usable as is to generate llvm ir to be fed to emscripten ?
The warning is expected, but should not cause problems in practice. The important things are the same in those two triples. (Except perhaps for the size of long doubles, is that important in Swift?)
https://github.com/apple/swift/pull/1442 - Android port has been merged.
@kripken Thanks a lot. I do not think its important in swift. On a second thought I think it would be great if emscripten can read in bc files (not generated with asm-unknown-emscripten) and emit bc files compatible with asm-unknown-emscripten. Can you please tell me is this currently supported or how difficult it would be to implement this. One challenge could be to undo the existing target assumptions of the input bc file.
It's not possible in general, as LLVM IR is not portable. When you build for e.g. 64-bit ARM, you are baking in things that simply cannot be undone later.
@kripken do you have a slack channel or something similar for Emscripten discussions? A lot of the bits I referenced above are falling into place and I'd be interested in figuring out what else is missing from the picture. Specifically I'm interested with how the c++ stdlib is currently dealt with as a dependency (to compare with how swift's stdlib might fit in), and to what extent the swift runtime might get in the way.
I see a lot of potential for swift + webassembly + WebGL via Emscripten!
No slack, but there is an irc channel.
The C++ stdlib is basically just libc++ compiled in when needed. The only "magic" it requires is unwinding for C++ exceptions, which we have a few special functions for (using JS exceptions).
@kripken Thanks for the link to the IRC channel.
The bit about 'compiled in' is what I don't really understand yet. Do users depend on a static libc++
that gets compiled into the LLVM IR before emscripten has anything to do with it? Or do they link against a dylib that is somehow later provided automatically by emscripten?
The former. We take user input files, find out what system libs they need like libc and libc++, then link all those into one big bitcode file and optimize that. Doing so can really help with code size. Then we compile that into asm.js.
For special functionality that can't be done in bitcode (which turns into compiled asm.js), like stack unwinding, we call out into JS. So we link in necessary "JS libraries" as well, after the process described above.
Emscripten does have support for dylibs, so in theory one could use libc++ that way, however it's significantly less efficient in terms of code size and startup speed. However dylibs are still useful in other situations.
@kripken thanks for the info.
So from what I can see, swiftc
will have to be compiled with knowledge of the relevant triple (you mentioned that wasm32-wasm32-wasm32
is probably the most reasonable choice here, because it's already in upstream llvm), and referencing the correct headers, much like in https://github.com/apple/swift/pull/1442.
As in the android port, we'd need a swift stdlib (libswiftCore
) compiled based on the emscripten sysroot. The issue I can see here is the swift build system currently expects to build and use complete (not intermediate llvm-ir) libraries. Someone smarter than me should be able to figure their way around that though. I know there is an option to produce llvm-ir as well, just not sure about producing only that.
For Linux, https://github.com/apple/swift/pull/1891 has been merged, the last of three pull requests to support compiling swift with -static-stdlib (libswiftCore
). That said, I gather it was possible to emit just the llvm-ir already, so maybe this isn't a huge step forward after all.
On the Mac side (or maybe generally, I haven't looked into it yet) we do have https://github.com/apple/swift/pull/1398, which seems to enable cross-compilation based on an arbitrary sysroot and target. This is exactly what we need, maybe limited by the 'full compilation' issue mentioned above. See specifically https://github.com/apple/swift/pull/1398/commits/a4df003038b454d486bcb5fa8ef061e5ba446908 - I don't have time to look into this right now but maybe someone who does could give this process a go, putting in wasm32-wasm32 as the target and pointing to the emscripten sysroot at ...emsdk_portable/emscripten/1.35.0/system
. We'd also need to point cross-compile-toolchain-bin
to emscripten's clang
. Just maybe we're close enough already...
Hi team, playing around with Emscripten in earnest for the first time, not my usual area of work so apologies if this is clearly never going to work. What I'd like to do is compile a simple Swift program to JS:
So far what I've tried is:
but that fails because it can't find certain symbols (looks like the standard library isn't present):
Drilling a bit further, and looking at how
xcrun swift -v hello_world.swift
actually works, I'm able to use this linking command to compile the bitcode to an executable using normalld
.So, it seems like
libswift_stdlib_core.dylib
is the only dependency forhello_world.bc
to be properly linked to an executable.But I'm stuck - is there some equivalent between the
-L
and-rpath
flags onld
that I should be passing toemcc
? Or is a dylib like that not possible to be used in emscripten? The final command I tried was:Hopefully something's possible from here - Swift is a neat high-level language with a nice type system and no garbage collector, which makes me think it's a good fit for compiling to JS.