crystalline icon indicating copy to clipboard operation
crystalline copied to clipboard

Should have an M1 compatible build or a Universal Binary

Open uchuugaka opened this issue 3 years ago • 15 comments

It would be great to have an M1 compatible build or a Universal Binary.

uchuugaka avatar Jan 29 '22 15:01 uchuugaka

Hey @uchuugaka,

Yes that would be great. Unfortunately I don't have an M1 mac, so I won't be able to implement this (I could - but I'm not that comfortable shipping something without testing it).

So I'll need to rely on external contributions.

elbywan avatar Jan 30 '22 15:01 elbywan

Sadly, there is no M1 runners available for GitHub Actions: https://github.com/actions/virtual-environments/issues/2187. If there is a way to get "free for open source" M1 instance somewhere, then it can be built with self-hosted runners.

It may be done with cross-compilation, but I had hard time trying to link object file on foreign architecture.

Just in case, here is m1 build from current HEAD: crystalline-v0.5-arm64-apple-darwin.zip

y8 avatar Feb 05 '22 17:02 y8

Just in case, here is m1 build from current HEAD: crystalline-v0.5-arm64-apple-darwin.zip

Works great for me. Thank you!

dogweather avatar May 06 '22 05:05 dogweather

Here is m1 build from HEAD crystalline-v0.6-arm64-apple-darwin.gz

EruEri avatar May 17 '22 19:05 EruEri

@elbywan I have an M1 Mac and can help test.

dogweather avatar May 17 '22 20:05 dogweather

Here is m1 build from HEAD crystalline-v0.6-arm64-apple-darwin.gz

I can't get it work with vscode:

dyld[20271]: Symbol not found: __ZN4llvm9DIBuilder14createFunctionEPNS_7DIScopeENS_9StringRefES3_PNS_6DIFileEjPNS_16DISubroutineTypeEjNS_6DINode7DIFlagsENS_12DISubprogram9DISPFlagsENS_24MDTupleTypedArrayWrapperINS_19DITemplateParameterEEEPSA_NSC_INS_6DITypeEEE
  Referenced from: /Users/iambudi/Development/Library/crystalline/crystalline
  Expected in: /opt/homebrew/Cellar/llvm/14.0.6/lib/libLLVM.dylib
[Info  - 12:41:47 PM] Connection to server got closed. Server will restart.
...
The Crystal Language server crashed 5 times in the last 3 minutes. The server will not be restarted.

iambudi avatar Jul 09 '22 05:07 iambudi

That either indicates the dylib referenced wasn’t not found at the expected path nor in the searched paths OR the one found does not contain the symbol.

I saw a lot of this with having the dependency dylibs at different paths and shimmed them in with symlinks.

Not sure if it is a project config issue or an issue with where a given brew install is installing the dependencies

uchuugaka avatar Jul 09 '22 06:07 uchuugaka

Here is a build made with crystal v1.5.0 on llvm v14.0.6 on current HEAD (a7c9aba74c43efce53941f940da0e1485e95bc7f), that fixes issue with missing symbols.

crystalline-v0.6-arm64-apple-darwin-llvm-v14.0.6.tar.gz

y8 avatar Jul 13 '22 12:07 y8

Here is a build made with crystal v1.5.0 on llvm v14.0.6 on current HEAD (a7c9aba), that fixes issue with missing symbols.

crystalline-v0.6-arm64-apple-darwin-llvm-v14.0.6.tar.gz

Thank you it works nicely :)

iambudi avatar Jul 14 '22 05:07 iambudi

@y8 how long does it takes to compile crystalline on M1 machine?

iambudi avatar Jul 14 '22 05:07 iambudi

@y8 how long does it takes to compile crystalline on M1 machine?

Insanely fast 🤯

About 3 minutes on my low-end MacBook Air with 16 gigs of ram for full build without cache. Crystal itself builds in about 5 minutes.

y8 avatar Jul 14 '22 20:07 y8

I’ve just got an idea: we can publish crystalline formula in homebrew. They have m1 build infrastructure to provide precompiled “bottles”.

I can make a formula if @elbywan is okay with that

y8 avatar Jul 14 '22 21:07 y8

I can make a formula if @elbywan is okay with that

@y8 Go for it! Thanks! 🙏

elbywan avatar Jul 15 '22 06:07 elbywan

@y8 Go for it! Thanks! 🙏

I've made a draft formula. It builds and passes all the formula check on macOS. Most likely it will work on linux as well, but I haven't tested that yet.

