Skip to content

Commit 7f2ba7a

Browse files
authored
Added CI and updated OTP source trees
1 parent 426bc79 commit 7f2ba7a

11 files changed

+150
-104
lines changed

.dockerignore

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
/otp
2-
/_build
3-
*.zip
2+
/_build/dev
3+
/_build/x86_64
4+
/_build/arm
5+
/_build/arm64
6+
/lib
7+
/.history
8+
/.elixir_ls
9+
/.github
10+
*.zip
11+
*.tmp

.github/workflows/ci.yml

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
name: "CI"
22
on: ["push", "pull_request"]
3+
env:
4+
OTP_TAG: ios
35

46
jobs:
57
build:

README.md

+9-3
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,22 @@ To use elixir-desktop on mobile-phones this projects packages the BEAM Virtual M
55
- Android arm 64-bit
66
- Android arm 32-bit
77
- Android x86 64-bit (for the Android Simulator)
8+
- iOS arm 32-bit (very old iPhones)
9+
- iOS arm 64-bit (current iPhones)
10+
- iOS arm 64-bit (MacOS M1 Simulator)
11+
- iOS x86_64 (MacOS Intel Simulator)
812

913
## Building
1014

11-
Runtimes depends on docker and the dockercross/* docker-images created for cross-compilation. If docker is installed for your
12-
current user then building all the runtimes bundled in a zip file is as easy as:
15+
Android runtimes depends on docker and the dockercross/* docker-images created for cross-compilation. If docker is installed for your current user then building all the runtimes bundled in a zip file is as easy as:
1316

14-
`mix package.runtime`
17+
`mix package.android.runtime`
1518

1619
After this you should have all runtimes in `_build/#{arch}-runtime.zip` these then will need to be packaged with your mobile app.
1720

21+
For iOS builds are triggered similiary with:
22+
23+
`mix package.ios.runtime`
1824

1925
## Android Versions and API-Levels (update Sept. 7th 2021)
2026

lib/beam.dockerfile renamed to lib/mix/tasks/android_beam.dockerfile

+7-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ ENV NDK_ROOT $CROSS_ROOT
55
ENV ANDROID_NDK_HOME $CROSS_ROOT
66
ENV NDK_ABI_PLAT <%= @arch.android_name %><%= @arch.abi %>
77
ENV PATH $NDK_ROOT/bin:$PATH
8-
ENV FC= CPP= LD= CC=clang AR=ar
8+
ENV FC= CPP= LD= CXX=clang++ CC=clang AR=ar
99
ENV MAKEFLAGS "-j10 -O"
1010

1111
# Setting up openssl
@@ -19,7 +19,7 @@ RUN cp ${NDK_ROOT}/bin/llvm-ranlib ${NDK_ROOT}/bin/<%= @arch.cpu %>-linux-<%= @a
1919
RUN ARCH="android-<%= @arch.id %> -D__ANDROID_API__=<%= @arch.abi %>" ./install_openssl.sh
2020

2121
# Fetching OTP
22-
RUN git clone --depth 1 -b diode/beta https://github.com/diodechain/otp.git
22+
COPY _build/otp otp
2323

2424
<%= if @arch.id == "arm" do %>
2525
ENV LIBS -L$NDK_ROOT/lib64/clang/12.0.5/lib/linux/ /usr/local/openssl/lib/libcrypto.a -lclang_rt.builtins-arm-android
@@ -30,7 +30,8 @@ ENV LIBS /usr/local/openssl/lib/libcrypto.a
3030
# We need -z global for liberlang.so because:
3131
# https://android-ndk.narkive.com/iNWj05IV/weak-symbol-linking-when-loading-dynamic-libraries
3232
# https://android.googlesource.com/platform/bionic/+/30b17e32f0b403a97cef7c4d1fcab471fa316340/linker/linker_namespaces.cpp#100
33-
ENV CFLAGS="-Os -fPIC" CXXFLAGS="-Os -fPIC" LDFLAGS="-z global"
33+
ENV CFLAGS="-Os -fPIC" CXXFLAGS="-Os -fPIC" LDFLAGS="-z global" CXX= CC=
34+
3435
# RUN env
3536
WORKDIR /work/otp
3637
RUN ./otp_build autoconf
@@ -41,7 +42,9 @@ RUN ./otp_build autoconf
4142
# Build run #1, building the x86 based cross compiler which will generate the .beam files
4243
<%
4344
config = "--with-ssl=/usr/local/openssl/ --disable-dynamic-ssl-lib --without-javac --without-odbc --without-wx --without-debugger --without-observer --without-cdv --without-et --xcomp-conf=xcomp/erl-xcomp-#{@arch.id}-android.conf"
44-
config = if @arch.id == "x86_64", do: "--disable-jit #{config}", else: config
45+
# Disabled jit for arm and x86_64 until https://github.com/erlang/otp/issues/4950 is fixed
46+
# config = if @arch.id == "x86_64", do: "--disable-jit #{config}", else: config
47+
config = "--disable-jit #{config}"
4548
%>
4649
RUN ./otp_build configure <%= config %>
4750
RUN ./otp_build boot -a

lib/nif.dockerfile renamed to lib/mix/tasks/android_nif.dockerfile

+5-4
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,16 @@ RUN apt install -y erlang
1111
WORKDIR /work
1212
RUN mix local.hex --force && mix local.rebar
1313

14-
ENV ERLANG_PATH /work/otp/release/<%= @arch.pc %>-linux-<%= @arch.android_name %>/erts-12.0/include
15-
ENV ERTS_INCLUDE_DIR /work/otp/release/<%= @arch.pc %>-linux-<%= @arch.android_name %>/erts-12.0/include
14+
ENV ERLANG_PATH /work/otp/release/<%= @arch.pc %>-linux-<%= @arch.android_name %>/erts-<%= @erts_version %>/include
15+
ENV ERTS_INCLUDE_DIR /work/otp/release/<%= @arch.pc %>-linux-<%= @arch.android_name %>/erts-<%= @erts_version %>/include
1616
ENV HOST <%= @arch.cpu %>
1717
ENV CROSSCOMPILE Android
18+
ENV CC=clang CXX=clang++
1819

19-
RUN git clone <%= @repo %>
20+
RUN git clone <%= @repo %>
2021
WORKDIR /work/<%= @basename %>
2122
<%= if @tag do %>
22-
RUN git checkout @tag
23+
RUN git checkout <%= @tag %>
2324
<% end %>
2425

2526
# Three variants of building {:mix, :make, :rebar3}

lib/mix/tasks/package_android_nif.ex

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
defmodule Mix.Tasks.Package.Android.Nif do
22
use Mix.Task
3+
alias Mix.Tasks.Package.Android.Runtime
34
require EEx
45

56
def run([]) do
67
for nif <- Runtimes.default_nifs() do
7-
for arch <- Runtimes.default_archs() do
8+
for arch <- Runtime.default_archs() do
89
build(arch, Runtimes.get_nif(nif))
910
end
1011
end
@@ -22,7 +23,7 @@ defmodule Mix.Tasks.Package.Android.Nif do
2223
end
2324

2425
defp build(arch, nif) do
25-
type = Runtimes.get_arch(arch).android_type
26+
type = Runtime.get_arch(arch).android_type
2627
target = "_build/#{type}-nif-#{nif.name}.zip"
2728

2829
if exists?(target) do
@@ -32,7 +33,7 @@ defmodule Mix.Tasks.Package.Android.Nif do
3233

3334
Runtimes.docker_build(
3435
image_name,
35-
Runtimes.generate_nif_dockerfile(arch, nif)
36+
Runtime.generate_nif_dockerfile(arch, nif)
3637
)
3738

3839
Runtimes.run(~w(docker run --rm

lib/mix/tasks/package_android_runtime.ex

+68-3
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,23 @@ defmodule Mix.Tasks.Package.Android.Runtime do
33
require EEx
44

55
def run(_) do
6-
buildall(Map.keys(Runtimes.architectures()))
6+
buildall(default_archs())
77
end
88

99
defp target(arch) do
1010
"_build/#{arch.android_type}-runtime.zip"
1111
end
1212

1313
def build(arch) do
14-
arch = Runtimes.get_arch(arch)
14+
arch = get_arch(arch)
1515
file_name = target(arch)
1616

1717
if File.exists?(file_name) do
1818
:ok
1919
else
20-
{content, _args} = Runtimes.generate_beam_dockerfile(arch.id)
20+
Runtimes.ensure_otp()
21+
22+
{content, _args} = generate_beam_dockerfile(arch.id)
2123
image_name = "beam-#{arch.id}"
2224
file = "#{image_name}.dockerfile.tmp"
2325
File.write!(file, content)
@@ -47,4 +49,67 @@ defmodule Mix.Tasks.Package.Android.Runtime do
4749
build(head)
4850
buildall(rest)
4951
end
52+
53+
def architectures() do
54+
%{
55+
"arm" => %{
56+
id: "arm",
57+
abi: 23,
58+
cpu: "arm",
59+
pc: "arm-unknown",
60+
android_name: "androideabi",
61+
android_type: "armeabi-v7a"
62+
},
63+
"arm64" => %{
64+
id: "arm64",
65+
abi: 23,
66+
cpu: "aarch64",
67+
pc: "aarch64-unknown",
68+
android_name: "android",
69+
android_type: "arm64-v8a"
70+
},
71+
"x86_64" => %{
72+
id: "x86_64",
73+
abi: 23,
74+
cpu: "x86_64",
75+
pc: "x86_64-pc",
76+
android_name: "android",
77+
android_type: "x86_64"
78+
}
79+
}
80+
end
81+
82+
def get_arch(arch) do
83+
Map.fetch!(architectures(), arch)
84+
end
85+
86+
def generate_beam_dockerfile(arch) do
87+
args = [arch: get_arch(arch), erts_version: Runtimes.erts_version()]
88+
{beam_dockerfile(args), args}
89+
end
90+
91+
def generate_nif_dockerfile(arch, nif) do
92+
{parent, args} = generate_beam_dockerfile(arch)
93+
94+
args =
95+
args ++
96+
[parent: parent, repo: nif.repo, tag: nif.tag, basename: nif.basename]
97+
98+
content = nif_dockerfile(args)
99+
100+
file = "#{nif.basename}-#{arch}.dockerfile.tmp"
101+
File.write!(file, content)
102+
file
103+
end
104+
105+
EEx.function_from_file(:defp, :nif_dockerfile, "#{__DIR__}/android_nif.dockerfile", [:assigns])
106+
107+
EEx.function_from_file(:defp, :beam_dockerfile, "#{__DIR__}/android_beam.dockerfile", [:assigns])
108+
109+
def default_archs() do
110+
case System.get_env("ARCH", nil) do
111+
nil -> ["arm", "arm64", "x86_64"]
112+
arch -> [arch]
113+
end
114+
end
50115
end

lib/mix/tasks/package_ios_nif.ex

+5-2
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,14 @@ defmodule Mix.Tasks.Package.Ios.Nif do
4848
sdkroot = String.trim(sdkroot)
4949
cflags = arch.cflags <> " -isysroot #{sdkroot} -I#{Path.absname("stubs")}"
5050
lflags = "-Wl,-syslibroot,#{sdkroot} -lc++"
51+
erts_version = Runtimes.erts_version()
5152

5253
env = [
5354
PATH: path,
54-
ERLANG_PATH: Path.join(otp_target(arch), "release/#{arch.name}/erts-12.0/include"),
55-
ERTS_INCLUDE_DIR: Path.join(otp_target(arch), "release/#{arch.name}/erts-12.0/include"),
55+
ERLANG_PATH:
56+
Path.join(otp_target(arch), "release/#{arch.name}/erts-#{erts_version}/include"),
57+
ERTS_INCLUDE_DIR:
58+
Path.join(otp_target(arch), "release/#{arch.name}/erts-#{erts_version}/include"),
5659
HOST: arch.name,
5760
CROSSCOMPILE: "iOS",
5861
STATIC_ERLANG_NIF: "yes",

lib/mix/tasks/package_ios_runtime.ex

+2-15
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
defmodule Mix.Tasks.Package.Ios.Runtime do
2-
@otp_source "https://github.com/diodechain/otp"
3-
@otp_tag "diode/ios"
4-
52
alias Mix.Tasks.Package.Ios.Nif
63
use Mix.Task
74
require EEx
@@ -97,7 +94,7 @@ defmodule Mix.Tasks.Package.Ios.Runtime do
9794
IO.puts("liberlang.a (#{arch.id}) already exists...")
9895
else
9996
if !File.exists?(otp_target(arch)) do
100-
ensure_otp()
97+
Runtimes.ensure_otp()
10198
Runtimes.run(~w(git clone _build/otp #{otp_target(arch)}))
10299
end
103100

@@ -198,7 +195,7 @@ defmodule Mix.Tasks.Package.Ios.Runtime do
198195
end
199196

200197
defp buildall(targets, nifs) do
201-
ensure_otp()
198+
Runtimes.ensure_otp()
202199

203200
# targets
204201
# |> Enum.map(fn target -> Task.async(fn -> build(target, nifs) end) end)
@@ -239,14 +236,4 @@ defmodule Mix.Tasks.Package.Ios.Runtime do
239236
Runtimes.run("lipo -create #{Enum.join(more, " ")} -output #{tmp}")
240237
[tmp]
241238
end
242-
243-
defp ensure_otp() do
244-
if !File.exists?("_build/otp") do
245-
File.mkdir_p!("_build")
246-
247-
Runtimes.run(
248-
"git clone #{@otp_source} _build/otp && cd _build/otp && git checkout #{@otp_tag}"
249-
)
250-
end
251-
end
252239
end

0 commit comments

Comments
 (0)