Skip to content

Commit ff9f091

Browse files
authored
Merge pull request #391 from AltGr/gh-act-static-bin
Add github action rules for static binaries generation (Linux, Macos)
2 parents 1b4a112 + 68a302f commit ff9f091

File tree

9 files changed

+220
-4
lines changed

9 files changed

+220
-4
lines changed

.ci-macosx.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ eval $(opam env)
1111

1212
opam install -y -j 2 . --deps-only --locked
1313
make && make opaminstall
14+
15+
# See src/main/linking_flags.sh
16+
make detect-libs
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
name: Generate static binaries
2+
on:
3+
push:
4+
branches:
5+
- master
6+
tags:
7+
- '*'
8+
pull_request:
9+
branches:
10+
- '**'
11+
jobs:
12+
static-bin-linux:
13+
name: Builds static Linux binaries
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Check out the repo
17+
uses: actions/checkout@v2
18+
- name: Build the binaries
19+
run: |
20+
./scripts/static-build.sh
21+
- name: Test the binaries
22+
run: |
23+
bin=(./learn-ocaml-client ./learn-ocaml-server ./learn-ocaml)
24+
file "${bin[@]}"
25+
ldd "${bin[@]}"
26+
for b in "${bin[@]}"; do ( set -x; "$b" --version ); done
27+
- name: Archive static binaries
28+
uses: actions/upload-artifact@v2
29+
with:
30+
name: static-binaries-linux
31+
path: |
32+
learn-ocaml
33+
learn-ocaml-server
34+
learn-ocaml-client
35+
static-bin-macos:
36+
name: Builds static Macos binaries
37+
runs-on: macos-latest
38+
env:
39+
OPAMYES: 1
40+
OPAMDEPEXTYES: 1
41+
steps:
42+
- name: Check out the repo
43+
uses: actions/checkout@v2
44+
- name: Show OS version
45+
run: |
46+
sw_vers
47+
system_profiler SPSoftwareDataType
48+
uname -a
49+
# Need unreleased 2.1.0~rc
50+
# - name: Retrieve opam
51+
# run: |
52+
# mkdir "$HOME/bin"
53+
# wget https://github.com/ocaml/opam/releases/download/2.1.0-beta2/opam-2.1.0-beta2-x86_64-macos -O $HOME/bin/opam
54+
# chmod a+x $HOME/bin/opam
55+
# echo "$HOME/bin" >> $GITHUB_PATH
56+
- name: Install latest opam
57+
run: |
58+
brew install opam --HEAD
59+
- name: Prepare build environment
60+
run: |
61+
opam init -a --bare
62+
opam switch create . ocaml-base-compiler 'dune<2' --deps-only
63+
- name: Build the binaries
64+
run: |
65+
opam exec -- make LINKING_MODE=static
66+
- name: Test the binaries
67+
run: |
68+
bin=(./learn-ocaml-client ./learn-ocaml-server ./learn-ocaml)
69+
dir="_build/install/default/bin"
70+
file "$dir"/*
71+
otool -L "$dir"/*
72+
for b in "${bin[@]}"; do ( set -x; "$dir/$b" --version ); done
73+
- name: Archive static binaries
74+
uses: actions/upload-artifact@v2
75+
with:
76+
name: static-binaries-macos
77+
path: _build/install/default/bin/*

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,5 @@ translations/*.pot
3535
**/.merlin
3636