Few questions:

  1. Homebrew consider a good practice to add meaningful test after formula is installed. I'm not familiar with LSP architecture. It would be awesome, if you can share "one-liner" that can verify that crystalline in fact runs correctly. If possible, something that will keep working between releases, so there is no need to change formula to update tests for each release.

  2. As far I understand, static builds are not possible on macOS. What is relation between llvm version and crystalline executable? Maybe you or fellow readers know how to deal with it. I haven't had time to check homebrew for existent formulas that are built from crystal sources, so if anyone have a link, it will help!

Formula for reference:

class Crystalline < Formula
  desc "Language Server Protocol implementation for Crystal"
  homepage "https://github.com/elbywan/crystalline"
  url "https://github.com/elbywan/crystalline/archive/refs/tags/v0.6.0.tar.gz"
  sha256 "0d15cc0208edcbfe11bb280c2dd535091003ff89016f990a123a49325f8a8f9a"
  license "MIT"

  livecheck do
    url :homepage
  end

  depends_on "crystal" => :build
  depends_on "llvm" => :build

  def install
    system "shards", "install"
    system "crystal", "build", "./src/crystalline.cr",
           "--release", "--no-debug",
           "-Dpreview_mt",
           "--progress", "--stats",
           "--time", "-o", "crystalline"

    bin.install "crystalline"
  end

  test do
    system "false"
  end
end

Thanks!

y8 avatar Jul 18 '22 19:07 y8

@y8 Thanks a bunch for the forumula (and sorry for not replying sooner)!

It would be awesome, if you can share "one-liner" that can verify that crystalline in fact runs correctly. If possible, something that will keep working between releases, so there is no need to change formula to update tests for each release.

Sure thing, I am lacking free time currently but I will share something as soon as I can.

What is relation between llvm version and crystalline executable?

I don't think that the installed LLVM version matters, AFAIK LLM is only used to build crystalline from source.

elbywan avatar Aug 01 '22 11:08 elbywan

The Homebrew formula above looks like a good idea to me!

Separately, if you want to have Apple Silicon artifacts attached to future releases, I tested the following using https://cirrus-ci.org/. It works and is free.

The steps from here would be:

  1. Decide where you want the bash script to live. I just created a mac_arm64.sh file in the crystalline root dir.
  2. Link your GitHub repo to Cirrus.
  3. Enter a GitHub token into the Cirrus "Secured Variables" field for the repo to generated an encrypted value that can be used in .cirrus.yml.

.cirrus.yml:

macos_instance:
  image: ghcr.io/cirruslabs/macos-ventura-base:latest

env:
  GITHUB_TOKEN: ENCRYPTED[abc123]

task:
  script: ./mac_arm64.sh

mac_arm64.sh:

#!/bin/bash

if [[ "$CIRRUS_RELEASE" == "" ]]; then
  echo "Not a release. No need to deploy!"
  exit 0
fi

if [[ "$GITHUB_TOKEN" == "" ]]; then
  echo "Please provide GitHub access token via GITHUB_TOKEN environment variable!"
  exit 1
fi

brew update
brew install openssl crystal
export LLVM_CONFIG="/opt/homebrew/opt/llvm@14/bin/llvm-config"
shards build crystalline --release --no-debug -Dpreview_mt --stats --progress --ignore-crystal-version
gzip -c bin/crystalline > crystalline_arm_64-apple-darwin.gz

echo "Uploading file..."
url_to_upload="https://uploads.github.com/repos/$CIRRUS_REPO_FULL_NAME/releases/$CIRRUS_RELEASE/assets?name=crystalline_arm_64-apple-darwin.gz"
curl -X POST \
  --data-binary @crystalline_arm_64-apple-darwin.gz \
  --header "Authorization: token $GITHUB_TOKEN" \
  --header "Content-Type: application/octet-stream" \
  "$url_to_upload"

croaky avatar Dec 30 '22 16:12 croaky

I'm also using Crystalline on an M1 and built from source. Here's a 0.8 build made with Crystal 1.8.0. Hope this helps!

crystalline0.8_arm_64-apple-darwin.gz

dorkrawk avatar Apr 14 '23 22:04 dorkrawk

@dorkrawk How were you able to build Crystalline on an M1? I get these errors when I try:

