Skip to content

Commit

Permalink
Added iOS runtimes
Browse files Browse the repository at this point in the history
  • Loading branch information
dominicletz authored Oct 19, 2021
1 parent ff90851 commit 426bc79
Show file tree
Hide file tree
Showing 16 changed files with 1,241 additions and 82 deletions.
31 changes: 25 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ on: ["push", "pull_request"]

jobs:
build:
name: "Build runtimes"
name: "Build Android runtimes"
runs-on: "ubuntu-latest"
strategy:
matrix:
Expand All @@ -18,18 +18,37 @@ jobs:
unzip Precompiled.zip
echo "$HOME/elixir/bin" >> $GITHUB_PATH
- uses: actions/checkout@v2
- name: Build ${{ matrix.arch }} runtimes
- name: Build Android ${{ matrix.arch }} runtimes
run: |
mix deps.get
ARCH=${{ matrix.arch }} mix package.runtime
ARCH=${{ matrix.arch }} mix package.nif
- name: Archive runtimes
ARCH=${{ matrix.arch }} mix package.android.runtime
ARCH=${{ matrix.arch }} mix package.android.nif
- name: Archive Android runtimes
uses: actions/upload-artifact@v2
with:
name: ${{ matrix.arch }}-runtime
path: _build/*.zip
- name: ${{ matrix.arch }} release
- name: Android ${{ matrix.arch }} release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: _build/*.zip

ios:
name: "Build iOS runtime"
runs-on: "macos-latest"
steps:
- run: brew install git elixir carthage coreutils
- uses: actions/checkout@v2
- name: Build runtime
run: mix package.ios.runtime
- name: Archive runtimes
uses: actions/upload-artifact@v2
with:
name: iOS-runtime
path: _build/liberlang.xcframework
- name: iOS release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: _build/liberlang.xcframework
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,9 @@
/erl_crash.dump
*.so
*.zip
*.tar.gz
*.tmp
/test_main
.DS_Store
/tmp
/test_main
/openssl-1.1.1k
5 changes: 3 additions & 2 deletions lib/beam.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ ENV FC= CPP= LD= CC=clang AR=ar
ENV MAKEFLAGS "-j10 -O"

# Setting up openssl
COPY scripts/install_openssl.sh /work/
COPY scripts/install_openssl.sh /work/
COPY patch /work/patch

# OpenSSL fails to detect this:
RUN cp ${NDK_ROOT}/bin/llvm-ar ${NDK_ROOT}/bin/<%= @arch.cpu %>-linux-<%= @arch.android_name %>-ar
Expand Down Expand Up @@ -48,4 +49,4 @@ RUN ./otp_build boot -a
# Build run #2, now creating the arm binaries, appliying the install flags only here...
ENV INSTALL_PROGRAM "/usr/bin/install -c -s --strip-program=llvm-strip"
RUN ./otp_build configure <%= config %> LDFLAGS="-z global"
RUN ./otp_build release -a
RUN ./otp_build release -a
51 changes: 51 additions & 0 deletions lib/mix/tasks/package_android_nif.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
defmodule Mix.Tasks.Package.Android.Nif do
use Mix.Task
require EEx

def run([]) do
for nif <- Runtimes.default_nifs() do
for arch <- Runtimes.default_archs() do
build(arch, Runtimes.get_nif(nif))
end
end
end

def run(args) do
{git, _tag} =
case args do
[] -> raise "Need git url parameter"
[git] -> {git, nil}
[git, tag] -> {git, tag}
end

build("arm64", Runtimes.get_nif(git))
end

defp build(arch, nif) do
type = Runtimes.get_arch(arch).android_type
target = "_build/#{type}-nif-#{nif.name}.zip"

if exists?(target) do
:ok
else
image_name = "#{nif.name}-#{arch}"

Runtimes.docker_build(
image_name,
Runtimes.generate_nif_dockerfile(arch, nif)
)

Runtimes.run(~w(docker run --rm
-w /work/#{nif.basename}/ --entrypoint ./package_nif.sh #{image_name}
#{nif.name} > #{target}))
end
end

def exists?(file) do
case File.stat(file) do
{:error, _} -> false
{:ok, %File.Stat{size: 0}} -> false
_ -> true
end
end
end
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule Mix.Tasks.Package.Runtime do
defmodule Mix.Tasks.Package.Android.Runtime do
use Mix.Task
require EEx

Expand Down
112 changes: 112 additions & 0 deletions lib/mix/tasks/package_ios_nif.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
defmodule Mix.Tasks.Package.Ios.Nif do
alias Mix.Tasks.Package.Ios.Runtime
use Mix.Task
require EEx

defdelegate architectures(), to: Runtime
defdelegate get_arch(arch), to: Runtime
defdelegate get_nif(nif), to: Runtimes
defdelegate otp_target(arch), to: Runtime

def run([nif]) do
buildall(Map.keys(architectures()), nif)
end

def elixir_target() do
Path.absname("_build/elixir")
end

def build(arch, nif) do
nif = get_nif(nif)
arch = get_arch(arch)

# Todo: How to sync cross-compiled erlang version and local erlang version?
path =
[
Path.join(elixir_target(), "bin"),
Path.join(System.get_env("HOME"), ".mix"),
# Path.join(otp_target(arch), "bootstrap/bin"),
System.get_env("PATH")
]
|> Enum.join(":")

# Getting an Elixir version
if File.exists?(Path.join(elixir_target(), "bin")) do
IO.puts("Elixir already exists...")
else
Runtimes.run(~w(
mkdir #{elixir_target()} &&
cd #{elixir_target()} &&
wget https://github.com/elixir-lang/elixir/releases/download/v1.11.4/Precompiled.zip &&
unzip Precompiled.zip
))

Runtimes.run("mix do local.hex --force && mix local.rebar --force", PATH: path)
end

{sdkroot, 0} = System.cmd("xcrun", ["-sdk", arch.sdk, "--show-sdk-path"])
sdkroot = String.trim(sdkroot)
cflags = arch.cflags <> " -isysroot #{sdkroot} -I#{Path.absname("stubs")}"
lflags = "-Wl,-syslibroot,#{sdkroot} -lc++"

env = [
PATH: path,
ERLANG_PATH: Path.join(otp_target(arch), "release/#{arch.name}/erts-12.0/include"),
ERTS_INCLUDE_DIR: Path.join(otp_target(arch), "release/#{arch.name}/erts-12.0/include"),
HOST: arch.name,
CROSSCOMPILE: "iOS",
STATIC_ERLANG_NIF: "yes",
CC: "xcrun -sdk #{arch.sdk} cc -arch #{arch.arch}",
CFLAGS: cflags,
CXX: "xcrun -sdk #{arch.sdk} c++ -arch #{arch.arch}",
CXXFLAGS: cflags,
LD: "xcrun -sdk #{arch.sdk} ld -arch #{arch.arch}",
LDFLAGS: lflags,
RANLIB: "xcrun -sdk #{arch.sdk} ranlib",
LIBTOOL: "xcrun -sdk #{arch.sdk} libtool",
AR: "xcrun -sdk #{arch.sdk} ar",
MIX_ENV: "prod",
MIX_TARGET: "ios"
]

# Start the builds
nif_dir = "_build/#{arch.name}/#{nif.basename}"

if !File.exists?(nif_dir) do
Runtimes.run(~w(git clone #{nif.repo} #{nif_dir}), env)
end

if nif.tag do
Runtimes.run(~w(cd #{nif_dir} && git checkout #{nif.tag}), env)
end

build_nif = Path.absname("scripts/build_nif.sh")
Runtimes.run(~w(cd #{nif_dir} && #{build_nif}), env)

case static_lib_path(arch, nif) do
nil -> raise "NIF build failed. Could not locate static lib"
lib -> lib
end
end

def static_lib_path(arch, nif) do
nif_dir = "_build/#{arch.name}/#{nif.basename}"

# Finding all .a files
:filelib.fold_files(
String.to_charlist(nif_dir),
'.+\\.a$',
true,
fn name, acc -> [List.to_string(name) | acc] end,
[]
)
|> Enum.filter(fn path -> String.contains?(path, "priv") end)
|> List.first()
end

defp buildall(targets, nif) do
for target <- targets do
build(target, nif)
end
end
end
Loading

0 comments on commit 426bc79

Please sign in to comment.