3737
tests/corpuses/*
38+
39+
detect-libs.*

Makefile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,25 @@ travis: # From https://stackoverflow.com/questions/21053657/how-to-run-travis-ci
9090
INSTANCE="travisci/ci-garnet:packer-1512502276-986baf0"; \
9191
docker run --name $$BUILDID -dit $$INSTANCE /sbin/init && \
9292
docker exec -it $$BUILDID bash -l
93+
94+
.PHONY: static-binaries
95+
static-binaries:
96+
./scripts/static-build.sh
97+
98+
BINARIES = src/main/learnocaml_client.bc src/main/learnocaml_main.bc src/main/learnocaml_server_main.exe
99+
100+
.PHONY: detect-libs
101+
detect-libs:
102+
$(RM) $(addprefix _build/default/,$(BINARIES))
103+
+sort=false; \
104+
baseid="detect-libs.$$$$"; echo ...; \
105+
$(MAKE) LINKING_MODE=dynamic OCAMLPARAM="_,verbose=1" > $$baseid.log 2>&1; \
106+
for bin in $(BINARIES); do \
107+
base=$${bin#src/main/}; base=$${base%.*}; \
108+
grep -e "'$$bin'" $$baseid.log > $$baseid.$$base.log; \
109+
printf "%s: " "$$base"; \
110+
( sed -e "s/'//g; s/ /\\$$(printf '\n/g')" $$baseid.$$base.log | grep -e "^-l" | \
111+
if [ "$$sort" = true ]; then printf "(sorted) "; sort -u; else cat; fi | xargs echo ); \
112+
done; echo; \
113+
cat $$baseid.*.log; \
114+
$(RM) $$baseid.*log

learn-ocaml-client.opam

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ depends: [
2525
"cohttp-lwt-unix" {>= "1.0.0" & < "2.0.0"}
2626
"ssl" {= "0.5.5"}
2727
"digestif" {>= "0.7.1"}
28-
"dune" {= "2.0.1"}
28+
"dune" {>= "1.11.4" & <= "2.0.1"}
2929
"ezjsonm"
3030
"lwt" {>= "4.0.0"}
3131
"lwt_ssl"

learn-ocaml.opam

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ depends: [
2323
"conf-git"
2424
"decompress" {= "0.8.1"}
2525
"digestif" {>= "0.7.1"}
26-
"dune" {= "2.0.1"}
26+
"dune" {>= "1.11.4"}
2727
"easy-format" {>= "1.3.0" }
2828
"ipaddr" {= "2.8.0" }
2929
"ezjsonm"

scripts/static-build.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/usr/bin/env bash
2+
set -ue
3+
4+
LC_ALL=C
5+
6+
cd $(dirname "$0")/..
7+
8+
## Run build in container
9+
10+
set -o pipefail
11+
git ls-files -z | xargs -0 tar c | \
12+
docker run --rm -i \
13+
ocamlpro/ocaml:4.05 \
14+
sh -uexc \
15+
'tar x >&2 &&
16+
sudo apk add openssl-libs-static >&2 &&
17+
opam switch create . ocaml-system "dune<2" --deps-only >&2 &&
18+
opam exec make LINKING_MODE=static >&2 &&
19+
tar c -hC _build/install/default/bin .' | \
20+
tar vx

src/main/dune

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
(name learnocaml_main)
1212
(modes byte)
1313
(ocamlc_flags :standard -custom)
14-
(flags :standard -linkall)
14+
(flags (:standard -linkall
15+
(:include linking_main.sexp)))
1516
(modules Learnocaml_main)
1617
(libraries cmdliner
1718
sha
@@ -29,7 +30,8 @@
2930
(name learnocaml_client)
3031
(modes byte)
3132
(ocamlc_flags :standard -custom)
32-
(flags :standard -linkall)
33+
(flags (:standard -linkall
34+
(:include linking_client.sexp)))
3335
(modules Learnocaml_client)
3436
(libraries cmdliner
3537
sha
@@ -48,4 +50,19 @@
4850
(name learnocaml_server_main)
4951
(modules learnocaml_server_main)
5052
(libraries learnocaml_server_args)
53+
(flags (:standard
54+
(:include linking_server.sexp)))
5155
)
56+
57+
(rule
58+
(targets linking_main.sexp)
59+
(action (with-stdout-to %{targets}
60+
(run ./linking_flags.sh %{env:LINKING_MODE=dynamic} %{ocaml-config:system} laolao_stubs threads camlrun))))
61+
(rule
62+
(targets linking_client.sexp)
63+
(action (with-stdout-to %{targets}
64+
(run ./linking_flags.sh %{env:LINKING_MODE=dynamic} %{ocaml-config:system} threads camlrun))))
65+
(rule
66+
(targets linking_server.sexp)
67+
(action (with-stdout-to %{targets}
68+
(run ./linking_flags.sh %{env:LINKING_MODE=dynamic} -- laolao_stubs threadsnat))))

src/main/linking_flags.sh

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/bin/sh
2+
set -ue
3+
4+
# This script is called by dune to generate the linking flags for static builds
5+
# (on the limited set of supported platforms). It only returns an empty set of
6+
# flags for the default dynamic linking mode.
7+
8+
LC_ALL=C
9+
10+
help_exit() {
11+
echo "Usage: $0 dynamic|static linux|macosx [extra-libs]" >&2
12+
exit 2
13+
}
14+
15+
[ $# -lt 2 ] && help_exit
16+
17+
echo ";; generated by $0"
18+
19+
case "$1" in
20+
dynamic) echo "()"; exit 0;;
21+
static) ;;
22+
*) echo "Invalid linking mode '$1'."; help_exit
23+
esac
24+
25+
shift
26+
case "$1" in
27+
macosx) shift; EXTRA_LIBS="curses $*";;
28+
linux) shift; EXTRA_LIBS="$*";;
29+
--) shift; EXTRA_LIBS="$*";;
30+
*) echo "Not supported %{ocamlc-config:system} '$1'."; help_exit
31+
esac
32+
33+
## Static linking configuration ##
34+
35+
# The linked C libraries list may need updating on changes to the dependencies.
36+
#
37+
# To get the correct list for manual linking, the simplest way is to set the
38+
# flags to `-verbose`, while on the normal `autolink` mode, then extract them
39+
# from the gcc command-line.
40+
# The Makefile contains a target to automate this: `make detect-libs`.
41+
42+
case $(uname -s) in
43+
Linux)
44+
case $(. /etc/os-release && echo $ID) in
45+
alpine)
46+
COMMON_LIBS="camlstr base_stubs ssl_threads_stubs ssl crypto cstruct_stubs lwt_unix_stubs bigarray unix c"
47+
# `m` and `pthread` are built-in musl
48+
echo '(-noautolink'
49+
echo ' -cclib -Wl,-Bstatic'
50+
echo ' -cclib -static-libgcc'
51+
for l in $EXTRA_LIBS $COMMON_LIBS; do
52+
echo " -cclib -l$l"
53+
done
54+
echo ' -cclib -static)'
55+
;;
56+
*)
57+
echo "Error: static linking is only supported in Alpine, to avoids glibc constraints" >&2
58+
exit 3
59+
esac
60+
;;
61+
Darwin)
62+
COMMON_LIBS="camlstr base_stubs ssl_threads_stubs /usr/local/opt/openssl/lib/libssl.a /usr/local/opt/openssl/lib/libcrypto.a cstruct_stubs lwt_unix_stubs bigarray unix"
63+
# `m` and `pthread` are built-in in libSystem
64+
echo '(-noautolink'
65+
for l in $EXTRA_LIBS $COMMON_LIBS; do
66+
if [ "${l%.a}" != "${l}" ]; then echo " -cclib $l"
67+
else echo " -cclib -l$l"
68+
fi
69+
done
70+
echo ')'
71+
;;
72+
*)
73+
echo "Static linking is not supported for your platform. See $0 to contribute." >&2
74+
exit 3
75+
esac

0 commit comments

Comments
 (0)