Undefined symbols for architecture arm64:
  "llvm::DISubprogram::toSPFlags(bool, bool, bool, unsigned int, bool)", referenced from:
      _LLVMExtDIBuilderCreateFunction in llvm_ext.o
  "llvm::DIBuilder::createFunction(llvm::DIScope*, llvm::StringRef, llvm::StringRef, llvm::DIFile*, unsigned int, llvm::DISubroutineType*, unsigned int, llvm::DINode::DIFlags, llvm::DISubprogram::DISPFlags, llvm::MDTupleTypedArrayWrapper<llvm::DITemplateParameter>, llvm::DISubprogram*, llvm::MDTupleTypedArrayWrapper<llvm::DIType>, llvm::MDTupleTypedArrayWrapper<llvm::DINode>, llvm::StringRef)", referenced from:
      _LLVMExtDIBuilderCreateFunction in llvm_ext.o
  "llvm::DIBuilder::createMemberType(llvm::DIScope*, llvm::StringRef, llvm::DIFile*, unsigned int, unsigned long long, unsigned int, unsigned long long, llvm::DINode::DIFlags, llvm::DIType*, llvm::MDTupleTypedArrayWrapper<llvm::DINode>)", referenced from:
      _LLVMExtDIBuilderCreateMemberType in llvm_ext.o
  "llvm::DIBuilder::createPointerType(llvm::DIType*, unsigned long long, unsigned int, llvm::Optional<unsigned int>, llvm::StringRef, llvm::MDTupleTypedArrayWrapper<llvm::DINode>)", referenced from:
      _LLVMExtDIBuilderCreatePointerType in llvm_ext.o
  "llvm::DIBuilder::createParameterVariable(llvm::DIScope*, llvm::StringRef, unsigned int, llvm::DIFile*, unsigned int, llvm::DIType*, bool, llvm::DINode::DIFlags, llvm::MDTupleTypedArrayWrapper<llvm::DINode>)", referenced from:
      _LLVMExtDIBuilderCreateParameterVariable in llvm_ext.o
  "llvm::DIBuilder::createReplaceableCompositeType(unsigned int, llvm::StringRef, llvm::DIScope*, llvm::DIFile*, unsigned int, unsigned int, unsigned long long, unsigned int, llvm::DINode::DIFlags, llvm::StringRef, llvm::MDTupleTypedArrayWrapper<llvm::DINode>)", referenced from:
      _LLVMExtDIBuilderCreateReplaceableCompositeType in llvm_ext.o
  "llvm::AttributeList::addAttributeAtIndex(llvm::LLVMContext&, unsigned int, llvm::Attribute::AttrKind) const", referenced from:
      llvm::IRBuilderBase::CreateCall(llvm::FunctionType*, llvm::Value*, llvm::ArrayRef<llvm::Value*>, llvm::ArrayRef<llvm::OperandBundleDefT<llvm::Value*>>, llvm::Twine const&, llvm::MDNode*) in llvm_ext.o
      llvm::IRBuilderBase::CreateInvoke(llvm::FunctionType*, llvm::Value*, llvm::BasicBlock*, llvm::BasicBlock*, llvm::ArrayRef<llvm::Value*>, llvm::ArrayRef<llvm::OperandBundleDefT<llvm::Value*>>, llvm::Twine const&) in llvm_ext.o
  "llvm::AttributeList::addAttributeAtIndex(llvm::LLVMContext&, unsigned int, llvm::StringRef, llvm::StringRef) const", referenced from:
      _LLVMExtCreateMCJITCompilerForModule in llvm_ext.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Error: execution of command failed with exit status 1: cc "${@}" -o /Users/avrameisner/Dev/crystal-code/crystalline/bin/crystalline  -rdynamic -L/opt/homebrew/Cellar/crystal/1.8.2/libexec/../../../../lib -L/opt/homebrew/Cellar/libyaml/0.2.5/lib -lyaml /opt/homebrew/Cellar/crystal/1.8.2/share/crystal/src/llvm/ext/llvm_ext.o `"/opt/homebrew/opt/llvm@13/bin/llvm-config" --libs --system-libs --ldflags 2> /dev/null` -lstdc++ -lpcre2-8 -lgc -L/opt/homebrew/Cellar/libevent/2.1.12/lib -levent_pthreads -levent -L/opt/homebrew/Cellar/libevent/2.1.12/lib -levent -liconv

avrame avatar May 28 '23 04:05 avrame

@y8 did you try submitting the homebrew formula above to homebrew-core (I can't find it).

It would be awesome, if you can share "one-liner" that can verify that crystalline in fact runs correctly. If possible, something that will keep working between releases, so there is no need to change formula to update tests for each release.

I suspect (based on previous experience) that something as simple as showing help text would be accepted as a test that compilation worked.

mloughran avatar Jul 12 '23 21:07 mloughran

@y8 did you try submitting the homebrew formula above to homebrew-core (I can't find it).

I've found a way to do some simple check that lsp works, so here is homebrew's PR: https://github.com/Homebrew/homebrew-core/pull/136517

y8 avatar Jul 13 '23 15:07 y8