-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Add support for LLVM 3.8 #2993
Add support for LLVM 3.8 #2993
Conversation
Wow, this is amazing 💚 |
@asterite so, do you want to retain 3.5 compatibility? If so we probably need to figure out a way to test against multiple LLVM versions on CI. |
Hurray! |
Great job!!
You mean that the build time is slower or that the resulting compiled binary is slower? |
@lbguilherme Sorry about that, build times appear slower.
Compared with installed crystal:
And then samples/conway.cr:
vs.
The builds themselves don't appear to be any slower. |
That is with |
Thanks for the hard work! We currently support both LLVM 3.5 and 3.6. Now with 3.8 it's a little difficult to understand what part is for what version. Most notably the default is kept to LLVM 3.6, and it's not clear from reading the code since there are no |
@omarroth This is amazing! And travis is happy! You are a hero! ❤️❤️❤️ I would personally drop support for LLVM < 3.8, since we are distributing LLVM libs with Crystal so there shouldn't be any problem with that. Can you check build times by passing |
I can update the docker images for Travis to Ubuntu xenial (16.04), if I find a 32bit image, which would give 3.8: http://packages.ubuntu.com/xenial/llvm However trusty (14.04) only has 3.6: http://packages.ubuntu.com/trusty-updates/llvm-3.6 For Debian, stretch (testing) has 3.8: https://packages.debian.org/stretch/llvm-3.8, jessie (stable) only has 3.5 still: https://packages.debian.org/jessie/llvm (https://packages.debian.org/stretch/llvm-3.6, https://packages.debian.org/stretch/llvm-3.7) However LLVM seems to still have "nightlies" for jessie for 3.8: http://apt.llvm.org/ The clang package from http://llvm.org/releases/download.html for CentOS should include LLVM too, CentOS 6 doesn't seem to have LLVM at all, CentOS 7 has 3.4 still http://centos-packages.com/7/package/llvm/ EPEL isn't any help https://dl.fedoraproject.org/pub/epel/7/x86_64/l/ Whether we can use the official package instead of updating our custom omnibus version is certainly worth an investigation. @asterite / @waj Since you do the release process, do you want to look into that? Regarding OS X, the homebrew formula seems to still be at LLVM 3.6? https://github.com/Homebrew/homebrew-core/blob/master/Formula/llvm.rb but there's this: https://github.com/Homebrew/homebrew-versions/blob/master/llvm38.rb Is this easily usable and we just have to brew install llvm3.8 on Travis? |
I get a segfault with this branch when running On the plus side this seems to fix #2789, so we can switch Travis to |
LLVM is providing binaries and repositories for major Linux distributions (Debian, Ubuntu, Fedora, Suse) as well as FreeBSD, so it's not thard to compile Crystal if LLVM 3.8 isn't in the official repositories. Alpine provides LLVM 3.8 in edge so I should be capable to compile against it. I may struggle a bit since they didn't distribute static libraries for LLVM 3.6, but I'll eventually bootstrap a new compiler. |
@ysbaddaden - I might remember wrong - but I think there are static libs for 3.8 edge in Alpine (but not earlier versions). |
@jhass I wasn't getting a segfault when passing -d to the compiler, but I did manage to fix a problem I was having, so you might try it again and see if it works for you. |
Yes, that indeed seems to have fixed the segfault for me. Let's try this for CI: diff --git a/bin/ci b/bin/ci
index 991c0f8..078819f 100755
--- a/bin/ci
+++ b/bin/ci
@@ -147,9 +147,10 @@ EOF
prepare_build() {
on_linux verify_linux_environment
- on_linux docker pull "jhass/crystal-build-$ARCH"
+ on_linux docker pull "jhass/crystal-build-$ARCH:llvm38"
on_osx brew install libevent crystal-lang
+ on_osx /bin/bash -c "'curl \"http://llvm.org/releases/3.8.0/clang+llvm-3.8.0-x86_64-apple-darwin.tar.xz\" | tar xz -C /tmp'"
on_osx /bin/bash -c "'curl \"http://crystal-lang.s3.amazonaws.com/llvm/llvm-3.5.0-1-darwin-x86_64.tar.gz\" | tar xz -C /tmp'"
}
@@ -169,7 +170,7 @@ with_build_env() {
"jhass/crystal-build-$ARCH" \
"$ARCH_CMD" /bin/bash -c "'$command'"
- on_osx PATH="/tmp/llvm-3.5.0-1/bin:\$PATH" \
+ on_osx PATH="/tmp/clang+llvm-3.8.0-x86_64-apple-darwin/bin:\$PATH" \
CRYSTAL_CACHE_DIR="/tmp/crystal" \
/bin/bash -c "'$command'"
@@ -220,4 +221,4 @@ case $command in
exit 1
fi
;;
-esac
\ No newline at end of file
+esac |
Take two: diff --git a/bin/ci b/bin/ci
index 3974350..a4b1c84 100755
--- a/bin/ci
+++ b/bin/ci
@@ -84,7 +84,7 @@ prepare_system() {
build() {
with_build_env 'make std_spec clean'
- with_build_env 'make crystal std_spec compiler_spec doc'
+ with_build_env 'make crystal spec doc'
with_build_env 'find samples -name "*.cr" | xargs -L 1 ./bin/crystal build --no-codegen'
with_build_env './bin/crystal tool format --check'
}
@@ -166,10 +166,10 @@ with_build_env() {
-v $(pwd):/mnt \
-w /mnt \
-e LIBRARY_PATH="/opt/crystal/embedded/lib/" \
- "jhass/crystal-build-$ARCH" \
+ "jhass/crystal-build-$ARCH:llvm38" \
"$ARCH_CMD" /bin/bash -c "'$command'"
- on_osx PATH="/tmp/clang+llvm-3.8.0-x86_64-apple-darwin/bin:\$PATH" \
+ on_osx PATH="/tmp/clang+llvm-3.8.0-x86_64-apple-darwin/bin:\$PATH" \
CRYSTAL_CACHE_DIR="/tmp/crystal" \
/bin/bash -c "'$command'"
@@ -220,4 +220,4 @@ case $command in
exit 1
fi
;;
-esac
\ No newline at end of file
+esac I'll have leave the warnings in https://travis-ci.org/crystal-lang/crystal/jobs/145038717#L166 to you and we need an OS X person to figure out https://travis-ci.org/crystal-lang/crystal/jobs/145038718#L110 Also please run the formatter https://travis-ci.org/crystal-lang/crystal/jobs/145038717#L441 |
I'm inclined to think that the warnings on OS X are caused by an outdated compiler as they don't appear on either of the linux builds. |
Let's try this for the OpenSSL failures: diff --git a/src/openssl/ssl/context.cr b/src/openssl/ssl/context.cr
index 4bb5dba..3136ab2 100644
--- a/src/openssl/ssl/context.cr
+++ b/src/openssl/ssl/context.cr
@@ -138,6 +138,9 @@ abstract class OpenSSL::SSL::Context
set_default_verify_paths
+ # Reset any default options, since they're version/OS dependent
+ LibSSL.ssl_ctx_ctrl(@handle, LibSSL::SSL_CTRL_CLEAR_OPTIONS, 0xFFFFFFFF, nil)
+
add_options(OpenSSL::SSL::Options.flags(
ALL,
NO_SSLV2, |
Meh, looks like we can't unset diff --git a/spec/std/openssl/ssl/context_spec.cr b/spec/std/openssl/ssl/context_spec.cr
index df14afa..3651eee 100644
--- a/spec/std/openssl/ssl/context_spec.cr
+++ b/spec/std/openssl/ssl/context_spec.cr
@@ -80,21 +80,24 @@ describe OpenSSL::SSL::Context do
it "adds options" do
context = OpenSSL::SSL::Context::Client.new
context.remove_options(context.options) # reset
- context.add_options(OpenSSL::SSL::Options::ALL).should eq(OpenSSL::SSL::Options::ALL)
+ default_options = context.options # options we can't unset
+ context.add_options(OpenSSL::SSL::Options::ALL).should eq(default_options | OpenSSL::SSL::Options::ALL)
context.add_options(OpenSSL::SSL::Options.flags(NO_SSLV2, NO_SSLV3))
.should eq(OpenSSL::SSL::Options.flags(ALL, NO_SSLV2, NO_SSLV3))
end
it "removes options" do
context = OpenSSL::SSL::Context::Client.insecure
- context.add_options(OpenSSL::SSL::Options.flags(ALL, NO_SSLV2))
- context.remove_options(OpenSSL::SSL::Options::ALL).should eq(OpenSSL::SSL::Options::NO_SSLV2)
+ default_options = context.options
+ context.add_options(OpenSSL::SSL::Options.flags(NO_TLSV1, NO_SSLV2))
+ context.remove_options(OpenSSL::SSL::Options::NO_TLSV1).should eq(default_options | OpenSSL::SSL::Options::NO_SSLV2)
end
it "returns options" do
context = OpenSSL::SSL::Context::Client.insecure
+ default_options = context.options
context.add_options(OpenSSL::SSL::Options.flags(ALL, NO_SSLV2))
- context.options.should eq(OpenSSL::SSL::Options.flags(ALL, NO_SSLV2))
+ context.options.should eq(default_options | OpenSSL::SSL::Options.flags(ALL, NO_SSLV2))
end
it "adds modes" do
diff --git a/src/openssl/ssl/context.cr b/src/openssl/ssl/context.cr
index 3136ab2..4bb5dba 100644
--- a/src/openssl/ssl/context.cr
+++ b/src/openssl/ssl/context.cr
@@ -138,9 +138,6 @@ abstract class OpenSSL::SSL::Context
set_default_verify_paths
- # Reset any default options, since they're version/OS dependent
- LibSSL.ssl_ctx_ctrl(@handle, LibSSL::SSL_CTRL_CLEAR_OPTIONS, 0xFFFFFFFF, nil)
-
add_options(OpenSSL::SSL::Options.flags(
ALL,
NO_SSLV2, |
On the XCode7.3 build there seems to be a version conflict. Clang is looking for a 10.10 SDK but the worker is running 10.11.
Besides changing the version of the worker, it might help to build LLVM on 10.11 and pulling from there instead. |
So back to pushing some custom build to S3? :( Why's there no proper binary package manager for OS X, sigh. |
My mistake, pulling from homebrew works fine. |
"$ARCH_CMD" /bin/bash -c "'$command'" | ||
|
||
on_osx PATH="/tmp/llvm-3.5.0-1/bin:\$PATH" \ | ||
on_osx PATH="/usr/local/opt/llvm/bin:\$PATH" \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix the indentation here and then I think this should be good to go.
After this patch, I will keep supporting for Windows porting. ❤️ |
Done for me, @asterite anything you still find missing? |
etc? because integrating it into omnibus doesn't block this from being merged, it only blocks the next release until that's done. |
If we are sure that we can provide LLVM 3.8 with omnibus, then I guess we can merge this. My only worry was: we merge this, later we have trouble making omnibus work with this, we can't release. |
Can't we just pull in the latest official tarballs for each architecture on omnibus? Also if I follow correctly this is still compatible to 3.5, just not 3.6 or 3.7. |
Ah! Then yes, let's merge :-) |
Actually I just tried locally and it no longer compiles against 3.5 for me. @omarroth would that be easily fixable? |
That should be possible with shelling out to However I'm getting errors compiling the extension:
|
I don't think keeping LLVM 3.5 compatibility is something that we need to do. I don't mind dropping it. In fact, keeping compatibility with LLVM 3.6 or 3.7 also doesn't matter, we should move forward and try to use the latest version of LLVM. Specially because we provide LLVM with the compiler. |
I think keeping compatibility in the short term is good, it allows us to move forward without blocking on necessary updates to the build infrastructure. It's a chicken-egg problem otherwise. |
The problem I'm having with macros though is that the generated code only seems to be callable in the same file. Something like this: {% if `(command -v llvm-config-3.6 || command -v llvm-config-36 || command -v llvm-config-3 || command -v llvm-config-35) > /dev/null && printf %s true || printf %s false` == "true" %}
lib LibLLVMExt
HAVE_LLVM_36_OR_LOWER = true
end
{% else %}
lib LibLLVMExt
HAVE_LLVM_36_OR_LOWER = false
end
{% end %} Throws an {% if LibLLVMExt::HAVE_LLVM_36_OR_LOWER %}
fn_metadata = di_builder.create_function(scope, target_def.name, target_def.name, scope,
location.line_number, fun_metadata_type, 1, 1, location.line_number, 0_u32, 0, context.fun)
{% else %}
fn_metadata = di_builder.create_function(scope, target_def.name, target_def.name, scope,
location.line_number, fun_metadata_type, true, true, location.line_number, 0_u32, false, context.fun)
{% end %}
fun_metadatas[context.fun] = fn_metadata Produces
|
Try wrapping it into another {% begin %}
{% if LibLLVMExt::HAVE_LLVM_36_OR_LOWER %}
fn_metadata = di_builder.create_function(scope, target_def.name, target_def.name, scope,
location.line_number, fun_metadata_type, 1, 1, location.line_number, 0_u32, 0, context.fun)
{% else %}
fn_metadata = di_builder.create_function(scope, target_def.name, target_def.name, scope,
location.line_number, fun_metadata_type, true, true, location.line_number, 0_u32, false, context.fun)
{% end %}
fun_metadatas[context.fun] = fn_metadata
{% end %} |
That works fine, other problem is when doing something like this: {% if LibLLVMExt::HAVE_LLVM_36_OR_LOWER %}
def insert_declare_at_end(storage, var_info, expr, block)
LibLLVMExt.di_builder_insert_declare_at_end(self, storage, var_info, expr, block)
end
{% else %}
def insert_declare_at_end(storage, var_info, expr, dl, block)
LibLLVMExt.di_builder_insert_declare_at_end(self, storage, var_info, expr, dl, block)
end
{% end %} Which outputs
|
Honestly, I see no reason to keep compatibility with LLVM 3.5 but lose compatibility with LLVM 3.6... |
@omarroth I have a suspicion or two, but it's very hard to tell without the whole context, can you share your work in progress somewhere? @ysbaddaden it allows us to merge this now rather than when somebody gets around to update omnibus and merging it now also makes testing easier while updating omnibus. It would be a shame to see this sitting around for a couple of weeks and eventually get out of date and getting conflicts. |
@ysbaddaden The hope is to support both 3.5 and 3.6. |
@jhass I forgot omnibus was still using 3.5... |
@omarroth The issue can be resolved with a couple explicit requires to have explicit load order. While at it I redesigned the whole detection a bit into a more general construct: diff --git a/src/compiler/crystal/codegen/debug.cr b/src/compiler/crystal/codegen/debug.cr
index e7c578e..587a14e 100644
--- a/src/compiler/crystal/codegen/debug.cr
+++ b/src/compiler/crystal/codegen/debug.cr
@@ -127,7 +127,7 @@ module Crystal
expr = di_builder.create_expression(nil, 0)
{% begin %}
- {% if LibLLVMExt::HAVE_LLVM_36_OR_LOWER %}
+ {% if LibLLVM::IS_36 || LibLLVM::IS_35 %}
declare = di_builder.insert_declare_at_end(alloca, var, expr, alloca_block)
{% else %}
declare = di_builder.insert_declare_at_end(alloca, var, expr, builder.current_debug_location, alloca_block)
@@ -211,9 +211,9 @@ module Crystal
file, dir = file_and_dir(filename)
scope = di_builder.create_file(file, dir)
{% begin %}
- {% if LibLLVMExt::HAVE_LLVM_36_OR_LOWER %}
+ {% if LibLLVM::IS_36 || LibLLVM::IS_35 %}
fn_metadata = di_builder.create_function(scope, MAIN_NAME, MAIN_NAME, scope,
- 0, fun_metadata_type, 1, 1, 0, 0_u32, 0, main_fun)
+ 0, fun_metadata_type, 1, 1, 0, 0_u32, 0, main_fun)
{% else %}
fn_metadata = di_builder.create_function(scope, MAIN_NAME, MAIN_NAME, scope,
0, fun_metadata_type, true, true, 0, 0_u32, false, main_fun)
@@ -229,7 +229,7 @@ module Crystal
file, dir = file_and_dir(location.filename)
scope = di_builder.create_file(file, dir)
{% begin %}
- {% if LibLLVMExt::HAVE_LLVM_36_OR_LOWER %}
+ {% if LibLLVM::IS_36 || LibLLVM::IS_35 %}
fn_metadata = di_builder.create_function(scope, target_def.name, target_def.name, scope,
location.line_number, fun_metadata_type, 1, 1, location.line_number, 0_u32, 0, context.fun)
{% else %}
diff --git a/src/llvm/di_builder.cr b/src/llvm/di_builder.cr
index aab951a..4923b31 100644
--- a/src/llvm/di_builder.cr
+++ b/src/llvm/di_builder.cr
@@ -1,3 +1,5 @@
+require "./lib_llvm"
+
struct LLVM::DIBuilder
def initialize(llvm_module)
@unwrap = LibLLVMExt.create_di_builder(llvm_module)
@@ -41,7 +43,7 @@ struct LLVM::DIBuilder
LibLLVMExt.di_builder_create_expression(self, addr, length)
end
- {% if LibLLVMExt::HAVE_LLVM_36_OR_LOWER %}
+ {% if LibLLVM::IS_36 || LibLLVM::IS_35 %}
def insert_declare_at_end(storage, var_info, expr, block)
LibLLVMExt.di_builder_insert_declare_at_end(self, storage, var_info, expr, block)
end
diff --git a/src/llvm/lib_llvm.cr b/src/llvm/lib_llvm.cr
index 6a3a4e0..40636d2 100644
--- a/src/llvm/lib_llvm.cr
+++ b/src/llvm/lib_llvm.cr
@@ -1,7 +1,27 @@
require "./enums"
-@[Link("stdc++")]
-@[Link(ldflags: "`$(command -v llvm-config-3.6 || command -v llvm-config36 || command -v llvm-config-3.5 || command -v llvm-config35 || command -v llvm-config) --libs --system-libs --ldflags 2> /dev/null`")]
+{% begin %}
+lib LibLLVM
+ LLVM_CONFIG = {{`command -v llvm-config-3.8 || command -v llvm-config38 || (command -v llvm-config > /dev/null && (case "$(llvm-config --version)" in 3.8*) command -v llvm-config;; *) false;; esac)) || command -v llvm-config-3.6 || command -v llvm-config36 || command -v llvm-config-3.5 || command -v llvm-config35 || command -v llvm-config `.chomp.stringify}}
+end
+{% end %}
+
+{% begin %}
+ @[Link("stdc++")]
+ @[Link(ldflags: "`{{LibLLVM::LLVM_CONFIG.id}} --libs --system-libs --ldflags 2> /dev/null`")]
+ lib LibLLVM
+ VERSION = {{`#{LibLLVM::LLVM_CONFIG} --version`.chomp.stringify}}
+ end
+{% end %}
+
+{% begin %}
+ lib LibLLVM
+ IS_38 = {{LibLLVM::VERSION.starts_with?("3.8")}}
+ IS_36 = {{LibLLVM::VERSION.starts_with?("3.6")}}
+ IS_35 = {{LibLLVM::VERSION.starts_with?("3.5")}}
+ end
+{% end %}
+
lib LibLLVM
type ContextRef = Void*
type ModuleRef = Void*
diff --git a/src/llvm/lib_llvm_ext.cr b/src/llvm/lib_llvm_ext.cr
index eaf0c78..fabbd34 100644
--- a/src/llvm/lib_llvm_ext.cr
+++ b/src/llvm/lib_llvm_ext.cr
@@ -1,3 +1,5 @@
+require "./lib_llvm"
+
@[Link(ldflags: "#{__DIR__}/ext/llvm_ext.o")]
lib LibLLVMExt
type DIBuilder = Void*
@@ -5,7 +7,7 @@ lib LibLLVMExt
fun create_di_builder = LLVMNewDIBuilder(LibLLVM::ModuleRef) : DIBuilder
fun di_builder_finalize = LLVMDIBuilderFinalize(DIBuilder)
-{% if LibLLVMExt::HAVE_LLVM_36_OR_LOWER %}
+{% if LibLLVM::IS_36 || LibLLVM::IS_35 %}
fun di_builder_create_function = LLVMDIBuilderCreateFunction(
builder : DIBuilder, scope : Metadata, name : LibC::Char*,
linkage_name : LibC::Char*, file : Metadata, line : LibC::UInt,
@@ -42,7 +44,7 @@ lib LibLLVMExt
name : LibC::Char*, file : Metadata, line : LibC::UInt, type : Metadata,
always_preserve : LibC::Int, flags : LibC::UInt, arg_no : LibC::UInt) : Metadata
-{% LibLLVMExt::HAVE_LLVM_36_OR_LOWER %}
+{% if LibLLVM::IS_36 || LibLLVM::IS_35 %}
fun di_builder_insert_declare_at_end = LLVMDIBuilderInsertDeclareAtEnd(builder : DIBuilder,
storage : LibLLVM::ValueRef,
var_info : Metadata,
@@ -89,12 +91,3 @@ lib LibLLVMExt
fun set_current_debug_location = LLVMSetCurrentDebugLocation2(LibLLVM::BuilderRef, LibC::Int, LibC::Int, Metadata, Metadata)
end
-{% if `(command -v llvm-config-3.6 || command -v llvm-config-36 || command -v llvm-config-3 || command -v llvm-config-35) > /dev/null && printf %s true || printf %s false` == "true" %}
-lib LibLLVMExt
- HAVE_LLVM_36_OR_LOWER = true
-end
-{% else %}
-lib LibLLVMExt
- HAVE_LLVM_36_OR_LOWER = false
-end
-{% end %}
\ No newline at end of file That patch is against your -fix branch. |
LGTM |
@[Link(ldflags: "`$(command -v llvm-config-3.6 || command -v llvm-config36 || command -v llvm-config-3.5 || command -v llvm-config35 || command -v llvm-config) --libs --system-libs --ldflags 2> /dev/null`")] | ||
{% begin %} | ||
lib LibLLVM | ||
LLVM_CONFIG = {{`command -v llvm-config-3.8 || command -v llvm-config38 || command -v llvm-config-3.6 || command -v llvm-config36 || command -v llvm-config-3.5 || command -v llvm-config35 || command -v llvm-config`.chomp.stringify}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I got an improved version:
LLVM_CONFIG = {{`command -v llvm-config-3.8 || command -v llvm-config38 || (command -v llvm-config > /dev/null && (case "$(llvm-config --version)" in 3.8*) command -v llvm-config;; *) false;; esac)) || command -v llvm-config-3.6 || command -v llvm-config36 || command -v llvm-config-3.5 || command -v llvm-config35 || command -v llvm-config `.chomp.stringify}}
This should
- prefer a side installed LLVM 3.8 over any other
- prefer the main LLVM if it's 3.8 already
- prefer a side installed 3.6 over the main LLVM not being 3.8 or a side installed 3.5
- prefer a side installed 3.5 over the main LLVM not being 3.8
- fallback to the main LLVM
Build failed due to formatting changes, please run the formatter. |
Thank you! |
Incompatible with 3.7, but is backwards compatible for currently supported versions of LLVM. Closes #1614. It is also necessary for #26, as TLS is now supported on cygwin targets with emutls.
Build times using 3.8 appear to be slower on average.